faraday 0.6.0 → 0.9.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 (83) hide show
  1. checksums.yaml +7 -0
  2. data/.document +6 -0
  3. data/CHANGELOG.md +15 -0
  4. data/CONTRIBUTING.md +36 -0
  5. data/Gemfile +25 -15
  6. data/{LICENSE → LICENSE.md} +1 -1
  7. data/README.md +187 -137
  8. data/Rakefile +38 -101
  9. data/faraday.gemspec +26 -81
  10. data/lib/faraday/adapter/em_http.rb +237 -0
  11. data/lib/faraday/adapter/em_http_ssl_patch.rb +56 -0
  12. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +66 -0
  13. data/lib/faraday/adapter/em_synchrony.rb +65 -38
  14. data/lib/faraday/adapter/excon.rb +60 -9
  15. data/lib/faraday/adapter/httpclient.rb +106 -0
  16. data/lib/faraday/adapter/net_http.rb +89 -38
  17. data/lib/faraday/adapter/net_http_persistent.rb +47 -0
  18. data/lib/faraday/adapter/patron.rb +46 -9
  19. data/lib/faraday/adapter/rack.rb +58 -0
  20. data/lib/faraday/adapter/test.rb +68 -28
  21. data/lib/faraday/adapter/typhoeus.rb +94 -16
  22. data/lib/faraday/adapter.rb +33 -25
  23. data/lib/faraday/autoload.rb +85 -0
  24. data/lib/faraday/connection.rb +342 -134
  25. data/lib/faraday/error.rb +44 -29
  26. data/lib/faraday/middleware.rb +18 -10
  27. data/lib/faraday/options.rb +350 -0
  28. data/lib/faraday/parameters.rb +193 -0
  29. data/lib/faraday/rack_builder.rb +212 -0
  30. data/lib/faraday/request/authorization.rb +42 -0
  31. data/lib/faraday/request/basic_authentication.rb +13 -0
  32. data/lib/faraday/request/instrumentation.rb +36 -0
  33. data/lib/faraday/request/multipart.rb +15 -15
  34. data/lib/faraday/request/retry.rb +118 -0
  35. data/lib/faraday/request/token_authentication.rb +15 -0
  36. data/lib/faraday/request/url_encoded.rb +8 -9
  37. data/lib/faraday/request.rb +46 -45
  38. data/lib/faraday/response/logger.rb +4 -4
  39. data/lib/faraday/response/raise_error.rb +8 -3
  40. data/lib/faraday/response.rb +20 -25
  41. data/lib/faraday/upload_io.rb +51 -7
  42. data/lib/faraday/utils.rb +240 -44
  43. data/lib/faraday.rb +218 -38
  44. data/script/console +7 -0
  45. data/script/generate_certs +42 -0
  46. data/script/package +7 -0
  47. data/script/proxy-server +42 -0
  48. data/script/release +17 -0
  49. data/script/server +36 -0
  50. data/script/test +172 -0
  51. data/test/adapters/default_test.rb +14 -0
  52. data/test/adapters/em_http_test.rb +20 -0
  53. data/test/adapters/em_synchrony_test.rb +20 -0
  54. data/test/adapters/excon_test.rb +20 -0
  55. data/test/adapters/httpclient_test.rb +21 -0
  56. data/test/adapters/integration.rb +254 -0
  57. data/test/adapters/logger_test.rb +3 -3
  58. data/test/adapters/net_http_persistent_test.rb +20 -0
  59. data/test/adapters/net_http_test.rb +6 -25
  60. data/test/adapters/patron_test.rb +20 -0
  61. data/test/adapters/rack_test.rb +31 -0
  62. data/test/adapters/test_middleware_test.rb +74 -3
  63. data/test/adapters/typhoeus_test.rb +28 -0
  64. data/test/authentication_middleware_test.rb +65 -0
  65. data/test/composite_read_io_test.rb +111 -0
  66. data/test/connection_test.rb +381 -104
  67. data/test/env_test.rb +116 -40
  68. data/test/helper.rb +61 -25
  69. data/test/live_server.rb +55 -29
  70. data/test/middleware/instrumentation_test.rb +88 -0
  71. data/test/middleware/retry_test.rb +109 -0
  72. data/test/middleware_stack_test.rb +87 -5
  73. data/test/multibyte.txt +1 -0
  74. data/test/options_test.rb +252 -0
  75. data/test/request_middleware_test.rb +78 -21
  76. data/test/response_middleware_test.rb +32 -7
  77. data/test/strawberry.rb +2 -0
  78. data/test/utils_test.rb +58 -0
  79. metadata +116 -117
  80. data/lib/faraday/adapter/action_dispatch.rb +0 -30
  81. data/lib/faraday/builder.rb +0 -137
  82. data/lib/faraday/request/json.rb +0 -31
  83. data/test/adapters/live_test.rb +0 -186
