faraday 0.12.0 → 1.4.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +380 -0
  3. data/LICENSE.md +1 -1
  4. data/README.md +21 -308
  5. data/Rakefile +7 -0
  6. data/examples/client_spec.rb +65 -0
  7. data/examples/client_test.rb +79 -0
  8. data/lib/faraday/adapter/httpclient.rb +83 -59
  9. data/lib/faraday/adapter/patron.rb +92 -36
  10. data/lib/faraday/adapter/rack.rb +30 -13
  11. data/lib/faraday/adapter/test.rb +103 -62
  12. data/lib/faraday/adapter/typhoeus.rb +7 -115
  13. data/lib/faraday/adapter.rb +77 -22
  14. data/lib/faraday/adapter_registry.rb +30 -0
  15. data/lib/faraday/autoload.rb +42 -36
  16. data/lib/faraday/connection.rb +345 -179
  17. data/lib/faraday/dependency_loader.rb +37 -0
  18. data/lib/faraday/encoders/flat_params_encoder.rb +105 -0
  19. data/lib/faraday/encoders/nested_params_encoder.rb +176 -0
  20. data/lib/faraday/error.rb +127 -38
  21. data/lib/faraday/file_part.rb +128 -0
  22. data/lib/faraday/logging/formatter.rb +105 -0
  23. data/lib/faraday/methods.rb +6 -0
  24. data/lib/faraday/middleware.rb +19 -25
  25. data/lib/faraday/middleware_registry.rb +129 -0
  26. data/lib/faraday/options/connection_options.rb +22 -0
  27. data/lib/faraday/options/env.rb +181 -0
  28. data/lib/faraday/options/proxy_options.rb +32 -0
  29. data/lib/faraday/options/request_options.rb +22 -0
  30. data/lib/faraday/options/ssl_options.rb +59 -0
  31. data/lib/faraday/options.rb +39 -193
  32. data/lib/faraday/param_part.rb +53 -0
  33. data/lib/faraday/parameters.rb +4 -196
  34. data/lib/faraday/rack_builder.rb +84 -48
  35. data/lib/faraday/request/authorization.rb +44 -30
  36. data/lib/faraday/request/basic_authentication.rb +14 -7
  37. data/lib/faraday/request/instrumentation.rb +45 -27
  38. data/lib/faraday/request/multipart.rb +86 -48
  39. data/lib/faraday/request/retry.rb +209 -133
  40. data/lib/faraday/request/token_authentication.rb +15 -10
  41. data/lib/faraday/request/url_encoded.rb +43 -23
  42. data/lib/faraday/request.rb +94 -32
  43. data/lib/faraday/response/logger.rb +22 -69
  44. data/lib/faraday/response/raise_error.rb +49 -14
  45. data/lib/faraday/response.rb +27 -23
  46. data/lib/faraday/utils/headers.rb +139 -0
  47. data/lib/faraday/utils/params_hash.rb +61 -0
  48. data/lib/faraday/utils.rb +38 -238
  49. data/lib/faraday/version.rb +5 -0
  50. data/lib/faraday.rb +124 -187
  51. data/spec/external_adapters/faraday_specs_setup.rb +14 -0
  52. data/spec/faraday/adapter/em_http_spec.rb +47 -0
  53. data/spec/faraday/adapter/em_synchrony_spec.rb +16 -0
  54. data/spec/faraday/adapter/excon_spec.rb +49 -0
  55. data/spec/faraday/adapter/httpclient_spec.rb +73 -0
  56. data/spec/faraday/adapter/net_http_spec.rb +64 -0
  57. data/spec/faraday/adapter/patron_spec.rb +18 -0
  58. data/spec/faraday/adapter/rack_spec.rb +8 -0
  59. data/spec/faraday/adapter/test_spec.rb +260 -0
  60. data/spec/faraday/adapter/typhoeus_spec.rb +7 -0
  61. data/spec/faraday/adapter_registry_spec.rb +28 -0
  62. data/spec/faraday/adapter_spec.rb +55 -0
  63. data/spec/faraday/composite_read_io_spec.rb +80 -0
  64. data/spec/faraday/connection_spec.rb +736 -0
  65. data/spec/faraday/error_spec.rb +60 -0
  66. data/spec/faraday/middleware_spec.rb +52 -0
  67. data/spec/faraday/options/env_spec.rb +70 -0
  68. data/spec/faraday/options/options_spec.rb +297 -0
  69. data/spec/faraday/options/proxy_options_spec.rb +44 -0
  70. data/spec/faraday/options/request_options_spec.rb +19 -0
  71. data/spec/faraday/params_encoders/flat_spec.rb +42 -0
  72. data/spec/faraday/params_encoders/nested_spec.rb +142 -0
  73. data/spec/faraday/rack_builder_spec.rb +345 -0
  74. data/spec/faraday/request/authorization_spec.rb +88 -0
  75. data/spec/faraday/request/instrumentation_spec.rb +76 -0
  76. data/spec/faraday/request/multipart_spec.rb +302 -0
  77. data/spec/faraday/request/retry_spec.rb +242 -0
  78. data/spec/faraday/request/url_encoded_spec.rb +83 -0
  79. data/spec/faraday/request_spec.rb +120 -0
  80. data/spec/faraday/response/logger_spec.rb +220 -0
  81. data/spec/faraday/response/middleware_spec.rb +68 -0
  82. data/spec/faraday/response/raise_error_spec.rb +169 -0
  83. data/spec/faraday/response_spec.rb +75 -0
  84. data/spec/faraday/utils/headers_spec.rb +82 -0
  85. data/spec/faraday/utils_spec.rb +56 -0
  86. data/spec/faraday_spec.rb +37 -0
  87. data/spec/spec_helper.rb +132 -0
  88. data/spec/support/disabling_stub.rb +14 -0
  89. data/spec/support/fake_safe_buffer.rb +15 -0
  90. data/spec/support/helper_methods.rb +133 -0
  91. data/spec/support/shared_examples/adapter.rb +105 -0
  92. data/spec/support/shared_examples/params_encoder.rb +18 -0
  93. data/spec/support/shared_examples/request_method.rb +262 -0
  94. data/spec/support/streaming_response_checker.rb +35 -0
  95. data/spec/support/webmock_rack_app.rb +68 -0
  96. metadata +164 -16
  97. data/lib/faraday/adapter/em_http.rb +0 -243
  98. data/lib/faraday/adapter/em_http_ssl_patch.rb +0 -56
  99. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +0 -66
  100. data/lib/faraday/adapter/em_synchrony.rb +0 -106
  101. data/lib/faraday/adapter/excon.rb +0 -80
  102. data/lib/faraday/adapter/net_http.rb +0 -135
  103. data/lib/faraday/adapter/net_http_persistent.rb +0 -50
  104. data/lib/faraday/upload_io.rb +0 -67
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Faraday
2
- # Public: Connection objects manage the default properties and the middleware
4
+ # Connection objects manage the default properties and the middleware
3
5
  # stack for fulfilling an HTTP request.
