Class: HTTP::Request::Builder
- Inherits:
-
Object
- Object
- HTTP::Request::Builder
- Defined in:
- lib/http/request/builder.rb,
sig/http.rbs
Overview
Builds HTTP::Request objects from resolved options
Constant Summary collapse
- HTTP_OR_HTTPS_RE =
Pattern matching HTTP or HTTPS URI schemes
%r{\Ahttps?://}i
Instance Method Summary collapse
-
#build(verb, uri) ⇒ HTTP::Request
Build an HTTP request.
-
#initialize(options) ⇒ HTTP::Request::Builder
constructor
Initialize a new Request Builder.
-
#make_form_data(form) ⇒ HTTP::FormData::Multipart, HTTP::FormData::Urlencoded
private
Coerce form data into an HTTP::FormData object.
-
#make_json_body(data, headers) ⇒ String
private
Encode JSON body and set content type header.
-
#make_request_body(headers) ⇒ String, ...
private
Create the request body object to send.
-
#make_request_headers ⇒ HTTP::Headers
private
Creates request headers.
-
#make_request_uri(uri) ⇒ HTTP::URI
private
Merges query params if needed.
-
#merge_query_params!(uri) ⇒ void
private
Merge query parameters into URI.
-
#neutralize_protocol_relative(uri) ⇒ String
private
Neutralize a leading "//" so it resolves as a relative path under base.
-
#resolve_against_base(uri) ⇒ String
private
Resolve a relative URI against the configured base URI.
-
#wrap(request) ⇒ HTTP::Request
Wrap a request through feature middleware.
Constructor Details
#initialize(options) ⇒ HTTP::Request::Builder
Initialize a new Request Builder
32 33 34 |
# File 'lib/http/request/builder.rb', line 32 def initialize() @options = end |
Instance Method Details
#build(verb, uri) ⇒ HTTP::Request
Build an HTTP request
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/http/request/builder.rb', line 45 def build(verb, uri) uri = make_request_uri(uri) headers = make_request_headers body = make_request_body(headers) req = HTTP::Request.new( verb: verb, uri: uri, uri_normalizer: @options.feature(:normalize_uri)&.normalizer, proxy: @options.proxy, headers: headers, body: body ) wrap(req) end |
#make_form_data(form) ⇒ HTTP::FormData::Multipart, HTTP::FormData::Urlencoded
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Coerce form data into an HTTP::FormData object
196 197 198 199 200 201 |
# File 'lib/http/request/builder.rb', line 196 def make_form_data(form) return form if form.is_a? FormData::Multipart return form if form.is_a? FormData::Urlencoded FormData.create(form) end |
#make_json_body(data, headers) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Encode JSON body and set content type header
187 188 189 190 191 |
# File 'lib/http/request/builder.rb', line 187 def make_json_body(data, headers) body = MimeType[:json].encode data headers[Headers::CONTENT_TYPE] ||= "application/json; charset=#{body.encoding.name.downcase}" body end |
#make_request_body(headers) ⇒ String, ...
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Create the request body object to send
172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/http/request/builder.rb', line 172 def make_request_body(headers) if @options.body @options.body elsif @options.form form = make_form_data(@options.form) headers[Headers::CONTENT_TYPE] ||= form.content_type form elsif @options.json make_json_body(@options.json, headers) end end |
#make_request_headers ⇒ HTTP::Headers
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Creates request headers
159 160 161 162 163 164 165 166 |
# File 'lib/http/request/builder.rb', line 159 def make_request_headers headers = @options.headers # Tell the server to keep the conn open headers[Headers::CONNECTION] = @options.persistent? ? Connection::KEEP_ALIVE : Connection::CLOSE headers end |
#make_request_uri(uri) ⇒ HTTP::URI
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Merges query params if needed
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/http/request/builder.rb', line 83 def make_request_uri(uri) uri = neutralize_protocol_relative(uri.to_s) if @options.base_uri? && uri !~ HTTP_OR_HTTPS_RE uri = resolve_against_base(uri) elsif @options.persistent? && uri !~ HTTP_OR_HTTPS_RE uri = "#{@options.persistent}#{uri}" end uri = HTTP::URI.parse uri merge_query_params!(uri) # Some proxies (seen on WEBrick) fail if URL has # empty path (e.g. `http://example.com`) while it's RFC-compliant: # http://tools.ietf.org/html/rfc1738#section-3.1 uri.path = "/" if uri.path.empty? uri end |
#merge_query_params!(uri) ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Merge query parameters into URI
148 149 150 151 152 153 |
# File 'lib/http/request/builder.rb', line 148 def merge_query_params!(uri) return unless @options.params && !@options.params.empty? existing = ::URI.decode_www_form(uri.query || "") uri.query = ::URI.encode_www_form(existing.concat(@options.params.to_a)) end |
#neutralize_protocol_relative(uri) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Neutralize a leading "//" so it resolves as a relative path under base
A "//"-prefixed input is a protocol-relative (network-path) reference per RFC 3986 §4.2 / §5.2. On the base_uri branch it would replace the base authority via URI#join; on the persistent branch naive concatenation produces "scheme://persistent//evil/path" which HTTP::URI.parse normalises into scheme://evil/path. Prepending "./" forces the input to resolve as an ordinary relative path under the configured base.
117 118 119 120 121 122 |
# File 'lib/http/request/builder.rb', line 117 def neutralize_protocol_relative(uri) return uri unless @options.base_uri? || @options.persistent? return uri unless uri.start_with?("//") "./#{uri}" end |
#resolve_against_base(uri) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Resolve a relative URI against the configured base URI
Ensures the base URI path has a trailing slash so that relative paths are appended rather than replacing the last path segment, per the convention described in RFC 3986 Section 5.
133 134 135 136 137 138 139 140 141 142 |
# File 'lib/http/request/builder.rb', line 133 def resolve_against_base(uri) base = @options.base_uri or raise Error, "base_uri is not set" unless base.path.end_with?("/") base = base.dup base.path = "#{base.path}/" end String(base.join(uri)) end |
#wrap(request) ⇒ HTTP::Request
Wrap a request through feature middleware
70 71 72 73 74 |
# File 'lib/http/request/builder.rb', line 70 def wrap(request) @options.features.inject(request) do |req, (_name, feature)| feature.wrap_request(req) end end |