faraday_middleware 0.8.7 → 0.8.8
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +5 -4
- data/Gemfile +2 -2
- data/Rakefile +3 -4
- data/lib/faraday_middleware.rb +3 -1
- data/lib/faraday_middleware/request/encode_json.rb +4 -2
- data/lib/faraday_middleware/response/chunked.rb +29 -0
- data/lib/faraday_middleware/response/follow_redirects.rb +23 -0
- data/lib/faraday_middleware/response/mashify.rb +1 -1
- data/lib/faraday_middleware/response/parse_dates.rb +39 -0
- data/lib/faraday_middleware/response/parse_json.rb +6 -6
- data/lib/faraday_middleware/response/parse_marshal.rb +2 -2
- data/lib/faraday_middleware/response/parse_xml.rb +2 -2
- data/lib/faraday_middleware/response/parse_yaml.rb +3 -1
- data/lib/faraday_middleware/version.rb +1 -1
- data/spec/chunked_spec.rb +78 -0
- data/spec/follow_redirects_spec.rb +23 -0
- data/spec/helper.rb +2 -1
- data/spec/mashify_spec.rb +7 -0
- data/spec/parse_dates_spec.rb +42 -0
- metadata +9 -3
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -1,6 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
if defined? RUBY_ENGINE and 'ruby' == RUBY_ENGINE and '1.9.3' == RUBY_VERSION
|
1
|
+
if defined? RUBY_ENGINE and 'ruby' == RUBY_ENGINE and RUBY_VERSION.index('1.9') == 0
|
4
2
|
task :default => [:enable_coverage, :spec, :test, :quality]
|
5
3
|
else
|
6
4
|
task :default => [:spec, :test]
|
@@ -22,7 +20,8 @@ end
|
|
22
20
|
|
23
21
|
task :quality do
|
24
22
|
sh 'cane',
|
23
|
+
'--abc-max=10',
|
25
24
|
'--style-measure=100',
|
26
25
|
'--gte=coverage/covered_percent,99',
|
27
|
-
'--max-violations=2'
|
26
|
+
'--max-violations=2'
|
28
27
|
end
|
data/lib/faraday_middleware.rb
CHANGED
@@ -11,6 +11,7 @@ module FaradayMiddleware
|
|
11
11
|
autoload :ParseMarshal, 'faraday_middleware/response/parse_marshal'
|
12
12
|
autoload :ParseYaml, 'faraday_middleware/response/parse_yaml'
|
13
13
|
autoload :Caching, 'faraday_middleware/response/caching'
|
14
|
+
autoload :Chunked, 'faraday_middleware/response/chunked'
|
14
15
|
autoload :RackCompatible, 'faraday_middleware/rack_compatible'
|
15
16
|
autoload :FollowRedirects, 'faraday_middleware/response/follow_redirects'
|
16
17
|
autoload :Instrumentation, 'faraday_middleware/instrumentation'
|
@@ -30,7 +31,8 @@ module FaradayMiddleware
|
|
30
31
|
:marshal => lambda { ParseMarshal },
|
31
32
|
:yaml => lambda { ParseYaml },
|
32
33
|
:caching => lambda { Caching },
|
33
|
-
:follow_redirects => lambda { FollowRedirects }
|
34
|
+
:follow_redirects => lambda { FollowRedirects },
|
35
|
+
:chunked => lambda { Chunked }
|
34
36
|
|
35
37
|
Faraday.register_middleware \
|
36
38
|
:instrumentation => lambda { Instrumentation }
|
@@ -12,7 +12,9 @@ module FaradayMiddleware
|
|
12
12
|
CONTENT_TYPE = 'Content-Type'.freeze
|
13
13
|
MIME_TYPE = 'application/json'.freeze
|
14
14
|
|
15
|
-
dependency
|
15
|
+
dependency do
|
16
|
+
require 'json' unless defined?(::JSON)
|
17
|
+
end
|
16
18
|
|
17
19
|
def call(env)
|
18
20
|
match_content_type(env) do |data|
|
@@ -22,7 +24,7 @@ module FaradayMiddleware
|
|
22
24
|
end
|
23
25
|
|
24
26
|
def encode(data)
|
25
|
-
JSON.dump data
|
27
|
+
::JSON.dump data
|
26
28
|
end
|
27
29
|
|
28
30
|
def match_content_type(env)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'faraday_middleware/response_middleware'
|
2
|
+
|
3
|
+
module FaradayMiddleware
|
4
|
+
# Public: Parse a Transfer-Encoding: Chunked response to just the original data
|
5
|
+
class Chunked < FaradayMiddleware::ResponseMiddleware
|
6
|
+
TRANSFER_ENCODING = 'transfer-encoding'.freeze
|
7
|
+
|
8
|
+
define_parser do |raw_body|
|
9
|
+
decoded_body = []
|
10
|
+
until raw_body.empty?
|
11
|
+
chunk_len, raw_body = raw_body.split("\r\n", 2)
|
12
|
+
chunk_len = chunk_len.split(';',2).first.hex
|
13
|
+
break if chunk_len == 0
|
14
|
+
decoded_body << raw_body[0, chunk_len]
|
15
|
+
# The 2 is to strip the extra CRLF at the end of the chunk
|
16
|
+
raw_body = raw_body[chunk_len + 2, raw_body.length - chunk_len - 2]
|
17
|
+
end
|
18
|
+
decoded_body.join('')
|
19
|
+
end
|
20
|
+
|
21
|
+
def parse_response?(env)
|
22
|
+
super and chunked_encoding?(env[:response_headers])
|
23
|
+
end
|
24
|
+
|
25
|
+
def chunked_encoding?(headers)
|
26
|
+
encoding = headers[TRANSFER_ENCODING] and encoding.split(',').include?('chunked')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -50,6 +50,9 @@ module FaradayMiddleware
|
|
50
50
|
# standards_compliant - A Boolean indicating whether to respect
|
51
51
|
# the HTTP spec when following 302
|
52
52
|
# (default: false)
|
53
|
+
# cookie - Use either an array of strings
|
54
|
+
# (e.g. ['cookie1', 'cookie2']) to choose kept cookies
|
55
|
+
# or :all to keep all cookies.
|
53
56
|
def initialize(app, options = {})
|
54
57
|
super(app)
|
55
58
|
@options = options
|
@@ -84,6 +87,7 @@ module FaradayMiddleware
|
|
84
87
|
|
85
88
|
def update_env(env, request_body, response)
|
86
89
|
env[:url] += response['location']
|
90
|
+
env[:request_headers][:cookies] = keep_cookies(env) if @options[:cookies]
|
87
91
|
|
88
92
|
if transform_into_get?(response)
|
89
93
|
env[:method] = :get
|
@@ -106,6 +110,25 @@ module FaradayMiddleware
|
|
106
110
|
@options.fetch(:limit, FOLLOW_LIMIT)
|
107
111
|
end
|
108
112
|
|
113
|
+
def keep_cookies(env)
|
114
|
+
cookies = @options.fetch(:cookies, [])
|
115
|
+
response_cookies = env[:response_headers][:cookies]
|
116
|
+
cookies == :all ? response_cookies : selected_request_cookies(response_cookies)
|
117
|
+
end
|
118
|
+
|
119
|
+
def selected_request_cookies(cookies)
|
120
|
+
selected_cookies(cookies)[0...-1]
|
121
|
+
end
|
122
|
+
|
123
|
+
def selected_cookies(cookies)
|
124
|
+
"".tap do |cookie_string|
|
125
|
+
@options[:cookies].each do |cookie|
|
126
|
+
string = /#{cookie}=?[^;]*/.match(cookies)[0] + ';'
|
127
|
+
cookie_string << string
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
109
132
|
def standards_compliant?
|
110
133
|
@options.fetch(:standards_compliant, false)
|
111
134
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require "time"
|
2
|
+
require "faraday"
|
3
|
+
|
4
|
+
module FaradayMiddleware
|
5
|
+
# Parse dates from response body
|
6
|
+
class ParseDates < ::Faraday::Response::Middleware
|
7
|
+
ISO_DATE_FORMAT = /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z\Z/m
|
8
|
+
|
9
|
+
def initialize(app, options = {})
|
10
|
+
@regexp = options[:match] || ISO_DATE_FORMAT
|
11
|
+
super(app)
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
response = @app.call(env)
|
16
|
+
parse_dates! response.env[:body]
|
17
|
+
response
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def parse_dates!(value)
|
23
|
+
case value
|
24
|
+
when Hash
|
25
|
+
value.each do |key, element|
|
26
|
+
value[key] = parse_dates!(element)
|
27
|
+
end
|
28
|
+
when Array
|
29
|
+
value.each_with_index do |element, index|
|
30
|
+
value[index] = parse_dates!(element)
|
31
|
+
end
|
32
|
+
when @regexp
|
33
|
+
Time.parse(value)
|
34
|
+
else
|
35
|
+
value
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -3,13 +3,13 @@ require 'faraday_middleware/response_middleware'
|
|
3
3
|
module FaradayMiddleware
|
4
4
|
# Public: Parse response bodies as JSON.
|
5
5
|
class ParseJson < ResponseMiddleware
|
6
|
-
dependency
|
7
|
-
require 'json' unless defined?(JSON)
|
8
|
-
|
6
|
+
dependency do
|
7
|
+
require 'json' unless defined?(::JSON)
|
8
|
+
end
|
9
9
|
|
10
|
-
define_parser
|
11
|
-
JSON.parse body unless body.strip.empty?
|
12
|
-
|
10
|
+
define_parser do |body|
|
11
|
+
::JSON.parse body unless body.strip.empty?
|
12
|
+
end
|
13
13
|
|
14
14
|
# Public: Override the content-type of the response with "application/json"
|
15
15
|
# if the response body looks like it might be JSON, i.e. starts with an
|
@@ -3,9 +3,9 @@ require 'faraday_middleware/response_middleware'
|
|
3
3
|
module FaradayMiddleware
|
4
4
|
# Public: Restore marshalled Ruby objects in response bodies.
|
5
5
|
class ParseMarshal < ResponseMiddleware
|
6
|
-
define_parser
|
6
|
+
define_parser do |body|
|
7
7
|
::Marshal.load body unless body.empty?
|
8
|
-
|
8
|
+
end
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'faraday_middleware/response/chunked'
|
3
|
+
|
4
|
+
describe FaradayMiddleware::Chunked, :type => :response do
|
5
|
+
context "no transfer-encoding" do
|
6
|
+
it "doesn't change nil body" do
|
7
|
+
process(nil).body.should be_nil
|
8
|
+
end
|
9
|
+
|
10
|
+
it "doesn't change an empty body" do
|
11
|
+
process('').body.should eql('')
|
12
|
+
end
|
13
|
+
|
14
|
+
it "doesn't change a normal body" do
|
15
|
+
process('asdf').body.should eql('asdf')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context "transfer-encoding gzip" do
|
20
|
+
let(:headers) { {"transfer-encoding" => "gzip"}}
|
21
|
+
|
22
|
+
it "doesn't change nil body" do
|
23
|
+
process(nil).body.should be_nil
|
24
|
+
end
|
25
|
+
|
26
|
+
it "doesn't change an empty body" do
|
27
|
+
process('').body.should eql('')
|
28
|
+
end
|
29
|
+
|
30
|
+
it "doesn't change a normal body" do
|
31
|
+
process('asdf').body.should eql('asdf')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "transfer-encoding chunked" do
|
36
|
+
let(:headers) { {"transfer-encoding" => "chunked"}}
|
37
|
+
|
38
|
+
it "doesn't change nil body" do
|
39
|
+
process(nil).body.should be_nil
|
40
|
+
end
|
41
|
+
|
42
|
+
it "doesn't change an empty body" do
|
43
|
+
process('').body.should eql('')
|
44
|
+
end
|
45
|
+
|
46
|
+
it "parses a basic chunked body" do
|
47
|
+
process("10\r\nasdfghjklasdfghj\r\n0\r\n").body.should eql('asdfghjklasdfghj')
|
48
|
+
end
|
49
|
+
|
50
|
+
it "parses a chunked body with no ending chunk" do
|
51
|
+
process("10\r\nasdfghjklasdfghj\r\n").body.should eql('asdfghjklasdfghj')
|
52
|
+
end
|
53
|
+
|
54
|
+
it "parses a chunked body with no trailing CRLF on the data chunk" do
|
55
|
+
process("10\r\nasdfghjklasdfghj0\r\n").body.should eql('asdfghjklasdfghj')
|
56
|
+
end
|
57
|
+
|
58
|
+
it "parses a chunked body with an extension" do
|
59
|
+
process("10;foo=bar\r\nasdfghjklasdfghj\r\n0\r\n").body.should eql('asdfghjklasdfghj')
|
60
|
+
end
|
61
|
+
|
62
|
+
it "parses a chunked body with two extensions" do
|
63
|
+
process("10;foo=bar;bar=baz\r\nasdfghjklasdfghj\r\n0\r\n").body.should eql('asdfghjklasdfghj')
|
64
|
+
end
|
65
|
+
|
66
|
+
it "parses a chunked body with two chunks" do
|
67
|
+
process("8\r\nasdfghjk\r\n8\r\nlasdfghj\r\n0\r\n").body.should eql('asdfghjklasdfghj')
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context "transfer-encoding chunked,chunked" do
|
72
|
+
let(:headers) { {"transfer-encoding" => "chunked,chunked"}}
|
73
|
+
|
74
|
+
it "parses a basic chunked body" do
|
75
|
+
process("10\r\nasdfghjklasdfghj\r\n0\r\n").body.should eql('asdfghjklasdfghj')
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -130,6 +130,29 @@ describe FaradayMiddleware::FollowRedirects do
|
|
130
130
|
expect { conn.get('/') }.to raise_error(FaradayMiddleware::RedirectLimitReached)
|
131
131
|
end
|
132
132
|
|
133
|
+
context 'when cookies option' do
|
134
|
+
|
135
|
+
let(:cookies) { 'cookie1=abcdefg; cookie2=1234567; cookie3=awesome' }
|
136
|
+
|
137
|
+
context "is :all" do
|
138
|
+
it "puts all cookies from the response into the next request" do
|
139
|
+
conn = connection(:cookies => :all) do |stub|
|
140
|
+
stub.get('/') { [301, {'Location' => '/found', 'Cookies' => cookies }, ''] }
|
141
|
+
stub.get('/found') { [200, {'Content-Type' => 'text/plain'}, ''] }
|
142
|
+
end.get('/').env[:request_headers][:cookies].should == cookies
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
context "is an array of cookie names" do
|
147
|
+
it "puts selected cookies from the response into the next request" do
|
148
|
+
conn = connection(:cookies => ['cookie2']) do |stub|
|
149
|
+
stub.get('/') { [301, {'Location' => '/found', 'Cookies' => cookies }, ''] }
|
150
|
+
stub.get('/found') { [200, {'Content-Type' => 'text/plain'}, ''] }
|
151
|
+
end.get('/').env[:request_headers][:cookies].should == 'cookie2=1234567'
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
133
156
|
context 'for an HTTP 301 response' do
|
134
157
|
it_should_behave_like 'a successful redirection', 301
|
135
158
|
it_should_behave_like 'a forced GET redirection', 301
|
data/spec/helper.rb
CHANGED
@@ -21,6 +21,7 @@ require 'rspec'
|
|
21
21
|
module ResponseMiddlewareExampleGroup
|
22
22
|
def self.included(base)
|
23
23
|
base.let(:options) { Hash.new }
|
24
|
+
base.let(:headers) { Hash.new }
|
24
25
|
base.let(:middleware) {
|
25
26
|
described_class.new(lambda {|env|
|
26
27
|
Faraday::Response.new(env)
|
@@ -31,7 +32,7 @@ module ResponseMiddlewareExampleGroup
|
|
31
32
|
def process(body, content_type = nil, options = {})
|
32
33
|
env = {
|
33
34
|
:body => body, :request => options,
|
34
|
-
:response_headers => Faraday::Utils::Headers.new
|
35
|
+
:response_headers => Faraday::Utils::Headers.new(headers)
|
35
36
|
}
|
36
37
|
env[:response_headers]['content-type'] = content_type if content_type
|
37
38
|
middleware.call(env)
|
data/spec/mashify_spec.rb
CHANGED
@@ -39,6 +39,13 @@ describe FaradayMiddleware::Mashify do
|
|
39
39
|
us.last.username.should == 'pengwynn'
|
40
40
|
end
|
41
41
|
|
42
|
+
it 'should handle nested arrays of hashes' do
|
43
|
+
env = { :body => [[{ "username" => "sferik" }, { "username" => "pengwynn" }]] }
|
44
|
+
us = mashify.on_complete(env)
|
45
|
+
us.first.first.username.should == 'sferik'
|
46
|
+
us.first.last.username.should == 'pengwynn'
|
47
|
+
end
|
48
|
+
|
42
49
|
it 'should handle mixed arrays' do
|
43
50
|
env = { :body => [123, { "username" => "sferik" }, 456] }
|
44
51
|
values = mashify.on_complete(env)
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'faraday_middleware/response/parse_dates'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
describe FaradayMiddleware::ParseDates, :type => :response do
|
6
|
+
let(:parsed){
|
7
|
+
if RUBY_VERSION > "1.9"
|
8
|
+
"2012-02-01 13:14:15 UTC"
|
9
|
+
else
|
10
|
+
"Wed Feb 01 13:14:15 UTC 2012"
|
11
|
+
end
|
12
|
+
}
|
13
|
+
|
14
|
+
it "should parse dates" do
|
15
|
+
process({"x" => "2012-02-01T13:14:15Z"}).body["x"].to_s.should == parsed
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should parse nested dates in hash" do
|
19
|
+
process({"x" => {"y" => "2012-02-01T13:14:15Z"}}).body["x"]["y"].to_s.should == parsed
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should parse nested dates in arrays" do
|
23
|
+
process({"x" => [{"y" =>"2012-02-01T13:14:15Z"}]}).body["x"][0]["y"].to_s.should == parsed
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should not blow up on empty body" do
|
27
|
+
process(nil).body.should == nil
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should leave arrays with ids alone" do
|
31
|
+
process({"x" => [1,2,3]}).body.should == {"x" => [1,2,3]}
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should not parse date-like things" do
|
35
|
+
process({"x" => "2012-02-01T13:14:15Z bla"}).body["x"].to_s.should ==
|
36
|
+
"2012-02-01T13:14:15Z bla"
|
37
|
+
process({"x" => "12012-02-01T13:14:15Z"}).body["x"].to_s.should ==
|
38
|
+
"12012-02-01T13:14:15Z"
|
39
|
+
process({"x" => "2012-02-01T13:14:15Z\nfoo"}).body["x"].to_s.should ==
|
40
|
+
"2012-02-01T13:14:15Z\nfoo"
|
41
|
+
end
|
42
|
+
end
|
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.8
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-06-24 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: faraday
|
@@ -173,8 +173,10 @@ files:
|
|
173
173
|
- lib/faraday_middleware/request/oauth.rb
|
174
174
|
- lib/faraday_middleware/request/oauth2.rb
|
175
175
|
- lib/faraday_middleware/response/caching.rb
|
176
|
+
- lib/faraday_middleware/response/chunked.rb
|
176
177
|
- lib/faraday_middleware/response/follow_redirects.rb
|
177
178
|
- lib/faraday_middleware/response/mashify.rb
|
179
|
+
- lib/faraday_middleware/response/parse_dates.rb
|
178
180
|
- lib/faraday_middleware/response/parse_json.rb
|
179
181
|
- lib/faraday_middleware/response/parse_marshal.rb
|
180
182
|
- lib/faraday_middleware/response/parse_xml.rb
|
@@ -183,12 +185,14 @@ files:
|
|
183
185
|
- lib/faraday_middleware/response_middleware.rb
|
184
186
|
- lib/faraday_middleware/version.rb
|
185
187
|
- spec/caching_test.rb
|
188
|
+
- spec/chunked_spec.rb
|
186
189
|
- spec/encode_json_spec.rb
|
187
190
|
- spec/follow_redirects_spec.rb
|
188
191
|
- spec/helper.rb
|
189
192
|
- spec/mashify_spec.rb
|
190
193
|
- spec/oauth2_spec.rb
|
191
194
|
- spec/oauth_spec.rb
|
195
|
+
- spec/parse_dates_spec.rb
|
192
196
|
- spec/parse_json_spec.rb
|
193
197
|
- spec/parse_marshal_spec.rb
|
194
198
|
- spec/parse_xml_spec.rb
|
@@ -214,18 +218,20 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
214
218
|
version: 1.3.6
|
215
219
|
requirements: []
|
216
220
|
rubyforge_project:
|
217
|
-
rubygems_version: 1.8.
|
221
|
+
rubygems_version: 1.8.23
|
218
222
|
signing_key:
|
219
223
|
specification_version: 3
|
220
224
|
summary: Various middleware for Faraday
|
221
225
|
test_files:
|
222
226
|
- spec/caching_test.rb
|
227
|
+
- spec/chunked_spec.rb
|
223
228
|
- spec/encode_json_spec.rb
|
224
229
|
- spec/follow_redirects_spec.rb
|
225
230
|
- spec/helper.rb
|
226
231
|
- spec/mashify_spec.rb
|
227
232
|
- spec/oauth2_spec.rb
|
228
233
|
- spec/oauth_spec.rb
|
234
|
+
- spec/parse_dates_spec.rb
|
229
235
|
- spec/parse_json_spec.rb
|
230
236
|
- spec/parse_marshal_spec.rb
|
231
237
|
- spec/parse_xml_spec.rb
|