4
6
  #
5
- # Examples
7
+ # @example
6
8
  #
7
9
  # conn = Faraday::Connection.new 'http://sushi.com'
8
10
  #
@@ -12,52 +14,55 @@ module Faraday
12
14
  #
13
15
  class Connection
14
16
  # A Set of allowed HTTP verbs.
15
- METHODS = Set.new [:get, :post, :put, :delete, :head, :patch, :options]
17
+ METHODS = Set.new %i[get post put delete head patch options trace]
16
18
 
17
- # Public: Returns a Hash of URI query unencoded key/value pairs.
19
+ # @return [Hash] URI query unencoded key/value pairs.
18
20
  attr_reader :params
19
21
 
20
- # Public: Returns a Hash of unencoded HTTP header key/value pairs.
22
+ # @return [Hash] unencoded HTTP header key/value pairs.
21
23
  attr_reader :headers
22
24
 
23
- # Public: Returns a URI with the prefix used for all requests from this
24
- # Connection. This includes a default host name, scheme, port, and path.
25
+ # @return [String] a URI with the prefix used for all requests from this
26
+ # Connection. This includes a default host name, scheme, port, and path.
25
27
  attr_reader :url_prefix
26
28
 
27
- # Public: Returns the Faraday::Builder for this Connection.
29
+ # @return [Faraday::Builder] Builder for this Connection.
28
30
  attr_reader :builder
29
31
 
30
- # Public: Returns a Hash of the request options.
31
- attr_reader :options
32
-
33
- # Public: Returns a Hash of the SSL options.
32
+ # @return [Hash] SSL options.
34
33
  attr_reader :ssl
35
34
 
36
- # Public: Returns the parallel manager for this Connection.
35
+ # @return [Object] the parallel manager for this Connection.
37
36
  attr_reader :parallel_manager
38
37
 
39
- # Public: Sets the default parallel manager for this connection.
38
+ # Sets the default parallel manager for this connection.
40
39
  attr_writer :default_parallel_manager
41
40
 
42
- # Public: Initializes a new Faraday::Connection.
41
+ # @return [Hash] proxy options.
42
+ attr_reader :proxy
43
+
44
+ # Initializes a new Faraday::Connection.
43
45
  #
44
- # url - URI or String base URL to use as a prefix for all
46
+ # @param url [URI, String] URI or String base URL to use as a prefix for all
45
47
  # requests (optional).
