Class: HTTPX::Request
- Inherits:
-
Object
- Object
- HTTPX::Request
- Extended by:
- Forwardable
- Defined in:
- lib/httpx/request.rb
Overview
Defines how an HTTP request is handled internally, both in terms of making attributes accessible, as well as maintaining the state machine which manages streaming the request onto the wire.
Direct Known Subclasses
Defined Under Namespace
Classes: Body
Constant Summary collapse
- ALLOWED_URI_SCHEMES =
%w[https http].freeze
Constants included from Loggable
Loggable::COLORS, Loggable::USE_DEBUG_LOG
Instance Attribute Summary collapse
-
#active_timeouts ⇒ Object
readonly
Returns the value of attribute active_timeouts.
-
#body ⇒ Object
readonly
an HTTPX::Request::Body object containing the request body payload (or
nil, whenn there is none). -
#connection ⇒ Object
writeonly
the connection the request is currently being sent to (none if before or after transaction).
-
#drain_error ⇒ Object
readonly
Exception raised during enumerable body writes.
-
#headers ⇒ Object
readonly
an HTTPX::Headers object containing the request HTTP headers.
-
#on_response_arrived ⇒ Object
writeonly
callback triggered when a response (which may not be the final response) was assigned to the request.
-
#options ⇒ Object
readonly
an HTTPX::Options object containing request options.
-
#peer_address ⇒ Object
The IP address from the peer server.
-
#persistent ⇒ Object
writeonly
Sets the attribute persistent.
-
#response ⇒ Object
the corresponding HTTPX::Response object, when there is one.
-
#state ⇒ Object
readonly
a symbol describing which frame is currently being flushed.
-
#uri ⇒ Object
readonly
the absolute URI object for this request.
-
#verb ⇒ Object
readonly
the upcased string HTTP verb for this request.
Instance Method Summary collapse
-
#authority ⇒ Object
returs the URI authority of the request.
- #can_buffer? ⇒ Boolean
- #complete!(response = @response) ⇒ Object
-
#drain_body ⇒ Object
consumes and returns the next available chunk of request body that can be sent.
- #emit_response(response) ⇒ Object
-
#expects? ⇒ Boolean
whether the request supports the 100-continue handshake and already processed the 100 response.
- #handle_error(error) ⇒ Object
-
#initialize(verb, uri, options, params = EMPTY_HASH) ⇒ Request
constructor
initializes the instance with the given
verb(an upppercase String, ex. ‘GEt’), an absolute or relativeuri(either as String or URI::HTTP object), the requestoptions(instance of HTTPX::Options) and an optional Hash ofparams. -
#initialize_dup(orig) ⇒ Object
dupped initialization.
-
#inspect ⇒ Object
:nocov:.
-
#interests ⇒ Object
returns
:ror:w, depending on whether the request is waiting for a response or flushing. -
#merge_headers(h) ⇒ Object
merges
hinto the instance of HTTPX::Headers of the request. -
#origin ⇒ Object
returs the URI origin of the request.
-
#path ⇒ Object
returnns the URI path of the request
uri. - #persistent? ⇒ Boolean
-
#ping! ⇒ Object
marks the request as having been buffered with a ping.
-
#ping? ⇒ Boolean
whether request has been buffered with a ping.
-
#query ⇒ Object
returs the URI query string of the request (when available).
-
#read_timeout ⇒ Object
the read timeout defined for this request.
-
#request_timeout ⇒ Object
the request timeout defined for this request.
-
#scheme ⇒ Object
the URI scheme of the request
uri. - #set_timeout_callback(event, &callback) ⇒ Object
-
#trailers ⇒ Object
returns an instance of HTTPX::Headers containing the trailer headers.
-
#trailers? ⇒ Boolean
if the request contains trailer headers.
-
#transition(nextstate) ⇒ Object
moves on to the
nextstateof the request state machine (when all preconditions are met). -
#write_timeout ⇒ Object
the write timeout defined for this request.
Methods included from Callbacks
#callbacks_for?, #emit, #on, #once
Methods included from Loggable
#log, #log_exception, #log_redact, #log_redact_body, #log_redact_headers
Constructor Details
#initialize(verb, uri, options, params = EMPTY_HASH) ⇒ Request
initializes the instance with the given verb (an upppercase String, ex. ‘GEt’), an absolute or relative uri (either as String or URI::HTTP object), the request options (instance of HTTPX::Options) and an optional Hash of params.
Besides any of the options documented in HTTPX::Options (which would override or merge with what options sets), it accepts also the following:
- :params
-
hash or array of key-values which will be encoded and set in the query string of request uris.
- :body
-
to be encoded in the request body payload. can be a String, an IO object (i.e. a File), or an Enumerable.
- :form
-
hash of array of key-values which will be form-urlencoded- or multipart-encoded in requests body payload.
- :json
-
hash of array of key-values which will be JSON-encoded in requests body payload.
- :xml
-
Nokogiri XML nodes which will be encoded in requests body payload.
:body, :form, :json and :xml are all mutually exclusive, i.e. only one of them gets picked up.
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/httpx/request.rb', line 75 def initialize(verb, uri, , params = EMPTY_HASH) @verb = verb.to_s.upcase @uri = Utils.to_uri(uri) @headers = .headers.dup merge_headers(params.delete(:headers)) if params.key?(:headers) @query_params = params.delete(:params) if params.key?(:params) @body = .request_body_class.new(@headers, , **params) @options = @body. if @uri.relative? || @uri.host.nil? origin = @options.origin raise(Error, "invalid URI: #{@uri}") unless origin base_path = @options.base_path @uri = origin.merge("#{base_path}#{@uri}") end raise UnsupportedSchemeError, "#{@uri}: #{@uri.scheme}: unsupported URI scheme" unless ALLOWED_URI_SCHEMES.include?(@uri.scheme) @state = :idle @connection = @response = @drainer = @peer_address = @informational_status = @on_response_arrived = nil @ping = false @persistent = @options.persistent @active_timeouts = [] end |
Instance Attribute Details
#active_timeouts ⇒ Object (readonly)
Returns the value of attribute active_timeouts.
53 54 55 |
# File 'lib/httpx/request.rb', line 53 def active_timeouts @active_timeouts end |
#body ⇒ Object (readonly)
an HTTPX::Request::Body object containing the request body payload (or nil, whenn there is none).
28 29 30 |
# File 'lib/httpx/request.rb', line 28 def body @body end |
#connection=(value) ⇒ Object (writeonly)
the connection the request is currently being sent to (none if before or after transaction)
46 47 48 |
# File 'lib/httpx/request.rb', line 46 def connection=(value) @connection = value end |
#drain_error ⇒ Object (readonly)
Exception raised during enumerable body writes.
40 41 42 |
# File 'lib/httpx/request.rb', line 40 def drain_error @drain_error end |
#headers ⇒ Object (readonly)
an HTTPX::Headers object containing the request HTTP headers.
25 26 27 |
# File 'lib/httpx/request.rb', line 25 def headers @headers end |
#on_response_arrived=(value) ⇒ Object (writeonly)
callback triggered when a response (which may not be the final response) was assigned to the request.
49 50 51 |
# File 'lib/httpx/request.rb', line 49 def on_response_arrived=(value) @on_response_arrived = value end |
#options ⇒ Object (readonly)
an HTTPX::Options object containing request options.
34 35 36 |
# File 'lib/httpx/request.rb', line 34 def @options end |
#peer_address ⇒ Object
The IP address from the peer server.
43 44 45 |
# File 'lib/httpx/request.rb', line 43 def peer_address @peer_address end |
#persistent=(value) ⇒ Object (writeonly)
Sets the attribute persistent
51 52 53 |
# File 'lib/httpx/request.rb', line 51 def persistent=(value) @persistent = value end |
#response ⇒ Object
the corresponding HTTPX::Response object, when there is one.
37 38 39 |
# File 'lib/httpx/request.rb', line 37 def response @response end |
#state ⇒ Object (readonly)
a symbol describing which frame is currently being flushed.
31 32 33 |
# File 'lib/httpx/request.rb', line 31 def state @state end |
#uri ⇒ Object (readonly)
the absolute URI object for this request.
22 23 24 |
# File 'lib/httpx/request.rb', line 22 def uri @uri end |
#verb ⇒ Object (readonly)
the upcased string HTTP verb for this request.
19 20 21 |
# File 'lib/httpx/request.rb', line 19 def verb @verb end |
Instance Method Details
#authority ⇒ Object
returs the URI authority of the request.
session.build_request("GET", "https://google.com/query"). #=> "google.com"
session.build_request("GET", "http://internal:3182/a"). #=> "internal:3182"
224 225 226 |
# File 'lib/httpx/request.rb', line 224 def @uri. end |
#can_buffer? ⇒ Boolean
166 167 168 |
# File 'lib/httpx/request.rb', line 166 def can_buffer? @state != :done end |
#complete!(response = @response) ⇒ Object
116 117 118 |
# File 'lib/httpx/request.rb', line 116 def complete!(response = @response) emit(:complete, response) end |
#drain_body ⇒ Object
consumes and returns the next available chunk of request body that can be sent
254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
# File 'lib/httpx/request.rb', line 254 def drain_body return nil if @body.nil? @drainer ||= @body.each chunk = @drainer.next.dup emit(:body_chunk, chunk) chunk rescue StopIteration nil rescue StandardError => e @drain_error = e nil end |
#emit_response(response) ⇒ Object
342 343 344 345 346 347 348 |
# File 'lib/httpx/request.rb', line 342 def emit_response(response) emit(:response, response) return unless @on_response_arrived @on_response_arrived.call end |
#expects? ⇒ Boolean
whether the request supports the 100-continue handshake and already processed the 100 response.
319 320 321 |
# File 'lib/httpx/request.rb', line 319 def expects? @headers["expect"] == "100-continue" && @informational_status == 100 && !@response end |
#handle_error(error) ⇒ Object
332 333 334 335 336 337 338 339 340 |
# File 'lib/httpx/request.rb', line 332 def handle_error(error) if (connection = @connection) connection.on_error(error, self) else response = ErrorResponse.new(self, error) self.response = response emit_response(response) end end |
#initialize_dup(orig) ⇒ Object
dupped initialization
109 110 111 112 113 114 |
# File 'lib/httpx/request.rb', line 109 def initialize_dup(orig) super @uri = orig.instance_variable_get(:@uri).dup @headers = orig.instance_variable_get(:@headers).dup @body = orig.instance_variable_get(:@body).dup end |
#inspect ⇒ Object
:nocov:
270 271 272 273 274 275 276 |
# File 'lib/httpx/request.rb', line 270 def inspect "#<#{self.class}:#{object_id} " \ "#{@verb} " \ "#{uri} " \ "@headers=#{@headers} " \ "@body=#{@body}>" end |
#interests ⇒ Object
returns :r or :w, depending on whether the request is waiting for a response or flushing.
160 161 162 163 164 |
# File 'lib/httpx/request.rb', line 160 def interests return :r if @state == :done || @state == :expect :w end |
#merge_headers(h) ⇒ Object
merges h into the instance of HTTPX::Headers of the request.
171 172 173 174 175 176 |
# File 'lib/httpx/request.rb', line 171 def merge_headers(h) @headers = @headers.merge(h) return unless @headers.key?("range") @headers.delete("accept-encoding") end |
#origin ⇒ Object
returs the URI origin of the request.
session.build_request("GET", "https://google.com/query"). #=> "https://google.com"
session.build_request("GET", "http://internal:3182/a"). #=> "http://internal:3182"
232 233 234 |
# File 'lib/httpx/request.rb', line 232 def origin @uri.origin end |
#path ⇒ Object
returnns the URI path of the request uri.
212 213 214 215 216 217 218 |
# File 'lib/httpx/request.rb', line 212 def path path = uri.path.dup path = +"" if path.nil? path << "/" if path.empty? path << "?#{query}" unless query.empty? path end |
#persistent? ⇒ Boolean
145 146 147 |
# File 'lib/httpx/request.rb', line 145 def persistent? @persistent end |
#ping! ⇒ Object
marks the request as having been buffered with a ping
126 127 128 |
# File 'lib/httpx/request.rb', line 126 def ping! @ping = true end |
#ping? ⇒ Boolean
whether request has been buffered with a ping
121 122 123 |
# File 'lib/httpx/request.rb', line 121 def ping? @ping end |
#query ⇒ Object
returs the URI query string of the request (when available).
session.build_request("GET", "https://search.com").query #=> ""
session.build_request("GET", "https://search.com?q=a").query #=> "q=a"
session.build_request("GET", "https://search.com", params: { q: "a"}).query #=> "q=a"
session.build_request("GET", "https://search.com?q=a", params: { foo: "bar"}).query #=> "q=a&foo&bar"
242 243 244 245 246 247 248 249 250 251 |
# File 'lib/httpx/request.rb', line 242 def query return @query if defined?(@query) query = [] if (q = @query_params) && !q.empty? query << Transcoder::Form.encode(q) end query << @uri.query if @uri.query @query = query.join("&") end |
#read_timeout ⇒ Object
the read timeout defined for this request.
131 132 133 |
# File 'lib/httpx/request.rb', line 131 def read_timeout @options.timeout[:read_timeout] end |
#request_timeout ⇒ Object
the request timeout defined for this request.
141 142 143 |
# File 'lib/httpx/request.rb', line 141 def request_timeout @options.timeout[:request_timeout] end |
#scheme ⇒ Object
the URI scheme of the request uri.
179 180 181 |
# File 'lib/httpx/request.rb', line 179 def scheme @uri.scheme end |
#set_timeout_callback(event, &callback) ⇒ Object
323 324 325 326 327 328 329 330 |
# File 'lib/httpx/request.rb', line 323 def set_timeout_callback(event, &callback) clb = once(event, &callback) # reset timeout callbacks when requests get rerouted to a different connection once(:idle) do callbacks(event).delete(clb) end end |
#trailers ⇒ Object
returns an instance of HTTPX::Headers containing the trailer headers
155 156 157 |
# File 'lib/httpx/request.rb', line 155 def trailers @trailers ||= @options.headers_class.new end |
#trailers? ⇒ Boolean
if the request contains trailer headers
150 151 152 |
# File 'lib/httpx/request.rb', line 150 def trailers? defined?(@trailers) end |
#transition(nextstate) ⇒ Object
moves on to the nextstate of the request state machine (when all preconditions are met)
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 |
# File 'lib/httpx/request.rb', line 280 def transition(nextstate) case nextstate when :idle @body.rewind @ping = false @response = @drainer = nil @active_timeouts.clear when :headers return unless @state == :idle when :body return unless @state == :headers || @state == :expect if @headers.key?("expect") if @informational_status && @informational_status == 100 # check for 100 Continue response, and deallocate the var # if @informational_status == 100 # @response = nil # end else return if @state == :expect # do not re-set it nextstate = :expect end end when :trailers return unless @state == :body when :done return if @state == :expect end log(level: 3) { "#{@state}] -> #{nextstate}" } @state = nextstate emit(@state, self) nil end |
#write_timeout ⇒ Object
the write timeout defined for this request.
136 137 138 |
# File 'lib/httpx/request.rb', line 136 def write_timeout @options.timeout[:write_timeout] end |