about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorzedshaw <zedshaw@19e92222-5c0b-0410-8929-a290d50e31e9>2006-06-18 04:57:26 +0000
committerzedshaw <zedshaw@19e92222-5c0b-0410-8929-a290d50e31e9>2006-06-18 04:57:26 +0000
commit364270615b8e6f1bd5cc8611267137f1a83b8124 (patch)
treeaff4bf91f421237f8fb39e666c9e7f4666fbe356
parente5c6b9ad70d844f4d656efa2306c2f7973cb2fee (diff)
downloadunicorn-364270615b8e6f1bd5cc8611267137f1a83b8124.tar.gz
git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/trunk@245 19e92222-5c0b-0410-8929-a290d50e31e9
-rw-r--r--examples/simpletest.rb2
-rw-r--r--lib/mongrel.rb33
-rw-r--r--lib/mongrel/handlers.rb59
-rw-r--r--test/test_redirect_handler.rb41
4 files changed, 129 insertions, 6 deletions
diff --git a/examples/simpletest.rb b/examples/simpletest.rb
index df1ad56..b82e2c6 100644
--- a/examples/simpletest.rb
+++ b/examples/simpletest.rb
@@ -40,6 +40,8 @@ config = Mongrel::Configurator.new :host => ARGV[0], :port => ARGV[1] do
     uri "/files", :handler => Mongrel::DirHandler.new(ARGV[2])
     uri "/files", :handler => stats
     uri "/status", :handler => Mongrel::StatusHandler.new(:stats_filter => stats)
+    redirect "/redir1", "/"
+    redirect "/to", /to/, 'w'
   end
 
   trap("INT") { stop }
diff --git a/lib/mongrel.rb b/lib/mongrel.rb
index 6090708..4432a2e 100644
--- a/lib/mongrel.rb
+++ b/lib/mongrel.rb
@@ -171,6 +171,7 @@ module Mongrel
     HTTP_X_FORWARDED_FOR="HTTP_X_FORWARDED_FOR".freeze
     HTTP_IF_UNMODIFIED_SINCE="HTTP_IF_UNMODIFIED_SINCE".freeze
     HTTP_IF_NONE_MATCH="HTTP_IF_NONE_MATCH".freeze
+    REDIRECT = "HTTP/1.1 302 Found\r\nLocation: %s\r\nConnection: close\r\n\r\n".freeze
   end
 
 
@@ -534,9 +535,15 @@ module Mongrel
               params[Const::PATH_INFO] = path_info
               params[Const::SCRIPT_NAME] = script_name
               params[Const::REMOTE_ADDR] = params[Const::HTTP_X_FORWARDED_FOR] || client.peeraddr.last
+              data = data[nparsed ... data.length] || ""
+
+              if handlers[0].request_notify
+                # this first handler wants to be notified when the process starts
+                handlers[0].request_begins(params)
+              end
 
               # TODO: Find a faster/better way to carve out the range, preferably without copying.
-              request = HttpRequest.new(params, data[nparsed ... data.length] || "", client)
+              request = HttpRequest.new(params, data, 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
@@ -926,6 +933,16 @@ module Mongrel
       GemPlugin::Manager.instance.create(name, ops)
     end
 
+    # Let's 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
@@ -968,13 +985,21 @@ module Mongrel
     # found in Rails applications that are either slow or become unresponsive
     # after a little while.
     #
-    # TODO: Document the optional selections from the what parameter
+    # 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:  :object, :railes, :files, :threads, :params
+    #
+    # NOTE: Use [:files] to get acccesses dumped to stderr like with WEBrick.
     def debug(location, what = [:object, :rails, :files, :threads, :params])
       require 'mongrel/debug'
       handlers = {
-        :object => "/handlers/requestlog::access",
+        :files => "/handlers/requestlog::access",
         :rails => "/handlers/requestlog::files",
-        :files => "/handlers/requestlog::objects",
+        :object => "/handlers/requestlog::objects",
         :threads => "/handlers/requestlog::threads",
         :params => "/handlers/requestlog::params"
       }
diff --git a/lib/mongrel/handlers.rb b/lib/mongrel/handlers.rb
index d20ca17..509d3e9 100644
--- a/lib/mongrel/handlers.rb
+++ b/lib/mongrel/handlers.rb
@@ -31,11 +31,19 @@ module Mongrel
   # should be implemented using the HttpHandlerPlugin mixin.
   #
   class HttpHandler
-    attr_reader :header_only
+    attr_reader :request_notify
     attr_accessor :listener
 
+    # This will be called by Mongrel on the *first* (index 0) handler *if* it has
+    # HttpHandler.request_notify set to *true*.  You only get the parameters
+    # for the request, with the idea that you'd "bound" the beginning of the
+    # request processing and the first call to process.
+    def request_begins(params)
+    end
+
     def process(request, response)
     end
+
   end
 
 
@@ -45,9 +53,12 @@ module Mongrel
   # the process method later.
   module HttpHandlerPlugin
     attr_reader :options
-    attr_reader :header_only
+    attr_reader :request_notify
     attr_accessor :listener
 
+    def request_begins(params)
+    end
+
     def initialize(options={})
       @options = options
       @header_only = false
@@ -398,4 +409,48 @@ 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
+        @replacement = 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
diff --git a/test/test_redirect_handler.rb b/test/test_redirect_handler.rb
new file mode 100644
index 0000000..dfd994a
--- /dev/null
+++ b/test/test_redirect_handler.rb
@@ -0,0 +1,41 @@
+require 'test/unit'
+require 'mongrel'
+require 'mongrel/redirect_handler'
+require 'net/http'
+require 'uri'
+require 'timeout'
+
+class TC_RedirectHandler < Test::Unit::TestCase
+
+  def setup
+    @server = Mongrel::HttpServer.new('0.0.0.0', 9998)
+    @server.run
+    @client = Net::HTTP.new('0.0.0.0', 9998)
+  end
+
+  def teardown
+    @server.stop
+  end
+
+  def test_simple_redirect
+    tester = Mongrel::RedirectHandler.new('/yo')
+    @server.register("/test", tester)
+
+    sleep(1)
+    res = @client.request_get('/test')
+    assert res != nil, "Didn't get a response"
+    assert_equal ['/yo'], res.get_fields('Location')
+  end
+
+  def test_rewrite
+    tester = Mongrel::RedirectHandler.new(/(\w+)/, '+\1+')
+    @server.register("/test", tester)
+
+    sleep(1)
+    res = @client.request_get('/test/something')
+    assert_equal ['/+test+/+something+'], res.get_fields('Location')
+  end
+
+end
+
+