diff --git a/Rakefile b/Rakefile index 4aeba02b..dad9f7b0 100644 --- a/Rakefile +++ b/Rakefile @@ -32,7 +32,7 @@ end setup_extension("http11", "http11") name="mongrel" -version="0.3.11" +version="0.3.12" setup_gem(name, version) do |spec| spec.summary = "A small fast HTTP library and server that runs Rails, Camping, and Nitro apps." diff --git a/bin/mongrel_rails b/bin/mongrel_rails index e66d99e2..1682ae58 100644 --- a/bin/mongrel_rails +++ b/bin/mongrel_rails @@ -113,6 +113,12 @@ class Start < GemPlugin::Plugin "/commands" File.unlink @pid_file if File.exist?(@pid_file) @restart = true } + + trap("INT") { + server.stop + File.unlink @pid_file if File.exist?(@pid_file) + @restart = false + } end # hook up any rails specific plugins diff --git a/lib/mongrel.rb b/lib/mongrel.rb index d5c994d3..65d2f043 100644 --- a/lib/mongrel.rb +++ b/lib/mongrel.rb @@ -142,6 +142,40 @@ module Mongrel end end + + def self.escape(s) + s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) { + '%'+$1.unpack('H2'*$1.size).join('%').upcase + }.tr(' ', '+') + end + + + def self.unescape(s) + s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){ + [$1.delete('%')].pack('H*') + } + end + + + def self.query_parse(qs, d = '&;') + params = {} + (qs||'').split(/[#{d}] */n).inject(params) { |h,p| + k, v=unescape(p).split('=',2) + if cur = params[k] + if cur.class == Array + params[k] << v + else + params[k] = [cur, v] + end + else + params[k] = v + end + } + + return params + end + + end @@ -292,25 +326,11 @@ module Mongrel # try lowering it (after you've tuned your stuff of course). def initialize(host, port, num_processors=20, timeout=120) @socket = TCPServer.new(host, port) - @classifier = URIClassifier.new - @req_queue = Queue.new @host = host @port = port - @processors = [] - - # create the worker threads - num_processors.times do |i| - @processors << Thread.new do - parser = HttpParser.new - while client = @req_queue.deq - Timeout::timeout(timeout) do - process_client(client, parser) - parser.reset - end - end - end - end + @worker_group = ThreadGroup.new + @timeout = timeout end @@ -320,8 +340,9 @@ module Mongrel # the performance just does not improve. It is currently carefully constructed # to make sure that it gets the best possible performance, but anyone who # thinks they can make it faster is more than welcome to take a crack at it. - def process_client(client, parser) + def process_client(client) begin + parser = HttpParser.new params = {} data = client.readpartial(Const::CHUNK_SIZE) @@ -368,13 +389,22 @@ module Mongrel # Runs the thing. It returns the thread used so you can "join" it. You can also # access the HttpServer::acceptor attribute to get the thread later. def run + BasicSocket.do_not_reverse_lookup=true + @acceptor = Thread.new do Thread.current[:stopped] = false - + while not Thread.current[:stopped] begin - @req_queue << @socket.accept + client = @socket.accept + + thread = Thread.new do + process_client(client) + end + + thread.priority=1 + @worker_group.add(thread) rescue StopServer STDERR.puts "Server stopped. Exiting." @socket.close if not @socket.closed? @@ -387,17 +417,14 @@ module Mongrel # now that processing is done we feed enough false onto the request queue to get # each processor to exit and stop processing. - @processors.length.times { @req_queue << false } # finally we wait until the queue is empty - while @req_queue.length > 0 - STDERR.puts "Shutdown waiting for #{@req_queue.length} requests" if @req_queue.length > 0 + while @worker_group.list.length > 0 + STDERR.puts "Shutdown waiting for #{@worker_group.list.length} requests" if @worker_group.list.length > 0 sleep 1 end end - @acceptor.priority = 1 - return @acceptor end diff --git a/projects/mongrel_console/Rakefile b/projects/mongrel_console/Rakefile index 6193badd..f134b286 100644 --- a/projects/mongrel_console/Rakefile +++ b/projects/mongrel_console/Rakefile @@ -23,7 +23,7 @@ setup_gem(name, version) do |spec| spec.description = spec.summary spec.author="Zed A. Shaw" spec.add_dependency('gem_plugin', '>= 0.2.1') - spec.add_dependency('mongrel', '>= 0.2.1') + spec.add_dependency('mongrel', '>= 0.3.11') spec.files += Dir.glob("resources/**/*") end diff --git a/test/test_http11.rb b/test/test_http11.rb index 60d020b2..6805039f 100644 --- a/test/test_http11.rb +++ b/test/test_http11.rb @@ -1,6 +1,9 @@ require 'test/unit' require 'http11' +require 'mongrel' +require 'benchmark' +include Mongrel class HttpParserTest < Test::Unit::TestCase @@ -34,5 +37,18 @@ class HttpParserTest < Test::Unit::TestCase assert !parser.finished?, "Parser shouldn't be finished" assert parser.error?, "Parser SHOULD have error" end + + def test_query_parse + puts HttpRequest.query_parse("zed=1&frank=2").inspect + puts HttpRequest.query_parse("zed=1&zed=2&zed=3&frank=11;zed=45").inspect + + puts Benchmark.measure { + 10000.times do |i| + g = HttpRequest.query_parse("zed=1&zed=2&zed=3&frank=11").inspect + end + } + end + + end diff --git a/test/test_response.rb b/test/test_response.rb index d436bfaa..e905e01f 100644 --- a/test/test_response.rb +++ b/test/test_response.rb @@ -1,5 +1,6 @@ require 'test/unit' require 'mongrel' +require 'benchmark' include Mongrel @@ -40,5 +41,6 @@ class ResponseTest < Test::Unit::TestCase assert io.length > 0, "output didn't have data" end + end