faraday 1.1.0 → 2.7.4
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +299 -1
- data/LICENSE.md +1 -1
- data/README.md +18 -17
- data/examples/client_spec.rb +67 -13
- data/examples/client_test.rb +80 -15
- data/lib/faraday/adapter/test.rb +117 -52
- data/lib/faraday/adapter.rb +5 -20
- data/lib/faraday/connection.rb +64 -118
- data/lib/faraday/encoders/nested_params_encoder.rb +13 -6
- data/lib/faraday/error.rb +15 -8
- data/lib/faraday/logging/formatter.rb +19 -2
- data/lib/faraday/methods.rb +6 -0
- data/lib/faraday/middleware.rb +17 -5
- data/lib/faraday/middleware_registry.rb +17 -63
- data/lib/faraday/options/env.rb +31 -7
- data/lib/faraday/options/proxy_options.rb +4 -0
- data/lib/faraday/options/ssl_options.rb +11 -1
- data/lib/faraday/options.rb +3 -3
- data/lib/faraday/rack_builder.rb +23 -20
- data/lib/faraday/request/authorization.rb +37 -38
- data/lib/faraday/request/instrumentation.rb +2 -0
- data/lib/faraday/request/json.rb +55 -0
- data/lib/faraday/request/url_encoded.rb +5 -1
- data/lib/faraday/request.rb +12 -32
- data/lib/faraday/response/json.rb +54 -0
- data/lib/faraday/response/logger.rb +8 -4
- data/lib/faraday/response/raise_error.rb +9 -1
- data/lib/faraday/response.rb +10 -26
- data/lib/faraday/utils/headers.rb +7 -2
- data/lib/faraday/utils.rb +10 -5
- data/lib/faraday/version.rb +5 -0
- data/lib/faraday.rb +49 -58
- data/spec/faraday/adapter/test_spec.rb +182 -0
- data/spec/faraday/connection_spec.rb +207 -90
- data/spec/faraday/error_spec.rb +15 -0
- data/spec/faraday/middleware_registry_spec.rb +31 -0
- data/spec/faraday/middleware_spec.rb +50 -6
- data/spec/faraday/options/env_spec.rb +8 -2
- data/spec/faraday/options/proxy_options_spec.rb +7 -0
- data/spec/faraday/params_encoders/nested_spec.rb +8 -0
- data/spec/faraday/rack_builder_spec.rb +26 -54
- data/spec/faraday/request/authorization_spec.rb +54 -24
- data/spec/faraday/request/instrumentation_spec.rb +5 -7
- data/spec/faraday/request/json_spec.rb +111 -0
- data/spec/faraday/request/url_encoded_spec.rb +12 -2
- data/spec/faraday/request_spec.rb +5 -15
- data/spec/faraday/response/json_spec.rb +117 -0
- data/spec/faraday/response/logger_spec.rb +28 -0
- data/spec/faraday/response/raise_error_spec.rb +37 -4
- data/spec/faraday/response_spec.rb +3 -1
- data/spec/faraday/utils/headers_spec.rb +22 -4
- data/spec/faraday/utils_spec.rb +63 -1
- data/spec/support/fake_safe_buffer.rb +1 -1
- data/spec/support/helper_methods.rb +0 -37
- data/spec/support/shared_examples/adapter.rb +4 -3
- data/spec/support/shared_examples/request_method.rb +58 -29
- metadata +19 -45
- data/lib/faraday/adapter/em_http.rb +0 -286
- data/lib/faraday/adapter/em_http_ssl_patch.rb +0 -62
- data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +0 -69
- data/lib/faraday/adapter/em_synchrony.rb +0 -150
- data/lib/faraday/adapter/excon.rb +0 -124
- data/lib/faraday/adapter/httpclient.rb +0 -152
- data/lib/faraday/adapter/net_http.rb +0 -219
- data/lib/faraday/adapter/net_http_persistent.rb +0 -91
- data/lib/faraday/adapter/patron.rb +0 -132
- data/lib/faraday/adapter/rack.rb +0 -75
- data/lib/faraday/adapter/typhoeus.rb +0 -15
- data/lib/faraday/autoload.rb +0 -95
- data/lib/faraday/dependency_loader.rb +0 -39
- data/lib/faraday/file_part.rb +0 -128
- data/lib/faraday/param_part.rb +0 -53
- data/lib/faraday/request/basic_authentication.rb +0 -20
- data/lib/faraday/request/multipart.rb +0 -106
- data/lib/faraday/request/retry.rb +0 -239
- data/lib/faraday/request/token_authentication.rb +0 -20
- data/spec/faraday/adapter/em_http_spec.rb +0 -47
- data/spec/faraday/adapter/em_synchrony_spec.rb +0 -16
- data/spec/faraday/adapter/excon_spec.rb +0 -49
- data/spec/faraday/adapter/httpclient_spec.rb +0 -73
- data/spec/faraday/adapter/net_http_persistent_spec.rb +0 -57
- data/spec/faraday/adapter/net_http_spec.rb +0 -64
- data/spec/faraday/adapter/patron_spec.rb +0 -18
- data/spec/faraday/adapter/rack_spec.rb +0 -8
- data/spec/faraday/adapter/typhoeus_spec.rb +0 -7
- data/spec/faraday/composite_read_io_spec.rb +0 -80
- data/spec/faraday/request/multipart_spec.rb +0 -302
- data/spec/faraday/request/retry_spec.rb +0 -242
- data/spec/faraday/response/middleware_spec.rb +0 -68
- data/spec/support/webmock_rack_app.rb +0 -68
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Faraday::Response::Json, type: :response do
|
4
|
+
let(:options) { {} }
|
5
|
+
let(:headers) { {} }
|
6
|
+
let(:middleware) do
|
7
|
+
described_class.new(lambda { |env|
|
8
|
+
Faraday::Response.new(env)
|
9
|
+
}, **options)
|
10
|
+
end
|
11
|
+
|
12
|
+
def process(body, content_type = 'application/json', options = {})
|
13
|
+
env = {
|
14
|
+
body: body, request: options,
|
15
|
+
request_headers: Faraday::Utils::Headers.new,
|
16
|
+
response_headers: Faraday::Utils::Headers.new(headers)
|
17
|
+
}
|
18
|
+
env[:response_headers]['content-type'] = content_type if content_type
|
19
|
+
yield(env) if block_given?
|
20
|
+
middleware.call(Faraday::Env.from(env))
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'no type matching' do
|
24
|
+
it "doesn't change nil body" do
|
25
|
+
expect(process(nil).body).to be_nil
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'nullifies empty body' do
|
29
|
+
expect(process('').body).to be_nil
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'parses json body' do
|
33
|
+
response = process('{"a":1}')
|
34
|
+
expect(response.body).to eq('a' => 1)
|
35
|
+
expect(response.env[:raw_body]).to be_nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'with preserving raw' do
|
40
|
+
let(:options) { { preserve_raw: true } }
|
41
|
+
|
42
|
+
it 'parses json body' do
|
43
|
+
response = process('{"a":1}')
|
44
|
+
expect(response.body).to eq('a' => 1)
|
45
|
+
expect(response.env[:raw_body]).to eq('{"a":1}')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'with default regexp type matching' do
|
50
|
+
it 'parses json body of correct type' do
|
51
|
+
response = process('{"a":1}', 'application/x-json')
|
52
|
+
expect(response.body).to eq('a' => 1)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'ignores json body of incorrect type' do
|
56
|
+
response = process('{"a":1}', 'text/json-xml')
|
57
|
+
expect(response.body).to eq('{"a":1}')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'with array type matching' do
|
62
|
+
let(:options) { { content_type: %w[a/b c/d] } }
|
63
|
+
|
64
|
+
it 'parses json body of correct type' do
|
65
|
+
expect(process('{"a":1}', 'a/b').body).to be_a(Hash)
|
66
|
+
expect(process('{"a":1}', 'c/d').body).to be_a(Hash)
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'ignores json body of incorrect type' do
|
70
|
+
expect(process('{"a":1}', 'a/d').body).not_to be_a(Hash)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'chokes on invalid json' do
|
75
|
+
expect { process('{!') }.to raise_error(Faraday::ParsingError)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'includes the response on the ParsingError instance' do
|
79
|
+
process('{') { |env| env[:response] = Faraday::Response.new }
|
80
|
+
raise 'Parsing should have failed.'
|
81
|
+
rescue Faraday::ParsingError => e
|
82
|
+
expect(e.response).to be_a(Faraday::Response)
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'HEAD responses' do
|
86
|
+
it "nullifies the body if it's only one space" do
|
87
|
+
response = process(' ')
|
88
|
+
expect(response.body).to be_nil
|
89
|
+
end
|
90
|
+
|
91
|
+
it "nullifies the body if it's two spaces" do
|
92
|
+
response = process(' ')
|
93
|
+
expect(response.body).to be_nil
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'JSON options' do
|
98
|
+
let(:body) { '{"a": 1}' }
|
99
|
+
let(:result) { { a: 1 } }
|
100
|
+
let(:options) do
|
101
|
+
{
|
102
|
+
parser_options: {
|
103
|
+
symbolize_names: true
|
104
|
+
}
|
105
|
+
}
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'passes relevant options to JSON parse' do
|
109
|
+
expect(::JSON).to receive(:parse)
|
110
|
+
.with(body, options[:parser_options])
|
111
|
+
.and_return(result)
|
112
|
+
|
113
|
+
response = process(body)
|
114
|
+
expect(response.body).to eq(result)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -64,6 +64,15 @@ RSpec.describe Faraday::Response::Logger do
|
|
64
64
|
expect(formatter).to receive(:response).with(an_instance_of(Faraday::Env))
|
65
65
|
conn.get '/hello'
|
66
66
|
end
|
67
|
+
|
68
|
+
context 'when no route' do
|
69
|
+
it 'delegates logging to the formatter' do
|
70
|
+
expect(formatter).to receive(:request).with(an_instance_of(Faraday::Env))
|
71
|
+
expect(formatter).to receive(:exception).with(an_instance_of(Faraday::Adapter::Test::Stubs::NotFound))
|
72
|
+
|
73
|
+
expect { conn.get '/noroute' }.to raise_error(Faraday::Adapter::Test::Stubs::NotFound)
|
74
|
+
end
|
75
|
+
end
|
67
76
|
end
|
68
77
|
|
69
78
|
context 'with custom formatter' do
|
@@ -94,6 +103,16 @@ RSpec.describe Faraday::Response::Logger do
|
|
94
103
|
expect(string_io.string).to match('GET http:/hello')
|
95
104
|
end
|
96
105
|
|
106
|
+
it 'logs status' do
|
107
|
+
conn.get '/hello', nil, accept: 'text/html'
|
108
|
+
expect(string_io.string).to match('Status 200')
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'does not log error message by default' do
|
112
|
+
expect { conn.get '/noroute' }.to raise_error(Faraday::Adapter::Test::Stubs::NotFound)
|
113
|
+
expect(string_io.string).not_to match(%(no stubbed request for get http:/noroute))
|
114
|
+
end
|
115
|
+
|
97
116
|
it 'logs request headers by default' do
|
98
117
|
conn.get '/hello', nil, accept: 'text/html'
|
99
118
|
expect(string_io.string).to match(%(Accept: "text/html))
|
@@ -188,6 +207,15 @@ RSpec.describe Faraday::Response::Logger do
|
|
188
207
|
end
|
189
208
|
end
|
190
209
|
|
210
|
+
context 'when logging errors' do
|
211
|
+
let(:logger_options) { { errors: true } }
|
212
|
+
|
213
|
+
it 'logs error message' do
|
214
|
+
expect { conn.get '/noroute' }.to raise_error(Faraday::Adapter::Test::Stubs::NotFound)
|
215
|
+
expect(string_io.string).to match(%(no stubbed request for get http:/noroute))
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
191
219
|
context 'when using log_level' do
|
192
220
|
let(:logger_options) { { bodies: true, log_level: :debug } }
|
193
221
|
|
@@ -29,6 +29,9 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
29
29
|
expect(ex.message).to eq('the server responded with status 400')
|
30
30
|
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
31
31
|
expect(ex.response[:status]).to eq(400)
|
32
|
+
expect(ex.response_status).to eq(400)
|
33
|
+
expect(ex.response_body).to eq('keep looking')
|
34
|
+
expect(ex.response_headers['X-Reason']).to eq('because')
|
32
35
|
end
|
33
36
|
end
|
34
37
|
|
@@ -37,6 +40,9 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
37
40
|
expect(ex.message).to eq('the server responded with status 401')
|
38
41
|
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
39
42
|
expect(ex.response[:status]).to eq(401)
|
43
|
+
expect(ex.response_status).to eq(401)
|
44
|
+
expect(ex.response_body).to eq('keep looking')
|
45
|
+
expect(ex.response_headers['X-Reason']).to eq('because')
|
40
46
|
end
|
41
47
|
end
|
42
48
|
|
@@ -45,6 +51,9 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
45
51
|
expect(ex.message).to eq('the server responded with status 403')
|
46
52
|
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
47
53
|
expect(ex.response[:status]).to eq(403)
|
54
|
+
expect(ex.response_status).to eq(403)
|
55
|
+
expect(ex.response_body).to eq('keep looking')
|
56
|
+
expect(ex.response_headers['X-Reason']).to eq('because')
|
48
57
|
end
|
49
58
|
end
|
50
59
|
|
@@ -53,6 +62,9 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
53
62
|
expect(ex.message).to eq('the server responded with status 404')
|
54
63
|
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
55
64
|
expect(ex.response[:status]).to eq(404)
|
65
|
+
expect(ex.response_status).to eq(404)
|
66
|
+
expect(ex.response_body).to eq('keep looking')
|
67
|
+
expect(ex.response_headers['X-Reason']).to eq('because')
|
56
68
|
end
|
57
69
|
end
|
58
70
|
|
@@ -61,6 +73,9 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
61
73
|
expect(ex.message).to eq('407 "Proxy Authentication Required"')
|
62
74
|
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
63
75
|
expect(ex.response[:status]).to eq(407)
|
76
|
+
expect(ex.response_status).to eq(407)
|
77
|
+
expect(ex.response_body).to eq('keep looking')
|
78
|
+
expect(ex.response_headers['X-Reason']).to eq('because')
|
64
79
|
end
|
65
80
|
end
|
66
81
|
|
@@ -69,6 +84,9 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
69
84
|
expect(ex.message).to eq('the server responded with status 409')
|
70
85
|
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
71
86
|
expect(ex.response[:status]).to eq(409)
|
87
|
+
expect(ex.response_status).to eq(409)
|
88
|
+
expect(ex.response_body).to eq('keep looking')
|
89
|
+
expect(ex.response_headers['X-Reason']).to eq('because')
|
72
90
|
end
|
73
91
|
end
|
74
92
|
|
@@ -77,6 +95,9 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
77
95
|
expect(ex.message).to eq('the server responded with status 422')
|
78
96
|
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
79
97
|
expect(ex.response[:status]).to eq(422)
|
98
|
+
expect(ex.response_status).to eq(422)
|
99
|
+
expect(ex.response_body).to eq('keep looking')
|
100
|
+
expect(ex.response_headers['X-Reason']).to eq('because')
|
80
101
|
end
|
81
102
|
end
|
82
103
|
|
@@ -85,6 +106,9 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
85
106
|
expect(ex.message).to eq('http status could not be derived from the server response')
|
86
107
|
expect(ex.response[:headers]['X-Reason']).to eq('nil')
|
87
108
|
expect(ex.response[:status]).to be_nil
|
109
|
+
expect(ex.response_status).to be_nil
|
110
|
+
expect(ex.response_body).to eq('fail')
|
111
|
+
expect(ex.response_headers['X-Reason']).to eq('nil')
|
88
112
|
end
|
89
113
|
end
|
90
114
|
|
@@ -93,6 +117,9 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
93
117
|
expect(ex.message).to eq('the server responded with status 499')
|
94
118
|
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
95
119
|
expect(ex.response[:status]).to eq(499)
|
120
|
+
expect(ex.response_status).to eq(499)
|
121
|
+
expect(ex.response_body).to eq('keep looking')
|
122
|
+
expect(ex.response_headers['X-Reason']).to eq('because')
|
96
123
|
end
|
97
124
|
end
|
98
125
|
|
@@ -101,6 +128,9 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
101
128
|
expect(ex.message).to eq('the server responded with status 500')
|
102
129
|
expect(ex.response[:headers]['X-Error']).to eq('bailout')
|
103
130
|
expect(ex.response[:status]).to eq(500)
|
131
|
+
expect(ex.response_status).to eq(500)
|
132
|
+
expect(ex.response_body).to eq('fail')
|
133
|
+
expect(ex.response_headers['X-Error']).to eq('bailout')
|
104
134
|
end
|
105
135
|
end
|
106
136
|
|
@@ -109,7 +139,7 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
109
139
|
Faraday.new do |b|
|
110
140
|
b.response :raise_error
|
111
141
|
b.adapter :test do |stub|
|
112
|
-
stub.post(
|
142
|
+
stub.post(url, request_body, request_headers) do
|
113
143
|
[400, { 'X-Reason' => 'because' }, 'keep looking']
|
114
144
|
end
|
115
145
|
end
|
@@ -117,11 +147,13 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
117
147
|
end
|
118
148
|
let(:request_body) { JSON.generate({ 'item' => 'sth' }) }
|
119
149
|
let(:request_headers) { { 'Authorization' => 'Basic 123' } }
|
150
|
+
let(:url_path) { 'request' }
|
151
|
+
let(:query_params) { 'full=true' }
|
152
|
+
let(:url) { "#{url_path}?#{query_params}" }
|
120
153
|
|
121
154
|
subject(:perform_request) do
|
122
|
-
conn.post
|
155
|
+
conn.post url do |req|
|
123
156
|
req.headers['Authorization'] = 'Basic 123'
|
124
|
-
req.params[:full] = true
|
125
157
|
req.body = request_body
|
126
158
|
end
|
127
159
|
end
|
@@ -129,7 +161,8 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
129
161
|
it 'returns the request info in the exception' do
|
130
162
|
expect { perform_request }.to raise_error(Faraday::BadRequestError) do |ex|
|
131
163
|
expect(ex.response[:request][:method]).to eq(:post)
|
132
|
-
expect(ex.response[:request][:
|
164
|
+
expect(ex.response[:request][:url]).to eq(URI("http:/#{url}"))
|
165
|
+
expect(ex.response[:request][:url_path]).to eq("/#{url_path}")
|
133
166
|
expect(ex.response[:request][:params]).to eq({ 'full' => 'true' })
|
134
167
|
expect(ex.response[:request][:headers]).to match(a_hash_including(request_headers))
|
135
168
|
expect(ex.response[:request][:body]).to eq(request_body)
|
@@ -4,7 +4,7 @@ RSpec.describe Faraday::Response do
|
|
4
4
|
subject { Faraday::Response.new(env) }
|
5
5
|
|
6
6
|
let(:env) do
|
7
|
-
Faraday::Env.from(status: 404, body: 'yikes',
|
7
|
+
Faraday::Env.from(status: 404, body: 'yikes', url: Faraday::Utils.URI('https://lostisland.github.io/faraday'),
|
8
8
|
response_headers: { 'Content-Type' => 'text/plain' })
|
9
9
|
end
|
10
10
|
|
@@ -30,6 +30,7 @@ RSpec.describe Faraday::Response do
|
|
30
30
|
it { expect(hash[:status]).to eq(subject.status) }
|
31
31
|
it { expect(hash[:response_headers]).to eq(subject.headers) }
|
32
32
|
it { expect(hash[:body]).to eq(subject.body) }
|
33
|
+
it { expect(hash[:url]).to eq(subject.env.url) }
|
33
34
|
end
|
34
35
|
|
35
36
|
describe 'marshal serialization support' do
|
@@ -45,6 +46,7 @@ RSpec.describe Faraday::Response do
|
|
45
46
|
it { expect(loaded.env[:body]).to eq(env[:body]) }
|
46
47
|
it { expect(loaded.env[:response_headers]).to eq(env[:response_headers]) }
|
47
48
|
it { expect(loaded.env[:status]).to eq(env[:status]) }
|
49
|
+
it { expect(loaded.env[:url]).to eq(env[:url]) }
|
48
50
|
end
|
49
51
|
|
50
52
|
describe '#on_complete' do
|
@@ -57,26 +57,44 @@ RSpec.describe Faraday::Utils::Headers do
|
|
57
57
|
end
|
58
58
|
|
59
59
|
describe '#parse' do
|
60
|
-
before { subject.parse(headers) }
|
61
|
-
|
62
60
|
context 'when response headers leave http status line out' do
|
63
61
|
let(:headers) { "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n" }
|
64
62
|
|
63
|
+
before { subject.parse(headers) }
|
64
|
+
|
65
65
|
it { expect(subject.keys).to eq(%w[Content-Type]) }
|
66
66
|
it { expect(subject['Content-Type']).to eq('text/html') }
|
67
67
|
it { expect(subject['content-type']).to eq('text/html') }
|
68
68
|
end
|
69
69
|
|
70
70
|
context 'when response headers values include a colon' do
|
71
|
-
let(:headers) { "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nLocation: http://
|
71
|
+
let(:headers) { "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nLocation: http://httpbingo.org/\r\n\r\n" }
|
72
72
|
|
73
|
-
|
73
|
+
before { subject.parse(headers) }
|
74
|
+
|
75
|
+
it { expect(subject['location']).to eq('http://httpbingo.org/') }
|
74
76
|
end
|
75
77
|
|
76
78
|
context 'when response headers include a blank line' do
|
77
79
|
let(:headers) { "HTTP/1.1 200 OK\r\n\r\nContent-Type: text/html\r\n\r\n" }
|
78
80
|
|
81
|
+
before { subject.parse(headers) }
|
82
|
+
|
79
83
|
it { expect(subject['content-type']).to eq('text/html') }
|
80
84
|
end
|
85
|
+
|
86
|
+
context 'when response headers include already stored keys' do
|
87
|
+
let(:headers) { "HTTP/1.1 200 OK\r\nX-Numbers: 123\r\n\r\n" }
|
88
|
+
|
89
|
+
before do
|
90
|
+
h = subject
|
91
|
+
h[:x_numbers] = 8
|
92
|
+
h.parse(headers)
|
93
|
+
end
|
94
|
+
|
95
|
+
it do
|
96
|
+
expect(subject[:x_numbers]).to eq('8, 123')
|
97
|
+
end
|
98
|
+
end
|
81
99
|
end
|
82
100
|
end
|
data/spec/faraday/utils_spec.rb
CHANGED
@@ -4,7 +4,7 @@ RSpec.describe Faraday::Utils do
|
|
4
4
|
describe 'headers parsing' do
|
5
5
|
let(:multi_response_headers) do
|
6
6
|
"HTTP/1.x 500 OK\r\nContent-Type: text/html; charset=UTF-8\r\n" \
|
7
|
-
|
7
|
+
"HTTP/1.x 200 OK\r\nContent-Type: application/json; charset=UTF-8\r\n\r\n"
|
8
8
|
end
|
9
9
|
|
10
10
|
it 'parse headers for aggregated responses' do
|
@@ -53,4 +53,66 @@ RSpec.describe Faraday::Utils do
|
|
53
53
|
expect(headers).not_to have_key('authorization')
|
54
54
|
end
|
55
55
|
end
|
56
|
+
|
57
|
+
describe '.deep_merge!' do
|
58
|
+
let(:connection_options) { Faraday::ConnectionOptions.new }
|
59
|
+
let(:url) do
|
60
|
+
{
|
61
|
+
url: 'http://example.com/abc',
|
62
|
+
headers: { 'Mime-Version' => '1.0' },
|
63
|
+
request: { oauth: { consumer_key: 'anonymous' } },
|
64
|
+
ssl: { version: '2' }
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'recursively merges the headers' do
|
69
|
+
connection_options.headers = { user_agent: 'My Agent 1.0' }
|
70
|
+
deep_merge = Faraday::Utils.deep_merge!(connection_options, url)
|
71
|
+
|
72
|
+
expect(deep_merge.headers).to eq('Mime-Version' => '1.0', user_agent: 'My Agent 1.0')
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'when a target hash has an Options Struct value' do
|
76
|
+
let(:request) do
|
77
|
+
{
|
78
|
+
params_encoder: nil,
|
79
|
+
proxy: nil,
|
80
|
+
bind: nil,
|
81
|
+
timeout: nil,
|
82
|
+
open_timeout: nil,
|
83
|
+
read_timeout: nil,
|
84
|
+
write_timeout: nil,
|
85
|
+
boundary: nil,
|
86
|
+
oauth: { consumer_key: 'anonymous' },
|
87
|
+
context: nil,
|
88
|
+
on_data: nil
|
89
|
+
}
|
90
|
+
end
|
91
|
+
let(:ssl) do
|
92
|
+
{
|
93
|
+
verify: nil,
|
94
|
+
ca_file: nil,
|
95
|
+
ca_path: nil,
|
96
|
+
verify_mode: nil,
|
97
|
+
cert_store: nil,
|
98
|
+
client_cert: nil,
|
99
|
+
client_key: nil,
|
100
|
+
certificate: nil,
|
101
|
+
private_key: nil,
|
102
|
+
verify_depth: nil,
|
103
|
+
version: '2',
|
104
|
+
min_version: nil,
|
105
|
+
max_version: nil,
|
106
|
+
verify_hostname: nil
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'does not overwrite an Options Struct value' do
|
111
|
+
deep_merge = Faraday::Utils.deep_merge!(connection_options, url)
|
112
|
+
|
113
|
+
expect(deep_merge.request.to_h).to eq(request)
|
114
|
+
expect(deep_merge.ssl.to_h).to eq(ssl)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
56
118
|
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'multipart_parser/reader'
|
4
|
-
|
5
3
|
module Faraday
|
6
4
|
module HelperMethods
|
7
5
|
def self.included(base)
|
@@ -86,41 +84,6 @@ module Faraday
|
|
86
84
|
end
|
87
85
|
end
|
88
86
|
|
89
|
-
def multipart_file
|
90
|
-
Faraday::FilePart.new(__FILE__, 'text/x-ruby')
|
91
|
-
end
|
92
|
-
|
93
|
-
# parse boundary out of a Content-Type header like:
|
94
|
-
# Content-Type: multipart/form-data; boundary=gc0p4Jq0M2Yt08jU534c0p
|
95
|
-
def parse_multipart_boundary(ctype)
|
96
|
-
MultipartParser::Reader.extract_boundary_value(ctype)
|
97
|
-
end
|
98
|
-
|
99
|
-
# parse a multipart MIME message, returning a hash of any multipart errors
|
100
|
-
def parse_multipart(boundary, body)
|
101
|
-
reader = MultipartParser::Reader.new(boundary)
|
102
|
-
result = { errors: [], parts: [] }
|
103
|
-
def result.part(name)
|
104
|
-
hash = self[:parts].detect { |h| h[:part].name == name }
|
105
|
-
[hash[:part], hash[:body].join]
|
106
|
-
end
|
107
|
-
|
108
|
-
reader.on_part do |part|
|
109
|
-
result[:parts] << thispart = {
|
110
|
-
part: part,
|
111
|
-
body: []
|
112
|
-
}
|
113
|
-
part.on_data do |chunk|
|
114
|
-
thispart[:body] << chunk
|
115
|
-
end
|
116
|
-
end
|
117
|
-
reader.on_error do |msg|
|
118
|
-
result[:errors] << msg
|
119
|
-
end
|
120
|
-
reader.write(body)
|
121
|
-
result
|
122
|
-
end
|
123
|
-
|
124
87
|
def method_with_body?(method)
|
125
88
|
self.class.method_with_body?(method)
|
126
89
|
end
|
@@ -33,20 +33,21 @@ shared_examples 'adapter examples' do |**options|
|
|
33
33
|
|
34
34
|
let(:protocol) { ssl_mode? ? 'https' : 'http' }
|
35
35
|
let(:remote) { "#{protocol}://example.com" }
|
36
|
+
let(:stub_remote) { remote }
|
36
37
|
|
37
38
|
let(:conn) do
|
38
39
|
conn_options[:ssl] ||= {}
|
39
|
-
conn_options[:ssl][:ca_file] ||= ENV
|
40
|
+
conn_options[:ssl][:ca_file] ||= ENV.fetch('SSL_FILE', nil)
|
41
|
+
conn_options[:ssl][:verify_hostname] ||= ENV['SSL_VERIFY_HOSTNAME'] == 'yes'
|
40
42
|
|
41
43
|
Faraday.new(remote, conn_options) do |conn|
|
42
|
-
conn.request :multipart
|
43
44
|
conn.request :url_encoded
|
44
45
|
conn.response :raise_error
|
45
46
|
conn.adapter described_class, *adapter_options
|
46
47
|
end
|
47
48
|
end
|
48
49
|
|
49
|
-
let!(:request_stub) { stub_request(http_method,
|
50
|
+
let!(:request_stub) { stub_request(http_method, stub_remote) }
|
50
51
|
|
51
52
|
after do
|
52
53
|
expect(request_stub).to have_been_requested unless request_stub.disabled?
|