faraday 0.8.11 → 0.9.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +6 -0
- data/CONTRIBUTING.md +36 -0
- data/Gemfile +7 -6
- data/LICENSE.md +1 -1
- data/README.md +38 -51
- data/Rakefile +2 -18
- data/faraday.gemspec +34 -0
- data/lib/faraday.rb +181 -67
- data/lib/faraday/adapter.rb +19 -34
- data/lib/faraday/adapter/em_http.rb +24 -10
- data/lib/faraday/adapter/em_synchrony.rb +1 -15
- data/lib/faraday/adapter/excon.rb +6 -12
- data/lib/faraday/adapter/httpclient.rb +92 -0
- data/lib/faraday/adapter/net_http.rb +2 -3
- data/lib/faraday/adapter/net_http_persistent.rb +3 -15
- data/lib/faraday/adapter/patron.rb +13 -21
- data/lib/faraday/adapter/rack.rb +0 -2
- data/lib/faraday/adapter/test.rb +35 -36
- data/lib/faraday/adapter/typhoeus.rb +10 -12
- data/lib/faraday/autoload.rb +87 -0
- data/lib/faraday/connection.rb +196 -99
- data/lib/faraday/error.rb +33 -33
- data/lib/faraday/options.rb +215 -0
- data/lib/faraday/parameters.rb +193 -0
- data/lib/faraday/{builder.rb → rack_builder.rb} +78 -21
- data/lib/faraday/request.rb +12 -25
- data/lib/faraday/request/authorization.rb +3 -3
- data/lib/faraday/request/basic_authentication.rb +1 -1
- data/lib/faraday/request/instrumentation.rb +38 -0
- data/lib/faraday/request/multipart.rb +10 -9
- data/lib/faraday/request/retry.rb +70 -6
- data/lib/faraday/request/token_authentication.rb +2 -2
- data/lib/faraday/request/url_encoded.rb +7 -6
- data/lib/faraday/response.rb +17 -22
- data/lib/faraday/response/logger.rb +4 -4
- data/lib/faraday/response/raise_error.rb +4 -5
- data/lib/faraday/utils.rb +54 -67
- data/script/console +7 -0
- data/script/release +6 -3
- data/script/server +3 -1
- data/script/test +7 -33
- data/test/adapters/em_http_test.rb +6 -1
- data/test/adapters/em_synchrony_test.rb +7 -1
- data/test/adapters/excon_test.rb +0 -7
- data/test/adapters/httpclient_test.rb +16 -0
- data/test/adapters/integration.rb +8 -39
- data/test/adapters/logger_test.rb +1 -1
- data/test/adapters/net_http_test.rb +0 -31
- data/test/adapters/patron_test.rb +1 -1
- data/test/adapters/rack_test.rb +0 -5
- data/test/adapters/test_middleware_test.rb +19 -4
- data/test/adapters/typhoeus_test.rb +20 -3
- data/test/authentication_middleware_test.rb +7 -7
- data/test/connection_test.rb +52 -75
- data/test/env_test.rb +33 -24
- data/test/helper.rb +15 -13
- data/test/live_server.rb +10 -4
- data/test/middleware/instrumentation_test.rb +75 -0
- data/test/middleware/retry_test.rb +44 -38
- data/test/middleware_stack_test.rb +12 -11
- data/test/options_test.rb +126 -0
- data/test/request_middleware_test.rb +17 -7
- data/test/response_middleware_test.rb +2 -4
- data/test/strawberry.rb +2 -0
- metadata +82 -28
- checksums.yaml +0 -7
- data/script/proxy-server +0 -41
- data/test/multibyte.txt +0 -1
- data/test/parameters_test.rb +0 -24
- data/test/utils_test.rb +0 -30
data/lib/faraday/response.rb
CHANGED
@@ -13,43 +13,37 @@ module Faraday
|
|
13
13
|
# Override this to modify the environment after the response has finished.
|
14
14
|
# Calls the `parse` method if defined
|
15
15
|
def on_complete(env)
|
16
|
-
if respond_to?
|
17
|
-
env[:body] = parse(env[:body]) unless [204,304].index env[:status]
|
18
|
-
end
|
16
|
+
env.body = parse(env.body) if respond_to?(:parse) && env.parse_body?
|
19
17
|
end
|
20
18
|
end
|
21
19
|
|
22
20
|
extend Forwardable
|
23
|
-
extend AutoloadHelper
|
24
21
|
extend MiddlewareRegistry
|
25
22
|
|
26
|
-
|
27
|
-
:
|
28
|
-
:
|
29
|
-
|
30
|
-
register_middleware \
|
31
|
-
:raise_error => :RaiseError,
|
32
|
-
:logger => :Logger
|
23
|
+
register_middleware File.expand_path('../response', __FILE__),
|
24
|
+
:raise_error => [:RaiseError, 'raise_error'],
|
25
|
+
:logger => [:Logger, 'logger']
|
33
26
|
|
34
27
|
def initialize(env = nil)
|
35
|
-
@env = env
|
28
|
+
@env = Env.from(env) if env
|
36
29
|
@on_complete_callbacks = []
|
37
30
|
end
|
38
31
|
|
39
32
|
attr_reader :env
|
40
|
-
|
33
|
+
|
34
|
+
def_delegators :env, :to_hash
|
41
35
|
|
42
36
|
def status
|
43
|
-
finished? ? env
|
37
|
+
finished? ? env.status : nil
|
44
38
|
end
|
45
39
|
|
46
40
|
def headers
|
47
|
-
finished? ? env
|
41
|
+
finished? ? env.response_headers : {}
|
48
42
|
end
|
49
43
|
def_delegator :headers, :[]
|
50
44
|
|
51
45
|
def body
|
52
|
-
finished? ? env
|
46
|
+
finished? ? env.body : nil
|
53
47
|
end
|
54
48
|
|
55
49
|
def finished?
|
@@ -67,33 +61,34 @@ module Faraday
|
|
67
61
|
|
68
62
|
def finish(env)
|
69
63
|
raise "response already finished" if finished?
|
70
|
-
@env = env
|
64
|
+
@env = Env.from(env)
|
71
65
|
@on_complete_callbacks.each { |callback| callback.call(env) }
|
72
66
|
return self
|
73
67
|
end
|
74
68
|
|
75
69
|
def success?
|
76
|
-
|
70
|
+
finished? && env.success?
|
77
71
|
end
|
78
72
|
|
79
73
|
# because @on_complete_callbacks cannot be marshalled
|
80
74
|
def marshal_dump
|
81
75
|
!finished? ? nil : {
|
82
|
-
:status => @env
|
83
|
-
:response_headers => @env
|
76
|
+
:status => @env.status, :body => @env.body,
|
77
|
+
:response_headers => @env.response_headers
|
84
78
|
}
|
85
79
|
end
|
86
80
|
|
87
81
|
def marshal_load(env)
|
88
|
-
@env = env
|
82
|
+
@env = Env.from(env)
|
89
83
|
end
|
90
84
|
|
91
85
|
# Expand the env with more properties, without overriding existing ones.
|
92
86
|
# Useful for applying request params after restoring a marshalled Response.
|
93
87
|
def apply_request(request_env)
|
94
88
|
raise "response didn't finish yet" unless finished?
|
95
|
-
@env = request_env.merge
|
89
|
+
@env = Env.from(request_env).merge(@env)
|
96
90
|
return self
|
97
91
|
end
|
98
92
|
end
|
99
93
|
end
|
94
|
+
|
@@ -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
|
19
|
-
debug('request') { dump_headers env
|
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
|
25
|
-
debug('response') { dump_headers env
|
24
|
+
info('Status') { env.status.to_s }
|
25
|
+
debug('response') { dump_headers env.response_headers }
|
26
26
|
end
|
27
27
|
|
28
28
|
private
|
@@ -1,19 +1,18 @@
|
|
1
1
|
module Faraday
|
2
2
|
class Response::RaiseError < Response::Middleware
|
3
|
+
ClientErrorStatuses = 400...600
|
4
|
+
|
3
5
|
def on_complete(env)
|
4
6
|
case env[:status]
|
5
7
|
when 404
|
6
8
|
raise Faraday::Error::ResourceNotFound, response_values(env)
|
7
|
-
when
|
8
|
-
# mimic the behavior that we get with proxy requests with HTTPS
|
9
|
-
raise Faraday::Error::ConnectionFailed, %{407 "Proxy Authentication Required "}
|
10
|
-
when 400...600
|
9
|
+
when ClientErrorStatuses
|
11
10
|
raise Faraday::Error::ClientError, response_values(env)
|
12
11
|
end
|
13
12
|
end
|
14
13
|
|
15
14
|
def response_values(env)
|
16
|
-
{:status => env
|
15
|
+
{:status => env.status, :headers => env.response_headers, :body => env.body}
|
17
16
|
end
|
18
17
|
end
|
19
18
|
end
|
data/lib/faraday/utils.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
require '
|
1
|
+
require 'uri'
|
2
|
+
require 'thread'
|
3
|
+
Faraday.require_libs 'parameters'
|
2
4
|
|
3
5
|
module Faraday
|
4
6
|
module Utils
|
@@ -6,26 +8,28 @@ module Faraday
|
|
6
8
|
|
7
9
|
# Adapted from Rack::Utils::HeaderHash
|
8
10
|
class Headers < ::Hash
|
11
|
+
def self.from(value)
|
12
|
+
new(value)
|
13
|
+
end
|
14
|
+
|
9
15
|
def initialize(hash={})
|
10
16
|
super()
|
11
17
|
@names = {}
|
12
18
|
self.update hash
|
13
19
|
end
|
14
20
|
|
15
|
-
#
|
16
|
-
|
17
|
-
super
|
18
|
-
@names = other.names.dup
|
19
|
-
end
|
21
|
+
# need to synchronize concurrent writes to the shared KeyMap
|
22
|
+
keymap_mutex = Mutex.new
|
20
23
|
|
21
24
|
# symbol -> string mapper + cache
|
22
25
|
KeyMap = Hash.new do |map, key|
|
23
|
-
|
26
|
+
value = if key.respond_to?(:to_str) then key
|
24
27
|
else
|
25
28
|
key.to_s.split('_'). # :user_agent => %w(user agent)
|
26
29
|
each { |w| w.capitalize! }. # => %w(User Agent)
|
27
30
|
join('-') # => "User-Agent"
|
28
31
|
end
|
32
|
+
keymap_mutex.synchronize { map[key] = value }
|
29
33
|
end
|
30
34
|
KeyMap[:etag] = "ETag"
|
31
35
|
|
@@ -71,7 +75,6 @@ module Faraday
|
|
71
75
|
|
72
76
|
def replace(other)
|
73
77
|
clear
|
74
|
-
@names.clear
|
75
78
|
self.update other
|
76
79
|
self
|
77
80
|
end
|
@@ -90,12 +93,6 @@ module Faraday
|
|
90
93
|
end
|
91
94
|
}
|
92
95
|
end
|
93
|
-
|
94
|
-
protected
|
95
|
-
|
96
|
-
def names
|
97
|
-
@names
|
98
|
-
end
|
99
96
|
end
|
100
97
|
|
101
98
|
# hash with stringified keys
|
@@ -137,15 +134,15 @@ module Faraday
|
|
137
134
|
update(other)
|
138
135
|
end
|
139
136
|
|
140
|
-
def merge_query(query)
|
137
|
+
def merge_query(query, encoder = nil)
|
141
138
|
if query && !query.empty?
|
142
|
-
update Utils.
|
139
|
+
update((encoder || Utils.default_params_encoder).decode(query))
|
143
140
|
end
|
144
141
|
self
|
145
142
|
end
|
146
143
|
|
147
|
-
def to_query
|
148
|
-
Utils.
|
144
|
+
def to_query(encoder = nil)
|
145
|
+
(encoder || Utils.default_params_encoder).encode(self)
|
149
146
|
end
|
150
147
|
|
151
148
|
private
|
@@ -155,39 +152,19 @@ module Faraday
|
|
155
152
|
end
|
156
153
|
end
|
157
154
|
|
158
|
-
# Copied from Rack
|
159
155
|
def build_query(params)
|
160
|
-
params
|
161
|
-
if v.class == Array
|
162
|
-
build_query(v.map { |x| [k, x] })
|
163
|
-
else
|
164
|
-
v.nil? ? escape(k) : "#{escape(k)}=#{escape(v)}"
|
165
|
-
end
|
166
|
-
}.join("&")
|
156
|
+
FlatParamsEncoder.encode(params)
|
167
157
|
end
|
168
158
|
|
169
|
-
|
170
|
-
|
171
|
-
case value
|
172
|
-
when Array
|
173
|
-
value.map { |v| build_nested_query(v, "#{prefix}%5B%5D") }.join("&")
|
174
|
-
when Hash
|
175
|
-
value.map { |k, v|
|
176
|
-
build_nested_query(v, prefix ? "#{prefix}%5B#{escape(k)}%5D" : escape(k))
|
177
|
-
}.join("&")
|
178
|
-
when NilClass
|
179
|
-
prefix
|
180
|
-
else
|
181
|
-
raise ArgumentError, "value must be a Hash" if prefix.nil?
|
182
|
-
"#{prefix}=#{escape(value)}"
|
183
|
-
end
|
159
|
+
def build_nested_query(params)
|
160
|
+
NestedParamsEncoder.encode(params)
|
184
161
|
end
|
185
162
|
|
186
163
|
ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/
|
187
164
|
|
188
165
|
def escape(s)
|
189
|
-
s.to_s.gsub(ESCAPE_RE) {
|
190
|
-
'%' +
|
166
|
+
s.to_s.gsub(ESCAPE_RE) {
|
167
|
+
'%' + $&.unpack('H2' * $&.bytesize).join('%').upcase
|
191
168
|
}.tr(' ', '+')
|
192
169
|
end
|
193
170
|
|
@@ -196,31 +173,20 @@ module Faraday
|
|
196
173
|
DEFAULT_SEP = /[&;] */n
|
197
174
|
|
198
175
|
# Adapted from Rack
|
199
|
-
def parse_query(
|
200
|
-
|
201
|
-
|
202
|
-
(qs || '').split(DEFAULT_SEP).each do |p|
|
203
|
-
k, v = p.split('=', 2).map { |x| unescape(x) }
|
176
|
+
def parse_query(query)
|
177
|
+
FlatParamsEncoder.decode(query)
|
178
|
+
end
|
204
179
|
|
205
|
-
|
206
|
-
|
207
|
-
else params[k] = [cur, v]
|
208
|
-
end
|
209
|
-
else
|
210
|
-
params[k] = v
|
211
|
-
end
|
212
|
-
end
|
213
|
-
params
|
180
|
+
def parse_nested_query(query)
|
181
|
+
NestedParamsEncoder.decode(query)
|
214
182
|
end
|
215
183
|
|
216
|
-
def
|
217
|
-
|
184
|
+
def default_params_encoder
|
185
|
+
@default_params_encoder ||= NestedParamsEncoder
|
186
|
+
end
|
218
187
|
|
219
|
-
|
220
|
-
|
221
|
-
normalize_params(params, k, v)
|
222
|
-
end
|
223
|
-
params
|
188
|
+
class << self
|
189
|
+
attr_writer :default_params_encoder
|
224
190
|
end
|
225
191
|
|
226
192
|
# Stolen from Rack
|
@@ -232,7 +198,12 @@ module Faraday
|
|
232
198
|
return if k.empty?
|
233
199
|
|
234
200
|
if after == ""
|
235
|
-
params[k]
|
201
|
+
if params[k]
|
202
|
+
params[k] = Array[params[k]] unless params[k].kind_of?(Array)
|
203
|
+
params[k] << v
|
204
|
+
else
|
205
|
+
params[k] = v
|
206
|
+
end
|
236
207
|
elsif after == "[]"
|
237
208
|
params[k] ||= []
|
238
209
|
raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
|
@@ -255,9 +226,25 @@ module Faraday
|
|
255
226
|
return params
|
256
227
|
end
|
257
228
|
|
258
|
-
#
|
229
|
+
# Normalize URI() behavior across Ruby versions
|
230
|
+
#
|
231
|
+
# url - A String or URI.
|
232
|
+
#
|
233
|
+
# Returns a parsed URI.
|
234
|
+
def URI(url)
|
235
|
+
if url.respond_to?(:host)
|
236
|
+
url
|
237
|
+
elsif url.respond_to?(:to_str)
|
238
|
+
Kernel.URI(url)
|
239
|
+
else
|
240
|
+
raise ArgumentError, "bad argument (expected URI object or URI string)"
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
# Receives a String or URI and returns just the path with the query string sorted.
|
259
245
|
def normalize_path(url)
|
260
|
-
|
246
|
+
url = URI(url)
|
247
|
+
(url.path.start_with?('/') ? url.path : '/' + url.path) +
|
261
248
|
(url.query ? "?#{sort_query_params(url.query)}" : "")
|
262
249
|
end
|
263
250
|
|
data/script/console
ADDED
data/script/release
CHANGED
@@ -8,7 +8,10 @@ set -e
|
|
8
8
|
version="$(script/package | grep Version: | awk '{print $2}')"
|
9
9
|
[ -n "$version" ] || exit 1
|
10
10
|
|
11
|
-
git commit -a -m "
|
12
|
-
git tag "v$
|
13
|
-
git push origin
|
11
|
+
git commit --allow-empty -a -m "Release $version"
|
12
|
+
git tag "v$version"
|
13
|
+
git push origin
|
14
|
+
git push origin "v$version"
|
15
|
+
git push legacy
|
16
|
+
git push legacy "v$version"
|
14
17
|
gem push pkg/*-${version}.gem
|
data/script/server
CHANGED
@@ -6,13 +6,15 @@ ensure
|
|
6
6
|
$VERBOSE = old_verbose
|
7
7
|
end
|
8
8
|
require 'webrick'
|
9
|
+
require 'fileutils'
|
9
10
|
|
10
11
|
port = 4000
|
11
12
|
if found = ARGV.index('-p')
|
12
13
|
port = ARGV[found + 1].to_i
|
13
14
|
end
|
14
15
|
|
15
|
-
|
16
|
+
FileUtils.mkdir_p('log')
|
17
|
+
log_io = File.open('log/test.log', 'w')
|
16
18
|
log_io.sync = true
|
17
19
|
|
18
20
|
webrick_opts = {
|
data/script/test
CHANGED
@@ -24,7 +24,6 @@ if [[ "$RUBYOPT" != *"bundler/setup"* ]]; then
|
|
24
24
|
fi
|
25
25
|
|
26
26
|
port=3999
|
27
|
-
proxy_port=3998
|
28
27
|
scheme=http
|
29
28
|
|
30
29
|
if [ "$SSL" = "yes" ]; then
|
@@ -48,18 +47,12 @@ filter_matching() {
|
|
48
47
|
|
49
48
|
start_server() {
|
50
49
|
mkdir -p log
|
51
|
-
script/server -p $port >log/
|
52
|
-
echo $!
|
53
|
-
}
|
54
|
-
|
55
|
-
start_proxy() {
|
56
|
-
mkdir -p log
|
57
|
-
script/proxy-server -p $proxy_port -u "faraday@test.local:there is cake" >log/proxy.log 2>&1 &
|
50
|
+
script/server -p $port >log/server.log 2>&1 &
|
58
51
|
echo $!
|
59
52
|
}
|
60
53
|
|
61
54
|
server_started() {
|
62
|
-
lsof -i :$
|
55
|
+
lsof -i :$port >/dev/null
|
63
56
|
}
|
64
57
|
|
65
58
|
timestamp() {
|
@@ -69,7 +62,7 @@ timestamp() {
|
|
69
62
|
wait_for_server() {
|
70
63
|
timeout=$(( `timestamp` + $1 ))
|
71
64
|
while true; do
|
72
|
-
if server_started
|
65
|
+
if server_started; then
|
73
66
|
break
|
74
67
|
elif [ `timestamp` -gt "$timeout" ]; then
|
75
68
|
echo "timed out after $1 seconds" >&2
|
@@ -116,45 +109,27 @@ fi
|
|
116
109
|
|
117
110
|
# If there are any adapter tests, spin up the HTTP server
|
118
111
|
if [ -n "$(filter_matching "adapters" "${test_files[@]}")" ]; then
|
119
|
-
if server_started
|
112
|
+
if server_started; then
|
120
113
|
echo "aborted: another instance of server running on $port" >&2
|
121
114
|
exit 1
|
122
115
|
fi
|
123
116
|
server_pid=$(start_server)
|
124
|
-
|
125
|
-
|
126
|
-
cat log/test.log
|
117
|
+
wait_for_server 15 || {
|
118
|
+
cat log/server.log
|
127
119
|
exit 1
|
128
120
|
}
|
129
|
-
wait_for_server 5 $proxy_port
|
130
121
|
cleanup() {
|
131
122
|
if [ $? -ne 0 ] && [ -n "$TRAVIS" ]; then
|
132
123
|
cat log/test.log
|
133
124
|
fi
|
134
125
|
kill "$server_pid"
|
135
|
-
kill "$proxy_pid"
|
136
126
|
}
|
137
127
|
trap cleanup INT EXIT
|
138
128
|
export LIVE="${scheme}://localhost:${port}"
|
139
|
-
export LIVE_PROXY="http://faraday%40test.local:there%20is%20cake@localhost:${proxy_port}"
|
140
129
|
fi
|
141
130
|
|
142
|
-
warnings="${TMPDIR:-/tmp}/faraday-warnings.$$"
|
143
|
-
|
144
131
|
run_test_files() {
|
145
|
-
|
146
|
-
RUBYOPT="$RUBYOPT -w" ruby -e 'while f=ARGV.shift and f!="--"; load f; end' "${test_files[@]}" -- "$@" \
|
147
|
-
2> >(tee >(grep 'warning:' >"$warnings") | grep -v 'warning:')
|
148
|
-
}
|
149
|
-
|
150
|
-
check_warnings() {
|
151
|
-
# Display Ruby warnings from this project's source files. Abort if any were found.
|
152
|
-
num="$(grep -F "$PWD" "$warnings" | grep -v "${PWD}/vendor/bundle" | sort | uniq -c | sort -rn | tee /dev/stderr | wc -l)"
|
153
|
-
rm -f "$warnings"
|
154
|
-
if [ "$num" -gt 0 ]; then
|
155
|
-
echo "FAILED: this test suite doesn't tolerate Ruby syntax warnings!" >&2
|
156
|
-
exit 1
|
157
|
-
fi
|
132
|
+
ruby -e 'while f=ARGV.shift and f!="--"; load f; end' "${test_files[@]}" -- "$@"
|
158
133
|
}
|
159
134
|
|
160
135
|
if [ -n "$RBENV_VERSIONS" ]; then
|
@@ -167,4 +142,3 @@ else
|
|
167
142
|
run_test_files "$@"
|
168
143
|
fi
|
169
144
|
|
170
|
-
check_warnings
|