faraday 1.10.6 → 2.0.0.alpha.pre.1
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 +111 -1
- data/README.md +16 -9
- data/examples/client_test.rb +1 -1
- data/lib/faraday/adapter/test.rb +2 -0
- data/lib/faraday/adapter.rb +0 -5
- data/lib/faraday/connection.rb +3 -86
- data/lib/faraday/encoders/nested_params_encoder.rb +3 -12
- data/lib/faraday/error.rb +7 -0
- data/lib/faraday/file_part.rb +122 -0
- data/lib/faraday/logging/formatter.rb +1 -0
- data/lib/faraday/middleware.rb +0 -1
- data/lib/faraday/middleware_registry.rb +15 -79
- data/lib/faraday/options.rb +3 -3
- data/lib/faraday/param_part.rb +53 -0
- data/lib/faraday/rack_builder.rb +1 -1
- data/lib/faraday/request/authorization.rb +26 -40
- data/lib/faraday/request/instrumentation.rb +2 -0
- data/lib/faraday/request/multipart.rb +108 -0
- data/lib/faraday/request/retry.rb +241 -0
- data/lib/faraday/request/url_encoded.rb +2 -0
- data/lib/faraday/request.rb +8 -24
- data/lib/faraday/response/json.rb +4 -4
- data/lib/faraday/response/logger.rb +2 -0
- data/lib/faraday/response/raise_error.rb +9 -1
- data/lib/faraday/response.rb +7 -20
- data/lib/faraday/utils/headers.rb +1 -1
- data/lib/faraday/utils.rb +9 -4
- data/lib/faraday/version.rb +1 -1
- data/lib/faraday.rb +6 -45
- data/spec/faraday/connection_spec.rb +78 -97
- data/spec/faraday/options/env_spec.rb +2 -2
- data/spec/faraday/params_encoders/nested_spec.rb +0 -30
- data/spec/faraday/rack_builder_spec.rb +5 -43
- data/spec/faraday/request/authorization_spec.rb +14 -36
- data/spec/faraday/request/instrumentation_spec.rb +5 -7
- data/spec/faraday/request/multipart_spec.rb +302 -0
- data/spec/faraday/request/retry_spec.rb +254 -0
- data/spec/faraday/request_spec.rb +0 -11
- data/spec/faraday/response/json_spec.rb +4 -6
- data/spec/faraday/response/raise_error_spec.rb +7 -4
- data/spec/faraday/utils_spec.rb +1 -1
- data/spec/faraday_spec.rb +4 -8
- data/spec/spec_helper.rb +0 -2
- data/spec/support/fake_safe_buffer.rb +1 -1
- data/spec/support/shared_examples/request_method.rb +5 -5
- metadata +25 -156
- data/lib/faraday/adapter/typhoeus.rb +0 -15
- data/lib/faraday/autoload.rb +0 -89
- data/lib/faraday/dependency_loader.rb +0 -39
- data/lib/faraday/deprecate.rb +0 -110
- data/lib/faraday/request/basic_authentication.rb +0 -20
- data/lib/faraday/request/token_authentication.rb +0 -20
- data/spec/faraday/adapter/em_http_spec.rb +0 -49
- data/spec/faraday/adapter/em_synchrony_spec.rb +0 -18
- data/spec/faraday/adapter/excon_spec.rb +0 -49
- data/spec/faraday/adapter/httpclient_spec.rb +0 -73
- 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/deprecate_spec.rb +0 -147
- data/spec/faraday/response/middleware_spec.rb +0 -68
- data/spec/support/webmock_rack_app.rb +0 -68
|
@@ -12,13 +12,11 @@ RSpec.describe Faraday::RackBuilder do
|
|
|
12
12
|
|
|
13
13
|
class Apple < Handler
|
|
14
14
|
end
|
|
15
|
+
|
|
15
16
|
class Orange < Handler
|
|
16
17
|
end
|
|
17
|
-
class Banana < Handler
|
|
18
|
-
end
|
|
19
18
|
|
|
20
|
-
class
|
|
21
|
-
dependency 'zomg/i_dont/exist'
|
|
19
|
+
class Banana < Handler
|
|
22
20
|
end
|
|
23
21
|
|
|
24
22
|
subject { conn.builder }
|
|
@@ -127,24 +125,6 @@ RSpec.describe Faraday::RackBuilder do
|
|
|
127
125
|
subject.use(:apple)
|
|
128
126
|
expect(subject.handlers).to eq([Apple])
|
|
129
127
|
end
|
|
130
|
-
|
|
131
|
-
it 'allows to register with symbol' do
|
|
132
|
-
Faraday::Middleware.register_middleware(apple: :Apple)
|
|
133
|
-
subject.use(:apple)
|
|
134
|
-
expect(subject.handlers).to eq([Apple])
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
it 'allows to register with string' do
|
|
138
|
-
Faraday::Middleware.register_middleware(apple: 'Apple')
|
|
139
|
-
subject.use(:apple)
|
|
140
|
-
expect(subject.handlers).to eq([Apple])
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
it 'allows to register with Proc' do
|
|
144
|
-
Faraday::Middleware.register_middleware(apple: -> { Apple })
|
|
145
|
-
subject.use(:apple)
|
|
146
|
-
expect(subject.handlers).to eq([Apple])
|
|
147
|
-
end
|
|
148
128
|
end
|
|
149
129
|
|
|
150
130
|
context 'when having two handlers' do
|
|
@@ -176,24 +156,6 @@ RSpec.describe Faraday::RackBuilder do
|
|
|
176
156
|
end
|
|
177
157
|
end
|
|
178
158
|
|
|
179
|
-
context 'when having a handler with broken dependency' do
|
|
180
|
-
let(:conn) do
|
|
181
|
-
Faraday::Connection.new do |builder|
|
|
182
|
-
builder.adapter :test do |stub|
|
|
183
|
-
stub.get('/') { |_| [200, {}, ''] }
|
|
184
|
-
end
|
|
185
|
-
end
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
before { subject.use(Broken) }
|
|
189
|
-
|
|
190
|
-
it 'raises an error while making a request' do
|
|
191
|
-
expect { conn.get('/') }.to raise_error(RuntimeError) do |err|
|
|
192
|
-
expect(err.message).to match(%r{missing dependency for Broken: .+ -- zomg/i_dont/exist})
|
|
193
|
-
end
|
|
194
|
-
end
|
|
195
|
-
end
|
|
196
|
-
|
|
197
159
|
context 'when middleware is added with named arguments' do
|
|
198
160
|
let(:conn) { Faraday::Connection.new {} }
|
|
199
161
|
|
|
@@ -220,7 +182,7 @@ RSpec.describe Faraday::RackBuilder do
|
|
|
220
182
|
end
|
|
221
183
|
end
|
|
222
184
|
|
|
223
|
-
context 'when a
|
|
185
|
+
context 'when a middleware is added with named arguments' do
|
|
224
186
|
let(:conn) { Faraday::Connection.new {} }
|
|
225
187
|
|
|
226
188
|
let(:cat_request) do
|
|
@@ -247,11 +209,11 @@ RSpec.describe Faraday::RackBuilder do
|
|
|
247
209
|
end
|
|
248
210
|
end
|
|
249
211
|
|
|
250
|
-
context 'when a
|
|
212
|
+
context 'when a middleware is added with named arguments' do
|
|
251
213
|
let(:conn) { Faraday::Connection.new {} }
|
|
252
214
|
|
|
253
215
|
let(:fish_response) do
|
|
254
|
-
Class.new(Faraday::
|
|
216
|
+
Class.new(Faraday::Middleware) do
|
|
255
217
|
attr_accessor :name
|
|
256
218
|
|
|
257
219
|
def initialize(app, name:)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
RSpec.describe Faraday::Request::Authorization do
|
|
4
4
|
let(:conn) do
|
|
5
5
|
Faraday.new do |b|
|
|
6
|
-
b.request auth_type, *auth_config
|
|
6
|
+
b.request :authorization, auth_type, *auth_config
|
|
7
7
|
b.adapter :test do |stub|
|
|
8
8
|
stub.get('/auth-echo') do |env|
|
|
9
9
|
[200, {}, env[:request_headers]['Authorization']]
|
|
@@ -14,10 +14,10 @@ RSpec.describe Faraday::Request::Authorization do
|
|
|
14
14
|
|
|
15
15
|
shared_examples 'does not interfere with existing authentication' do
|
|
16
16
|
context 'and request already has an authentication header' do
|
|
17
|
-
let(:response) { conn.get('/auth-echo', nil, authorization: '
|
|
17
|
+
let(:response) { conn.get('/auth-echo', nil, authorization: 'OAuth oauth_token') }
|
|
18
18
|
|
|
19
19
|
it 'does not interfere with existing authorization' do
|
|
20
|
-
expect(response.body).to eq('
|
|
20
|
+
expect(response.body).to eq('OAuth oauth_token')
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
end
|
|
@@ -25,7 +25,7 @@ RSpec.describe Faraday::Request::Authorization do
|
|
|
25
25
|
let(:response) { conn.get('/auth-echo') }
|
|
26
26
|
|
|
27
27
|
describe 'basic_auth' do
|
|
28
|
-
let(:auth_type) { :
|
|
28
|
+
let(:auth_type) { :basic }
|
|
29
29
|
|
|
30
30
|
context 'when passed correct params' do
|
|
31
31
|
let(:auth_config) { %w[aladdin opensesame] }
|
|
@@ -44,51 +44,29 @@ RSpec.describe Faraday::Request::Authorization do
|
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
describe 'token_auth' do
|
|
48
|
-
let(:auth_type) { :token_auth }
|
|
49
|
-
|
|
50
|
-
context 'when passed correct params' do
|
|
51
|
-
let(:auth_config) { 'quux' }
|
|
52
|
-
|
|
53
|
-
it { expect(response.body).to eq('Token token="quux"') }
|
|
54
|
-
|
|
55
|
-
include_examples 'does not interfere with existing authentication'
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
context 'when other values are provided' do
|
|
59
|
-
let(:auth_config) { ['baz', { foo: 42 }] }
|
|
60
|
-
|
|
61
|
-
it { expect(response.body).to match(/^Token /) }
|
|
62
|
-
it { expect(response.body).to match(/token="baz"/) }
|
|
63
|
-
it { expect(response.body).to match(/foo="42"/) }
|
|
64
|
-
|
|
65
|
-
include_examples 'does not interfere with existing authentication'
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
47
|
describe 'authorization' do
|
|
70
|
-
let(:auth_type) { :
|
|
48
|
+
let(:auth_type) { :Bearer }
|
|
71
49
|
|
|
72
|
-
context 'when passed
|
|
73
|
-
let(:auth_config) { ['custom'
|
|
50
|
+
context 'when passed a string' do
|
|
51
|
+
let(:auth_config) { ['custom'] }
|
|
74
52
|
|
|
75
|
-
it { expect(response.body).to eq('custom
|
|
53
|
+
it { expect(response.body).to eq('Bearer custom') }
|
|
76
54
|
|
|
77
55
|
include_examples 'does not interfere with existing authentication'
|
|
78
56
|
end
|
|
79
57
|
|
|
80
|
-
context 'when passed a
|
|
81
|
-
let(:auth_config) { [
|
|
58
|
+
context 'when passed a proc' do
|
|
59
|
+
let(:auth_config) { [-> { 'custom_from_proc' }] }
|
|
82
60
|
|
|
83
|
-
it { expect(response.body).to eq('
|
|
61
|
+
it { expect(response.body).to eq('Bearer custom_from_proc') }
|
|
84
62
|
|
|
85
63
|
include_examples 'does not interfere with existing authentication'
|
|
86
64
|
end
|
|
87
65
|
|
|
88
|
-
context 'when passed
|
|
89
|
-
let(:auth_config) { [
|
|
66
|
+
context 'when passed too many arguments' do
|
|
67
|
+
let(:auth_config) { %w[baz foo] }
|
|
90
68
|
|
|
91
|
-
it { expect
|
|
69
|
+
it { expect { response }.to raise_error(ArgumentError) }
|
|
92
70
|
|
|
93
71
|
include_examples 'does not interfere with existing authentication'
|
|
94
72
|
end
|
|
@@ -30,13 +30,11 @@ RSpec.describe Faraday::Request::Instrumentation do
|
|
|
30
30
|
|
|
31
31
|
it { expect(options.name).to eq('request.faraday') }
|
|
32
32
|
it 'defaults to ActiveSupport::Notifications' do
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
expect(res).to eq(ActiveSupport::Notifications)
|
|
39
|
-
end
|
|
33
|
+
res = options.instrumenter
|
|
34
|
+
rescue NameError => e
|
|
35
|
+
expect(e.to_s).to match('ActiveSupport')
|
|
36
|
+
else
|
|
37
|
+
expect(res).to eq(ActiveSupport::Notifications)
|
|
40
38
|
end
|
|
41
39
|
|
|
42
40
|
it 'instruments with default name' do
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe Faraday::Request::Multipart do
|
|
4
|
+
let(:options) { {} }
|
|
5
|
+
let(:conn) do
|
|
6
|
+
Faraday.new do |b|
|
|
7
|
+
b.request :multipart, options
|
|
8
|
+
b.request :url_encoded
|
|
9
|
+
b.adapter :test do |stub|
|
|
10
|
+
stub.post('/echo') do |env|
|
|
11
|
+
posted_as = env[:request_headers]['Content-Type']
|
|
12
|
+
expect(env[:body]).to be_a_kind_of(Faraday::CompositeReadIO)
|
|
13
|
+
[200, { 'Content-Type' => posted_as }, env[:body].read]
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
shared_examples 'a multipart request' do
|
|
20
|
+
it 'generates a unique boundary for each request' do
|
|
21
|
+
response1 = conn.post('/echo', payload)
|
|
22
|
+
response2 = conn.post('/echo', payload)
|
|
23
|
+
|
|
24
|
+
b1 = parse_multipart_boundary(response1.headers['Content-Type'])
|
|
25
|
+
b2 = parse_multipart_boundary(response2.headers['Content-Type'])
|
|
26
|
+
expect(b1).to_not eq(b2)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
context 'FilePart: when multipart objects in param' do
|
|
31
|
+
let(:payload) do
|
|
32
|
+
{
|
|
33
|
+
a: 1,
|
|
34
|
+
b: {
|
|
35
|
+
c: Faraday::FilePart.new(__FILE__, 'text/x-ruby', nil,
|
|
36
|
+
'Content-Disposition' => 'form-data; foo=1'),
|
|
37
|
+
d: 2
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
end
|
|
41
|
+
it_behaves_like 'a multipart request'
|
|
42
|
+
|
|
43
|
+
it 'forms a multipart request' do
|
|
44
|
+
response = conn.post('/echo', payload)
|
|
45
|
+
|
|
46
|
+
boundary = parse_multipart_boundary(response.headers['Content-Type'])
|
|
47
|
+
result = parse_multipart(boundary, response.body)
|
|
48
|
+
expect(result[:errors]).to be_empty
|
|
49
|
+
|
|
50
|
+
part_a, body_a = result.part('a')
|
|
51
|
+
expect(part_a).to_not be_nil
|
|
52
|
+
expect(part_a.filename).to be_nil
|
|
53
|
+
expect(body_a).to eq('1')
|
|
54
|
+
|
|
55
|
+
part_bc, body_bc = result.part('b[c]')
|
|
56
|
+
expect(part_bc).to_not be_nil
|
|
57
|
+
expect(part_bc.filename).to eq('multipart_spec.rb')
|
|
58
|
+
expect(part_bc.headers['content-disposition'])
|
|
59
|
+
.to eq(
|
|
60
|
+
'form-data; foo=1; name="b[c]"; filename="multipart_spec.rb"'
|
|
61
|
+
)
|
|
62
|
+
expect(part_bc.headers['content-type']).to eq('text/x-ruby')
|
|
63
|
+
expect(part_bc.headers['content-transfer-encoding']).to eq('binary')
|
|
64
|
+
expect(body_bc).to eq(File.read(__FILE__))
|
|
65
|
+
|
|
66
|
+
part_bd, body_bd = result.part('b[d]')
|
|
67
|
+
expect(part_bd).to_not be_nil
|
|
68
|
+
expect(part_bd.filename).to be_nil
|
|
69
|
+
expect(body_bd).to eq('2')
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
context 'FilePart: when providing json and IO content in the same payload' do
|
|
74
|
+
let(:io) { StringIO.new('io-content') }
|
|
75
|
+
let(:json) do
|
|
76
|
+
{
|
|
77
|
+
b: 1,
|
|
78
|
+
c: 2
|
|
79
|
+
}.to_json
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
let(:payload) do
|
|
83
|
+
{
|
|
84
|
+
json: Faraday::ParamPart.new(json, 'application/json'),
|
|
85
|
+
io: Faraday::FilePart.new(io, 'application/pdf')
|
|
86
|
+
}
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it_behaves_like 'a multipart request'
|
|
90
|
+
|
|
91
|
+
it 'forms a multipart request' do
|
|
92
|
+
response = conn.post('/echo', payload)
|
|
93
|
+
|
|
94
|
+
boundary = parse_multipart_boundary(response.headers['Content-Type'])
|
|
95
|
+
result = parse_multipart(boundary, response.body)
|
|
96
|
+
expect(result[:errors]).to be_empty
|
|
97
|
+
|
|
98
|
+
part_json, body_json = result.part('json')
|
|
99
|
+
expect(part_json).to_not be_nil
|
|
100
|
+
expect(part_json.mime).to eq('application/json')
|
|
101
|
+
expect(part_json.filename).to be_nil
|
|
102
|
+
expect(body_json).to eq(json)
|
|
103
|
+
|
|
104
|
+
part_io, body_io = result.part('io')
|
|
105
|
+
expect(part_io).to_not be_nil
|
|
106
|
+
expect(part_io.mime).to eq('application/pdf')
|
|
107
|
+
expect(part_io.filename).to eq('local.path')
|
|
108
|
+
expect(body_io).to eq(io.string)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
context 'FilePart: when multipart objects in array param' do
|
|
113
|
+
let(:payload) do
|
|
114
|
+
{
|
|
115
|
+
a: 1,
|
|
116
|
+
b: [{
|
|
117
|
+
c: Faraday::FilePart.new(__FILE__, 'text/x-ruby'),
|
|
118
|
+
d: 2
|
|
119
|
+
}]
|
|
120
|
+
}
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it_behaves_like 'a multipart request'
|
|
124
|
+
|
|
125
|
+
it 'forms a multipart request' do
|
|
126
|
+
response = conn.post('/echo', payload)
|
|
127
|
+
|
|
128
|
+
boundary = parse_multipart_boundary(response.headers['Content-Type'])
|
|
129
|
+
result = parse_multipart(boundary, response.body)
|
|
130
|
+
expect(result[:errors]).to be_empty
|
|
131
|
+
|
|
132
|
+
part_a, body_a = result.part('a')
|
|
133
|
+
expect(part_a).to_not be_nil
|
|
134
|
+
expect(part_a.filename).to be_nil
|
|
135
|
+
expect(body_a).to eq('1')
|
|
136
|
+
|
|
137
|
+
part_bc, body_bc = result.part('b[][c]')
|
|
138
|
+
expect(part_bc).to_not be_nil
|
|
139
|
+
expect(part_bc.filename).to eq('multipart_spec.rb')
|
|
140
|
+
expect(part_bc.headers['content-disposition'])
|
|
141
|
+
.to eq(
|
|
142
|
+
'form-data; name="b[][c]"; filename="multipart_spec.rb"'
|
|
143
|
+
)
|
|
144
|
+
expect(part_bc.headers['content-type']).to eq('text/x-ruby')
|
|
145
|
+
expect(part_bc.headers['content-transfer-encoding']).to eq('binary')
|
|
146
|
+
expect(body_bc).to eq(File.read(__FILE__))
|
|
147
|
+
|
|
148
|
+
part_bd, body_bd = result.part('b[][d]')
|
|
149
|
+
expect(part_bd).to_not be_nil
|
|
150
|
+
expect(part_bd.filename).to be_nil
|
|
151
|
+
expect(body_bd).to eq('2')
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
context 'UploadIO: when multipart objects in param' do
|
|
156
|
+
let(:payload) do
|
|
157
|
+
{
|
|
158
|
+
a: 1,
|
|
159
|
+
b: {
|
|
160
|
+
c: Faraday::FilePart.new(__FILE__, 'text/x-ruby', nil,
|
|
161
|
+
'Content-Disposition' => 'form-data; foo=1'),
|
|
162
|
+
d: 2
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
end
|
|
166
|
+
it_behaves_like 'a multipart request'
|
|
167
|
+
|
|
168
|
+
it 'forms a multipart request' do
|
|
169
|
+
response = conn.post('/echo', payload)
|
|
170
|
+
|
|
171
|
+
boundary = parse_multipart_boundary(response.headers['Content-Type'])
|
|
172
|
+
result = parse_multipart(boundary, response.body)
|
|
173
|
+
expect(result[:errors]).to be_empty
|
|
174
|
+
|
|
175
|
+
part_a, body_a = result.part('a')
|
|
176
|
+
expect(part_a).to_not be_nil
|
|
177
|
+
expect(part_a.filename).to be_nil
|
|
178
|
+
expect(body_a).to eq('1')
|
|
179
|
+
|
|
180
|
+
part_bc, body_bc = result.part('b[c]')
|
|
181
|
+
expect(part_bc).to_not be_nil
|
|
182
|
+
expect(part_bc.filename).to eq('multipart_spec.rb')
|
|
183
|
+
expect(part_bc.headers['content-disposition'])
|
|
184
|
+
.to eq(
|
|
185
|
+
'form-data; foo=1; name="b[c]"; filename="multipart_spec.rb"'
|
|
186
|
+
)
|
|
187
|
+
expect(part_bc.headers['content-type']).to eq('text/x-ruby')
|
|
188
|
+
expect(part_bc.headers['content-transfer-encoding']).to eq('binary')
|
|
189
|
+
expect(body_bc).to eq(File.read(__FILE__))
|
|
190
|
+
|
|
191
|
+
part_bd, body_bd = result.part('b[d]')
|
|
192
|
+
expect(part_bd).to_not be_nil
|
|
193
|
+
expect(part_bd.filename).to be_nil
|
|
194
|
+
expect(body_bd).to eq('2')
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
context 'UploadIO: when providing json and IO content in the same payload' do
|
|
199
|
+
let(:io) { StringIO.new('io-content') }
|
|
200
|
+
let(:json) do
|
|
201
|
+
{
|
|
202
|
+
b: 1,
|
|
203
|
+
c: 2
|
|
204
|
+
}.to_json
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
let(:payload) do
|
|
208
|
+
{
|
|
209
|
+
json: Faraday::ParamPart.new(json, 'application/json'),
|
|
210
|
+
io: Faraday::FilePart.new(io, 'application/pdf')
|
|
211
|
+
}
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
it_behaves_like 'a multipart request'
|
|
215
|
+
|
|
216
|
+
it 'forms a multipart request' do
|
|
217
|
+
response = conn.post('/echo', payload)
|
|
218
|
+
|
|
219
|
+
boundary = parse_multipart_boundary(response.headers['Content-Type'])
|
|
220
|
+
result = parse_multipart(boundary, response.body)
|
|
221
|
+
expect(result[:errors]).to be_empty
|
|
222
|
+
|
|
223
|
+
part_json, body_json = result.part('json')
|
|
224
|
+
expect(part_json).to_not be_nil
|
|
225
|
+
expect(part_json.mime).to eq('application/json')
|
|
226
|
+
expect(part_json.filename).to be_nil
|
|
227
|
+
expect(body_json).to eq(json)
|
|
228
|
+
|
|
229
|
+
part_io, body_io = result.part('io')
|
|
230
|
+
expect(part_io).to_not be_nil
|
|
231
|
+
expect(part_io.mime).to eq('application/pdf')
|
|
232
|
+
expect(part_io.filename).to eq('local.path')
|
|
233
|
+
expect(body_io).to eq(io.string)
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
context 'UploadIO: when multipart objects in array param' do
|
|
238
|
+
let(:payload) do
|
|
239
|
+
{
|
|
240
|
+
a: 1,
|
|
241
|
+
b: [{
|
|
242
|
+
c: Faraday::FilePart.new(__FILE__, 'text/x-ruby'),
|
|
243
|
+
d: 2
|
|
244
|
+
}]
|
|
245
|
+
}
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
it_behaves_like 'a multipart request'
|
|
249
|
+
|
|
250
|
+
it 'forms a multipart request' do
|
|
251
|
+
response = conn.post('/echo', payload)
|
|
252
|
+
|
|
253
|
+
boundary = parse_multipart_boundary(response.headers['Content-Type'])
|
|
254
|
+
result = parse_multipart(boundary, response.body)
|
|
255
|
+
expect(result[:errors]).to be_empty
|
|
256
|
+
|
|
257
|
+
part_a, body_a = result.part('a')
|
|
258
|
+
expect(part_a).to_not be_nil
|
|
259
|
+
expect(part_a.filename).to be_nil
|
|
260
|
+
expect(body_a).to eq('1')
|
|
261
|
+
|
|
262
|
+
part_bc, body_bc = result.part('b[][c]')
|
|
263
|
+
expect(part_bc).to_not be_nil
|
|
264
|
+
expect(part_bc.filename).to eq('multipart_spec.rb')
|
|
265
|
+
expect(part_bc.headers['content-disposition'])
|
|
266
|
+
.to eq(
|
|
267
|
+
'form-data; name="b[][c]"; filename="multipart_spec.rb"'
|
|
268
|
+
)
|
|
269
|
+
expect(part_bc.headers['content-type']).to eq('text/x-ruby')
|
|
270
|
+
expect(part_bc.headers['content-transfer-encoding']).to eq('binary')
|
|
271
|
+
expect(body_bc).to eq(File.read(__FILE__))
|
|
272
|
+
|
|
273
|
+
part_bd, body_bd = result.part('b[][d]')
|
|
274
|
+
expect(part_bd).to_not be_nil
|
|
275
|
+
expect(part_bd.filename).to be_nil
|
|
276
|
+
expect(body_bd).to eq('2')
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
context 'when passing flat_encode=true option' do
|
|
281
|
+
let(:options) { { flat_encode: true } }
|
|
282
|
+
let(:io) { StringIO.new('io-content') }
|
|
283
|
+
let(:payload) do
|
|
284
|
+
{
|
|
285
|
+
a: 1,
|
|
286
|
+
b: [
|
|
287
|
+
Faraday::FilePart.new(io, 'application/pdf'),
|
|
288
|
+
Faraday::FilePart.new(io, 'application/pdf')
|
|
289
|
+
]
|
|
290
|
+
}
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
it_behaves_like 'a multipart request'
|
|
294
|
+
|
|
295
|
+
it 'encode params using flat encoder' do
|
|
296
|
+
response = conn.post('/echo', payload)
|
|
297
|
+
|
|
298
|
+
expect(response.body).to include('name="b"')
|
|
299
|
+
expect(response.body).not_to include('name="b[]"')
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
end
|