Feature #3622 » expect-continue.diff
| lib/net/http.rb (working copy) | ||
|---|---|---|
|
@started = false
|
||
|
@open_timeout = nil
|
||
|
@read_timeout = 60
|
||
|
@continue_timeout = nil
|
||
|
@debug_output = nil
|
||
|
@use_ssl = false
|
||
|
@ssl_context = nil
|
||
| ... | ... | |
|
@read_timeout = sec
|
||
|
end
|
||
|
# Seconds to wait for 100 Continue response. If the HTTP object does not
|
||
|
# receive a response in this many seconds it sends the request body.
|
||
|
attr_reader :continue_timeout
|
||
|
# Setter for the continue_timeout attribute.
|
||
|
def continue_timeout=(sec)
|
||
|
@socket.continue_timeout = sec if @socket
|
||
|
@continue_timeout = sec
|
||
|
end
|
||
|
# returns true if the HTTP session is started.
|
||
|
def started?
|
||
|
@started
|
||
| ... | ... | |
|
def transport_request(req)
|
||
|
begin_transport req
|
||
|
req.exec @socket, @curr_http_version, edit_path(req.path)
|
||
|
begin
|
||
|
res = HTTPResponse.read_new(@socket)
|
||
|
end while res.kind_of?(HTTPContinue)
|
||
|
res.reading_body(@socket, req.response_body_permitted?) {
|
||
|
yield res if block_given?
|
||
|
res = catch(:response) {
|
||
|
req.exec @socket, @curr_http_version, edit_path(req.path)
|
||
|
begin
|
||
|
res = HTTPResponse.read_new(@socket)
|
||
|
end while res.kind_of?(HTTPContinue)
|
||
|
res.reading_body(@socket, req.response_body_permitted?) {
|
||
|
yield res if block_given?
|
||
|
}
|
||
|
res
|
||
|
}
|
||
|
end_transport req, res
|
||
|
res
|
||
| ... | ... | |
|
self.content_length = body.bytesize
|
||
|
delete 'Transfer-Encoding'
|
||
|
supply_default_content_type
|
||
|
wait_for_continue sock, ver if sock.continue_timeout
|
||
|
write_header sock, ver, path
|
||
|
sock.write body
|
||
|
end
|
||
| ... | ... | |
|
"Content-Length not given and Transfer-Encoding is not `chunked'"
|
||
|
end
|
||
|
supply_default_content_type
|
||
|
wait_for_continue sock, ver if sock.continue_timeout
|
||
|
write_header sock, ver, path
|
||
|
if chunked?
|
||
|
while s = f.read(1024)
|
||
| ... | ... | |
|
set_content_type 'application/x-www-form-urlencoded'
|
||
|
end
|
||
|
##
|
||
|
# Waits up to the continue timeout for a response from the server provided
|
||
|
# we're speaking HTTP 1.1 and are expecting a 100-continue response.
|
||
|
def wait_for_continue(sock, ver)
|
||
|
if ver >= '1.1' and @header['expect'] and
|
||
|
@header['expect'].include?('100-continue') then
|
||
|
if IO.select [sock.io], nil, nil, sock.continue_timeout then
|
||
|
res = HTTPResponse.read_new sock
|
||
|
unless res.kind_of?(Net::HTTPContinue)
|
||
|
throw :response, res
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
def write_header(sock, ver, path)
|
||
|
buf = "#{@method} #{path} HTTP/#{ver}\r\n"
|
||
|
each_capitalized do |k,v|
|
||
| lib/net/protocol.rb (working copy) | ||
|---|---|---|
|
def initialize(io)
|
||
|
@io = io
|
||
|
@read_timeout = 60
|
||
|
@continue_timeout = nil
|
||
|
@debug_output = nil
|
||
|
@rbuf = ''
|
||
|
end
|
||
|
attr_reader :io
|
||
|
attr_accessor :read_timeout
|
||
|
attr_accessor :continue_timeout
|
||
|
attr_accessor :debug_output
|
||
|
def inspect
|
||
| test/net/http/test_http.rb (working copy) | ||
|---|---|---|
|
end
|
||
|
end
|
||
|
class TestNetHTTPContinue < Test::Unit::TestCase
|
||
|
CONFIG = {
|
||
|
'host' => '127.0.0.1',
|
||
|
'port' => 10081,
|
||
|
'proxy_host' => nil,
|
||
|
'proxy_port' => nil,
|
||
|
'chunked' => true,
|
||
|
}
|
||
|
include TestNetHTTPUtils
|
||
|
def logfile
|
||
|
@debug = StringIO.new('')
|
||
|
end
|
||
|
def mount_proc(&block)
|
||
|
@server.mount('/continue', WEBrick::HTTPServlet::ProcHandler.new(block.to_proc))
|
||
|
end
|
||
|
def test_expect_continue
|
||
|
mount_proc {|req, res|
|
||
|
req.continue
|
||
|
res.body = req.query['body']
|
||
|
}
|
||
|
start {|http|
|
||
|
http.continue_timeout = 0.2
|
||
|
http.request_post('/continue', 'body=BODY', 'expect' => '100-continue') {|res|
|
||
|
assert_equal('BODY', res.read_body)
|
||
|
}
|
||
|
}
|
||
|
assert_match(/Expect: 100-continue/, @debug.string)
|
||
|
assert_match(/HTTP\/1.1 100 continue/, @debug.string)
|
||
|
end
|
||
|
def test_expect_continue_timeout
|
||
|
mount_proc {|req, res|
|
||
|
sleep 0.2
|
||
|
req.continue # just ignored because it's '100'
|
||
|
res.body = req.query['body']
|
||
|
}
|
||
|
start {|http|
|
||
|
http.continue_timeout = 0
|
||
|
http.request_post('/continue', 'body=BODY', 'expect' => '100-continue') {|res|
|
||
|
assert_equal('BODY', res.read_body)
|
||
|
}
|
||
|
}
|
||
|
assert_match(/Expect: 100-continue/, @debug.string)
|
||
|
assert_match(/HTTP\/1.1 100 continue/, @debug.string)
|
||
|
end
|
||
|
def test_expect_continue_error
|
||
|
mount_proc {|req, res|
|
||
|
res.status = 501
|
||
|
res.body = req.query['body']
|
||
|
}
|
||
|
start {|http|
|
||
|
http.continue_timeout = 0
|
||
|
http.request_post('/continue', 'body=ERROR', 'expect' => '100-continue') {|res|
|
||
|
assert_equal('ERROR', res.read_body)
|
||
|
}
|
||
|
}
|
||
|
assert_match(/Expect: 100-continue/, @debug.string)
|
||
|
assert_not_match(/HTTP\/1.1 100 continue/, @debug.string)
|
||
|
end
|
||
|
def test_expect_continue_error_while_waiting
|
||
|
mount_proc {|req, res|
|
||
|
res.status = 501
|
||
|
res.body = req.query['body']
|
||
|
}
|
||
|
start {|http|
|
||
|
http.continue_timeout = 0.5
|
||
|
http.request_post('/continue', 'body=ERROR', 'expect' => '100-continue') {|res|
|
||
|
assert_equal('ERROR', res.read_body)
|
||
|
}
|
||
|
}
|
||
|
assert_match(/Expect: 100-continue/, @debug.string)
|
||
|
assert_not_match(/HTTP\/1.1 100 continue/, @debug.string)
|
||
|
end
|
||
|
end
|
||
|
=begin
|
||
|
class TestNetHTTP_proxy < Test::Unit::TestCase
|
||
|
CONFIG = {
|
||