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
@@ -0,0 +1,212 @@
1
+ module Faraday
2
+ # A Builder that processes requests into responses by passing through an inner
3
+ # middleware stack (heavily inspired by Rack).
4
+ #
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
10
+ attr_accessor :handlers
11
+
12
+ # Error raised when trying to modify the stack after calling `lock!`
13
+ class StackLocked < RuntimeError; end
14
+
15
+ # borrowed from ActiveSupport::Dependencies::Reference &
16
+ # ActionDispatch::MiddlewareStack::Middleware
17
+ class Handler
18
+ @@constants_mutex = Mutex.new
19
+ @@constants = Hash.new { |h, k|
20
+ value = k.respond_to?(:constantize) ? k.constantize : Object.const_get(k)
21
+ @@constants_mutex.synchronize { h[k] = value }
22
+ }
23
+
24
+ attr_reader :name
25
+
26
+ def initialize(klass, *args, &block)
27
+ @name = klass.to_s
28
+ if klass.respond_to?(:name)
29
+ @@constants_mutex.synchronize { @@constants[@name] = klass }
30
+ end
31
+ @args, @block = args, block
32
+ end
33
+
34
+ def klass() @@constants[@name] end
35
+ def inspect() @name end
36
+
37
+ def ==(other)
38
+ if other.is_a? Handler
39
+ self.name == other.name
40
+ elsif other.respond_to? :name
41
+ klass == other
42
+ else
43
+ @name == other.to_s
44
+ end
45
+ end
46
+
47
+ def build(app)
48
+ klass.new(app, *@args, &@block)
49
+ end
50
+ end
51
+
52
+ def initialize(handlers = [])
53
+ @handlers = handlers
54
+ if block_given?
55
+ build(&Proc.new)
56
+ elsif @handlers.empty?
57
+ # default stack, if nothing else is configured
58
+ self.request :url_encoded
59
+ self.adapter Faraday.default_adapter
60
+ end
61
+ end
62
+
63
+ def build(options = {})
64
+ raise_if_locked
65
+ @handlers.clear unless options[:keep]
66
+ yield(self) if block_given?
67
+ end
68
+
69
+ def [](idx)
70
+ @handlers[idx]
71
+ end
72
+
73
+ # Locks the middleware stack to ensure no further modifications are possible.
74
+ def lock!
75
+ @handlers.freeze
76
+ end
77
+
78
+ def locked?
79
+ @handlers.frozen?
80
+ end
81
+
82
+ def use(klass, *args, &block)
83
+ if klass.is_a? Symbol
84
+ use_symbol(Faraday::Middleware, klass, *args, &block)
85
+ else
86
+ raise_if_locked
87
+ @handlers << self.class::Handler.new(klass, *args, &block)
88
+ end
89
+ end
90
+
91
+ def request(key, *args, &block)
92
+ use_symbol(Faraday::Request, key, *args, &block)
93
+ end
94
+
95
+ def response(key, *args, &block)
96
+ use_symbol(Faraday::Response, key, *args, &block)
97
+ end
98
+
99
+ def adapter(key, *args, &block)
100
+ use_symbol(Faraday::Adapter, key, *args, &block)
101
+ end
102
+
103
+ ## methods to push onto the various positions in the stack:
104
+
105
+ def insert(index, *args, &block)
106
+ raise_if_locked
107
+ index = assert_index(index)
108
+ handler = self.class::Handler.new(*args, &block)
109
+ @handlers.insert(index, handler)
110
+ end
111
+
112
+ alias_method :insert_before, :insert
113
+
114
+ def insert_after(index, *args, &block)
115
+ index = assert_index(index)
116
+ insert(index + 1, *args, &block)
117
+ end
118
+
119
+ def swap(index, *args, &block)
120
+ raise_if_locked
121
+ index = assert_index(index)
122
+ @handlers.delete_at(index)
123
+ insert(index, *args, &block)
124
+ end
125
+
126
+ def delete(handler)
127
+ raise_if_locked
128
+ @handlers.delete(handler)
129
+ end
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
+
196
+ private
197
+
198
+ def raise_if_locked
199
+ raise StackLocked, "can't modify middleware stack after making a request" if locked?
200
+ end
201
+
202
+ def use_symbol(mod, key, *args, &block)
203
+ use(mod.lookup_middleware(key), *args, &block)
204
+ end
205
+
206
+ def assert_index(index)
207
+ idx = index.is_a?(Integer) ? index : @handlers.index(index)
208
+ raise "No such handler: #{index.inspect}" unless idx
209
+ idx
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,42 @@
1
+ module Faraday
2
+ class Request::Authorization < Faraday::Middleware
3
+ KEY = "Authorization".freeze unless defined? KEY
4
+
5
+ # Public
6
+ def self.header(type, token)
7
+ case token
8
+ when String, Symbol
9
+ "#{type} #{token}"
10
+ when Hash
11
+ build_hash(type.to_s, token)
12
+ else
13
+ raise ArgumentError, "Can't build an Authorization #{type} header from #{token.inspect}"
14
+ end
15
+ end
16
+
17
+ # Internal
18
+ def self.build_hash(type, hash)
19
+ offset = KEY.size + type.size + 3
20
+ comma = ",\n#{' ' * offset}"
21
+ values = []
22
+ hash.each do |key, value|
23
+ values << "#{key}=#{value.to_s.inspect}"
24
+ end
25
+ "#{type} #{values * comma}"
26
+ end
27
+
28
+ def initialize(app, type, token)
29
+ @header_value = self.class.header(type, token)
30
+ super(app)
31
+ end
32
+
33
+ # Public
34
+ def call(env)
35
+ unless env.request_headers[KEY]
36
+ env.request_headers[KEY] = @header_value
37
+ end
38
+ @app.call(env)
39
+ end
40
+ end
41
+ end
42
+
@@ -0,0 +1,13 @@
1
+ require 'base64'
2
+
3
+ module Faraday
4
+ class Request::BasicAuthentication < Request.load_middleware(:authorization)
5
+ # Public
6
+ def self.header(login, pass)
7
+ value = Base64.encode64([login, pass].join(':'))
8
+ value.gsub!("\n", '')
9
+ super(:Basic, value)
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,36 @@
1
+ module Faraday
2
+ class Request::Instrumentation < Faraday::Middleware
3
+ class Options < Faraday::Options.new(:name, :instrumenter)
4
+ def name
5
+ self[:name] ||= 'request.faraday'
6
+ end
7
+
8
+ def instrumenter
9
+ self[:instrumenter] ||= ActiveSupport::Notifications
10
+ end
11
+ end
12
+
13
+ # Public: Instruments requests using Active Support.
14
+ #
15
+ # Measures time spent only for synchronous requests.
16
+ #
17
+ # Examples
18
+ #
19
+ # ActiveSupport::Notifications.subscribe('request.faraday') do |name, starts, ends, _, env|
20
+ # url = env[:url]
21
+ # http_method = env[:method].to_s.upcase
22
+ # duration = ends - starts
23
+ # $stderr.puts '[%s] %s %s (%.3f s)' % [url.host, http_method, url.request_uri, duration]
24
+ # end
25
+ def initialize(app, options = nil)
26
+ super(app)
27
+ @name, @instrumenter = Options.from(options).values_at(:name, :instrumenter)
28
+ end
29
+
30
+ def call(env)
31
+ @instrumenter.instrument(@name, env) do
32
+ @app.call(env)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -1,46 +1,46 @@
1
+ require File.expand_path("../url_encoded", __FILE__)
2
+
1
3
  module Faraday
