faraday_middleware 0.8.4 → 0.8.5
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +5 -1
- data/Rakefile +13 -2
- data/lib/faraday_middleware/instrumentation.rb +2 -2
- data/lib/faraday_middleware/rack_compatible.rb +9 -5
- data/lib/faraday_middleware/request/oauth.rb +28 -5
- data/lib/faraday_middleware/response/follow_redirects.rb +71 -11
- data/lib/faraday_middleware/response/mashify.rb +2 -0
- data/lib/faraday_middleware/response/parse_json.rb +11 -1
- data/lib/faraday_middleware/response/parse_xml.rb +1 -0
- data/lib/faraday_middleware/response/rashify.rb +2 -0
- data/lib/faraday_middleware/version.rb +1 -1
- data/spec/follow_redirects_spec.rb +167 -18
- data/spec/helper.rb +11 -0
- data/spec/mashify_spec.rb +4 -1
- data/spec/oauth_spec.rb +52 -2
- data/spec/parse_json_spec.rb +6 -0
- data/spec/rashify_spec.rb +4 -1
- metadata +18 -18
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
2
|
|
3
|
-
|
3
|
+
if defined? RUBY_ENGINE and 'ruby' == RUBY_ENGINE and '1.9.3' == RUBY_VERSION
|
4
|
+
task :default => [:enable_coverage, :spec, :test, :quality]
|
5
|
+
else
|
6
|
+
task :default => [:spec, :test]
|
7
|
+
end
|
4
8
|
|
5
9
|
require 'bundler'
|
6
10
|
Bundler::GemHelper.install_tasks
|
@@ -9,9 +13,16 @@ require 'rspec/core/rake_task'
|
|
9
13
|
RSpec::Core::RakeTask.new(:spec)
|
10
14
|
|
11
15
|
task :enable_coverage do
|
12
|
-
ENV['COVERAGE'] = 'yes'
|
16
|
+
ENV['COVERAGE'] = 'yes'
|
13
17
|
end
|
14
18
|
|
15
19
|
task :test do
|
16
20
|
sh 'ruby', '-Ilib', 'spec/caching_test.rb'
|
17
21
|
end
|
22
|
+
|
23
|
+
task :quality do
|
24
|
+
sh 'cane',
|
25
|
+
'--style-measure=100',
|
26
|
+
'--gte=coverage/covered_percent,99',
|
27
|
+
'--max-violations=2' # TODO: remove for cane > 1.0.0
|
28
|
+
end
|
@@ -7,10 +7,10 @@ module FaradayMiddleware
|
|
7
7
|
#
|
8
8
|
# Examples
|
9
9
|
#
|
10
|
-
# ActiveSupport::Notifications.subscribe('request.faraday') do |name,
|
10
|
+
# ActiveSupport::Notifications.subscribe('request.faraday') do |name, starts, ends, _, env|
|
11
11
|
# url = env[:url]
|
12
12
|
# http_method = env[:method].to_s.upcase
|
13
|
-
# duration =
|
13
|
+
# duration = ends - starts
|
14
14
|
# $stderr.puts '[%s] %s %s (%.3f s)' % [url.host, http_method, url.request_uri, duration]
|
15
15
|
# end
|
16
16
|
class Instrumentation < Faraday::Middleware
|
@@ -26,11 +26,7 @@ module FaradayMiddleware
|
|
26
26
|
|
27
27
|
# faraday to rack-compatible
|
28
28
|
def prepare_env(env)
|
29
|
-
env
|
30
|
-
name = name.upcase.tr('-', '_')
|
31
|
-
name = "HTTP_#{name}" unless NonPrefixedHeaders.include? name
|
32
|
-
env[name] = value
|
33
|
-
end
|
29
|
+
headers_to_rack(env)
|
34
30
|
|
35
31
|
url = env[:url]
|
36
32
|
env['rack.url_scheme'] = url.scheme
|
@@ -44,6 +40,14 @@ module FaradayMiddleware
|
|
44
40
|
env
|
45
41
|
end
|
46
42
|
|
43
|
+
def headers_to_rack(env)
|
44
|
+
env[:request_headers].each do |name, value|
|
45
|
+
name = name.upcase.tr('-', '_')
|
46
|
+
name = "HTTP_#{name}" unless NonPrefixedHeaders.include? name
|
47
|
+
env[name] = value
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
47
51
|
# rack to faraday-compatible
|
48
52
|
def restore_env(env)
|
49
53
|
headers = env[:request_headers]
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'faraday'
|
2
|
+
require 'forwardable'
|
2
3
|
|
3
4
|
module FaradayMiddleware
|
4
5
|
# Public: Uses the simple_oauth library to sign requests according the
|
@@ -11,14 +12,25 @@ module FaradayMiddleware
|
|
11
12
|
# The signature is added to the "Authorization" HTTP request header. If the
|
12
13
|
# value for this header already exists, it is not overriden.
|
13
14
|
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
15
|
+
# If no Content-Type header is specified, this middleware assumes that
|
16
|
+
# request body parameters should be included while signing the request.
|
17
|
+
# Otherwise, it only includes them if the Content-Type is
|
18
|
+
# "application/x-www-form-urlencoded", as per OAuth 1.0.
|
19
|
+
#
|
20
|
+
# For better performance while signing requests, this middleware should be
|
21
|
+
# positioned before UrlEncoded middleware on the stack, but after any other
|
22
|
+
# body-encoding middleware (such as EncodeJson).
|
18
23
|
class OAuth < Faraday::Middleware
|
19
24
|
dependency 'simple_oauth'
|
20
25
|
|
21
26
|
AUTH_HEADER = 'Authorization'.freeze
|
27
|
+
CONTENT_TYPE = 'Content-Type'.freeze
|
28
|
+
TYPE_URLENCODED = 'application/x-www-form-urlencoded'.freeze
|
29
|
+
|
30
|
+
extend Forwardable
|
31
|
+
parser_method = :parse_nested_query
|
32
|
+
parser_module = ::Faraday::Utils.respond_to?(parser_method) ? 'Faraday::Utils' : 'Rack::Utils'
|
33
|
+
def_delegator parser_module, parser_method
|
22
34
|
|
23
35
|
def initialize(app, options)
|
24
36
|
super(app)
|
@@ -50,7 +62,18 @@ module FaradayMiddleware
|
|
50
62
|
end
|
51
63
|
|
52
64
|
def body_params(env)
|
53
|
-
env
|
65
|
+
if include_body_params?(env)
|
66
|
+
if env[:body].respond_to?(:to_str)
|
67
|
+
parse_nested_query env[:body]
|
68
|
+
else
|
69
|
+
env[:body]
|
70
|
+
end
|
71
|
+
end || {}
|
72
|
+
end
|
73
|
+
|
74
|
+
def include_body_params?(env)
|
75
|
+
# see RFC 5489, section 3.4.1.3.1 for details
|
76
|
+
!(type = env[:request_headers][CONTENT_TYPE]) or type == TYPE_URLENCODED
|
54
77
|
end
|
55
78
|
|
56
79
|
def signature_params(params)
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'faraday'
|
2
|
+
require 'set'
|
2
3
|
|
3
4
|
module FaradayMiddleware
|
5
|
+
# Public: Exception thrown when the maximum amount of requests is exceeded.
|
4
6
|
class RedirectLimitReached < Faraday::Error::ClientError
|
5
7
|
attr_reader :response
|
6
8
|
|
@@ -10,10 +12,34 @@ module FaradayMiddleware
|
|
10
12
|
end
|
11
13
|
end
|
12
14
|
|
13
|
-
# Public: Follow HTTP
|
15
|
+
# Public: Follow HTTP 301, 302, 303, and 307 redirects for GET, PATCH, POST,
|
16
|
+
# PUT, and DELETE requests.
|
17
|
+
#
|
18
|
+
# This middleware does not follow the HTTP specification for HTTP 302, by
|
19
|
+
# default, in that it follows the improper implementation used by most major
|
20
|
+
# web browsers which forces the redirected request to become a GET request
|
21
|
+
# regardless of the original request method.
|
22
|
+
#
|
23
|
+
# For HTTP 301, 302, and 303, the original request is transformed into a
|
24
|
+
# GET request to the response Location, by default. However, with standards
|
25
|
+
# compliance enabled, a 302 will instead act in accordance with the HTTP
|
26
|
+
# specification, which will replay the original request to the received
|
27
|
+
# Location, just as with a 307.
|
28
|
+
#
|
29
|
+
# For HTTP 307, the original request is replayed to the response Location,
|
30
|
+
# including original HTTP request method (GET, POST, PUT, DELETE, PATCH),
|
31
|
+
# original headers, and original body.
|
32
|
+
#
|
33
|
+
# This middleware currently only works with synchronous requests; in other
|
34
|
+
# words, it doesn't support parallelism.
|
14
35
|
class FollowRedirects < Faraday::Middleware
|
15
|
-
#
|
16
|
-
|
36
|
+
# HTTP methods for which 30x redirects can be followed
|
37
|
+
ALLOWED_METHODS = Set.new [:get, :post, :put, :patch, :delete]
|
38
|
+
# HTTP redirect status codes that this middleware implements
|
39
|
+
REDIRECT_CODES = Set.new [301, 302, 303, 307]
|
40
|
+
# Keys in env hash which will get cleared between requests
|
41
|
+
ENV_TO_CLEAR = Set.new [:status, :response, :response_headers]
|
42
|
+
|
17
43
|
# Default value for max redirects followed
|
18
44
|
FOLLOW_LIMIT = 3
|
19
45
|
|
@@ -21,33 +47,67 @@ module FaradayMiddleware
|
|
21
47
|
#
|
22
48
|
# options - An options Hash (default: {}):
|
23
49
|
# limit - A Numeric redirect limit (default: 3)
|
50
|
+
# standards_compliant - A Boolean indicating whether to respect
|
51
|
+
# the HTTP spec when following 302
|
52
|
+
# (default: false)
|
24
53
|
def initialize(app, options = {})
|
25
54
|
super(app)
|
26
55
|
@options = options
|
56
|
+
|
57
|
+
@replay_request_codes = Set.new [307]
|
58
|
+
@replay_request_codes << 302 if standards_compliant?
|
27
59
|
end
|
28
60
|
|
29
61
|
def call(env)
|
30
|
-
|
62
|
+
perform_with_redirection(env, follow_limit)
|
31
63
|
end
|
32
64
|
|
33
|
-
|
65
|
+
private
|
66
|
+
|
67
|
+
def transform_into_get?(response)
|
68
|
+
!@replay_request_codes.include? response.status
|
69
|
+
end
|
70
|
+
|
71
|
+
def perform_with_redirection(env, follows)
|
72
|
+
request_body = env[:body]
|
73
|
+
response = @app.call(env)
|
74
|
+
|
34
75
|
response.on_complete do |env|
|
35
|
-
if
|
76
|
+
if follow_redirect?(env, response)
|
36
77
|
raise RedirectLimitReached, response if follows.zero?
|
37
|
-
env
|
38
|
-
|
39
|
-
response = process_response(@app.call(env), follows - 1)
|
78
|
+
env = update_env(env, request_body, response)
|
79
|
+
response = perform_with_redirection(env, follows - 1)
|
40
80
|
end
|
41
81
|
end
|
42
82
|
response
|
43
83
|
end
|
44
84
|
|
45
|
-
def
|
46
|
-
|
85
|
+
def update_env(env, request_body, response)
|
86
|
+
env[:url] += response['location']
|
87
|
+
|
88
|
+
if transform_into_get?(response)
|
89
|
+
env[:method] = :get
|
90
|
+
env[:body] = nil
|
91
|
+
else
|
92
|
+
env[:body] = request_body
|
93
|
+
end
|
94
|
+
|
95
|
+
ENV_TO_CLEAR.each {|key| env.delete key }
|
96
|
+
|
97
|
+
env
|
98
|
+
end
|
99
|
+
|
100
|
+
def follow_redirect?(env, response)
|
101
|
+
ALLOWED_METHODS.include? env[:method] and
|
102
|
+
REDIRECT_CODES.include? response.status
|
47
103
|
end
|
48
104
|
|
49
105
|
def follow_limit
|
50
106
|
@options.fetch(:limit, FOLLOW_LIMIT)
|
51
107
|
end
|
108
|
+
|
109
|
+
def standards_compliant?
|
110
|
+
@options.fetch(:standards_compliant, false)
|
111
|
+
end
|
52
112
|
end
|
53
113
|
end
|
@@ -26,9 +26,19 @@ module FaradayMiddleware
|
|
26
26
|
end
|
27
27
|
|
28
28
|
BRACKETS = %w- [ { -
|
29
|
+
WHITESPACE = [ " ", "\n", "\r", "\t" ]
|
29
30
|
|
30
31
|
def parse_response?(env)
|
31
|
-
super and BRACKETS.include? env[:body]
|
32
|
+
super and BRACKETS.include? first_char(env[:body])
|
33
|
+
end
|
34
|
+
|
35
|
+
def first_char(body)
|
36
|
+
idx = -1
|
37
|
+
begin
|
38
|
+
char = body[idx += 1]
|
39
|
+
char = char.chr if char
|
40
|
+
end while char and WHITESPACE.include? char
|
41
|
+
char
|
32
42
|
end
|
33
43
|
end
|
34
44
|
end
|
@@ -1,33 +1,182 @@
|
|
1
1
|
require 'helper'
|
2
2
|
require 'faraday_middleware/response/follow_redirects'
|
3
3
|
require 'faraday'
|
4
|
-
|
4
|
+
|
5
|
+
# expose a method in Test adapter that should have been public
|
6
|
+
Faraday::Adapter::Test::Stubs.class_eval { public :new_stub }
|
5
7
|
|
6
8
|
describe FaradayMiddleware::FollowRedirects do
|
7
|
-
let(:
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
stub.
|
13
|
-
stub.get('/found')
|
14
|
-
|
9
|
+
let(:middleware_options) { Hash.new }
|
10
|
+
|
11
|
+
shared_examples_for 'a successful redirection' do |status_code|
|
12
|
+
it "follows the redirection for a GET request" do
|
13
|
+
connection do |stub|
|
14
|
+
stub.get('/permanent') { [status_code, {'Location' => '/found'}, ''] }
|
15
|
+
stub.get('/found') { [200, {'Content-Type' => 'text/plain'}, 'fin'] }
|
16
|
+
end.get('/permanent').body.should eql 'fin'
|
17
|
+
end
|
18
|
+
|
19
|
+
[:head, :options].each do |method|
|
20
|
+
it "returning the response headers for a #{method.to_s.upcase} request" do
|
21
|
+
connection do |stub|
|
22
|
+
stub.new_stub(method, '/permanent') { [status_code, {'Location' => '/found'}, ''] }
|
23
|
+
end.run_request(method, '/permanent', nil, nil).headers['Location'].should eql('/found')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
shared_examples_for 'a forced GET redirection' do |status_code|
|
29
|
+
[:put, :post, :delete, :patch].each do |method|
|
30
|
+
it "a #{method.to_s.upcase} request is converted to a GET" do
|
31
|
+
connection = connection do |stub|
|
32
|
+
stub.new_stub(method, '/redirect') {
|
33
|
+
[status_code, {'Location' => '/found'}, 'elsewhere']
|
34
|
+
}
|
35
|
+
stub.get('/found') { |env|
|
36
|
+
body = env[:body] and body.empty? && (body = nil)
|
37
|
+
[200, {'Content-Type' => 'text/plain'}, body.inspect]
|
38
|
+
}
|
39
|
+
end.run_request(method, '/redirect', 'request data', nil).body.should eql('nil')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
shared_examples_for 'a replayed redirection' do |status_code|
|
45
|
+
it 'redirects with the original request headers' do
|
46
|
+
conn = connection do |stub|
|
47
|
+
stub.get('/redirect') {
|
48
|
+
[status_code, {'Location' => '/found'}, '']
|
49
|
+
}
|
50
|
+
stub.get('/found') { |env|
|
51
|
+
[200, {'Content-Type' => 'text/plain'}, env[:request_headers]['X-Test-Value']]
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
response = conn.get('/redirect') { |req|
|
56
|
+
req.headers['X-Test-Value'] = 'success'
|
57
|
+
}
|
58
|
+
|
59
|
+
response.body.should eql('success')
|
60
|
+
end
|
61
|
+
|
62
|
+
[:put, :post, :delete, :patch].each do |method|
|
63
|
+
it "replays a #{method.to_s.upcase} request" do
|
64
|
+
connection do |stub|
|
65
|
+
stub.new_stub(method, '/redirect') { [status_code, {'Location' => '/found'}, ''] }
|
66
|
+
stub.new_stub(method, '/found') { [200, {'Content-Type' => 'text/plain'}, 'fin'] }
|
67
|
+
end.run_request(method, '/redirect', nil, nil).body.should eql 'fin'
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
[:put, :post, :patch].each do |method|
|
72
|
+
it "forwards request body for a #{method.to_s.upcase} request" do
|
73
|
+
conn = connection do |stub|
|
74
|
+
stub.new_stub(method, '/redirect') {
|
75
|
+
[status_code, {'Location' => '/found'}, '']
|
76
|
+
}
|
77
|
+
stub.new_stub(method, '/found') { |env|
|
78
|
+
[200, {'Content-Type' => 'text/plain'}, env[:body]]
|
79
|
+
}
|
80
|
+
end
|
81
|
+
|
82
|
+
response = conn.run_request(method, '/redirect', 'original data', nil)
|
83
|
+
response.body.should eql('original data')
|
15
84
|
end
|
16
85
|
end
|
17
|
-
|
86
|
+
end
|
18
87
|
|
19
|
-
extend Forwardable
|
20
|
-
def_delegators :connection, :get, :post
|
21
88
|
|
22
|
-
it "
|
23
|
-
|
89
|
+
it "returns non-redirect response results" do
|
90
|
+
connection do |stub|
|
91
|
+
stub.get('/found') { [200, {'Content-Type' => 'text/plain'}, 'fin'] }
|
92
|
+
end.get('/found').body.should eql 'fin'
|
24
93
|
end
|
25
94
|
|
26
|
-
it "follows
|
27
|
-
|
95
|
+
it "follows a single redirection" do
|
96
|
+
connection do |stub|
|
97
|
+
stub.get('/') { [301, {'Location' => '/found'}, ''] }
|
98
|
+
stub.get('/found') { [200, {'Content-Type' => 'text/plain'}, 'fin'] }
|
99
|
+
end.get('/').body.should eql 'fin'
|
28
100
|
end
|
29
101
|
|
30
|
-
it "
|
31
|
-
|
102
|
+
it "follows many redirections" do
|
103
|
+
connection do |stub|
|
104
|
+
stub.get('/') { [301, {'Location' => '/redirect1'}, ''] }
|
105
|
+
stub.get('/redirect1') { [301, {'Location' => '/redirect2'}, ''] }
|
106
|
+
stub.get('/redirect2') { [301, {'Location' => '/found'}, ''] }
|
107
|
+
stub.get('/found') { [200, {'Content-Type' => 'text/plain'}, 'fin'] }
|
108
|
+
end.get('/').body.should eql 'fin'
|
109
|
+
end
|
110
|
+
|
111
|
+
it "raises a FaradayMiddleware::RedirectLimitReached after 3 redirections (by default)" do
|
112
|
+
conn = connection do |stub|
|
113
|
+
stub.get('/') { [301, {'Location' => '/redirect1'}, ''] }
|
114
|
+
stub.get('/redirect1') { [301, {'Location' => '/redirect2'}, ''] }
|
115
|
+
stub.get('/redirect2') { [301, {'Location' => '/redirect3'}, ''] }
|
116
|
+
stub.get('/redirect3') { [301, {'Location' => '/found'}, ''] }
|
117
|
+
stub.get('/found') { [200, {'Content-Type' => 'text/plain'}, 'fin'] }
|
118
|
+
end
|
119
|
+
|
120
|
+
expect { conn.get('/') }.to raise_error(FaradayMiddleware::RedirectLimitReached)
|
121
|
+
end
|
122
|
+
|
123
|
+
it "raises a FaradayMiddleware::RedirectLimitReached after the initialized limit" do
|
124
|
+
conn = connection(:limit => 1) do |stub|
|
125
|
+
stub.get('/') { [301, {'Location' => '/redirect1'}, ''] }
|
126
|
+
stub.get('/redirect1') { [301, {'Location' => '/found'}, ''] }
|
127
|
+
stub.get('/found') { [200, {'Content-Type' => 'text/plain'}, 'fin'] }
|
128
|
+
end
|
129
|
+
|
130
|
+
expect { conn.get('/') }.to raise_error(FaradayMiddleware::RedirectLimitReached)
|
131
|
+
end
|
132
|
+
|
133
|
+
context 'for an HTTP 301 response' do
|
134
|
+
it_should_behave_like 'a successful redirection', 301
|
135
|
+
it_should_behave_like 'a forced GET redirection', 301
|
136
|
+
end
|
137
|
+
|
138
|
+
context 'for an HTTP 302 response' do
|
139
|
+
it_should_behave_like 'a successful redirection', 302
|
140
|
+
|
141
|
+
context 'by default' do
|
142
|
+
it_should_behave_like 'a forced GET redirection', 302
|
143
|
+
end
|
144
|
+
|
145
|
+
context 'with standards compliancy enabled' do
|
146
|
+
let(:middleware_options) { { :standards_compliant => true } }
|
147
|
+
it_should_behave_like 'a replayed redirection', 302
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
context 'for an HTTP 303 response' do
|
152
|
+
it_should_behave_like 'a successful redirection', 303
|
153
|
+
it_should_behave_like 'a forced GET redirection', 303
|
154
|
+
end
|
155
|
+
|
156
|
+
context 'for an HTTP 307 response' do
|
157
|
+
it_should_behave_like 'a successful redirection', 307
|
158
|
+
it_should_behave_like 'a replayed redirection', 307
|
159
|
+
end
|
160
|
+
|
161
|
+
# checks env hash in request phase for basic validity
|
162
|
+
class Lint < Struct.new(:app)
|
163
|
+
def call(env)
|
164
|
+
if env[:status] or env[:response] or env[:response_headers]
|
165
|
+
raise "invalid request: #{env.inspect}"
|
166
|
+
end
|
167
|
+
app.call(env)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
private
|
172
|
+
|
173
|
+
def connection(options = middleware_options)
|
174
|
+
Faraday.new do |c|
|
175
|
+
c.use described_class, options
|
176
|
+
c.use Lint
|
177
|
+
c.adapter :test do |stub|
|
178
|
+
yield(stub) if block_given?
|
179
|
+
end
|
180
|
+
end
|
32
181
|
end
|
33
182
|
end
|
data/spec/helper.rb
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
if ENV['COVERAGE']
|
2
2
|
require 'simplecov'
|
3
|
+
|
4
|
+
class SimpleCov::Formatter::QualityFormatter
|
5
|
+
def format(result)
|
6
|
+
SimpleCov::Formatter::HTMLFormatter.new.format(result)
|
7
|
+
File.open('coverage/covered_percent', 'w') do |f|
|
8
|
+
f.puts result.source_files.covered_percent.to_i
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
SimpleCov.formatter = SimpleCov::Formatter::QualityFormatter
|
13
|
+
|
3
14
|
SimpleCov.start do
|
4
15
|
# add_filter 'faraday_middleware.rb'
|
5
16
|
add_filter 'backwards_compatibility.rb'
|
data/spec/mashify_spec.rb
CHANGED
@@ -70,7 +70,10 @@ describe FaradayMiddleware::Mashify do
|
|
70
70
|
# although it is not good practice to pass a hash as the body, if we add ParseJson
|
71
71
|
# to the middleware stack we end up testing two middlewares instead of one
|
72
72
|
it 'should create a Hash from the body' do
|
73
|
-
stubs.get('/hash') {
|
73
|
+
stubs.get('/hash') {
|
74
|
+
data = { 'name' => 'Erik Michaels-Ober', 'username' => 'sferik' }
|
75
|
+
[200, {'content-type' => 'application/json; charset=utf-8'}, data]
|
76
|
+
}
|
74
77
|
me = connection.get('/hash').body
|
75
78
|
me.name.should == 'Erik Michaels-Ober'
|
76
79
|
me.username.should == 'sferik'
|
data/spec/oauth_spec.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'helper'
|
2
2
|
require 'faraday_middleware/request/oauth'
|
3
3
|
require 'uri'
|
4
|
+
require 'forwardable'
|
4
5
|
|
5
6
|
describe FaradayMiddleware::OAuth do
|
6
7
|
def auth_header(env)
|
@@ -14,11 +15,12 @@ describe FaradayMiddleware::OAuth do
|
|
14
15
|
end
|
15
16
|
end
|
16
17
|
|
17
|
-
def perform(oauth_options = {}, headers = {})
|
18
|
+
def perform(oauth_options = {}, headers = {}, params = {})
|
18
19
|
env = {
|
19
20
|
:url => URI('http://example.com/'),
|
20
21
|
:request_headers => Faraday::Utils::Headers.new.update(headers),
|
21
|
-
:request => {}
|
22
|
+
:request => {},
|
23
|
+
:body => params
|
22
24
|
}
|
23
25
|
unless oauth_options.is_a? Hash and oauth_options.empty?
|
24
26
|
env[:request][:oauth] = oauth_options
|
@@ -98,4 +100,52 @@ describe FaradayMiddleware::OAuth do
|
|
98
100
|
auth.should_not include('oauth_token')
|
99
101
|
end
|
100
102
|
end
|
103
|
+
|
104
|
+
context "handling body parameters" do
|
105
|
+
let(:options) { [{ :consumer_key => 'CKEY',
|
106
|
+
:consumer_secret => 'CSECRET',
|
107
|
+
:nonce => '547fed103e122eecf84c080843eedfe6',
|
108
|
+
:timestamp => '1286830180'}] }
|
109
|
+
|
110
|
+
let(:value) { {'foo' => 'bar'} }
|
111
|
+
|
112
|
+
let(:type_json) { {'Content-Type' => 'application/json'} }
|
113
|
+
let(:type_form) { {'Content-Type' => 'application/x-www-form-urlencoded'} }
|
114
|
+
|
115
|
+
extend Forwardable
|
116
|
+
query_method = :build_nested_query
|
117
|
+
query_module = ::Faraday::Utils.respond_to?(query_method) ? 'Faraday::Utils' : 'Rack::Utils'
|
118
|
+
def_delegator query_module, query_method
|
119
|
+
|
120
|
+
it "does not include the body for JSON" do
|
121
|
+
auth_header_with = auth_header(perform({}, type_json, '{"foo":"bar"}'))
|
122
|
+
auth_header_without = auth_header(perform({}, type_json, {}))
|
123
|
+
|
124
|
+
auth_header_with.should == auth_header_without
|
125
|
+
end
|
126
|
+
|
127
|
+
it "includes the body parameters with form Content-Type" do
|
128
|
+
auth_header_with = auth_header(perform({}, type_form, {}))
|
129
|
+
auth_header_without = auth_header(perform({}, type_form, value))
|
130
|
+
|
131
|
+
auth_header_with.should_not == auth_header_without
|
132
|
+
end
|
133
|
+
|
134
|
+
it "includes the body parameters with an unspecified Content-Type" do
|
135
|
+
auth_header_with = auth_header(perform({}, {}, value))
|
136
|
+
auth_header_without = auth_header(perform({}, type_form, value))
|
137
|
+
|
138
|
+
auth_header_with.should == auth_header_without
|
139
|
+
end
|
140
|
+
|
141
|
+
it "includes the body parameters for form type with string body" do
|
142
|
+
# simulates the behavior of Faraday::MiddleWare::UrlEncoded
|
143
|
+
value = { 'foo' => ['bar', 'baz', 'wat'] }
|
144
|
+
auth_header_hash = auth_header(perform({}, type_form, value))
|
145
|
+
auth_header_string = auth_header(perform({}, type_form, build_nested_query(value)))
|
146
|
+
auth_header_string.should == auth_header_hash
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
|
101
151
|
end
|
data/spec/parse_json_spec.rb
CHANGED
@@ -90,5 +90,11 @@ describe FaradayMiddleware::ParseJson, :type => :response do
|
|
90
90
|
response.body.should be_a(Hash)
|
91
91
|
response['content-type'].should eql('application/json')
|
92
92
|
end
|
93
|
+
|
94
|
+
it "corrects compatible type even when data starts with whitespace" do
|
95
|
+
response = process(%( \r\n\t{"a":1}), 'text/javascript')
|
96
|
+
response.body.should be_a(Hash)
|
97
|
+
response['content-type'].should eql('application/json')
|
98
|
+
end
|
93
99
|
end
|
94
100
|
end
|
data/spec/rashify_spec.rb
CHANGED
@@ -60,7 +60,10 @@ describe FaradayMiddleware::Rashify do
|
|
60
60
|
# although it is not good practice to pass a hash as the body, if we add ParseJson
|
61
61
|
# to the middleware stack we end up testing two middlewares instead of one
|
62
62
|
it 'should create a Hash from the body' do
|
63
|
-
stubs.get('/hash') {
|
63
|
+
stubs.get('/hash') {
|
64
|
+
data = { 'name' => 'Erik Michaels-Ober', 'username' => 'sferik' }
|
65
|
+
[200, {'content-type' => 'application/json; charset=utf-8'}, data]
|
66
|
+
}
|
64
67
|
me = connection.get('/hash').body
|
65
68
|
me.name.should == 'Erik Michaels-Ober'
|
66
69
|
me.username.should == 'sferik'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: faraday_middleware
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-03-11 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: faraday
|
17
|
-
requirement: &
|
17
|
+
requirement: &70319499815400 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -25,10 +25,10 @@ dependencies:
|
|
25
25
|
version: '0.9'
|
26
26
|
type: :runtime
|
27
27
|
prerelease: false
|
28
|
-
version_requirements: *
|
28
|
+
version_requirements: *70319499815400
|
29
29
|
- !ruby/object:Gem::Dependency
|
30
30
|
name: multi_xml
|
31
|
-
requirement: &
|
31
|
+
requirement: &70319499836420 !ruby/object:Gem::Requirement
|
32
32
|
none: false
|
33
33
|
requirements:
|
34
34
|
- - ~>
|
@@ -36,10 +36,10 @@ dependencies:
|
|
36
36
|
version: '0.2'
|
37
37
|
type: :development
|
38
38
|
prerelease: false
|
39
|
-
version_requirements: *
|
39
|
+
version_requirements: *70319499836420
|
40
40
|
- !ruby/object:Gem::Dependency
|
41
41
|
name: rake
|
42
|
-
requirement: &
|
42
|
+
requirement: &70319499834040 !ruby/object:Gem::Requirement
|
43
43
|
none: false
|
44
44
|
requirements:
|
45
45
|
- - ~>
|
@@ -47,10 +47,10 @@ dependencies:
|
|
47
47
|
version: '0.9'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
|
-
version_requirements: *
|
50
|
+
version_requirements: *70319499834040
|
51
51
|
- !ruby/object:Gem::Dependency
|
52
52
|
name: hashie
|
53
|
-
requirement: &
|
53
|
+
requirement: &70319499847520 !ruby/object:Gem::Requirement
|
54
54
|
none: false
|
55
55
|
requirements:
|
56
56
|
- - ~>
|
@@ -58,10 +58,10 @@ dependencies:
|
|
58
58
|
version: '1.2'
|
59
59
|
type: :development
|
60
60
|
prerelease: false
|
61
|
-
version_requirements: *
|
61
|
+
version_requirements: *70319499847520
|
62
62
|
- !ruby/object:Gem::Dependency
|
63
63
|
name: rash
|
64
|
-
requirement: &
|
64
|
+
requirement: &70319499843360 !ruby/object:Gem::Requirement
|
65
65
|
none: false
|
66
66
|
requirements:
|
67
67
|
- - ~>
|
@@ -69,10 +69,10 @@ dependencies:
|
|
69
69
|
version: '0.3'
|
70
70
|
type: :development
|
71
71
|
prerelease: false
|
72
|
-
version_requirements: *
|
72
|
+
version_requirements: *70319499843360
|
73
73
|
- !ruby/object:Gem::Dependency
|
74
74
|
name: rspec
|
75
|
-
requirement: &
|
75
|
+
requirement: &70319499841140 !ruby/object:Gem::Requirement
|
76
76
|
none: false
|
77
77
|
requirements:
|
78
78
|
- - ~>
|
@@ -80,10 +80,10 @@ dependencies:
|
|
80
80
|
version: '2.6'
|
81
81
|
type: :development
|
82
82
|
prerelease: false
|
83
|
-
version_requirements: *
|
83
|
+
version_requirements: *70319499841140
|
84
84
|
- !ruby/object:Gem::Dependency
|
85
85
|
name: simple_oauth
|
86
|
-
requirement: &
|
86
|
+
requirement: &70319499852100 !ruby/object:Gem::Requirement
|
87
87
|
none: false
|
88
88
|
requirements:
|
89
89
|
- - ~>
|
@@ -91,10 +91,10 @@ dependencies:
|
|
91
91
|
version: '0.1'
|
92
92
|
type: :development
|
93
93
|
prerelease: false
|
94
|
-
version_requirements: *
|
94
|
+
version_requirements: *70319499852100
|
95
95
|
- !ruby/object:Gem::Dependency
|
96
96
|
name: rack-cache
|
97
|
-
requirement: &
|
97
|
+
requirement: &70319499897100 !ruby/object:Gem::Requirement
|
98
98
|
none: false
|
99
99
|
requirements:
|
100
100
|
- - ~>
|
@@ -102,7 +102,7 @@ dependencies:
|
|
102
102
|
version: '1.1'
|
103
103
|
type: :development
|
104
104
|
prerelease: false
|
105
|
-
version_requirements: *
|
105
|
+
version_requirements: *70319499897100
|
106
106
|
description: Various middleware for Faraday
|
107
107
|
email:
|
108
108
|
- sferik@gmail.com
|