Class: HTTPX::Request
- Inherits:
-
Object
- Object
- HTTPX::Request
- Extended by:
- Forwardable
- Defined in:
- lib/httpx/request.rb,
sig/request.rbs
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
- METHODS =
- USER_AGENT =
Constants included from Loggable
Loggable::COLORS, Loggable::USE_DEBUG_LOG
Instance Attribute Summary collapse
-
#active_timeouts ⇒ Array[Timers::Timer]
readonly
Returns the value of attribute active_timeouts.
-
#body ⇒ Body
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 ⇒ StandardError?
readonly
Exception raised during enumerable body writes.
-
#headers ⇒ Headers
readonly
an HTTPX::Headers object containing the request HTTP headers.
-
#http2_stream_options ⇒ { ?dependency: Integer, ?exclusive: bool, ?weight: Integer }
readonly
when this request is sent via HTTP/2, it'll use this hash of options to set the priority of the respective HTTP/2 frame.
-
#on_response_arrived ⇒ Object
writeonly
callback triggered when a response (which may not be the final response) was assigned to the request.
-
#options ⇒ Options
readonly
an HTTPX::Options object containing request options.
-
#peer_address ⇒ String, ...
The IP address from the peer server.
-
#persistent ⇒ Object
writeonly
Sets the attribute persistent.
-
#response ⇒ response?
the corresponding HTTPX::Response object, when there is one.
-
#state ⇒ Symbol
readonly
a symbol describing which frame is currently being flushed.
-
#uri ⇒ http_uri
readonly
the absolute URI object for this request.
-
#verb ⇒ verb
readonly
the upcased string HTTP verb for this request.
Instance Method Summary collapse
-
#authority ⇒ String
returs the URI authority of the request.
- #can_buffer? ⇒ Boolean
- #close ⇒ void
- #complete!(response = @response) ⇒ void
-
#drain_body ⇒ String?
consumes and returns the next available chunk of request body that can be sent.
- #emit_response(response) ⇒ void
- #empty? ⇒ Boolean
-
#expects? ⇒ Boolean
whether the request supports the 100-continue handshake and already processed the 100 response.
- #handle_error(error) ⇒ void
-
#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 ⇒ String
simplecov:disable.
-
#interests ⇒ :r, :w
returns
:ror:w, depending on whether the request is waiting for a response or flushing. -
#merge_headers(h) ⇒ void
merges
hinto the instance of HTTPX::Headers of the request. -
#origin ⇒ String
returs the URI origin of the request.
-
#path ⇒ String
returnns the URI path of the request
uri. - #persistent? ⇒ Boolean
-
#ping! ⇒ void
marks the request as having been buffered with a ping.
-
#ping? ⇒ Boolean
whether request has been buffered with a ping.
-
#query ⇒ String
returs the URI query string of the request (when available).
-
#read_timeout ⇒ interval?
the read timeout defined for this request.
-
#request_timeout ⇒ interval?
the request timeout defined for this request.
- #reset_timers(reset_total_request_timers) ⇒ void
-
#scheme ⇒ String
the URI scheme of the request
uri. - #set_timeout_callback(event) {|arg0| ... } ⇒ void
- #started? ⇒ Boolean
-
#total_request_timeout ⇒ Object
the total request timeout defined for this request.
-
#trailers ⇒ Headers
returns an instance of HTTPX::Headers containing the trailer headers.
-
#trailers? ⇒ Boolean
if the request contains trailer headers.
-
#transition(nextstate) ⇒ void
moves on to the
nextstateof the request state machine (when all preconditions are met). -
#write_timeout ⇒ interval?
the write timeout defined for this request.
Methods included from Callbacks
#callbacks, #callbacks_for?, #emit, #on, #once
Methods included from Loggable
#log, #log_exception, log_identifiers, #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. :http2_stream_options :: hash of options to be used to set the HTTP/2 priority by sending an initial PRIORITY frame.
:body, :form, :json and :xml are all mutually exclusive, i.e. only one of them gets picked up.
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 107 108 109 110 111 112 113 |
# File 'lib/httpx/request.rb', line 80 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) @http2_stream_options = params.key?(:http2_stream_options) ? params.delete(:http2_stream_options) : EMPTY_HASH @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 = @callbacks = @informational_status = @on_response_arrived = nil @ping = @started = false @persistent = @options.persistent @active_timeouts = [] end |
Instance Attribute Details
#active_timeouts ⇒ Array[Timers::Timer] (readonly)
Returns the value of attribute active_timeouts.
57 58 59 |
# File 'lib/httpx/request.rb', line 57 def active_timeouts @active_timeouts end |
#body ⇒ Body (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)
50 51 52 |
# File 'lib/httpx/request.rb', line 50 def connection=(value) @connection = value end |
#drain_error ⇒ StandardError? (readonly)
Exception raised during enumerable body writes.
40 41 42 |
# File 'lib/httpx/request.rb', line 40 def drain_error @drain_error end |
#headers ⇒ Headers (readonly)
an HTTPX::Headers object containing the request HTTP headers.
25 26 27 |
# File 'lib/httpx/request.rb', line 25 def headers @headers end |
#http2_stream_options ⇒ { ?dependency: Integer, ?exclusive: bool, ?weight: Integer } (readonly)
when this request is sent via HTTP/2, it'll use this hash of options to set the priority of the respective HTTP/2 frame.
44 45 46 |
# File 'lib/httpx/request.rb', line 44 def @http2_stream_options end |
#on_response_arrived=(value) ⇒ Object (writeonly)
callback triggered when a response (which may not be the final response) was assigned to the request.
53 54 55 |
# File 'lib/httpx/request.rb', line 53 def on_response_arrived=(value) @on_response_arrived = value end |
#options ⇒ Options (readonly)
an HTTPX::Options object containing request options.
34 35 36 |
# File 'lib/httpx/request.rb', line 34 def @options end |
#peer_address ⇒ String, ...
The IP address from the peer server.
47 48 49 |
# File 'lib/httpx/request.rb', line 47 def peer_address @peer_address end |
#persistent=(value) ⇒ Object (writeonly)
Sets the attribute persistent
55 56 57 |
# File 'lib/httpx/request.rb', line 55 def persistent=(value) @persistent = value end |
#response ⇒ response?
the corresponding HTTPX::Response object, when there is one.
37 38 39 |
# File 'lib/httpx/request.rb', line 37 def response @response end |
#state ⇒ Symbol (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 ⇒ http_uri (readonly)
the absolute URI object for this request.
22 23 24 |
# File 'lib/httpx/request.rb', line 22 def uri @uri end |
#verb ⇒ verb (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 ⇒ String
returs the URI authority of the request.
session.build_request("GET", "https://google.com/query").authority #=> "google.com"
session.build_request("GET", "http://internal:3182/a").authority #=> "internal:3182"
241 242 243 |
# File 'lib/httpx/request.rb', line 241 def @uri. end |
#can_buffer? ⇒ Boolean
179 180 181 |
# File 'lib/httpx/request.rb', line 179 def can_buffer? @state != :done end |
#close ⇒ void
This method returns an undefined value.
48 |
# File 'sig/request.rbs', line 48
def close: () -> void
|
#complete!(response = @response) ⇒ void
This method returns an undefined value.
123 124 125 126 |
# File 'lib/httpx/request.rb', line 123 def complete!(response = @response) emit(:complete, response) reset_timers(true) end |
#drain_body ⇒ String?
consumes and returns the next available chunk of request body that can be sent
271 272 273 274 275 276 277 278 279 280 281 282 |
# File 'lib/httpx/request.rb', line 271 def drain_body return if @body.nil? @drainer ||= @body.each @drainer.next.dup rescue StopIteration nil rescue StandardError => e # in case an error occurs while emitting body chunks @drain_error = e nil end |
#emit_response(response) ⇒ void
This method returns an undefined value.
361 362 363 364 365 366 367 |
# File 'lib/httpx/request.rb', line 361 def emit_response(response) emit(:response, response) return unless @on_response_arrived @on_response_arrived.call end |
#empty? ⇒ Boolean
46 |
# File 'sig/request.rbs', line 46
def empty?: () -> bool
|
#expects? ⇒ Boolean
whether the request supports the 100-continue handshake and already processed the 100 response.
338 339 340 |
# File 'lib/httpx/request.rb', line 338 def expects? @headers["expect"] == "100-continue" && @informational_status == 100 && !@response end |
#handle_error(error) ⇒ void
This method returns an undefined value.
351 352 353 354 355 356 357 358 359 |
# File 'lib/httpx/request.rb', line 351 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
116 117 118 119 120 121 |
# File 'lib/httpx/request.rb', line 116 def initialize_dup(orig) super @headers = orig.instance_variable_get(:@headers).dup @body = orig.instance_variable_get(:@body).dup @active_timeouts = orig.instance_variable_get(:@active_timeouts).dup end |
#inspect ⇒ String
simplecov:disable
285 286 287 288 289 290 291 |
# File 'lib/httpx/request.rb', line 285 def inspect "#<#{self.class}:#{object_id} " \ "#{@verb} " \ "#{uri} " \ "@headers=#{@headers} " \ "@body=#{@body}>" end |
#interests ⇒ :r, :w
returns :r or :w, depending on whether the request is waiting for a response or flushing.
173 174 175 176 177 |
# File 'lib/httpx/request.rb', line 173 def interests return :r if @state == :done || @state == :expect :w end |
#merge_headers(h) ⇒ void
This method returns an undefined value.
merges h into the instance of HTTPX::Headers of the request.
188 189 190 191 192 193 |
# File 'lib/httpx/request.rb', line 188 def merge_headers(h) @headers = @headers.merge(h) return unless @headers.key?("range") @headers.delete("accept-encoding") end |
#origin ⇒ String
returs the URI origin of the request.
session.build_request("GET", "https://google.com/query").authority #=> "https://google.com"
session.build_request("GET", "http://internal:3182/a").authority #=> "http://internal:3182"
249 250 251 |
# File 'lib/httpx/request.rb', line 249 def origin @uri.origin end |
#path ⇒ String
returnns the URI path of the request uri.
229 230 231 232 233 234 235 |
# File 'lib/httpx/request.rb', line 229 def path path = uri.path.dup path = +"" if path.nil? path << "/" if path.empty? path << "?#{query}" unless query.empty? path end |
#persistent? ⇒ Boolean
158 159 160 |
# File 'lib/httpx/request.rb', line 158 def persistent? @persistent end |
#ping! ⇒ void
This method returns an undefined value.
marks the request as having been buffered with a ping
134 135 136 |
# File 'lib/httpx/request.rb', line 134 def ping! @ping = true end |
#ping? ⇒ Boolean
whether request has been buffered with a ping
129 130 131 |
# File 'lib/httpx/request.rb', line 129 def ping? @ping end |
#query ⇒ String
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"
259 260 261 262 263 264 265 266 267 268 |
# File 'lib/httpx/request.rb', line 259 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 ⇒ interval?
the read timeout defined for this request.
139 140 141 |
# File 'lib/httpx/request.rb', line 139 def read_timeout @options.timeout[:read_timeout] end |
#request_timeout ⇒ interval?
the request timeout defined for this request.
149 150 151 |
# File 'lib/httpx/request.rb', line 149 def request_timeout @options.timeout[:request_timeout] end |
#reset_timers(reset_total_request_timers) ⇒ void
This method returns an undefined value.
371 372 373 374 375 376 377 378 379 380 |
# File 'lib/httpx/request.rb', line 371 def reset_timers(reset_total_request_timers) timers = @active_timeouts until (timer = timers.shift).nil? next if !reset_total_request_timers && timer.label == :total_request_timeout # cancel active timers. timer.cancel end end |
#scheme ⇒ String
the URI scheme of the request uri.
196 197 198 |
# File 'lib/httpx/request.rb', line 196 def scheme @uri.scheme end |
#set_timeout_callback(event) {|arg0| ... } ⇒ void
This method returns an undefined value.
342 343 344 345 346 347 348 349 |
# File 'lib/httpx/request.rb', line 342 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 |
#started? ⇒ Boolean
183 184 185 |
# File 'lib/httpx/request.rb', line 183 def started? @started end |
#total_request_timeout ⇒ Object
the total request timeout defined for this request.
154 155 156 |
# File 'lib/httpx/request.rb', line 154 def total_request_timeout @options.timeout[:total_request_timeout] end |
#trailers ⇒ Headers
returns an instance of HTTPX::Headers containing the trailer headers
168 169 170 |
# File 'lib/httpx/request.rb', line 168 def trailers @trailers ||= @options.headers_class.new end |
#trailers? ⇒ Boolean
if the request contains trailer headers
163 164 165 |
# File 'lib/httpx/request.rb', line 163 def trailers? defined?(@trailers) end |
#transition(nextstate) ⇒ void
This method returns an undefined value.
moves on to the nextstate of the request state machine (when all preconditions are met)
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
# File 'lib/httpx/request.rb', line 295 def transition(nextstate) case nextstate when :idle @body.rewind @ping = false @response = @drainer = nil # request may be sent to a different connection and will be # reassigned a new set of timers. reset_timers(false) when :headers return unless @state == :idle @started = true 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 ⇒ interval?
the write timeout defined for this request.
144 145 146 |
# File 'lib/httpx/request.rb', line 144 def write_timeout @options.timeout[:write_timeout] end |