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 = @callbacks =
109                  @informational_status = @on_response_arrived = nil
110   @ping = @started = @complete = 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
244 def authority
245   @uri.authority
246 end
can_buffer?()
[show source]
    # File lib/httpx/request.rb
182 def can_buffer?
183   @state != :done
184 end
complete!(response = @response)
[show source]
    # File lib/httpx/request.rb
123 def complete!(response = @response)
124   return false if @complete
125 
126   emit(:complete, response)
127   reset_timers(true)
128   @complete = true
129 end
drain_body()

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

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

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

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

dupped initialization

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

simplecov:disable

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

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

[show source]
    # File lib/httpx/request.rb
191 def merge_headers(h)
192   @headers = @headers.merge(h)
193   return unless @headers.key?("range")
194 
195   @headers.delete("accept-encoding")
196 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
252 def origin
253   @uri.origin
254 end
path()

returnns the URI path of the request uri.

[show source]
    # File lib/httpx/request.rb
232 def path
233   path = uri.path.dup
234   path =  +"" if path.nil?
235   path << "/" if path.empty?
236   path << "?#{query}" unless query.empty?
237   path
238 end
persistent?()
[show source]
    # File lib/httpx/request.rb
161 def persistent?
162   @persistent
163 end
ping!()

marks the request as having been buffered with a ping

[show source]
    # File lib/httpx/request.rb
137 def ping!
138   @ping = true
139 end
ping?()

whether request has been buffered with a ping

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

the read timeout defined for this request.

[show source]
    # File lib/httpx/request.rb
142 def read_timeout
143   @options.timeout[:read_timeout]
144 end
request_timeout()

the request timeout defined for this request.

[show source]
    # File lib/httpx/request.rb
152 def request_timeout
153   @options.timeout[:request_timeout]
154 end
response=(response)

sets the response on this request.

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

the URI scheme of the request uri.

[show source]
    # File lib/httpx/request.rb
199 def scheme
200   @uri.scheme
201 end
set_timeout_callback(event, &callback)
[show source]
    # File lib/httpx/request.rb
345 def set_timeout_callback(event, &callback)
346   clb = once(event, &callback)
347 
348   # reset timeout callbacks when requests get rerouted to a different connection
349   once(:idle) do
350     callbacks(event).delete(clb)
351   end
352 end
started?()
[show source]
    # File lib/httpx/request.rb
186 def started?
187   @started
188 end
total_request_timeout()

the total request timeout defined for this request.

[show source]
    # File lib/httpx/request.rb
157 def total_request_timeout
158   @options.timeout[:total_request_timeout]
159 end
trailers()

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

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

if the request contains trailer headers

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

the write timeout defined for this request.

[show source]
    # File lib/httpx/request.rb
147 def write_timeout
148   @options.timeout[:write_timeout]
149 end