46
- # options - Hash or Faraday::ConnectionOptions.
47
- # :url - URI or String base URL (default: "http:/").
48
- # :params - Hash of URI query unencoded key/value pairs.
49
- # :headers - Hash of unencoded HTTP header key/value pairs.
50
- # :request - Hash of request options.
51
- # :ssl - Hash of SSL options.
52
- # :proxy - URI, String or Hash of HTTP proxy options
53
- # (default: "http_proxy" environment variable).
54
- # :uri - URI or String
55
- # :user - String (optional)
56
- # :password - String (optional)
48
+ # @param options [Hash, Faraday::ConnectionOptions]
49
+ # @option options [URI, String] :url ('http:/') URI or String base URL
50
+ # @option options [Hash<String => String>] :params URI query unencoded
51
+ # key/value pairs.
52
+ # @option options [Hash<String => String>] :headers Hash of unencoded HTTP
53
+ # header key/value pairs.
54
+ # @option options [Hash] :request Hash of request options.
55
+ # @option options [Hash] :ssl Hash of SSL options.
56
+ # @option options [Hash, URI, String] :proxy proxy options, either as a URL
57
+ # or as a Hash
58
+ # @option options [URI, String] :proxy[:uri]
59
+ # @option options [String] :proxy[:user]
60
+ # @option options [String] :proxy[:password]
61
+ # @yield [self] after all setup has been done
57
62
  def initialize(url = nil, options = nil)
58
63
  options = ConnectionOptions.from(options)
59
64
 
60
- if url.is_a?(Hash)
65
+ if url.is_a?(Hash) || url.is_a?(ConnectionOptions)
61
66
  options = options.merge(url)
62
67
  url = options.url
63
68
  end
@@ -68,10 +73,11 @@ module Faraday
68
73
  @options = options.request
69
74
  @ssl = options.ssl
70
75
  @default_parallel_manager = options.parallel_manager
76
+ @manual_proxy = nil
71
77
 
72
78
  @builder = options.builder || begin
73
79
  # pass an empty block to Builder so it doesn't assume default middleware
74
- options.new_builder(block_given? ? Proc.new { |b| } : nil)
80
+ options.new_builder(block_given? ? proc { |b| } : nil)
75
81
  end
76
82
 
77
83
  self.url_prefix = url || 'http:/'
@@ -79,35 +85,31 @@ module Faraday
79
85
  @params.update(options.params) if options.params
80
86
  @headers.update(options.headers) if options.headers
81
87
 
82
- @proxy = nil
83
- proxy(options.fetch(:proxy) {
84
- uri = nil
85
- if URI.parse("").respond_to?(:find_proxy)
86
- case url
87
- when String
88
- uri = URI.parse(url).find_proxy
89
- when URI
90
- uri = url.find_proxy
91
- when nil
92
- uri = find_default_proxy
93
- end
94
- else
95
- uri = find_default_proxy
96
- end
97
- uri
98
- })
88
+ initialize_proxy(url, options)
99
89
 
100
90
  yield(self) if block_given?
101
91
 
102
92
  @headers[:user_agent] ||= "Faraday v#{VERSION}"
103
93
  end
104
94
 
105
- # Public: Sets the Hash of URI query unencoded key/value pairs.
95
+ def initialize_proxy(url, options)
96
+ @manual_proxy = !!options.proxy
97
+ @proxy =
98
+ if options.proxy
99
+ ProxyOptions.from(options.proxy)
100
+ else
101
+ proxy_from_env(url)
102
+ end
103
+ end
104
+
105
+ # Sets the Hash of URI query unencoded key/value pairs.
106
+ # @param hash [Hash]
106
107
  def params=(hash)
107
108
  @params.replace hash
108
109
  end
109
110
 
110
- # Public: Sets the Hash of unencoded HTTP header key/value pairs.
111
+ # Sets the Hash of unencoded HTTP header key/value pairs.
112
+ # @param hash [Hash]
111
113
  def headers=(hash)
112
114
  @headers.replace hash
113
115
  end
@@ -116,71 +118,163 @@ module Faraday
116
118
 
117
119
  def_delegators :builder, :build, :use, :request, :response, :adapter, :app
118
120
 
119
- # Public: Makes an HTTP request without a body.
121
+ # Closes the underlying resources and/or connections. In the case of
122
+ # persistent connections, this closes all currently open connections
123
+ # but does not prevent new connections from being made.
124
+ def close
125
+ app.close
126
+ end
127
+
128
+ # @!method get(url = nil, params = nil, headers = nil)
129
+ # Makes a GET HTTP request without a body.
130
+ # @!scope class
120
131
  #
121
- # url - The optional String base URL to use as a prefix for all
122
- # requests. Can also be the options Hash.
123
- # params - Hash of URI query unencoded key/value pairs.
124
- # headers - Hash of unencoded HTTP header key/value pairs.
132
+ # @param url [String] The optional String base URL to use as a prefix for
133
+ # all requests. Can also be the options Hash.
134
+ # @param params [Hash] Hash of URI query unencoded key/value pairs.
135
+ # @param headers [Hash] unencoded HTTP header key/value pairs.
125
136
  #
