summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/webrick/httpresponse.rb41
-rw-r--r--test/webrick/test_httpproxy.rb40
2 files changed, 79 insertions, 2 deletions
diff --git a/lib/webrick/httpresponse.rb b/lib/webrick/httpresponse.rb
index f206a05ce9..62d8056cf7 100644
--- a/lib/webrick/httpresponse.rb
+++ b/lib/webrick/httpresponse.rb
@@ -113,6 +113,7 @@ module WEBrick
@chunked = false
@filename = nil
@sent_size = 0
+ @bodytempfile = nil
end
##
@@ -253,7 +254,10 @@ module WEBrick
elsif %r{^multipart/byteranges} =~ @header['content-type']
@header.delete('content-length')
elsif @header['content-length'].nil?
- unless @body.is_a?(IO)
+ if @body.respond_to? :readpartial
+ elsif @body.respond_to? :call
+ make_body_tempfile
+ else
@header['content-length'] = (@body ? @body.bytesize : 0).to_s
end
end
@@ -282,6 +286,33 @@ module WEBrick
end
end
+ def make_body_tempfile # :nodoc:
+ return if @bodytempfile
+ bodytempfile = Tempfile.create("webrick")
+ if @body.nil?
+ # nothing
+ elsif @body.respond_to? :readpartial
+ IO.copy_stream(@body, bodytempfile)
+ @body.close
+ elsif @body.respond_to? :call
+ @body.call(bodytempfile)
+ else
+ bodytempfile.write @body
+ end
+ bodytempfile.rewind
+ @body = @bodytempfile = bodytempfile
+ @header['content-length'] = bodytempfile.stat.size.to_s
+ end
+
+ def remove_body_tempfile # :nodoc:
+ if @bodytempfile
+ @bodytempfile.close
+ File.unlink @bodytempfile.path
+ @bodytempfile = nil
+ end
+ end
+
+
##
# Sends the headers on +socket+
@@ -445,6 +476,7 @@ module WEBrick
ensure
@body.close
end
+ remove_body_tempfile
end
def send_body_string(socket)
@@ -477,7 +509,12 @@ module WEBrick
socket.write("0#{CRLF}#{CRLF}")
else
size = @header['content-length'].to_i
- @body.call(socket)
+ if @bodytempfile
+ @bodytempfile.rewind
+ IO.copy_stream(@bodytempfile, socket)
+ else
+ @body.call(socket)
+ end
@sent_size = size
end
end
diff --git a/test/webrick/test_httpproxy.rb b/test/webrick/test_httpproxy.rb
index a9f6f7d610..8bc8a1240a 100644
--- a/test/webrick/test_httpproxy.rb
+++ b/test/webrick/test_httpproxy.rb
@@ -215,6 +215,46 @@ class TestWEBrickHTTPProxy < Test::Unit::TestCase
end
end
+ def test_http10_proxy_chunked
+ # Testing HTTP/1.0 client request and HTTP/1.1 chunked response
+ # from origin server.
+ # +------+
+ # V |
+ # client -------> proxy ---+
+ # GET GET
+ # HTTP/1.0 HTTP/1.1
+ # non-chunked chunked
+ #
+ proxy_handler_called = request_handler_called = 0
+ config = {
+ :ServerName => "localhost.localdomain",
+ :ProxyContentHandler => Proc.new{|req, res| proxy_handler_called += 1 },
+ :RequestCallback => Proc.new{|req, res| request_handler_called += 1 }
+ }
+ log_tester = lambda {|log, access_log|
+ log.reject! {|str|
+ %r{WARN chunked is set for an HTTP/1\.0 request\. \(ignored\)} =~ str
+ }
+ assert_equal([], log)
+ }
+ TestWEBrick.start_httpproxy(config, log_tester){|server, addr, port, log|
+ body = nil
+ server.mount_proc("/"){|req, res|
+ body = "#{req.request_method} #{req.path} #{req.body}"
+ res.chunked = true
+ res.body = -> (socket) { body.each_char {|c| socket.write c } }
+ }
+ http = Net::HTTP.new(addr, port, addr, port)
+
+ # Don't use Net::HTTP because it uses HTTP/1.1.
+ TCPSocket.open(addr, port) {|s|
+ s.write "GET / HTTP/1.0\r\nHost: localhost.localdomain\r\n\r\n"
+ response = s.read
+ assert_equal(body, response[/.*\z/])
+ }
+ }
+ end
+
def make_certificate(key, cn)
subject = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=#{cn}")
exts = [