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.
Methods
Public Class
Public Instance
- active_timeouts
- authority
- body
- can_buffer?
- complete!
- connection
- drain_body
- drain_error
- emit_response
- expects?
- handle_error
- headers
- http2_stream_options
- initialize_dup
- inspect
- interests
- merge_headers
- on_response_arrived
- options
- origin
- path
- peer_address
- persistent
- persistent?
- ping!
- ping?
- query
- read_timeout
- request_timeout
- response
- response=
- scheme
- set_timeout_callback
- started?
- state
- total_request_timeout
- trailers
- trailers?
- transition
- uri
- verb
- write_timeout
Classes and Modules
Constants
| ALLOWED_URI_SCHEMES | = | %w[https http].freeze |
Attributes
| active_timeouts | [R] | |
| body | [R] |
an |
| 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 |
| 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 |
| peer_address | [RW] |
The IP address from the peer server. |
| persistent | [W] | |
| response | [R] |
the corresponding |
| 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
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.
# 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
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"
# File lib/httpx/request.rb 241 def authority 242 @uri.authority 243 end
# File lib/httpx/request.rb 179 def can_buffer? 180 @state != :done 181 end
# File lib/httpx/request.rb 123 def complete!(response = @response) 124 emit(:complete, response) 125 reset_timers(true) 126 end
consumes and returns the next available chunk of request body that can be sent
# File lib/httpx/request.rb 271 def drain_body 272 return if @body.nil? 273 274 @drainer ||= @body.each 275 @drainer.next.dup 276 rescue StopIteration 277 nil 278 rescue StandardError => e 279 # in case an error occurs while emitting body chunks 280 @drain_error = e 281 nil 282 end
# File lib/httpx/request.rb 361 def emit_response(response) 362 emit(:response, response) 363 364 return unless @on_response_arrived 365 366 @on_response_arrived.call 367 end
whether the request supports the 100-continue handshake and already processed the 100 response.
# File lib/httpx/request.rb 338 def expects? 339 @headers["expect"] == "100-continue" && @informational_status == 100 && !@response 340 end
# File lib/httpx/request.rb 351 def handle_error(error) 352 if (connection = @connection) 353 connection.on_error(error, self) 354 else 355 response = ErrorResponse.new(self, error) 356 self.response = response 357 emit_response(response) 358 end 359 end
dupped initialization
# 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
simplecov:disable
# File lib/httpx/request.rb 285 def inspect 286 "#<#{self.class}:#{object_id} " \ 287 "#{@verb} " \ 288 "#{uri} " \ 289 "@headers=#{@headers} " \ 290 "@body=#{@body}>" 291 end
returns :r or :w, depending on whether the request is waiting for a response or flushing.
# File lib/httpx/request.rb 173 def interests 174 return :r if @state == :done || @state == :expect 175 176 :w 177 end
merges h into the instance of HTTPX::Headers of the request.
# File lib/httpx/request.rb 188 def merge_headers(h) 189 @headers = @headers.merge(h) 190 return unless @headers.key?("range") 191 192 @headers.delete("accept-encoding") 193 end
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"
# File lib/httpx/request.rb 249 def origin 250 @uri.origin 251 end
returnns the URI path of the request uri.
# File lib/httpx/request.rb 229 def path 230 path = uri.path.dup 231 path = +"" if path.nil? 232 path << "/" if path.empty? 233 path << "?#{query}" unless query.empty? 234 path 235 end
marks the request as having been buffered with a ping
# File lib/httpx/request.rb 134 def ping! 135 @ping = true 136 end
whether request has been buffered with a ping
# File lib/httpx/request.rb 129 def ping? 130 @ping 131 end
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"
# File lib/httpx/request.rb 259 def query 260 return @query if defined?(@query) 261 262 query = [] 263 if (q = @query_params) && !q.empty? 264 query << Transcoder::Form.encode(q) 265 end 266 query << @uri.query if @uri.query 267 @query = query.join("&") 268 end
the read timeout defined for this request.
# File lib/httpx/request.rb 139 def read_timeout 140 @options.timeout[:read_timeout] 141 end
the request timeout defined for this request.
# File lib/httpx/request.rb 149 def request_timeout 150 @options.timeout[:request_timeout] 151 end
sets the response on this request.
# File lib/httpx/request.rb 201 def response=(response) 202 return unless response 203 204 case response 205 when Response 206 if response.status < 200 207 # deal with informational responses 208 209 if response.status == 100 && @headers.key?("expect") 210 @informational_status = response.status 211 return 212 end 213 214 # 103 Early Hints advertises resources in document to browsers. 215 # not very relevant for an HTTP client, discard. 216 return if response.status >= 103 217 218 end 219 when ErrorResponse 220 response.error.connection = nil if response.error.respond_to?(:connection=) 221 end 222 223 @response = response 224 225 emit(:response_started, response) 226 end
the URI scheme of the request uri.
# File lib/httpx/request.rb 196 def scheme 197 @uri.scheme 198 end
# File lib/httpx/request.rb 342 def set_timeout_callback(event, &callback) 343 clb = once(event, &callback) 344 345 # reset timeout callbacks when requests get rerouted to a different connection 346 once(:idle) do 347 callbacks(event).delete(clb) 348 end 349 end
the total request timeout defined for this request.
# File lib/httpx/request.rb 154 def total_request_timeout 155 @options.timeout[:total_request_timeout] 156 end
returns an instance of HTTPX::Headers containing the trailer headers
# File lib/httpx/request.rb 168 def trailers 169 @trailers ||= @options.headers_class.new 170 end
if the request contains trailer headers
# File lib/httpx/request.rb 163 def trailers? 164 defined?(@trailers) 165 end
moves on to the nextstate of the request state machine (when all preconditions are met)
# File lib/httpx/request.rb 295 def transition(nextstate) 296 case nextstate 297 when :idle 298 @body.rewind 299 @ping = false 300 @response = @drainer = nil 301 302 # request may be sent to a different connection and will be 303 # reassigned a new set of timers. 304 reset_timers(false) 305 when :headers 306 return unless @state == :idle 307 308 @started = true 309 when :body 310 return unless @state == :headers || 311 @state == :expect 312 313 if @headers.key?("expect") 314 if @informational_status && @informational_status == 100 315 # check for 100 Continue response, and deallocate the var 316 # if @informational_status == 100 317 # @response = nil 318 # end 319 else 320 return if @state == :expect # do not re-set it 321 322 nextstate = :expect 323 end 324 end 325 when :trailers 326 return unless @state == :body 327 when :done 328 return if @state == :expect 329 330 end 331 log(level: 3) { "#{@state} -> #{nextstate}" } 332 @state = nextstate 333 emit(@state, self) 334 nil 335 end
the write timeout defined for this request.
# File lib/httpx/request.rb 144 def write_timeout 145 @options.timeout[:write_timeout] 146 end