faraday 0.4.6 → 0.5.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 +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
|