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.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +110 -13
  4. data/http.gemspec +38 -35
  5. data/lib/http/base64.rb +22 -0
  6. data/lib/http/chainable/helpers.rb +62 -0
  7. data/lib/http/chainable/verbs.rb +136 -0
  8. data/lib/http/chainable.rb +249 -129
  9. data/lib/http/client.rb +158 -127
  10. data/lib/http/connection/internals.rb +141 -0
  11. data/lib/http/connection.rb +128 -97
  12. data/lib/http/content_type.rb +61 -6
  13. data/lib/http/errors.rb +41 -1
  14. data/lib/http/feature.rb +67 -6
  15. data/lib/http/features/auto_deflate.rb +124 -17
  16. data/lib/http/features/auto_inflate.rb +38 -15
  17. data/lib/http/features/caching/entry.rb +178 -0
  18. data/lib/http/features/caching/in_memory_store.rb +63 -0
  19. data/lib/http/features/caching.rb +216 -0
  20. data/lib/http/features/digest_auth.rb +234 -0
  21. data/lib/http/features/instrumentation.rb +97 -17
  22. data/lib/http/features/logging.rb +183 -5
  23. data/lib/http/features/normalize_uri.rb +17 -0
  24. data/lib/http/features/raise_error.rb +37 -0
  25. data/lib/http/form_data/composite_io.rb +106 -0
  26. data/lib/http/form_data/file.rb +95 -0
  27. data/lib/http/form_data/multipart/param.rb +62 -0
  28. data/lib/http/form_data/multipart.rb +106 -0
  29. data/lib/http/form_data/part.rb +52 -0
  30. data/lib/http/form_data/readable.rb +58 -0
  31. data/lib/http/form_data/urlencoded.rb +175 -0
  32. data/lib/http/form_data/version.rb +8 -0
  33. data/lib/http/form_data.rb +102 -0
  34. data/lib/http/headers/known.rb +3 -0
  35. data/lib/http/headers/normalizer.rb +50 -0
  36. data/lib/http/headers.rb +185 -92
  37. data/lib/http/mime_type/adapter.rb +24 -9
  38. data/lib/http/mime_type/json.rb +19 -4
  39. data/lib/http/mime_type.rb +21 -3
  40. data/lib/http/options/definitions.rb +189 -0
  41. data/lib/http/options.rb +172 -125
  42. data/lib/http/redirector.rb +80 -75
  43. data/lib/http/request/body.rb +87 -6
  44. data/lib/http/request/builder.rb +184 -0
  45. data/lib/http/request/proxy.rb +83 -0
  46. data/lib/http/request/writer.rb +78 -17
  47. data/lib/http/request.rb +216 -99
  48. data/lib/http/response/body.rb +103 -18
  49. data/lib/http/response/inflater.rb +35 -7
  50. data/lib/http/response/parser.rb +98 -4
  51. data/lib/http/response/status/reasons.rb +2 -4
  52. data/lib/http/response/status.rb +141 -31
  53. data/lib/http/response.rb +219 -61
  54. data/lib/http/retriable/delay_calculator.rb +91 -0
  55. data/lib/http/retriable/errors.rb +35 -0
  56. data/lib/http/retriable/performer.rb +197 -0
  57. data/lib/http/session.rb +280 -0
  58. data/lib/http/timeout/global.rb +147 -34
  59. data/lib/http/timeout/null.rb +155 -9
  60. data/lib/http/timeout/per_operation.rb +139 -18
  61. data/lib/http/uri/normalizer.rb +82 -0
  62. data/lib/http/uri/parsing.rb +182 -0
  63. data/lib/http/uri.rb +289 -124
  64. data/lib/http/version.rb +2 -1
  65. data/lib/http.rb +11 -1
  66. data/sig/http.rbs +1619 -0
  67. metadata +42 -175
  68. data/.github/workflows/ci.yml +0 -67
  69. data/.gitignore +0 -15
  70. data/.rspec +0 -1
  71. data/.rubocop/layout.yml +0 -8
  72. data/.rubocop/metrics.yml +0 -4
  73. data/.rubocop/style.yml +0 -32
  74. data/.rubocop.yml +0 -11
  75. data/.rubocop_todo.yml +0 -206
  76. data/.yardopts +0 -2
  77. data/CHANGELOG.md +0 -41
  78. data/CHANGES_OLD.md +0 -1002
  79. data/CONTRIBUTING.md +0 -26
  80. data/Gemfile +0 -50
  81. data/Guardfile +0 -18
  82. data/Rakefile +0 -64
  83. data/SECURITY.md +0 -17
  84. data/lib/http/headers/mixin.rb +0 -34
  85. data/logo.png +0 -0
  86. data/spec/lib/http/client_spec.rb +0 -556
  87. data/spec/lib/http/connection_spec.rb +0 -88
  88. data/spec/lib/http/content_type_spec.rb +0 -47
  89. data/spec/lib/http/features/auto_deflate_spec.rb +0 -77
  90. data/spec/lib/http/features/auto_inflate_spec.rb +0 -86
  91. data/spec/lib/http/features/instrumentation_spec.rb +0 -81
  92. data/spec/lib/http/features/logging_spec.rb +0 -65
  93. data/spec/lib/http/headers/mixin_spec.rb +0 -36
  94. data/spec/lib/http/headers_spec.rb +0 -527
  95. data/spec/lib/http/options/body_spec.rb +0 -15
  96. data/spec/lib/http/options/features_spec.rb +0 -33
  97. data/spec/lib/http/options/form_spec.rb +0 -15
  98. data/spec/lib/http/options/headers_spec.rb +0 -24
  99. data/spec/lib/http/options/json_spec.rb +0 -15
  100. data/spec/lib/http/options/merge_spec.rb +0 -68
  101. data/spec/lib/http/options/new_spec.rb +0 -30
  102. data/spec/lib/http/options/proxy_spec.rb +0 -20
  103. data/spec/lib/http/options_spec.rb +0 -13
  104. data/spec/lib/http/redirector_spec.rb +0 -529
  105. data/spec/lib/http/request/body_spec.rb +0 -211
  106. data/spec/lib/http/request/writer_spec.rb +0 -121
  107. data/spec/lib/http/request_spec.rb +0 -234
  108. data/spec/lib/http/response/body_spec.rb +0 -85
  109. data/spec/lib/http/response/parser_spec.rb +0 -74
  110. data/spec/lib/http/response/status_spec.rb +0 -253
  111. data/spec/lib/http/response_spec.rb +0 -262
  112. data/spec/lib/http/uri/normalizer_spec.rb +0 -95
  113. data/spec/lib/http/uri_spec.rb +0 -71
  114. data/spec/lib/http_spec.rb +0 -506
  115. data/spec/regression_specs.rb +0 -24
  116. data/spec/spec_helper.rb +0 -88
  117. data/spec/support/black_hole.rb +0 -13
  118. data/spec/support/capture_warning.rb +0 -10
  119. data/spec/support/dummy_server/servlet.rb +0 -190
  120. data/spec/support/dummy_server.rb +0 -43
  121. data/spec/support/fakeio.rb +0 -21
  122. data/spec/support/fuubar.rb +0 -21
  123. data/spec/support/http_handling_shared.rb +0 -190
  124. data/spec/support/proxy_server.rb +0 -39
  125. data/spec/support/servers/config.rb +0 -11
  126. data/spec/support/servers/runner.rb +0 -19
  127. data/spec/support/simplecov.rb +0 -19
  128. data/spec/support/ssl_helper.rb +0 -104
