about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorzedshaw <zedshaw@19e92222-5c0b-0410-8929-a290d50e31e9>2006-01-28 19:34:12 +0000
committerzedshaw <zedshaw@19e92222-5c0b-0410-8929-a290d50e31e9>2006-01-28 19:34:12 +0000
commit6a5116197a687798f1dc9b533796a8319cb82c2e (patch)
treebd791521e8515b0388b658ad8a4856e5870e28e8
parent004dec2c2f44a0db510dfd65e5ffd8c9fc4ff83e (diff)
downloadunicorn-6a5116197a687798f1dc9b533796a8319cb82c2e.tar.gz
git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/trunk@9 19e92222-5c0b-0410-8929-a290d50e31e9
-rw-r--r--examples/simpletest.rb7
-rw-r--r--lib/mongrel.rb93
-rw-r--r--test/test_response.rb48
3 files changed, 137 insertions, 11 deletions
diff --git a/examples/simpletest.rb b/examples/simpletest.rb
index c05a745..864c226 100644
--- a/examples/simpletest.rb
+++ b/examples/simpletest.rb
@@ -2,11 +2,12 @@ require 'mongrel'
 require 'yaml'
 
 class SimpleHandler < Mongrel::HttpHandler
-    
     def process(request, response)
-      response.socket.write("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nhello!\n")
+      response.start do |head,out|
+        head["Content-Type"] = "text/plain"
+        out.write("hello!\n")
+      end
     end
-    
 end
 
 h = Mongrel::HttpServer.new("0.0.0.0", "3000")
diff --git a/lib/mongrel.rb b/lib/mongrel.rb
index c46ccab..c24cc67 100644
--- a/lib/mongrel.rb
+++ b/lib/mongrel.rb
@@ -1,13 +1,53 @@
 require 'socket'
 require 'http11'
 require 'thread'
-
+require 'stringio'
 
 # Mongrel module containing all of the classes (include C extensions) for running
 # a Mongrel web server.  It contains a minimalist HTTP server with just enough
 # functionality to service web application requests fast as possible.
 module Mongrel
 
+  HTTP_STATUS_CODES = {  
+    100  => 'Continue',
+    101  => 'Switching Protocols',
+    200  => 'OK',
+    201  => 'Created',
+    202  => 'Accepted',
+    203  => 'Non-Authoritative Information',
+    204  => 'No Content',
+    205  => 'Reset Content',
+    206  => 'Partial Content',
+    300  => 'Multiple Choices',
+    301  => 'Moved Permanently',
+    302  => 'Moved Temporarily',
+    303  => 'See Other',
+    304  => 'Not Modified',
+    305  => 'Use Proxy',
+    400  => 'Bad Request',
+    401  => 'Unauthorized',
+    402  => 'Payment Required',
+    403  => 'Forbidden',
+    404  => 'Not Found',
+    405  => 'Method Not Allowed',
+    406  => 'Not Acceptable',
+    407  => 'Proxy Authentication Required',
+    408  => 'Request Time-out',
+    409  => 'Conflict',
+    410  => 'Gone',
+    411  => 'Length Required',
+    412  => 'Precondition Failed',
+    413  => 'Request Entity Too Large',
+    414  => 'Request-URI Too Large',
+    415  => 'Unsupported Media Type',
+    500  => 'Internal Server Error',
+    501  => 'Not Implemented',
+    502  => 'Bad Gateway',
+    503  => 'Service Unavailable',
+    504  => 'Gateway Time-out',
+    505  => 'HTTP Version not supported'
+  }
+
   # 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 HttpReqeust is a
@@ -41,19 +81,55 @@ module Mongrel
     end
   end
 
-  # Very very simple response object.  You basically write your stuff raw
-  # to the HttpResponse.socket variable.  This will be made *much* easier
-  # in future releases allowing you to set status and request headers prior
-  # to sending the response.
+
+  class HeaderOut
+    attr_reader :out
+
+    def initialize(out)
+      @out = out
+    end
+
+    def[]=(key,value)
+      @out.write(key)
+      @out.write(": ")
+      @out.write(value)
+      @out.write("\r\n")
+    end
+  end
+
+
   class HttpResponse
     attr_reader :socket
-    
+    attr_reader :out
+    attr_reader :header
+    attr_reader :status
+    attr_writer :status
+    
     def initialize(socket)
       @socket = socket
+      @out = StringIO.new
+      @status = 404
+      @header = HeaderOut.new(StringIO.new)
+    end
+
+    def start(status=200)
+      @status = status
+      yield @header, @out
+      finished
+    end
+    
+    def finished
+      @header.out.rewind
+      @out.rewind
+
+      @socket.write("HTTP/1.1 #{@status} #{HTTP_STATUS_CODES[@status]}\r\nContent-Length: #{@out.length}\r\n")
+      @socket.write(@header.out.read)
+      @socket.write("\r\n")
+      @socket.write(@out.read)
     end
-  
   end
   
+
   # You implement your application handler with this.  It's very light giving
   # just the minimum necessary for you to handle a request and shoot back
   # a response.  Look at the HttpRequest and HttpResponse objects for how
@@ -65,6 +141,7 @@ module Mongrel
     end
   end
 
+
   # The server normally returns a 404 response if a URI is requested, but it
   # also returns a lame empty message.  This lets you do a 404 response
   # with a custom message for special URIs.
@@ -107,7 +184,7 @@ module Mongrel
     ERROR_404_RESPONSE="HTTP/1.1 404 Not Found\r\nConnection: close\r\nContent-Type: text/plain\r\nServer: Mongrel/0.1\r\n\r\n"
 
     # For now we just read 2k chunks.  Not optimal at all.
-    CHUNK_SIZE=2048
+    CHUNK_SIZE=2048
     
     # Creates a working server on host:port (strange things happen if port isn't a Number).
     # Use HttpServer::run to start the server.
diff --git a/test/test_response.rb b/test/test_response.rb
new file mode 100644
index 0000000..f033ba6
--- /dev/null
+++ b/test/test_response.rb
@@ -0,0 +1,48 @@
+require 'test/unit'
+require 'mongrel'
+
+include Mongrel
+
+class ResponseTest < Test::Unit::TestCase
+  
+  def test_response_headers
+    out = StringIO.new
+    resp = HttpResponse.new(out)
+    resp.status = 200
+    resp.header["Accept"] = "text/plain"
+    resp.header["X-Whatever"] = "stuff"
+    resp.out.write("test")
+    resp.finished
+
+    out.rewind
+    puts out.read
+  end
+
+  def test_response_200
+    io = StringIO.new
+    resp = HttpResponse.new(io)
+    resp.start do |head,out|
+      head["Accept"] = "text/plain"
+      out.write("tested")
+      out.write("hello!")
+    end
+
+    io.rewind
+    puts io.read
+  end
+
+  def test_response_404
+    io = StringIO.new
+
+    resp = HttpResponse.new(io)
+    resp.start(404) do |head,out|
+      head['Accept'] = "text/plain"
+      out.write("NOT FOUND")
+    end
+
+    io.rewind
+    puts io.read
+  end
+
+end
+