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