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
- expects?
- handle_error
- headers
- initialize_dup
- inspect
- interests
- merge_headers
- 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 |
| 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 72 def initialize(verb, uri, options, params = EMPTY_HASH) 73 @verb = verb.to_s.upcase 74 @uri = Utils.to_uri(uri) 75 76 @headers = options.headers.dup 77 merge_headers(params.delete(:headers)) if params.key?(:headers) 78 79 @query_params = params.delete(:params) if params.key?(:params) 80 81 @body = options.request_body_class.new(@headers, options, **params) 82 83 @options = @body.options 84 85 if @uri.relative? || @uri.host.nil? 86 origin = @options.origin 87 raise(Error, "invalid URI: #{@uri}") unless origin 88 89 base_path = @options.base_path 90 91 @uri = origin.merge("#{base_path}#{@uri}") 92 end 93 94 raise UnsupportedSchemeError, "#{@uri}: #{@uri.scheme}: unsupported URI scheme" unless ALLOWED_URI_SCHEMES.include?(@uri.scheme) 95 96 @state = :idle 97 @connection = @response = @drainer = @peer_address = @informational_status = nil 98 @ping = false 99 @persistent = @options.persistent 100 @active_timeouts = [] 101 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 219 def authority 220 @uri.authority 221 end
# File lib/httpx/request.rb 161 def can_buffer? 162 @state != :done 163 end
# File lib/httpx/request.rb 111 def complete!(response = @response) 112 emit(:complete, response) 113 end
consumes and returns the next available chunk of request body that can be sent
# File lib/httpx/request.rb 249 def drain_body 250 return nil if @body.nil? 251 252 @drainer ||= @body.each 253 chunk = @drainer.next.dup 254 255 emit(:body_chunk, chunk) 256 chunk 257 rescue StopIteration 258 nil 259 rescue StandardError => e 260 @drain_error = e 261 nil 262 end
whether the request supports the 100-continue handshake and already processed the 100 response.
# File lib/httpx/request.rb 314 def expects? 315 @headers["expect"] == "100-continue" && @informational_status == 100 && !@response 316 end
# File lib/httpx/request.rb 327 def handle_error(error) 328 if (connection = @connection) 329 connection.on_error(error, self) 330 else 331 response = ErrorResponse.new(self, error) 332 self.response = response 333 emit(:response, response) 334 end 335 end
dupped initialization
# File lib/httpx/request.rb 104 def initialize_dup(orig) 105 super 106 @uri = orig.instance_variable_get(:@uri).dup 107 @headers = orig.instance_variable_get(:@headers).dup 108 @body = orig.instance_variable_get(:@body).dup 109 end
:nocov:
# File lib/httpx/request.rb 265 def inspect 266 "#<#{self.class}:#{object_id} " \ 267 "#{@verb} " \ 268 "#{uri} " \ 269 "@headers=#{@headers} " \ 270 "@body=#{@body}>" 271 end
returns :r or :w, depending on whether the request is waiting for a response or flushing.
# File lib/httpx/request.rb 155 def interests 156 return :r if @state == :done || @state == :expect 157 158 :w 159 end
merges h into the instance of HTTPX::Headers of the request.
# File lib/httpx/request.rb 166 def merge_headers(h) 167 @headers = @headers.merge(h) 168 return unless @headers.key?("range") 169 170 @headers.delete("accept-encoding") 171 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 227 def origin 228 @uri.origin 229 end
returnns the URI path of the request uri.
# File lib/httpx/request.rb 207 def path 208 path = uri.path.dup 209 path = +"" if path.nil? 210 path << "/" if path.empty? 211 path << "?#{query}" unless query.empty? 212 path 213 end
marks the request as having been buffered with a ping
# File lib/httpx/request.rb 121 def ping! 122 @ping = true 123 end
whether request has been buffered with a ping
# File lib/httpx/request.rb 116 def ping? 117 @ping 118 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 237 def query 238 return @query if defined?(@query) 239 240 query = [] 241 if (q = @query_params) && !q.empty? 242 query << Transcoder::Form.encode(q) 243 end 244 query << @uri.query if @uri.query 245 @query = query.join("&") 246 end
the read timeout defined for this request.
# File lib/httpx/request.rb 126 def read_timeout 127 @options.timeout[:read_timeout] 128 end
the request timeout defined for this request.
# File lib/httpx/request.rb 136 def request_timeout 137 @options.timeout[:request_timeout] 138 end
sets the response on this request.
# File lib/httpx/request.rb 179 def response=(response) 180 return unless response 181 182 case response 183 when Response 184 if response.status < 200 185 # deal with informational responses 186 187 if response.status == 100 && @headers.key?("expect") 188 @informational_status = response.status 189 return 190 end 191 192 # 103 Early Hints advertises resources in document to browsers. 193 # not very relevant for an HTTP client, discard. 194 return if response.status >= 103 195 196 end 197 when ErrorResponse 198 response.error.connection = nil if response.error.respond_to?(:connection=) 199 end 200 201 @response = response 202 203 emit(:response_started, response) 204 end
the URI scheme of the request uri.
# File lib/httpx/request.rb 174 def scheme 175 @uri.scheme 176 end
# File lib/httpx/request.rb 318 def set_timeout_callback(event, &callback) 319 clb = once(event, &callback) 320 321 # reset timeout callbacks when requests get rerouted to a different connection 322 once(:idle) do 323 callbacks(event).delete(clb) 324 end 325 end
returns an instance of HTTPX::Headers containing the trailer headers
# File lib/httpx/request.rb 150 def trailers 151 @trailers ||= @options.headers_class.new 152 end
if the request contains trailer headers
# File lib/httpx/request.rb 145 def trailers? 146 defined?(@trailers) 147 end
moves on to the nextstate of the request state machine (when all preconditions are met)
# File lib/httpx/request.rb 275 def transition(nextstate) 276 case nextstate 277 when :idle 278 @body.rewind 279 @ping = false 280 @response = @drainer = nil 281 @active_timeouts.clear 282 when :headers 283 return unless @state == :idle 284 285 when :body 286 return unless @state == :headers || 287 @state == :expect 288 289 if @headers.key?("expect") 290 if @informational_status && @informational_status == 100 291 # check for 100 Continue response, and deallocate the var 292 # if @informational_status == 100 293 # @response = nil 294 # end 295 else 296 return if @state == :expect # do not re-set it 297 298 nextstate = :expect 299 end 300 end 301 when :trailers 302 return unless @state == :body 303 when :done 304 return if @state == :expect 305 306 end 307 log(level: 3) { "#{@state}] -> #{nextstate}" } 308 @state = nextstate 309 emit(@state, self) 310 nil 311 end
the write timeout defined for this request.
# File lib/httpx/request.rb 131 def write_timeout 132 @options.timeout[:write_timeout] 133 end