http 6.0.0-java

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.
Files changed (142) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +267 -0
  3. data/CONTRIBUTING.md +26 -0
  4. data/LICENSE.txt +20 -0
  5. data/README.md +263 -0
  6. data/SECURITY.md +17 -0
  7. data/UPGRADING.md +491 -0
  8. data/http.gemspec +48 -0
  9. data/lib/http/base64.rb +22 -0
  10. data/lib/http/chainable/helpers.rb +62 -0
  11. data/lib/http/chainable/verbs.rb +136 -0
  12. data/lib/http/chainable.rb +377 -0
  13. data/lib/http/client.rb +230 -0
  14. data/lib/http/connection/internals.rb +141 -0
  15. data/lib/http/connection.rb +265 -0
  16. data/lib/http/content_type.rb +89 -0
  17. data/lib/http/errors.rb +67 -0
  18. data/lib/http/feature.rb +86 -0
  19. data/lib/http/features/auto_deflate.rb +230 -0
  20. data/lib/http/features/auto_inflate.rb +64 -0
  21. data/lib/http/features/caching/entry.rb +178 -0
  22. data/lib/http/features/caching/in_memory_store.rb +63 -0
  23. data/lib/http/features/caching.rb +216 -0
  24. data/lib/http/features/digest_auth.rb +234 -0
  25. data/lib/http/features/instrumentation.rb +149 -0
  26. data/lib/http/features/logging.rb +231 -0
  27. data/lib/http/features/normalize_uri.rb +34 -0
  28. data/lib/http/features/raise_error.rb +37 -0
  29. data/lib/http/form_data/composite_io.rb +106 -0
  30. data/lib/http/form_data/file.rb +95 -0
  31. data/lib/http/form_data/multipart/param.rb +62 -0
  32. data/lib/http/form_data/multipart.rb +106 -0
  33. data/lib/http/form_data/part.rb +52 -0
  34. data/lib/http/form_data/readable.rb +58 -0
  35. data/lib/http/form_data/urlencoded.rb +175 -0
  36. data/lib/http/form_data/version.rb +8 -0
  37. data/lib/http/form_data.rb +102 -0
  38. data/lib/http/headers/known.rb +90 -0
  39. data/lib/http/headers/normalizer.rb +50 -0
  40. data/lib/http/headers.rb +343 -0
  41. data/lib/http/mime_type/adapter.rb +43 -0
  42. data/lib/http/mime_type/json.rb +41 -0
  43. data/lib/http/mime_type.rb +96 -0
  44. data/lib/http/options/definitions.rb +189 -0
  45. data/lib/http/options.rb +241 -0
  46. data/lib/http/redirector.rb +157 -0
  47. data/lib/http/request/body.rb +181 -0
  48. data/lib/http/request/builder.rb +184 -0
  49. data/lib/http/request/proxy.rb +83 -0
  50. data/lib/http/request/writer.rb +186 -0
  51. data/lib/http/request.rb +375 -0
  52. data/lib/http/response/body.rb +172 -0
  53. data/lib/http/response/inflater.rb +60 -0
  54. data/lib/http/response/parser.rb +223 -0
  55. data/lib/http/response/status/reasons.rb +79 -0
  56. data/lib/http/response/status.rb +263 -0
  57. data/lib/http/response.rb +350 -0
  58. data/lib/http/retriable/delay_calculator.rb +91 -0
  59. data/lib/http/retriable/errors.rb +35 -0
  60. data/lib/http/retriable/performer.rb +197 -0
  61. data/lib/http/session.rb +280 -0
  62. data/lib/http/timeout/global.rb +229 -0
  63. data/lib/http/timeout/null.rb +225 -0
  64. data/lib/http/timeout/per_operation.rb +197 -0
  65. data/lib/http/uri/normalizer.rb +82 -0
  66. data/lib/http/uri/parsing.rb +182 -0
  67. data/lib/http/uri.rb +376 -0
  68. data/lib/http/version.rb +6 -0
  69. data/lib/http.rb +36 -0
  70. data/sig/deps.rbs +122 -0
  71. data/sig/http.rbs +1619 -0
  72. data/test/http/base64_test.rb +28 -0
  73. data/test/http/client_test.rb +739 -0
  74. data/test/http/connection_test.rb +1533 -0
  75. data/test/http/content_type_test.rb +190 -0
  76. data/test/http/errors_test.rb +28 -0
  77. data/test/http/feature_test.rb +49 -0
  78. data/test/http/features/auto_deflate_test.rb +317 -0
  79. data/test/http/features/auto_inflate_test.rb +213 -0
  80. data/test/http/features/caching_test.rb +942 -0
  81. data/test/http/features/digest_auth_test.rb +996 -0
  82. data/test/http/features/instrumentation_test.rb +246 -0
  83. data/test/http/features/logging_test.rb +654 -0
  84. data/test/http/features/normalize_uri_test.rb +41 -0
  85. data/test/http/features/raise_error_test.rb +77 -0
  86. data/test/http/form_data/composite_io_test.rb +215 -0
  87. data/test/http/form_data/file_test.rb +255 -0
  88. data/test/http/form_data/fixtures/the-http-gem.info +1 -0
  89. data/test/http/form_data/multipart_test.rb +303 -0
  90. data/test/http/form_data/part_test.rb +90 -0
  91. data/test/http/form_data/urlencoded_test.rb +164 -0
  92. data/test/http/form_data_test.rb +232 -0
  93. data/test/http/headers/normalizer_test.rb +93 -0
  94. data/test/http/headers_test.rb +888 -0
  95. data/test/http/mime_type/json_test.rb +39 -0
  96. data/test/http/mime_type_test.rb +150 -0
  97. data/test/http/options/base_uri_test.rb +148 -0
  98. data/test/http/options/body_test.rb +21 -0
  99. data/test/http/options/features_test.rb +38 -0
  100. data/test/http/options/form_test.rb +21 -0
  101. data/test/http/options/headers_test.rb +32 -0
  102. data/test/http/options/json_test.rb +21 -0
  103. data/test/http/options/merge_test.rb +78 -0
  104. data/test/http/options/new_test.rb +37 -0
  105. data/test/http/options/proxy_test.rb +32 -0
  106. data/test/http/options_test.rb +575 -0
  107. data/test/http/redirector_test.rb +639 -0
  108. data/test/http/request/body_test.rb +318 -0
  109. data/test/http/request/builder_test.rb +623 -0
  110. data/test/http/request/writer_test.rb +391 -0
  111. data/test/http/request_test.rb +1733 -0
  112. data/test/http/response/body_test.rb +292 -0
  113. data/test/http/response/parser_test.rb +105 -0
  114. data/test/http/response/status_test.rb +322 -0
  115. data/test/http/response_test.rb +502 -0
  116. data/test/http/retriable/delay_calculator_test.rb +194 -0
  117. data/test/http/retriable/errors_test.rb +71 -0
  118. data/test/http/retriable/performer_test.rb +551 -0
  119. data/test/http/session_test.rb +424 -0
  120. data/test/http/timeout/global_test.rb +239 -0
  121. data/test/http/timeout/null_test.rb +218 -0
  122. data/test/http/timeout/per_operation_test.rb +220 -0
  123. data/test/http/uri/normalizer_test.rb +89 -0
  124. data/test/http/uri_test.rb +1140 -0
  125. data/test/http/version_test.rb +15 -0
  126. data/test/http_test.rb +818 -0
  127. data/test/regression_tests.rb +27 -0
  128. data/test/support/capture_warning.rb +10 -0
  129. data/test/support/dummy_server/encoding_routes.rb +47 -0
  130. data/test/support/dummy_server/routes.rb +201 -0
  131. data/test/support/dummy_server/servlet.rb +81 -0
  132. data/test/support/dummy_server.rb +200 -0
  133. data/test/support/fakeio.rb +21 -0
  134. data/test/support/http_handling_shared/connection_reuse_tests.rb +97 -0
  135. data/test/support/http_handling_shared/timeout_tests.rb +134 -0
  136. data/test/support/http_handling_shared.rb +11 -0
  137. data/test/support/proxy_server.rb +207 -0
  138. data/test/support/servers/runner.rb +67 -0
  139. data/test/support/simplecov.rb +28 -0
  140. data/test/support/ssl_helper.rb +108 -0
  141. data/test/test_helper.rb +38 -0
  142. metadata +218 -0
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTP
4
+ module Chainable
5
+ # HTTP verb shortcut methods
6
+ #
7
+ # Each method delegates to {Chainable#request} with the appropriate verb.
8
+ module Verbs
9
+ # Request a get sans response body
10
+ #
11
+ # @example
12
+ # HTTP.head("http://example.com")
13
+ #
14
+ # @param [String, URI] uri URI to request
15
+ # @param options [Hash] request options
16
+ # @yieldparam response [HTTP::Response] the response
17
+ # @return [HTTP::Response, Object] the response, or block return value
18
+ # @api public
19
+ def head(uri, **, &)
20
+ request(:head, uri, **, &) # steep:ignore
21
+ end
22
+
23
+ # Get a resource
24
+ #
25
+ # @example
26
+ # HTTP.get("http://example.com")
27
+ #
28
+ # @param [String, URI] uri URI to request
29
+ # @param options [Hash] request options
30
+ # @yieldparam response [HTTP::Response] the response
31
+ # @return [HTTP::Response, Object] the response, or block return value
32
+ # @api public
33
+ def get(uri, **, &)
34
+ request(:get, uri, **, &) # steep:ignore
35
+ end
36
+
37
+ # Post to a resource
38
+ #
39
+ # @example
40
+ # HTTP.post("http://example.com", body: "data")
41
+ #
42
+ # @param [String, URI] uri URI to request
43
+ # @param options [Hash] request options
44
+ # @yieldparam response [HTTP::Response] the response
45
+ # @return [HTTP::Response, Object] the response, or block return value
46
+ # @api public
47
+ def post(uri, **, &)
48
+ request(:post, uri, **, &) # steep:ignore
49
+ end
50
+
51
+ # Put to a resource
52
+ #
53
+ # @example
54
+ # HTTP.put("http://example.com", body: "data")
55
+ #
56
+ # @param [String, URI] uri URI to request
57
+ # @param options [Hash] request options
58
+ # @yieldparam response [HTTP::Response] the response
59
+ # @return [HTTP::Response, Object] the response, or block return value
60
+ # @api public
61
+ def put(uri, **, &)
62
+ request(:put, uri, **, &) # steep:ignore
63
+ end
64
+
65
+ # Delete a resource
66
+ #
67
+ # @example
68
+ # HTTP.delete("http://example.com/resource")
69
+ #
70
+ # @param [String, URI] uri URI to request
71
+ # @param options [Hash] request options
72
+ # @yieldparam response [HTTP::Response] the response
73
+ # @return [HTTP::Response, Object] the response, or block return value
74
+ # @api public
75
+ def delete(uri, **, &)
76
+ request(:delete, uri, **, &) # steep:ignore
77
+ end
78
+
79
+ # Echo the request back to the client
80
+ #
81
+ # @example
82
+ # HTTP.trace("http://example.com")
83
+ #
84
+ # @param [String, URI] uri URI to request
85
+ # @param options [Hash] request options
86
+ # @yieldparam response [HTTP::Response] the response
87
+ # @return [HTTP::Response, Object] the response, or block return value
88
+ # @api public
89
+ def trace(uri, **, &)
90
+ request(:trace, uri, **, &) # steep:ignore
91
+ end
92
+
93
+ # Return the methods supported on the given URI
94
+ #
95
+ # @example
96
+ # HTTP.options("http://example.com")
97
+ #
98
+ # @param [String, URI] uri URI to request
99
+ # @param options [Hash] request options
100
+ # @yieldparam response [HTTP::Response] the response
101
+ # @return [HTTP::Response, Object] the response, or block return value
102
+ # @api public
103
+ def options(uri, **, &)
104
+ request(:options, uri, **, &) # steep:ignore
105
+ end
106
+
107
+ # Convert to a transparent TCP/IP tunnel
108
+ #
109
+ # @example
110
+ # HTTP.connect("http://example.com")
111
+ #
112
+ # @param [String, URI] uri URI to request
113
+ # @param options [Hash] request options
114
+ # @yieldparam response [HTTP::Response] the response
115
+ # @return [HTTP::Response, Object] the response, or block return value
116
+ # @api public
117
+ def connect(uri, **, &)
118
+ request(:connect, uri, **, &) # steep:ignore
119
+ end
120
+
121
+ # Apply partial modifications to a resource
122
+ #
123
+ # @example
124
+ # HTTP.patch("http://example.com/resource", body: "data")
125
+ #
126
+ # @param [String, URI] uri URI to request
127
+ # @param options [Hash] request options
128
+ # @yieldparam response [HTTP::Response] the response
129
+ # @return [HTTP::Response, Object] the response, or block return value
130
+ # @api public
131
+ def patch(uri, **, &)
132
+ request(:patch, uri, **, &) # steep:ignore
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,377 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "http/base64"
4
+ require "http/chainable/helpers"
5
+ require "http/chainable/verbs"
6
+ require "http/headers"
7
+
8
+ module HTTP
9
+ # HTTP verb methods and client configuration DSL
10
+ module Chainable
11
+ include HTTP::Base64
12
+ include Verbs
13
+
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
+ #
22
+ # @param (see Client#request)
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
34
+ end
35
+
36
+ # Set timeout on the request
37
+ #
38
+ # @example
39
+ # HTTP.timeout(10).get("http://example.com")
40
+ #
41
+ # @overload timeout(options = {})
42
+ # Adds per operation timeouts to the request
43
+ # @param [Hash] options
44
+ # @option options [Float] :read Read timeout
45
+ # @option options [Float] :write Write timeout
46
+ # @option options [Float] :connect Connect timeout
47
+ # @option options [Float] :global Global timeout (combines with per-operation)
48
+ # @overload timeout(global_timeout)
49
+ # Adds a global timeout to the full request
50
+ # @param [Numeric] global_timeout
51
+ # @return [HTTP::Session]
52
+ # @api public
53
+ def timeout(options)
54
+ klass, options = case options
55
+ when Numeric then [HTTP::Timeout::Global, { global_timeout: options }]
56
+ when Hash then resolve_timeout_hash(options)
57
+ when :null then [HTTP::Timeout::Null, {}]
58
+ else raise ArgumentError,
59
+ "Use `.timeout(:null)`, " \
60
+ "`.timeout(global_timeout_in_seconds)` or " \
61
+ "`.timeout(connect: x, write: y, read: z)`."
62
+ end
63
+
64
+ branch default_options.merge(
65
+ timeout_class: klass,
66
+ timeout_options: options
67
+ )
68
+ end
69
+
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)
106
+ # Flags as persistent
107
+ # @param [String, nil] host connection origin (derived from base URI when nil)
108
+ # @option [Integer] timeout Keep alive timeout
109
+ # @raise [ArgumentError] if host is nil and no base URI is set
110
+ # @raise [Request::Error] if Host is invalid
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.
115
+ #
116
+ # @example
117
+ #
118
+ # def keys(users)
119
+ # HTTP.persistent("https://github.com") do |http|
120
+ # users.map { |u| http.get("/#{u}.keys").to_s }
121
+ # end
122
+ # end
123
+ #
124
+ # # same as
125
+ #
126
+ # def keys(users)
127
+ # http = HTTP.persistent "https://github.com"
128
+ # users.map { |u| http.get("/#{u}.keys").to_s }
129
+ # ensure
130
+ # http.close if http
131
+ # end
132
+ #
133
+ #
134
+ # @yieldparam [HTTP::Session] session Persistent session
135
+ # @return [Object] result of last expression in the block
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
141
+
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
147
+ ensure
148
+ session&.close if block_given?
149
+ end
150
+
151
+ # Make a request through an HTTP proxy
152
+ #
153
+ # @example
154
+ # HTTP.via("proxy.example.com", 8080).get("http://example.com")
155
+ #
156
+ # @param [Array] proxy
157
+ # @raise [Request::Error] if HTTP proxy is invalid
158
+ # @return [HTTP::Session]
159
+ # @api public
160
+ def via(*proxy)
161
+ proxy_hash = build_proxy_hash(proxy)
162
+
163
+ raise(RequestError, "invalid HTTP proxy: #{proxy_hash}") unless (2..5).cover?(proxy_hash.keys.size)
164
+
165
+ branch default_options.with_proxy(proxy_hash)
166
+ end
167
+ alias through via
168
+
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]
178
+ # @see Redirector#initialize
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)
183
+ end
184
+
185
+ # Make a request with the given headers
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
193
+ def headers(headers)
194
+ branch default_options.with_headers(headers)
195
+ end
196
+
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
205
+ def cookies(cookies)
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)
216
+ end
217
+
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
226
+ def encoding(encoding)
227
+ branch default_options.with_encoding(encoding)
228
+ end
229
+
230
+ # Accept the given MIME type(s)
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
238
+ def accept(type)
239
+ headers Headers::ACCEPT => MimeType.normalize(type)
240
+ end
241
+
242
+ # Make a request with the given Authorization header
243
+ #
244
+ # @example
245
+ # HTTP.auth("Bearer token123").get("http://example.com")
246
+ #
247
+ # @param [#to_s] value Authorization header value
248
+ # @return [HTTP::Session]
249
+ # @api public
250
+ def auth(value)
251
+ headers Headers::AUTHORIZATION => value.to_s
252
+ end
253
+
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
+ #
259
+ # @see http://tools.ietf.org/html/rfc2617
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
267
+
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 })
283
+ end
284
+
285
+ # Get options for HTTP
286
+ #
287
+ # @example
288
+ # HTTP.default_options
289
+ #
290
+ # @return [HTTP::Options]
291
+ # @api public
292
+ def default_options
293
+ @default_options ||= HTTP::Options.new
294
+ end
295
+
296
+ # Set options for HTTP
297
+ #
298
+ # @example
299
+ # HTTP.default_options = { response: :object }
300
+ #
301
+ # @param [Hash, HTTP::Options] opts options to set
302
+ # @return [HTTP::Options]
303
+ # @api public
304
+ def default_options=(opts)
305
+ @default_options = HTTP::Options.new(opts)
306
+ end
307
+
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
315
+ def nodelay
316
+ branch default_options.with_nodelay(true)
317
+ end
318
+
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
327
+ def use(*features)
328
+ branch default_options.with_features(features)
329
+ end
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
+
357
+ private
358
+
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
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)
374
+ HTTP::Client.new(options)
375
+ end
376
+ end
377
+ end