faraday 0.9.2 → 0.17.6
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +232 -0
- data/LICENSE.md +1 -1
- data/README.md +168 -18
- data/Rakefile +13 -0
- data/lib/faraday/adapter/em_http.rb +17 -11
- data/lib/faraday/adapter/em_http_ssl_patch.rb +1 -1
- data/lib/faraday/adapter/em_synchrony.rb +13 -7
- data/lib/faraday/adapter/excon.rb +12 -11
- data/lib/faraday/adapter/httpclient.rb +21 -10
- data/lib/faraday/adapter/net_http.rb +36 -13
- data/lib/faraday/adapter/net_http_persistent.rb +36 -17
- data/lib/faraday/adapter/patron.rb +36 -19
- data/lib/faraday/adapter/rack.rb +1 -1
- data/lib/faraday/adapter/test.rb +79 -28
- data/lib/faraday/adapter/typhoeus.rb +4 -115
- data/lib/faraday/adapter.rb +10 -1
- data/lib/faraday/autoload.rb +1 -1
- data/lib/faraday/connection.rb +64 -17
- data/lib/faraday/deprecate.rb +109 -0
- data/lib/faraday/error.rb +132 -27
- data/lib/faraday/options.rb +36 -22
- data/lib/faraday/parameters.rb +2 -1
- data/lib/faraday/rack_builder.rb +26 -2
- data/lib/faraday/request/authorization.rb +1 -2
- data/lib/faraday/request/multipart.rb +7 -2
- data/lib/faraday/request/retry.rb +77 -18
- data/lib/faraday/request.rb +24 -0
- data/lib/faraday/response/logger.rb +29 -8
- data/lib/faraday/response/raise_error.rb +7 -3
- data/lib/faraday/response.rb +7 -3
- data/lib/faraday/upload_io.rb +16 -6
- data/lib/faraday/utils.rb +19 -2
- data/lib/faraday.rb +15 -36
- data/spec/faraday/deprecate_spec.rb +147 -0
- data/spec/faraday/error_spec.rb +102 -0
- data/spec/faraday/response/raise_error_spec.rb +106 -0
- data/spec/spec_helper.rb +105 -0
- data/test/adapters/default_test.rb +14 -0
- data/test/adapters/em_http_test.rb +30 -0
- data/test/adapters/em_synchrony_test.rb +32 -0
- data/test/adapters/excon_test.rb +30 -0
- data/test/adapters/httpclient_test.rb +34 -0
- data/test/adapters/integration.rb +263 -0
- data/test/adapters/logger_test.rb +136 -0
- data/test/adapters/net_http_persistent_test.rb +114 -0
- data/test/adapters/net_http_test.rb +79 -0
- data/test/adapters/patron_test.rb +40 -0
- data/test/adapters/rack_test.rb +38 -0
- data/test/adapters/test_middleware_test.rb +157 -0
- data/test/adapters/typhoeus_test.rb +38 -0
- data/test/authentication_middleware_test.rb +65 -0
- data/test/composite_read_io_test.rb +109 -0
- data/test/connection_test.rb +738 -0
- data/test/env_test.rb +268 -0
- data/test/helper.rb +75 -0
- data/test/live_server.rb +67 -0
- data/test/middleware/instrumentation_test.rb +88 -0
- data/test/middleware/retry_test.rb +282 -0
- data/test/middleware_stack_test.rb +260 -0
- data/test/multibyte.txt +1 -0
- data/test/options_test.rb +333 -0
- data/test/parameters_test.rb +157 -0
- data/test/request_middleware_test.rb +126 -0
- data/test/response_middleware_test.rb +72 -0
- data/test/strawberry.rb +2 -0
- data/test/utils_test.rb +98 -0
- metadata +81 -63
data/lib/faraday/options.rb
CHANGED
@@ -18,23 +18,20 @@ module Faraday
|
|
18
18
|
# Public
|
19
19
|
def update(obj)
|
20
20
|
obj.each do |key, value|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
value.
|
26
|
-
|
27
|
-
|
28
|
-
value = hash
|
21
|
+
sub_options = self.class.options_for(key)
|
22
|
+
if sub_options
|
23
|
+
new_value = sub_options.from(value) if value
|
24
|
+
elsif value.is_a?(Hash)
|
25
|
+
new_value = value.dup
|
26
|
+
else
|
27
|
+
new_value = value
|
29
28
|
end
|
30
29
|
|
31
|
-
self.send("#{key}=",
|
30
|
+
self.send("#{key}=", new_value) unless new_value.nil?
|
32
31
|
end
|
33
32
|
self
|
34
33
|
end
|
35
34
|
|
36
|
-
alias merge! update
|
37
|
-
|
38
35
|
# Public
|
39
36
|
def delete(key)
|
40
37
|
value = send(key)
|
@@ -48,8 +45,24 @@ module Faraday
|
|
48
45
|
end
|
49
46
|
|
50
47
|
# Public
|
51
|
-
def merge(
|
52
|
-
|
48
|
+
def merge!(other)
|
49
|
+
other.each do |key, other_value|
|
50
|
+
self_value = self.send(key)
|
51
|
+
sub_options = self.class.options_for(key)
|
52
|
+
new_value = (self_value && sub_options && other_value) ? self_value.merge(other_value) : other_value
|
53
|
+
self.send("#{key}=", new_value) unless new_value.nil?
|
54
|
+
end
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
# Public
|
59
|
+
def merge(other)
|
60
|
+
dup.merge!(other)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Public
|
64
|
+
def deep_dup
|
65
|
+
self.class.from(self)
|
53
66
|
end
|
54
67
|
|
55
68
|
# Public
|
@@ -59,7 +72,7 @@ module Faraday
|
|
59
72
|
if args.size > 0
|
60
73
|
send(key_setter, args.first)
|
61
74
|
elsif block_given?
|
62
|
-
send(key_setter,
|
75
|
+
send(key_setter, yield(key))
|
63
76
|
else
|
64
77
|
raise self.class.fetch_error_class, "key not found: #{key.inspect}"
|
65
78
|
end
|
@@ -149,8 +162,8 @@ module Faraday
|
|
149
162
|
@attribute_options ||= {}
|
150
163
|
end
|
151
164
|
|
152
|
-
def self.memoized(key)
|
153
|
-
memoized_attributes[key.to_sym] =
|
165
|
+
def self.memoized(key, &block)
|
166
|
+
memoized_attributes[key.to_sym] = block
|
154
167
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
155
168
|
def #{key}() self[:#{key}]; end
|
156
169
|
RUBY
|
@@ -189,8 +202,7 @@ module Faraday
|
|
189
202
|
end
|
190
203
|
|
191
204
|
class RequestOptions < Options.new(:params_encoder, :proxy, :bind,
|
192
|
-
:timeout, :open_timeout, :boundary,
|
193
|
-
:oauth)
|
205
|
+
:timeout, :open_timeout, :write_timeout, :boundary, :oauth, :context)
|
194
206
|
|
195
207
|
def []=(key, value)
|
196
208
|
if key && key.to_sym == :proxy
|
@@ -202,7 +214,8 @@ module Faraday
|
|
202
214
|
end
|
203
215
|
|
204
216
|
class SSLOptions < Options.new(:verify, :ca_file, :ca_path, :verify_mode,
|
205
|
-
:cert_store, :client_cert, :client_key, :certificate, :private_key, :verify_depth,
|
217
|
+
:cert_store, :client_cert, :client_key, :certificate, :private_key, :verify_depth,
|
218
|
+
:version, :min_version, :max_version)
|
206
219
|
|
207
220
|
def verify?
|
208
221
|
verify != false
|
@@ -231,8 +244,8 @@ module Faraday
|
|
231
244
|
super(value)
|
232
245
|
end
|
233
246
|
|
234
|
-
memoized(:user) { uri.user && Utils.unescape(uri.user) }
|
235
|
-
memoized(:password) { uri.password && Utils.unescape(uri.password) }
|
247
|
+
memoized(:user) { uri && uri.user && Utils.unescape(uri.user) }
|
248
|
+
memoized(:password) { uri && uri.password && Utils.unescape(uri.password) }
|
236
249
|
end
|
237
250
|
|
238
251
|
class ConnectionOptions < Options.new(:request, :proxy, :ssl, :builder, :url,
|
@@ -252,7 +265,8 @@ module Faraday
|
|
252
265
|
end
|
253
266
|
|
254
267
|
class Env < Options.new(:method, :body, :url, :request, :request_headers,
|
255
|
-
:ssl, :parallel_manager, :params, :response, :response_headers, :status
|
268
|
+
:ssl, :parallel_manager, :params, :response, :response_headers, :status,
|
269
|
+
:reason_phrase)
|
256
270
|
|
257
271
|
ContentLength = 'Content-Length'.freeze
|
258
272
|
StatusesWithoutBody = Set.new [204, 304]
|
data/lib/faraday/parameters.rb
CHANGED
@@ -40,9 +40,10 @@ module Faraday
|
|
40
40
|
end
|
41
41
|
return buffer.chop
|
42
42
|
elsif value.is_a?(Array)
|
43
|
+
new_parent = "#{parent}%5B%5D"
|
44
|
+
return new_parent if value.empty?
|
43
45
|
buffer = ""
|
44
46
|
value.each_with_index do |val, i|
|
45
|
-
new_parent = "#{parent}%5B%5D"
|
46
47
|
buffer << "#{to_query.call(new_parent, val)}&"
|
47
48
|
end
|
48
49
|
return buffer.chop
|
data/lib/faraday/rack_builder.rb
CHANGED
@@ -49,10 +49,10 @@ module Faraday
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
-
def initialize(handlers = [])
|
52
|
+
def initialize(handlers = [], &block)
|
53
53
|
@handlers = handlers
|
54
54
|
if block_given?
|
55
|
-
build(&
|
55
|
+
build(&block)
|
56
56
|
elsif @handlers.empty?
|
57
57
|
# default stack, if nothing else is configured
|
58
58
|
self.request :url_encoded
|
@@ -84,6 +84,7 @@ module Faraday
|
|
84
84
|
use_symbol(Faraday::Middleware, klass, *args, &block)
|
85
85
|
else
|
86
86
|
raise_if_locked
|
87
|
+
warn_middleware_after_adapter if adapter_set?
|
87
88
|
@handlers << self.class::Handler.new(klass, *args, &block)
|
88
89
|
end
|
89
90
|
end
|
@@ -105,6 +106,7 @@ module Faraday
|
|
105
106
|
def insert(index, *args, &block)
|
106
107
|
raise_if_locked
|
107
108
|
index = assert_index(index)
|
109
|
+
warn_middleware_after_adapter if inserting_after_adapter?(index)
|
108
110
|
handler = self.class::Handler.new(*args, &block)
|
109
111
|
@handlers.insert(index, handler)
|
110
112
|
end
|
@@ -136,6 +138,8 @@ module Faraday
|
|
136
138
|
#
|
137
139
|
# Returns a Faraday::Response.
|
138
140
|
def build_response(connection, request)
|
141
|
+
warn 'WARNING: No adapter was configured for this request' unless adapter_set?
|
142
|
+
|
139
143
|
app.call(build_env(connection, request))
|
140
144
|
end
|
141
145
|
|
@@ -200,6 +204,26 @@ module Faraday
|
|
200
204
|
raise StackLocked, "can't modify middleware stack after making a request" if locked?
|
201
205
|
end
|
202
206
|
|
207
|
+
def warn_middleware_after_adapter
|
208
|
+
warn "WARNING: Unexpected middleware set after the adapter. " \
|
209
|
+
"This won't be supported from Faraday 1.0."
|
210
|
+
end
|
211
|
+
|
212
|
+
def adapter_set?
|
213
|
+
@handlers.any? { |handler| is_adapter?(handler) }
|
214
|
+
end
|
215
|
+
|
216
|
+
def inserting_after_adapter?(index)
|
217
|
+
adapter_index = @handlers.find_index { |handler| is_adapter?(handler) }
|
218
|
+
return false if adapter_index.nil?
|
219
|
+
|
220
|
+
index > adapter_index
|
221
|
+
end
|
222
|
+
|
223
|
+
def is_adapter?(handler)
|
224
|
+
handler.klass.ancestors.include? Faraday::Adapter
|
225
|
+
end
|
226
|
+
|
203
227
|
def use_symbol(mod, key, *args, &block)
|
204
228
|
use(mod.lookup_middleware(key), *args, &block)
|
205
229
|
end
|
@@ -1,13 +1,14 @@
|
|
1
1
|
require File.expand_path("../url_encoded", __FILE__)
|
2
|
+
require 'securerandom'
|
2
3
|
|
3
4
|
module Faraday
|
4
5
|
class Request::Multipart < Request::UrlEncoded
|
5
6
|
self.mime_type = 'multipart/form-data'.freeze
|
6
|
-
|
7
|
+
DEFAULT_BOUNDARY_PREFIX = "-----------RubyMultipartPost".freeze unless defined? DEFAULT_BOUNDARY_PREFIX
|
7
8
|
|
8
9
|
def call(env)
|
9
10
|
match_content_type(env) do |params|
|
10
|
-
env.request.boundary ||=
|
11
|
+
env.request.boundary ||= unique_boundary
|
11
12
|
env.request_headers[CONTENT_TYPE] += "; boundary=#{env.request.boundary}"
|
12
13
|
env.body = create_multipart(env, params)
|
13
14
|
end
|
@@ -44,6 +45,10 @@ module Faraday
|
|
44
45
|
return body
|
45
46
|
end
|
46
47
|
|
48
|
+
def unique_boundary
|
49
|
+
"#{DEFAULT_BOUNDARY_PREFIX}-#{SecureRandom.hex}"
|
50
|
+
end
|
51
|
+
|
47
52
|
def process_params(params, prefix = nil, pieces = nil, &block)
|
48
53
|
params.inject(pieces || []) do |all, (key, value)|
|
49
54
|
key = "#{prefix}[#{key}]" if prefix
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
1
3
|
module Faraday
|
2
4
|
# Catches exceptions and retries each request a limited number of times.
|
3
5
|
#
|
@@ -10,7 +12,7 @@ module Faraday
|
|
10
12
|
#
|
11
13
|
# Faraday.new do |conn|
|
12
14
|
# conn.request :retry, max: 2, interval: 0.05,
|
13
|
-
# interval_randomness: 0.5, backoff_factor: 2
|
15
|
+
# interval_randomness: 0.5, backoff_factor: 2,
|
14
16
|
# exceptions: [CustomException, 'Timeout::Error']
|
15
17
|
# conn.adapter ...
|
16
18
|
# end
|
@@ -19,15 +21,19 @@ module Faraday
|
|
19
21
|
# interval that is random between 0.1 and 0.15
|
20
22
|
#
|
21
23
|
class Request::Retry < Faraday::Middleware
|
22
|
-
|
24
|
+
DEFAULT_EXCEPTIONS = [Errno::ETIMEDOUT, 'Timeout::Error',
|
25
|
+
Faraday::TimeoutError, Faraday::RetriableResponse
|
26
|
+
].freeze
|
23
27
|
IDEMPOTENT_METHODS = [:delete, :get, :head, :options, :put]
|
24
28
|
|
25
29
|
class Options < Faraday::Options.new(:max, :interval, :max_interval, :interval_randomness,
|
26
|
-
:backoff_factor, :exceptions, :methods, :retry_if
|
30
|
+
:backoff_factor, :exceptions, :methods, :retry_if, :retry_block,
|
31
|
+
:retry_statuses)
|
32
|
+
|
27
33
|
DEFAULT_CHECK = lambda { |env,exception| false }
|
28
34
|
|
29
35
|
def self.from(value)
|
30
|
-
if
|
36
|
+
if Integer === value
|
31
37
|
new(value)
|
32
38
|
else
|
33
39
|
super(value)
|
@@ -55,8 +61,7 @@ module Faraday
|
|
55
61
|
end
|
56
62
|
|
57
63
|
def exceptions
|
58
|
-
Array(self[:exceptions] ||=
|
59
|
-
Error::TimeoutError])
|
64
|
+
Array(self[:exceptions] ||= DEFAULT_EXCEPTIONS)
|
60
65
|
end
|
61
66
|
|
62
67
|
def methods
|
@@ -67,6 +72,13 @@ module Faraday
|
|
67
72
|
self[:retry_if] ||= DEFAULT_CHECK
|
68
73
|
end
|
69
74
|
|
75
|
+
def retry_block
|
76
|
+
self[:retry_block] ||= Proc.new {}
|
77
|
+
end
|
78
|
+
|
79
|
+
def retry_statuses
|
80
|
+
Array(self[:retry_statuses] ||= [])
|
81
|
+
end
|
70
82
|
end
|
71
83
|
|
72
84
|
# Public: Initialize middleware
|
@@ -83,8 +95,8 @@ module Faraday
|
|
83
95
|
# (default: 1)
|
84
96
|
# exceptions - The list of exceptions to handle. Exceptions can be
|
85
97
|
# given as Class, Module, or String. (default:
|
86
|
-
# [Errno::ETIMEDOUT, Timeout::Error,
|
87
|
-
#
|
98
|
+
# [Errno::ETIMEDOUT, 'Timeout::Error',
|
99
|
+
# Faraday::TimeoutError, Faraday::RetriableResponse])
|
88
100
|
# methods - A list of HTTP methods to retry without calling retry_if. Pass
|
89
101
|
# an empty Array to call retry_if for all exceptions.
|
90
102
|
# (defaults to the idempotent HTTP methods in IDEMPOTENT_METHODS)
|
@@ -94,18 +106,21 @@ module Faraday
|
|
94
106
|
# if the exception produced is non-recoverable or if the
|
95
107
|
# the HTTP method called is not idempotent.
|
96
108
|
# (defaults to return false)
|
109
|
+
# retry_block - block that is executed after every retry. Request environment, middleware options,
|
110
|
+
# current number of retries and the exception is passed to the block as parameters.
|
97
111
|
def initialize(app, options = nil)
|
98
112
|
super(app)
|
99
113
|
@options = Options.from(options)
|
100
114
|
@errmatch = build_exception_matcher(@options.exceptions)
|
101
115
|
end
|
102
116
|
|
103
|
-
def
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
117
|
+
def calculate_sleep_amount(retries, env)
|
118
|
+
retry_after = calculate_retry_after(env)
|
119
|
+
retry_interval = calculate_retry_interval(retries)
|
120
|
+
|
121
|
+
return if retry_after && retry_after > @options.max_interval
|
122
|
+
|
123
|
+
retry_after && retry_after >= retry_interval ? retry_after : retry_interval
|
109
124
|
end
|
110
125
|
|
111
126
|
def call(env)
|
@@ -113,14 +128,25 @@ module Faraday
|
|
113
128
|
request_body = env[:body]
|
114
129
|
begin
|
115
130
|
env[:body] = request_body # after failure env[:body] is set to the response body
|
116
|
-
@app.call(env)
|
131
|
+
@app.call(env).tap do |resp|
|
132
|
+
raise Faraday::RetriableResponse.new(nil, resp) if @options.retry_statuses.include?(resp.status)
|
133
|
+
end
|
117
134
|
rescue @errmatch => exception
|
118
135
|
if retries > 0 && retry_request?(env, exception)
|
119
136
|
retries -= 1
|
120
|
-
|
121
|
-
|
137
|
+
rewind_files(request_body)
|
138
|
+
@options.retry_block.call(env, @options, retries, exception)
|
139
|
+
if (sleep_amount = calculate_sleep_amount(retries + 1, env))
|
140
|
+
sleep sleep_amount
|
141
|
+
retry
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
if exception.is_a?(Faraday::RetriableResponse)
|
146
|
+
exception.response
|
147
|
+
else
|
148
|
+
raise
|
122
149
|
end
|
123
|
-
raise
|
124
150
|
end
|
125
151
|
end
|
126
152
|
|
@@ -150,5 +176,38 @@ module Faraday
|
|
150
176
|
@options.methods.include?(env[:method]) || @options.retry_if.call(env, exception)
|
151
177
|
end
|
152
178
|
|
179
|
+
def rewind_files(body)
|
180
|
+
return unless body.is_a?(Hash)
|
181
|
+
body.each do |_, value|
|
182
|
+
if value.is_a? UploadIO
|
183
|
+
value.rewind
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
# MDN spec for Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
|
189
|
+
def calculate_retry_after(env)
|
190
|
+
response_headers = env[:response_headers]
|
191
|
+
return unless response_headers
|
192
|
+
|
193
|
+
retry_after_value = env[:response_headers]["Retry-After"]
|
194
|
+
|
195
|
+
# Try to parse date from the header value
|
196
|
+
begin
|
197
|
+
datetime = DateTime.rfc2822(retry_after_value)
|
198
|
+
datetime.to_time - Time.now.utc
|
199
|
+
rescue ArgumentError
|
200
|
+
retry_after_value.to_f
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def calculate_retry_interval(retries)
|
205
|
+
retry_index = @options.max - retries
|
206
|
+
current_interval = @options.interval * (@options.backoff_factor ** retry_index)
|
207
|
+
current_interval = [current_interval, @options.max_interval].min
|
208
|
+
random_interval = rand * @options.interval_randomness.to_f * @options.interval
|
209
|
+
|
210
|
+
current_interval + random_interval
|
211
|
+
end
|
153
212
|
end
|
154
213
|
end
|
data/lib/faraday/request.rb
CHANGED
@@ -12,6 +12,8 @@ module Faraday
|
|
12
12
|
class Request < Struct.new(:method, :path, :params, :headers, :body, :options)
|
13
13
|
extend MiddlewareRegistry
|
14
14
|
|
15
|
+
alias_method :http_method, :method
|
16
|
+
|
15
17
|
register_middleware File.expand_path('../request', __FILE__),
|
16
18
|
:url_encoded => [:UrlEncoded, 'url_encoded'],
|
17
19
|
:multipart => [:Multipart, 'multipart'],
|
@@ -52,6 +54,8 @@ module Faraday
|
|
52
54
|
path.query = nil
|
53
55
|
end
|
54
56
|
else
|
57
|
+
anchor_index = path.index('#')
|
58
|
+
path = path.slice(0, anchor_index) unless anchor_index.nil?
|
55
59
|
path, query = path.split('?', 2)
|
56
60
|
end
|
57
61
|
self.path = path
|
@@ -67,6 +71,26 @@ module Faraday
|
|
67
71
|
headers[key] = value
|
68
72
|
end
|
69
73
|
|
74
|
+
def marshal_dump
|
75
|
+
{
|
76
|
+
:method => method,
|
77
|
+
:body => body,
|
78
|
+
:headers => headers,
|
79
|
+
:path => path,
|
80
|
+
:params => params,
|
81
|
+
:options => options
|
82
|
+
}
|
83
|
+
end
|
84
|
+
|
85
|
+
def marshal_load(serialised)
|
86
|
+
self.method = serialised[:method]
|
87
|
+
self.body = serialised[:body]
|
88
|
+
self.headers = serialised[:headers]
|
89
|
+
self.path = serialised[:path]
|
90
|
+
self.params = serialised[:params]
|
91
|
+
self.options = serialised[:options]
|
92
|
+
end
|
93
|
+
|
70
94
|
# ENV Keys
|
71
95
|
# :method - a symbolized request method (:get, :post)
|
72
96
|
# :body - the request body that will eventually be converted to a string.
|
@@ -4,30 +4,36 @@ module Faraday
|
|
4
4
|
class Response::Logger < Response::Middleware
|
5
5
|
extend Forwardable
|
6
6
|
|
7
|
-
DEFAULT_OPTIONS = { :bodies => false }
|
7
|
+
DEFAULT_OPTIONS = { :headers => true, :bodies => false }
|
8
8
|
|
9
9
|
def initialize(app, logger = nil, options = {})
|
10
10
|
super(app)
|
11
11
|
@logger = logger || begin
|
12
12
|
require 'logger'
|
13
|
-
::Logger.new(
|
13
|
+
::Logger.new($stdout)
|
14
14
|
end
|
15
|
+
@filter = []
|
15
16
|
@options = DEFAULT_OPTIONS.merge(options)
|
17
|
+
yield self if block_given?
|
16
18
|
end
|
17
19
|
|
18
20
|
def_delegators :@logger, :debug, :info, :warn, :error, :fatal
|
19
21
|
|
20
22
|
def call(env)
|
21
|
-
info "#{env.method} #{env.url.to_s}"
|
22
|
-
debug('request') { dump_headers env.request_headers }
|
23
|
-
debug('request') { dump_body(env[:body]) } if env[:body] && log_body?(:request)
|
23
|
+
info('request') { "#{env.method.upcase} #{apply_filters(env.url.to_s)}" }
|
24
|
+
debug('request') { apply_filters( dump_headers env.request_headers ) } if log_headers?(:request)
|
25
|
+
debug('request') { apply_filters( dump_body(env[:body]) ) } if env[:body] && log_body?(:request)
|
24
26
|
super
|
25
27
|
end
|
26
28
|
|
27
29
|
def on_complete(env)
|
28
|
-
info('
|
29
|
-
debug('response') { dump_headers env.response_headers }
|
30
|
-
debug('response') { dump_body env[:body] } if env[:body] && log_body?(:response)
|
30
|
+
info('response') { "Status #{env.status.to_s}" }
|
31
|
+
debug('response') { apply_filters( dump_headers env.response_headers ) } if log_headers?(:response)
|
32
|
+
debug('response') { apply_filters( dump_body env[:body] ) } if env[:body] && log_body?(:response)
|
33
|
+
end
|
34
|
+
|
35
|
+
def filter(filter_word, filter_replacement)
|
36
|
+
@filter.push([ filter_word, filter_replacement ])
|
31
37
|
end
|
32
38
|
|
33
39
|
private
|
@@ -49,11 +55,26 @@ module Faraday
|
|
49
55
|
body.pretty_inspect
|
50
56
|
end
|
51
57
|
|
58
|
+
def log_headers?(type)
|
59
|
+
case @options[:headers]
|
60
|
+
when Hash then @options[:headers][type]
|
61
|
+
else @options[:headers]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
52
65
|
def log_body?(type)
|
53
66
|
case @options[:bodies]
|
54
67
|
when Hash then @options[:bodies][type]
|
55
68
|
else @options[:bodies]
|
56
69
|
end
|
57
70
|
end
|
71
|
+
|
72
|
+
def apply_filters(output)
|
73
|
+
@filter.each do |pattern, replacement|
|
74
|
+
output = output.to_s.gsub(pattern, replacement)
|
75
|
+
end
|
76
|
+
output
|
77
|
+
end
|
78
|
+
|
58
79
|
end
|
59
80
|
end
|
@@ -5,12 +5,16 @@ module Faraday
|
|
5
5
|
def on_complete(env)
|
6
6
|
case env[:status]
|
7
7
|
when 404
|
8
|
-
raise Faraday::
|
8
|
+
raise Faraday::ResourceNotFound, response_values(env)
|
9
9
|
when 407
|
10
10
|
# mimic the behavior that we get with proxy requests with HTTPS
|
11
|
-
raise Faraday::
|
11
|
+
raise Faraday::ConnectionFailed.new(
|
12
|
+
%{407 "Proxy Authentication Required "},
|
13
|
+
response_values(env))
|
12
14
|
when ClientErrorStatuses
|
13
|
-
raise Faraday::
|
15
|
+
raise Faraday::ClientError, response_values(env)
|
16
|
+
when nil
|
17
|
+
raise Faraday::NilStatusError, response_values(env)
|
14
18
|
end
|
15
19
|
end
|
16
20
|
|
data/lib/faraday/response.rb
CHANGED
@@ -37,6 +37,10 @@ module Faraday
|
|
37
37
|
finished? ? env.status : nil
|
38
38
|
end
|
39
39
|
|
40
|
+
def reason_phrase
|
41
|
+
finished? ? env.reason_phrase : nil
|
42
|
+
end
|
43
|
+
|
40
44
|
def headers
|
41
45
|
finished? ? env.response_headers : {}
|
42
46
|
end
|
@@ -50,9 +54,9 @@ module Faraday
|
|
50
54
|
!!env
|
51
55
|
end
|
52
56
|
|
53
|
-
def on_complete
|
54
|
-
if
|
55
|
-
@on_complete_callbacks <<
|
57
|
+
def on_complete(&block)
|
58
|
+
if !finished?
|
59
|
+
@on_complete_callbacks << block
|
56
60
|
else
|
57
61
|
yield(env)
|
58
62
|
end
|
data/lib/faraday/upload_io.rb
CHANGED
@@ -1,10 +1,15 @@
|
|
1
1
|
begin
|
2
|
-
require '
|
3
|
-
require 'parts'
|
2
|
+
require 'multipart/post'
|
4
3
|
require 'stringio'
|
5
4
|
rescue LoadError
|
6
|
-
|
7
|
-
|
5
|
+
begin
|
6
|
+
require 'composite_io'
|
7
|
+
require 'parts'
|
8
|
+
require 'stringio'
|
9
|
+
rescue LoadError
|
10
|
+
$stderr.puts "Install the multipart-post gem."
|
11
|
+
raise
|
12
|
+
end
|
8
13
|
end
|
9
14
|
|
10
15
|
module Faraday
|
@@ -62,6 +67,11 @@ module Faraday
|
|
62
67
|
end
|
63
68
|
end
|
64
69
|
|
65
|
-
|
66
|
-
|
70
|
+
if defined?(::Multipart::Post::UploadIO)
|
71
|
+
UploadIO = ::Multipart::Post::UploadIO
|
72
|
+
Parts = ::Multipart::Post::Parts
|
73
|
+
else
|
74
|
+
UploadIO = ::UploadIO
|
75
|
+
Parts = ::Parts
|
76
|
+
end
|
67
77
|
end
|
data/lib/faraday/utils.rb
CHANGED
@@ -10,12 +10,22 @@ module Faraday
|
|
10
10
|
new(value)
|
11
11
|
end
|
12
12
|
|
13
|
+
def self.allocate
|
14
|
+
new_self = super
|
15
|
+
new_self.initialize_names
|
16
|
+
new_self
|
17
|
+
end
|
18
|
+
|
13
19
|
def initialize(hash = nil)
|
14
20
|
super()
|
15
21
|
@names = {}
|
16
22
|
self.update(hash || {})
|
17
23
|
end
|
18
24
|
|
25
|
+
def initialize_names
|
26
|
+
@names = {}
|
27
|
+
end
|
28
|
+
|
19
29
|
# on dup/clone, we need to duplicate @names hash
|
20
30
|
def initialize_copy(other)
|
21
31
|
super
|
@@ -95,9 +105,16 @@ module Faraday
|
|
95
105
|
|
96
106
|
def parse(header_string)
|
97
107
|
return unless header_string && !header_string.empty?
|
98
|
-
|
108
|
+
|
109
|
+
headers = header_string.split(/\r\n/)
|
110
|
+
|
111
|
+
# Find the last set of response headers.
|
112
|
+
start_index = headers.rindex { |x| x.match(/^HTTP\//) } || 0
|
113
|
+
last_response = headers.slice(start_index, headers.size)
|
114
|
+
|
115
|
+
last_response.
|
99
116
|
tap { |a| a.shift if a.first.index('HTTP/') == 0 }. # drop the HTTP status line
|
100
|
-
map { |h| h.split(/:\s
|
117
|
+
map { |h| h.split(/:\s*/, 2) }.reject { |p| p[0].nil? }. # split key and value, ignore blank lines
|
101
118
|
each { |key, value|
|
102
119
|
# join multiple values with a comma
|
103
120
|
if self[key]
|