@@ -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
- # Request a get sans response body
10
- # @param uri
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
- def request(*args)
75
- branch(default_options).request(*args)
76
- end
77
-
78
- # Prepare an HTTP request with the given verb
79
- # @param (see Client#build_request)
80
- def build_request(*args)
81
- branch(default_options).build_request(*args)
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, {:global => options}]
96
- when Hash then [HTTP::Timeout::PerOperation, options.dup]
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, "Use `.timeout(global_timeout_in_seconds)` or `.timeout(connect: x, write: y, read: z)`."
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
- :timeout_class => klass,
110
- :timeout_options => options
65
+ timeout_class: klass,
66
+ timeout_options: options
111
67
  )
112
68
  end
113
69
 
114
- # @overload persistent(host, timeout: 5)
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::Client] Persistent client
120
- # @overload persistent(host, timeout: 5, &block)
121
- # Executes given block with persistent client and automatically closes
122
- # connection at the end of execution.
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::Client] client Persistent client
134
+ # @yieldparam [HTTP::Session] session Persistent session
143
135
  # @return [Object] result of last expression in the block
144
- def persistent(host, timeout: 5)
145
- options = {:keep_alive_timeout => timeout}
146
- p_client = branch default_options.merge(options).with_persistent host
147
- return p_client unless block_given?
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
- yield p_client
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
- p_client&.close
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
- # @param options
174
- # @return [HTTP::Client]
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
- def follow(options = {})
177
- branch default_options.with_follow options
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
- # @param 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
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
- branch default_options.with_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)
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
- # @param type
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 [#fetch] opts
211
- # @option opts [#to_s] :user
212
- # @option opts [#to_s] :pass
213
- def basic_auth(opts)
214
- user = opts.fetch(:user)
215
- pass = opts.fetch(:pass)
216
- creds = "#{user}:#{pass}"
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
- auth("Basic #{Base64.strict_encode64(creds)}")
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
- # @param opts
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
- # Turn on given features. Available features are:
240
- # * auto_inflate
241
- # * auto_deflate
242
- # * instrumentation
243
- # * logging
244
- # * normalize_uri
245
- # @param features
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
- # :nodoc:
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