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

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

[show source]
    # File lib/httpx/request.rb
270 def drain_body
271   return nil if @body.nil?
272 
273   @drainer ||= @body.each
274   chunk = @drainer.next.dup
275 
276   emit(:body_chunk, chunk)
277   chunk
278 rescue StopIteration
279   nil
280 rescue StandardError => e
281   @drain_error = e
282   nil
283 end
emit_response(response)
[show source]
    # File lib/httpx/request.rb
359 def emit_response(response)
360   emit(:response, response)
361 
362   return unless @on_response_arrived
363 
364   @on_response_arrived.call
365 end
expects?()

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

[show source]
    # File lib/httpx/request.rb
336 def expects?
337   @headers["expect"] == "100-continue" && @informational_status == 100 && !@response
338 end
handle_error(error)
[show source]
    # File lib/httpx/request.rb
349 def handle_error(error)
350   if (connection = @connection)
351     connection.on_error(error, self)
352   else
353     response = ErrorResponse.new(self, error)
354     self.response = response
355     emit_response(response)
356   end
357 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()

:nocov:

[show source]
    # File lib/httpx/request.rb
286 def inspect
287   "#<#{self.class}:#{object_id} " \
288     "#{@verb} " \
289     "#{uri} " \
290     "@headers=#{@headers} " \
291     "@body=#{@body}>"
292 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
172 def interests
173   return :r if @state == :done || @state == :expect
174 
175   :w
176 end
merge_headers(h)

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

[show source]
    # File lib/httpx/request.rb
187 def merge_headers(h)
188   @headers = @headers.merge(h)
189   return unless @headers.key?("range")
190 
191   @headers.delete("accept-encoding")
192 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
248 def origin
249   @uri.origin
250 end
path()

returnns the URI path of the request uri.

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

marks the request as having been buffered with a ping

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

whether request has been buffered with a ping

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

the read timeout defined for this request.

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

the request timeout defined for this request.

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

sets the response on this request.

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

the URI scheme of the request uri.

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

the total request timeout defined for this request.

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

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

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

if the request contains trailer headers

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

the write timeout defined for this request.

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