def request(params, &block)
begin
params = @connection.merge(params)
params[:headers] = @connection[:headers].merge(params[:headers] || {})
params[:headers]['Host'] ||= '' << params[:host] << ':' << params[:port]
unless params[:path][0, 1] == '/'
params[:path].insert(0, '/')
end
if params[:mock]
for stub, response in Excon.stubs
if [stub.keys - [:headers]].all? {|key| stub[key] == params[key] } &&
(!stub.has_key?(:headers) || stub[:headers].keys.all? {|key| stub[:headers][key] == params[:headers][key]})
case response
when Proc
return Excon::Response.new(response.call(params))
else
return Excon::Response.new(response)
end
end
end
raise(Excon::Errors::StubNotFound.new('no stubs matched ' << params.inspect))
end
request = params[:method].to_s.upcase << ' '
if @proxy
request << params[:scheme] << '://' << params[:host] << ':' << params[:port]
end
request << params[:path]
case params[:query]
when String
request << '?' << params[:query]
when Hash
request << '?'
for key, values in params[:query]
if values.nil?
request << key.to_s << '&'
else
for value in [*values]
request << key.to_s << '=' << CGI.escape(value.to_s) << '&'
end
end
end
request.chop!
end
request << HTTP_1_1
unless params[:headers].has_key?('Content-Length')
params[:headers]['Content-Length'] = case params[:body]
when File
params[:body].binmode
File.size(params[:body])
when String
if FORCE_ENC
params[:body].force_encoding('BINARY')
end
params[:body].length
else
0
end
end
for key, values in params[:headers]
for value in [*values]
request << key.to_s << ': ' << value.to_s << CR_NL
end
end
request << CR_NL
socket.write(request)
socket.flush
if params[:body]
if params[:body].is_a?(String)
socket.write(params[:body])
else
while chunk = params[:body].read(CHUNK_SIZE)
socket.write(chunk)
end
end
end
response = Excon::Response.parse(socket, params, &block)
if response.headers['Connection'] == 'close'
reset
end
response
rescue Excon::Errors::StubNotFound => stub_not_found
raise(stub_not_found)
rescue => socket_error
reset
raise(Excon::Errors::SocketError.new(socket_error))
end
if params.has_key?(:expects) && ![*params[:expects]].include?(response.status)
reset
raise(Excon::Errors.status_error(params, response))
else
response
end
rescue => request_error
if params[:idempotent] && [Excon::Errors::SocketError, Excon::Errors::HTTPStatusError].include?(request_error)
retries_remaining ||= 4
retries_remaining -= 1
if retries_remaining > 0
if params[:body].respond_to?(:pos=)
params[:body].pos = 0
end
retry
else
raise(request_error)
end
else
raise(request_error)
end
end