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
Included modules
Classes and Modules
Constants
ALLOWED_URI_SCHEMES | = | %w[https http].freeze | ||
USER_AGENT | = | "httpx.rb/#{VERSION}".freeze |
default value used for “user-agent” header, when not overridden. |
Attributes
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 65 def initialize(verb, uri, options, params = EMPTY_HASH) 66 @verb = verb.to_s.upcase 67 @uri = Utils.to_uri(uri) 68 69 @headers = options.headers.dup 70 merge_headers(params.delete(:headers)) if params.key?(:headers) 71 72 @headers["user-agent"] ||= USER_AGENT 73 @headers["accept"] ||= "*/*" 74 75 # forego compression in the Range request case 76 if @headers.key?("range") 77 @headers.delete("accept-encoding") 78 else 79 @headers["accept-encoding"] ||= options.supported_compression_formats 80 end 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 @response = nil 101 @peer_address = nil 102 @persistent = @options.persistent 103 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 186 def authority 187 @uri.authority 188 end
consumes and returns the next available chunk of request body that can be sent
# File lib/httpx/request.rb 216 def drain_body 217 return nil if @body.nil? 218 219 @drainer ||= @body.each 220 chunk = @drainer.next.dup 221 222 emit(:body_chunk, chunk) 223 chunk 224 rescue StopIteration 225 nil 226 rescue StandardError => e 227 @drain_error = e 228 nil 229 end
whether the request supports the 100-continue handshake and already processed the 100 response.
# File lib/httpx/request.rb 279 def expects? 280 @headers["expect"] == "100-continue" && @informational_status == 100 && !@response 281 end
:nocov:
# File lib/httpx/request.rb 232 def inspect 233 "#<HTTPX::Request:#{object_id} " \ 234 "#{@verb} " \ 235 "#{uri} " \ 236 "@headers=#{@headers} " \ 237 "@body=#{@body}>" 238 end
returns :r
or :w
, depending on whether the request is waiting for a response or flushing.
# File lib/httpx/request.rb 135 def interests 136 return :r if @state == :done || @state == :expect 137 138 :w 139 end
merges h
into the instance of HTTPX::Headers
of the request.
# File lib/httpx/request.rb 142 def merge_headers(h) 143 @headers = @headers.merge(h) 144 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 194 def origin 195 @uri.origin 196 end
returnns the URI path of the request uri
.
# File lib/httpx/request.rb 174 def path 175 path = uri.path.dup 176 path = +"" if path.nil? 177 path << "/" if path.empty? 178 path << "?#{query}" unless query.empty? 179 path 180 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 204 def query 205 return @query if defined?(@query) 206 207 query = [] 208 if (q = @query_params) 209 query << Transcoder::Form.encode(q) 210 end 211 query << @uri.query if @uri.query 212 @query = query.join("&") 213 end
the read timeout defined for this requet.
# File lib/httpx/request.rb 106 def read_timeout 107 @options.timeout[:read_timeout] 108 end
the request timeout defined for this requet.
# File lib/httpx/request.rb 116 def request_timeout 117 @options.timeout[:request_timeout] 118 end
sets the response
on this request.
# File lib/httpx/request.rb 152 def response=(response) 153 return unless response 154 155 if response.is_a?(Response) && response.status < 200 156 # deal with informational responses 157 158 if response.status == 100 && @headers.key?("expect") 159 @informational_status = response.status 160 return 161 end 162 163 # 103 Early Hints advertises resources in document to browsers. 164 # not very relevant for an HTTP client, discard. 165 return if response.status >= 103 166 end 167 168 @response = response 169 170 emit(:response_started, response) 171 end
the URI scheme of the request uri
.
# File lib/httpx/request.rb 147 def scheme 148 @uri.scheme 149 end
returns an instance of HTTPX::Headers
containing the trailer headers
# File lib/httpx/request.rb 130 def trailers 131 @trailers ||= @options.headers_class.new 132 end
if the request contains trailer headers
# File lib/httpx/request.rb 125 def trailers? 126 defined?(@trailers) 127 end
moves on to the nextstate
of the request state machine (when all preconditions are met)
# File lib/httpx/request.rb 242 def transition(nextstate) 243 case nextstate 244 when :idle 245 @body.rewind 246 @response = nil 247 @drainer = nil 248 when :headers 249 return unless @state == :idle 250 when :body 251 return unless @state == :headers || 252 @state == :expect 253 254 if @headers.key?("expect") 255 if @informational_status && @informational_status == 100 256 # check for 100 Continue response, and deallocate the var 257 # if @informational_status == 100 258 # @response = nil 259 # end 260 else 261 return if @state == :expect # do not re-set it 262 263 nextstate = :expect 264 end 265 end 266 when :trailers 267 return unless @state == :body 268 when :done 269 return if @state == :expect 270 271 @body.close 272 end 273 @state = nextstate 274 emit(@state, self) 275 nil 276 end
the write timeout defined for this requet.
# File lib/httpx/request.rb 111 def write_timeout 112 @options.timeout[:write_timeout] 113 end