This improves handling of 100-continue responses
parent
19920b3275
commit
43fe219a05
|
@ -195,8 +195,7 @@ class Client
|
|||
# - cookie: Cookie header value
|
||||
# - ctype: Content-Type header value, default: +application/x-www-form-urlencoded+
|
||||
# - data: HTTP data (only useful with some methods, see rfc2616)
|
||||
# - encode: URI encode the supplied URI, default: false
|
||||
# - encode_params: URI encode the GET or POST variables (names and values), default: true
|
||||
# - encode: URI encode the supplied URI
|
||||
# - headers: HTTP headers as a hash, e.g. <code>{ "X-MyHeader" => "value" }</code>
|
||||
# - method: HTTP method to use in the request, not limited to standard methods defined by rfc2616, default: GET
|
||||
# - proto: protocol, default: HTTP
|
||||
|
@ -209,28 +208,28 @@ class Client
|
|||
# - vhost: Host header value
|
||||
#
|
||||
def request_cgi(opts={})
|
||||
c_enc = opts['encode'] || false
|
||||
c_enc_p = (opts['encode_params'] == true or opts['encode_params'].nil? ? true : false)
|
||||
c_cgi = opts['uri'] || '/'
|
||||
c_body = opts['data'] || ''
|
||||
c_meth = opts['method'] || 'GET'
|
||||
c_prot = opts['proto'] || 'HTTP'
|
||||
c_vers = opts['version'] || config['version'] || '1.1'
|
||||
c_qs = opts['query'] || ''
|
||||
c_varg = opts['vars_get'] || {}
|
||||
c_varp = opts['vars_post'] || {}
|
||||
c_head = opts['headers'] || config['headers'] || {}
|
||||
c_rawh = opts['raw_headers'] || config['raw_headers'] || ''
|
||||
c_type = opts['ctype'] || 'application/x-www-form-urlencoded'
|
||||
c_ag = opts['agent'] || config['agent']
|
||||
c_cook = opts['cookie'] || config['cookie']
|
||||
c_host = opts['vhost'] || config['vhost']
|
||||
c_conn = opts['connection']
|
||||
c_path = opts['path_info']
|
||||
c_auth = opts['basic_auth'] || config['basic_auth'] || ''
|
||||
uri = set_cgi(c_cgi)
|
||||
qstr = c_qs
|
||||
pstr = c_body
|
||||
c_enc = opts['encode'] || false
|
||||
c_cgi = opts['uri'] || '/'
|
||||
c_body = opts['data'] || ''
|
||||
c_meth = opts['method'] || 'GET'
|
||||
c_prot = opts['proto'] || 'HTTP'
|
||||
c_vers = opts['version'] || config['version'] || '1.1'
|
||||
c_qs = opts['query'] || ''
|
||||
c_varg = opts['vars_get'] || {}
|
||||
c_varp = opts['vars_post'] || {}
|
||||
c_head = opts['headers'] || config['headers'] || {}
|
||||
c_rawh = opts['raw_headers']|| config['raw_headers'] || ''
|
||||
c_type = opts['ctype'] || 'application/x-www-form-urlencoded'
|
||||
c_ag = opts['agent'] || config['agent']
|
||||
c_cook = opts['cookie'] || config['cookie']
|
||||
c_host = opts['vhost'] || config['vhost']
|
||||
c_conn = opts['connection']
|
||||
c_path = opts['path_info']
|
||||
c_auth = opts['basic_auth'] || config['basic_auth'] || ''
|
||||
|
||||
uri = set_cgi(c_cgi)
|
||||
qstr = c_qs
|
||||
pstr = c_body
|
||||
|
||||
if (config['pad_get_params'])
|
||||
1.upto(config['pad_get_params_count'].to_i) do |i|
|
||||
|
@ -243,27 +242,25 @@ class Client
|
|||
|
||||
c_varg.each_pair do |var,val|
|
||||
qstr << '&' if qstr.length > 0
|
||||
qstr << (c_enc_p ? set_encode_uri(var) : var)
|
||||
qstr << set_encode_uri(var)
|
||||
qstr << '='
|
||||
qstr << (c_enc_p ? set_encode_uri(val) : val)
|
||||
qstr << set_encode_uri(val)
|
||||
end
|
||||
|
||||
if (config['pad_post_params'])
|
||||
1.upto(config['pad_post_params_count'].to_i) do |i|
|
||||
rand_var = Rex::Text.rand_text_alphanumeric(rand(32)+1)
|
||||
rand_val = Rex::Text.rand_text_alphanumeric(rand(32)+1)
|
||||
pstr << '&' if pstr.length > 0
|
||||
pstr << (c_enc_p ? set_encode_uri(rand_var) : rand_var)
|
||||
pstr << set_encode_uri(Rex::Text.rand_text_alphanumeric(rand(32)+1))
|
||||
pstr << '='
|
||||
pstr << (c_enc_p ? set_encode_uri(rand_val) : rand_val)
|
||||
pstr << set_encode_uri(Rex::Text.rand_text_alphanumeric(rand(32)+1))
|
||||
end
|
||||
end
|
||||
|
||||
c_varp.each_pair do |var,val|
|
||||
pstr << '&' if pstr.length > 0
|
||||
pstr << (c_enc_p ? set_encode_uri(var) : var)
|
||||
pstr << set_encode_uri(var)
|
||||
pstr << '='
|
||||
pstr << (c_enc_p ? set_encode_uri(val) : val)
|
||||
pstr << set_encode_uri(val)
|
||||
end
|
||||
|
||||
req = ''
|
||||
|
@ -297,7 +294,6 @@ class Client
|
|||
req << set_chunked_header()
|
||||
req << set_raw_headers(c_rawh)
|
||||
req << set_body(pstr)
|
||||
|
||||
req
|
||||
end
|
||||
|
||||
|
@ -365,7 +361,7 @@ class Client
|
|||
#
|
||||
# Read a response from the server
|
||||
#
|
||||
def read_response(t = -1)
|
||||
def read_response(t = -1, opts = {})
|
||||
|
||||
resp = Response.new
|
||||
resp.max_data = config['read_max_data']
|
||||
|
@ -392,7 +388,7 @@ class Client
|
|||
|
||||
##########################################################################
|
||||
# XXX: NOTE: BUG: get_once currently (as of r10042) rescues "Exception"
|
||||
# As such, the following rescue block will ever be reached. -jjd
|
||||
# As such, the following rescue block will never be reached. -jjd
|
||||
##########################################################################
|
||||
|
||||
# Handle unexpected disconnects
|
||||
|
@ -434,14 +430,20 @@ class Client
|
|||
return resp if not resp
|
||||
|
||||
# As a last minute hack, we check to see if we're dealing with a 100 Continue here.
|
||||
if resp.proto == '1.1' and resp.code == 100
|
||||
# If so, our real response becaome the body, so we re-parse it.
|
||||
body = resp.body
|
||||
resp = Response.new
|
||||
resp.max_data = config['read_max_data']
|
||||
rv = resp.parse(body)
|
||||
# XXX: At some point, this may benefit from processing post-completion code
|
||||
# as seen above.
|
||||
# Most of the time this is handled by the parser via check_100()
|
||||
if resp.proto == '1.1' and resp.code == 100 and not opts[:skip_100]
|
||||
# Read the real response from the body if we found one
|
||||
# If so, our real response became the body, so we re-parse it.
|
||||
if resp.body.to_s =~ /^HTTP/
|
||||
body = resp.body
|
||||
resp = Response.new
|
||||
resp.max_data = config['read_max_data']
|
||||
rv = resp.parse(body)
|
||||
# We found a 100 Continue but didn't read the real reply yet
|
||||
# Otherwise reread the reply, but don't try this hack again
|
||||
else
|
||||
resp = read_response(t, :skip_100 => true)
|
||||
end
|
||||
end
|
||||
|
||||
resp
|
||||
|
|
|
@ -367,6 +367,7 @@ protected
|
|||
if (self.body_bytes_left == 0)
|
||||
self.bufq.sub!(/^\r?\n/s,'')
|
||||
self.state = ParseState::Completed
|
||||
self.check_100
|
||||
return
|
||||
end
|
||||
|
||||
|
@ -396,10 +397,15 @@ protected
|
|||
# ready to go.
|
||||
if (not self.transfer_chunked and self.body_bytes_left == 0)
|
||||
self.state = ParseState::Completed
|
||||
self.check_100
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
# Override this as needed
|
||||
def check_100
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -53,6 +53,9 @@ class Response < Packet
|
|||
# default chunk sizes (if chunked is used)
|
||||
self.chunk_min_size = 1
|
||||
self.chunk_max_size = 10
|
||||
|
||||
# 100 continue counter
|
||||
self.count_100 = 0
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -66,6 +69,19 @@ class Response < Packet
|
|||
else
|
||||
raise RuntimeError, "Invalid response command string", caller
|
||||
end
|
||||
|
||||
check_100()
|
||||
end
|
||||
|
||||
#
|
||||
# Allow 100 Continues to be ignored by the caller
|
||||
#
|
||||
def check_100
|
||||
# If this was a 100 continue with no data, reset
|
||||
if self.code == 100 and (self.body_bytes_left == -1 or self.body_bytes_left == 0) and self.count_100 < 5
|
||||
self.reset_except_queue
|
||||
self.count_100 += 1
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -84,6 +100,7 @@ class Response < Packet
|
|||
attr_accessor :code
|
||||
attr_accessor :message
|
||||
attr_accessor :proto
|
||||
attr_accessor :count_100
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue