faraday 0.15.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +350 -0
- data/LICENSE.md +1 -1
- data/README.md +18 -345
- data/Rakefile +7 -0
- data/examples/client_spec.rb +65 -0
- data/examples/client_test.rb +79 -0
- data/lib/faraday.rb +118 -190
- data/lib/faraday/adapter.rb +82 -22
- data/lib/faraday/adapter/em_http.rb +150 -104
- data/lib/faraday/adapter/em_http_ssl_patch.rb +24 -18
- data/lib/faraday/adapter/em_synchrony.rb +110 -63
- data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +18 -15
- data/lib/faraday/adapter/excon.rb +98 -53
- data/lib/faraday/adapter/httpclient.rb +83 -59
- data/lib/faraday/adapter/net_http_persistent.rb +57 -29
- data/lib/faraday/adapter/patron.rb +80 -48
- data/lib/faraday/adapter/rack.rb +30 -13
- data/lib/faraday/adapter/test.rb +86 -53
- data/lib/faraday/adapter/typhoeus.rb +4 -1
- data/lib/faraday/adapter_registry.rb +30 -0
- data/lib/faraday/autoload.rb +46 -36
- data/lib/faraday/connection.rb +312 -182
- data/lib/faraday/dependency_loader.rb +37 -0
- data/lib/faraday/encoders/flat_params_encoder.rb +105 -0
- data/lib/faraday/encoders/nested_params_encoder.rb +176 -0
- data/lib/faraday/error.rb +123 -37
- data/lib/faraday/file_part.rb +128 -0
- data/lib/faraday/logging/formatter.rb +105 -0
- data/lib/faraday/methods.rb +6 -0
- data/lib/faraday/middleware.rb +19 -25
- data/lib/faraday/middleware_registry.rb +129 -0
- data/lib/faraday/options.rb +39 -193
- data/lib/faraday/options/connection_options.rb +22 -0
- data/lib/faraday/options/env.rb +181 -0
- data/lib/faraday/options/proxy_options.rb +28 -0
- data/lib/faraday/options/request_options.rb +22 -0
- data/lib/faraday/options/ssl_options.rb +59 -0
- data/lib/faraday/param_part.rb +53 -0
- data/lib/faraday/parameters.rb +4 -196
- data/lib/faraday/rack_builder.rb +77 -65
- data/lib/faraday/request.rb +94 -32
- data/lib/faraday/request/authorization.rb +44 -30
- data/lib/faraday/request/basic_authentication.rb +14 -7
- data/lib/faraday/request/instrumentation.rb +45 -27
- data/lib/faraday/request/multipart.rb +86 -48
- data/lib/faraday/request/retry.rb +198 -170
- data/lib/faraday/request/token_authentication.rb +15 -10
- data/lib/faraday/request/url_encoded.rb +43 -23
- data/lib/faraday/response.rb +27 -23
- data/lib/faraday/response/logger.rb +22 -69
- data/lib/faraday/response/raise_error.rb +49 -14
- data/lib/faraday/utils.rb +38 -247
- data/lib/faraday/utils/headers.rb +139 -0
- data/lib/faraday/utils/params_hash.rb +61 -0
- data/lib/faraday/version.rb +5 -0
- data/spec/external_adapters/faraday_specs_setup.rb +14 -0
- data/spec/faraday/adapter/em_http_spec.rb +47 -0
- data/spec/faraday/adapter/em_synchrony_spec.rb +16 -0
- data/spec/faraday/adapter/excon_spec.rb +49 -0
- data/spec/faraday/adapter/httpclient_spec.rb +73 -0
- data/spec/faraday/adapter/net_http_persistent_spec.rb +57 -0
- data/spec/faraday/adapter/net_http_spec.rb +64 -0
- data/spec/faraday/adapter/patron_spec.rb +18 -0
- data/spec/faraday/adapter/rack_spec.rb +8 -0
- data/spec/faraday/adapter/test_spec.rb +260 -0
- data/spec/faraday/adapter/typhoeus_spec.rb +7 -0
- data/spec/faraday/adapter_registry_spec.rb +28 -0
- data/spec/faraday/adapter_spec.rb +55 -0
- data/spec/faraday/composite_read_io_spec.rb +80 -0
- data/spec/faraday/connection_spec.rb +691 -0
- data/spec/faraday/error_spec.rb +60 -0
- data/spec/faraday/middleware_spec.rb +52 -0
- data/spec/faraday/options/env_spec.rb +70 -0
- data/spec/faraday/options/options_spec.rb +297 -0
- data/spec/faraday/options/proxy_options_spec.rb +37 -0
- data/spec/faraday/options/request_options_spec.rb +19 -0
- data/spec/faraday/params_encoders/flat_spec.rb +42 -0
- data/spec/faraday/params_encoders/nested_spec.rb +142 -0
- data/spec/faraday/rack_builder_spec.rb +345 -0
- data/spec/faraday/request/authorization_spec.rb +88 -0
- data/spec/faraday/request/instrumentation_spec.rb +76 -0
- data/spec/faraday/request/multipart_spec.rb +302 -0
- data/spec/faraday/request/retry_spec.rb +242 -0
- data/spec/faraday/request/url_encoded_spec.rb +83 -0
- data/spec/faraday/request_spec.rb +120 -0
- data/spec/faraday/response/logger_spec.rb +220 -0
- data/spec/faraday/response/middleware_spec.rb +68 -0
- data/spec/faraday/response/raise_error_spec.rb +169 -0
- data/spec/faraday/response_spec.rb +75 -0
- data/spec/faraday/utils/headers_spec.rb +82 -0
- data/spec/faraday/utils_spec.rb +56 -0
- data/spec/faraday_spec.rb +37 -0
- data/spec/spec_helper.rb +132 -0
- data/spec/support/disabling_stub.rb +14 -0
- data/spec/support/fake_safe_buffer.rb +15 -0
- data/spec/support/helper_methods.rb +133 -0
- data/spec/support/shared_examples/adapter.rb +105 -0
- data/spec/support/shared_examples/params_encoder.rb +18 -0
- data/spec/support/shared_examples/request_method.rb +262 -0
- data/spec/support/streaming_response_checker.rb +35 -0
- data/spec/support/webmock_rack_app.rb +68 -0
- metadata +109 -10
- data/lib/faraday/adapter/net_http.rb +0 -137
- data/lib/faraday/upload_io.rb +0 -67
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Faraday::Response::Middleware do
|
4
|
+
let(:conn) do
|
5
|
+
Faraday.new do |b|
|
6
|
+
b.use custom_middleware
|
7
|
+
b.adapter :test do |stub|
|
8
|
+
stub.get('ok') { [200, { 'Content-Type' => 'text/html' }, '<body></body>'] }
|
9
|
+
stub.get('not_modified') { [304, nil, nil] }
|
10
|
+
stub.get('no_content') { [204, nil, nil] }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'with a custom ResponseMiddleware' do
|
16
|
+
let(:custom_middleware) do
|
17
|
+
Class.new(Faraday::Response::Middleware) do
|
18
|
+
def parse(body)
|
19
|
+
body.upcase
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'parses the response' do
|
25
|
+
expect(conn.get('ok').body).to eq('<BODY></BODY>')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'with a custom ResponseMiddleware and private parse' do
|
30
|
+
let(:custom_middleware) do
|
31
|
+
Class.new(Faraday::Response::Middleware) do
|
32
|
+
private
|
33
|
+
|
34
|
+
def parse(body)
|
35
|
+
body.upcase
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'parses the response' do
|
41
|
+
expect(conn.get('ok').body).to eq('<BODY></BODY>')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'with a custom ResponseMiddleware but empty response' do
|
46
|
+
let(:custom_middleware) do
|
47
|
+
Class.new(Faraday::Response::Middleware) do
|
48
|
+
def parse(_body)
|
49
|
+
raise 'this should not be called'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'raises exception for 200 responses' do
|
55
|
+
expect { conn.get('ok') }.to raise_error(StandardError)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'doesn\'t call the middleware for 204 responses' do
|
59
|
+
expect_any_instance_of(custom_middleware).not_to receive(:parse)
|
60
|
+
expect(conn.get('no_content').body).to be_nil
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'doesn\'t call the middleware for 304 responses' do
|
64
|
+
expect_any_instance_of(custom_middleware).not_to receive(:parse)
|
65
|
+
expect(conn.get('not_modified').body).to be_nil
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Faraday::Response::RaiseError do
|
4
|
+
let(:conn) do
|
5
|
+
Faraday.new do |b|
|
6
|
+
b.response :raise_error
|
7
|
+
b.adapter :test do |stub|
|
8
|
+
stub.get('ok') { [200, { 'Content-Type' => 'text/html' }, '<body></body>'] }
|
9
|
+
stub.get('bad-request') { [400, { 'X-Reason' => 'because' }, 'keep looking'] }
|
10
|
+
stub.get('unauthorized') { [401, { 'X-Reason' => 'because' }, 'keep looking'] }
|
11
|
+
stub.get('forbidden') { [403, { 'X-Reason' => 'because' }, 'keep looking'] }
|
12
|
+
stub.get('not-found') { [404, { 'X-Reason' => 'because' }, 'keep looking'] }
|
13
|
+
stub.get('proxy-error') { [407, { 'X-Reason' => 'because' }, 'keep looking'] }
|
14
|
+
stub.get('conflict') { [409, { 'X-Reason' => 'because' }, 'keep looking'] }
|
15
|
+
stub.get('unprocessable-entity') { [422, { 'X-Reason' => 'because' }, 'keep looking'] }
|
16
|
+
stub.get('4xx') { [499, { 'X-Reason' => 'because' }, 'keep looking'] }
|
17
|
+
stub.get('nil-status') { [nil, { 'X-Reason' => 'nil' }, 'fail'] }
|
18
|
+
stub.get('server-error') { [500, { 'X-Error' => 'bailout' }, 'fail'] }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'raises no exception for 200 responses' do
|
24
|
+
expect { conn.get('ok') }.not_to raise_error
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'raises Faraday::BadRequestError for 400 responses' do
|
28
|
+
expect { conn.get('bad-request') }.to raise_error(Faraday::BadRequestError) do |ex|
|
29
|
+
expect(ex.message).to eq('the server responded with status 400')
|
30
|
+
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
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')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'raises Faraday::UnauthorizedError for 401 responses' do
|
39
|
+
expect { conn.get('unauthorized') }.to raise_error(Faraday::UnauthorizedError) do |ex|
|
40
|
+
expect(ex.message).to eq('the server responded with status 401')
|
41
|
+
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
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')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'raises Faraday::ForbiddenError for 403 responses' do
|
50
|
+
expect { conn.get('forbidden') }.to raise_error(Faraday::ForbiddenError) do |ex|
|
51
|
+
expect(ex.message).to eq('the server responded with status 403')
|
52
|
+
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
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')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'raises Faraday::ResourceNotFound for 404 responses' do
|
61
|
+
expect { conn.get('not-found') }.to raise_error(Faraday::ResourceNotFound) do |ex|
|
62
|
+
expect(ex.message).to eq('the server responded with status 404')
|
63
|
+
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
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')
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'raises Faraday::ProxyAuthError for 407 responses' do
|
72
|
+
expect { conn.get('proxy-error') }.to raise_error(Faraday::ProxyAuthError) do |ex|
|
73
|
+
expect(ex.message).to eq('407 "Proxy Authentication Required"')
|
74
|
+
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
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')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'raises Faraday::ConflictError for 409 responses' do
|
83
|
+
expect { conn.get('conflict') }.to raise_error(Faraday::ConflictError) do |ex|
|
84
|
+
expect(ex.message).to eq('the server responded with status 409')
|
85
|
+
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
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')
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'raises Faraday::UnprocessableEntityError for 422 responses' do
|
94
|
+
expect { conn.get('unprocessable-entity') }.to raise_error(Faraday::UnprocessableEntityError) do |ex|
|
95
|
+
expect(ex.message).to eq('the server responded with status 422')
|
96
|
+
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
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')
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'raises Faraday::NilStatusError for nil status in response' do
|
105
|
+
expect { conn.get('nil-status') }.to raise_error(Faraday::NilStatusError) do |ex|
|
106
|
+
expect(ex.message).to eq('http status could not be derived from the server response')
|
107
|
+
expect(ex.response[:headers]['X-Reason']).to eq('nil')
|
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')
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'raises Faraday::ClientError for other 4xx responses' do
|
116
|
+
expect { conn.get('4xx') }.to raise_error(Faraday::ClientError) do |ex|
|
117
|
+
expect(ex.message).to eq('the server responded with status 499')
|
118
|
+
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
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')
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'raises Faraday::ServerError for 500 responses' do
|
127
|
+
expect { conn.get('server-error') }.to raise_error(Faraday::ServerError) do |ex|
|
128
|
+
expect(ex.message).to eq('the server responded with status 500')
|
129
|
+
expect(ex.response[:headers]['X-Error']).to eq('bailout')
|
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')
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe 'request info' do
|
138
|
+
let(:conn) do
|
139
|
+
Faraday.new do |b|
|
140
|
+
b.response :raise_error
|
141
|
+
b.adapter :test do |stub|
|
142
|
+
stub.post('request?full=true', request_body, request_headers) do
|
143
|
+
[400, { 'X-Reason' => 'because' }, 'keep looking']
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
let(:request_body) { JSON.generate({ 'item' => 'sth' }) }
|
149
|
+
let(:request_headers) { { 'Authorization' => 'Basic 123' } }
|
150
|
+
|
151
|
+
subject(:perform_request) do
|
152
|
+
conn.post 'request' do |req|
|
153
|
+
req.headers['Authorization'] = 'Basic 123'
|
154
|
+
req.params[:full] = true
|
155
|
+
req.body = request_body
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'returns the request info in the exception' do
|
160
|
+
expect { perform_request }.to raise_error(Faraday::BadRequestError) do |ex|
|
161
|
+
expect(ex.response[:request][:method]).to eq(:post)
|
162
|
+
expect(ex.response[:request][:url_path]).to eq('/request')
|
163
|
+
expect(ex.response[:request][:params]).to eq({ 'full' => 'true' })
|
164
|
+
expect(ex.response[:request][:headers]).to match(a_hash_including(request_headers))
|
165
|
+
expect(ex.response[:request][:body]).to eq(request_body)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Faraday::Response do
|
4
|
+
subject { Faraday::Response.new(env) }
|
5
|
+
|
6
|
+
let(:env) do
|
7
|
+
Faraday::Env.from(status: 404, body: 'yikes',
|
8
|
+
response_headers: { 'Content-Type' => 'text/plain' })
|
9
|
+
end
|
10
|
+
|
11
|
+
it { expect(subject.finished?).to be_truthy }
|
12
|
+
it { expect { subject.finish({}) }.to raise_error(RuntimeError) }
|
13
|
+
it { expect(subject.success?).to be_falsey }
|
14
|
+
it { expect(subject.status).to eq(404) }
|
15
|
+
it { expect(subject.body).to eq('yikes') }
|
16
|
+
it { expect(subject.headers['Content-Type']).to eq('text/plain') }
|
17
|
+
it { expect(subject['content-type']).to eq('text/plain') }
|
18
|
+
|
19
|
+
describe '#apply_request' do
|
20
|
+
before { subject.apply_request(body: 'a=b', method: :post) }
|
21
|
+
|
22
|
+
it { expect(subject.body).to eq('yikes') }
|
23
|
+
it { expect(subject.env[:method]).to eq(:post) }
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#to_hash' do
|
27
|
+
let(:hash) { subject.to_hash }
|
28
|
+
|
29
|
+
it { expect(hash).to be_a(Hash) }
|
30
|
+
it { expect(hash[:status]).to eq(subject.status) }
|
31
|
+
it { expect(hash[:response_headers]).to eq(subject.headers) }
|
32
|
+
it { expect(hash[:body]).to eq(subject.body) }
|
33
|
+
end
|
34
|
+
|
35
|
+
describe 'marshal serialization support' do
|
36
|
+
subject { Faraday::Response.new }
|
37
|
+
let(:loaded) { Marshal.load(Marshal.dump(subject)) }
|
38
|
+
|
39
|
+
before do
|
40
|
+
subject.on_complete {}
|
41
|
+
subject.finish(env.merge(params: 'moo'))
|
42
|
+
end
|
43
|
+
|
44
|
+
it { expect(loaded.env[:params]).to be_nil }
|
45
|
+
it { expect(loaded.env[:body]).to eq(env[:body]) }
|
46
|
+
it { expect(loaded.env[:response_headers]).to eq(env[:response_headers]) }
|
47
|
+
it { expect(loaded.env[:status]).to eq(env[:status]) }
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#on_complete' do
|
51
|
+
subject { Faraday::Response.new }
|
52
|
+
|
53
|
+
it 'parse body on finish' do
|
54
|
+
subject.on_complete { |env| env[:body] = env[:body].upcase }
|
55
|
+
subject.finish(env)
|
56
|
+
|
57
|
+
expect(subject.body).to eq('YIKES')
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'can access response body in on_complete callback' do
|
61
|
+
subject.on_complete { |env| env[:body] = subject.body.upcase }
|
62
|
+
subject.finish(env)
|
63
|
+
|
64
|
+
expect(subject.body).to eq('YIKES')
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'can access response body in on_complete callback' do
|
68
|
+
callback_env = nil
|
69
|
+
subject.on_complete { |env| callback_env = env }
|
70
|
+
subject.finish({})
|
71
|
+
|
72
|
+
expect(subject.env).to eq(callback_env)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Faraday::Utils::Headers do
|
4
|
+
subject { Faraday::Utils::Headers.new }
|
5
|
+
|
6
|
+
context 'when Content-Type is set to application/json' do
|
7
|
+
before { subject['Content-Type'] = 'application/json' }
|
8
|
+
|
9
|
+
it { expect(subject.keys).to eq(['Content-Type']) }
|
10
|
+
it { expect(subject['Content-Type']).to eq('application/json') }
|
11
|
+
it { expect(subject['CONTENT-TYPE']).to eq('application/json') }
|
12
|
+
it { expect(subject['content-type']).to eq('application/json') }
|
13
|
+
it { is_expected.to include('content-type') }
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when Content-Type is set to application/xml' do
|
17
|
+
before { subject['Content-Type'] = 'application/xml' }
|
18
|
+
|
19
|
+
it { expect(subject.keys).to eq(['Content-Type']) }
|
20
|
+
it { expect(subject['Content-Type']).to eq('application/xml') }
|
21
|
+
it { expect(subject['CONTENT-TYPE']).to eq('application/xml') }
|
22
|
+
it { expect(subject['content-type']).to eq('application/xml') }
|
23
|
+
it { is_expected.to include('content-type') }
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#fetch' do
|
27
|
+
before { subject['Content-Type'] = 'application/json' }
|
28
|
+
|
29
|
+
it { expect(subject.fetch('Content-Type')).to eq('application/json') }
|
30
|
+
it { expect(subject.fetch('CONTENT-TYPE')).to eq('application/json') }
|
31
|
+
it { expect(subject.fetch(:content_type)).to eq('application/json') }
|
32
|
+
it { expect(subject.fetch('invalid', 'default')).to eq('default') }
|
33
|
+
it { expect(subject.fetch('invalid', false)).to eq(false) }
|
34
|
+
it { expect(subject.fetch('invalid', nil)).to be_nil }
|
35
|
+
it { expect(subject.fetch('Invalid') { |key| "#{key} key" }).to eq('Invalid key') }
|
36
|
+
it 'calls a block when provided' do
|
37
|
+
block_called = false
|
38
|
+
expect(subject.fetch('content-type') { block_called = true }).to eq('application/json')
|
39
|
+
expect(block_called).to be_falsey
|
40
|
+
end
|
41
|
+
it 'raises an error if key not found' do
|
42
|
+
expected_error = defined?(KeyError) ? KeyError : IndexError
|
43
|
+
expect { subject.fetch('invalid') }.to raise_error(expected_error)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#delete' do
|
48
|
+
before do
|
49
|
+
subject['Content-Type'] = 'application/json'
|
50
|
+
@deleted = subject.delete('content-type')
|
51
|
+
end
|
52
|
+
|
53
|
+
it { expect(@deleted).to eq('application/json') }
|
54
|
+
it { expect(subject.size).to eq(0) }
|
55
|
+
it { is_expected.not_to include('content-type') }
|
56
|
+
it { expect(subject.delete('content-type')).to be_nil }
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '#parse' do
|
60
|
+
before { subject.parse(headers) }
|
61
|
+
|
62
|
+
context 'when response headers leave http status line out' do
|
63
|
+
let(:headers) { "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n" }
|
64
|
+
|
65
|
+
it { expect(subject.keys).to eq(%w[Content-Type]) }
|
66
|
+
it { expect(subject['Content-Type']).to eq('text/html') }
|
67
|
+
it { expect(subject['content-type']).to eq('text/html') }
|
68
|
+
end
|
69
|
+
|
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://sushi.com/\r\n\r\n" }
|
72
|
+
|
73
|
+
it { expect(subject['location']).to eq('http://sushi.com/') }
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'when response headers include a blank line' do
|
77
|
+
let(:headers) { "HTTP/1.1 200 OK\r\n\r\nContent-Type: text/html\r\n\r\n" }
|
78
|
+
|
79
|
+
it { expect(subject['content-type']).to eq('text/html') }
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Faraday::Utils do
|
4
|
+
describe 'headers parsing' do
|
5
|
+
let(:multi_response_headers) do
|
6
|
+
"HTTP/1.x 500 OK\r\nContent-Type: text/html; charset=UTF-8\r\n" \
|
7
|
+
"HTTP/1.x 200 OK\r\nContent-Type: application/json; charset=UTF-8\r\n\r\n"
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'parse headers for aggregated responses' do
|
11
|
+
headers = Faraday::Utils::Headers.new
|
12
|
+
headers.parse(multi_response_headers)
|
13
|
+
|
14
|
+
result = headers.to_hash
|
15
|
+
|
16
|
+
expect(result['Content-Type']).to eq('application/json; charset=UTF-8')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'URI parsing' do
|
21
|
+
let(:url) { 'http://example.com/abc' }
|
22
|
+
|
23
|
+
it 'escapes safe buffer' do
|
24
|
+
str = FakeSafeBuffer.new('$32,000.00')
|
25
|
+
expect(Faraday::Utils.escape(str)).to eq('%2432%2C000.00')
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'parses with default parser' do
|
29
|
+
with_default_uri_parser(nil) do
|
30
|
+
uri = normalize(url)
|
31
|
+
expect(uri.host).to eq('example.com')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'parses with URI' do
|
36
|
+
with_default_uri_parser(::URI) do
|
37
|
+
uri = normalize(url)
|
38
|
+
expect(uri.host).to eq('example.com')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'parses with block' do
|
43
|
+
with_default_uri_parser(->(u) { "booya#{'!' * u.size}" }) do
|
44
|
+
expect(normalize(url)).to eq('booya!!!!!!!!!!!!!!!!!!!!!!')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'replaces headers hash' do
|
49
|
+
headers = Faraday::Utils::Headers.new('authorization' => 't0ps3cr3t!')
|
50
|
+
expect(headers).to have_key('authorization')
|
51
|
+
|
52
|
+
headers.replace('content-type' => 'text/plain')
|
53
|
+
expect(headers).not_to have_key('authorization')
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|