2
4
  class Request::Multipart < Request::UrlEncoded
3
5
  self.mime_type = 'multipart/form-data'.freeze
4
- DEFAULT_BOUNDARY = "-----------RubyMultipartPost".freeze
6
+ DEFAULT_BOUNDARY = "-----------RubyMultipartPost".freeze unless defined? DEFAULT_BOUNDARY
5
7
 
6
8
  def call(env)
7
9
  match_content_type(env) do |params|
8
- env[:request] ||= {}
9
- env[:request][:boundary] ||= DEFAULT_BOUNDARY
10
- env[:request_headers][CONTENT_TYPE] += ";boundary=#{env[:request][:boundary]}"
11
- env[:body] = create_multipart(env, params)
10
+ env.request.boundary ||= DEFAULT_BOUNDARY
11
+ env.request_headers[CONTENT_TYPE] += "; boundary=#{env.request.boundary}"
12
+ env.body = create_multipart(env, params)
12
13
  end
13
14
  @app.call env
14
15
  end
15
16
 
16
17
  def process_request?(env)
17
18
  type = request_type(env)
18
- env[:body].respond_to?(:each_key) and !env[:body].empty? and (
19
- (type.empty? and has_multipart?(env[:body])) or
19
+ env.body.respond_to?(:each_key) and !env.body.empty? and (
20
+ (type.empty? and has_multipart?(env.body)) or
20
21
  type == self.class.mime_type
21
22
  )
22
23
  end
23
24
 
24
- def has_multipart?(body)
25
- body.values.each do |val|
26
- if val.respond_to?(:content_type)
27
- return true
28
- elsif val.respond_to?(:values)
29
- return true if has_multipart?(val)
25
+ def has_multipart?(obj)
26
+ # string is an enum in 1.8, returning list of itself
27
+ if obj.respond_to?(:each) && !obj.is_a?(String)
28
+ (obj.respond_to?(:values) ? obj.values : obj).each do |val|
29
+ return true if (val.respond_to?(:content_type) || has_multipart?(val))
30
30
  end
31
31
  end
32
32
  false
33
33
  end
34
34
 
35
35
  def create_multipart(env, params)
36
- boundary = env[:request][:boundary]
36
+ boundary = env.request.boundary
37
37
  parts = process_params(params) do |key, value|
38
38
  Faraday::Parts::Part.new(boundary, key, value)
39
39
  end
40
40
  parts << Faraday::Parts::EpiloguePart.new(boundary)
41
41
 
42
42
  body = Faraday::CompositeReadIO.new(parts)
43
- env[:request_headers]['Content-Length'] = body.length.to_s
43
+ env.request_headers[Faraday::Env::ContentLength] = body.length.to_s
44
44
  return body
45
45
  end
46
46
 
@@ -0,0 +1,118 @@
1
+ module Faraday
2
+ # Catches exceptions and retries each request a limited number of times.
3
+ #
4
+ # By default, it retries 2 times and handles only timeout exceptions. It can
5
+ # be configured with an arbitrary number of retries, a list of exceptions to
6
+ # handle, a retry interval, a percentage of randomness to add to the retry
7
+ # interval, and a backoff factor.
8
+ #
9
+ # Examples
10
+ #
11
+ # Faraday.new do |conn|
12
+ # conn.request :retry, max: 2, interval: 0.05,
13
+ # interval_randomness: 0.5, backoff_factor: 2
14
+ # exceptions: [CustomException, 'Timeout::Error']
15
+ # conn.adapter ...
16
+ # end
17
+ #
18
+ # This example will result in a first interval that is random between 0.05 and 0.075 and a second
19
+ # interval that is random between 0.1 and 0.15
20
+ #
21
+ class Request::Retry < Faraday::Middleware
22
+ class Options < Faraday::Options.new(:max, :interval, :interval_randomness, :backoff_factor, :exceptions)
23
+ def self.from(value)
24
+ if Fixnum === value
25
+ new(value)
26
+ else
27
+ super(value)
28
+ end
29
+ end
30
+
31
+ def max
32
+ (self[:max] ||= 2).to_i
33
+ end
34
+
35
+ def interval
36
+ (self[:interval] ||= 0).to_f
37
+ end
38
+
39
+ def interval_randomness
40
+ (self[:interval_randomness] ||= 0).to_i
41
+ end
42
+
43
+ def backoff_factor
44
+ (self[:backoff_factor] ||= 1).to_f
45
+ end
46
+
47
+ def exceptions
48
+ Array(self[:exceptions] ||= [Errno::ETIMEDOUT, 'Timeout::Error',
49
+ Error::TimeoutError])
50
+ end
51
+
52
+ end
53
+
54
+ # Public: Initialize middleware
55
+ #
56
+ # Options:
57
+ # max - Maximum number of retries (default: 2)
58
+ # interval - Pause in seconds between retries (default: 0)
59
+ # interval_randomness - The maximum random interval amount expressed
60
+ # as a float between 0 and 1 to use in addition to the
61
+ # interval. (default: 0)
62
+ # backoff_factor - The amount to multiple each successive retry's
63
+ # interval amount by in order to provide backoff
64
+ # (default: 1)
65
+ # exceptions - The list of exceptions to handle. Exceptions can be
66
+ # given as Class, Module, or String. (default:
67
+ # [Errno::ETIMEDOUT, Timeout::Error,
68
+ # Error::TimeoutError])
69
+ def initialize(app, options = nil)
70
+ super(app)
71
+ @options = Options.from(options)
72
+ @errmatch = build_exception_matcher(@options.exceptions)
73
+ end
74
+
75
+ def sleep_amount(retries)
76
+ retry_index = @options.max - retries
77
+ current_interval = @options.interval * (@options.backoff_factor ** retry_index)
78
+ random_interval = rand * @options.interval_randomness.to_f * @options.interval
79
+ current_interval + random_interval
80
+ end
81
+
82
+ def call(env)
83
+ retries = @options.max
84
+ request_body = env[:body]
85
+ begin
86
+ env[:body] = request_body # after failure env[:body] is set to the response body
87
+ @app.call(env)
88
+ rescue @errmatch
89
+ if retries > 0
90
+ retries -= 1
91
+ sleep sleep_amount(retries + 1)
92
+ retry
93
+ end
94
+ raise
95
+ end
96
+ end
97
+
98
+ # Private: construct an exception matcher object.
99
+ #
100
+ # An exception matcher for the rescue clause can usually be any object that
101
+ # responds to `===`, but for Ruby 1.8 it has to be a Class or Module.
102
+ def build_exception_matcher(exceptions)
103
+ matcher = Module.new
104
+ (class << matcher; self; end).class_eval do
105
+ define_method(:===) do |error|
106
+ exceptions.any? do |ex|
107
+ if ex.is_a? Module
108
+ error.is_a? ex
109
+ else
110
+ error.class.to_s == ex.to_s
111
+ end
112
+ end
113
+ end
114
+ end
115
+ matcher
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,15 @@
1
+ module Faraday
2
+ class Request::TokenAuthentication < Request.load_middleware(:authorization)
3
+ # Public
4
+ def self.header(token, options = nil)
5
+ options ||= {}
6
+ options[:token] = token
7
+ super(:Token, options)
8
+ end
9
+
10
+ def initialize(app, token, options = nil)
11
+ super(app, token, options)
12
+ end
13
+ end
14
+ end
15
+
@@ -1,6 +1,6 @@
1
1
  module Faraday
2
2
  class Request::UrlEncoded < Faraday::Middleware
3
- CONTENT_TYPE = 'Content-Type'.freeze
3
+ CONTENT_TYPE = 'Content-Type'.freeze unless defined? CONTENT_TYPE
4
4
 
5
5
  class << self
6
6
  attr_accessor :mime_type
@@ -9,27 +9,26 @@ module Faraday
9
9
 
10
10
  def call(env)
11
11
  match_content_type(env) do |data|
12
- env[:body] = Faraday::Utils.build_nested_query data
12
+ params = Faraday::Utils::ParamsHash[data]
13
+ env.body = params.to_query(env.params_encoder)
13
14
  end
14
15
  @app.call env
15
16
  end
16
-
17
+
17
18
  def match_content_type(env)
18
- type = request_type(env)
19
-
20
19
  if process_request?(env)
21
- env[:request_headers][CONTENT_TYPE] ||= self.class.mime_type
22
- yield env[:body] unless env[:body].respond_to?(:to_str)
20
+ env.request_headers[CONTENT_TYPE] ||= self.class.mime_type
21
+ yield(env.body) unless env.body.respond_to?(:to_str)
23
22
  end
24
23
  end
25
24
 
26
25
  def process_request?(env)
27
26
  type = request_type(env)
28
- env[:body] and (type.empty? or type == self.class.mime_type)
27
+ env.body and (type.empty? or type == self.class.mime_type)
29
28
  end
30
29
 
31
30
  def request_type(env)
32
- type = env[:request_headers][CONTENT_TYPE].to_s
31
+ type = env.request_headers[CONTENT_TYPE].to_s
33
32
  type = type.split(';', 2).first if type.index(';')
34
33
  type
35
34
  end
@@ -9,34 +9,54 @@ module Faraday
9
9
  # req.body = 'abc'
10
10
  # end
11
11
  #
12
- class Request < Struct.new(:path, :params, :headers, :body)
13
- extend AutoloadHelper
12
+ class Request < Struct.new(:method, :path, :params, :headers, :body, :options)
13
+ extend MiddlewareRegistry
14
14
 
15
- autoload_all 'faraday/request',
16
- :JSON => 'json',
17
- :UrlEncoded => 'url_encoded',
18
- :Multipart => 'multipart'
15
+ register_middleware File.expand_path('../request', __FILE__),
16
+ :url_encoded => [:UrlEncoded, 'url_encoded'],
17
+ :multipart => [:Multipart, 'multipart'],
18
+ :retry => [:Retry, 'retry'],
19
+ :authorization => [:Authorization, 'authorization'],
20
+ :basic_auth => [:BasicAuthentication, 'basic_authentication'],
21
+ :token_auth => [:TokenAuthentication, 'token_authentication'],
22
+ :instrumentation => [:Instrumentation, 'instrumentation']
19
23
 
20
- register_lookup_modules \
21
- :json => :JSON,
22
- :url_encoded => :UrlEncoded,
23
- :multipart => :Multipart
24
+ def self.create(request_method)
25
+ new(request_method).tap do |request|
26
+ yield(request) if block_given?
27
+ end
28
+ end
24
29
 
25
- def self.run(connection, request_method)
26
- req = create
27
- yield req if block_given?
28
- req.run(connection, request_method)
30
+ # Public: Replace params, preserving the existing hash type
31
+ def params=(hash)
32
+ if params
33
+ params.replace hash
34
+ else
35
+ super
36
+ end
29
37
  end
30
38
 
31
- def self.create
32
- req = new(nil, {}, {}, nil)
33
- yield req if block_given?
34
- req
39
+ # Public: Replace request headers, preserving the existing hash type
40
+ def headers=(hash)
41
+ if headers
42
+ headers.replace hash
43
+ else
44
+ super
45
+ end
35
46
  end
36
47
 
37
- def url(path, params = {})
38
- self.path = path
39
- self.params = params
48
+ def url(path, params = nil)
49
+ if path.respond_to? :query
50
+ if query = path.query
51
+ path = path.dup
52
+ path.query = nil
53
+ end
54
+ else
55
+ path, query = path.split('?', 2)
56
+ end
57
+ self.path = path
58
+ self.params.merge_query query, options.params_encoder
59
+ self.params.update(params) if params
40
60
  end
41
61
 
42
62
  def [](key)
@@ -50,7 +70,7 @@ module Faraday
50
70
  # ENV Keys
51
71
  # :method - a symbolized request method (:get, :post)
52
72
  # :body - the request body that will eventually be converted to a string.
53
- # :url - Addressable::URI instance of the URI for the current request.
73
+ # :url - URI instance for the current request.
54
74
  # :status - HTTP response status code
55
75
  # :request_headers - hash of HTTP Headers to be sent to the server
56
76
  # :response_headers - Hash of HTTP headers from the server
@@ -63,29 +83,10 @@ module Faraday
63
83
  # :user - Proxy server username
64
84
  # :password - Proxy server password
65
85
  # :ssl - Hash of options for configuring SSL requests.
66
- def to_env_hash(connection, request_method)
67
- env_headers = connection.headers.dup
68
- env_params = connection.params.dup
69
- connection.merge_headers(env_headers, headers)
70
- connection.merge_params(env_params, params)
71
-
72
- { :method => request_method,
73
- :body => body,
74
- :url => connection.build_url(path, env_params),
75
- :request_headers => env_headers,
76
- :parallel_manager => connection.parallel_manager,
77
- :request => connection.options.merge(:proxy => connection.proxy),
78
- :ssl => connection.ssl}
79
- end
80
-
81
- def run(connection, request_method)
82
- app = lambda { |env|
83
- response = Response.new
84
- response.finish(env) unless env[:parallel_manager]
85
- env[:response] = response
86
- }
87
- env = to_env_hash(connection, request_method)
88
- connection.builder.to_app(app).call(env)
86
+ def to_env(connection)
87
+ Env.new(method, body, connection.build_exclusive_url(path, params),
88
+ options, headers, connection.ssl, connection.parallel_manager)
89
89
  end
90
90
  end
91
91
  end
92
+
@@ -15,14 +15,14 @@ module Faraday
15
15
  def_delegators :@logger, :debug, :info, :warn, :error, :fatal
16
16
 
17
17
  def call(env)
18
- info "#{env[:method]} #{env[:url].to_s}"
19
- debug('request') { dump_headers env[:request_headers] }
18
+ info "#{env.method} #{env.url.to_s}"
19
+ debug('request') { dump_headers env.request_headers }
20
20
  super
21
21
  end
22
22
 
23
23
  def on_complete(env)
24
- info('Status') { env[:status].to_s }
25
- debug('response') { dump_headers env[:response_headers] }
24
+ info('Status') { env.status.to_s }
25
+ debug('response') { dump_headers env.response_headers }
26
26
  end
27
27
 
28
28
  private