lib/httpclient/http.rb in httpclient-2.5.3.3 vs lib/httpclient/http.rb in httpclient-2.6.0

- old
+ new

@@ -196,10 +196,11 @@ @is_request = true @request_method = method @request_uri = uri || NIL_URI @request_query = query @request_absolute_uri = false + self end # Initialize this instance as a response. def init_response(status_code, req = nil) @is_request = false @@ -207,10 +208,11 @@ if req @request_method = req.request_method @request_uri = req.request_uri @request_query = req.request_query end + self end # Sets status code and reason phrase. def status_code=(status_code) @status_code = status_code @@ -439,10 +441,12 @@ class Body # Size of body. nil when size is unknown (e.g. chunked response). attr_reader :size # maxbytes of IO#read for streaming request. See DEFAULT_CHUNK_SIZE. attr_accessor :chunk_size + # Hash that keeps IO positions + attr_accessor :positions # Default value for chunk_size DEFAULT_CHUNK_SIZE = 1024 * 16 # Creates a Message::Body. Use init_request or init_response @@ -458,10 +462,11 @@ def init_request(body = nil, boundary = nil) @boundary = boundary @positions = {} set_content(body, boundary) @chunk_size = DEFAULT_CHUNK_SIZE + self end # Initialize this instance as a response. def init_response(body = nil) @body = body @@ -470,34 +475,37 @@ elsif @body.respond_to?(:size) @size = @body.size else @size = nil end + self end # Dumps message body to given dev. # dev needs to respond to <<. # # Message header must be given as the first argument for performance # reason. (header is dumped to dev, too) # If no dev (the second argument) given, this method returns a dumped # String. + # + # assert: @size is not nil def dump(header = '', dev = '') if @body.is_a?(Parts) dev << header @body.parts.each do |part| if Message.file?(part) reset_pos(part) - dump_file(part, dev) + dump_file(part, dev, @body.sizes[part]) else dev << part end end elsif Message.file?(@body) dev << header reset_pos(@body) - dump_file(@body, dev) + dump_file(@body, dev, @size) elsif @body dev << header + @body else dev << header end @@ -561,14 +569,18 @@ def reset_pos(io) io.pos = @positions[io] if @positions.key?(io) end - def dump_file(io, dev) + def dump_file(io, dev, sz) buf = '' - while !io.read(@chunk_size, buf).nil? + rest = sz + while rest > 0 + n = io.read([rest, @chunk_size].min, buf) + raise ArgumentError.new("Illegal size value: #size returns #{sz} but cannot read") if n.nil? dev << buf + rest -= n.bytesize end end def dump_chunks(io, dev) buf = '' @@ -589,31 +601,36 @@ sprintf("%x", size) + CRLF end class Parts attr_reader :size + attr_reader :sizes def initialize @body = [] - @size = 0 + @sizes = {} + @size = 0 # total @as_stream = false end def add(part) if Message.file?(part) @as_stream = true @body << part if part.respond_to?(:lstat) - @size += part.lstat.size + sz = part.lstat.size + add_size(part, sz) elsif part.respond_to?(:size) if sz = part.size - @size += sz + add_size(part, sz) else + @sizes.clear @size = nil end else # use chunked upload + @sizes.clear @size = nil end elsif @body[-1].is_a?(String) @body[-1] += part.to_s @size += part.to_s.bytesize if @size @@ -628,10 +645,19 @@ @body else [@body.join] end end + + private + + def add_size(part, sz) + if @size + @sizes[part] = sz + @size += sz + end + end end def build_query_multipart_str(query, boundary) parts = Parts.new query.each do |attr, value| @@ -906,16 +932,21 @@ # OpenSSL::X509::Certificate:: response only. server certificate which is # used for retrieving the response. attr_accessor :peer_cert + # The other Message object when this Message is generated instead of + # the Message because of redirection, negotiation, or format conversion. + attr_accessor :previous + # Creates a Message. This method should be used internally. # Use Message.new_connect_request, Message.new_request or # Message.new_response instead. def initialize # :nodoc: @http_header = Headers.new @http_body = @peer_cert = nil + @previous = nil end # Dumps message (header and body) to given dev. # dev needs to respond to <<. def dump(dev = '') @@ -1021,13 +1052,11 @@ def cookies set_cookies = http_header['set-cookie'] unless set_cookies.empty? uri = http_header.request_uri set_cookies.map { |str| - cookie = WebAgent::Cookie.new - cookie.parse(str, uri) - cookie - } + WebAgent::Cookie.parse(str, uri) + }.flatten end end # Convenience method to return boolean of whether we had a successful request def ok?