@@ -1,137 +1,302 @@
1
- require 'addressable/uri'
2
- require 'set'
3
- require 'base64'
4
-
5
1
  module Faraday
2
+ # Public: Connection objects manage the default properties and the middleware
3
+ # stack for fulfilling an HTTP request.
4
+ #
5
+ # Examples
6
+ #
7
+ # conn = Faraday::Connection.new 'http://sushi.com'
8
+ #
9
+ # # GET http://sushi.com/nigiri
10
+ # conn.get 'nigiri'
11
+ # # => #<Faraday::Response>
12
+ #
6
13
  class Connection
7
- include Addressable, Faraday::Utils
14
+ # A Set of allowed HTTP verbs.
15
+ METHODS = Set.new [:get, :post, :put, :delete, :head, :patch, :options]
16
+
17
+ # Public: Returns a Hash of URI query unencoded key/value pairs.
18
+ attr_reader :params
19
+
20
+ # Public: Returns a Hash of unencoded HTTP header key/value pairs.
21
+ attr_reader :headers
22
+
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
+ attr_reader :url_prefix
26
+
27
+ # Public: Returns the Faraday::Builder for this Connection.
28
+ attr_reader :builder
29
+
30
+ # Public: Returns a Hash of the request options.
31
+ attr_reader :options
32
+
33
+ # Public: Returns a Hash of the SSL options.
34
+ attr_reader :ssl
8
35
 
9
- METHODS = Set.new [:get, :post, :put, :delete, :head]
10
- METHODS_WITH_BODIES = Set.new [:post, :put]
36
+ # Public: Returns the parallel manager for this Connection.
37
+ attr_reader :parallel_manager
11
38
 
12
- attr_accessor :host, :port, :scheme, :params, :headers, :parallel_manager
13
- attr_reader :path_prefix, :builder, :options, :ssl
39
+ # Public: Sets the default parallel manager for this connection.
40
+ attr_writer :default_parallel_manager
14
41
 
15
- # :url
16
- # :params
17
- # :headers
18
- # :request
19
- # :ssl
20
- def initialize(url = nil, options = {})
42
+ # Public: Initializes a new Faraday::Connection.
43
+ #
44
+ # url - URI or String base URL to use as a prefix for all
45
+ # 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)
57
+ def initialize(url = nil, options = nil)
21
58
  if url.is_a?(Hash)
22
- options = url
23
- url = options[:url]
24
- end
25
- @headers = Headers.new
26
- @params = {}
27
- @options = options[:request] || {}
28
- @ssl = options[:ssl] || {}
29
- @parallel_manager = options[:parallel]
30
- self.url_prefix = url if url
31
- proxy(options[:proxy])
32
- merge_params @params, options[:params] if options[:params]
33
- merge_headers @headers, options[:headers] if options[:headers]
34
-
35
- if block_given?
36
- @builder = Builder.create { |b| yield b }
59
+ options = ConnectionOptions.from(url)
60
+ url = options.url
37
61
  else
38
- @builder = options[:builder] || Builder.new
62
+ options = ConnectionOptions.from(options)
39
63
  end
40
- end
41
64
 
42
- def use(klass, *args, &block)
43
- @builder.use(klass, *args, &block)
44
- end
65
+ @parallel_manager = nil
66
+ @headers = Utils::Headers.new
67
+ @params = Utils::ParamsHash.new
68
+ @options = options.request
69
+ @ssl = options.ssl
70
+ @default_parallel_manager = options.parallel_manager
45
71
 
