[Mongrel] http parser

snacktime snacktime at gmail.com
Sun Aug 20 16:38:42 EDT 2006


Here is a quick and dirty example of how to use the parser.  Notice
that the server isn't sending a valid reply to the client, and the
handler doesn't exist, I added that just as an example for others of
how you might use the Eventmachine thread pool to run the handler.
But you should get the general idea.  Zed correct me if I am wrong,
but nparsed returns the length of the headers that were parsed, so if
the parser finishes nparsed is the header length.  Then I just add the
content length to that and keep reading until we get all the content.
I also subclassed HttpRequest since in mongrel that's where the rest
of the body is read, but in eventmachine it's not.

To use EM in mongrel you would need to find the best way to only run
one handler at a time.  An array of connections in process_request
together with a state variable might work.  New requests get pushed
onto a list, and process_request takes the first request in the list,
sets the state to busy, then when it's done sets the state to idle and
checks the array for more request to process before finishing.  Need
to think that one through a bit more.


require 'rubygems'
require 'mongrel'
require 'eventmachine'


class Mongrel::HttpRequest
    attr_reader :body, :params

    # 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.
    #
    # TODO: Implement tempfile removal when the request is done.
    def initialize(params, initial_body)
      @params = params
  end

class Server < EventMachine::Connection

  def initialize *args
    super
    @linebuffer = ""
  end

  def post_init
    @parser = Mongrel::HttpParser.new
    @params = {}
    @nparsed = 0
    @request = nil
    @request_len = nil
    #start_tls
  end

  def unbind
    puts "Connection Closed\r\n"
  end

  def process_request(request)
    # Run the handler in a thread.  Not implemented just put here to
show how to use
    # EventMachine.defer to run the handler in EventMachine's thread pool.
    start = proc {run_handler}
    stop = proc {|r|
      send_data r
      close_connection
    }
    EventMachine.defer(start,stop)
  end

  def receive_data data
    @linebuffer << data
    @nparsed = @parser.execute(@params, @linebuffer, @nparsed)
    p "nparsed=#{@nparsed}"
    if @parser.finished?
      if @request_len.nil?
        @request = Mongrel::HttpRequest.new(@params, at linebuffer)
        @request_len = @nparsed +
@request.params[Mongrel::Const::CONTENT_LENGTH].to_i
        if @linebuffer.length >= @request_len
          process_request(@request)
        end
      elsif @linebuffer.length >= @request_len
        process_request(@request)
      end
    end
  end
end

EventMachine::run {
  EventMachine::start_server "127.0.0.1", 80, Server
}


More information about the Mongrel-users mailing list