faraday_middleware 0.8.4 → 0.8.5
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 +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
|