From: Nathaniel Talbott Date: 2003-12-02T05:50:53+09:00 Subject: WEBrick bug & fix I have a production WEBrick server whose common usage includes clients making requests and then disconnecting before a response can be given. There is a bug in WEBrick::GenericServer#start_thread that can cause threads to silently die under these conditions, causing the thread pool to eventually be exhausted, triggering the error reported in ruby-talk:86309. Basically, the call to sock.peeraddr can result in an exception being raised, which causes the addr local variable to be nil when the ensure block is executed, raising an additional exception which is not handled. The patch below should fix that bug. I've also included some improved error-handling which rescues all Exceptions (not just StandardError), and keeps the server a bit quieter under normal operation. Let me know if you have any questions or need more info about the patch. Thanks, Nathaniel <:((>< Index: lib/webrick/httpresponse.rb =================================================================== RCS file: /src/ruby/lib/webrick/httpresponse.rb,v retrieving revision 1.2 diff -u -r1.2 httpresponse.rb --- lib/webrick/httpresponse.rb 25 Nov 2003 16:02:45 -0000 1.2 +++ lib/webrick/httpresponse.rb 1 Dec 2003 20:25:26 -0000 @@ -84,10 +84,10 @@ setup_header() send_header(socket) send_body(socket) - rescue Errno::EPIPE - @logger.error("HTTPResponse#send_response: EPIPE occured.") + rescue Errno::EPIPE, Errno::ECONNRESET, Errno::ENOTCONN => ex + @logger.debug(ex) @keep_alive = false - rescue => ex + rescue Exception => ex @logger.error(ex) @keep_alive = false end Index: lib/webrick/server.rb =================================================================== RCS file: /src/ruby/lib/webrick/server.rb,v retrieving revision 1.4 diff -u -r1.4 server.rb --- lib/webrick/server.rb 23 Oct 2003 11:29:29 -0000 1.4 +++ lib/webrick/server.rb 1 Dec 2003 20:25:26 -0000 @@ -102,7 +102,7 @@ rescue Errno::EBADF, IOError => ex # if the listening socket was closed in GenericServer#shutdown, # IO::select raise it. - rescue => ex + rescue Exception => ex msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}" @logger.error msg end @@ -148,14 +148,20 @@ @logger.debug "accept: #{addr[3]}:#{addr[1]}" call_callback(:AcceptCallback, sock) block ? block.call(sock) : run(sock) - rescue ServerError, Errno::ENOTCONN => ex + rescue Errno::ENOTCONN + @logger.debug "Errno::ENOTCONN raised" + rescue ServerError => ex msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}" @logger.error msg rescue Exception => ex @logger.error ex ensure Thread.current[:WEBrickSocket] = nil - @logger.debug "close: #{addr[3]}:#{addr[1]}" + if(addr) + @logger.debug "close: #{addr[3]}:#{addr[1]}" + else + @logger.debug "close: nil" + end sock.close end @tokens.push(nil)