faraday 0.5.7 → 0.6.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.
- data/Gemfile +9 -8
- data/README.md +99 -20
- data/faraday.gemspec +9 -11
- data/lib/faraday.rb +1 -1
- data/lib/faraday/adapter.rb +11 -86
- data/lib/faraday/adapter/action_dispatch.rb +3 -12
- data/lib/faraday/adapter/em_synchrony.rb +9 -24
- data/lib/faraday/adapter/excon.rb +7 -19
- data/lib/faraday/adapter/net_http.rb +37 -35
- data/lib/faraday/adapter/patron.rb +16 -23
- data/lib/faraday/adapter/test.rb +4 -10
- data/lib/faraday/adapter/typhoeus.rb +11 -39
- data/lib/faraday/builder.rb +82 -33
- data/lib/faraday/connection.rb +3 -10
- data/lib/faraday/error.rb +20 -15
- data/lib/faraday/middleware.rb +7 -2
- data/lib/faraday/request.rb +13 -10
- data/lib/faraday/request/json.rb +31 -0
- data/lib/faraday/request/multipart.rb +63 -0
- data/lib/faraday/request/url_encoded.rb +37 -0
- data/lib/faraday/response.rb +72 -30
- data/lib/faraday/response/logger.rb +34 -0
- data/lib/faraday/response/raise_error.rb +16 -0
- data/lib/faraday/upload_io.rb +14 -6
- data/lib/faraday/utils.rb +54 -17
- data/test/adapters/live_test.rb +36 -14
- data/test/adapters/logger_test.rb +1 -1
- data/test/adapters/net_http_test.rb +33 -0
- data/test/connection_test.rb +0 -39
- data/test/env_test.rb +84 -6
- data/test/helper.rb +17 -8
- data/test/live_server.rb +19 -17
- data/test/middleware_stack_test.rb +91 -0
- data/test/request_middleware_test.rb +75 -21
- data/test/response_middleware_test.rb +34 -31
- metadata +21 -17
- data/lib/faraday/adapter/logger.rb +0 -32
- data/lib/faraday/request/active_support_json.rb +0 -21
- data/lib/faraday/request/yajl.rb +0 -18
- data/lib/faraday/response/active_support_json.rb +0 -30
- data/lib/faraday/response/yajl.rb +0 -26
- data/test/adapters/typhoeus_test.rb +0 -31
- data/test/connection_app_test.rb +0 -60
- data/test/form_post_test.rb +0 -58
- data/test/multipart_test.rb +0 -48
data/lib/faraday/utils.rb
CHANGED
@@ -6,22 +6,64 @@ module Faraday
|
|
6
6
|
extend Rack::Utils
|
7
7
|
extend self
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
9
|
+
class Headers < HeaderHash
|
10
|
+
# symbol -> string mapper + cache
|
11
|
+
KeyMap = Hash.new do |map, key|
|
12
|
+
map[key] = if key.respond_to?(:to_str) then key
|
13
|
+
else
|
14
|
+
key.to_s.split('_'). # :user_agent => %w(user agent)
|
15
|
+
each { |w| w.capitalize! }. # => %w(User Agent)
|
16
|
+
join('-') # => "User-Agent"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
KeyMap[:etag] = "ETag"
|
20
|
+
|
21
|
+
def [](k)
|
22
|
+
super(KeyMap[k])
|
16
23
|
end
|
17
|
-
end
|
18
24
|
|
19
|
-
|
20
|
-
|
25
|
+
def []=(k, v)
|
26
|
+
# join multiple values with a comma
|
27
|
+
v = v.to_ary.join(', ') if v.respond_to? :to_ary
|
28
|
+
super(KeyMap[k], v)
|
29
|
+
end
|
30
|
+
|
31
|
+
alias_method :update, :merge!
|
32
|
+
|
33
|
+
def parse(header_string)
|
34
|
+
return unless header_string && !header_string.empty?
|
35
|
+
header_string.split(/\r\n/).
|
36
|
+
tap { |a| a.shift if a.first.index('HTTP/') == 0 }. # drop the HTTP status line
|
37
|
+
map { |h| h.split(/:\s+/, 2) }.reject { |(k, v)| k.nil? }. # split key and value, ignore blank lines
|
38
|
+
each { |key, value|
|
39
|
+
# join multiple values with a comma
|
40
|
+
if self[key] then self[key] << ', ' << value
|
41
|
+
else self[key] = value
|
42
|
+
end
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
21
46
|
|
22
47
|
# Make Rack::Utils build_query method public.
|
23
48
|
public :build_query
|
24
49
|
|
50
|
+
# Override Rack's version since it doesn't handle non-String values
|
51
|
+
def build_nested_query(value, prefix = nil)
|
52
|
+
case value
|
53
|
+
when Array
|
54
|
+
value.map { |v| build_nested_query(v, "#{prefix}[]") }.join("&")
|
55
|
+
when Hash
|
56
|
+
value.map { |k, v|
|
57
|
+
build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
|
58
|
+
}.join("&")
|
59
|
+
when NilClass
|
60
|
+
prefix
|
61
|
+
else
|
62
|
+
raise ArgumentError, "value must be a Hash" if prefix.nil?
|
63
|
+
"#{prefix}=#{escape(value)}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
25
67
|
# Be sure to URI escape '+' symbols to %2B. Otherwise, they get interpreted
|
26
68
|
# as spaces.
|
27
69
|
def escape(s)
|
@@ -37,15 +79,10 @@ module Faraday
|
|
37
79
|
end
|
38
80
|
end
|
39
81
|
|
40
|
-
# Turns headers keys and values into strings
|
41
|
-
# the HEADERS hash.
|
42
|
-
#
|
43
|
-
# h = merge_headers(HeaderHash.new, :content_type => 'text/plain')
|
44
|
-
# h['Content-Type'] # = 'text/plain'
|
45
|
-
#
|
82
|
+
# Turns headers keys and values into strings
|
46
83
|
def merge_headers(existing_headers, new_headers)
|
47
84
|
new_headers.each do |key, value|
|
48
|
-
existing_headers[
|
85
|
+
existing_headers[key] = value.to_s
|
49
86
|
end
|
50
87
|
end
|
51
88
|
|
data/test/adapters/live_test.rb
CHANGED
@@ -1,12 +1,19 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'helper'))
|
2
2
|
|
3
|
-
if Faraday::TestCase::LIVE_SERVER
|
3
|
+
if !Faraday::TestCase::LIVE_SERVER
|
4
|
+
warn "warning: test server is not up; skipping live server tests"
|
5
|
+
else
|
4
6
|
module Adapters
|
5
7
|
class LiveTest < Faraday::TestCase
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
adapters = if ENV['ADAPTER']
|
9
|
+
ENV['ADAPTER'].split(':').map { |name| Faraday::Adapter.lookup_module name.to_sym }
|
10
|
+
else
|
11
|
+
loaded_adapters = Faraday::Adapter.all_loaded_constants
|
12
|
+
loaded_adapters -= [Faraday::Adapter::ActionDispatch]
|
13
|
+
loaded_adapters << :default
|
14
|
+
end
|
15
|
+
|
16
|
+
adapters.each do |adapter|
|
10
17
|
define_method "test_#{adapter}_GET_retrieves_the_response_body" do
|
11
18
|
assert_equal 'hello world', create_connection(adapter).get('hello_world').body
|
12
19
|
end
|
@@ -19,7 +26,17 @@ if Faraday::TestCase::LIVE_SERVER
|
|
19
26
|
end
|
20
27
|
|
21
28
|
define_method "test_#{adapter}_GET_retrieves_the_response_headers" do
|
22
|
-
|
29
|
+
response = create_connection(adapter).get('hello_world')
|
30
|
+
assert_match /text\/html/, response.headers['Content-Type'], 'original case fail'
|
31
|
+
assert_match /text\/html/, response.headers['content-type'], 'lowercase fail'
|
32
|
+
end
|
33
|
+
|
34
|
+
# https://github.com/geemus/excon/issues/10
|
35
|
+
unless %[Faraday::Adapter::Excon] == adapter.to_s
|
36
|
+
define_method "test_#{adapter}_GET_handles_headers_with_multiple_values" do
|
37
|
+
response = create_connection(adapter).get('multi')
|
38
|
+
assert_equal 'one, two', response.headers['set-cookie']
|
39
|
+
end
|
23
40
|
end
|
24
41
|
|
25
42
|
define_method "test_#{adapter}_POST_send_url_encoded_params" do
|
@@ -43,13 +60,12 @@ if Faraday::TestCase::LIVE_SERVER
|
|
43
60
|
end
|
44
61
|
|
45
62
|
define_method "test_#{adapter}_POST_sends_files" do
|
46
|
-
name = File.join(File.dirname(__FILE__), '..', 'live_server.rb')
|
47
63
|
resp = create_connection(adapter).post do |req|
|
48
64
|
req.url 'file'
|
49
|
-
req.body = {'uploaded_file' => Faraday::UploadIO.new(
|
65
|
+
req.body = {'uploaded_file' => Faraday::UploadIO.new(__FILE__, 'text/x-ruby')}
|
50
66
|
end
|
51
|
-
assert_equal "file
|
52
|
-
end
|
67
|
+
assert_equal "file live_test.rb text/x-ruby", resp.body
|
68
|
+
end unless :default == adapter # isn't configured for multipart
|
53
69
|
|
54
70
|
# http://github.com/toland/patron/issues/#issue/9
|
55
71
|
if ENV['FORCE'] || adapter != Faraday::Adapter::Patron
|
@@ -142,13 +158,19 @@ if Faraday::TestCase::LIVE_SERVER
|
|
142
158
|
|
143
159
|
def create_connection(adapter)
|
144
160
|
if adapter == :default
|
145
|
-
|
146
|
-
|
147
|
-
|
161
|
+
Faraday.default_connection.tap do |conn|
|
162
|
+
conn.url_prefix = LIVE_SERVER
|
163
|
+
conn.headers['X-Faraday-Adapter'] = adapter.to_s
|
164
|
+
end
|
148
165
|
else
|
149
|
-
Faraday::Connection.new LIVE_SERVER do |b|
|
166
|
+
Faraday::Connection.new LIVE_SERVER, :headers => {'X-Faraday-Adapter' => adapter.to_s} do |b|
|
167
|
+
b.request :multipart
|
168
|
+
b.request :url_encoded
|
150
169
|
b.use adapter
|
151
170
|
end
|
171
|
+
end.tap do |conn|
|
172
|
+
target = conn.builder.handlers.last
|
173
|
+
conn.builder.insert_before target, Faraday::Response::RaiseError
|
152
174
|
end
|
153
175
|
end
|
154
176
|
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'helper'))
|
2
|
+
|
3
|
+
module Adapters
|
4
|
+
class NetHttpTest < Faraday::TestCase
|
5
|
+
def setup
|
6
|
+
@connection = Faraday.new('http://disney.com') do |b|
|
7
|
+
b.adapter :net_http
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_handles_compression_transparently_on_get
|
12
|
+
stub_request(:get, 'disney.com/hello').with { |request|
|
13
|
+
accept_encoding = request.headers['Accept-Encoding']
|
14
|
+
if RUBY_VERSION.index('1.8') == 0
|
15
|
+
# ruby 1.8 doesn't do any gzip/deflate automatically
|
16
|
+
accept_encoding == nil
|
17
|
+
else
|
18
|
+
# test for a value such as "gzip;q=1.0,deflate;q=0.6,identity;q=0.3"
|
19
|
+
accept_encoding =~ /gzip;.+\bdeflate\b/
|
20
|
+
end
|
21
|
+
}
|
22
|
+
@connection.get('/hello')
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_connect_error_gets_wrapped
|
26
|
+
stub_request(:get, 'disney.com/hello').to_raise(Errno::ECONNREFUSED)
|
27
|
+
|
28
|
+
assert_raise Faraday::Error::ConnectionFailed do
|
29
|
+
@connection.get('/hello')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/test/connection_test.rb
CHANGED
@@ -242,43 +242,4 @@ class TestConnection < Faraday::TestCase
|
|
242
242
|
assert_not_equal conn.send(attr).object_id, duped.send(attr).object_id
|
243
243
|
end
|
244
244
|
end
|
245
|
-
|
246
|
-
def test_allows_rebuilding_of_connection_handlers
|
247
|
-
conn = Faraday::Connection.new
|
248
|
-
conn.to_app
|
249
|
-
inner = conn.builder.handlers[0]
|
250
|
-
mware = conn.builder.handlers[1].call({})
|
251
|
-
assert_kind_of Faraday::Adapter::NetHttp, mware
|
252
|
-
|
253
|
-
conn.build do |b|
|
254
|
-
b.adapter :test
|
255
|
-
end
|
256
|
-
mware = conn.builder.handlers[1].call({})
|
257
|
-
assert_kind_of Faraday::Adapter::Test, mware
|
258
|
-
assert_equal inner, conn.builder.handlers[0]
|
259
|
-
end
|
260
|
-
|
261
|
-
def test_allows_extending_of_existing_connection_handlers
|
262
|
-
conn = Faraday::Connection.new
|
263
|
-
conn.to_app
|
264
|
-
mware = conn.builder.handlers[1].call({})
|
265
|
-
assert_kind_of Faraday::Adapter::NetHttp, mware
|
266
|
-
assert_equal 2, conn.builder.handlers.size
|
267
|
-
|
268
|
-
conn.build :keep => true do |b|
|
269
|
-
b.adapter :test
|
270
|
-
end
|
271
|
-
mware = conn.builder.handlers[1].call({})
|
272
|
-
assert_kind_of Faraday::Adapter::Test, mware
|
273
|
-
assert_equal 3, conn.builder.handlers.size
|
274
|
-
end
|
275
|
-
|
276
|
-
def test_sets_default_adapter_if_none_set
|
277
|
-
conn = Faraday::Connection.new
|
278
|
-
assert_equal 0, conn.builder.handlers.size
|
279
|
-
|
280
|
-
app = conn.to_app
|
281
|
-
mware = conn.builder.handlers[1].call({})
|
282
|
-
assert_kind_of Faraday::Adapter::NetHttp, mware
|
283
|
-
end
|
284
245
|
end
|
data/test/env_test.rb
CHANGED
@@ -1,15 +1,13 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
2
2
|
|
3
|
-
class
|
3
|
+
class EnvTest < Faraday::TestCase
|
4
4
|
def setup
|
5
5
|
@conn = Faraday.new :url => 'http://sushi.com/api', :headers => {'Mime-Version' => '1.0'}
|
6
6
|
@conn.options[:timeout] = 3
|
7
7
|
@conn.options[:open_timeout] = 5
|
8
8
|
@conn.ssl[:verify] = false
|
9
9
|
@conn.proxy 'http://proxy.com'
|
10
|
-
@input = {
|
11
|
-
:body => 'abc',
|
12
|
-
:headers => {'Server' => 'Faraday'}}
|
10
|
+
@input = { :body => 'abc' }
|
13
11
|
@env = env_for @conn do |req|
|
14
12
|
req.url 'foo.json', 'a' => 1
|
15
13
|
req['Server'] = 'Faraday'
|
@@ -26,8 +24,9 @@ class TestEnv < Faraday::TestCase
|
|
26
24
|
end
|
27
25
|
|
28
26
|
def test_request_create_stores_headers
|
29
|
-
|
30
|
-
assert_equal
|
27
|
+
headers = @env[:request_headers]
|
28
|
+
assert_equal '1.0', headers['mime-version']
|
29
|
+
assert_equal 'Faraday', headers['server']
|
31
30
|
end
|
32
31
|
|
33
32
|
def test_request_create_stores_body
|
@@ -54,3 +53,82 @@ class TestEnv < Faraday::TestCase
|
|
54
53
|
env_setup.to_env_hash(connection, :get)
|
55
54
|
end
|
56
55
|
end
|
56
|
+
|
57
|
+
class HeadersTest < Faraday::TestCase
|
58
|
+
def setup
|
59
|
+
@headers = Faraday::Utils::Headers.new
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_parse_response_headers_leaves_http_status_line_out
|
63
|
+
@headers.parse("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n")
|
64
|
+
assert_equal %w(Content-Type), @headers.keys
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_parse_response_headers_parses_lower_cased_header_name_and_value
|
68
|
+
@headers.parse("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n")
|
69
|
+
assert_equal 'text/html', @headers['content-type']
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_parse_response_headers_parses_lower_cased_header_name_and_value_with_colon
|
73
|
+
@headers.parse("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nLocation: http://sushi.com/\r\n\r\n")
|
74
|
+
assert_equal 'http://sushi.com/', @headers['location']
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_parse_response_headers_parses_blank_lines
|
78
|
+
@headers.parse("HTTP/1.1 200 OK\r\n\r\nContent-Type: text/html\r\n\r\n")
|
79
|
+
assert_equal 'text/html', @headers['content-type']
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class ResponseTest < Faraday::TestCase
|
84
|
+
def setup
|
85
|
+
@env = {
|
86
|
+
:status => 404, :body => 'yikes',
|
87
|
+
:response_headers => Faraday::Utils::Headers.new('Content-Type' => 'text/plain')
|
88
|
+
}
|
89
|
+
@response = Faraday::Response.new @env
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_finished
|
93
|
+
assert @response.finished?
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_error_on_finish
|
97
|
+
assert_raises RuntimeError do
|
98
|
+
@response.finish({})
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_not_success
|
103
|
+
assert !@response.success?
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_status
|
107
|
+
assert_equal 404, @response.status
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_body
|
111
|
+
assert_equal 'yikes', @response.body
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_headers
|
115
|
+
assert_equal 'text/plain', @response.headers['Content-Type']
|
116
|
+
assert_equal 'text/plain', @response['content-type']
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_apply_request
|
120
|
+
@response.apply_request :body => 'a=b', :method => :post
|
121
|
+
assert_equal 'yikes', @response.body
|
122
|
+
assert_equal :post, @response.env[:method]
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_marshal
|
126
|
+
@response = Faraday::Response.new
|
127
|
+
@response.on_complete { }
|
128
|
+
@response.finish @env.merge(:custom => 'moo')
|
129
|
+
|
130
|
+
loaded = Marshal.load Marshal.dump(@response)
|
131
|
+
assert_nil loaded.env[:custom]
|
132
|
+
assert_equal %w[body response_headers status], loaded.env.keys.map { |k| k.to_s }.sort
|
133
|
+
end
|
134
|
+
end
|
data/test/helper.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
gem 'rack', '>= 1.2.1'
|
3
|
-
gem 'addressable', '>= 2.2.2'
|
4
|
-
|
5
1
|
require 'test/unit'
|
2
|
+
unless ENV['BUNDLE_GEMFILE']
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
Bundler.setup
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'webmock/test_unit'
|
9
|
+
WebMock.disable_net_connect!(:allow_localhost => true)
|
10
|
+
|
6
11
|
if ENV['LEFTRIGHT']
|
7
12
|
begin
|
8
13
|
require 'leftright'
|
@@ -11,14 +16,18 @@ if ENV['LEFTRIGHT']
|
|
11
16
|
end
|
12
17
|
end
|
13
18
|
|
14
|
-
$LOAD_PATH.
|
15
|
-
$LOAD_PATH.unshift(File.
|
19
|
+
unless $LOAD_PATH.include? 'lib'
|
20
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
21
|
+
$LOAD_PATH.unshift(File.join($LOAD_PATH.first, '..', 'lib'))
|
22
|
+
end
|
16
23
|
require 'faraday'
|
17
24
|
|
18
25
|
begin
|
19
26
|
require 'ruby-debug'
|
20
|
-
Debugger.start
|
21
27
|
rescue LoadError
|
28
|
+
# ignore
|
29
|
+
else
|
30
|
+
Debugger.start
|
22
31
|
end
|
23
32
|
|
24
33
|
module Faraday
|
@@ -31,6 +40,6 @@ module Faraday
|
|
31
40
|
|
32
41
|
def test_default
|
33
42
|
assert true
|
34
|
-
end
|
43
|
+
end unless defined? ::MiniTest
|
35
44
|
end
|
36
45
|
end
|
data/test/live_server.rb
CHANGED
@@ -1,39 +1,41 @@
|
|
1
1
|
require 'sinatra'
|
2
|
+
set :logging, false
|
2
3
|
|
3
4
|
get '/hello_world' do
|
4
5
|
'hello world'
|
5
6
|
end
|
6
7
|
|
7
8
|
get '/json' do
|
9
|
+
content_type 'application/json'
|
8
10
|
"[1,2,3]"
|
9
11
|
end
|
10
12
|
|
11
13
|
post '/file' do
|
12
|
-
|
13
|
-
|
14
|
-
|
14
|
+
if params[:uploaded_file].respond_to? :each_key
|
15
|
+
"file %s %s" % [
|
16
|
+
params[:uploaded_file][:filename],
|
17
|
+
params[:uploaded_file][:type]]
|
18
|
+
else
|
19
|
+
status 400
|
20
|
+
end
|
15
21
|
end
|
16
22
|
|
17
|
-
post
|
18
|
-
|
23
|
+
%w[get post].each do |method|
|
24
|
+
send(method, '/hello') do
|
25
|
+
"hello #{params[:name]}"
|
26
|
+
end
|
19
27
|
end
|
20
28
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
post '/echo_name' do
|
26
|
-
params[:name].inspect
|
27
|
-
end
|
28
|
-
|
29
|
-
put '/echo_name' do
|
30
|
-
params[:name].inspect
|
29
|
+
%w[post put].each do |method|
|
30
|
+
send(method, '/echo_name') do
|
31
|
+
params[:name].inspect
|
32
|
+
end
|
31
33
|
end
|
32
34
|
|
33
35
|
delete '/delete_with_json' do
|
34
36
|
%/{"deleted":true}/
|
35
37
|
end
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
+
get '/multi' do
|
40
|
+
[200, { 'Set-Cookie' => %w[ one two ] }, '']
|
39
41
|
end
|