faraday 0.8.11 → 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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/.document +6 -0
  3. data/CHANGELOG.md +15 -0
  4. data/CONTRIBUTING.md +36 -0
  5. data/Gemfile +10 -3
  6. data/LICENSE.md +1 -1
  7. data/README.md +17 -51
  8. data/Rakefile +2 -18
  9. data/faraday.gemspec +34 -0
  10. data/lib/faraday/adapter/em_http.rb +34 -0
  11. data/lib/faraday/adapter/em_http_ssl_patch.rb +56 -0
  12. data/lib/faraday/adapter/em_synchrony.rb +11 -24
  13. data/lib/faraday/adapter/excon.rb +12 -2
  14. data/lib/faraday/adapter/httpclient.rb +106 -0
  15. data/lib/faraday/adapter/net_http.rb +10 -6
  16. data/lib/faraday/adapter/patron.rb +2 -8
  17. data/lib/faraday/adapter/rack.rb +0 -2
  18. data/lib/faraday/adapter/test.rb +39 -39
  19. data/lib/faraday/adapter/typhoeus.rb +12 -3
  20. data/lib/faraday/adapter.rb +20 -35
  21. data/lib/faraday/autoload.rb +85 -0
  22. data/lib/faraday/connection.rb +232 -125
  23. data/lib/faraday/error.rb +42 -34
  24. data/lib/faraday/options.rb +350 -0
  25. data/lib/faraday/parameters.rb +193 -0
  26. data/lib/faraday/{builder.rb → rack_builder.rb} +79 -22
  27. data/lib/faraday/request/authorization.rb +7 -5
  28. data/lib/faraday/request/basic_authentication.rb +1 -1
  29. data/lib/faraday/request/instrumentation.rb +36 -0
  30. data/lib/faraday/request/multipart.rb +10 -9
  31. data/lib/faraday/request/retry.rb +99 -4
  32. data/lib/faraday/request/token_authentication.rb +2 -2
  33. data/lib/faraday/request/url_encoded.rb +7 -6
  34. data/lib/faraday/request.rb +21 -30
  35. data/lib/faraday/response/logger.rb +4 -4
  36. data/lib/faraday/response/raise_error.rb +4 -2
  37. data/lib/faraday/response.rb +17 -23
  38. data/lib/faraday/utils.rb +81 -71
  39. data/lib/faraday.rb +187 -68
  40. data/script/console +7 -0
  41. data/script/proxy-server +1 -0
  42. data/script/release +6 -3
  43. data/script/test +4 -2
  44. data/test/adapters/em_http_test.rb +6 -1
  45. data/test/adapters/em_synchrony_test.rb +7 -1
  46. data/test/adapters/httpclient_test.rb +21 -0
  47. data/test/adapters/integration.rb +23 -8
  48. data/test/adapters/logger_test.rb +1 -1
  49. data/test/adapters/net_http_persistent_test.rb +10 -1
  50. data/test/adapters/net_http_test.rb +0 -31
  51. data/test/adapters/patron_test.rb +4 -1
  52. data/test/adapters/test_middleware_test.rb +48 -4
  53. data/test/adapters/typhoeus_test.rb +8 -1
  54. data/test/authentication_middleware_test.rb +2 -2
  55. data/test/connection_test.rb +160 -84
  56. data/test/env_test.rb +51 -24
  57. data/test/helper.rb +13 -13
  58. data/test/live_server.rb +8 -0
  59. data/test/middleware/instrumentation_test.rb +88 -0
  60. data/test/middleware/retry_test.rb +88 -35
  61. data/test/middleware_stack_test.rb +13 -12
  62. data/test/options_test.rb +252 -0
  63. data/test/request_middleware_test.rb +11 -1
  64. data/test/response_middleware_test.rb +2 -4
  65. data/test/strawberry.rb +2 -0
  66. data/test/utils_test.rb +34 -6
  67. metadata +71 -11
  68. data/test/parameters_test.rb +0 -24
