diff options
author | azul <azul@riseup.net> | 2016-06-21 11:54:32 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-06-21 11:54:32 +0200 |
commit | 27196b87e8d0ce5325381ea96ccd68ced8ee2e4d (patch) | |
tree | 331cfb3d07f49f1e12e5cbf50f63e80692e0868f | |
parent | 3c6dc3d7b902b46b82a3d8cd38bd3fa896024beb (diff) | |
parent | b185742d959a0a3854c5e628354a538a15bdea15 (diff) |
Merge pull request #4 from azul/refactor/separate-em-server
refactor: separate em specifics from generic server
-rw-r--r-- | lib/nickserver/couch_db/source.rb | 12 | ||||
-rw-r--r-- | lib/nickserver/em_server.rb | 51 | ||||
-rw-r--r-- | lib/nickserver/hkp/source.rb | 8 | ||||
-rw-r--r-- | lib/nickserver/request_handler.rb | 85 | ||||
-rw-r--r-- | lib/nickserver/server.rb | 107 | ||||
-rw-r--r-- | lib/nickserver/source.rb | 13 | ||||
-rw-r--r-- | test/unit/request_handler_test.rb | 41 |
7 files changed, 201 insertions, 116 deletions
diff --git a/lib/nickserver/couch_db/source.rb b/lib/nickserver/couch_db/source.rb index 874fe4f..b30fdfc 100644 --- a/lib/nickserver/couch_db/source.rb +++ b/lib/nickserver/couch_db/source.rb @@ -1,18 +1,15 @@ # # This class allows querying couch for public keys. # +require 'nickserver/source' require 'nickserver/couch_db/response' require 'nickserver/config' module Nickserver::CouchDB - class Source + class Source < Nickserver::Source VIEW = '/_design/Identity/_view/pgp_key_by_email' - def initialize(adapter) - @adapter = adapter - end - def query(nick) adapter.get url, query: query_for(nick) do |status, body| yield Response.new(nick, status: status, body: body) @@ -29,11 +26,6 @@ module Nickserver::CouchDB { reduce: "false", key: "\"#{nick}\"" } end - def adapter - @adapter - # Nickserver::Adapters::Http.new(config) - end - attr_reader :config end end diff --git a/lib/nickserver/em_server.rb b/lib/nickserver/em_server.rb new file mode 100644 index 0000000..bcec4cd --- /dev/null +++ b/lib/nickserver/em_server.rb @@ -0,0 +1,51 @@ +require 'eventmachine' +silence_warnings do + require 'evma_httpserver' +end +require 'nickserver/request_handler' + +module Nickserver + class EmServer < EM::Connection + include EM::HttpServer + + def self.start(options = {}) + EventMachine.run do + EM.start_server options[:host], options[:port], self + end + end + + def post_init + super + no_environment_strings + end + + def process_http_request + handler.respond_to params, @http_headers + end + + def send_response(options = {}) + response = EM::DelegatedHttpResponse.new(self) + response.status = options[:status] + response.content_type options[:content_type] + response.content = options[:content] + silence_warnings do + response.send_response + end + end + + private + + def handler + @handler ||= RequestHandler.new(self, Nickserver::Adapters::EmHttp.new) + end + + def params + if @http_query_string + CGI.parse(@http_query_string) + elsif @http_post_content + CGI.parse(@http_post_content) + end + end + + end +end diff --git a/lib/nickserver/hkp/source.rb b/lib/nickserver/hkp/source.rb index cae3e01..8b2a62b 100644 --- a/lib/nickserver/hkp/source.rb +++ b/lib/nickserver/hkp/source.rb @@ -11,11 +11,7 @@ require "nickserver/hkp/key_info" # module Nickserver; module Hkp - class Source - - def initialize(adapter) - @adapter = adapter - end + class Source < Nickserver::Source def query(nick, &block) search(nick) do |status, response| @@ -37,8 +33,6 @@ module Nickserver; module Hkp protected - attr_reader :adapter - # # for now, just pick the newest key. # diff --git a/lib/nickserver/request_handler.rb b/lib/nickserver/request_handler.rb new file mode 100644 index 0000000..26b6ec1 --- /dev/null +++ b/lib/nickserver/request_handler.rb @@ -0,0 +1,85 @@ +module Nickserver + class RequestHandler + + def initialize(responder, adapter) + @responder = responder + @adapter = adapter + end + + def respond_to(params, headers) + uid = get_uid_from_params(params) + if uid.nil? + send_not_found + elsif uid !~ EmailAddress + send_error("Not a valid address") + else + send_key(uid, headers) + end + rescue RuntimeError => exc + puts "Error: #{exc}" + puts exc.backtrace + send_error(exc.to_s) + end + + protected + + def get_uid_from_params(params) + if params && params["address"] && params["address"].any? + return params["address"].first + else + return nil + end + end + + def send_key(uid, headers) + if local_address?(uid, headers) + source = Nickserver::CouchDB::Source.new(adapter) + else + source = Nickserver::Hkp::Source.new(adapter) + end + source.query(uid) do |response| + send_response(status: response.status, content: response.content) + end + end + + # + # Return true if the user address is for a user of this service provider. + # e.g. if the provider is example.org, then alice@example.org returns true. + # + # If 'domain' is not configured, we rely on the Host header of the HTTP request. + # + def local_address?(uid, headers) + uid_domain = uid.sub(/^.*@(.*)$/, "\\1") + if Config.domain + return uid_domain == Config.domain + else + # no domain configured, use Host header + host_header = headers.split(/\0/).grep(/^Host: /).first + if host_header.nil? + send_error("HTTP request must include a Host header.") + else + host = host_header.split(':')[1].strip.sub(/^nicknym\./, '') + return uid_domain == host + end + end + end + def send_error(msg = "not supported") + send_response(status: 500, content: "500 #{msg}\n") + end + + def send_not_found(msg = "Not Found") + send_response(status: 404, content: "404 #{msg}\n") + end + + def send_response(opts = {}) + responder.send_response default_response.merge(opts) + end + + def default_response + {status: 200, content_type: 'text/plain', content: ''} + end + + attr_reader :responder, :adapter + + end +end diff --git a/lib/nickserver/server.rb b/lib/nickserver/server.rb index 2453f94..174d6ac 100644 --- a/lib/nickserver/server.rb +++ b/lib/nickserver/server.rb @@ -1,9 +1,6 @@ require 'kernel_ext' -require 'eventmachine' -silence_warnings do - require 'evma_httpserver' -end require 'json' +require 'nickserver/em_server' require 'nickserver/couch_db/source' require 'nickserver/hkp/source' require 'nickserver/adapters/em_http' @@ -15,8 +12,7 @@ require 'nickserver/adapters/em_http' # For info on EM::HttpServer, see https://github.com/eventmachine/evma_httpserver # module Nickserver - class Server < EM::Connection - include EM::HttpServer + class Server # # Starts the Nickserver. Must be run inside an EM.run block. @@ -28,105 +24,18 @@ module Nickserver # def self.start(opts={}) Nickserver::Config.load - options = {host: '127.0.0.1', port: Nickserver::Config.port.to_i}.merge(opts) + options = { + host: '127.0.0.1', + port: Nickserver::Config.port.to_i + }.merge(opts) + unless defined?(TESTING) puts "Starting nickserver #{options[:host]}:#{options[:port]}" end - EM.start_server options[:host], options[:port], Nickserver::Server - end - - def post_init - super - no_environment_strings - end - def process_http_request - uid = get_uid_from_request - if uid.nil? - send_not_found - elsif uid !~ EmailAddress - send_error("Not a valid address") - else - send_key(uid) - end - rescue RuntimeError => exc - puts "Error: #{exc}" - puts exc.backtrace - send_error(exc.to_s) + Nickserver::EmServer.start(options) end - private - - def send_error(msg = "not supported") - send_response(status: 500, content: "500 #{msg}\n") - end - - def send_not_found(msg = "Not Found") - send_response(status: 404, content: "404 #{msg}\n") - end - - def send_response(opts = {}) - options = {status: 200, content_type: 'text/plain', content: ''}.merge(opts) - response = EM::DelegatedHttpResponse.new(self) - response.status = options[:status] - response.content_type options[:content_type] - response.content = options[:content] - silence_warnings do - response.send_response - end - end - - def get_uid_from_request - if @http_query_string - params = CGI.parse(@http_query_string) - elsif @http_post_content - params = CGI.parse(@http_post_content) - end - if params && params["address"] && params["address"].any? - return params["address"].first - else - return nil - end - end - - def send_key(uid) - if local_address?(uid) - source = Nickserver::CouchDB::Source.new(adapter) - else - source = Nickserver::Hkp::Source.new(adapter) - end - source.query(uid) do |response| - send_response(status: response.status, content: response.content) - end - end - - # - # Return true if the user address is for a user of this service provider. - # e.g. if the provider is example.org, then alice@example.org returns true. - # - # If 'domain' is not configured, we rely on the Host header of the HTTP request. - # - def local_address?(uid) - uid_domain = uid.sub(/^.*@(.*)$/, "\\1") - if Config.domain - return uid_domain == Config.domain - else - # no domain configured, use Host header - host_header = @http_headers.split(/\0/).grep(/^Host: /).first - if host_header.nil? - send_error("HTTP request must include a Host header.") - else - host = host_header.split(':')[1].strip.sub(/^nicknym\./, '') - return uid_domain == host - end - end - rescue # XXX what are we rescueing here? - return false - end - - def adapter - @adapter ||= Nickserver::Adapters::EmHttp.new - end end end diff --git a/lib/nickserver/source.rb b/lib/nickserver/source.rb new file mode 100644 index 0000000..b8135da --- /dev/null +++ b/lib/nickserver/source.rb @@ -0,0 +1,13 @@ +module Nickserver + class Source + + def initialize(adapter) + @adapter = adapter + end + + protected + + attr_reader :adapter + + end +end diff --git a/test/unit/request_handler_test.rb b/test/unit/request_handler_test.rb new file mode 100644 index 0000000..c9d316f --- /dev/null +++ b/test/unit/request_handler_test.rb @@ -0,0 +1,41 @@ +require 'test_helper' +require 'nickserver/request_handler' + +class Nickserver::RequestHandlerTest < Minitest::Test + + def test_empty_query + handle + assert_response status: 404, content: "404 Not Found\n" + end + + def test_invalid_query + handle address: ['asdf'] + assert_response status: 500, content: "500 Not a valid address\n" + end + + protected + + def handle(params = {}, headers = {}) + @params = Hash[ params.map{ |k,v| [k.to_s, v] } ] + @headers = headers + end + + def assert_response(args) + args[:content_type] ||= 'text/plain' + responder.expect :send_response, nil, [args] + handler.respond_to @params, @headers + responder.verify + end + + def handler + Nickserver::RequestHandler.new responder, adapter + end + + def responder + @responder ||= Minitest::Mock.new + end + + def adapter + @adapter ||= Minitest::Mock.new + end +end |