faraday 0.12.2 → 1.3.0

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