From 39c1bad6267bd74f5fa0a6a625b7ae48e47793fb Mon Sep 17 00:00:00 2001 From: zedshaw Date: Thu, 15 Jun 2006 18:14:07 +0000 Subject: Major bug fixed where sockets would get leaked if the client closed early (or any socket errors from the client). git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/trunk@238 19e92222-5c0b-0410-8929-a290d50e31e9 --- Rakefile | 2 +- bin/mongrel_rails | 10 ---------- lib/mongrel.rb | 39 ++++++++++++++++++++++++++++----------- lib/mongrel/command.rb | 6 +++++- lib/mongrel/handlers.rb | 3 +-- 5 files changed, 35 insertions(+), 25 deletions(-) diff --git a/Rakefile b/Rakefile index 4b2217c..462eaec 100644 --- a/Rakefile +++ b/Rakefile @@ -33,7 +33,7 @@ task :ragel do end task :site_webgen do - sh %{pushd doc/site; webgen; scp -r `find output -name "*.html" -print` #{ENV['SSH_USER']}@rubyforge.org:/var/www/gforge-projects/mongrel/; popd } + sh %{pushd doc/site; webgen; scp -r output/* #{ENV['SSH_USER']}@rubyforge.org:/var/www/gforge-projects/mongrel/; popd } end task :site_rdoc do diff --git a/bin/mongrel_rails b/bin/mongrel_rails index 61306bc..b1cf737 100644 --- a/bin/mongrel_rails +++ b/bin/mongrel_rails @@ -6,16 +6,6 @@ require 'mongrel/rails' require 'etc' -class Version < GemPlugin::Plugin "/commands" - include Mongrel::Command::Base - - def run - puts "Version #{Mongrel::Const::MONGREL_VERSION}" - end - -end - - class Start < GemPlugin::Plugin "/commands" include Mongrel::Command::Base diff --git a/lib/mongrel.rb b/lib/mongrel.rb index bd3bb75..6090708 100644 --- a/lib/mongrel.rb +++ b/lib/mongrel.rb @@ -372,7 +372,7 @@ module Mongrel def send_status(content_length=nil) if not @status_sent content_length ||= @body.length - @socket.write(Const::STATUS_FORMAT % [status, HTTP_STATUS_CODES[@status], content_length]) + write(Const::STATUS_FORMAT % [status, HTTP_STATUS_CODES[@status], content_length]) @status_sent = true end end @@ -380,7 +380,7 @@ module Mongrel def send_header if not @header_sent @header.out.rewind - @socket.write(@header.out.read + Const::LINE_END) + write(@header.out.read + Const::LINE_END) @header_sent = true end end @@ -388,7 +388,7 @@ module Mongrel def send_body if not @body_sent @body.rewind - @socket.write(@body.read) + write(@body.read) @body_sent = true end end @@ -404,22 +404,31 @@ module Mongrel def send_file(path) File.open(path, "rb") do |f| if @socket.respond_to? :sendfile - @socket.sendfile(f) + begin + @socket.sendfile(f) + rescue => details + socket_error(details) + end else while chunk = f.read(Const::CHUNK_SIZE) and chunk.length > 0 - @socket.write(chunk) + write(chunk) end end - @body_send = true end - rescue EOFError,Errno::ECONNRESET,Errno::EPIPE,Errno::EINVAL,Errno::EBADF + end + + def socket_error(details) # ignore these since it means the client closed off early - STDERR.puts "Client closed socket early requesting file #{path}: #$!" + @socket.close unless @socket.closed? + done = true + raise details end def write(data) @socket.write(data) + rescue => details + socket_error(details) end # This takes whatever has been done to header and body and then writes it in the @@ -430,6 +439,14 @@ module Mongrel send_body end + # Used during error conditions to mark the response as "done" so there isn't any more processing + # sent to the client. + def done=(val) + @status_sent = true + @header_sent = true + @body_sent = true + end + def done (@status_sent and @header_sent and @body_sent) end @@ -530,11 +547,11 @@ module Mongrel # 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 + break if response.done or client.closed? end # And finally, if nobody closed the response off, we finalize it. - if not response.done + unless response.done or client.closed? response.finished end else @@ -560,7 +577,7 @@ module Mongrel STDERR.puts "#{Time.now}: ERROR: #$!" STDERR.puts details.backtrace.join("\n") ensure - client.close + client.close unless client.closed? end end diff --git a/lib/mongrel/command.rb b/lib/mongrel/command.rb index 20466e2..1071944 100644 --- a/lib/mongrel/command.rb +++ b/lib/mongrel/command.rb @@ -186,6 +186,9 @@ module Mongrel if !cmd_name or cmd_name == "?" or cmd_name == "help" print_command_list return true + elsif cmd_name == "--version" + STDERR.puts "Mongrel Web Server #{Mongrel::Const::MONGREL_VERSION}" + return true end # command exists, set it up and validate it @@ -194,7 +197,7 @@ module Mongrel rescue STDERR.puts "INVALID COMMAND: #$!" print_command_list - return + return false end # Normally the command is NOT valid right after being created @@ -208,6 +211,7 @@ module Mongrel command.run end end + return true end diff --git a/lib/mongrel/handlers.rb b/lib/mongrel/handlers.rb index 1d0cd37..d20ca17 100644 --- a/lib/mongrel/handlers.rb +++ b/lib/mongrel/handlers.rb @@ -256,8 +256,7 @@ module Mongrel response.start(403) {|head,out| out.write(ONLY_HEAD_GET) } end rescue => details - STDERR.puts "Error accessing file #{req_path}: #{details}" - STDERR.puts details.backtrace.join("\n") + STDERR.puts "Error sending file #{req_path}: #{details}" end end end -- cgit v1.2.3-24-ge0c7