http 5.2.0 → 6.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +110 -13
- data/http.gemspec +38 -35
- data/lib/http/base64.rb +22 -0
- data/lib/http/chainable/helpers.rb +62 -0
- data/lib/http/chainable/verbs.rb +136 -0
- data/lib/http/chainable.rb +249 -129
- data/lib/http/client.rb +158 -127
- data/lib/http/connection/internals.rb +141 -0
- data/lib/http/connection.rb +128 -97
- data/lib/http/content_type.rb +61 -6
- data/lib/http/errors.rb +41 -1
- data/lib/http/feature.rb +67 -6
- data/lib/http/features/auto_deflate.rb +124 -17
- data/lib/http/features/auto_inflate.rb +38 -15
- data/lib/http/features/caching/entry.rb +178 -0
- data/lib/http/features/caching/in_memory_store.rb +63 -0
- data/lib/http/features/caching.rb +216 -0
- data/lib/http/features/digest_auth.rb +234 -0
- data/lib/http/features/instrumentation.rb +97 -17
- data/lib/http/features/logging.rb +183 -5
- data/lib/http/features/normalize_uri.rb +17 -0
- data/lib/http/features/raise_error.rb +37 -0
- data/lib/http/form_data/composite_io.rb +106 -0
- data/lib/http/form_data/file.rb +95 -0
- data/lib/http/form_data/multipart/param.rb +62 -0
- data/lib/http/form_data/multipart.rb +106 -0
- data/lib/http/form_data/part.rb +52 -0
- data/lib/http/form_data/readable.rb +58 -0
- data/lib/http/form_data/urlencoded.rb +175 -0
- data/lib/http/form_data/version.rb +8 -0
- data/lib/http/form_data.rb +102 -0
- data/lib/http/headers/known.rb +3 -0
- data/lib/http/headers/normalizer.rb +50 -0
- data/lib/http/headers.rb +185 -92
- data/lib/http/mime_type/adapter.rb +24 -9
- data/lib/http/mime_type/json.rb +19 -4
- data/lib/http/mime_type.rb +21 -3
- data/lib/http/options/definitions.rb +189 -0
- data/lib/http/options.rb +172 -125
- data/lib/http/redirector.rb +80 -75
- data/lib/http/request/body.rb +87 -6
- data/lib/http/request/builder.rb +184 -0
- data/lib/http/request/proxy.rb +83 -0
- data/lib/http/request/writer.rb +78 -17
- data/lib/http/request.rb +216 -99
- data/lib/http/response/body.rb +103 -18
- data/lib/http/response/inflater.rb +35 -7
- data/lib/http/response/parser.rb +98 -4
- data/lib/http/response/status/reasons.rb +2 -4
- data/lib/http/response/status.rb +141 -31
- data/lib/http/response.rb +219 -61
- data/lib/http/retriable/delay_calculator.rb +91 -0
- data/lib/http/retriable/errors.rb +35 -0
- data/lib/http/retriable/performer.rb +197 -0
- data/lib/http/session.rb +280 -0
- data/lib/http/timeout/global.rb +147 -34
- data/lib/http/timeout/null.rb +155 -9
- data/lib/http/timeout/per_operation.rb +139 -18
- data/lib/http/uri/normalizer.rb +82 -0
- data/lib/http/uri/parsing.rb +182 -0
- data/lib/http/uri.rb +289 -124
- data/lib/http/version.rb +2 -1
- data/lib/http.rb +11 -1
- data/sig/http.rbs +1619 -0
- metadata +42 -175
- data/.github/workflows/ci.yml +0 -67
- data/.gitignore +0 -15
- data/.rspec +0 -1
- data/.rubocop/layout.yml +0 -8
- data/.rubocop/metrics.yml +0 -4
- data/.rubocop/style.yml +0 -32
- data/.rubocop.yml +0 -11
- data/.rubocop_todo.yml +0 -206
- data/.yardopts +0 -2
- data/CHANGELOG.md +0 -41
- data/CHANGES_OLD.md +0 -1002
- data/CONTRIBUTING.md +0 -26
- data/Gemfile +0 -50
- data/Guardfile +0 -18
- data/Rakefile +0 -64
- data/SECURITY.md +0 -17
- data/lib/http/headers/mixin.rb +0 -34
- data/logo.png +0 -0
- data/spec/lib/http/client_spec.rb +0 -556
- data/spec/lib/http/connection_spec.rb +0 -88
- data/spec/lib/http/content_type_spec.rb +0 -47
- data/spec/lib/http/features/auto_deflate_spec.rb +0 -77
- data/spec/lib/http/features/auto_inflate_spec.rb +0 -86
- data/spec/lib/http/features/instrumentation_spec.rb +0 -81
- data/spec/lib/http/features/logging_spec.rb +0 -65
- data/spec/lib/http/headers/mixin_spec.rb +0 -36
- data/spec/lib/http/headers_spec.rb +0 -527
- data/spec/lib/http/options/body_spec.rb +0 -15
- data/spec/lib/http/options/features_spec.rb +0 -33
- data/spec/lib/http/options/form_spec.rb +0 -15
- data/spec/lib/http/options/headers_spec.rb +0 -24
- data/spec/lib/http/options/json_spec.rb +0 -15
- data/spec/lib/http/options/merge_spec.rb +0 -68
- data/spec/lib/http/options/new_spec.rb +0 -30
- data/spec/lib/http/options/proxy_spec.rb +0 -20
- data/spec/lib/http/options_spec.rb +0 -13
- data/spec/lib/http/redirector_spec.rb +0 -529
- data/spec/lib/http/request/body_spec.rb +0 -211
- data/spec/lib/http/request/writer_spec.rb +0 -121
- data/spec/lib/http/request_spec.rb +0 -234
- data/spec/lib/http/response/body_spec.rb +0 -85
- data/spec/lib/http/response/parser_spec.rb +0 -74
- data/spec/lib/http/response/status_spec.rb +0 -253
- data/spec/lib/http/response_spec.rb +0 -262
- data/spec/lib/http/uri/normalizer_spec.rb +0 -95
- data/spec/lib/http/uri_spec.rb +0 -71
- data/spec/lib/http_spec.rb +0 -506
- data/spec/regression_specs.rb +0 -24
- data/spec/spec_helper.rb +0 -88
- data/spec/support/black_hole.rb +0 -13
- data/spec/support/capture_warning.rb +0 -10
- data/spec/support/dummy_server/servlet.rb +0 -190
- data/spec/support/dummy_server.rb +0 -43
- data/spec/support/fakeio.rb +0 -21
- data/spec/support/fuubar.rb +0 -21
- data/spec/support/http_handling_shared.rb +0 -190
- data/spec/support/proxy_server.rb +0 -39
- data/spec/support/servers/config.rb +0 -11
- data/spec/support/servers/runner.rb +0 -19
- data/spec/support/simplecov.rb +0 -19
- data/spec/support/ssl_helper.rb +0 -104
data/lib/http/chainable.rb
CHANGED
|
@@ -1,125 +1,117 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "base64"
|
|
4
|
-
|
|
3
|
+
require "http/base64"
|
|
4
|
+
require "http/chainable/helpers"
|
|
5
|
+
require "http/chainable/verbs"
|
|
5
6
|
require "http/headers"
|
|
6
7
|
|
|
7
8
|
module HTTP
|
|
9
|
+
# HTTP verb methods and client configuration DSL
|
|
8
10
|
module Chainable
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
# @option options [Hash]
|
|
12
|
-
def head(uri, options = {})
|
|
13
|
-
request :head, uri, options
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# Get a resource
|
|
17
|
-
# @param uri
|
|
18
|
-
# @option options [Hash]
|
|
19
|
-
def get(uri, options = {})
|
|
20
|
-
request :get, uri, options
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
# Post to a resource
|
|
24
|
-
# @param uri
|
|
25
|
-
# @option options [Hash]
|
|
26
|
-
def post(uri, options = {})
|
|
27
|
-
request :post, uri, options
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# Put to a resource
|
|
31
|
-
# @param uri
|
|
32
|
-
# @option options [Hash]
|
|
33
|
-
def put(uri, options = {})
|
|
34
|
-
request :put, uri, options
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# Delete a resource
|
|
38
|
-
# @param uri
|
|
39
|
-
# @option options [Hash]
|
|
40
|
-
def delete(uri, options = {})
|
|
41
|
-
request :delete, uri, options
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# Echo the request back to the client
|
|
45
|
-
# @param uri
|
|
46
|
-
# @option options [Hash]
|
|
47
|
-
def trace(uri, options = {})
|
|
48
|
-
request :trace, uri, options
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# Return the methods supported on the given URI
|
|
52
|
-
# @param uri
|
|
53
|
-
# @option options [Hash]
|
|
54
|
-
def options(uri, options = {})
|
|
55
|
-
request :options, uri, options
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
# Convert to a transparent TCP/IP tunnel
|
|
59
|
-
# @param uri
|
|
60
|
-
# @option options [Hash]
|
|
61
|
-
def connect(uri, options = {})
|
|
62
|
-
request :connect, uri, options
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
# Apply partial modifications to a resource
|
|
66
|
-
# @param uri
|
|
67
|
-
# @option options [Hash]
|
|
68
|
-
def patch(uri, options = {})
|
|
69
|
-
request :patch, uri, options
|
|
70
|
-
end
|
|
11
|
+
include HTTP::Base64
|
|
12
|
+
include Verbs
|
|
71
13
|
|
|
72
14
|
# Make an HTTP request with the given verb
|
|
15
|
+
#
|
|
16
|
+
# @example Without a block
|
|
17
|
+
# HTTP.request(:get, "http://example.com")
|
|
18
|
+
#
|
|
19
|
+
# @example With a block (auto-closes connection)
|
|
20
|
+
# HTTP.request(:get, "http://example.com") { |res| res.status }
|
|
21
|
+
#
|
|
73
22
|
# @param (see Client#request)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
23
|
+
# @yieldparam response [HTTP::Response] the response
|
|
24
|
+
# @return [HTTP::Response, Object] the response, or block return value
|
|
25
|
+
# @api public
|
|
26
|
+
def request(verb, uri, **, &block)
|
|
27
|
+
client = make_client(default_options)
|
|
28
|
+
response = client.request(verb, uri, **)
|
|
29
|
+
return response unless block
|
|
30
|
+
|
|
31
|
+
yield response
|
|
32
|
+
ensure
|
|
33
|
+
client&.close if block
|
|
82
34
|
end
|
|
83
35
|
|
|
36
|
+
# Set timeout on the request
|
|
37
|
+
#
|
|
38
|
+
# @example
|
|
39
|
+
# HTTP.timeout(10).get("http://example.com")
|
|
40
|
+
#
|
|
84
41
|
# @overload timeout(options = {})
|
|
85
42
|
# Adds per operation timeouts to the request
|
|
86
43
|
# @param [Hash] options
|
|
87
44
|
# @option options [Float] :read Read timeout
|
|
88
45
|
# @option options [Float] :write Write timeout
|
|
89
46
|
# @option options [Float] :connect Connect timeout
|
|
47
|
+
# @option options [Float] :global Global timeout (combines with per-operation)
|
|
90
48
|
# @overload timeout(global_timeout)
|
|
91
49
|
# Adds a global timeout to the full request
|
|
92
50
|
# @param [Numeric] global_timeout
|
|
51
|
+
# @return [HTTP::Session]
|
|
52
|
+
# @api public
|
|
93
53
|
def timeout(options)
|
|
94
54
|
klass, options = case options
|
|
95
|
-
when Numeric then [HTTP::Timeout::Global, {:
|
|
96
|
-
when Hash then
|
|
55
|
+
when Numeric then [HTTP::Timeout::Global, { global_timeout: options }]
|
|
56
|
+
when Hash then resolve_timeout_hash(options)
|
|
97
57
|
when :null then [HTTP::Timeout::Null, {}]
|
|
98
|
-
else raise ArgumentError,
|
|
99
|
-
|
|
58
|
+
else raise ArgumentError,
|
|
59
|
+
"Use `.timeout(:null)`, " \
|
|
60
|
+
"`.timeout(global_timeout_in_seconds)` or " \
|
|
61
|
+
"`.timeout(connect: x, write: y, read: z)`."
|
|
100
62
|
end
|
|
101
63
|
|
|
102
|
-
%i[global read write connect].each do |k|
|
|
103
|
-
next unless options.key? k
|
|
104
|
-
|
|
105
|
-
options["#{k}_timeout".to_sym] = options.delete k
|
|
106
|
-
end
|
|
107
|
-
|
|
108
64
|
branch default_options.merge(
|
|
109
|
-
:
|
|
110
|
-
:
|
|
65
|
+
timeout_class: klass,
|
|
66
|
+
timeout_options: options
|
|
111
67
|
)
|
|
112
68
|
end
|
|
113
69
|
|
|
114
|
-
#
|
|
70
|
+
# Set a base URI for resolving relative request paths
|
|
71
|
+
#
|
|
72
|
+
# The first call must use an absolute URI that includes a scheme
|
|
73
|
+
# (e.g. "https://example.com"). Once a base URI is set, subsequent chained
|
|
74
|
+
# calls may use relative paths that are resolved against the existing base.
|
|
75
|
+
#
|
|
76
|
+
# @example
|
|
77
|
+
# HTTP.base_uri("https://example.com/api/v1").get("users")
|
|
78
|
+
#
|
|
79
|
+
# @example Chaining base URIs
|
|
80
|
+
# HTTP.base_uri("https://example.com").base_uri("api/v1").get("users")
|
|
81
|
+
#
|
|
82
|
+
# @param [String, HTTP::URI] uri the base URI (absolute with scheme when
|
|
83
|
+
# no base is set; may be relative when chaining)
|
|
84
|
+
# @return [HTTP::Session]
|
|
85
|
+
# @raise [HTTP::Error] if no base URI is set and the given URI has no scheme
|
|
86
|
+
# @api public
|
|
87
|
+
def base_uri(uri)
|
|
88
|
+
branch default_options.with_base_uri(uri)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Open a persistent connection to a host
|
|
92
|
+
#
|
|
93
|
+
# Returns an {HTTP::Session} that pools persistent {HTTP::Client}
|
|
94
|
+
# instances by origin. This allows connection reuse within the same
|
|
95
|
+
# origin and transparent cross-origin redirect handling.
|
|
96
|
+
#
|
|
97
|
+
# When no host is given, the origin is derived from the configured base URI.
|
|
98
|
+
#
|
|
99
|
+
# @example
|
|
100
|
+
# HTTP.persistent("http://example.com").get("/")
|
|
101
|
+
#
|
|
102
|
+
# @example Derive host from base URI
|
|
103
|
+
# HTTP.base_uri("https://example.com/api").persistent.get("users")
|
|
104
|
+
#
|
|
105
|
+
# @overload persistent(host = nil, timeout: 5)
|
|
115
106
|
# Flags as persistent
|
|
116
|
-
# @param [String] host
|
|
107
|
+
# @param [String, nil] host connection origin (derived from base URI when nil)
|
|
117
108
|
# @option [Integer] timeout Keep alive timeout
|
|
109
|
+
# @raise [ArgumentError] if host is nil and no base URI is set
|
|
118
110
|
# @raise [Request::Error] if Host is invalid
|
|
119
|
-
# @return [HTTP::
|
|
120
|
-
# @overload persistent(host, timeout: 5, &block)
|
|
121
|
-
# Executes given block with persistent
|
|
122
|
-
#
|
|
111
|
+
# @return [HTTP::Session] Persistent session
|
|
112
|
+
# @overload persistent(host = nil, timeout: 5, &block)
|
|
113
|
+
# Executes given block with persistent session and automatically closes
|
|
114
|
+
# all connections at the end of execution.
|
|
123
115
|
#
|
|
124
116
|
# @example
|
|
125
117
|
#
|
|
@@ -139,29 +131,34 @@ module HTTP
|
|
|
139
131
|
# end
|
|
140
132
|
#
|
|
141
133
|
#
|
|
142
|
-
# @yieldparam [HTTP::
|
|
134
|
+
# @yieldparam [HTTP::Session] session Persistent session
|
|
143
135
|
# @return [Object] result of last expression in the block
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
136
|
+
# @return [HTTP::Session, Object]
|
|
137
|
+
# @api public
|
|
138
|
+
def persistent(host = nil, timeout: 5)
|
|
139
|
+
host ||= default_options.base_uri&.origin
|
|
140
|
+
raise ArgumentError, "host is required for persistent connections" unless host
|
|
148
141
|
|
|
149
|
-
|
|
142
|
+
options = default_options.merge(keep_alive_timeout: timeout).with_persistent(host)
|
|
143
|
+
session = branch(options)
|
|
144
|
+
return session unless block_given?
|
|
145
|
+
|
|
146
|
+
yield session
|
|
150
147
|
ensure
|
|
151
|
-
|
|
148
|
+
session&.close if block_given?
|
|
152
149
|
end
|
|
153
150
|
|
|
154
151
|
# Make a request through an HTTP proxy
|
|
152
|
+
#
|
|
153
|
+
# @example
|
|
154
|
+
# HTTP.via("proxy.example.com", 8080).get("http://example.com")
|
|
155
|
+
#
|
|
155
156
|
# @param [Array] proxy
|
|
156
157
|
# @raise [Request::Error] if HTTP proxy is invalid
|
|
158
|
+
# @return [HTTP::Session]
|
|
159
|
+
# @api public
|
|
157
160
|
def via(*proxy)
|
|
158
|
-
proxy_hash =
|
|
159
|
-
proxy_hash[:proxy_address] = proxy[0] if proxy[0].is_a?(String)
|
|
160
|
-
proxy_hash[:proxy_port] = proxy[1] if proxy[1].is_a?(Integer)
|
|
161
|
-
proxy_hash[:proxy_username] = proxy[2] if proxy[2].is_a?(String)
|
|
162
|
-
proxy_hash[:proxy_password] = proxy[3] if proxy[3].is_a?(String)
|
|
163
|
-
proxy_hash[:proxy_headers] = proxy[2] if proxy[2].is_a?(Hash)
|
|
164
|
-
proxy_hash[:proxy_headers] = proxy[4] if proxy[4].is_a?(Hash)
|
|
161
|
+
proxy_hash = build_proxy_hash(proxy)
|
|
165
162
|
|
|
166
163
|
raise(RequestError, "invalid HTTP proxy: #{proxy_hash}") unless (2..5).cover?(proxy_hash.keys.size)
|
|
167
164
|
|
|
@@ -169,88 +166,211 @@ module HTTP
|
|
|
169
166
|
end
|
|
170
167
|
alias through via
|
|
171
168
|
|
|
172
|
-
# Make client follow redirects
|
|
173
|
-
#
|
|
174
|
-
# @
|
|
169
|
+
# Make client follow redirects
|
|
170
|
+
#
|
|
171
|
+
# @example
|
|
172
|
+
# HTTP.follow.get("http://example.com")
|
|
173
|
+
#
|
|
174
|
+
# @param [Boolean] strict (true) redirector hops policy
|
|
175
|
+
# @param [Integer] max_hops (5) maximum allowed redirect hops
|
|
176
|
+
# @param [#call, nil] on_redirect optional redirect callback
|
|
177
|
+
# @return [HTTP::Session]
|
|
175
178
|
# @see Redirector#initialize
|
|
176
|
-
|
|
177
|
-
|
|
179
|
+
# @api public
|
|
180
|
+
def follow(strict: nil, max_hops: nil, on_redirect: nil)
|
|
181
|
+
opts = { strict: strict, max_hops: max_hops, on_redirect: on_redirect }.compact
|
|
182
|
+
branch default_options.with_follow(opts)
|
|
178
183
|
end
|
|
179
184
|
|
|
180
185
|
# Make a request with the given headers
|
|
181
|
-
#
|
|
186
|
+
#
|
|
187
|
+
# @example
|
|
188
|
+
# HTTP.headers("Accept" => "text/plain").get("http://example.com")
|
|
189
|
+
#
|
|
190
|
+
# @param [Hash] headers request headers
|
|
191
|
+
# @return [HTTP::Session]
|
|
192
|
+
# @api public
|
|
182
193
|
def headers(headers)
|
|
183
194
|
branch default_options.with_headers(headers)
|
|
184
195
|
end
|
|
185
196
|
|
|
186
197
|
# Make a request with the given cookies
|
|
198
|
+
#
|
|
199
|
+
# @example
|
|
200
|
+
# HTTP.cookies(session: "abc123").get("http://example.com")
|
|
201
|
+
#
|
|
202
|
+
# @param [Hash, Array<HTTP::Cookie>] cookies cookies to set
|
|
203
|
+
# @return [HTTP::Session]
|
|
204
|
+
# @api public
|
|
187
205
|
def cookies(cookies)
|
|
188
|
-
|
|
206
|
+
value = cookies.map do |entry|
|
|
207
|
+
case entry
|
|
208
|
+
when HTTP::Cookie then entry.cookie_value
|
|
209
|
+
else
|
|
210
|
+
name, val = entry
|
|
211
|
+
HTTP::Cookie.new(name.to_s, val.to_s).cookie_value
|
|
212
|
+
end
|
|
213
|
+
end.join("; ")
|
|
214
|
+
|
|
215
|
+
headers(Headers::COOKIE => value)
|
|
189
216
|
end
|
|
190
217
|
|
|
191
218
|
# Force a specific encoding for response body
|
|
219
|
+
#
|
|
220
|
+
# @example
|
|
221
|
+
# HTTP.encoding("UTF-8").get("http://example.com")
|
|
222
|
+
#
|
|
223
|
+
# @param [String, Encoding] encoding encoding to use
|
|
224
|
+
# @return [HTTP::Session]
|
|
225
|
+
# @api public
|
|
192
226
|
def encoding(encoding)
|
|
193
227
|
branch default_options.with_encoding(encoding)
|
|
194
228
|
end
|
|
195
229
|
|
|
196
230
|
# Accept the given MIME type(s)
|
|
197
|
-
#
|
|
231
|
+
#
|
|
232
|
+
# @example
|
|
233
|
+
# HTTP.accept("application/json").get("http://example.com")
|
|
234
|
+
#
|
|
235
|
+
# @param [String, Symbol] type MIME type to accept
|
|
236
|
+
# @return [HTTP::Session]
|
|
237
|
+
# @api public
|
|
198
238
|
def accept(type)
|
|
199
239
|
headers Headers::ACCEPT => MimeType.normalize(type)
|
|
200
240
|
end
|
|
201
241
|
|
|
202
242
|
# Make a request with the given Authorization header
|
|
243
|
+
#
|
|
244
|
+
# @example
|
|
245
|
+
# HTTP.auth("Bearer token123").get("http://example.com")
|
|
246
|
+
#
|
|
203
247
|
# @param [#to_s] value Authorization header value
|
|
248
|
+
# @return [HTTP::Session]
|
|
249
|
+
# @api public
|
|
204
250
|
def auth(value)
|
|
205
251
|
headers Headers::AUTHORIZATION => value.to_s
|
|
206
252
|
end
|
|
207
253
|
|
|
208
254
|
# Make a request with the given Basic authorization header
|
|
255
|
+
#
|
|
256
|
+
# @example
|
|
257
|
+
# HTTP.basic_auth(user: "user", pass: "pass").get("http://example.com")
|
|
258
|
+
#
|
|
209
259
|
# @see http://tools.ietf.org/html/rfc2617
|
|
210
|
-
# @param [#
|
|
211
|
-
# @
|
|
212
|
-
# @
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
260
|
+
# @param [#to_s] user
|
|
261
|
+
# @param [#to_s] pass
|
|
262
|
+
# @return [HTTP::Session]
|
|
263
|
+
# @api public
|
|
264
|
+
def basic_auth(user:, pass:)
|
|
265
|
+
auth("Basic #{encode64("#{user}:#{pass}")}")
|
|
266
|
+
end
|
|
217
267
|
|
|
218
|
-
|
|
268
|
+
# Enable HTTP Digest authentication
|
|
269
|
+
#
|
|
270
|
+
# Automatically handles 401 Digest challenges by computing the digest
|
|
271
|
+
# response and retrying the request with proper credentials.
|
|
272
|
+
#
|
|
273
|
+
# @example
|
|
274
|
+
# HTTP.digest_auth(user: "admin", pass: "secret").get("http://example.com")
|
|
275
|
+
#
|
|
276
|
+
# @see https://datatracker.ietf.org/doc/html/rfc2617
|
|
277
|
+
# @param [#to_s] user
|
|
278
|
+
# @param [#to_s] pass
|
|
279
|
+
# @return [HTTP::Session]
|
|
280
|
+
# @api public
|
|
281
|
+
def digest_auth(user:, pass:)
|
|
282
|
+
use(digest_auth: { user: user, pass: pass })
|
|
219
283
|
end
|
|
220
284
|
|
|
221
285
|
# Get options for HTTP
|
|
286
|
+
#
|
|
287
|
+
# @example
|
|
288
|
+
# HTTP.default_options
|
|
289
|
+
#
|
|
222
290
|
# @return [HTTP::Options]
|
|
291
|
+
# @api public
|
|
223
292
|
def default_options
|
|
224
293
|
@default_options ||= HTTP::Options.new
|
|
225
294
|
end
|
|
226
295
|
|
|
227
296
|
# Set options for HTTP
|
|
228
|
-
#
|
|
297
|
+
#
|
|
298
|
+
# @example
|
|
299
|
+
# HTTP.default_options = { response: :object }
|
|
300
|
+
#
|
|
301
|
+
# @param [Hash, HTTP::Options] opts options to set
|
|
229
302
|
# @return [HTTP::Options]
|
|
303
|
+
# @api public
|
|
230
304
|
def default_options=(opts)
|
|
231
305
|
@default_options = HTTP::Options.new(opts)
|
|
232
306
|
end
|
|
233
307
|
|
|
234
308
|
# Set TCP_NODELAY on the socket
|
|
309
|
+
#
|
|
310
|
+
# @example
|
|
311
|
+
# HTTP.nodelay.get("http://example.com")
|
|
312
|
+
#
|
|
313
|
+
# @return [HTTP::Session]
|
|
314
|
+
# @api public
|
|
235
315
|
def nodelay
|
|
236
316
|
branch default_options.with_nodelay(true)
|
|
237
317
|
end
|
|
238
318
|
|
|
239
|
-
#
|
|
240
|
-
#
|
|
241
|
-
#
|
|
242
|
-
#
|
|
243
|
-
#
|
|
244
|
-
#
|
|
245
|
-
# @
|
|
319
|
+
# Enable one or more features
|
|
320
|
+
#
|
|
321
|
+
# @example
|
|
322
|
+
# HTTP.use(:auto_inflate).get("http://example.com")
|
|
323
|
+
#
|
|
324
|
+
# @param [Array<Symbol, Hash>] features features to enable
|
|
325
|
+
# @return [HTTP::Session]
|
|
326
|
+
# @api public
|
|
246
327
|
def use(*features)
|
|
247
328
|
branch default_options.with_features(features)
|
|
248
329
|
end
|
|
249
330
|
|
|
331
|
+
# Return a retriable session that retries on failure
|
|
332
|
+
#
|
|
333
|
+
# @example Usage
|
|
334
|
+
#
|
|
335
|
+
# # Retry max 5 times with randomly growing delay between retries
|
|
336
|
+
# HTTP.retriable.get(url)
|
|
337
|
+
#
|
|
338
|
+
# # Retry max 3 times with randomly growing delay between retries
|
|
339
|
+
# HTTP.retriable(tries: 3).get(url)
|
|
340
|
+
#
|
|
341
|
+
# # Retry max 3 times with 1 sec delay between retries
|
|
342
|
+
# HTTP.retriable(tries: 3, delay: proc { 1 }).get(url)
|
|
343
|
+
#
|
|
344
|
+
# # Retry max 3 times with geometrically progressed delay between retries
|
|
345
|
+
# HTTP.retriable(tries: 3, delay: proc { |i| 1 + i*i }).get(url)
|
|
346
|
+
#
|
|
347
|
+
# @param (see Performer#initialize)
|
|
348
|
+
# @return [HTTP::Session]
|
|
349
|
+
# @api public
|
|
350
|
+
def retriable(tries: nil, delay: nil, exceptions: nil, retry_statuses: nil,
|
|
351
|
+
on_retry: nil, max_delay: nil, should_retry: nil)
|
|
352
|
+
opts = { tries: tries, delay: delay, exceptions: exceptions, retry_statuses: retry_statuses,
|
|
353
|
+
on_retry: on_retry, max_delay: max_delay, should_retry: should_retry }.compact
|
|
354
|
+
branch default_options.with_retriable(opts.empty? || opts)
|
|
355
|
+
end
|
|
356
|
+
|
|
250
357
|
private
|
|
251
358
|
|
|
252
|
-
#
|
|
359
|
+
# Create a new session with the given options
|
|
360
|
+
#
|
|
361
|
+
# @param [HTTP::Options] options options for the session
|
|
362
|
+
# @return [HTTP::Session]
|
|
363
|
+
# @api private
|
|
253
364
|
def branch(options)
|
|
365
|
+
HTTP::Session.new(options)
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
# Create a new client for executing a request
|
|
369
|
+
#
|
|
370
|
+
# @param [HTTP::Options] options options for the client
|
|
371
|
+
# @return [HTTP::Client]
|
|
372
|
+
# @api private
|
|
373
|
+
def make_client(options)
|
|
254
374
|
HTTP::Client.new(options)
|
|
255
375
|
end
|
|
256
376
|
end
|