46
- def request(key, *args, &block)
47
- @builder.request(key, *args, &block)
48
- end
72
+ @builder = options.builder || begin
73
+ # pass an empty block to Builder so it doesn't assume default middleware
74
+ options.new_builder(block_given? ? Proc.new { |b| } : nil)
75
+ end
49
76
 
50
- def response(key, *args, &block)
51
- @builder.response(key, *args, &block)
52
- end
77
+ self.url_prefix = url || 'http:/'
78
+
79
+ @params.update(options.params) if options.params
80
+ @headers.update(options.headers) if options.headers
81
+
82
+ @proxy = nil
83
+ proxy(options.fetch(:proxy) {
84
+ uri = ENV['http_proxy']
85
+ if uri && !uri.empty?
86
+ uri = 'http://' + uri if uri !~ /^http/i
87
+ uri
88
+ end
89
+ })
53
90
 
54
- def adapter(key, *args, &block)
55
- @builder.adapter(key, *args, &block)
91
+ yield(self) if block_given?
92
+
93
+ @headers[:user_agent] ||= "Faraday v#{VERSION}"
56
94
  end
57
95
 
58
- def build(options = {}, &block)
59
- @builder.build(options, &block)
96
+ # Public: Sets the Hash of URI query unencoded key/value pairs.
97
+ def params=(hash)
98
+ @params.replace hash
60
99
  end
61
100
 
62
- def get(url = nil, headers = nil)
63
- block = block_given? ? Proc.new : nil
64
- run_request(:get, url, nil, headers, &block)
101
+ # Public: Sets the Hash of unencoded HTTP header key/value pairs.
102
+ def headers=(hash)
103
+ @headers.replace hash
65
104
  end
66
105
 
67
- def post(url = nil, body = nil, headers = nil)
68
- block = block_given? ? Proc.new : nil
69
- run_request(:post, url, body, headers, &block)
106
+ extend Forwardable
107
+
108
+ def_delegators :builder, :build, :use, :request, :response, :adapter, :app
109
+
110
+ # Public: Makes an HTTP request without a body.
111
+ #
112
+ # url - The optional String base URL to use as a prefix for all
113
+ # requests. Can also be the options Hash.
114
+ # params - Hash of URI query unencoded key/value pairs.
115
+ # headers - Hash of unencoded HTTP header key/value pairs.
116
+ #
117
+ # Examples
118
+ #
119
+ # conn.get '/items', {:page => 1}, :accept => 'application/json'
120
+ # conn.head '/items/1'
121
+ #
122
+ # # ElasticSearch example sending a body with GET.
123
+ # conn.get '/twitter/tweet/_search' do |req|
124
+ # req.headers[:content_type] = 'application/json'
125
+ # req.params[:routing] = 'kimchy'
126
+ # req.body = JSON.generate(:query => {...})
127
+ # end
128
+ #
129
+ # Yields a Faraday::Response for further request customizations.
130
+ # Returns a Faraday::Response.
131
+ #
132
+ # Signature
133
+ #
134
+ # <verb>(url = nil, params = nil, headers = nil)
135
+ #
136
+ # verb - An HTTP verb: get, head, or delete.
137
+ %w[get head delete].each do |method|
138
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
139
+ def #{method}(url = nil, params = nil, headers = nil)
140
+ run_request(:#{method}, url, nil, headers) { |request|
141
+ request.params.update(params) if params
142
+ yield(request) if block_given?
143
+ }
144
+ end
145
+ RUBY
70
146
  end
71
147
 
