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.

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.

: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
 75 def initialize(verb, uri, options, params = EMPTY_HASH)
 76   @verb    = verb.to_s.upcase
 77   @uri     = Utils.to_uri(uri)
 78 
 79   @headers = options.headers.dup
 80   merge_headers(params.delete(:headers)) if params.key?(:headers)
 81 
 82   @query_params = params.delete(:params) if params.key?(:params)
 83 
 84   @body = options.request_body_class.new(@headers, options, **params)
 85 
 86   @options = @body.options
 87 
 88   if @uri.relative? || @uri.host.nil?
 89     origin = @options.origin
 90     raise(Error, "invalid URI: #{@uri}") unless origin
 91 
 92     base_path = @options.base_path
 93 
 94     @uri = origin.merge("#{base_path}#{@uri}")
 95   end
 96 
 97   raise UnsupportedSchemeError, "#{@uri}: #{@uri.scheme}: unsupported URI scheme" unless ALLOWED_URI_SCHEMES.include?(@uri.scheme)
 98 
 99   @state = :idle
100   @connection = @response =
101     @drainer = @peer_address =
102       @informational_status = @on_response_arrived = nil
103   @ping = false
104   @persistent = @options.persistent
105   @active_timeouts = []
106 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
224 def authority
225   @uri.authority
226 end
can_buffer?()
[show source]
    # File lib/httpx/request.rb
166 def can_buffer?
167   @state != :done
168 end
complete!(response = @response)
[show source]
    # File lib/httpx/request.rb
116 def complete!(response = @response)
117   emit(:complete, response)
118 end
drain_body()

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

[show source]
    # File lib/httpx/request.rb
254 def drain_body
255   return nil if @body.nil?
256 
257   @drainer ||= @body.each
258   chunk = @drainer.next.dup
259 
260   emit(:body_chunk, chunk)
261   chunk
262 rescue StopIteration
263   nil
264 rescue StandardError => e
265   @drain_error = e
266   nil
267 end
emit_response(response)
[show source]
    # File lib/httpx/request.rb
342 def emit_response(response)
343   emit(:response, response)
344 
345   return unless @on_response_arrived
346 
347   @on_response_arrived.call
348 end
expects?()

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

[show source]
    # File lib/httpx/request.rb
319 def expects?
320   @headers["expect"] == "100-continue" && @informational_status == 100 && !@response
321 end
handle_error(error)
[show source]
    # File lib/httpx/request.rb
332 def handle_error(error)
333   if (connection = @connection)
334     connection.on_error(error, self)
335   else
336     response = ErrorResponse.new(self, error)
337     self.response = response
338     emit_response(response)
339   end
340 end
initialize_dup(orig)

dupped initialization

[show source]
    # File lib/httpx/request.rb
109 def initialize_dup(orig)
110   super
111   @uri = orig.instance_variable_get(:@uri).dup
112   @headers = orig.instance_variable_get(:@headers).dup
113   @body = orig.instance_variable_get(:@body).dup
114 end
inspect()

:nocov:

[show source]
    # File lib/httpx/request.rb
270 def inspect
271   "#<#{self.class}:#{object_id} " \
272     "#{@verb} " \
273     "#{uri} " \
274     "@headers=#{@headers} " \
275     "@body=#{@body}>"
276 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
160 def interests
161   return :r if @state == :done || @state == :expect
162 
163   :w
164 end
merge_headers(h)

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

[show source]
    # File lib/httpx/request.rb
171 def merge_headers(h)
172   @headers = @headers.merge(h)
173   return unless @headers.key?("range")
174 
175   @headers.delete("accept-encoding")
176 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
232 def origin
233   @uri.origin
234 end
path()

returnns the URI path of the request uri.

[show source]
    # File lib/httpx/request.rb
212 def path
213   path = uri.path.dup
214   path =  +"" if path.nil?
215   path << "/" if path.empty?
216   path << "?#{query}" unless query.empty?
217   path
218 end
persistent?()
[show source]
    # File lib/httpx/request.rb
145 def persistent?
146   @persistent
147 end
ping!()

marks the request as having been buffered with a ping

[show source]
    # File lib/httpx/request.rb
126 def ping!
127   @ping = true
128 end
ping?()

whether request has been buffered with a ping

[show source]
    # File lib/httpx/request.rb
121 def ping?
122   @ping
123 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
242 def query
243   return @query if defined?(@query)
244 
245   query = []
246   if (q = @query_params) && !q.empty?
247     query << Transcoder::Form.encode(q)
248   end
249   query << @uri.query if @uri.query
250   @query = query.join("&")
251 end
read_timeout()

the read timeout defined for this request.

[show source]
    # File lib/httpx/request.rb
131 def read_timeout
132   @options.timeout[:read_timeout]
133 end
request_timeout()

the request timeout defined for this request.

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

sets the response on this request.

[show source]
    # File lib/httpx/request.rb
184 def response=(response)
185   return unless response
186 
187   case response
188   when Response
189     if response.status < 200
190       # deal with informational responses
191 
192       if response.status == 100 && @headers.key?("expect")
193         @informational_status = response.status
194         return
195       end
196 
197       # 103 Early Hints advertises resources in document to browsers.
198       # not very relevant for an HTTP client, discard.
199       return if response.status >= 103
200 
201     end
202   when ErrorResponse
203     response.error.connection = nil if response.error.respond_to?(:connection=)
204   end
205 
206   @response = response
207 
208   emit(:response_started, response)
209 end
scheme()

the URI scheme of the request uri.

[show source]
    # File lib/httpx/request.rb
179 def scheme
180   @uri.scheme
181 end
set_timeout_callback(event, &callback)
[show source]
    # File lib/httpx/request.rb
323 def set_timeout_callback(event, &callback)
324   clb = once(event, &callback)
325 
326   # reset timeout callbacks when requests get rerouted to a different connection
327   once(:idle) do
328     callbacks(event).delete(clb)
329   end
330 end
trailers()

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

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

if the request contains trailer headers

[show source]
    # File lib/httpx/request.rb
150 def trailers?
151   defined?(@trailers)
152 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
280 def transition(nextstate)
281   case nextstate
282   when :idle
283     @body.rewind
284     @ping = false
285     @response = @drainer = nil
286     @active_timeouts.clear
287   when :headers
288     return unless @state == :idle
289 
290   when :body
291     return unless @state == :headers ||
292                   @state == :expect
293 
294     if @headers.key?("expect")
295       if @informational_status && @informational_status == 100
296         # check for 100 Continue response, and deallocate the var
297         # if @informational_status == 100
298         #   @response = nil
299         # end
300       else
301         return if @state == :expect # do not re-set it
302 
303         nextstate = :expect
304       end
305     end
306   when :trailers
307     return unless @state == :body
308   when :done
309     return if @state == :expect
310 
311   end
312   log(level: 3) { "#{@state}] -> #{nextstate}" }
313   @state = nextstate
314   emit(@state, self)
315   nil
316 end
write_timeout()

the write timeout defined for this request.

[show source]
    # File lib/httpx/request.rb
136 def write_timeout
137   @options.timeout[:write_timeout]
138 end