class HTTPX::Request

  1. lib/httpx/request.rb
  2. lib/httpx/request/body.rb
  3. show all
Superclass: Object

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.

Included modules

  1. Loggable
  2. Callbacks

Classes and Modules

  1. HTTPX::Request::Body

Constants

ALLOWED_URI_SCHEMES = %w[https http].freeze  

Attributes

active_timeouts [R]
body [R]

an HTTPX::Request::Body object containing the request body payload (or nil, whenn there is none).

connection [W]

the connection the request is currently being sent to (none if before or after transaction)

drain_error [R]

Exception raised during enumerable body writes.

headers [R]

an HTTPX::Headers object containing the request HTTP headers.

http2_stream_options [R]

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 [W]

callback triggered when a response (which may not be the final response) was assigned to the request.

options [R]

an HTTPX::Options object containing request options.

peer_address [RW]

The IP address from the peer server.

persistent [W]
response [R]

the corresponding HTTPX::Response object, when there is one.

state [R]

a symbol describing which frame is currently being flushed.

uri [R]

the absolute URI object for this request.

verb [R]

the upcased string HTTP verb for this request.

Public Class methods

new(verb, uri, options, params = EMPTY_HASH)

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.

[show source]
    # File lib/httpx/request.rb
 80 def initialize(verb, uri, options, params = EMPTY_HASH)
 81   @verb    = verb.to_s.upcase
 82   @uri     = Utils.to_uri(uri)
 83 
 84   @headers = options.headers.dup
 85   merge_headers(params.delete(:headers)) if params.key?(:headers)
 86 
 87   @query_params = params.delete(:params) if params.key?(:params)
 88 
 89   @http2_stream_options = params.key?(:http2_stream_options) ? params.delete(:http2_stream_options) : EMPTY_HASH
 90 
 91   @body = options.request_body_class.new(@headers, options, **params)
 92 
 93   @options = @body.options
 94 
 95   if @uri.relative? || @uri.host.nil?
 96     origin = @options.origin
 97     raise(Error, "invalid URI: #{@uri}") unless origin
 98 
 99     base_path = @options.base_path
100 
101     @uri = origin.merge("#{base_path}#{@uri}")
102   end
103 
104   raise UnsupportedSchemeError, "#{@uri}: #{@uri.scheme}: unsupported URI scheme" unless ALLOWED_URI_SCHEMES.include?(@uri.scheme)
105 
106   @state = :idle
107   @connection = @response =
108     @drainer = @peer_address =
109       @informational_status = @on_response_arrived = nil
110   @ping = @started = false
111   @persistent = @options.persistent
112   @active_timeouts = []
113 end

Public Instance methods

authority()

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"
[show source]
    # File lib/httpx/request.rb
241 def authority
242   @uri.authority
243 end
can_buffer?()
[show source]
    # File lib/httpx/request.rb
179 def can_buffer?
180   @state != :done
181 end
complete!(response = @response)
[show source]
    # File lib/httpx/request.rb
123 def complete!(response = @response)
124   emit(:complete, response)
125   reset_timers(true)
126 end
drain_body()

consumes and returns the next available chunk of request body that can be sent

[show source]
    # File lib/httpx/request.rb
271 def drain_body
272   return if @body.nil?
273 
274   @drainer ||= @body.each
275   @drainer.next.dup
276 rescue StopIteration
277   nil
278 rescue StandardError => e
279   # in case an error occurs while emitting body chunks
280   @drain_error = e
281   nil
282 end
emit_response(response)
[show source]
    # File lib/httpx/request.rb
361 def emit_response(response)
362   emit(:response, response)
363 
364   return unless @on_response_arrived
365 
366   @on_response_arrived.call
367 end
expects?()

whether the request supports the 100-continue handshake and already processed the 100 response.

[show source]
    # File lib/httpx/request.rb
338 def expects?
339   @headers["expect"] == "100-continue" && @informational_status == 100 && !@response
340 end
handle_error(error)
[show source]
    # File lib/httpx/request.rb
351 def handle_error(error)
352   if (connection = @connection)
353     connection.on_error(error, self)
354   else
355     response = ErrorResponse.new(self, error)
356     self.response = response
357     emit_response(response)
358   end
359 end
initialize_dup(orig)

dupped initialization

[show source]
    # File lib/httpx/request.rb
116 def initialize_dup(orig)
117   super
118   @uri = orig.instance_variable_get(:@uri).dup
119   @headers = orig.instance_variable_get(:@headers).dup
120   @body = orig.instance_variable_get(:@body).dup
121 end
inspect()

simplecov:disable

[show source]
    # File lib/httpx/request.rb
285 def inspect
286   "#<#{self.class}:#{object_id} " \
287     "#{@verb} " \
288     "#{uri} " \
289     "@headers=#{@headers} " \
290     "@body=#{@body}>"
291 end
interests()

returns :r or :w, depending on whether the request is waiting for a response or flushing.

[show source]
    # File lib/httpx/request.rb