126
- # Examples
127
- #
128
- # conn.get '/items', {:page => 1}, :accept => 'application/json'
129
- # conn.head '/items/1'
137
+ # @example
138
+ # conn.get '/items', { page: 1 }, :accept => 'application/json'
130
139
  #
131
140
  # # ElasticSearch example sending a body with GET.
132
141
  # conn.get '/twitter/tweet/_search' do |req|
133
142
  # req.headers[:content_type] = 'application/json'
134
143
  # req.params[:routing] = 'kimchy'
135
- # req.body = JSON.generate(:query => {...})
144
+ # req.body = JSON.generate(query: {...})
136
145
  # end
137
146
  #
138
- # Yields a Faraday::Request for further request customizations.
139
- # Returns a Faraday::Response.
147
+ # @yield [Faraday::Request] for further request customizations
148
+ # @return [Faraday::Response]
149
+
150
+ # @!method head(url = nil, params = nil, headers = nil)
151
+ # Makes a HEAD HTTP request without a body.
152
+ # @!scope class
140
153
  #
141
- # Signature
154
+ # @param url [String] The optional String base URL to use as a prefix for
155
+ # all requests. Can also be the options Hash.
156
+ # @param params [Hash] Hash of URI query unencoded key/value pairs.
157
+ # @param headers [Hash] unencoded HTTP header key/value pairs.
142
158
  #
143
- # <verb>(url = nil, params = nil, headers = nil)
159
+ # @example
160
+ # conn.head '/items/1'
144
161
  #
145
- # verb - An HTTP verb: get, head, or delete.
146
- %w[get head delete].each do |method|
162
+ # @yield [Faraday::Request] for further request customizations
163
+ # @return [Faraday::Response]
164
+
165
+ # @!method delete(url = nil, params = nil, headers = nil)
166
+ # Makes a DELETE HTTP request without a body.
167
+ # @!scope class
168
+ #
169
+ # @param url [String] The optional String base URL to use as a prefix for
170
+ # all requests. Can also be the options Hash.
171
+ # @param params [Hash] Hash of URI query unencoded key/value pairs.
172
+ # @param headers [Hash] unencoded HTTP header key/value pairs.
173
+ #
174
+ # @example
175
+ # conn.delete '/items/1'
176
+ #
177
+ # @yield [Faraday::Request] for further request customizations
178
+ # @return [Faraday::Response]
179
+
180
+ # @!method trace(url = nil, params = nil, headers = nil)
181
+ # Makes a TRACE HTTP request without a body.
182
+ # @!scope class
183
+ #
184
+ # @param url [String] The optional String base URL to use as a prefix for
185
+ # all requests. Can also be the options Hash.
186
+ # @param params [Hash] Hash of URI query unencoded key/value pairs.
187
+ # @param headers [Hash] unencoded HTTP header key/value pairs.
188
+ #
189
+ # @example
190
+ # conn.connect '/items/1'
191
+ #
192
+ # @yield [Faraday::Request] for further request customizations
193
+ # @return [Faraday::Response]
194
+
195
+ # @!visibility private
196
+ METHODS_WITH_QUERY.each do |method|
147
197
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
148
198
  def #{method}(url = nil, params = nil, headers = nil)
