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) ⇒ Boolean
-
#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) = params.key?(:http2_stream_options) ? params.delete(:http2_stream_options) : EMPTY_HASH @body = .request_body_class.new(@headers, , **params) = @body. if @uri.relative? || @uri.host.nil? origin = .origin raise(Error, "invalid URI: #{@uri}") unless origin base_path = .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 = @complete = false @persistent = .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 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 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"
244 245 246 |
# File 'lib/httpx/request.rb', line 244 def @uri. end |
#can_buffer? ⇒ Boolean
182 183 184 |
# File 'lib/httpx/request.rb', line 182 def can_buffer? @state != :done end |
#close ⇒ void
49 |
# File 'sig/request.rbs', line 49 def close: () -> void |
#complete!(response = @response) ⇒ Boolean
123 124 125 126 127 128 129 |
# File 'lib/httpx/request.rb', line 123 def complete!(response = @response) return false if @complete emit(:complete, response) reset_timers(true) @complete = true end |
#drain_body ⇒ String?
consumes and returns the next available chunk of request body that can be sent
274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'lib/httpx/request.rb', line 274 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
364 365 366 367 368 369 370 |
# File 'lib/httpx/request.rb', line 364 def emit_response(response) emit(:response, response) return unless @on_response_arrived @on_response_arrived.call end |
#empty? ⇒ Boolean
47 |
# File 'sig/request.rbs', line 47 def empty?: () -> bool |
#expects? ⇒ Boolean
whether the request supports the 100-continue handshake and already processed the 100 response.
341 342 343 |
# File 'lib/httpx/request.rb', line 341 def expects? @headers["expect"] == "100-continue" && @informational_status == 100 && !@response end |
#handle_error(error) ⇒ void
354 355 356 357 358 359 360 361 362 |
# File 'lib/httpx/request.rb', line 354 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
288 289 290 291 292 293 294 |
# File 'lib/httpx/request.rb', line 288 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.
176 177 178 179 180 |
# File 'lib/httpx/request.rb', line 176 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.
191 192 193 194 195 196 |
# File 'lib/httpx/request.rb', line 191 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"
252 253 254 |
# File 'lib/httpx/request.rb', line 252 def origin @uri.origin end |
#path ⇒ String
returnns the URI path of the request uri.
232 233 234 235 236 237 238 |
# File 'lib/httpx/request.rb', line 232 def path path = uri.path.dup path = +"" if path.nil? path << "/" if path.empty? path << "?#{query}" unless query.empty? path end |
#persistent? ⇒ Boolean
161 162 163 |
# File 'lib/httpx/request.rb', line 161 def persistent? @persistent end |
#ping! ⇒ void
This method returns an undefined value.
marks the request as having been buffered with a ping
137 138 139 |
# File 'lib/httpx/request.rb', line 137 def ping! @ping = true end |
#ping? ⇒ Boolean
whether request has been buffered with a ping
132 133 134 |
# File 'lib/httpx/request.rb', line 132 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"
262 263 264 265 266 267 268 269 270 271 |
# File 'lib/httpx/request.rb', line 262 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.
142 143 144 |
# File 'lib/httpx/request.rb', line 142 def read_timeout .timeout[:read_timeout] end |
#request_timeout ⇒ interval?
the request timeout defined for this request.
152 153 154 |
# File 'lib/httpx/request.rb', line 152 def request_timeout .timeout[:request_timeout] end |
#reset_timers(reset_total_request_timers) ⇒ void
374 375 376 377 378 379 380 381 382 383 |
# File 'lib/httpx/request.rb', line 374 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.
199 200 201 |
# File 'lib/httpx/request.rb', line 199 def scheme @uri.scheme end |
#set_timeout_callback(event) {|arg0| ... } ⇒ void
This method returns an undefined value.
345 346 347 348 349 350 351 352 |
# File 'lib/httpx/request.rb', line 345 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
186 187 188 |
# File 'lib/httpx/request.rb', line 186 def started? @started end |
#total_request_timeout ⇒ Object
the total request timeout defined for this request.
157 158 159 |
# File 'lib/httpx/request.rb', line 157 def total_request_timeout .timeout[:total_request_timeout] end |
#trailers ⇒ Headers
returns an instance of HTTPX::Headers containing the trailer headers
171 172 173 |
# File 'lib/httpx/request.rb', line 171 def trailers @trailers ||= .headers_class.new end |
#trailers? ⇒ Boolean
if the request contains trailer headers
166 167 168 |
# File 'lib/httpx/request.rb', line 166 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)
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 336 337 338 |
# File 'lib/httpx/request.rb', line 298 def transition(nextstate) case nextstate when :idle @body.rewind @ping = @complete = 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.
147 148 149 |
# File 'lib/httpx/request.rb', line 147 def write_timeout .timeout[:write_timeout] end |