173 def interests
174   return :r if @state == :done || @state == :expect
175 
176   :w
177 end
merge_headers(h)

merges h into the instance of HTTPX::Headers of the request.

[show source]
    # File lib/httpx/request.rb
188 def merge_headers(h)
189   @headers = @headers.merge(h)
190   return unless @headers.key?("range")
191 
192   @headers.delete("accept-encoding")
193 end
origin()

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"
[show source]
    # File lib/httpx/request.rb
249 def origin
250   @uri.origin
251 end
path()

returnns the URI path of the request uri.

[show source]
    # File lib/httpx/request.rb
229 def path
230   path = uri.path.dup
231   path =  +"" if path.nil?
232   path << "/" if path.empty?
233   path << "?#{query}" unless query.empty?
234   path
235 end
persistent?()
[show source]
    # File lib/httpx/request.rb
158 def persistent?
159   @persistent
160 end
ping!()

marks the request as having been buffered with a ping

[show source]
    # File lib/httpx/request.rb
134 def ping!
135   @ping = true
136 end
ping?()

whether request has been buffered with a ping

[show source]
    # File lib/httpx/request.rb
129 def ping?
130   @ping
131 end
query()

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"
[show source]
    # File lib/httpx/request.rb
259 def query
260   return @query if defined?(@query)
261 
262   query = []
263   if (q = @query_params) && !q.empty?
264     query << Transcoder::Form.encode(q)
265   end
266   query << @uri.query if @uri.query
267   @query = query.join("&")
268 end
read_timeout()

the read timeout defined for this request.

[show source]
    # File lib/httpx/request.rb
139 def read_timeout
140   @options.timeout[:read_timeout]
141 end
request_timeout()

the request timeout defined for this request.

[show source]
    # File lib/httpx/request.rb
149 def request_timeout
150   @options.timeout[:request_timeout]
151 end
response=(response)

sets the response on this request.

[show source]
    # File lib/httpx/request.rb
201 def response=(response)
202   return unless response
203 
204   case response
205   when Response
206     if response.status < 200
207       # deal with informational responses
208 
209       if response.status == 100 && @headers.key?("expect")
210         @informational_status = response.status
211         return
212       end
213 
214       # 103 Early Hints advertises resources in document to browsers.
215       # not very relevant for an HTTP client, discard.
216       return if response.status >= 103
217 
218     end
219   when ErrorResponse
220     response.error.connection = nil if response.error.respond_to?(:connection=)
221   end
222 
223   @response = response
224 
225   emit(:response_started, response)
226 end
scheme()

the URI scheme of the request uri.

[show source]
    # File lib/httpx/request.rb
196 def scheme
197   @uri.scheme
198 end
set_timeout_callback(event, &callback)
[show source]
    # File lib/httpx/request.rb
342 def set_timeout_callback(event, &callback)
343   clb = once(event, &callback)
344 
345   # reset timeout callbacks when requests get rerouted to a different connection
346   once(:idle) do
347     callbacks(event).delete(clb)
348   end
349 end
started?()
[show source]
    # File lib/httpx/request.rb
183 def started?
184   @started
185 end
total_request_timeout()

the total request timeout defined for this request.

[show source]
    # File lib/httpx/request.rb
154 def total_request_timeout
155   @options.timeout[:total_request_timeout]
156 end
trailers()

returns an instance of HTTPX::Headers containing the trailer headers

[show source]
    # File lib/httpx/request.rb
168 def trailers
169   @trailers ||= @options.headers_class.new
170 end
trailers?()

if the request contains trailer headers

[show source]
    # File lib/httpx/request.rb
163 def trailers?
164   defined?(@trailers)
165 end
transition(nextstate)

moves on to the nextstate of the request state machine (when all preconditions are met)

[show source]
    # File lib/httpx/request.rb
295 def transition(nextstate)
296   case nextstate
297   when :idle
298     @body.rewind
299     @ping = false
300     @response = @drainer = nil
301 
302     # request may be sent to a different connection and will be
303     # reassigned a new set of timers.
304     reset_timers(false)
305   when :headers
306     return unless @state == :idle
307 
308     @started = true
309   when :body
310     return unless @state == :headers ||
311                   @state == :expect
312 
313     if @headers.key?("expect")
314       if @informational_status && @informational_status == 100
315         # check for 100 Continue response, and deallocate the var
316         # if @informational_status == 100
317         #   @response = nil
318         # end
319       else
320         return if @state == :expect # do not re-set it
321 
322         nextstate = :expect
323       end
324     end
325   when :trailers
326     return unless @state == :body
327   when :done
328     return if @state == :expect
329 
330   end
331   log(level: 3) { "#{@state} -> #{nextstate}" }
332   @state = nextstate
333   emit(@state, self)
334   nil
335 end
write_timeout()

the write timeout defined for this request.

[show source]
    # File lib/httpx/request.rb
144 def write_timeout
145   @options.timeout[:write_timeout]
146 end