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!
- drain_body
- drain_error
- expects?
- 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 |
| 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 69 def initialize(verb, uri, options, params = EMPTY_HASH) 70 @verb = verb.to_s.upcase 71 @uri = Utils.to_uri(uri) 72 73 @headers = options.headers.dup 74 merge_headers(params.delete(:headers)) if params.key?(:headers) 75 76 @query_params = params.delete(:params) if params.key?(:params) 77 78 @body = options.request_body_class.new(@headers, options, **params) 79 80 @options = @body.options 81 82 if @uri.relative? || @uri.host.nil? 83 origin = @options.origin 84 raise(Error, "invalid URI: #{@uri}") unless origin 85 86 base_path = @options.base_path 87 88 @uri = origin.merge("#{base_path}#{@uri}") 89 end 90 91 raise UnsupportedSchemeError, "#{@uri}: #{@uri.scheme}: unsupported URI scheme" unless ALLOWED_URI_SCHEMES.include?(@uri.scheme) 92 93 @state = :idle 94 @response = @peer_address = @informational_status = nil 95 @ping = false 96 @persistent = @options.persistent 97 @active_timeouts = [] 98 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 216 def authority 217 @uri.authority 218 end
# File lib/httpx/request.rb 158 def can_buffer? 159 @state != :done 160 end
# File lib/httpx/request.rb 108 def complete!(response = @response) 109 emit(:complete, response) 110 end
consumes and returns the next available chunk of request body that can be sent
# File lib/httpx/request.rb 246 def drain_body 247 return nil if @body.nil? 248 249 @drainer ||= @body.each 250 chunk = @drainer.next.dup 251 252 emit(:body_chunk, chunk) 253 chunk 254 rescue StopIteration 255 nil 256 rescue StandardError => e 257 @drain_error = e 258 nil 259 end
whether the request supports the 100-continue handshake and already processed the 100 response.
# File lib/httpx/request.rb 312 def expects? 313 @headers["expect"] == "100-continue" && @informational_status == 100 && !@response 314 end
dupped initialization
# File lib/httpx/request.rb 101 def initialize_dup(orig) 102 super 103 @uri = orig.instance_variable_get(:@uri).dup 104 @headers = orig.instance_variable_get(:@headers).dup 105 @body = orig.instance_variable_get(:@body).dup 106 end
:nocov:
# File lib/httpx/request.rb 262 def inspect 263 "#<#{self.class}:#{object_id} " \ 264 "#{@verb} " \ 265 "#{uri} " \ 266 "@headers=#{@headers} " \ 267 "@body=#{@body}>" 268 end
returns :r or :w, depending on whether the request is waiting for a response or flushing.
# File lib/httpx/request.rb 152 def interests 153 return :r if @state == :done || @state == :expect 154 155 :w 156 end
merges h into the instance of HTTPX::Headers of the request.
# File lib/httpx/request.rb 163 def merge_headers(h) 164 @headers = @headers.merge(h) 165 return unless @headers.key?("range") 166 167 @headers.delete("accept-encoding") 168 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 224 def origin 225 @uri.origin 226 end
returnns the URI path of the request uri.
# File lib/httpx/request.rb 204 def path 205 path = uri.path.dup 206 path = +"" if path.nil? 207 path << "/" if path.empty? 208 path << "?#{query}" unless query.empty? 209 path 210 end
marks the request as having been buffered with a ping
# File lib/httpx/request.rb 118 def ping! 119 @ping = true 120 end
whether request has been buffered with a ping
# File lib/httpx/request.rb 113 def ping? 114 @ping 115 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 234 def query 235 return @query if defined?(@query) 236 237 query = [] 238 if (q = @query_params) && !q.empty? 239 query << Transcoder::Form.encode(q) 240 end 241 query << @uri.query if @uri.query 242 @query = query.join("&") 243 end
the read timeout defined for this request.
# File lib/httpx/request.rb 123 def read_timeout 124 @options.timeout[:read_timeout] 125 end
the request timeout defined for this request.
# File lib/httpx/request.rb 133 def request_timeout 134 @options.timeout[:request_timeout] 135 end
sets the response on this request.
# File lib/httpx/request.rb 176 def response=(response) 177 return unless response 178 179 case response 180 when Response 181 if response.status < 200 182 # deal with informational responses 183 184 if response.status == 100 && @headers.key?("expect") 185 @informational_status = response.status 186 return 187 end 188 189 # 103 Early Hints advertises resources in document to browsers. 190 # not very relevant for an HTTP client, discard. 191 return if response.status >= 103 192 193 end 194 when ErrorResponse 195 response.error.connection = nil if response.error.respond_to?(:connection=) 196 end 197 198 @response = response 199 200 emit(:response_started, response) 201 end
the URI scheme of the request uri.
# File lib/httpx/request.rb 171 def scheme 172 @uri.scheme 173 end
# File lib/httpx/request.rb 316 def set_timeout_callback(event, &callback) 317 clb = once(event, &callback) 318 319 # reset timeout callbacks when requests get rerouted to a different connection 320 once(:idle) do 321 callbacks(event).delete(clb) 322 end 323 end
returns an instance of HTTPX::Headers containing the trailer headers
# File lib/httpx/request.rb 147 def trailers 148 @trailers ||= @options.headers_class.new 149 end
if the request contains trailer headers
# File lib/httpx/request.rb 142 def trailers? 143 defined?(@trailers) 144 end
moves on to the nextstate of the request state machine (when all preconditions are met)
# File lib/httpx/request.rb 272 def transition(nextstate) 273 case nextstate 274 when :idle 275 @body.rewind 276 @ping = false 277 @response = nil 278 @drainer = nil 279 @active_timeouts.clear 280 when :headers 281 return unless @state == :idle 282 283 when :body 284 return unless @state == :headers || 285 @state == :expect 286 287 if @headers.key?("expect") 288 if @informational_status && @informational_status == 100 289 # check for 100 Continue response, and deallocate the var 290 # if @informational_status == 100 291 # @response = nil 292 # end 293 else 294 return if @state == :expect # do not re-set it 295 296 nextstate = :expect 297 end 298 end 299 when :trailers 300 return unless @state == :body 301 when :done 302 return if @state == :expect 303 304 end 305 log(level: 3) { "#{@state}] -> #{nextstate}" } 306 @state = nextstate 307 emit(@state, self) 308 nil 309 end
the write timeout defined for this request.
# File lib/httpx/request.rb 128 def write_timeout 129 @options.timeout[:write_timeout] 130 end