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  
USER_AGENT = "httpx.rb/#{VERSION}".freeze  

default value used for “user-agent” header, when not overridden.

Attributes

active_timeouts [R]
body [R]

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

context [R]

the execution context (fiber) this request was sent on.

drain_error [R]

Exception raised during enumerable body writes.

headers [R]

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

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
 74 def initialize(verb, uri, options, params = EMPTY_HASH)
 75   @verb    = verb.to_s.upcase
 76   @uri     = Utils.to_uri(uri)
 77 
 78   @headers = options.headers.dup
 79   merge_headers(params.delete(:headers)) if params.key?(:headers)
 80 
 81   @headers["user-agent"] ||= USER_AGENT
 82   @headers["accept"]     ||= "*/*"
 83 
 84   # forego compression in the Range request case
 85   if @headers.key?("range")
 86     @headers.delete("accept-encoding")
 87   else
 88     @headers["accept-encoding"] ||= options.supported_compression_formats
 89   end
 90 
 91   @query_params = params.delete(:params) if params.key?(:params)
 92 
 93   @body = options.request_body_class.new(@headers, options, **params)
 94 
 95   @options = @body.options
 96 
 97   if @uri.relative? || @uri.host.nil?
 98     origin = @options.origin
 99     raise(Error, "invalid URI: #{@uri}") unless origin
100 
101     base_path = @options.base_path
102 
103     @uri = origin.merge("#{base_path}#{@uri}")
104   end
105 
106   raise UnsupportedSchemeError, "#{@uri}: #{@uri.scheme}: unsupported URI scheme" unless ALLOWED_URI_SCHEMES.include?(@uri.scheme)
107 
108   @state = :idle
109   @response = @peer_address = @context = nil
110   @ping = 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
225 def authority
226   @uri.authority
227 end
can_buffer?()
[show source]
    # File lib/httpx/request.rb
176 def can_buffer?
177   @state != :done
178 end
complete!(response = @response)
[show source]
    # File lib/httpx/request.rb
125 def complete!(response = @response)
126   @context = nil
127   emit(:complete, response)
128 end
current_context?()

checks whether the current execution context is the one where the request was created.

[show source]
    # File lib/httpx/request.rb
121 def current_context?
122   @context == Fiber.current
123 end
drain_body()

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

[show source]
    # File lib/httpx/request.rb
255 def drain_body
256   return nil if @body.nil?
257 
258   @drainer ||= @body.each
259   chunk = @drainer.next.dup
260 
261   emit(:body_chunk, chunk)
262   chunk
263 rescue StopIteration
264   nil
265 rescue StandardError => e
266   @drain_error = e
267   nil
268 end
expects?()

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

[show source]
    # File lib/httpx/request.rb
321 def expects?
322   @headers["expect"] == "100-continue" && @informational_status == 100 && !@response
323 end
inspect()

:nocov:

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

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

[show source]
    # File lib/httpx/request.rb
181 def merge_headers(h)
182   @headers = @headers.merge(h)
183 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
233 def origin
234   @uri.origin
235 end
path()

returnns the URI path of the request uri.

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

marks the request as having been buffered with a ping

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

whether request has been buffered with a ping

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

the read timeout defined for this request.

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

the request timeout defined for this request.

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

sets the response on this request.

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

the URI scheme of the request uri.

[show source]
    # File lib/httpx/request.rb
186 def scheme
187   @uri.scheme
188 end
set_context!()

sets the execution context for this request. the default is the current fiber.

[show source]
    # File lib/httpx/request.rb
116 def set_context!
117   @context ||= Fiber.current # rubocop:disable Naming/MemoizedInstanceVariableName
118 end
set_timeout_callback(event, &callback)
[show source]
    # File lib/httpx/request.rb
325 def set_timeout_callback(event, &callback)
326   clb = once(event, &callback)
327 
328   # reset timeout callbacks when requests get rerouted to a different connection
329   once(:idle) do
330     callbacks(event).delete(clb)
331   end
332 end
trailers()

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

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

if the request contains trailer headers

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

the write timeout defined for this request.

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