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. 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).

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

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

[show source]
    # File lib/httpx/request.rb
237 def drain_body
238   return nil if @body.nil?
239 
240   @drainer ||= @body.each
241   chunk = @drainer.next.dup
242 
243   emit(:body_chunk, chunk)
244   chunk
245 rescue StopIteration
246   nil
247 rescue StandardError => e
248   @drain_error = e
249   nil
250 end
expects?()

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

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

:nocov:

[show source]
    # File lib/httpx/request.rb
253 def inspect
254   "#<#{self.class}:#{object_id} " \
255     "#{@verb} " \
256     "#{uri} " \
257     "@headers=#{@headers} " \
258     "@body=#{@body}>"
259 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
152 def interests
153   return :r if @state == :done || @state == :expect
154 
155   :w
156 end
merge_headers(h)

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

[show source]
    # File lib/httpx/request.rb
163 def merge_headers(h)
164   @headers = @headers.merge(h)
165 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
215 def origin
216   @uri.origin
217 end
path()

returnns the URI path of the request uri.

[show source]
    # File lib/httpx/request.rb
195 def path
196   path = uri.path.dup
197   path =  +"" if path.nil?
198   path << "/" if path.empty?
199   path << "?#{query}" unless query.empty?
200   path
201 end
persistent?()
[show source]
    # File lib/httpx/request.rb
137 def persistent?
138   @persistent
139 end
ping!()

marks the request as having been buffered with a ping

[show source]
    # File lib/httpx/request.rb
118 def ping!
119   @ping = true
120 end
ping?()

whether request has been buffered with a ping

[show source]
    # File lib/httpx/request.rb
113 def ping?
114   @ping
115 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
225 def query
226   return @query if defined?(@query)
227 
228   query = []
229   if (q = @query_params) && !q.empty?
230     query << Transcoder::Form.encode(q)
231   end
232   query << @uri.query if @uri.query
233   @query = query.join("&")
234 end
read_timeout()

the read timeout defined for this request.

[show source]
    # File lib/httpx/request.rb
123 def read_timeout
124   @options.timeout[:read_timeout]
125 end
request_timeout()

the request timeout defined for this request.

[show source]
    # File lib/httpx/request.rb
133 def request_timeout
134   @options.timeout[:request_timeout]
135 end
response=(response)

sets the response on this request.

[show source]
    # File lib/httpx/request.rb
173 def response=(response)
174   return unless response
175 
176   if response.is_a?(Response) && response.status < 200
177     # deal with informational responses
178 
179     if response.status == 100 && @headers.key?("expect")
180       @informational_status = response.status
181       return
182     end
183 
184     # 103 Early Hints advertises resources in document to browsers.
185     # not very relevant for an HTTP client, discard.
186     return if response.status >= 103
187   end
188 
189   @response = response
190 
191   emit(:response_started, response)
192 end
scheme()

the URI scheme of the request uri.

[show source]
    # File lib/httpx/request.rb
168 def scheme
169   @uri.scheme
170 end
set_timeout_callback(event, &callback)
[show source]
    # File lib/httpx/request.rb
306 def set_timeout_callback(event, &callback)
307   clb = once(event, &callback)
308 
309   # reset timeout callbacks when requests get rerouted to a different connection
310   once(:idle) do
311     callbacks(event).delete(clb)
312   end
313 end
trailers()

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

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

if the request contains trailer headers

[show source]
    # File lib/httpx/request.rb
142 def trailers?
143   defined?(@trailers)
144 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
263 def transition(nextstate)
264   case nextstate
265   when :idle
266     @body.rewind
267     @ping = false
268     @response = nil
269     @drainer = nil
270     @active_timeouts.clear
271   when :headers
272     return unless @state == :idle
273 
274   when :body
275     return unless @state == :headers ||
276                   @state == :expect
277 
278     if @headers.key?("expect")
279       if @informational_status && @informational_status == 100
280         # check for 100 Continue response, and deallocate the var
281         # if @informational_status == 100
282         #   @response = nil
283         # end
284       else
285         return if @state == :expect # do not re-set it
286 
287         nextstate = :expect
288       end
289     end
290   when :trailers
291     return unless @state == :body
292   when :done
293     return if @state == :expect
294 
295   end
296   @state = nextstate
297   emit(@state, self)
298   nil
299 end
write_timeout()

the write timeout defined for this request.

[show source]
    # File lib/httpx/request.rb
128 def write_timeout
129   @options.timeout[:write_timeout]
130 end