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