# File lib/mongrel.rb, line 573
573:     def process_client(client)
574:       begin
575:         parser = HttpParser.new
576:         params = HttpParams.new
577:         request = nil
578:         data = client.readpartial(Const::CHUNK_SIZE)
579:         nparsed = 0
580: 
581:         # Assumption: nparsed will always be less since data will get filled with more
582:         # after each parsing.  If it doesn't get more then there was a problem
583:         # with the read operation on the client socket.  Effect is to stop processing when the
584:         # socket can't fill the buffer for further parsing.
585:         while nparsed < data.length
586:           nparsed = parser.execute(params, data, nparsed)
587: 
588:           if parser.finished?
589:             if not params[Const::REQUEST_PATH]
590:               # it might be a dumbass full host request header
591:               uri = URI.parse(params[Const::REQUEST_URI])
592:               params[Const::REQUEST_PATH] = uri.request_uri
593:             end
594: 
595:             raise "No REQUEST PATH" if not params[Const::REQUEST_PATH]
596: 
597:             script_name, path_info, handlers = @classifier.resolve(params[Const::REQUEST_PATH])
598: 
599:             if handlers
600:               params[Const::PATH_INFO] = path_info
601:               params[Const::SCRIPT_NAME] = script_name
602:               params[Const::REMOTE_ADDR] = params[Const::HTTP_X_FORWARDED_FOR] || client.peeraddr.last
603: 
604:               # select handlers that want more detailed request notification
605:               notifiers = handlers.select { |h| h.request_notify }
606:               request = HttpRequest.new(params, client, notifiers)
607: 
608:               # in the case of large file uploads the user could close the socket, so skip those requests
609:               break if request.body == nil  # nil signals from HttpRequest::initialize that the request was aborted
610: 
611:               # request is good so far, continue processing the response
612:               response = HttpResponse.new(client)
613: 
614:               # Process each handler in registered order until we run out or one finalizes the response.
615:               handlers.each do |handler|
616:                 handler.process(request, response)
617:                 break if response.done or client.closed?
618:               end
619: 
620:               # And finally, if nobody closed the response off, we finalize it.
621:               unless response.done or client.closed? 
622:                 response.finished
623:               end
624:             else
625:               # Didn't find it, return a stock 404 response.
626:               client.write(Const::ERROR_404_RESPONSE)
627:             end
628: 
629:             break #done
630:           else
631:             # Parser is not done, queue up more data to read and continue parsing
632:             chunk = client.readpartial(Const::CHUNK_SIZE)
633:             break if !chunk or chunk.length == 0  # read failed, stop processing
634: 
635:             data << chunk
636:             if data.length >= Const::MAX_HEADER
637:               raise HttpParserError.new("HEADER is longer than allowed, aborting client early.")
638:             end
639:           end
640:         end
641:       rescue EOFError,Errno::ECONNRESET,Errno::EPIPE,Errno::EINVAL,Errno::EBADF
642:         client.close rescue Object
643:       rescue HttpParserError
644:         if $mongrel_debug_client
645:           STDERR.puts "#{Time.now}: BAD CLIENT (#{params[Const::HTTP_X_FORWARDED_FOR] || client.peeraddr.last}): #$!"
646:           STDERR.puts "#{Time.now}: REQUEST DATA: #{data.inspect}\n---\nPARAMS: #{params.inspect}\n---\n"
647:         end
648:       rescue Errno::EMFILE
649:         reap_dead_workers('too many files')
650:       rescue Object
651:         STDERR.puts "#{Time.now}: ERROR: #$!"
652:         STDERR.puts $!.backtrace.join("\n") if $mongrel_debug_client
653:       ensure
654:         client.close rescue Object
655:         request.body.delete if request and request.body.class == Tempfile
656:       end
657:     end