# File lib/mongrel.rb, line 516
516:     def process_client(client)
517:       begin
518:         parser = HttpParser.new
519:         params = {}
520: 
521:         data = client.readpartial(Const::CHUNK_SIZE)
522:         nparsed = 0
523: 
524:         # Assumption: nparsed will always be less since data will get filled with more
525:         # after each parsing.  If it doesn't get more then there was a problem
526:         # with the read operation on the client socket.  Effect is to stop processing when the
527:         # socket can't fill the buffer for further parsing.
528:         while nparsed < data.length
529:           nparsed = parser.execute(params, data, nparsed)
530: 
531:           if parser.finished?
532:             script_name, path_info, handlers = @classifier.resolve(params[Const::REQUEST_URI])
533: 
534:             if handlers
535:               params[Const::PATH_INFO] = path_info
536:               params[Const::SCRIPT_NAME] = script_name
537:               params[Const::REMOTE_ADDR] = params[Const::HTTP_X_FORWARDED_FOR] || client.peeraddr.last
538:               data = data[nparsed ... data.length] || ""
539: 
540:               if handlers[0].request_notify
541:                 # this first handler wants to be notified when the process starts
542:                 handlers[0].request_begins(params)
543:               end
544: 
545:               # TODO: Find a faster/better way to carve out the range, preferably without copying.
546:               request = HttpRequest.new(params, data, client)
547: 
548:               # in the case of large file uploads the user could close the socket, so skip those requests
549:               break if request.body == nil  # nil signals from HttpRequest::initialize that the request was aborted
550: 
551:               # request is good so far, continue processing the response
552:               response = HttpResponse.new(client)
553: 
554:               # Process each handler in registered order until we run out or one finalizes the response.
555:               handlers.each do |handler|
556:                 handler.process(request, response)
557:                 break if response.done or client.closed?
558:               end
559: 
560:               # And finally, if nobody closed the response off, we finalize it.
561:               unless response.done or client.closed? 
562:                 response.finished
563:               end
564:             else
565:               # Didn't find it, return a stock 404 response.
566:               # TODO: Implement customer 404 files (but really they should use a real web server).
567:               client.write(Const::ERROR_404_RESPONSE)
568:             end
569: 
570:             break #done
571:           else
572:             # Parser is not done, queue up more data to read and continue parsing
573:             data << client.readpartial(Const::CHUNK_SIZE)
574:             if data.length >= Const::MAX_HEADER
575:               raise HttpParserError.new("HEADER is longer than allowed, aborting client early.")
576:             end
577:           end
578:         end
579:       rescue EOFError,Errno::ECONNRESET,Errno::EPIPE,Errno::EINVAL,Errno::EBADF
580:         # ignored
581:       rescue HttpParserError
582:         STDERR.puts "#{Time.now}: BAD CLIENT (#{params[Const::HTTP_X_FORWARDED_FOR] || client.peeraddr.last}): #$!"
583:       rescue => details
584:         STDERR.puts "#{Time.now}: ERROR: #$!"
585:         STDERR.puts details.backtrace.join("\n")
586:       ensure
587:         client.close unless client.closed?
588:       end
589:     end