faraday 0.8.11 → 0.9.0.rc1
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.
- 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
|