149
- run_request(:#{method}, url, nil, headers) { |request|
199
+ run_request(:#{method}, url, nil, headers) do |request|
150
200
  request.params.update(params) if params
151
- yield(request) if block_given?
152
- }
201
+ yield request if block_given?
202
+ end
153
203
  end
154
204
  RUBY
155
205
  end
156
206
 
157
- # Public: Makes an HTTP request with a body.
207
+ # @overload options()
208
+ # Returns current Connection options.
158
209
  #
159
- # url - The optional String base URL to use as a prefix for all
160
- # requests. Can also be the options Hash.
161
- # body - The String body for the request.
162
- # headers - Hash of unencoded HTTP header key/value pairs.
210
+ # @overload options(url, params = nil, headers = nil)
211
+ # Makes an OPTIONS HTTP request to the given URL.
212
+ # @param url [String] String base URL to sue as a prefix for all requests.
213
+ # @param params [Hash] Hash of URI query unencoded key/value pairs.
214
+ # @param headers [Hash] unencoded HTTP header key/value pairs.
163
215
  #
164
- # Examples
216
+ # @example
217
+ # conn.options '/items/1'
165
218
  #
166
- # conn.post '/items', data, :content_type => 'application/json'
219
+ # @yield [Faraday::Request] for further request customizations
220
+ # @return [Faraday::Response]
221
+ def options(*args)
222
+ return @options if args.size.zero?
223
+
224
+ url, params, headers = *args
225
+ run_request(:options, url, nil, headers) do |request|
226
+ request.params.update(params) if params
227
+ yield request if block_given?
228
+ end
229
+ end
230
+
231
+ # @!method post(url = nil, body = nil, headers = nil)
232
+ # Makes a POST HTTP request with a body.
233
+ # @!scope class
234
+ #
235
+ # @param url [String] The optional String base URL to use as a prefix for
236
+ # all requests. Can also be the options Hash.
237
+ # @param body [String] body for the request.
238
+ # @param headers [Hash] unencoded HTTP header key/value pairs.
239
+ #
240
+ # @example
241
+ # conn.post '/items', data, content_type: 'application/json'
167
242
  #
168
243
  # # Simple ElasticSearch indexing sample.
169
244
  # conn.post '/twitter/tweet' do |req|
170
245
  # req.headers[:content_type] = 'application/json'
171
246
  # req.params[:routing] = 'kimchy'
172
- # req.body = JSON.generate(:user => 'kimchy', ...)
247
+ # req.body = JSON.generate(user: 'kimchy', ...)
173
248
  # end
174
249
  #
175
- # Yields a Faraday::Request for further request customizations.
176
- # Returns a Faraday::Response.
250
+ # @yield [Faraday::Request] for further request customizations
251
+ # @return [Faraday::Response]
252
+
253
+ # @!method put(url = nil, body = nil, headers = nil)
254
+ # Makes a PUT HTTP request with a body.
255
+ # @!scope class
256
+ #
257
+ # @param url [String] The optional String base URL to use as a prefix for
258
+ # all requests. Can also be the options Hash.
259
+ # @param body [String] body for the request.
260
+ # @param headers [Hash] unencoded HTTP header key/value pairs.
177
261
  #
178
- # Signature
262
+ # @example
263
+ # # TODO: Make it a PUT example
264
+ # conn.post '/items', data, content_type: 'application/json'
179
265
  #
180
- # <verb>(url = nil, body = nil, headers = nil)
266
+ # # Simple ElasticSearch indexing sample.
267
+ # conn.post '/twitter/tweet' do |req|
268
+ # req.headers[:content_type] = 'application/json'
269
+ # req.params[:routing] = 'kimchy'
270
+ # req.body = JSON.generate(user: 'kimchy', ...)
271
+ # end
181
272
  #
182
- # verb - An HTTP verb: post, put, or patch.
183
- %w[post put patch].each do |method|
273
+ # @yield [Faraday::Request] for further request customizations
274
+ # @return [Faraday::Response]
275
+
276
+ # @!visibility private
277
+ METHODS_WITH_BODY.each do |method|
184
278
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
185
279
  def #{method}(url = nil, body = nil, headers = nil, &block)
186
280
  run_request(:#{method}, url, body, headers, &block)
@@ -188,123 +282,126 @@ module Faraday
188
282
  RUBY
189
283
  end
190
284
 
191
- # Public: Sets up the Authorization header with these credentials, encoded
285
+ # Sets up the Authorization header with these credentials, encoded
192
286
  # with base64.
193
287
  #
194
- # login - The authentication login.
195
- # pass - The authentication password.
288
+ # @param login [String] The authentication login.
289
+ # @param pass [String] The authentication password.
196
290
  #
197
- # Examples
291
+ # @example
198
292
  #
199
293
  # conn.basic_auth 'Aladdin', 'open sesame'
200
294
  # conn.headers['Authorization']
201
295
  # # => "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
202
296
  #
203
- # Returns nothing.
297
+ # @return [void]
204
298
  def basic_auth(login, pass)
205
299
  set_authorization_header(:basic_auth, login, pass)
206
300
  end
207
301
 
208
- # Public: Sets up the Authorization header with the given token.
302
+ # Sets up the Authorization header with the given token.
209
303
  #
210
- # token - The String token.
211
- # options - Optional Hash of extra token options.
304
+ # @param token [String]
305
+ # @param options [Hash] extra token options.
212
306
  #
213
- # Examples
307
+ # @example
214
308
  #
215
- # conn.token_auth 'abcdef', :foo => 'bar'
309
+ # conn.token_auth 'abcdef', foo: 'bar'
216
310
  # conn.headers['Authorization']
217
311
  # # => "Token token=\"abcdef\",
218
312
  # foo=\"bar\""
219
313
  #
220
- # Returns nothing.
314
+ # @return [void]
221
315
  def token_auth(token, options = nil)
222
316
  set_authorization_header(:token_auth, token, options)
223
317
  end
224
318
 
225
- # Public: Sets up a custom Authorization header.
319
+ # Sets up a custom Authorization header.
226
320
  #
227
- # type - The String authorization type.
228
- # token - The String or Hash token. A String value is taken literally, and
229
- # a Hash is encoded into comma separated key/value pairs.
321
+ # @param type [String] authorization type
322
+ # @param token [String, Hash] token. A String value is taken literally, and
323
+ # a Hash is encoded into comma-separated key/value pairs.
230
324
  #
231
- # Examples
325
+ # @example
232
326
  #
233
327
  # conn.authorization :Bearer, 'mF_9.B5f-4.1JqM'
234
328
  # conn.headers['Authorization']
235
329
  # # => "Bearer mF_9.B5f-4.1JqM"
236
330
  #
237
- # conn.authorization :Token, :token => 'abcdef', :foo => 'bar'
331
+ # conn.authorization :Token, token: 'abcdef', foo: 'bar'
238
332
  # conn.headers['Authorization']
239
333
  # # => "Token token=\"abcdef\",
240
334
  # foo=\"bar\""
241
335
  #
242
- # Returns nothing.
336
+ # @return [void]
243
337
  def authorization(type, token)
244
338
  set_authorization_header(:authorization, type, token)
245
339
  end
246
340
 
247
- # Internal: Traverse the middleware stack in search of a
248
- # parallel-capable adapter.
341
+ # Check if the adapter is parallel-capable.
249
342
  #
250
- # Yields in case of not found.
343
+ # @yield if the adapter isn't parallel-capable, or if no adapter is set yet.
251
344
  #
252
- # Returns a parallel manager or nil if not found.
345
+ # @return [Object, nil] a parallel manager or nil if yielded
346
+ # @api private
253
347
  def default_parallel_manager
254
348
  @default_parallel_manager ||= begin
255
- handler = @builder.handlers.detect do |h|
256
- h.klass.respond_to?(:supports_parallel?) and h.klass.supports_parallel?
257
- end
349
+ adapter = @builder.adapter.klass if @builder.adapter
258
350
 
259
- if handler
260
- handler.klass.setup_parallel_manager
351
+ if support_parallel?(adapter)
352
+ adapter.setup_parallel_manager
261
353
  elsif block_given?
262
354
  yield
263
355
  end
264
356
  end
265
357
  end
266
358
 
267
- # Public: Determine if this Faraday::Connection can make parallel requests.
359
+ # Determine if this Faraday::Connection can make parallel requests.
268
360
  #
269
- # Returns true or false.
361
+ # @return [Boolean]
270
362
  def in_parallel?
271
363
  !!@parallel_manager
272
364
  end
273
365
 
274
- # Public: Sets up the parallel manager to make a set of requests.
366
+ # Sets up the parallel manager to make a set of requests.
275
367
  #
276
- # manager - The parallel manager that this Connection's Adapter uses.
368
+ # @param manager [Object] The parallel manager that this Connection's
369
+ # Adapter uses.
277
370
  #
278
- # Yields a block to execute multiple requests.
279
- # Returns nothing.
371
+ # @yield a block to execute multiple requests.
372
+ # @return [void]
280
373
  def in_parallel(manager = nil)
281
- @parallel_manager = manager || default_parallel_manager {
282
- warn "Warning: `in_parallel` called but no parallel-capable adapter on Faraday stack"
283
- warn caller[2,10].join("\n")
374
+ @parallel_manager = manager || default_parallel_manager do
375
+ warn 'Warning: `in_parallel` called but no parallel-capable adapter ' \
376
+ 'on Faraday stack'
377
+ warn caller[2, 10].join("\n")
284
378
  nil
285
- }
379
+ end
286
380
  yield
287
- @parallel_manager && @parallel_manager.run
381
+ @parallel_manager&.run
288
382
  ensure
289
383
  @parallel_manager = nil
290
384
  end
291
385
 
292
- # Public: Gets or Sets the Hash proxy options.
293
- def proxy(arg = nil)
294
- return @proxy if arg.nil?
295
- @proxy = ProxyOptions.from(arg)
386
+ # Sets the Hash proxy options.
387
+ #
388
+ # @param new_value [Object]
389
+ def proxy=(new_value)
390
+ @manual_proxy = true
391
+ @proxy = new_value ? ProxyOptions.from(new_value) : nil
296
392
  end
297
393
 
298
394
  def_delegators :url_prefix, :scheme, :scheme=, :host, :host=, :port, :port=
299
395
  def_delegator :url_prefix, :path, :path_prefix
300
396
 
301
- # Public: Parses the giving url with URI and stores the individual
302
- # components in this connection. These components serve as defaults for
397
+ # Parses the given URL with URI and stores the individual
398
+ # components in this connection. These components serve as defaults for
303
399
  # requests made by this connection.
304
400
  #
305
- # url - A String or URI.
401
+ # @param url [String, URI]
402
+ # @param encoder [Object]
306
403
  #
307
- # Examples
404
+ # @example
308
405
  #
309
406
  # conn = Faraday::Connection.new { ... }
310
407
  # conn.url_prefix = "https://sushi.com/api"
@@ -312,8 +409,6 @@ module Faraday
312
409
  # conn.path_prefix # => "/api"
313
410
  #
314
411
  # conn.get("nigiri?page=2") # accesses https://sushi.com/api/nigiri
315
- #
316
- # Returns the parsed URI from teh given input..
317
412
  def url_prefix=(url, encoder = nil)
318
413
  uri = @url_prefix = Utils.URI(url)
319
414
  self.path_prefix = uri.path
@@ -326,57 +421,71 @@ module Faraday
326
421
  uri.user = uri.password = nil
327
422
  end
328
423
 
329
- uri
424
+ @proxy = proxy_from_env(url) unless @manual_proxy
330
425
  end
331
426
 
332
- # Public: Sets the path prefix and ensures that it always has a leading
427
+ # Sets the path prefix and ensures that it always has a leading
333
428
  # slash.
334
429
  #
335
- # value - A String.
430
+ # @param value [String]
336
431
  #
337
- # Returns the new String path prefix.
432
+ # @return [String] the new path prefix
338
433
  def path_prefix=(value)
339
434
  url_prefix.path = if value
340
- value = '/' + value unless value[0,1] == '/'
341
- value
342
- end
435
+ value = "/#{value}" unless value[0, 1] == '/'
436
+ value
437
+ end
343
438
  end
344
439
 
345
- # Public: Takes a relative url for a request and combines it with the defaults
440
+ # Takes a relative url for a request and combines it with the defaults
346
441
  # set on the connection instance.
347
442
  #
443
+ # @param url [String]
444
+ # @param extra_params [Hash]
445
+ #
446
+ # @example
348
447
  # conn = Faraday::Connection.new { ... }
349
448
  # conn.url_prefix = "https://sushi.com/api?token=abc"
350
449
  # conn.scheme # => https
351
450
  # conn.path_prefix # => "/api"
352
451
  #
353
- # conn.build_url("nigiri?page=2") # => https://sushi.com/api/nigiri?token=abc&page=2
354
- # conn.build_url("nigiri", :page => 2) # => https://sushi.com/api/nigiri?token=abc&page=2
452
+ # conn.build_url("nigiri?page=2")
453
+ # # => https://sushi.com/api/nigiri?token=abc&page=2
454
+ #
455
+ # conn.build_url("nigiri", page: 2)
456
+ # # => https://sushi.com/api/nigiri?token=abc&page=2
355
457
  #
356
458
  def build_url(url = nil, extra_params = nil)
357
459
  uri = build_exclusive_url(url)
358
460
 
359
461
  query_values = params.dup.merge_query(uri.query, options.params_encoder)
360
- query_values.update extra_params if extra_params
361
- uri.query = query_values.empty? ? nil : query_values.to_query(options.params_encoder)
462
+ query_values.update(extra_params) if extra_params
463
+ uri.query =
464
+ if query_values.empty?
465
+ nil
466
+ else
467
+ query_values.to_query(options.params_encoder)
468
+ end
362
469
 
363
470
  uri
364
471
  end
365
472
 
366
473
  # Builds and runs the Faraday::Request.
367
474
  #
368
- # method - The Symbol HTTP method.
369
- # url - The String or URI to access.
370
- # body - The request body that will eventually be converted to a string.
371
- # headers - Hash of unencoded HTTP header key/value pairs.
475
+ # @param method [Symbol] HTTP method.
476
+ # @param url [String, URI] String or URI to access.
477
+ # @param body [Object] The request body that will eventually be converted to
478
+ # a string.
479
+ # @param headers [Hash] unencoded HTTP header key/value pairs.
372
480
  #
373
- # Returns a Faraday::Response.
481
+ # @return [Faraday::Response]
374
482
  def run_request(method, url, body, headers)
375
- if !METHODS.include?(method)
483
+ unless METHODS.include?(method)
376
484
  raise ArgumentError, "unknown http method: #{method}"
377
485
  end
378
486
 
379
487
  request = build_request(method) do |req|
488
+ req.options.proxy = proxy_for_request(url)
380
489
  req.url(url) if url
381
490
  req.headers.update(headers) if headers
382
491
  req.body = body if body
@@ -388,68 +497,125 @@ module Faraday
388
497
 
389
498
  # Creates and configures the request object.
390
499
  #
391
- # Returns the new Request.
500
+ # @param method [Symbol]
501
+ #
502
+ # @yield [Faraday::Request] if block given
503
+ # @return [Faraday::Request]
392
504
  def build_request(method)
393
505
  Request.create(method) do |req|
394
- req.params = self.params.dup
395
- req.headers = self.headers.dup
396
- req.options = self.options.merge(:proxy => self.proxy)
506
+ req.params = params.dup
507
+ req.headers = headers.dup
508
+ req.options = options.dup
397
509
  yield(req) if block_given?
398
510
  end
399
511
  end
400
512
 
401
- # Internal: Build an absolute URL based on url_prefix.
513
+ # Build an absolute URL based on url_prefix.
402
514
  #
403
- # url - A String or URI-like object
404
- # params - A Faraday::Utils::ParamsHash to replace the query values
515
+ # @param url [String, URI]
516
+ # @param params [Faraday::Utils::ParamsHash] A Faraday::Utils::ParamsHash to
517
+ # replace the query values
405
518
  # of the resulting url (default: nil).
406
519
  #
407
- # Returns the resulting URI instance.
520
+ # @return [URI]
408
521
  def build_exclusive_url(url = nil, params = nil, params_encoder = nil)
409
- url = nil if url.respond_to?(:empty?) and url.empty?
410
- base = url_prefix
411
- if url and base.path and base.path !~ /\/$/
412
- base = base.dup
413
- base.path = base.path + '/' # ensure trailing slash
522
+ url = nil if url.respond_to?(:empty?) && url.empty?
523
+ base = url_prefix.dup
524
+ if url && base.path && base.path !~ %r{/$}
525
+ base.path = "#{base.path}/" # ensure trailing slash
414
526
  end
527
+ url = url && URI.parse(url.to_s).opaque ? url.to_s.gsub(':', '%3A') : url
415
528
  uri = url ? base + url : base
416
- uri.query = params.to_query(params_encoder || options.params_encoder) if params
417
- uri.query = nil if uri.query and uri.query.empty?
529
+ if params
530
+ uri.query = params.to_query(params_encoder || options.params_encoder)
531
+ end
532
+ # rubocop:disable Style/SafeNavigation
533
+ uri.query = nil if uri.query && uri.query.empty?
534
+ # rubocop:enable Style/SafeNavigation
418
535
  uri
419
536
  end
420
537
 
421
- # Internal: Creates a duplicate of this Faraday::Connection.
538
+ # Creates a duplicate of this Faraday::Connection.
422
539
  #
423
- # Returns a Faraday::Connection.
540
+ # @api private
541
+ #
542
+ # @return [Faraday::Connection]
424
543
  def dup
425
544
  self.class.new(build_exclusive_url,
426
- :headers => headers.dup,
427
- :params => params.dup,
428
- :builder => builder.dup,
429
- :ssl => ssl.dup,
430
- :request => options.dup)
545
+ headers: headers.dup,
546
+ params: params.dup,
547
+ builder: builder.dup,
548
+ ssl: ssl.dup,
549
+ request: options.dup)
431
550
  end
432
551
 
433
- # Internal: Yields username and password extracted from a URI if they both exist.
552
+ # Yields username and password extracted from a URI if they both exist.
553
+ #
554
+ # @param uri [URI]
555
+ # @yield [username, password] any username and password
556
+ # @yieldparam username [String] any username from URI
557
+ # @yieldparam password [String] any password from URI
558
+ # @return [void]
559
+ # @api private
434
560
  def with_uri_credentials(uri)
435
- if uri.user and uri.password
436
- yield(Utils.unescape(uri.user), Utils.unescape(uri.password))
437
- end
561
+ return unless uri.user && uri.password
562
+
563
+ yield(Utils.unescape(uri.user), Utils.unescape(uri.password))
438
564
  end
439
565
 
440
566
  def set_authorization_header(header_type, *args)
441
- header = Faraday::Request.lookup_middleware(header_type).
442
- header(*args)
567
+ header = Faraday::Request
568
+ .lookup_middleware(header_type)
569
+ .header(*args)
570
+
443
571
  headers[Faraday::Request::Authorization::KEY] = header
444
572
  end
445
573
 
574
+ def proxy_from_env(url)
575
+ return if Faraday.ignore_env_proxy
576
+
577
+ uri = nil
578
+ if URI.parse('').respond_to?(:find_proxy)
579
+ case url
580
+ when String
581
+ uri = Utils.URI(url)
582
+ uri = if uri.host.nil?
583
+ find_default_proxy
584
+ else
585
+ URI.parse("#{uri.scheme}://#{uri.host}").find_proxy
586
+ end
587
+ when URI
588
+ uri = url.find_proxy
589
+ when nil
590
+ uri = find_default_proxy
591
+ end
592
+ else
593
+ warn 'no_proxy is unsupported' if ENV['no_proxy'] || ENV['NO_PROXY']
594
+ uri = find_default_proxy
595
+ end
596
+ ProxyOptions.from(uri) if uri
597
+ end
598
+
446
599
  def find_default_proxy
447
- warn 'no_proxy is unsupported' if ENV['no_proxy'] || ENV['NO_PROXY']
448
600
  uri = ENV['http_proxy']
449
- if uri && !uri.empty?
450
- uri = 'http://' + uri if uri !~ /^http/i
451
- uri
601
+ return unless uri && !uri.empty?
602
+
603
+ uri = "http://#{uri}" unless uri.match?(/^http/i)
604
+ uri
605
+ end
606
+
607
+ def proxy_for_request(url)
608
+ return proxy if @manual_proxy
609
+
610
+ if url && Utils.URI(url).absolute?
611
+ proxy_from_env(url)
612
+ else
613
+ proxy
452
614
  end
453
615
  end
616
+
617
+ def support_parallel?(adapter)
618
+ adapter&.respond_to?(:supports_parallel?) && adapter&.supports_parallel?
619
+ end
454
620
  end
455
621
  end