From a59c388dd518d0b0ff85d0621d3406fcc23d6173 Mon Sep 17 00:00:00 2001 From: Ian Ownbey Date: Sat, 22 Nov 2008 17:48:36 -0800 Subject: Non working rack implementation --- lib/mongrel.rb | 44 +++++++++++++++++++++++++------------------- lib/mongrel/http_request.rb | 21 ++++++++++++++++++++- lib/mongrel/http_response.rb | 21 +++++++++++---------- 3 files changed, 56 insertions(+), 30 deletions(-) (limited to 'lib') diff --git a/lib/mongrel.rb b/lib/mongrel.rb index f09a617..e3c56be 100644 --- a/lib/mongrel.rb +++ b/lib/mongrel.rb @@ -17,6 +17,7 @@ require 'mongrel/gems' Mongrel::Gems.require 'cgi_multipart_eof_fix' Mongrel::Gems.require 'fastthread' require 'thread' +require 'rack' # Ruby Mongrel require 'mongrel/cgi' @@ -88,21 +89,21 @@ module Mongrel # The throttle parameter is a sleep timeout (in hundredths of a second) that is placed between # socket.accept calls in order to give the server a cheap throttle time. It defaults to 0 and # actually if it is 0 then the sleep is not done at all. - def initialize(host, port, num_processors=950, throttle=0, timeout=60) - + def initialize(host, port, app, opts = {}) tries = 0 @socket = TCPServer.new(host, port) if defined?(Fcntl::FD_CLOEXEC) @socket.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) end - @classifier = URIClassifier.new @host = host @port = port @workers = ThreadGroup.new - @throttle = throttle / 100.0 - @num_processors = num_processors - @timeout = timeout + # Set default opts + @app = app + @num_processors = opts.delete(:num_processors) + @throttle = (opts.delete(:throttle) || 0) / 100 + @timeout = opts.delete(:timeout) || 60 end # Does the majority of the IO processing. It has been written in Ruby using @@ -134,6 +135,7 @@ module Mongrel raise "No REQUEST PATH" if not params[Const::REQUEST_PATH] + script_name, path_info, handlers = @classifier.resolve(params[Const::REQUEST_PATH]) if handlers @@ -154,20 +156,23 @@ module Mongrel # in the case of large file uploads the user could close the socket, so skip those requests break if request.body == nil # nil signals from HttpRequest::initialize that the request was aborted + raise "CALLING APPPPPPP" + app_responce = @app.call(request.env) + response = HttpResponse.new(client, app_response).start # 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. - handlers.each do |handler| - handler.process(request, response) - break if response.done or client.closed? - end - - # And finally, if nobody closed the response off, we finalize it. - unless response.done or client.closed? - response.finished - end + # response = HttpResponse.new(client) + + # # Process each handler in registered order until we run out or one finalizes the response. + # handlers.each do |handler| + # handler.process(request, response) + # break if response.done or client.closed? + # end + + # # And finally, if nobody closed the response off, we finalize it. + # unless response.done or client.closed? + # response.finished + # end else # Didn't find it, return a stock 404 response. client.write(Const::ERROR_404_RESPONSE) @@ -260,7 +265,8 @@ 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 + def start! + p @num_processors BasicSocket.do_not_reverse_lookup=true configure_socket_options diff --git a/lib/mongrel/http_request.rb b/lib/mongrel/http_request.rb index c8d4ce4..8df3a5a 100644 --- a/lib/mongrel/http_request.rb +++ b/lib/mongrel/http_request.rb @@ -58,6 +58,25 @@ module Mongrel @body.rewind if @body end + # returns an environment which is rackable + # http://rack.rubyforge.org/doc/files/SPEC.html + def env + env = params.clone + env.delete "HTTP_CONTENT_TYPE" + env.delete "HTTP_CONTENT_LENGTH" + env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" + env.update({"rack.version" => [0,1], + "rack.input" => @body, + "rack.errors" => STDERR, + + "rack.multithread" => true, + "rack.multiprocess" => false, # ??? + "rack.run_once" => false, + + "rack.url_scheme" => "http", + }) + end + # updates all dispatchers about our progress def update_request_progress(clen, total) return if @dispatchers.nil? || @dispatchers.empty? @@ -152,4 +171,4 @@ module Mongrel return params end end -end \ No newline at end of file +end diff --git a/lib/mongrel/http_response.rb b/lib/mongrel/http_response.rb index 3076712..08d4d75 100644 --- a/lib/mongrel/http_response.rb +++ b/lib/mongrel/http_response.rb @@ -39,12 +39,13 @@ module Mongrel attr_reader :header_sent attr_reader :status_sent - def initialize(socket) + def initialize(socket, app_responce) @socket = socket - @body = StringIO.new - @status = 404 + @app_responce = app_responce + @body = app_responce[2] + @status = app_responce[0] @reason = nil - @header = HeaderOut.new(StringIO.new) + @header = HeaderOut.new(app_responce[1]) @header[Const::DATE] = Time.now.httpdate @body_sent = false @header_sent = false @@ -59,10 +60,10 @@ module Mongrel # by simple passing "finalize=true" to the start method. By default # all handlers run and then mongrel finalizes the request when they're # all done. - def start(status=200, finalize=false, reason=nil) - @status = status.to_i - @reason = reason - yield @header, @body + # TODO: docs + def start #(status=200, finalize=false, reason=nil) + @reason = nil # TODO take this out + out.write(@body) finished if finalize end @@ -78,7 +79,7 @@ module Mongrel # XXX Dubious ( http://mongrel.rubyforge.org/ticket/19 ) @header.out.close @header = HeaderOut.new(StringIO.new) - + @body.close @body = StringIO.new end @@ -163,4 +164,4 @@ module Mongrel end end -end \ No newline at end of file +end -- cgit v1.2.3-24-ge0c7 From 01a76eb1ddc67dda21cc2646dc73c15830cb3de7 Mon Sep 17 00:00:00 2001 From: Ian Ownbey Date: Sat, 22 Nov 2008 18:00:10 -0800 Subject: removed dispatchers --- lib/mongrel.rb | 60 ++++++++++++++------------------------------- lib/mongrel/http_request.rb | 8 +----- 2 files changed, 20 insertions(+), 48 deletions(-) (limited to 'lib') diff --git a/lib/mongrel.rb b/lib/mongrel.rb index e3c56be..423abeb 100644 --- a/lib/mongrel.rb +++ b/lib/mongrel.rb @@ -138,47 +138,25 @@ module Mongrel script_name, path_info, handlers = @classifier.resolve(params[Const::REQUEST_PATH]) - if handlers - params[Const::PATH_INFO] = path_info - params[Const::SCRIPT_NAME] = script_name - - # From http://www.ietf.org/rfc/rfc3875 : - # "Script authors should be aware that the REMOTE_ADDR and REMOTE_HOST - # meta-variables (see sections 4.1.8 and 4.1.9) may not identify the - # ultimate source of the request. They identify the client for the - # immediate request to the server; that client may be a proxy, gateway, - # or other intermediary acting on behalf of the actual source client." - params[Const::REMOTE_ADDR] = client.peeraddr.last - - # select handlers that want more detailed request notification - notifiers = handlers.select { |h| h.request_notify } - request = HttpRequest.new(params, client, notifiers) - - # in the case of large file uploads the user could close the socket, so skip those requests - break if request.body == nil # nil signals from HttpRequest::initialize that the request was aborted - raise "CALLING APPPPPPP" - app_responce = @app.call(request.env) - response = HttpResponse.new(client, app_response).start - - # 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. - # handlers.each do |handler| - # handler.process(request, response) - # break if response.done or client.closed? - # end - - # # And finally, if nobody closed the response off, we finalize it. - # unless response.done or client.closed? - # response.finished - # end - else - # Didn't find it, return a stock 404 response. - client.write(Const::ERROR_404_RESPONSE) - end - - break #done + params[Const::PATH_INFO] = path_info + params[Const::SCRIPT_NAME] = script_name + + # From http://www.ietf.org/rfc/rfc3875 : + # "Script authors should be aware that the REMOTE_ADDR and REMOTE_HOST + # meta-variables (see sections 4.1.8 and 4.1.9) may not identify the + # ultimate source of the request. They identify the client for the + # immediate request to the server; that client may be a proxy, gateway, + # or other intermediary acting on behalf of the actual source client." + params[Const::REMOTE_ADDR] = client.peeraddr.last + + # select handlers that want more detailed request notification + request = HttpRequest.new(params, client) + + # in the case of large file uploads the user could close the socket, so skip those requests + break if request.body == nil # nil signals from HttpRequest::initialize that the request was aborted + app_response = @app.call(request.env) + response = HttpResponse.new(client, app_response).start + break #done else # Parser is not done, queue up more data to read and continue parsing chunk = client.readpartial(Const::CHUNK_SIZE) diff --git a/lib/mongrel/http_request.rb b/lib/mongrel/http_request.rb index 8df3a5a..0e3790f 100644 --- a/lib/mongrel/http_request.rb +++ b/lib/mongrel/http_request.rb @@ -22,17 +22,11 @@ module Mongrel # You don't really call this. It's made for you. # Main thing it does is hook up the params, and store any remaining # body data into the HttpRequest.body attribute. - def initialize(params, socket, dispatchers) + def initialize(params, socket) @params = params @socket = socket - @dispatchers = dispatchers content_length = @params[Const::CONTENT_LENGTH].to_i remain = content_length - @params.http_body.length - - # tell all dispatchers the request has begun - @dispatchers.each do |dispatcher| - dispatcher.request_begins(@params) - end unless @dispatchers.nil? || @dispatchers.empty? # Some clients (like FF1.0) report 0 for body and then send a body. This will probably truncate them but at least the request goes through usually. if remain <= 0 -- cgit v1.2.3-24-ge0c7 From 18ac0fcc47f5533d695d629ca60f6d8cd2befd3f Mon Sep 17 00:00:00 2001 From: Ian Ownbey Date: Sat, 22 Nov 2008 18:20:46 -0800 Subject: test_ws passes with rack --- lib/mongrel/header_out.rb | 10 ++++++++-- lib/mongrel/http_response.rb | 15 +++++++-------- 2 files changed, 15 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/mongrel/header_out.rb b/lib/mongrel/header_out.rb index b34e95e..008bff8 100644 --- a/lib/mongrel/header_out.rb +++ b/lib/mongrel/header_out.rb @@ -10,13 +10,19 @@ module Mongrel attr_reader :out attr_accessor :allowed_duplicates - def initialize(out) + def initialize(out = StringIO.new) @sent = {} @allowed_duplicates = {"Set-Cookie" => true, "Set-Cookie2" => true, "Warning" => true, "WWW-Authenticate" => true} @out = out end + def merge!(hash) + hash.each do |key, value| + self[key] = value + end + end + # Simply writes "#{key}: #{value}" to an output buffer. def[]=(key,value) if not @sent.has_key?(key) or @allowed_duplicates.has_key?(key) @@ -25,4 +31,4 @@ module Mongrel end end end -end \ No newline at end of file +end diff --git a/lib/mongrel/http_response.rb b/lib/mongrel/http_response.rb index 08d4d75..bda2ed3 100644 --- a/lib/mongrel/http_response.rb +++ b/lib/mongrel/http_response.rb @@ -39,14 +39,15 @@ module Mongrel attr_reader :header_sent attr_reader :status_sent - def initialize(socket, app_responce) + def initialize(socket, app_response) @socket = socket - @app_responce = app_responce - @body = app_responce[2] - @status = app_responce[0] + @app_response = app_response + @body = StringIO.new(app_response[2].join('')) + @status = app_response[0] @reason = nil - @header = HeaderOut.new(app_responce[1]) + @header = HeaderOut.new @header[Const::DATE] = Time.now.httpdate + @header.merge!(app_response[1]) @body_sent = false @header_sent = false @status_sent = false @@ -62,9 +63,7 @@ module Mongrel # all done. # TODO: docs def start #(status=200, finalize=false, reason=nil) - @reason = nil # TODO take this out - out.write(@body) - finished if finalize + finished end # Primarily used in exception handling to reset the response output in order to write -- cgit v1.2.3-24-ge0c7 From 5139bbfd22c48e29ea6c66d3e47631877db65492 Mon Sep 17 00:00:00 2001 From: Ian Ownbey Date: Sat, 22 Nov 2008 18:56:06 -0800 Subject: Join thread at the end of start --- lib/mongrel.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/mongrel.rb b/lib/mongrel.rb index 423abeb..57b849b 100644 --- a/lib/mongrel.rb +++ b/lib/mongrel.rb @@ -101,7 +101,7 @@ module Mongrel @workers = ThreadGroup.new # Set default opts @app = app - @num_processors = opts.delete(:num_processors) + @num_processors = opts.delete(:num_processors) || 950 @throttle = (opts.delete(:throttle) || 0) / 100 @timeout = opts.delete(:timeout) || 60 end @@ -244,7 +244,6 @@ 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 start! - p @num_processors BasicSocket.do_not_reverse_lookup=true configure_socket_options @@ -264,7 +263,6 @@ module Mongrel end worker_list = @workers.list - if worker_list.length >= @num_processors STDERR.puts "Server overloaded with #{worker_list.length} processors (#@num_processors max). Dropping connection." client.close rescue nil @@ -296,7 +294,7 @@ module Mongrel end end - return @acceptor + return @acceptor.join end # Simply registers a handler with the internal URIClassifier. When the URI is -- cgit v1.2.3-24-ge0c7 From b1dd32f73eb72d861810bd96305b85d082606c5b Mon Sep 17 00:00:00 2001 From: Ian Ownbey Date: Fri, 28 Nov 2008 03:23:34 -0500 Subject: Unjoined thread for now. Will fix later. --- lib/mongrel.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/mongrel.rb b/lib/mongrel.rb index 57b849b..9fe0daf 100644 --- a/lib/mongrel.rb +++ b/lib/mongrel.rb @@ -294,7 +294,7 @@ module Mongrel end end - return @acceptor.join + return @acceptor end # Simply registers a handler with the internal URIClassifier. When the URI is -- cgit v1.2.3-24-ge0c7 From c178815ef6496d3d2dfe83b77a0332138a4ae1ee Mon Sep 17 00:00:00 2001 From: Ian Ownbey Date: Mon, 1 Dec 2008 00:50:24 -0500 Subject: Got tests working with rack --- lib/mongrel/http_response.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/mongrel/http_response.rb b/lib/mongrel/http_response.rb index bda2ed3..811570b 100644 --- a/lib/mongrel/http_response.rb +++ b/lib/mongrel/http_response.rb @@ -87,7 +87,7 @@ module Mongrel def send_status(content_length=@body.length) if not @status_sent @header['Content-Length'] = content_length if content_length and @status != 304 - write(Const::STATUS_FORMAT % [@status, @reason || HTTP_STATUS_CODES[@status]]) + write(Const::STATUS_FORMAT % [@status, HTTP_STATUS_CODES[@status]]) @status_sent = true end end -- cgit v1.2.3-24-ge0c7 From 2482c33a3b616ad62d0b564c0d7224dd8432ffdf Mon Sep 17 00:00:00 2001 From: Ian Ownbey Date: Mon, 1 Dec 2008 00:57:05 -0500 Subject: Removed configurator, replaced by Racks UrlMap --- lib/mongrel/configurator.rb | 388 -------------------------------------------- 1 file changed, 388 deletions(-) delete mode 100644 lib/mongrel/configurator.rb (limited to 'lib') diff --git a/lib/mongrel/configurator.rb b/lib/mongrel/configurator.rb deleted file mode 100644 index 439b44c..0000000 --- a/lib/mongrel/configurator.rb +++ /dev/null @@ -1,388 +0,0 @@ -require 'yaml' -require 'etc' - -module Mongrel - # Implements a simple DSL for configuring a Mongrel server for your - # purposes. More used by framework implementers to setup Mongrel - # how they like, but could be used by regular folks to add more things - # to an existing mongrel configuration. - # - # It is used like this: - # - # require 'mongrel' - # config = Mongrel::Configurator.new :host => "127.0.0.1" do - # listener :port => 3000 do - # uri "/app", :handler => Mongrel::DirHandler.new(".", load_mime_map("mime.yaml")) - # end - # run - # end - # - # This will setup a simple DirHandler at the current directory and load additional - # mime types from mimy.yaml. The :host => "127.0.0.1" is actually not - # specific to the servers but just a hash of default parameters that all - # server or uri calls receive. - # - # When you are inside the block after Mongrel::Configurator.new you can simply - # call functions that are part of Configurator (like server, uri, daemonize, etc) - # without having to refer to anything else. You can also call these functions on - # the resulting object directly for additional configuration. - # - # A major thing about Configurator is that it actually lets you configure - # multiple listeners for any hosts and ports you want. These are kept in a - # map config.listeners so you can get to them. - # - # * :pid_file => Where to write the process ID. - class Configurator - attr_reader :listeners - attr_reader :defaults - attr_reader :needs_restart - - # You pass in initial defaults and then a block to continue configuring. - def initialize(defaults={}, &block) - @listener = nil - @listener_name = nil - @listeners = {} - @defaults = defaults - @needs_restart = false - @pid_file = defaults[:pid_file] - - if block - cloaker(&block).bind(self).call - end - end - - # Change privileges of the process to specified user and group. - def change_privilege(user, group) - begin - uid, gid = Process.euid, Process.egid - target_uid = Etc.getpwnam(user).uid if user - target_gid = Etc.getgrnam(group).gid if group - - if uid != target_uid or gid != target_gid - log "Initiating groups for #{user.inspect}:#{group.inspect}." - Process.initgroups(user, target_gid) - - log "Changing group to #{group.inspect}." - Process::GID.change_privilege(target_gid) - - log "Changing user to #{user.inspect}." - Process::UID.change_privilege(target_uid) - end - rescue Errno::EPERM => e - log "Couldn't change user and group to #{user.inspect}:#{group.inspect}: #{e.to_s}." - log "Mongrel failed to start." - exit 1 - end - end - - def remove_pid_file - File.unlink(@pid_file) if @pid_file and File.exists?(@pid_file) - end - - # Writes the PID file if we're not on Windows. - def write_pid_file - if RUBY_PLATFORM !~ /djgpp|(cyg|ms|bcc)win|mingw/ - log "Writing PID file to #{@pid_file}" - open(@pid_file,"w") {|f| f.write(Process.pid) } - open(@pid_file,"w") do |f| - f.write(Process.pid) - File.chmod(0644, @pid_file) - end - end - end - - # Generates a class for cloaking the current self and making the DSL nicer. - def cloaking_class - class << self - self - end - end - - # Do not call this. You were warned. - def cloaker(&block) - cloaking_class.class_eval do - define_method :cloaker_, &block - meth = instance_method( :cloaker_ ) - remove_method :cloaker_ - meth - end - end - - # This will resolve the given options against the defaults. - # Normally just used internally. - def resolve_defaults(options) - options.merge(@defaults) - end - - # Starts a listener block. This is the only one that actually takes - # a block and then you make Configurator.uri calls in order to setup - # your URIs and handlers. If you write your Handlers as GemPlugins - # then you can use load_plugins and plugin to load them. - # - # It expects the following options (or defaults): - # - # * :host => Host name to bind. - # * :port => Port to bind. - # * :num_processors => The maximum number of concurrent threads allowed. - # * :throttle => Time to pause (in hundredths of a second) between accepting clients. - # * :timeout => Time to wait (in seconds) before killing a stalled thread. - # * :user => User to change to, must have :group as well. - # * :group => Group to change to, must have :user as well. - # - def listener(options={},&block) - raise "Cannot call listener inside another listener block." if (@listener or @listener_name) - ops = resolve_defaults(options) - ops[:num_processors] ||= 950 - ops[:throttle] ||= 0 - ops[:timeout] ||= 60 - - @listener = Mongrel::HttpServer.new(ops[:host], ops[:port].to_i, ops[:num_processors].to_i, ops[:throttle].to_i, ops[:timeout].to_i) - @listener_name = "#{ops[:host]}:#{ops[:port]}" - @listeners[@listener_name] = @listener - - if ops[:user] and ops[:group] - change_privilege(ops[:user], ops[:group]) - end - - # Does the actual cloaking operation to give the new implicit self. - if block - cloaker(&block).bind(self).call - end - - # all done processing this listener setup, reset implicit variables - @listener = nil - @listener_name = nil - end - - - # Called inside a Configurator.listener block in order to - # add URI->handler mappings for that listener. Use this as - # many times as you like. It expects the following options - # or defaults: - # - # * :handler => HttpHandler -- Handler to use for this location. - # * :in_front => true/false -- Rather than appending, it prepends this handler. - def uri(location, options={}) - ops = resolve_defaults(options) - @listener.register(location, ops[:handler], ops[:in_front]) - end - - - # Daemonizes the current Ruby script turning all the - # listeners into an actual "server" or detached process. - # You must call this *before* frameworks that open files - # as otherwise the files will be closed by this function. - # - # Does not work for Win32 systems (the call is silently ignored). - # - # Requires the following options or defaults: - # - # * :cwd => Directory to change to. - # * :log_file => Where to write STDOUT and STDERR. - # - # It is safe to call this on win32 as it will only require the daemons - # gem/library if NOT win32. - def daemonize(options={}) - ops = resolve_defaults(options) - # save this for later since daemonize will hose it - if RUBY_PLATFORM !~ /djgpp|(cyg|ms|bcc)win|mingw/ - require 'daemons/daemonize' - - logfile = ops[:log_file] - if logfile[0].chr != "/" - logfile = File.join(ops[:cwd],logfile) - if not File.exist?(File.dirname(logfile)) - log "!!! Log file directory not found at full path #{File.dirname(logfile)}. Update your configuration to use a full path." - exit 1 - end - end - - Daemonize.daemonize(logfile) - - # change back to the original starting directory - Dir.chdir(ops[:cwd]) - - else - log "WARNING: Win32 does not support daemon mode." - end - end - - - # Uses the GemPlugin system to easily load plugins based on their - # gem dependencies. You pass in either an :includes => [] or - # :excludes => [] setting listing the names of plugins to include - # or exclude from the determining the dependencies. - def load_plugins(options={}) - ops = resolve_defaults(options) - - load_settings = {} - if ops[:includes] - ops[:includes].each do |plugin| - load_settings[plugin] = GemPlugin::INCLUDE - end - end - - if ops[:excludes] - ops[:excludes].each do |plugin| - load_settings[plugin] = GemPlugin::EXCLUDE - end - end - - GemPlugin::Manager.instance.load(load_settings) - end - - - # Easy way to load a YAML file and apply default settings. - def load_yaml(file, default={}) - default.merge(YAML.load_file(file)) - end - - - # Loads the MIME map file and checks that it is correct - # on loading. This is commonly passed to Mongrel::DirHandler - # or any framework handler that uses DirHandler to serve files. - # You can also include a set of default MIME types as additional - # settings. See Mongrel::DirHandler for how the MIME types map - # is organized. - def load_mime_map(file, mime={}) - # configure any requested mime map - mime = load_yaml(file, mime) - - # check all the mime types to make sure they are the right format - mime.each {|k,v| log "WARNING: MIME type #{k} must start with '.'" if k.index(".") != 0 } - - return mime - end - - - # Loads and creates a plugin for you based on the given - # name and configured with the selected options. The options - # are merged with the defaults prior to passing them in. - def plugin(name, options={}) - ops = resolve_defaults(options) - GemPlugin::Manager.instance.create(name, ops) - end - - # Lets you do redirects easily as described in Mongrel::RedirectHandler. - # You use it inside the configurator like this: - # - # redirect("/test", "/to/there") # simple - # redirect("/to", /t/, 'w') # regexp - # redirect("/hey", /(w+)/) {|match| ...} # block - # - def redirect(from, pattern, replacement = nil, &block) - uri from, :handler => Mongrel::RedirectHandler.new(pattern, replacement, &block) - end - - # Works like a meta run method which goes through all the - # configured listeners. Use the Configurator.join method - # to prevent Ruby from exiting until each one is done. - def run - @listeners.each {|name,s| - s.run - } - - $mongrel_sleeper_thread = Thread.new { loop { sleep 1 } } - end - - # Calls .stop on all the configured listeners so they - # stop processing requests (gracefully). By default it - # assumes that you don't want to restart. - def stop(needs_restart=false, synchronous=false) - @listeners.each do |name,s| - s.stop(synchronous) - end - @needs_restart = needs_restart - end - - - # This method should actually be called *outside* of the - # Configurator block so that you can control it. In other words - # do it like: config.join. - def join - @listeners.values.each {|s| s.acceptor.join } - end - - - # Calling this before you register your URIs to the given location - # will setup a set of handlers that log open files, objects, and the - # parameters for each request. This helps you track common problems - # found in Rails applications that are either slow or become unresponsive - # after a little while. - # - # You can pass an extra parameter *what* to indicate what you want to - # debug. For example, if you just want to dump rails stuff then do: - # - # debug "/", what = [:rails] - # - # And it will only produce the log/mongrel_debug/rails.log file. - # Available options are: :access, :files, :objects, :threads, :rails - # - # NOTE: Use [:files] to get accesses dumped to stderr like with WEBrick. - def debug(location, what = [:access, :files, :objects, :threads, :rails]) - require 'mongrel/debug' - handlers = { - :access => "/handlers/requestlog::access", - :files => "/handlers/requestlog::files", - :objects => "/handlers/requestlog::objects", - :threads => "/handlers/requestlog::threads", - :rails => "/handlers/requestlog::params" - } - - # turn on the debugging infrastructure, and ObjectTracker is a pig - MongrelDbg.configure - - # now we roll through each requested debug type, turn it on and load that plugin - what.each do |type| - MongrelDbg.begin_trace type - uri location, :handler => plugin(handlers[type]) - end - end - - # Used to allow you to let users specify their own configurations - # inside your Configurator setup. You pass it a script name and - # it reads it in and does an eval on the contents passing in the right - # binding so they can put their own Configurator statements. - def run_config(script) - open(script) {|f| eval(f.read, proc {self}) } - end - - # Sets up the standard signal handlers that are used on most Ruby - # It only configures if the platform is not win32 and doesn't do - # a HUP signal since this is typically framework specific. - # - # Requires a :pid_file option given to Configurator.new to indicate a file to delete. - # It sets the MongrelConfig.needs_restart attribute if - # the start command should reload. It's up to you to detect this - # and do whatever is needed for a "restart". - # - # This command is safely ignored if the platform is win32 (with a warning) - def setup_signals(options={}) - ops = resolve_defaults(options) - - # forced shutdown, even if previously restarted (actually just like TERM but for CTRL-C) - trap("INT") { log "INT signal received."; stop(false) } - - # clean up the pid file always - at_exit { remove_pid_file } - - if RUBY_PLATFORM !~ /djgpp|(cyg|ms|bcc)win|mingw/ - # graceful shutdown - trap("TERM") { log "TERM signal received."; stop } - trap("USR1") { log "USR1 received, toggling $mongrel_debug_client to #{!$mongrel_debug_client}"; $mongrel_debug_client = !$mongrel_debug_client } - # restart - trap("USR2") { log "USR2 signal received."; stop(true) } - - log "Signals ready. TERM => stop. USR2 => restart. INT => stop (no restart)." - else - log "Signals ready. INT => stop (no restart)." - end - end - - # Logs a simple message to STDERR (or the mongrel log if in daemon mode). - def log(msg) - STDERR.print "** ", msg, "\n" - end - - end -end -- cgit v1.2.3-24-ge0c7 From d2dcbb98ae7c3963c0c658c196644095ccaec1ca Mon Sep 17 00:00:00 2001 From: Ian Ownbey Date: Mon, 1 Dec 2008 03:45:02 -0500 Subject: Got rid of handlers and test_conditional, now people just use rack --- lib/mongrel/handlers.rb | 236 ------------------------------------------------ 1 file changed, 236 deletions(-) (limited to 'lib') diff --git a/lib/mongrel/handlers.rb b/lib/mongrel/handlers.rb index e643025..ce24628 100644 --- a/lib/mongrel/handlers.rb +++ b/lib/mongrel/handlers.rb @@ -88,198 +88,6 @@ module Mongrel end - # - # Serves the contents of a directory. You give it the path to the root - # where the files are located, and it tries to find the files based on - # the PATH_INFO inside the directory. If the requested path is a - # directory then it returns a simple directory listing. - # - # It does a simple protection against going outside it's root path by - # converting all paths to an absolute expanded path, and then making - # sure that the final expanded path includes the root path. If it doesn't - # than it simply gives a 404. - # - # If you pass nil as the root path, it will not check any locations or - # expand any paths. This lets you serve files from multiple drives - # on win32. It should probably not be used in a public-facing way - # without additional checks. - # - # The default content type is "text/plain; charset=ISO-8859-1" but you - # can change it anything you want using the DirHandler.default_content_type - # attribute. - # - class DirHandler < HttpHandler - attr_accessor :default_content_type - attr_reader :path - - MIME_TYPES_FILE = "mime_types.yml" - MIME_TYPES = YAML.load_file(File.join(File.dirname(__FILE__), MIME_TYPES_FILE)) - - ONLY_HEAD_GET="Only HEAD and GET allowed.".freeze - - # You give it the path to the directory root and and optional listing_allowed and index_html - def initialize(path, listing_allowed=true, index_html="index.html") - @path = File.expand_path(path) if path - @listing_allowed = listing_allowed - @index_html = index_html - @default_content_type = "application/octet-stream".freeze - end - - # Checks if the given path can be served and returns the full path (or nil if not). - def can_serve(path_info) - - req_path = HttpRequest.unescape(path_info) - # Add the drive letter or root path - req_path = File.join(@path, req_path) if @path - req_path = File.expand_path req_path - - if File.exist? req_path and (!@path or req_path.index(@path) == 0) - # It exists and it's in the right location - if File.directory? req_path - # The request is for a directory - index = File.join(req_path, @index_html) - if File.exist? index - # Serve the index - return index - elsif @listing_allowed - # Serve the directory - return req_path - else - # Do not serve anything - return nil - end - else - # It's a file and it's there - return req_path - end - else - # does not exist or isn't in the right spot - return nil - end - end - - - # Returns a simplistic directory listing if they're enabled, otherwise a 403. - # Base is the base URI from the REQUEST_URI, dir is the directory to serve - # on the file system (comes from can_serve()), and response is the HttpResponse - # object to send the results on. - def send_dir_listing(base, dir, response) - # take off any trailing / so the links come out right - base = HttpRequest.unescape(base) - base.chop! if base[-1] == "/"[-1] - - if @listing_allowed - response.start(200) do |head,out| - head[Const::CONTENT_TYPE] = "text/html" - out << "Directory Listing" - Dir.entries(dir).each do |child| - next if child == "." - out << "" - out << (child == ".." ? "Up to parent.." : child) - out << "
" - end - out << "" - end - else - response.start(403) do |head,out| - out.write("Directory listings not allowed") - end - end - end - - - # Sends the contents of a file back to the user. Not terribly efficient since it's - # opening and closing the file for each read. - def send_file(req_path, request, response, header_only=false) - - stat = File.stat(req_path) - - # Set the last modified times as well and etag for all files - mtime = stat.mtime - # Calculated the same as apache, not sure how well the works on win32 - etag = Const::ETAG_FORMAT % [mtime.to_i, stat.size, stat.ino] - - modified_since = request.params[Const::HTTP_IF_MODIFIED_SINCE] - none_match = request.params[Const::HTTP_IF_NONE_MATCH] - - # test to see if this is a conditional request, and test if - # the response would be identical to the last response - same_response = case - when modified_since && !last_response_time = Time.httpdate(modified_since) rescue nil : false - when modified_since && last_response_time > Time.now : false - when modified_since && mtime > last_response_time : false - when none_match && none_match == '*' : false - when none_match && !none_match.strip.split(/\s*,\s*/).include?(etag) : false - else modified_since || none_match # validation successful if we get this far and at least one of the header exists - end - - header = response.header - header[Const::ETAG] = etag - - if same_response - response.start(304) {} - else - - # First we setup the headers and status then we do a very fast send on the socket directly - - # Support custom responses except 404, which is the default. A little awkward. - response.status = 200 if response.status == 404 - header[Const::LAST_MODIFIED] = mtime.httpdate - - # Set the mime type from our map based on the ending - dot_at = req_path.rindex('.') - if dot_at - header[Const::CONTENT_TYPE] = MIME_TYPES[req_path[dot_at .. -1]] || @default_content_type - else - header[Const::CONTENT_TYPE] = @default_content_type - end - - # send a status with out content length - response.send_status(stat.size) - response.send_header - - if not header_only - response.send_file(req_path, stat.size < Const::CHUNK_SIZE * 2) - end - end - end - - # Process the request to either serve a file or a directory listing - # if allowed (based on the listing_allowed parameter to the constructor). - def process(request, response) - req_method = request.params[Const::REQUEST_METHOD] || Const::GET - req_path = can_serve request.params[Const::PATH_INFO] - if not req_path - # not found, return a 404 - response.start(404) do |head,out| - out << "File not found" - end - else - begin - if File.directory? req_path - send_dir_listing(request.params[Const::REQUEST_URI], req_path, response) - elsif req_method == Const::HEAD - send_file(req_path, request, response, true) - elsif req_method == Const::GET - send_file(req_path, request, response, false) - else - response.start(403) {|head,out| out.write(ONLY_HEAD_GET) } - end - rescue => details - STDERR.puts "Error sending file #{req_path}: #{details}" - end - end - end - - # There is a small number of default mime types for extensions, but - # this lets you add any others you'll need when serving content. - def DirHandler::add_mime_type(extension, type) - MIME_TYPES[extension] = type - end - - end - - # When added to a config script (-S in mongrel_rails) it will # look at the client's allowed response types and then gzip # compress anything that is going out. @@ -421,48 +229,4 @@ module Mongrel end end end - - # This handler allows you to redirect one url to another. - # You can use it like String#gsub, where the string is the REQUEST_URI. - # REQUEST_URI is the full path with GET parameters. - # - # Eg. /test/something?help=true&disclaimer=false - # - # == Examples - # - # h = Mongrel::HttpServer.new('0.0.0.0') - # h.register '/test', Mongrel::RedirectHandler.new('/to/there') # simple - # h.register '/to', Mongrel::RedirectHandler.new(/t/, 'w') # regexp - # # and with a block - # h.register '/hey', Mongrel::RedirectHandler.new(/(\w+)/) { |match| ... } - # - class RedirectHandler < Mongrel::HttpHandler - # You set the rewrite rules when building the object. - # - # pattern => What to look for or replacement if used alone - # - # replacement, block => One of them is used to replace the found text - - def initialize(pattern, replacement = nil, &block) - unless replacement or block - @pattern, @replacement = nil, pattern - else - @pattern, @replacement, @block = pattern, replacement, block - end - end - - # Process the request and return a redirect response - def process(request, response) - unless @pattern - response.socket.write(Mongrel::Const::REDIRECT % @replacement) - else - if @block - new_path = request.params['REQUEST_URI'].gsub(@pattern, &@block) - else - new_path = request.params['REQUEST_URI'].gsub(@pattern, @replacement) - end - response.socket.write(Mongrel::Const::REDIRECT % new_path) - end - end - end end -- cgit v1.2.3-24-ge0c7 From 62c94742f39c511cd98e976f008e0de0140381c1 Mon Sep 17 00:00:00 2001 From: Ian Ownbey Date: Mon, 1 Dec 2008 15:47:57 -0800 Subject: Removed configurator completely --- lib/mongrel.rb | 1 - 1 file changed, 1 deletion(-) (limited to 'lib') diff --git a/lib/mongrel.rb b/lib/mongrel.rb index 9fe0daf..251e2d4 100644 --- a/lib/mongrel.rb +++ b/lib/mongrel.rb @@ -24,7 +24,6 @@ require 'mongrel/cgi' require 'mongrel/handlers' require 'mongrel/command' require 'mongrel/tcphack' -require 'mongrel/configurator' require 'mongrel/uri_classifier' require 'mongrel/const' require 'mongrel/http_request' -- cgit v1.2.3-24-ge0c7 From 9c82be1259a951a8e34459b63f3ad27ea9b95a30 Mon Sep 17 00:00:00 2001 From: Ian Ownbey Date: Mon, 1 Dec 2008 15:52:42 -0800 Subject: Removed request_progress, make it a middlewear or something --- lib/mongrel/http_request.rb | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'lib') diff --git a/lib/mongrel/http_request.rb b/lib/mongrel/http_request.rb index 0e3790f..e20434b 100644 --- a/lib/mongrel/http_request.rb +++ b/lib/mongrel/http_request.rb @@ -33,7 +33,6 @@ module Mongrel # we've got everything, pack it up @body = StringIO.new @body.write @params.http_body - update_request_progress(0, content_length) elsif remain > 0 # must read more data to complete body if remain > Const::MAX_BODY @@ -71,15 +70,6 @@ module Mongrel }) end - # updates all dispatchers about our progress - def update_request_progress(clen, total) - return if @dispatchers.nil? || @dispatchers.empty? - @dispatchers.each do |dispatcher| - dispatcher.request_progress(@params, clen, total) - end - end - private :update_request_progress - # Does the heavy lifting of properly reading the larger body requests in # small chunks. It expects @body to be an IO object, @socket to be valid, # and will set @body = nil if the request fails. It also expects any initial @@ -91,15 +81,11 @@ module Mongrel remain -= @body.write(@params.http_body) - update_request_progress(remain, total) - # then stream out nothing but perfectly sized chunks until remain <= 0 or @socket.closed? # ASSUME: we are writing to a disk and these writes always write the requested amount @params.http_body = read_socket(Const::CHUNK_SIZE) remain -= @body.write(@params.http_body) - - update_request_progress(remain, total) end rescue Object => e STDERR.puts "#{Time.now}: Error reading HTTP body: #{e.inspect}" -- cgit v1.2.3-24-ge0c7 From 8fd2a302ca5121eca4c96ddd10f3f705a422d378 Mon Sep 17 00:00:00 2001 From: Ian Ownbey Date: Mon, 1 Dec 2008 15:59:21 -0800 Subject: Doc fixes --- lib/mongrel/http_request.rb | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'lib') diff --git a/lib/mongrel/http_request.rb b/lib/mongrel/http_request.rb index e20434b..2416b04 100644 --- a/lib/mongrel/http_request.rb +++ b/lib/mongrel/http_request.rb @@ -1,21 +1,10 @@ module Mongrel - # - # When a handler is found for a registered URI then this class is constructed - # and passed to your HttpHandler::process method. You should assume that - # *one* handler processes all requests. Included in the HttpRequest is a - # HttpRequest.params Hash that matches common CGI params, and a HttpRequest.body - # which is a string containing the request body (raw for now). # # The HttpRequest.initialize method will convert any request that is larger than # Const::MAX_BODY into a Tempfile and use that as the body. Otherwise it uses # a StringIO object. To be safe, you should assume it works like a file. - # - # The HttpHandler.request_notify system is implemented by having HttpRequest call - # HttpHandler.request_begins, HttpHandler.request_progress, HttpHandler.process during - # the IO processing. This adds a small amount of overhead but lets you implement - # finer controlled handlers and filters. - # + # class HttpRequest attr_reader :body, :params @@ -53,6 +42,7 @@ module Mongrel # returns an environment which is rackable # http://rack.rubyforge.org/doc/files/SPEC.html + # copied directly from racks mongrel handler def env env = params.clone env.delete "HTTP_CONTENT_TYPE" -- cgit v1.2.3-24-ge0c7 From 98e8c726b75d1ecd6ca91c66397a3e2a8d88f13f Mon Sep 17 00:00:00 2001 From: Ian Ownbey Date: Wed, 3 Dec 2008 18:44:51 -0800 Subject: Dont need camping adapter anymore, rack does it for us --- lib/mongrel/camping.rb | 107 ------------------------------------------------- 1 file changed, 107 deletions(-) delete mode 100644 lib/mongrel/camping.rb (limited to 'lib') diff --git a/lib/mongrel/camping.rb b/lib/mongrel/camping.rb deleted file mode 100644 index 31bd196..0000000 --- a/lib/mongrel/camping.rb +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright (c) 2005 Zed A. Shaw -# You can redistribute it and/or modify it under the same terms as Ruby. -# -# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html -# for more information. - -require 'mongrel' - - -module Mongrel - # Support for the Camping micro framework at http://camping.rubyforge.org - # This implements the unusually long Postamble that Camping usually - # needs and shrinks it down to just a single line or two. - # - # Your Postamble would now be: - # - # Mongrel::Camping::start("0.0.0.0",3001,"/tepee",Tepee).join - # - # If you wish to get fancier than this then you can use the - # Camping::CampingHandler directly instead and do your own - # wiring: - # - # h = Mongrel::HttpServer.new(server, port) - # h.register(uri, CampingHandler.new(Tepee)) - # h.register("/favicon.ico", Mongrel::Error404Handler.new("")) - # - # I add the /favicon.ico since camping apps typically don't - # have them and it's just annoying anyway. - module Camping - - # This is a specialized handler for Camping applications - # that has them process the request and then translates - # the results into something the Mongrel::HttpResponse - # needs. - class CampingHandler < Mongrel::HttpHandler - attr_reader :files - attr_reader :guard - @@file_only_methods = ["GET","HEAD"] - - def initialize(klass) - @files = Mongrel::DirHandler.new(nil, false) - @guard = Mutex.new - @klass = klass - end - - def process(request, response) - if response.socket.closed? - return - end - - controller = nil - @guard.synchronize { - controller = @klass.run(request.body, request.params) - } - - sendfile, clength = nil - response.status = controller.status - controller.headers.each do |k, v| - if k =~ /^X-SENDFILE$/i - sendfile = v - elsif k =~ /^CONTENT-LENGTH$/i - clength = v.to_i - else - [*v].each do |vi| - response.header[k] = vi - end - end - end - - if sendfile - request.params[Mongrel::Const::PATH_INFO] = sendfile - @files.process(request, response) - elsif controller.body.respond_to? :read - response.send_status(clength) - response.send_header - while chunk = controller.body.read(16384) - response.write(chunk) - end - if controller.body.respond_to? :close - controller.body.close - end - else - body = controller.body.to_s - response.send_status(body.length) - response.send_header - response.write(body) - end - end - end - - # This is a convenience method that wires up a CampingHandler - # for your application on a given port and uri. It's pretty - # much all you need for a camping application to work right. - # - # It returns the Mongrel::HttpServer which you should either - # join or somehow manage. The thread is running when - # returned. - - def Camping.start(server, port, uri, klass) - h = Mongrel::HttpServer.new(server, port) - h.register(uri, CampingHandler.new(klass)) - h.register("/favicon.ico", Mongrel::Error404Handler.new("")) - h.run - return h - end - end -end -- cgit v1.2.3-24-ge0c7 From a5b87dcbe64f4fbfd7733e8762ec7b843ca7d39b Mon Sep 17 00:00:00 2001 From: Ian Ownbey Date: Wed, 3 Dec 2008 18:45:27 -0800 Subject: Dont need rails adapter anymore, rack handles it --- lib/mongrel/rails.rb | 185 --------------------------------------------------- 1 file changed, 185 deletions(-) delete mode 100644 lib/mongrel/rails.rb (limited to 'lib') diff --git a/lib/mongrel/rails.rb b/lib/mongrel/rails.rb deleted file mode 100644 index 7f66a5e..0000000 --- a/lib/mongrel/rails.rb +++ /dev/null @@ -1,185 +0,0 @@ -# Copyright (c) 2005 Zed A. Shaw -# You can redistribute it and/or modify it under the same terms as Ruby. -# -# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html -# for more information. - -require 'mongrel' -require 'cgi' - - -module Mongrel - module Rails - # Implements a handler that can run Rails and serve files out of the - # Rails application's public directory. This lets you run your Rails - # application with Mongrel during development and testing, then use it - # also in production behind a server that's better at serving the - # static files. - # - # The RailsHandler takes a mime_map parameter which is a simple suffix=mimetype - # mapping that it should add to the list of valid mime types. - # - # It also supports page caching directly and will try to resolve a request - # in the following order: - # - # * If the requested exact PATH_INFO exists as a file then serve it. - # * If it exists at PATH_INFO+".html" exists then serve that. - # * Finally, construct a Mongrel::CGIWrapper and run Dispatcher.dispatch to have Rails go. - # - # This means that if you are using page caching it will actually work with Mongrel - # and you should see a decent speed boost (but not as fast as if you use a static - # server like Apache or Litespeed). - class RailsHandler < Mongrel::HttpHandler - attr_reader :files - attr_reader :guard - @@file_only_methods = ["GET","HEAD"] - - def initialize(dir, mime_map = {}) - @files = Mongrel::DirHandler.new(dir,false) - @guard = Mutex.new - - # Register the requested MIME types - mime_map.each {|k,v| Mongrel::DirHandler::add_mime_type(k,v) } - end - - # Attempts to resolve the request as follows: - # - # * If the requested exact PATH_INFO exists as a file then serve it. - # * If it exists at PATH_INFO+".html" exists then serve that. - # * Finally, construct a Mongrel::CGIWrapper and run Dispatcher.dispatch to have Rails go. - def process(request, response) - return if response.socket.closed? - - path_info = request.params[Mongrel::Const::PATH_INFO] - rest_operator = request.params[Mongrel::Const::REQUEST_URI][/^#{Regexp.escape path_info}(;[^\?]+)/, 1].to_s - path_info.chomp!("/") - - page_cached = path_info + rest_operator + ActionController::Base.page_cache_extension - get_or_head = @@file_only_methods.include? request.params[Mongrel::Const::REQUEST_METHOD] - - if get_or_head and @files.can_serve(path_info) - # File exists as-is so serve it up - @files.process(request,response) - elsif get_or_head and @files.can_serve(page_cached) - # Possible cached page, serve it up - request.params[Mongrel::Const::PATH_INFO] = page_cached - @files.process(request,response) - else - begin - cgi = Mongrel::CGIWrapper.new(request, response) - cgi.handler = self - # We don't want the output to be really final until we're out of the lock - cgi.default_really_final = false - - @guard.synchronize { - @active_request_path = request.params[Mongrel::Const::PATH_INFO] - Dispatcher.dispatch(cgi, ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, response.body) - @active_request_path = nil - } - - # This finalizes the output using the proper HttpResponse way - cgi.out("text/html",true) {""} - rescue Errno::EPIPE - response.socket.close - rescue Object => rails_error - STDERR.puts "#{Time.now}: Error calling Dispatcher.dispatch #{rails_error.inspect}" - STDERR.puts rails_error.backtrace.join("\n") - end - end - end - - # Does the internal reload for Rails. It might work for most cases, but - # sometimes you get exceptions. In that case just do a real restart. - def reload! - begin - @guard.synchronize { - $".replace $orig_dollar_quote - GC.start - Dispatcher.reset_application! - ActionController::Routing::Routes.reload - } - end - end - end - - # Creates Rails specific configuration options for people to use - # instead of the base Configurator. - class RailsConfigurator < Mongrel::Configurator - - # Creates a single rails handler and returns it so you - # can add it to a URI. You can actually attach it to - # as many URIs as you want, but this returns the - # same RailsHandler for each call. - # - # Requires the following options: - # - # * :docroot => The public dir to serve from. - # * :environment => Rails environment to use. - # * :cwd => The change to working directory - # - # And understands the following optional settings: - # - # * :mime => A map of mime types. - # - # Because of how Rails is designed you can only have - # one installed per Ruby interpreter (talk to them - # about thread safety). Because of this the first - # time you call this function it does all the config - # needed to get your Rails working. After that - # it returns the one handler you've configured. - # This lets you attach Rails to any URI(s) you want, - # but it still protects you from threads destroying - # your handler. - def rails(options={}) - - return @rails_handler if @rails_handler - - ops = resolve_defaults(options) - - # fix up some defaults - ops[:environment] ||= "development" - ops[:docroot] ||= "public" - ops[:mime] ||= {} - - $orig_dollar_quote = $".clone - ENV['RAILS_ENV'] = ops[:environment] - env_location = "#{ops[:cwd]}/config/environment" - require env_location - require 'dispatcher' - require 'mongrel/rails' - - ActionController::AbstractRequest.relative_url_root = ops[:prefix] if ops[:prefix] - - @rails_handler = RailsHandler.new(ops[:docroot], ops[:mime]) - end - - # Reloads Rails. This isn't too reliable really, but it - # should work for most minimal reload purposes. The only reliable - # way to reload properly is to stop and then start the process. - def reload! - if not @rails_handler - raise "Rails was not configured. Read the docs for RailsConfigurator." - end - - log "Reloading Rails..." - @rails_handler.reload! - log "Done reloading Rails." - - end - - # Takes the exact same configuration as Mongrel::Configurator (and actually calls that) - # but sets up the additional HUP handler to call reload!. - def setup_rails_signals(options={}) - ops = resolve_defaults(options) - setup_signals(options) - - if RUBY_PLATFORM !~ /djgpp|(cyg|ms|bcc)win|mingw/ - # rails reload - trap("HUP") { log "HUP signal received."; reload! } - - log "Rails signals registered. HUP => reload (without restart). It might not work well." - end - end - end - end -end -- cgit v1.2.3-24-ge0c7 From 0d838c607c0c709e5190b24aff116306f4d02255 Mon Sep 17 00:00:00 2001 From: Ian Ownbey Date: Thu, 4 Dec 2008 15:36:59 -0800 Subject: Removed uri_classifier, now we just use racks --- lib/mongrel.rb | 9 ++--- lib/mongrel/uri_classifier.rb | 76 ------------------------------------------- 2 files changed, 2 insertions(+), 83 deletions(-) delete mode 100644 lib/mongrel/uri_classifier.rb (limited to 'lib') diff --git a/lib/mongrel.rb b/lib/mongrel.rb index 251e2d4..e0c2b01 100644 --- a/lib/mongrel.rb +++ b/lib/mongrel.rb @@ -24,7 +24,6 @@ require 'mongrel/cgi' require 'mongrel/handlers' require 'mongrel/command' require 'mongrel/tcphack' -require 'mongrel/uri_classifier' require 'mongrel/const' require 'mongrel/http_request' require 'mongrel/header_out' @@ -94,7 +93,6 @@ module Mongrel if defined?(Fcntl::FD_CLOEXEC) @socket.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) end - @classifier = URIClassifier.new @host = host @port = port @workers = ThreadGroup.new @@ -134,11 +132,8 @@ module Mongrel raise "No REQUEST PATH" if not params[Const::REQUEST_PATH] - - script_name, path_info, handlers = @classifier.resolve(params[Const::REQUEST_PATH]) - - params[Const::PATH_INFO] = path_info - params[Const::SCRIPT_NAME] = script_name + params[Const::PATH_INFO] = params[Const::REQUEST_PATH] + params[Const::SCRIPT_NAME] = Const::SLASH # From http://www.ietf.org/rfc/rfc3875 : # "Script authors should be aware that the REMOTE_ADDR and REMOTE_HOST diff --git a/lib/mongrel/uri_classifier.rb b/lib/mongrel/uri_classifier.rb deleted file mode 100644 index f39ccc9..0000000 --- a/lib/mongrel/uri_classifier.rb +++ /dev/null @@ -1,76 +0,0 @@ - -module Mongrel - class URIClassifier - - class RegistrationError < RuntimeError - end - class UsageError < RuntimeError - end - - attr_reader :handler_map - - # Returns the URIs that have been registered with this classifier so far. - def uris - @handler_map.keys - end - - def initialize - @handler_map = {} - @matcher = // - @root_handler = nil - end - - # Register a handler object at a particular URI. The handler can be whatever - # you want, including an array. It's up to you what to do with it. - # - # Registering a handler is not necessarily threadsafe, so be careful if you go - # mucking around once the server is running. - def register(uri, handler) - raise RegistrationError, "#{uri.inspect} is already registered" if @handler_map[uri] - raise RegistrationError, "URI is empty" if !uri or uri.empty? - raise RegistrationError, "URI must begin with a \"#{Const::SLASH}\"" unless uri[0..0] == Const::SLASH - @handler_map[uri.dup] = handler - rebuild - end - - # Unregister a particular URI and its handler. - def unregister(uri) - handler = @handler_map.delete(uri) - raise RegistrationError, "#{uri.inspect} was not registered" unless handler - rebuild - handler - end - - # Resolve a request URI by finding the best partial match in the registered - # handler URIs. - def resolve(request_uri) - if @root_handler - # Optimization for the pathological case of only one handler on "/"; e.g. Rails - [Const::SLASH, request_uri, @root_handler] - elsif match = @matcher.match(request_uri) - uri = match.to_s - # A root mounted ("/") handler must resolve such that path info matches the original URI. - [uri, (uri == Const::SLASH ? request_uri : match.post_match), @handler_map[uri]] - else - [nil, nil, nil] - end - end - - private - - def rebuild - if @handler_map.size == 1 and @handler_map[Const::SLASH] - @root_handler = @handler_map.values.first - else - @root_handler = nil - routes = @handler_map.keys.sort.sort_by do |uri| - -uri.length - end - @matcher = Regexp.new(routes.map do |uri| - Regexp.new('^' + Regexp.escape(uri)) - end.join('|')) - end - end - - end -end \ No newline at end of file -- cgit v1.2.3-24-ge0c7