class Excon::Connection
def request_call(datum)
def request_call(datum) begin if datum.has_key?(:response) # we already have data from a middleware, so bail return datum else socket(datum).data = datum # start with "METHOD /path" request = datum[:method].to_s.upcase + ' ' if datum[:proxy] && datum[:scheme] != HTTPS request << datum[:scheme] << '://' << datum[:host] << port_string(datum) end request << datum[:path] # add query to path, if there is one request << query_string(datum) # finish first line with "HTTP/1.1\r\n" request << HTTP_1_1 if datum.has_key?(:request_block) datum[:headers]['Transfer-Encoding'] = 'chunked' else body = datum[:body].is_a?(String) ? StringIO.new(datum[:body]) : datum[:body] # The HTTP spec isn't clear on it, but specifically, GET requests don't usually send bodies; # if they don't, sending Content-Length:0 can cause issues. unless datum[:method].to_s.casecmp('GET') == 0 && body.nil? unless datum[:headers].has_key?('Content-Length') datum[:headers]['Content-Length'] = detect_content_length(body) end end end # add headers to request request << Utils.headers_hash_to_s(datum[:headers]) # add additional "\r\n" to indicate end of headers request << CR_NL if datum.has_key?(:request_block) socket(datum).write(request) # write out request + headers while true # write out body with chunked encoding chunk = datum[:request_block].call chunk = binary_encode(chunk) if chunk.length > 0 socket(datum).write(chunk.length.to_s(16) << CR_NL << chunk << CR_NL) else socket(datum).write(String.new("0#{CR_NL}#{CR_NL}")) break end end elsif body.nil? socket(datum).write(request) # write out request + headers else # write out body if body.respond_to?(:binmode) && !body.is_a?(StringIO) body.binmode end if body.respond_to?(:rewind) body.rewind rescue nil end # if request + headers is less than chunk size, fill with body request = binary_encode(request) chunk = body.read([datum[:chunk_size] - request.length, 0].max) if chunk chunk = binary_encode(chunk) socket(datum).write(request << chunk) else socket(datum).write(request) # write out request + headers end while (chunk = body.read(datum[:chunk_size])) socket(datum).write(chunk) end end end rescue => error case error when Excon::Errors::InvalidHeaderKey, Excon::Errors::InvalidHeaderValue, Excon::Errors::StubNotFound, Excon::Errors::Timeout raise(error) when Errno::EPIPE # Read whatever remains in the pipe to aid in debugging response = socket.read error = Excon::Error.new(response + error.message) raise_socket_error(error) else raise_socket_error(error) end end datum end