72
- def put(url = nil, body = nil, headers = nil)
73
- block = block_given? ? Proc.new : nil
74
- run_request(:put, url, body, headers, &block)
148
+ # Public: Makes an HTTP request with a body.
149
+ #
150
+ # url - The optional String base URL to use as a prefix for all
151
+ # requests. Can also be the options Hash.
152
+ # body - The String body for the request.
153
+ # headers - Hash of unencoded HTTP header key/value pairs.
154
+ #
155
+ # Examples
156
+ #
157
+ # conn.post '/items', data, :content_type => 'application/json'
158
+ #
159
+ # # Simple ElasticSearch indexing sample.
160
+ # conn.post '/twitter/tweet' do |req|
161
+ # req.headers[:content_type] = 'application/json'
162
+ # req.params[:routing] = 'kimchy'
163
+ # req.body = JSON.generate(:user => 'kimchy', ...)
164
+ # end
165
+ #
166
+ # Yields a Faraday::Response for further request customizations.
167
+ # Returns a Faraday::Response.
168
+ #
169
+ # Signature
170
+ #
171
+ # <verb>(url = nil, body = nil, headers = nil)
172
+ #
173
+ # verb - An HTTP verb: post, put, or patch.
174
+ %w[post put patch].each do |method|
175
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
176
+ def #{method}(url = nil, body = nil, headers = nil, &block)
177
+ run_request(:#{method}, url, body, headers, &block)
178
+ end
179
+ RUBY
75
180
  end
76
181
 
77
- def head(url = nil, headers = nil)
78
- block = block_given? ? Proc.new : nil
79
- run_request(:head, url, nil, headers, &block)
182
+ # Public: Sets up the Authorization header with these credentials, encoded
183
+ # with base64.
184
+ #
185
+ # login - The authentication login.
186
+ # pass - The authentication password.
187
+ #
188
+ # Examples
189
+ #
190
+ # conn.basic_auth 'Aladdin', 'open sesame'
191
+ # conn.headers['Authorization']
192
+ # # => "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
193
+ #
194
+ # Returns nothing.
195
+ def basic_auth(login, pass)
196
+ set_authorization_header(:basic_auth, login, pass)
80
197
  end
81
198
 
82
- def delete(url = nil, headers = nil)
83
- block = block_given? ? Proc.new : nil
84
- run_request(:delete, url, nil, headers, &block)
199
+ # Public: Sets up the Authorization header with the given token.
200
+ #
201
+ # token - The String token.
202
+ # options - Optional Hash of extra token options.
203
+ #
204
+ # Examples
205
+ #
206
+ # conn.token_auth 'abcdef', :foo => 'bar'
207
+ # conn.headers['Authorization']
208
+ # # => "Token token=\"abcdef\",
209
+ # foo=\"bar\""
210
+ #
211
+ # Returns nothing.
212
+ def token_auth(token, options = nil)
213
+ set_authorization_header(:token_auth, token, options)
85
214
  end
86
215
 
87
- def basic_auth(login, pass)
88
- auth = Base64.encode64("#{login}:#{pass}")
89
- auth.gsub!("\n", "")
90
- @headers['authorization'] = "Basic #{auth}"
216
+ # Public: Sets up a custom Authorization header.
217
+ #
218
+ # type - The String authorization type.
219
+ # token - The String or Hash token. A String value is taken literally, and
220
+ # a Hash is encoded into comma separated key/value pairs.
221
+ #
222
+ # Examples
223
+ #
224
+ # conn.authorization :Bearer, 'mF_9.B5f-4.1JqM'
225
+ # conn.headers['Authorization']
226
+ # # => "Bearer mF_9.B5f-4.1JqM"
227
+ #
228
+ # conn.authorization :Token, :token => 'abcdef', :foo => 'bar'
229
+ # conn.headers['Authorization']
230
+ # # => "Token token=\"abcdef\",
231
+ # foo=\"bar\""
232
+ #
233
+ # Returns nothing.
234
+ def authorization(type, token)
235
+ set_authorization_header(:authorization, type, token)
91
236
  end
92
237
 
93
- def token_auth(token, options = {})
94
- values = ["token=#{token.to_s.inspect}"]
95
- options.each do |key, value|
96
- values << "#{key}=#{value.to_s.inspect}"
238
+ # Internal: Traverse the middleware stack in search of a
239
+ # parallel-capable adapter.
240
+ #
241
+ # Yields in case of not found.
242
+ #
243
+ # Returns a parallel manager or nil if not found.
244
+ def default_parallel_manager
245
+ @default_parallel_manager ||= begin
246
+ handler = @builder.handlers.detect do |h|
247
+ h.klass.respond_to?(:supports_parallel?) and h.klass.supports_parallel?
248
+ end
249
+
250
+ if handler
251
+ handler.klass.setup_parallel_manager
252
+ elsif block_given?
253
+ yield
254
+ end
97
255
  end
98
- # 21 = "Authorization: Token ".size
99
- comma = ",\n#{' ' * 21}"
100
- @headers['authorization'] = "Token #{values * comma}"
101
256
  end
102
257
 
258
+ # Public: Determine if this Faraday::Connection can make parallel requests.
259
+ #
260
+ # Returns true or false.
103
261
  def in_parallel?
104
262
  !!@parallel_manager
105
263
  end
106
264
 
107
- def in_parallel(manager)
108
- @parallel_manager = manager
265
+ # Public: Sets up the parallel manager to make a set of requests.
266
+ #
267
+ # manager - The parallel manager that this Connection's Adapter uses.
268
+ #
269
+ # Yields a block to execute multiple requests.
270
+ # Returns nothing.
271
+ def in_parallel(manager = nil)
272
+ @parallel_manager = manager || default_parallel_manager {
273
+ warn "Warning: `in_parallel` called but no parallel-capable adapter on Faraday stack"
274
+ warn caller[2,10].join("\n")
275
+ nil
276
+ }
109
277
  yield
110
278
  @parallel_manager && @parallel_manager.run
111
279
  ensure
112
280
  @parallel_manager = nil
113
281
  end
114
282
 
283
+ # Public: Gets or Sets the Hash proxy options.
115
284
  def proxy(arg = nil)
116
285
  return @proxy if arg.nil?
117
-
118
- @proxy =
119
- case arg
120
- when String then {:uri => proxy_arg_to_uri(arg)}
121
- when URI then {:uri => arg}
122
- when Hash
123
- if arg[:uri] = proxy_arg_to_uri(arg[:uri])
124
- arg
125
- else
126
- raise ArgumentError, "no :uri option."
127
- end
128
- end
286
+ @proxy = ProxyOptions.from(arg)
129
287
  end
130
288
 
131
- # Parses the giving url with Addressable::URI and stores the individual
289
+ def_delegators :url_prefix, :scheme, :scheme=, :host, :host=, :port, :port=
290
+ def_delegator :url_prefix, :path, :path_prefix
291
+
292
+ # Public: Parses the giving url with URI and stores the individual
132
293
  # components in this connection. These components serve as defaults for
133
294
  # requests made by this connection.
134
295
  #
296
+ # url - A String or URI.
297
+ #
298
+ # Examples
299
+ #
135
300
  # conn = Faraday::Connection.new { ... }
136
301
  # conn.url_prefix = "https://sushi.com/api"
137
302
  # conn.scheme # => https
@@ -139,86 +304,129 @@ module Faraday
139
304
  #
140
305
  # conn.get("nigiri?page=2") # accesses https://sushi.com/api/nigiri
141
306
  #
142
- def url_prefix=(url)
143
- uri = URI.parse(url)
144
- self.scheme = uri.scheme
145
- self.host = uri.host
146
- self.port = uri.port
307
+ # Returns the parsed URI from teh given input..
308
+ def url_prefix=(url, encoder = nil)
309
+ uri = @url_prefix = Utils.URI(url)
147
310
  self.path_prefix = uri.path
148
- if uri.query && !uri.query.empty?
149
- merge_params @params, parse_query(uri.query)
150
- end
151
- if uri.user && uri.password
152
- basic_auth(uri.user, uri.password)
311
+
312
+ params.merge_query(uri.query, encoder)
313
+ uri.query = nil
314
+
315
+ with_uri_credentials(uri) do |user, password|
316
+ basic_auth user, password
317
+ uri.user = uri.password = nil
153
318
  end
319
+
320
+ uri
154
321
  end
155
322
 
156
- # Ensures that the path prefix always has a leading / and no trailing /
323
+ # Public: Sets the path prefix and ensures that it always has a leading
324
+ # slash.
325
+ #
326
+ # value - A String.
327
+ #
328
+ # Returns the new String path prefix.
157
329
  def path_prefix=(value)
158
- if value
159
- value.chomp! "/"
160
- value.replace "/#{value}" if value !~ /^\//
330
+ url_prefix.path = if value
331
+ value = '/' + value unless value[0,1] == '/'
332
+ value
161
333
  end
162
- @path_prefix = value
163
334
  end
164
335
 
336
+ # Public: Takes a relative url for a request and combines it with the defaults
337
+ # set on the connection instance.
338
+ #
339
+ # conn = Faraday::Connection.new { ... }
340
+ # conn.url_prefix = "https://sushi.com/api?token=abc"
341
+ # conn.scheme # => https
342
+ # conn.path_prefix # => "/api"
343
+ #
344
+ # conn.build_url("nigiri?page=2") # => https://sushi.com/api/nigiri?token=abc&page=2
345
+ # conn.build_url("nigiri", :page => 2) # => https://sushi.com/api/nigiri?token=abc&page=2
346
+ #
347
+ def build_url(url = nil, extra_params = nil)
348
+ uri = build_exclusive_url(url)
349
+
350
+ query_values = params.dup.merge_query(uri.query, options.params_encoder)
351
+ query_values.update extra_params if extra_params
352
+ uri.query = query_values.empty? ? nil : query_values.to_query(options.params_encoder)
353
+
354
+ uri
355
+ end
356
+
357
+ # Builds and runs the Faraday::Request.
358
+ #
359
+ # method - The Symbol HTTP method.
360
+ # url - The String or URI to access.
361
+ # body - The String body
362
+ # headers - Hash of unencoded HTTP header key/value pairs.
363
+ #
364
+ # Returns a Faraday::Response.
165
365
  def run_request(method, url, body, headers)
166
366
  if !METHODS.include?(method)
167
367
  raise ArgumentError, "unknown http method: #{method}"
168
368
  end
169
369
 
170
- Request.run(self, method) do |req|
370
+ request = build_request(method) do |req|
171
371
  req.url(url) if url
172
372
  req.headers.update(headers) if headers
173
373
  req.body = body if body
174
- yield req if block_given?
374
+ yield(req) if block_given?
175
375
  end
376
+
377
+ builder.build_response(self, request)
176
378
  end
177
379
 
178
- # Takes a relative url for a request and combines it with the defaults
179
- # set on the connection instance.
380
+ # Creates and configures the request object.
180
381
  #
181
- # conn = Faraday::Connection.new { ... }
182
- # conn.url_prefix = "https://sushi.com/api?token=abc"
183
- # conn.scheme # => https
184
- # conn.path_prefix # => "/api"
382
+ # Returns the new Request.
383
+ def build_request(method)
384
+ Request.create(method) do |req|
385
+ req.params = self.params.dup
386
+ req.headers = self.headers.dup
387
+ req.options = self.options.merge(:proxy => self.proxy)
388
+ yield(req) if block_given?
389
+ end
390
+ end
391
+
392
+ # Internal: Build an absolute URL based on url_prefix.
185
393
  #
186
- # conn.build_url("nigiri?page=2") # => https://sushi.com/api/nigiri?token=abc&page=2
187
- # conn.build_url("nigiri", :page => 2) # => https://sushi.com/api/nigiri?token=abc&page=2
394
+ # url - A String or URI-like object
395
+ # params - A Faraday::Utils::ParamsHash to replace the query values
396
+ # of the resulting url (default: nil).
188
397
  #
189
- def build_url(url, params = nil)
190
- uri = URI.parse(url.to_s)
191
- if @path_prefix && uri.path !~ /^\//
192
- uri.path = "#{@path_prefix.size > 1 ? @path_prefix : nil}/#{uri.path}"
398
+ # Returns the resulting URI instance.
399
+ def build_exclusive_url(url = nil, params = nil)
400
+ url = nil if url.respond_to?(:empty?) and url.empty?
401
+ base = url_prefix
402
+ if url and base.path and base.path !~ /\/$/
403
+ base = base.dup
404
+ base.path = base.path + '/' # ensure trailing slash
193
405
  end
194
- uri.host ||= @host
195
- uri.port ||= @port
196
- uri.scheme ||= @scheme
197
- replace_query(uri, params)
406
+ uri = url ? base + url : base
407
+ uri.query = params.to_query(options.params_encoder) if params
408
+ uri.query = nil if uri.query and uri.query.empty?
198
409
  uri
199
410
  end
200
411
 
412
+ # Internal: Creates a duplicate of this Faraday::Connection.
413
+ #
414
+ # Returns a Faraday::Connection.
201
415
  def dup
202
- self.class.new(build_url(''), :headers => headers.dup, :params => params.dup, :builder => builder.dup)
416
+ self.class.new(build_exclusive_url, :headers => headers.dup, :params => params.dup, :builder => builder.dup, :ssl => ssl.dup)
203
417
  end
204
418
 
205
- def replace_query(uri, params)
206
- url_params = @params.dup
207
- if uri.query && !uri.query.empty?
208
- merge_params(url_params, parse_query(uri.query))
419
+ # Internal: Yields username and password extracted from a URI if they both exist.
420
+ def with_uri_credentials(uri)
421
+ if uri.user and uri.password
422
+ yield(Utils.unescape(uri.user), Utils.unescape(uri.password))
209
423
  end
210
- if params && !params.empty?
211
- merge_params(url_params, params)
212
- end
213
- uri.query = url_params.empty? ? nil : build_query(url_params)
214
- uri
215
424
  end
216
425
 
217
- def proxy_arg_to_uri(arg)
218
- case arg
219
- when String then URI.parse(arg)
220
- when URI then arg
221
- end
426
+ def set_authorization_header(header_type, *args)
427
+ header = Faraday::Request.lookup_middleware(header_type).
428
+ header(*args)
429
+ headers[Faraday::Request::Authorization::KEY] = header
222
430
  end
223
431
  end
224
432
  end
data/lib/faraday/error.rb CHANGED
@@ -1,38 +1,53 @@
1
1
  module Faraday
2
- module Error
3
- class ClientError < StandardError
4
- attr_reader :response
5
-
6
- def initialize(ex)
7
- @wrapped_exception = nil
8
- @response = nil
9
-
10
- if ex.respond_to?(:backtrace)
11
- super(ex.message)
12
- @wrapped_exception = ex
13
- elsif ex.respond_to?(:each_key)
14
- super("the server responded with status #{ex[:status]}")
15
- @response = ex
16
- else
17
- super(ex.to_s)
18
- end
19
- end
2
+ class Error < StandardError; end
3
+ class MissingDependency < Error; end
4
+
5
+ class ClientError < Error
6
+ attr_reader :response
20
7
 
21
- def backtrace
22
- if @wrapped_exception
23
- @wrapped_exception.backtrace
24
- else
25
- super
26
- end
8
+ def initialize(ex, response = nil)
9
+ @wrapped_exception = nil
10
+ @response = response
11
+
12
+ if ex.respond_to?(:backtrace)
13
+ super(ex.message)
14
+ @wrapped_exception = ex
15
+ elsif ex.respond_to?(:each_key)
16
+ super("the server responded with status #{ex[:status]}")
17
+ @response = ex
18
+ else
19
+ super(ex.to_s)
27
20
  end
21
+ end
28
22
 
29
- def inspect
30
- %(#<#{self.class}>)
23
+ def backtrace
24
+ if @wrapped_exception
25
+ @wrapped_exception.backtrace
26
+ else
27
+ super
31
28
  end
32
29
  end
33
30
 
34
- class ConnectionFailed < ClientError; end
35
- class ResourceNotFound < ClientError; end
36
- class ParsingError < ClientError; end
31
+ def inspect
32
+ %(#<#{self.class}>)
33
+ end
34
+ end
35
+
36
+ class ConnectionFailed < ClientError; end
37
+ class ResourceNotFound < ClientError; end
38
+ class ParsingError < ClientError; end
39
+
40
+ class TimeoutError < ClientError
41
+ def initialize(ex = nil)
42
+ super(ex || "timeout")
43
+ end
44
+ end
45
+
46
+ class SSLError < ClientError
47
+ end
48
+
49
+ [:MissingDependency, :ClientError, :ConnectionFailed, :ResourceNotFound,
50
+ :ParsingError, :TimeoutError, :SSLError].each do |const|
51
+ Error.const_set(const, Faraday.const_get(const))
37
52
  end
38
53
  end