lib/packet_mongrel.rb in packet-0.1.2 vs lib/packet_mongrel.rb in packet-0.1.3
- old
+ new
@@ -1,214 +1,208 @@
-# This module rewrites pieces of the very good Mongrel web server in
-# order to change it from a threaded application to an event based
-# application running inside an Packet event loop. It should
-# be compatible with the existing Mongrel handlers for Rails,
-# Camping, Nitro, etc....
-
-require 'packet'
+require "packet"
require 'mongrel'
module Mongrel
- class MongrelProtocol < Packet::Connection
- def post_init
- @parser = HttpParser.new
- @params = HttpParams.new
- @nparsed = 0
- @request = nil
- @request_len = nil
- @linebuffer = ''
- end
+ class MongrelProtocol
+ def post_init
+ @parser = HttpParser.new
+ @params = HttpParams.new
+ @nparsed = 0
+ @request = nil
+ @request_len = nil
+ @linebuffer = ''
+ end
- def receive_data data
- @linebuffer << data
- @nparsed = @parser.execute(@params, @linebuffer, @nparsed) unless @parser.finished?
- if @parser.finished?
- if @request_len.nil?
- @request_len = @params[::Mongrel::Const::CONTENT_LENGTH].to_i
- script_name, path_info, handlers = ::Mongrel::HttpServer::Instance.classifier.resolve(@params[::Mongrel::Const::REQUEST_PATH])
- if handlers
- @params[::Mongrel::Const::PATH_INFO] = path_info
- @params[::Mongrel::Const::SCRIPT_NAME] = script_name
- @params[::Mongrel::Const::REMOTE_ADDR] = @params[::Mongrel::Const::HTTP_X_FORWARDED_FOR] #|| ::Socket.unpack_sockaddr_in(get_peername)[1]
- @notifiers = handlers.select { |h| h.request_notify }
- end
- if @request_len > ::Mongrel::Const::MAX_BODY
- new_buffer = Tempfile.new(::Mongrel::Const::MONGREL_TMP_BASE)
- new_buffer.binmode
- new_buffer << @linebuffer[@nparsed..-1]
- @linebuffer = new_buffer
- else
- @linebuffer = StringIO.new(@linebuffer[@nparsed..-1])
- @linebuffer.pos = @linebuffer.length
- end
- end
- if @linebuffer.length >= @request_len
- @linebuffer.rewind
- ::Mongrel::HttpServer::Instance.process_http_request(@params,@linebuffer,self)
- @linebuffer.delete if Tempfile === @linebuffer
- end
- elsif @linebuffer.length > ::Mongrel::Const::MAX_HEADER
- close_connection
- raise ::Mongrel::HttpParserError.new("HEADER is longer than allowed, aborting client early.")
- end
- rescue ::Mongrel::HttpParserError
- if $mongrel_debug_client
- STDERR.puts "#{Time.now}: BAD CLIENT (#{params[Const::HTTP_X_FORWARDED_FOR] || client.peeraddr.last}): #$!"
- STDERR.puts "#{Time.now}: REQUEST DATA: #{data.inspect}\n---\nPARAMS: #{params.inspect}\n---\n"
- end
- close_connection
- rescue Exception => e
- close_connection
- raise e
- end
+ def receive_data data
+ @linebuffer << data
+ @nparsed = @parser.execute(@params, @linebuffer, @nparsed) unless @parser.finished?
+ if @parser.finished?
+ if @request_len.nil?
+ @request_len = @params[::Mongrel::Const::CONTENT_LENGTH].to_i
+ script_name, path_info, handlers = ::Mongrel::HttpServer::Instance.classifier.resolve(@params[::Mongrel::Const::REQUEST_PATH])
+ if handlers
+ @params[::Mongrel::Const::PATH_INFO] = path_info
+ @params[::Mongrel::Const::SCRIPT_NAME] = script_name
+ @params[::Mongrel::Const::REMOTE_ADDR] = @params[::Mongrel::Const::HTTP_X_FORWARDED_FOR] #|| ::Socket.unpack_sockaddr_in(get_peername)[1]
+ @notifiers = handlers.select { |h| h.request_notify }
+ end
+ if @request_len > ::Mongrel::Const::MAX_BODY
+ new_buffer = Tempfile.new(::Mongrel::Const::MONGREL_TMP_BASE)
+ new_buffer.binmode
+ new_buffer << @linebuffer[@nparsed..-1]
+ @linebuffer = new_buffer
+ else
+ @linebuffer = StringIO.new(@linebuffer[@nparsed..-1])
+ @linebuffer.pos = @linebuffer.length
+ end
+ end
+ if @linebuffer.length >= @request_len
+ @linebuffer.rewind
+ ::Mongrel::HttpServer::Instance.process_http_request(@params,@linebuffer,self)
+ @linebuffer.delete if Tempfile === @linebuffer
+ end
+ elsif @linebuffer.length > ::Mongrel::Const::MAX_HEADER
+ close_connection
+ raise ::Mongrel::HttpParserError.new("HEADER is longer than allowed, aborting client early.")
+ end
+ rescue ::Mongrel::HttpParserError
+ if $mongrel_debug_client
+ STDERR.puts "#{Time.now}: BAD CLIENT (#{params[Const::HTTP_X_FORWARDED_FOR] || client.peeraddr.last}): #$!"
+ STDERR.puts "#{Time.now}: REQUEST DATA: #{data.inspect}\n---\nPARAMS: #{params.inspect}\n---\n"
+ end
+ close_connection
+ rescue Exception => e
+ close_connection
+ raise e
+ end
- def write data
- send_data data
- end
+ def write data
+ send_data data
+ end
- def closed?
- false
- end
+ def closed?
+ false
+ end
- end
+ end
- class HttpServer
- def initialize(host, port, num_processors=950, x=0, y=nil) # Deal with Mongrel 1.0.1 or earlier, as well as later.
- @socket = nil
- @classifier = URIClassifier.new
- @host = host
- @port = port
- @workers = ThreadGroup.new
- if y
- @throttle = x
- @timeout = y || 60
- else
- @timeout = x
- end
- @num_processors = num_processors #num_processors is pointless for evented....
- @death_time = 60
- self.class.const_set(:Instance,self)
- end
+ class HttpServer
+ def initialize(host, port, num_processors=950, x=0, y=nil) # Deal with Mongrel 1.0.1 or earlier, as well as later.
+ @socket = nil
+ @classifier = URIClassifier.new
+ @host = host
+ @port = port
+ @workers = ThreadGroup.new
+ if y
+ @throttle = x
+ @timeout = y || 60
+ else
+ @timeout = x
+ end
+ @num_processors = num_processors #num_processors is pointless for evented....
+ @death_time = 60
+ self.class.const_set(:Instance,self)
+ end
- def run
- trap('INT') { raise StopServer }
- trap('TERM') { raise StopServer }
- @acceptor = Thread.new do
- Packet::Reactor.run do |t_reactor|
- begin
+ def run
+ trap('INT') { raise StopServer }
+ trap('TERM') { raise StopServer }
+ @acceptor = Thread.new do
+ Packet::Reactor.run do |t_reactor|
+ begin
t_reactor.start_server(@host,@port,MongrelProtocol)
rescue StopServer
t_reactor.start_server
- end
+ end
end
- end
- end
+ end
+ end
- def process_http_request(params,linebuffer,client)
- if not params[Const::REQUEST_PATH]
- uri = URI.parse(params[Const::REQUEST_URI])
- params[Const::REQUEST_PATH] = uri.request_uri
- end
+ def process_http_request(params,linebuffer,client)
+ if not params[Const::REQUEST_PATH]
+ uri = URI.parse(params[Const::REQUEST_URI])
+ params[Const::REQUEST_PATH] = uri.request_uri
+ end
- raise "No REQUEST PATH" if not params[Const::REQUEST_PATH]
+ raise "No REQUEST PATH" if not params[Const::REQUEST_PATH]
- script_name, path_info, handlers = @classifier.resolve(params[Const::REQUEST_PATH])
+ script_name, path_info, handlers = @classifier.resolve(params[Const::REQUEST_PATH])
- if handlers
- notifiers = handlers.select { |h| h.request_notify }
- request = HttpRequest.new(params, linebuffer, notifiers)
+ if handlers
+ notifiers = handlers.select { |h| h.request_notify }
+ request = HttpRequest.new(params, linebuffer, notifiers)
- # request is good so far, continue processing the response
- response = HttpResponse.new(client)
+ # request is good so far, continue processing the response
+ response = HttpResponse.new(client)
- # Process each handler in registered order until we run out or one finalizes the response.
- dispatch_to_handlers(handlers,request,response)
+ # Process each handler in registered order until we run out or one finalizes the response.
+ dispatch_to_handlers(handlers,request,response)
- # And finally, if nobody closed the response off, we finalize it.
- unless response.done
- response.finished
- else
- response.close_connection
- end
- else
- # Didn't find it, return a stock 404 response.
- client.send_data(Const::ERROR_404_RESPONSE)
- client.close_connection
- end
- end
-
- def dispatch_to_handlers(handlers,request,response)
- handlers.each do |handler|
- handler.process(request, response)
- break if response.done
- end
- end
- end
+ # And finally, if nobody closed the response off, we finalize it.
+ unless response.done
+ response.finished
+ end
+ else
+ # Didn't find it, return a stock 404 response.
+ client.send_data(Const::ERROR_404_RESPONSE)
+ client.close_connection
+ end
+ end
- class HttpRequest
- def initialize(params, linebuffer, dispatchers)
- @params = params
- @dispatchers = dispatchers
- @body = linebuffer
- end
- end
+ def dispatch_to_handlers(handlers,request,response)
+ handlers.each do |handler|
+ handler.process(request, response)
+ break if response.done
+ end
+ end
+ end
- class HttpResponse
- def send_file(path, small_file = false)
- File.open(path, "rb") do |f|
- while chunk = f.read(Const::CHUNK_SIZE) and chunk.length > 0
- begin
- write(chunk)
- rescue Object => exc
- break
- end
- end
- end
- @body_sent = true
- end
+ class HttpRequest
+ def initialize(params, linebuffer, dispatchers)
+ @params = params
+ @dispatchers = dispatchers
+ @body = linebuffer
+ end
+ end
- def write(data)
- @socket.send_data data
- end
+ class HttpResponse
+ def send_file(path, small_file = false)
+ File.open(path, "rb") do |f|
+ while chunk = f.read(Const::CHUNK_SIZE) and chunk.length > 0
+ begin
+ write(chunk)
+ rescue Object => exc
+ break
+ end
+ end
+ end
+ @body_sent = true
+ end
- def close_connection_after_writing
- @socket.close_connection
- end
+ def write(data)
+ @socket.send_data data
+ end
- def socket_error(details)
- @socket.close_connection
- done = true
- raise details
- end
+ def close_connection_after_writing
+ @socket.close_connection
+ end
- def finished
- send_status
- send_header
- send_body
- @socket.close_connection
- end
- end
-
- class Configurator
- # This version fixes a bug in the regular Mongrel version by adding
- # initialization of groups.
- def change_privilege(user, group)
- if user and group
- log "Initializing groups for {#user}:{#group}."
- Process.initgroups(user,Etc.getgrnam(group).gid)
- end
-
- if group
- log "Changing group to #{group}."
- Process::GID.change_privilege(Etc.getgrnam(group).gid)
- end
-
- if user
- log "Changing user to #{user}."
- Process::UID.change_privilege(Etc.getpwnam(user).uid)
- end
- rescue Errno::EPERM
- log "FAILED to change user:group #{user}:#{group}: #$!"
- exit 1
- end
- end
+ def socket_error(details)
+ @socket.close_connection
+ done = true
+ raise details
+ end
+
+ def finished
+ send_status
+ send_header
+ send_body
+ @socket.close_connection
+ end
+ end
+
+ class Configurator
+ # This version fixes a bug in the regular Mongrel version by adding
+ # initialization of groups.
+ def change_privilege(user, group)
+ if user and group
+ log "Initializing groups for {#user}:{#group}."
+ Process.initgroups(user,Etc.getgrnam(group).gid)
+ end
+
+ if group
+ log "Changing group to #{group}."
+ Process::GID.change_privilege(Etc.getgrnam(group).gid)
+ end
+
+ if user
+ log "Changing user to #{user}."
+ Process::UID.change_privilege(Etc.getpwnam(user).uid)
+ end
+ rescue Errno::EPERM
+ log "FAILED to change user:group #{user}:#{group}: #$!"
+ exit 1
+ end
+ end
end
+
+