class Excon::Connection
def request(params, &block)
(**params)
-
:scheme
(String
) -- The protocol; 'https' causes OpenSSL to be used -
:query
(Hash
) -- appended to the 'scheme://host:port/path/' in the form of '?key=value' -
:port
(Fixnum
) -- The port on which to connect, to the destination host -
:path
(String
) -- appears after 'scheme://host:port/' -
:host
(String
) -- The destination host's reachable DNS name or IP, in the form of a String -
:headers
(Hash
) -- The default headers to supply in a request -
:body
(String
) -- text to be sent over a socket
Parameters:
-
params
(Hash
) -- One or more optional params, override defaults set in Connection.new
Other tags:
- Yield: - @see Response#self.parse
def request(params, &block) begin # connection has defaults, merge in new params to override params = @connection.merge(params) params[:headers] = @connection[:headers].merge(params[:headers] || {}) # if path is empty or doesn't start with '/', insert one unless params[:path][0..0] == '/' params[:path].insert(0, '/') end # start with "METHOD /path" request = params[:method].to_s.upcase << ' ' << params[:path] # add query to path, if there is one case params[:query] when String request << '?' << params[:query] when Hash request << '?' for key, values in params[:query] for value in [*values] value_string = value && ('=' << CGI.escape(value.to_s)) request << key.to_s << value_string.to_s << '&' end end request.chop! # remove trailing '&' end # finish first line with "HTTP/1.1\r\n" request << HTTP_1_1 # calculate content length and set to handle non-ascii params[:headers]['Content-Length'] = case params[:body] when File params[:body].binmode File.size(params[:body].path) when String if params[:body].respond_to?(:force_encoding) params[:body].force_encoding('BINARY') end params[:body].length else 0 end # add headers to request for key, value in params[:headers] request << key.to_s << ': ' << value.to_s << CR_NL end # add additional "\r\n" to indicate end of headers request << CR_NL # write out the request, sans body socket.write(request) # write out the body 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 # read the response response = Excon::Response.parse(socket, params, &block) if response.headers['Connection'] == 'close' reset end response rescue => socket_error reset raise(Excon::Errors::SocketError.new(socket_error)) end if params[:expects] && ![*params[:expects]].include?(response.status) reset raise(Excon::Errors.status_error(params, response)) else response end rescue => request_error if params[:idempotent] && (request_error.is_a?(Excon::Errors::SocketError) || (request_error.is_a?(Excon::Errors::HTTPStatusError) && response.status != 404)) retries_remaining ||= 4 retries_remaining -= 1 if retries_remaining > 0 retry else raise(request_error) end else raise(request_error) end end