    # File lib/mongrel.rb, line 109
        def process_client(client)
          begin
            parser = HttpParser.new
            params = HttpParams.new
            request = nil
            data = client.readpartial(Const::CHUNK_SIZE)
            nparsed = 0

            # Assumption: nparsed will always be less since data will get filled with more
            # after each parsing.  If it doesn't get more then there was a problem
            # with the read operation on the client socket.  Effect is to stop processing when the
            # socket can't fill the buffer for further parsing.
            while nparsed < data.length
              nparsed = parser.execute(params, data, nparsed)

              if parser.finished?
                if not params[Const::REQUEST_PATH]
                  # it might be a dumbass full host request header
                  uri = URI.parse(params[Const::REQUEST_URI])
                  params[Const::REQUEST_PATH] = uri.path
                end

                raise "No REQUEST PATH" if not params[Const::REQUEST_PATH]

                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

                  # 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
              else
                # Parser is not done, queue up more data to read and continue parsing
                chunk = client.readpartial(Const::CHUNK_SIZE)
                break if !chunk or chunk.length == 0  # read failed, stop processing

                data << chunk
                if data.length >= Const::MAX_HEADER
                  raise HttpParserError.new("HEADER is longer than allowed, aborting client early.")
                end
              end
            end
          rescue EOFError,Errno::ECONNRESET,Errno::EPIPE,Errno::EINVAL,Errno::EBADF
            client.close rescue nil
          rescue HttpParserError => e
            STDERR.puts "#{Time.now}: HTTP parse error, malformed request (#{params[Const::HTTP_X_FORWARDED_FOR] || client.peeraddr.last}): #{e.inspect}"
            STDERR.puts "#{Time.now}: REQUEST DATA: #{data.inspect}\n---\nPARAMS: #{params.inspect}\n---\n"
          rescue Errno::EMFILE
            reap_dead_workers('too many files')
          rescue Object => e
            STDERR.puts "#{Time.now}: Read error: #{e.inspect}"
            STDERR.puts e.backtrace.join("\n")
          ensure
            begin
              client.close
            rescue IOError
              # Already closed
            rescue Object => e
              STDERR.puts "#{Time.now}: Client error: #{e.inspect}"
              STDERR.puts e.backtrace.join("\n")
            end
            request.body.delete if request and request.body.class == Tempfile
          end
        end