@@ -0,0 +1,350 @@
1
+ module Faraday
2
+ # Subclasses Struct with some special helpers for converting from a Hash to
3
+ # a Struct.
4
+ class Options < Struct
5
+ # Public
6
+ def self.from(value)
7
+ value ? new.update(value) : new
8
+ end
9
+
10
+ # Public
11
+ def each
12
+ return to_enum(:each) unless block_given?
13
+ members.each do |key|
14
+ yield(key.to_sym, send(key))
15
+ end
16
+ end
17
+
18
+ # Public
19
+ def update(obj)
20
+ obj.each do |key, value|
21
+ if sub_options = self.class.options_for(key)
22
+ value = sub_options.from(value) if value
23
+ elsif Hash === value
24
+ hash = {}
25
+ value.each do |hash_key, hash_value|
26
+ hash[hash_key] = hash_value
27
+ end
28
+ value = hash
29
+ end
30
+
31
+ self.send("#{key}=", value) unless value.nil?
32
+ end
33
+ self
34
+ end
35
+
36
+ alias merge! update
37
+
38
+ # Public
39
+ def delete(key)
40
+ value = send(key)
41
+ send("#{key}=", nil)
42
+ value
43
+ end
44
+
45
+ # Public
46
+ def clear
47
+ members.each { |member| delete(member) }
48
+ end
49
+
50
+ # Public
51
+ def merge(value)
52
+ dup.update(value)
53
+ end
54
+
55
+ # Public
56
+ def fetch(key, *args)
57
+ unless symbolized_key_set.include?(key.to_sym)
58
+ key_setter = "#{key}="
59
+ if args.size > 0
60
+ send(key_setter, args.first)
61
+ elsif block_given?
62
+ send(key_setter, Proc.new.call(key))
63
+ else
64
+ raise self.class.fetch_error_class, "key not found: #{key.inspect}"
65
+ end
66
+ end
67
+ send(key)
68
+ end
69
+
70
+ # Public
71
+ def values_at(*keys)
72
+ keys.map { |key| send(key) }
73
+ end
74
+
75
+ # Public
76
+ def keys
77
+ members.reject { |member| send(member).nil? }
78
+ end
79
+
80
+ # Public
81
+ def empty?
82
+ keys.empty?
83
+ end
84
+
85
+ # Public
86
+ def each_key
87
+ return to_enum(:each_key) unless block_given?
88
+ keys.each do |key|
89
+ yield(key)
90
+ end
91
+ end
92
+
93
+ # Public
94
+ def key?(key)
95
+ keys.include?(key)
96
+ end
97
+
98
+ alias has_key? key?
99
+
100
+ # Public
101
+ def each_value
102
+ return to_enum(:each_value) unless block_given?
103
+ values.each do |value|
104
+ yield(value)
105
+ end
106
+ end
107
+
108
+ # Public
109
+ def value?(value)
110
+ values.include?(value)
111
+ end
112
+
113
+ alias has_value? value?
114
+
115
+ # Public
116
+ def to_hash
117
+ hash = {}
118
+ members.each do |key|
119
+ value = send(key)
120
+ hash[key.to_sym] = value unless value.nil?
121
+ end
122
+ hash
123
+ end
124
+
125
+ # Internal
126
+ def inspect
127
+ values = []
128
+ members.each do |member|
129
+ value = send(member)
130
+ values << "#{member}=#{value.inspect}" if value
131
+ end
132
+ values = values.empty? ? ' (empty)' : (' ' << values.join(", "))
133
+
134
+ %(#<#{self.class}#{values}>)
135
+ end
136
+
137
+ # Internal
138
+ def self.options(mapping)
139
+ attribute_options.update(mapping)
140
+ end
141
+
142
+ # Internal
143
+ def self.options_for(key)
144
+ attribute_options[key]
145
+ end
146
+
147
+ # Internal
148
+ def self.attribute_options
149
+ @attribute_options ||= {}
150
+ end
151
+
152
+ def self.memoized(key)
153
+ memoized_attributes[key.to_sym] = Proc.new
154
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
155
+ def #{key}() self[:#{key}]; end
156
+ RUBY
157
+ end
158
+
159
+ def self.memoized_attributes
160
+ @memoized_attributes ||= {}
161
+ end
162
+
163
+ def [](key)
164
+ key = key.to_sym
165
+ if method = self.class.memoized_attributes[key]
166
+ super(key) || (self[key] = instance_eval(&method))
167
+ else
168
+ super
169
+ end
170
+ end
171
+
172
+ def symbolized_key_set
173
+ @symbolized_key_set ||= Set.new(keys.map { |k| k.to_sym })
174
+ end
175
+
176
+ def self.inherited(subclass)
177
+ super
178
+ subclass.attribute_options.update(attribute_options)
179
+ subclass.memoized_attributes.update(memoized_attributes)
180
+ end
181
+
182
+ def self.fetch_error_class
183
+ @fetch_error_class ||= if Object.const_defined?(:KeyError)
184
+ ::KeyError
185
+ else
186
+ ::IndexError
187
+ end
188
+ end
189
+ end
190
+
191
+ class RequestOptions < Options.new(:params_encoder, :proxy, :bind,
192
+ :timeout, :open_timeout, :boundary,
193
+ :oauth)
194
+
195
+ def []=(key, value)
196
+ if key && key.to_sym == :proxy
197
+ super(key, value ? ProxyOptions.from(value) : nil)
198
+ else
199
+ super(key, value)
200
+ end
201
+ end
202
+ end
203
+
204
+ class SSLOptions < Options.new(:verify, :ca_file, :ca_path, :verify_mode,
205
+ :cert_store, :client_cert, :client_key, :certificate, :private_key, :verify_depth, :version)
206
+
207
+ def verify?
208
+ verify != false
209
+ end
210
+
211
+ def disable?
212
+ !verify?
213
+ end
214
+ end
215
+
216
+ class ProxyOptions < Options.new(:uri, :user, :password)
217
+ extend Forwardable
218
+ def_delegators :uri, :scheme, :scheme=, :host, :host=, :port, :port=, :path, :path=
219
+
220
+ def self.from(value)
221
+ case value
222
+ when String
223
+ value = {:uri => Utils.URI(value)}
224
+ when URI
225
+ value = {:uri => value}
226
+ when Hash, Options
227
+ if uri = value.delete(:uri)
228
+ value[:uri] = Utils.URI(uri)
229
+ end
230
+ end
231
+ super(value)
232
+ end
233
+
234
+ memoized(:user) { uri.user && Utils.unescape(uri.user) }
235
+ memoized(:password) { uri.password && Utils.unescape(uri.password) }
236
+ end
237
+
238
+ class ConnectionOptions < Options.new(:request, :proxy, :ssl, :builder, :url,
239
+ :parallel_manager, :params, :headers, :builder_class)
240
+
241
+ options :request => RequestOptions, :ssl => SSLOptions
242
+
243
+ memoized(:request) { self.class.options_for(:request).new }
244
+
245
+ memoized(:ssl) { self.class.options_for(:ssl).new }
246
+
247
+ memoized(:builder_class) { RackBuilder }
248
+
249
+ def new_builder(block)
250
+ builder_class.new(&block)
251
+ end
252
+ end
253
+
254
+ class Env < Options.new(:method, :body, :url, :request, :request_headers,
255
+ :ssl, :parallel_manager, :params, :response, :response_headers, :status)
256
+
257
+ ContentLength = 'Content-Length'.freeze
258
+ StatusesWithoutBody = Set.new [204, 304]
259
+ SuccessfulStatuses = 200..299
260
+
261
+ # A Set of HTTP verbs that typically send a body. If no body is set for
262
+ # these requests, the Content-Length header is set to 0.
263
+ MethodsWithBodies = Set.new [:post, :put, :patch, :options]
264
+
265
+ options :request => RequestOptions,
266
+ :request_headers => Utils::Headers, :response_headers => Utils::Headers
267
+
268
+ extend Forwardable
269
+
270
+ def_delegators :request, :params_encoder
271
+
272
+ # Public
273
+ def [](key)
274
+ if in_member_set?(key)
275
+ super(key)
276
+ else
277
+ custom_members[key]
278
+ end
279
+ end
280
+
281
+ # Public
282
+ def []=(key, value)
283
+ if in_member_set?(key)
284
+ super(key, value)
285
+ else
286
+ custom_members[key] = value
287
+ end
288
+ end
289
+
290
+ # Public
291
+ def success?
292
+ SuccessfulStatuses.include?(status)
293
+ end
294
+
295
+ # Public
296
+ def needs_body?
297
+ !body && MethodsWithBodies.include?(method)
298
+ end
299
+
300
+ # Public
301
+ def clear_body
302
+ request_headers[ContentLength] = '0'
303
+ self.body = ''
304
+ end
305
+
306
+ # Public
307
+ def parse_body?
308
+ !StatusesWithoutBody.include?(status)
309
+ end
310
+
311
+ # Public
312
+ def parallel?
313
+ !!parallel_manager
314
+ end
315
+
316
+ def inspect
317
+ attrs = [nil]
318
+ members.each do |mem|
319
+ if value = send(mem)
320
+ attrs << "@#{mem}=#{value.inspect}"
321
+ end
322
+ end
323
+ if !custom_members.empty?
324
+ attrs << "@custom=#{custom_members.inspect}"
325
+ end
326
+ %(#<#{self.class}#{attrs.join(" ")}>)
327
+ end
328
+
329
+ # Internal
330
+ def custom_members
331
+ @custom_members ||= {}
332
+ end
333
+
334
+ # Internal
335
+ if members.first.is_a?(Symbol)
336
+ def in_member_set?(key)
337
+ self.class.member_set.include?(key.to_sym)
338
+ end
339
+ else
340
+ def in_member_set?(key)
341
+ self.class.member_set.include?(key.to_s)
342
+ end
343
+ end
344
+
345
+ # Internal
346
+ def self.member_set
347
+ @member_set ||= Set.new(members)
348
+ end
349
+ end
350
+ end
@@ -0,0 +1,193 @@
1
+ module Faraday
2
+ module NestedParamsEncoder
3
+ ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/
4
+
5
+ def self.escape(s)
6
+ return s.to_s.gsub(ESCAPE_RE) {
7
+ '%' + $&.unpack('H2' * $&.bytesize).join('%').upcase
8
+ }.tr(' ', '+')
9
+ end
10
+
11
+ def self.unescape(s)
12
+ CGI.unescape(s.to_s)
13
+ end
14
+
15
+ def self.encode(params)
16
+ return nil if params == nil
17
+
18
+ if !params.is_a?(Array)
19
+ if !params.respond_to?(:to_hash)
20
+ raise TypeError,
21
+ "Can't convert #{params.class} into Hash."
22
+ end
23
+ params = params.to_hash
24
+ params = params.map do |key, value|
25
+ key = key.to_s if key.kind_of?(Symbol)
26
+ [key, value]
27
+ end
28
+ # Useful default for OAuth and caching.
29
+ # Only to be used for non-Array inputs. Arrays should preserve order.
30
+ params.sort!
31
+ end
32
+
33
+ # Helper lambda
34
+ to_query = lambda do |parent, value|
35
+ if value.is_a?(Hash)
36
+ value = value.map do |key, val|
37
+ key = escape(key)
38
+ [key, val]
39
+ end
40
+ value.sort!
41
+ buffer = ""
42
+ value.each do |key, val|
43
+ new_parent = "#{parent}%5B#{key}%5D"
44
+ buffer << "#{to_query.call(new_parent, val)}&"
45
+ end
46
+ return buffer.chop
47
+ elsif value.is_a?(Array)
48
+ buffer = ""
49
+ value.each_with_index do |val, i|
50
+ new_parent = "#{parent}%5B%5D"
51
+ buffer << "#{to_query.call(new_parent, val)}&"
52
+ end
53
+ return buffer.chop
54
+ else
55
+ encoded_value = escape(value)
56
+ return "#{parent}=#{encoded_value}"
57
+ end
58
+ end
59
+
60
+ # The params have form [['key1', 'value1'], ['key2', 'value2']].
61
+ buffer = ''
62
+ params.each do |parent, value|
63
+ encoded_parent = escape(parent)
64
+ buffer << "#{to_query.call(encoded_parent, value)}&"
65
+ end
66
+ return buffer.chop
67
+ end
68
+
69
+ def self.decode(query)
70
+ return nil if query == nil
71
+ # Recursive helper lambda
72
+ dehash = lambda do |hash|
73
+ hash.each do |(key, value)|
74
+ if value.kind_of?(Hash)
75
+ hash[key] = dehash.call(value)
76
+ end
77
+ end
78
+ # Numeric keys implies an array
79
+ if hash != {} && hash.keys.all? { |key| key =~ /^\d+$/ }
80
+ hash.sort.inject([]) do |accu, (_, value)|
81
+ accu << value; accu
82
+ end
83
+ else
84
+ hash
85
+ end
86
+ end
87
+
88
+ empty_accumulator = {}
89
+ return ((query.split('&').map do |pair|
90
+ pair.split('=', 2) if pair && !pair.empty?
91
+ end).compact.inject(empty_accumulator.dup) do |accu, (key, value)|
92
+ key = unescape(key)
93
+ if value.kind_of?(String)
94
+ value = unescape(value.gsub(/\+/, ' '))
95
+ end
96
+
97
+ array_notation = !!(key =~ /\[\]$/)
98
+ subkeys = key.split(/[\[\]]+/)
99
+ current_hash = accu
100
+ for i in 0...(subkeys.size - 1)
101
+ subkey = subkeys[i]
102
+ current_hash[subkey] = {} unless current_hash[subkey]
103
+ current_hash = current_hash[subkey]
104
+ end
105
+ if array_notation
106
+ current_hash[subkeys.last] = [] unless current_hash[subkeys.last]
107
+ current_hash[subkeys.last] << value
108
+ else
109
+ current_hash[subkeys.last] = value
110
+ end
111
+ accu
112
+ end).inject(empty_accumulator.dup) do |accu, (key, value)|
113
+ accu[key] = value.kind_of?(Hash) ? dehash.call(value) : value
114
+ accu
115
+ end
116
+ end
117
+ end
118
+
119
+ module FlatParamsEncoder
120
+ ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/
121
+
122
+ def self.escape(s)
123
+ return s.to_s.gsub(ESCAPE_RE) {
124
+ '%' + $&.unpack('H2' * $&.bytesize).join('%').upcase
125
+ }.tr(' ', '+')
126
+ end
127
+
128
+ def self.unescape(s)
129
+ CGI.unescape(s.to_s)
130
+ end
131
+
132
+ def self.encode(params)
133
+ return nil if params == nil
134
+
135
+ if !params.is_a?(Array)
136
+ if !params.respond_to?(:to_hash)
137
+ raise TypeError,
138
+ "Can't convert #{params.class} into Hash."
139
+ end
140
+ params = params.to_hash
141
+ params = params.map do |key, value|
142
+ key = key.to_s if key.kind_of?(Symbol)
143
+ [key, value]
144
+ end
145
+ # Useful default for OAuth and caching.
146
+ # Only to be used for non-Array inputs. Arrays should preserve order.
147
+ params.sort!
148
+ end
149
+
150
+ # The params have form [['key1', 'value1'], ['key2', 'value2']].
151
+ buffer = ''
152
+ params.each do |key, value|
153
+ encoded_key = escape(key)
154
+ value = value.to_s if value == true || value == false
155
+ if value == nil
156
+ buffer << "#{encoded_key}&"
157
+ elsif value.kind_of?(Array)
158
+ value.each do |sub_value|
159
+ encoded_value = escape(sub_value)
160
+ buffer << "#{encoded_key}=#{encoded_value}&"
161
+ end
162
+ else
163
+ encoded_value = escape(value)
164
+ buffer << "#{encoded_key}=#{encoded_value}&"
165
+ end
166
+ end
167
+ return buffer.chop
168
+ end
169
+
170
+ def self.decode(query)
171
+ empty_accumulator = {}
172
+ return nil if query == nil
173
+ split_query = (query.split('&').map do |pair|
174
+ pair.split('=', 2) if pair && !pair.empty?
175
+ end).compact
176
+ return split_query.inject(empty_accumulator.dup) do |accu, pair|
177
+ pair[0] = unescape(pair[0])
178
+ pair[1] = true if pair[1].nil?
179
+ if pair[1].respond_to?(:to_str)
180
+ pair[1] = unescape(pair[1].to_str.gsub(/\+/, " "))
181
+ end
182
+ if accu[pair[0]].kind_of?(Array)
183
+ accu[pair[0]] << pair[1]
184
+ elsif accu[pair[0]]
185
+ accu[pair[0]] = [accu[pair[0]], pair[1]]
186
+ else
187
+ accu[pair[0]] = pair[1]
188
+ end
189
+ accu
190
+ end
191
+ end
192
+ end
193
+ end
@@ -1,11 +1,12 @@
1
1
  module Faraday
2
- # Possibly going to extend this a bit.
2
+ # A Builder that processes requests into responses by passing through an inner
3
+ # middleware stack (heavily inspired by Rack).
3
4
  #
4
- # Faraday::Connection.new(:url => 'http://sushi.com') do |builder|
5
- # builder.request :url_encoded # Faraday::Request::UrlEncoded
6
- # builder.adapter :net_http # Faraday::Adapter::NetHttp
7
- # end
8
- class Builder
5
+ # Faraday::Connection.new(:url => 'http://sushi.com') do |builder|
6
+ # builder.request :url_encoded # Faraday::Request::UrlEncoded
7
+ # builder.adapter :net_http # Faraday::Adapter::NetHttp
8
+ # end
9
+ class RackBuilder
9
10
  attr_accessor :handlers
10
11
 
11
12
  # Error raised when trying to modify the stack after calling `lock!`
@@ -14,15 +15,19 @@ module Faraday
14
15
  # borrowed from ActiveSupport::Dependencies::Reference &
15
16
  # ActionDispatch::MiddlewareStack::Middleware
16
17
  class Handler
18
+ @@constants_mutex = Mutex.new
17
19
  @@constants = Hash.new { |h, k|
18
- h[k] = k.respond_to?(:constantize) ? k.constantize : Object.const_get(k)
20
+ value = k.respond_to?(:constantize) ? k.constantize : Object.const_get(k)
21
+ @@constants_mutex.synchronize { h[k] = value }
19
22
  }
20
23
 
21
24
  attr_reader :name
22
25
 
23
26
  def initialize(klass, *args, &block)
24
27
  @name = klass.to_s
25
- @@constants[@name] = klass if klass.respond_to?(:name)
28
+ if klass.respond_to?(:name)
29
+ @@constants_mutex.synchronize { @@constants[@name] = klass }
30
+ end
26
31
  @args, @block = args, block
27
32
  end
28
33
 
@@ -58,26 +63,13 @@ module Faraday
58
63
  def build(options = {})
59
64
  raise_if_locked
60
65
  @handlers.clear unless options[:keep]
61
- yield self if block_given?
66
+ yield(self) if block_given?
62
67
  end
63
68
 
64
69
  def [](idx)
65
70
  @handlers[idx]
66
71
  end
67
72
 
68
- def ==(other)
69
- other.is_a?(self.class) && @handlers == other.handlers
70
- end
71
-
72
- def dup
73
- self.class.new(@handlers.dup)
74
- end
75
-
76
- def to_app(inner_app)
77
- # last added handler is the deepest and thus closest to the inner app
78
- @handlers.reverse.inject(inner_app) { |app, handler| handler.build(app) }
79
- end
80
-
81
73
  # Locks the middleware stack to ensure no further modifications are possible.
82
74
  def lock!
83
75
  @handlers.freeze
@@ -136,6 +128,71 @@ module Faraday
136
128
  @handlers.delete(handler)
137
129
  end
138
130
 
131
+ # Processes a Request into a Response by passing it through this Builder's
132
+ # middleware stack.
133
+ #
134
+ # connection - Faraday::Connection
135
+ # request - Faraday::Request
136
+ #
137
+ # Returns a Faraday::Response.
138
+ def build_response(connection, request)
139
+ app.call(build_env(connection, request))
140
+ end
141
+
142
+ # The "rack app" wrapped in middleware. All requests are sent here.
143
+ #
144
+ # The builder is responsible for creating the app object. After this,
145
+ # the builder gets locked to ensure no further modifications are made
146
+ # to the middleware stack.
147
+ #
148
+ # Returns an object that responds to `call` and returns a Response.
149
+ def app
150
+ @app ||= begin
151
+ lock!
152
+ to_app(lambda { |env|
153
+ response = Response.new
154
+ response.finish(env) unless env.parallel?
155
+ env.response = response
156
+ })
157
+ end
158
+ end
159
+
160
+ def to_app(inner_app)
161
+ # last added handler is the deepest and thus closest to the inner app
162
+ @handlers.reverse.inject(inner_app) { |app, handler| handler.build(app) }
163
+ end
164
+
165
+ def ==(other)
166
+ other.is_a?(self.class) && @handlers == other.handlers
167
+ end
168
+
169
+ def dup
170
+ self.class.new(@handlers.dup)
171
+ end
172
+
173
+ # ENV Keys
174
+ # :method - a symbolized request method (:get, :post)
175
+ # :body - the request body that will eventually be converted to a string.
176
+ # :url - URI instance for the current request.
177
+ # :status - HTTP response status code
178
+ # :request_headers - hash of HTTP Headers to be sent to the server
179
+ # :response_headers - Hash of HTTP headers from the server
180
+ # :parallel_manager - sent if the connection is in parallel mode
181
+ # :request - Hash of options for configuring the request.
182
+ # :timeout - open/read timeout Integer in seconds
183
+ # :open_timeout - read timeout Integer in seconds
184
+ # :proxy - Hash of proxy options
185
+ # :uri - Proxy Server URI
186
+ # :user - Proxy server username
187
+ # :password - Proxy server password
188
+ # :ssl - Hash of options for configuring SSL requests.
189
+ def build_env(connection, request)
190
+ Env.new(request.method, request.body,
191
+ connection.build_exclusive_url(request.path, request.params),
192
+ request.options, request.headers, connection.ssl,
193
+ connection.parallel_manager)
194
+ end
195
+
139
196
  private
140
197
 
141
198
  def raise_if_locked
@@ -1,12 +1,14 @@
1
1
  module Faraday
2
2
  class Request::Authorization < Faraday::Middleware
3
- KEY = "Authorization".freeze
3
+ KEY = "Authorization".freeze unless defined? KEY
4
4
 
5
5
  # Public
6
6
  def self.header(type, token)
7
7
  case token
8
- when String, Symbol then "#{type} #{token}"
9
- when Hash then build_hash(type.to_s, token)
8
+ when String, Symbol
9
+ "#{type} #{token}"
10
+ when Hash
11
+ build_hash(type.to_s, token)
10
12
  else
11
13
  raise ArgumentError, "Can't build an Authorization #{type} header from #{token.inspect}"
12
14
  end
@@ -30,8 +32,8 @@ module Faraday
30
32
 
31
33
  # Public
32
34
  def call(env)
33
- unless env[:request_headers][KEY]
34
- env[:request_headers][KEY] = @header_value
35
+ unless env.request_headers[KEY]
36
+ env.request_headers[KEY] = @header_value
35
37
  end
36
38
  @app.call(env)
37
39
  end
@@ -1,7 +1,7 @@
1
1
  require 'base64'
2
2
 
3
3
  module Faraday
4
- class Request::BasicAuthentication < Request::Authorization
4
+ class Request::BasicAuthentication < Request.load_middleware(:authorization)
5
5
  # Public
6
6
  def self.header(login, pass)
7
7
  value = Base64.encode64([login, pass].join(':'))