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