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
- 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
- state
- 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 |
| 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. |
:body, :form, :json and :xml are all mutually exclusive, i.e. only one of them gets picked up.
# 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
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 224 def authority 225 @uri.authority 226 end
# File lib/httpx/request.rb 166 def can_buffer? 167 @state != :done 168 end
# File lib/httpx/request.rb 116 def complete!(response = @response) 117 emit(:complete, response) 118 end
consumes and returns the next available chunk of request body that can be sent
# 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
# 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
whether the request supports the 100-continue handshake and already processed the 100 response.
# File lib/httpx/request.rb 319 def expects? 320 @headers["expect"] == "100-continue" && @informational_status == 100 && !@response 321 end
# 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
dupped initialization
# 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
:nocov:
# 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
returns :r or :w, depending on whether the request is waiting for a response or flushing.
# File lib/httpx/request.rb 160 def interests 161 return :r if @state == :done || @state == :expect 162 163 :w 164 end
merges h into the instance of HTTPX::Headers of the request.
# 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
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 232 def origin 233 @uri.origin 234 end
returnns the URI path of the request uri.
# 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
marks the request as having been buffered with a ping
# File lib/httpx/request.rb 126 def ping! 127 @ping = true 128 end
whether request has been buffered with a ping
# File lib/httpx/request.rb 121 def ping? 122 @ping 123 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 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
the read timeout defined for this request.
# File lib/httpx/request.rb 131 def read_timeout 132 @options.timeout[:read_timeout] 133 end
the request timeout defined for this request.
# File lib/httpx/request.rb 141 def request_timeout 142 @options.timeout[:request_timeout] 143 end
sets the response on this request.
# 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
the URI scheme of the request uri.
# File lib/httpx/request.rb 179 def scheme 180 @uri.scheme 181 end
# 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
returns an instance of HTTPX::Headers containing the trailer headers
# File lib/httpx/request.rb 155 def trailers 156 @trailers ||= @options.headers_class.new 157 end
if the request contains trailer headers
# File lib/httpx/request.rb 150 def trailers? 151 defined?(@trailers) 152 end
moves on to the nextstate of the request state machine (when all preconditions are met)
# 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
the write timeout defined for this request.
# File lib/httpx/request.rb 136 def write_timeout 137 @options.timeout[:write_timeout] 138 end