faraday 0.4.6 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +3 -0
- data/Gemfile.lock +28 -0
- data/README.md +84 -0
- data/Rakefile +111 -34
- data/faraday.gemspec +85 -82
- data/lib/faraday.rb +17 -26
- data/lib/faraday/adapter.rb +102 -0
- data/lib/faraday/adapter/action_dispatch.rb +39 -0
- data/lib/faraday/adapter/net_http.rb +20 -8
- data/lib/faraday/adapter/patron.rb +10 -4
- data/lib/faraday/adapter/test.rb +28 -15
- data/lib/faraday/adapter/typhoeus.rb +16 -6
- data/lib/faraday/builder.rb +6 -6
- data/lib/faraday/connection.rb +33 -46
- data/lib/faraday/error.rb +25 -1
- data/lib/faraday/middleware.rb +0 -30
- data/lib/faraday/request.rb +5 -5
- data/lib/faraday/request/active_support_json.rb +1 -1
- data/lib/faraday/request/yajl.rb +1 -1
- data/lib/faraday/response/active_support_json.rb +9 -2
- data/lib/faraday/response/yajl.rb +8 -2
- data/lib/faraday/upload_io.rb +15 -0
- data/lib/faraday/utils.rb +64 -0
- data/test/adapters/live_test.rb +24 -15
- data/test/adapters/test_middleware_test.rb +11 -0
- data/test/connection_test.rb +6 -7
- data/test/env_test.rb +2 -2
- data/test/form_post_test.rb +42 -0
- data/test/helper.rb +6 -2
- data/test/live_server.rb +6 -1
- data/test/multipart_test.rb +48 -0
- data/test/request_middleware_test.rb +9 -2
- data/test/response_middleware_test.rb +8 -1
- metadata +75 -29
- data/.document +0 -5
- data/.gitignore +0 -21
- data/README.rdoc +0 -86
- data/VERSION +0 -1
data/lib/faraday.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
require 'rack/utils'
|
2
|
-
|
3
1
|
module Faraday
|
2
|
+
VERSION = "0.5.0"
|
3
|
+
|
4
4
|
class << self
|
5
5
|
attr_accessor :default_adapter
|
6
6
|
attr_writer :default_connection
|
@@ -42,37 +42,28 @@ module Faraday
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def all_loaded_constants
|
45
|
-
constants.map { |c| const_get(c) }.
|
45
|
+
constants.map { |c| const_get(c) }.
|
46
|
+
select { |a| a.respond_to?(:loaded?) && a.loaded? }
|
46
47
|
end
|
47
48
|
end
|
48
49
|
|
49
50
|
extend AutoloadHelper
|
50
51
|
|
51
|
-
autoload_all 'faraday',
|
52
|
-
:
|
53
|
-
:
|
54
|
-
:
|
55
|
-
:
|
56
|
-
:
|
57
|
-
:
|
58
|
-
|
59
|
-
module Adapter
|
60
|
-
extend AutoloadHelper
|
61
|
-
autoload_all 'faraday/adapter',
|
62
|
-
:NetHttp => 'net_http',
|
63
|
-
:Typhoeus => 'typhoeus',
|
64
|
-
:Patron => 'patron',
|
65
|
-
:Test => 'test'
|
66
|
-
|
67
|
-
register_lookup_modules \
|
68
|
-
:test => :Test,
|
69
|
-
:net_http => :NetHttp,
|
70
|
-
:typhoeus => :Typhoeus,
|
71
|
-
:patron => :Patron,
|
72
|
-
:net_http => :NetHttp
|
73
|
-
end
|
52
|
+
autoload_all 'faraday',
|
53
|
+
:Middleware => 'middleware',
|
54
|
+
:Builder => 'builder',
|
55
|
+
:Request => 'request',
|
56
|
+
:Response => 'response',
|
57
|
+
:CompositeReadIO => 'upload_io',
|
58
|
+
:UploadIO => 'upload_io',
|
59
|
+
:Parts => 'upload_io'
|
74
60
|
end
|
75
61
|
|
62
|
+
require 'faraday/utils'
|
63
|
+
require 'faraday/connection'
|
64
|
+
require 'faraday/adapter'
|
65
|
+
require 'faraday/error'
|
66
|
+
|
76
67
|
# not pulling in active-support JUST for this method.
|
77
68
|
class Object
|
78
69
|
# Yields <code>x</code> to the block, and then returns <code>x</code>.
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module Faraday
|
2
|
+
class Adapter < Middleware
|
3
|
+
FORM_TYPE = 'application/x-www-form-urlencoded'.freeze
|
4
|
+
MULTIPART_TYPE = 'multipart/form-data'.freeze
|
5
|
+
CONTENT_TYPE = 'Content-Type'.freeze
|
6
|
+
DEFAULT_BOUNDARY = "-----------RubyMultipartPost".freeze
|
7
|
+
|
8
|
+
extend AutoloadHelper
|
9
|
+
autoload_all 'faraday/adapter',
|
10
|
+
:ActionDispatch => 'action_dispatch',
|
11
|
+
:NetHttp => 'net_http',
|
12
|
+
:Typhoeus => 'typhoeus',
|
13
|
+
:Patron => 'patron',
|
14
|
+
:Test => 'test'
|
15
|
+
|
16
|
+
register_lookup_modules \
|
17
|
+
:action_dispatch => :ActionDispatch,
|
18
|
+
:test => :Test,
|
19
|
+
:net_http => :NetHttp,
|
20
|
+
:typhoeus => :Typhoeus,
|
21
|
+
:patron => :Patron,
|
22
|
+
:net_http => :NetHttp
|
23
|
+
|
24
|
+
def call(env)
|
25
|
+
process_body_for_request(env)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Converts a body hash into encoded form params. This is done as late
|
29
|
+
# as possible in the request cycle in case some other middleware wants to
|
30
|
+
# act on the request before sending it out.
|
31
|
+
#
|
32
|
+
# env - The current request environment Hash.
|
33
|
+
# body - A Hash of keys/values. Strings and empty values will be
|
34
|
+
# ignored. Default: env[:body]
|
35
|
+
# headers - The Hash of request headers. Default: env[:request_headers]
|
36
|
+
#
|
37
|
+
# Returns nothing. If the body is processed, it is replaced in the
|
38
|
+
# environment for you.
|
39
|
+
def process_body_for_request(env, body = env[:body], headers = env[:request_headers])
|
40
|
+
return if body.nil? || body.empty? || !body.respond_to?(:each_key)
|
41
|
+
if has_multipart?(body)
|
42
|
+
env[:request] ||= {}
|
43
|
+
env[:request][:boundary] ||= DEFAULT_BOUNDARY
|
44
|
+
headers[CONTENT_TYPE] = MULTIPART_TYPE + ";boundary=#{env[:request][:boundary]}"
|
45
|
+
env[:body] = create_multipart(env, body)
|
46
|
+
else
|
47
|
+
type = headers[CONTENT_TYPE]
|
48
|
+
headers[CONTENT_TYPE] = FORM_TYPE if type.nil? || type.empty?
|
49
|
+
parts = []
|
50
|
+
process_to_params(parts, env[:body]) do |key, value|
|
51
|
+
"#{key}=#{escape(value.to_s)}"
|
52
|
+
end
|
53
|
+
env[:body] = parts * "&"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def has_multipart?(body)
|
58
|
+
body.values.each do |v|
|
59
|
+
if v.respond_to?(:content_type)
|
60
|
+
return true
|
61
|
+
elsif v.respond_to?(:values)
|
62
|
+
return true if has_multipart?(v)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
false
|
66
|
+
end
|
67
|
+
|
68
|
+
def create_multipart(env, params, boundary = nil)
|
69
|
+
boundary ||= env[:request][:boundary]
|
70
|
+
parts = []
|
71
|
+
process_to_params(parts, params) do |key, value|
|
72
|
+
Faraday::Parts::Part.new(boundary, key, value)
|
73
|
+
end
|
74
|
+
parts << Faraday::Parts::EpiloguePart.new(boundary)
|
75
|
+
env[:request_headers]['Content-Length'] = parts.inject(0) {|sum,i| sum + i.length }.to_s
|
76
|
+
Faraday::CompositeReadIO.new(*parts.map{|p| p.to_io })
|
77
|
+
end
|
78
|
+
|
79
|
+
def process_to_params(pieces, params, base = nil, &block)
|
80
|
+
params.each do |key, value|
|
81
|
+
key_str = base ? "#{base}[#{key}]" : key
|
82
|
+
if value.kind_of?(Hash)
|
83
|
+
process_to_params(pieces, value, key_str, &block)
|
84
|
+
else
|
85
|
+
pieces << block.call(key_str, value)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# assume that query and fragment are already encoded properly
|
91
|
+
def full_path_for(path, query = nil, fragment = nil)
|
92
|
+
full_path = path.dup
|
93
|
+
if query && !query.empty?
|
94
|
+
full_path << "?#{query}"
|
95
|
+
end
|
96
|
+
if fragment && !fragment.empty?
|
97
|
+
full_path << "##{fragment}"
|
98
|
+
end
|
99
|
+
full_path
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Faraday
|
2
|
+
class Adapter
|
3
|
+
class ActionDispatch < Faraday::Adapter
|
4
|
+
attr_reader :session
|
5
|
+
|
6
|
+
# Initializes a new middleware instance for each request. Instead of
|
7
|
+
# initiating an HTTP request with a web server, this adapter calls
|
8
|
+
# a Rails 3 app using integration tests.
|
9
|
+
#
|
10
|
+
# app - The current Faraday request.
|
11
|
+
# session - An ActionDispatch::Integration::Session instance.
|
12
|
+
#
|
13
|
+
# Returns nothing.
|
14
|
+
def initialize(app, session)
|
15
|
+
super(app)
|
16
|
+
@session = session
|
17
|
+
@session.reset!
|
18
|
+
end
|
19
|
+
|
20
|
+
def call(env)
|
21
|
+
super
|
22
|
+
full_path = full_path_for(env[:url].path, env[:url].query, env[:url].fragment)
|
23
|
+
@session.__send__(env[:method], full_path, env[:body], env[:request_headers])
|
24
|
+
resp = @session.response
|
25
|
+
env.update \
|
26
|
+
:status => resp.status,
|
27
|
+
:response_headers => resp.headers,
|
28
|
+
:body => resp.body
|
29
|
+
@app.call env
|
30
|
+
end
|
31
|
+
|
32
|
+
# TODO: build in support for multipart streaming if action dispatch supports it.
|
33
|
+
def create_multipart(env, params, boundary = nil)
|
34
|
+
stream = super
|
35
|
+
stream.read
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -6,10 +6,10 @@ rescue LoadError
|
|
6
6
|
end
|
7
7
|
|
8
8
|
module Faraday
|
9
|
-
|
10
|
-
class NetHttp <
|
9
|
+
class Adapter
|
10
|
+
class NetHttp < Faraday::Adapter
|
11
11
|
def call(env)
|
12
|
-
|
12
|
+
super
|
13
13
|
|
14
14
|
is_ssl = env[:url].scheme == 'https'
|
15
15
|
|
@@ -28,9 +28,21 @@ module Faraday
|
|
28
28
|
req = env[:request]
|
29
29
|
http.read_timeout = net.open_timeout = req[:timeout] if req[:timeout]
|
30
30
|
http.open_timeout = req[:open_timeout] if req[:open_timeout]
|
31
|
-
|
31
|
+
|
32
32
|
full_path = full_path_for(env[:url].path, env[:url].query, env[:url].fragment)
|
33
|
-
|
33
|
+
http_req = Net::HTTPGenericRequest.new(
|
34
|
+
env[:method].to_s.upcase, # request method
|
35
|
+
(env[:body] ? true : false), # is there data
|
36
|
+
true, # does net/http love you, true or false?
|
37
|
+
full_path, # request uri path
|
38
|
+
env[:request_headers]) # request headers
|
39
|
+
|
40
|
+
if env[:body].respond_to?(:read)
|
41
|
+
http_req.body_stream = env[:body]
|
42
|
+
env[:body] = nil
|
43
|
+
end
|
44
|
+
|
45
|
+
http_resp = http.request http_req, env[:body]
|
34
46
|
|
35
47
|
resp_headers = {}
|
36
48
|
http_resp.each_header do |key, value|
|
@@ -38,13 +50,13 @@ module Faraday
|
|
38
50
|
end
|
39
51
|
|
40
52
|
env.update \
|
41
|
-
:status => http_resp.code.to_i,
|
42
|
-
:response_headers => resp_headers,
|
53
|
+
:status => http_resp.code.to_i,
|
54
|
+
:response_headers => resp_headers,
|
43
55
|
:body => http_resp.body
|
44
56
|
|
45
57
|
@app.call env
|
46
58
|
rescue Errno::ECONNREFUSED
|
47
|
-
raise Error::ConnectionFailed
|
59
|
+
raise Error::ConnectionFailed.new(Errno::ECONNREFUSED)
|
48
60
|
end
|
49
61
|
|
50
62
|
def net_http_class(env)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Faraday
|
2
|
-
|
3
|
-
class Patron <
|
2
|
+
class Adapter
|
3
|
+
class Patron < Faraday::Adapter
|
4
4
|
begin
|
5
5
|
require 'patron'
|
6
6
|
rescue LoadError, NameError => e
|
@@ -8,7 +8,7 @@ module Faraday
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def call(env)
|
11
|
-
|
11
|
+
super
|
12
12
|
|
13
13
|
sess = ::Patron::Session.new
|
14
14
|
args = [env[:method], env[:url].to_s, env[:request_headers]]
|
@@ -26,7 +26,13 @@ module Faraday
|
|
26
26
|
|
27
27
|
@app.call env
|
28
28
|
rescue Errno::ECONNREFUSED
|
29
|
-
raise Error::ConnectionFailed
|
29
|
+
raise Error::ConnectionFailed.new(Errno::ECONNREFUSED)
|
30
|
+
end
|
31
|
+
|
32
|
+
# TODO: build in support for multipart streaming if patron supports it.
|
33
|
+
def create_multipart(env, params, boundary = nil)
|
34
|
+
stream = super
|
35
|
+
stream.read
|
30
36
|
end
|
31
37
|
end
|
32
38
|
end
|
data/lib/faraday/adapter/test.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Faraday
|
2
|
-
|
2
|
+
class Adapter
|
3
3
|
# test = Faraday::Connection.new do
|
4
4
|
# use Faraday::Adapter::Test do |stub|
|
5
5
|
# stub.get '/nigiri/sake.json' do
|
@@ -19,7 +19,7 @@ module Faraday
|
|
19
19
|
class Stubs
|
20
20
|
def initialize
|
21
21
|
# {:get => [Stub, Stub]}
|
22
|
-
@stack = {}
|
22
|
+
@stack, @consumed = {}, {}
|
23
23
|
yield self if block_given?
|
24
24
|
end
|
25
25
|
|
@@ -29,8 +29,15 @@ module Faraday
|
|
29
29
|
|
30
30
|
def match(request_method, path, body)
|
31
31
|
return false if !@stack.key?(request_method)
|
32
|
-
|
33
|
-
@
|
32
|
+
stack = @stack[request_method]
|
33
|
+
consumed = (@consumed[request_method] ||= [])
|
34
|
+
|
35
|
+
if stub = matches?(stack, path, body)
|
36
|
+
consumed << stack.delete(stub)
|
37
|
+
stub
|
38
|
+
else
|
39
|
+
matches?(consumed, path, body)
|
40
|
+
end
|
34
41
|
end
|
35
42
|
|
36
43
|
def get(path, &block)
|
@@ -53,10 +60,6 @@ module Faraday
|
|
53
60
|
new_stub(:delete, path, &block)
|
54
61
|
end
|
55
62
|
|
56
|
-
def new_stub(request_method, path, body=nil, &block)
|
57
|
-
(@stack[request_method] ||= []) << Stub.new(path, body, block)
|
58
|
-
end
|
59
|
-
|
60
63
|
# Raises an error if any of the stubbed calls have not been made.
|
61
64
|
def verify_stubbed_calls
|
62
65
|
failed_stubs = []
|
@@ -69,6 +72,16 @@ module Faraday
|
|
69
72
|
end
|
70
73
|
raise failed_stubs.join(" ") unless failed_stubs.size == 0
|
71
74
|
end
|
75
|
+
|
76
|
+
protected
|
77
|
+
|
78
|
+
def new_stub(request_method, path, body=nil, &block)
|
79
|
+
(@stack[request_method] ||= []) << Stub.new(path, body, block)
|
80
|
+
end
|
81
|
+
|
82
|
+
def matches?(stack, path, body)
|
83
|
+
stack.detect { |stub| stub.matches?(path, body) }
|
84
|
+
end
|
72
85
|
end
|
73
86
|
|
74
87
|
class Stub < Struct.new(:path, :body, :block)
|
@@ -81,7 +94,7 @@ module Faraday
|
|
81
94
|
end
|
82
95
|
end
|
83
96
|
|
84
|
-
def initialize
|
97
|
+
def initialize(app, stubs=nil, &block)
|
85
98
|
super(app)
|
86
99
|
@stubs = stubs || Stubs.new
|
87
100
|
configure(&block) if block
|
@@ -91,13 +104,8 @@ module Faraday
|
|
91
104
|
yield stubs
|
92
105
|
end
|
93
106
|
|
94
|
-
def request_uri url
|
95
|
-
(url.path != "" ? url.path : "/") +
|
96
|
-
(url.query ? "?#{url.query}" : "")
|
97
|
-
end
|
98
|
-
|
99
107
|
def call(env)
|
100
|
-
if stub = stubs.match(env[:method],
|
108
|
+
if stub = stubs.match(env[:method], Faraday::Utils.normalize_path(env[:url]), env[:body])
|
101
109
|
status, headers, body = stub.block.call(env)
|
102
110
|
env.update \
|
103
111
|
:status => status,
|
@@ -108,6 +116,11 @@ module Faraday
|
|
108
116
|
end
|
109
117
|
@app.call(env)
|
110
118
|
end
|
119
|
+
|
120
|
+
def create_multipart(env, params, boundary = nil)
|
121
|
+
stream = super
|
122
|
+
stream.read
|
123
|
+
end
|
111
124
|
end
|
112
125
|
end
|
113
126
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Faraday
|
2
|
-
|
3
|
-
class Typhoeus <
|
2
|
+
class Adapter
|
3
|
+
class Typhoeus < Faraday::Adapter
|
4
4
|
self.supports_parallel_requests = true
|
5
5
|
|
6
6
|
def self.setup_parallel_manager(options = {})
|
@@ -14,15 +14,18 @@ module Faraday
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def call(env)
|
17
|
-
|
17
|
+
super
|
18
18
|
|
19
|
-
|
20
|
-
req = ::Typhoeus::Request.new env[:url].to_s,
|
19
|
+
req = ::Typhoeus::Request.new env[:url].to_s,
|
21
20
|
:method => env[:method],
|
22
21
|
:body => env[:body],
|
23
22
|
:headers => env[:request_headers],
|
24
23
|
:disable_ssl_peer_verification => (env[:ssl][:verify] == false)
|
25
24
|
|
25
|
+
env_req = env[:request]
|
26
|
+
req.timeout = req.connect_timeout = (env_req[:timeout] * 1000) if env_req[:timeout]
|
27
|
+
req.connect_timeout = (env_req[:open_timeout] * 1000) if env_req[:open_timeout]
|
28
|
+
|
26
29
|
req.on_complete do |resp|
|
27
30
|
env.update \
|
28
31
|
:status => resp.code,
|
@@ -31,6 +34,7 @@ module Faraday
|
|
31
34
|
env[:response].finish(env)
|
32
35
|
end
|
33
36
|
|
37
|
+
hydra = env[:parallel_manager] || self.class.setup_parallel_manager
|
34
38
|
hydra.queue req
|
35
39
|
|
36
40
|
if !env[:parallel_manager]
|
@@ -39,7 +43,7 @@ module Faraday
|
|
39
43
|
|
40
44
|
@app.call env
|
41
45
|
rescue Errno::ECONNREFUSED
|
42
|
-
raise Error::ConnectionFailed
|
46
|
+
raise Error::ConnectionFailed.new(Errno::ECONNREFUSED)
|
43
47
|
end
|
44
48
|
|
45
49
|
def in_parallel(options = {})
|
@@ -56,6 +60,12 @@ module Faraday
|
|
56
60
|
map! { |h| h.split(/:\s+/,2) }. # split key and value
|
57
61
|
map! { |(k, v)| [k.downcase, v] }.flatten!]
|
58
62
|
end
|
63
|
+
|
64
|
+
# TODO: build in support for multipart streaming if typhoeus supports it.
|
65
|
+
def create_multipart(env, params, boundary = nil)
|
66
|
+
stream = super
|
67
|
+
stream.read
|
68
|
+
end
|
59
69
|
end
|
60
70
|
end
|
61
71
|
end
|
data/lib/faraday/builder.rb
CHANGED
@@ -14,7 +14,7 @@ module Faraday
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def self.inner_app
|
17
|
-
lambda do |env|
|
17
|
+
lambda do |env|
|
18
18
|
env[:parallel_manager] ? env[:response] : env[:response].finish(env)
|
19
19
|
end
|
20
20
|
end
|
@@ -56,19 +56,19 @@ module Faraday
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def request(key, *args, &block)
|
59
|
-
use_symbol
|
59
|
+
use_symbol(Faraday::Request, key, *args, &block)
|
60
60
|
end
|
61
61
|
|
62
62
|
def response(key, *args, &block)
|
63
|
-
use_symbol
|
63
|
+
use_symbol(Faraday::Response, key, *args, &block)
|
64
64
|
end
|
65
65
|
|
66
66
|
def adapter(key, *args, &block)
|
67
|
-
use_symbol
|
67
|
+
use_symbol(Faraday::Adapter, key, *args, &block)
|
68
68
|
end
|
69
69
|
|
70
70
|
def use_symbol(mod, key, *args, &block)
|
71
|
-
use
|
71
|
+
use(mod.lookup_module(key), *args, &block)
|
72
72
|
end
|
73
73
|
|
74
74
|
def ==(other)
|
@@ -76,7 +76,7 @@ module Faraday
|
|
76
76
|
end
|
77
77
|
|
78
78
|
def dup
|
79
|
-
self.class.new
|
79
|
+
self.class.new(@handlers.dup)
|
80
80
|
end
|
81
81
|
end
|
82
82
|
end
|