faraday 1.8.0 → 2.0.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.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +117 -1
  3. data/README.md +16 -9
  4. data/examples/client_spec.rb +1 -1
  5. data/examples/client_test.rb +2 -2
  6. data/lib/faraday/adapter/test.rb +2 -0
  7. data/lib/faraday/adapter.rb +2 -5
  8. data/lib/faraday/connection.rb +5 -86
  9. data/lib/faraday/encoders/nested_params_encoder.rb +2 -2
  10. data/lib/faraday/error.rb +3 -8
  11. data/lib/faraday/logging/formatter.rb +1 -0
  12. data/lib/faraday/middleware.rb +0 -1
  13. data/lib/faraday/middleware_registry.rb +15 -79
  14. data/lib/faraday/options.rb +3 -3
  15. data/lib/faraday/rack_builder.rb +21 -18
  16. data/lib/faraday/request/authorization.rb +28 -41
  17. data/lib/faraday/request/instrumentation.rb +2 -0
  18. data/lib/faraday/request/json.rb +55 -0
  19. data/lib/faraday/request/url_encoded.rb +2 -0
  20. data/lib/faraday/request.rb +11 -31
  21. data/lib/faraday/response/json.rb +54 -0
  22. data/lib/faraday/response/logger.rb +4 -4
  23. data/lib/faraday/response/raise_error.rb +9 -1
  24. data/lib/faraday/response.rb +8 -19
  25. data/lib/faraday/utils/headers.rb +1 -1
  26. data/lib/faraday/utils.rb +10 -5
  27. data/lib/faraday/version.rb +1 -1
  28. data/lib/faraday.rb +6 -40
  29. data/spec/faraday/connection_spec.rb +102 -51
  30. data/spec/faraday/options/env_spec.rb +2 -2
  31. data/spec/faraday/rack_builder_spec.rb +7 -50
  32. data/spec/faraday/request/authorization_spec.rb +19 -32
  33. data/spec/faraday/request/instrumentation_spec.rb +5 -7
  34. data/spec/faraday/request/json_spec.rb +111 -0
  35. data/spec/faraday/request/url_encoded_spec.rb +0 -1
  36. data/spec/faraday/request_spec.rb +0 -11
  37. data/spec/faraday/response/json_spec.rb +117 -0
  38. data/spec/faraday/response/raise_error_spec.rb +7 -4
  39. data/spec/faraday/utils_spec.rb +62 -1
  40. data/spec/support/fake_safe_buffer.rb +1 -1
  41. data/spec/support/helper_methods.rb +0 -37
  42. data/spec/support/shared_examples/adapter.rb +0 -1
  43. data/spec/support/shared_examples/request_method.rb +5 -18
  44. metadata +9 -159
  45. data/lib/faraday/adapter/typhoeus.rb +0 -15
  46. data/lib/faraday/autoload.rb +0 -87
  47. data/lib/faraday/dependency_loader.rb +0 -37
  48. data/lib/faraday/file_part.rb +0 -128
  49. data/lib/faraday/param_part.rb +0 -53
  50. data/lib/faraday/request/basic_authentication.rb +0 -20
  51. data/lib/faraday/request/multipart.rb +0 -106
  52. data/lib/faraday/request/retry.rb +0 -239
  53. data/lib/faraday/request/token_authentication.rb +0 -20
  54. data/spec/faraday/adapter/em_http_spec.rb +0 -49
  55. data/spec/faraday/adapter/em_synchrony_spec.rb +0 -18
  56. data/spec/faraday/adapter/excon_spec.rb +0 -49
  57. data/spec/faraday/adapter/httpclient_spec.rb +0 -73
  58. data/spec/faraday/adapter/net_http_spec.rb +0 -64
  59. data/spec/faraday/adapter/patron_spec.rb +0 -18
  60. data/spec/faraday/adapter/rack_spec.rb +0 -8
  61. data/spec/faraday/adapter/typhoeus_spec.rb +0 -7
  62. data/spec/faraday/composite_read_io_spec.rb +0 -80
  63. data/spec/faraday/request/multipart_spec.rb +0 -302
  64. data/spec/faraday/request/retry_spec.rb +0 -242
  65. data/spec/faraday/response/middleware_spec.rb +0 -68
  66. data/spec/support/webmock_rack_app.rb +0 -68
@@ -1,49 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- unless defined?(JRUBY_VERSION)
4
- RSpec.describe Faraday::Adapter::EMHttp do
5
- features :request_body_on_query_methods, :reason_phrase_parse, :trace_method,
6
- :skip_response_body_on_head, :parallel, :local_socket_binding
7
-
8
- it_behaves_like 'an adapter'
9
-
10
- it 'allows to provide adapter specific configs' do
11
- url = URI('https://example.com:1234')
12
- adapter = described_class.new nil, inactivity_timeout: 20
13
- req = adapter.create_request(url: url, request: {})
14
-
15
- expect(req.connopts.inactivity_timeout).to eq(20)
16
- end
17
-
18
- context 'Options' do
19
- let(:request) { Faraday::RequestOptions.new }
20
- let(:env) { { request: request } }
21
- let(:options) { {} }
22
- let(:adapter) { Faraday::Adapter::EMHttp.new }
23
-
24
- it 'configures timeout' do
25
- request.timeout = 5
26
- adapter.configure_timeout(options, env)
27
- expect(options[:inactivity_timeout]).to eq(5)
28
- expect(options[:connect_timeout]).to eq(5)
29
- end
30
-
31
- it 'configures timeout and open_timeout' do
32
- request.timeout = 5
33
- request.open_timeout = 1
34
- adapter.configure_timeout(options, env)
35
- expect(options[:inactivity_timeout]).to eq(5)
36
- expect(options[:connect_timeout]).to eq(1)
37
- end
38
-
39
- it 'configures all timeout settings' do
40
- request.timeout = 5
41
- request.read_timeout = 3
42
- request.open_timeout = 1
43
- adapter.configure_timeout(options, env)
44
- expect(options[:inactivity_timeout]).to eq(3)
45
- expect(options[:connect_timeout]).to eq(1)
46
- end
47
- end
48
- end
49
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- unless defined?(JRUBY_VERSION)
4
- RSpec.describe Faraday::Adapter::EMSynchrony do
5
- features :request_body_on_query_methods, :reason_phrase_parse,
6
- :skip_response_body_on_head, :parallel, :local_socket_binding
7
-
8
- it_behaves_like 'an adapter'
9
-
10
- it 'allows to provide adapter specific configs' do
11
- url = URI('https://example.com:1234')
12
- adapter = described_class.new nil, inactivity_timeout: 20
13
- req = adapter.create_request(url: url, request: {})
14
-
15
- expect(req.connopts.inactivity_timeout).to eq(20)
16
- end
17
- end
18
- end
@@ -1,49 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Faraday::Adapter::Excon do
4
- features :request_body_on_query_methods, :reason_phrase_parse, :trace_method
5
-
6
- it_behaves_like 'an adapter'
7
-
8
- it 'allows to provide adapter specific configs' do
9
- url = URI('https://example.com:1234')
10
-
11
- adapter = described_class.new(nil, debug_request: true)
12
-
13
- conn = adapter.build_connection(url: url)
14
-
15
- expect(conn.data[:debug_request]).to be_truthy
16
- end
17
-
18
- context 'config' do
19
- let(:adapter) { Faraday::Adapter::Excon.new }
20
- let(:request) { Faraday::RequestOptions.new }
21
- let(:uri) { URI.parse('https://example.com') }
22
- let(:env) { { request: request, url: uri } }
23
-
24
- it 'sets timeout' do
25
- request.timeout = 5
26
- options = adapter.send(:opts_from_env, env)
27
- expect(options[:read_timeout]).to eq(5)
28
- expect(options[:write_timeout]).to eq(5)
29
- expect(options[:connect_timeout]).to eq(5)
30
- end
31
-
32
- it 'sets timeout and open_timeout' do
33
- request.timeout = 5
34
- request.open_timeout = 3
35
- options = adapter.send(:opts_from_env, env)
36
- expect(options[:read_timeout]).to eq(5)
37
- expect(options[:write_timeout]).to eq(5)
38
- expect(options[:connect_timeout]).to eq(3)
39
- end
40
-
41
- it 'sets open_timeout' do
42
- request.open_timeout = 3
43
- options = adapter.send(:opts_from_env, env)
44
- expect(options[:read_timeout]).to eq(nil)
45
- expect(options[:write_timeout]).to eq(nil)
46
- expect(options[:connect_timeout]).to eq(3)
47
- end
48
- end
49
- end
@@ -1,73 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Faraday::Adapter::HTTPClient do
4
- # ruby gem defaults for testing purposes
5
- HTTPCLIENT_OPEN = 60
6
- HTTPCLIENT_READ = 60
7
- HTTPCLIENT_WRITE = 120
8
-
9
- features :request_body_on_query_methods, :reason_phrase_parse, :compression,
10
- :trace_method, :local_socket_binding
11
-
12
- it_behaves_like 'an adapter'
13
-
14
- it 'allows to provide adapter specific configs' do
15
- adapter = described_class.new do |client|
16
- client.keep_alive_timeout = 20
17
- client.ssl_config.timeout = 25
18
- end
19
-
20
- client = adapter.build_connection(url: URI.parse('https://example.com'))
21
- expect(client.keep_alive_timeout).to eq(20)
22
- expect(client.ssl_config.timeout).to eq(25)
23
- end
24
-
25
- context 'Options' do
26
- let(:request) { Faraday::RequestOptions.new }
27
- let(:env) { { request: request } }
28
- let(:options) { {} }
29
- let(:adapter) { Faraday::Adapter::HTTPClient.new }
30
- let(:client) { adapter.connection(url: URI.parse('https://example.com')) }
31
-
32
- it 'configures timeout' do
33
- assert_default_timeouts!
34
-
35
- request.timeout = 5
36
- adapter.configure_timeouts(client, request)
37
-
38
- expect(client.connect_timeout).to eq(5)
39
- expect(client.send_timeout).to eq(5)
40
- expect(client.receive_timeout).to eq(5)
41
- end
42
-
43
- it 'configures open timeout' do
44
- assert_default_timeouts!
45
-
46
- request.open_timeout = 1
47
- adapter.configure_timeouts(client, request)
48
-
49
- expect(client.connect_timeout).to eq(1)
50
- expect(client.send_timeout).to eq(HTTPCLIENT_WRITE)
51
- expect(client.receive_timeout).to eq(HTTPCLIENT_READ)
52
- end
53
-
54
- it 'configures multiple timeouts' do
55
- assert_default_timeouts!
56
-
57
- request.open_timeout = 1
58
- request.write_timeout = 10
59
- request.read_timeout = 5
60
- adapter.configure_timeouts(client, request)
61
-
62
- expect(client.connect_timeout).to eq(1)
63
- expect(client.send_timeout).to eq(10)
64
- expect(client.receive_timeout).to eq(5)
65
- end
66
-
67
- def assert_default_timeouts!
68
- expect(client.connect_timeout).to eq(HTTPCLIENT_OPEN)
69
- expect(client.send_timeout).to eq(HTTPCLIENT_WRITE)
70
- expect(client.receive_timeout).to eq(HTTPCLIENT_READ)
71
- end
72
- end
73
- end
@@ -1,64 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Faraday::Adapter::NetHttp do
4
- features :request_body_on_query_methods, :reason_phrase_parse, :compression, :streaming, :trace_method
5
-
6
- it_behaves_like 'an adapter'
7
-
8
- context 'checking http' do
9
- let(:url) { URI('http://example.com') }
10
- let(:adapter) { described_class.new }
11
- let(:http) { adapter.send(:connection, url: url, request: {}) }
12
-
13
- it { expect(http.port).to eq(80) }
14
-
15
- it 'sets max_retries to 0' do
16
- adapter.send(:configure_request, http, {})
17
-
18
- expect(http.max_retries).to eq(0) if http.respond_to?(:max_retries=)
19
- end
20
-
21
- it 'supports write_timeout' do
22
- adapter.send(:configure_request, http, write_timeout: 10)
23
-
24
- expect(http.write_timeout).to eq(10) if http.respond_to?(:write_timeout=)
25
- end
26
-
27
- it 'supports open_timeout' do
28
- adapter.send(:configure_request, http, open_timeout: 10)
29
-
30
- expect(http.open_timeout).to eq(10)
31
- end
32
-
33
- it 'supports read_timeout' do
34
- adapter.send(:configure_request, http, read_timeout: 10)
35
-
36
- expect(http.read_timeout).to eq(10)
37
- end
38
-
39
- context 'with https url' do
40
- let(:url) { URI('https://example.com') }
41
-
42
- it { expect(http.port).to eq(443) }
43
- end
44
-
45
- context 'with http url including port' do
46
- let(:url) { URI('https://example.com:1234') }
47
-
48
- it { expect(http.port).to eq(1234) }
49
- end
50
-
51
- context 'with custom adapter config' do
52
- let(:adapter) do
53
- described_class.new do |http|
54
- http.continue_timeout = 123
55
- end
56
- end
57
-
58
- it do
59
- adapter.send(:configure_request, http, {})
60
- expect(http.continue_timeout).to eq(123)
61
- end
62
- end
63
- end
64
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Faraday::Adapter::Patron, unless: defined?(JRUBY_VERSION) do
4
- features :reason_phrase_parse
5
-
6
- it_behaves_like 'an adapter'
7
-
8
- it 'allows to provide adapter specific configs' do
9
- conn = Faraday.new do |f|
10
- f.adapter :patron do |session|
11
- session.max_redirects = 10
12
- raise 'Configuration block called'
13
- end
14
- end
15
-
16
- expect { conn.get('/') }.to raise_error(RuntimeError, 'Configuration block called')
17
- end
18
- end
@@ -1,8 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Faraday::Adapter::Rack do
4
- features :request_body_on_query_methods, :trace_method,
5
- :skip_response_body_on_head
6
-
7
- it_behaves_like 'an adapter', adapter_options: WebmockRackApp.new
8
- end
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Faraday::Adapter::Typhoeus do
4
- features :request_body_on_query_methods, :parallel, :trace_method
5
-
6
- it_behaves_like 'an adapter'
7
- end
@@ -1,80 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'stringio'
4
-
5
- RSpec.describe Faraday::CompositeReadIO do
6
- Part = Struct.new(:to_io) do
7
- def length
8
- to_io.string.length
9
- end
10
- end
11
-
12
- def part(str)
13
- Part.new StringIO.new(str)
14
- end
15
-
16
- def composite_io(*parts)
17
- Faraday::CompositeReadIO.new(*parts)
18
- end
19
-
20
- context 'with empty composite_io' do
21
- subject { composite_io }
22
-
23
- it { expect(subject.length).to eq(0) }
24
- it { expect(subject.read).to eq('') }
25
- it { expect(subject.read(1)).to be_nil }
26
- end
27
-
28
- context 'with empty parts' do
29
- subject { composite_io(part(''), part('')) }
30
-
31
- it { expect(subject.length).to eq(0) }
32
- it { expect(subject.read).to eq('') }
33
- it { expect(subject.read(1)).to be_nil }
34
- end
35
-
36
- context 'with 2 parts' do
37
- subject { composite_io(part('abcd'), part('1234')) }
38
-
39
- it { expect(subject.length).to eq(8) }
40
- it { expect(subject.read).to eq('abcd1234') }
41
- it 'allows to read in chunks' do
42
- expect(subject.read(3)).to eq('abc')
43
- expect(subject.read(3)).to eq('d12')
44
- expect(subject.read(3)).to eq('34')
45
- expect(subject.read(3)).to be_nil
46
- end
47
- it 'allows to rewind while reading in chunks' do
48
- expect(subject.read(3)).to eq('abc')
49
- expect(subject.read(3)).to eq('d12')
50
- subject.rewind
51
- expect(subject.read(3)).to eq('abc')
52
- expect(subject.read(5)).to eq('d1234')
53
- expect(subject.read(3)).to be_nil
54
- subject.rewind
55
- expect(subject.read(2)).to eq('ab')
56
- end
57
- end
58
-
59
- context 'with mix of empty and non-empty parts' do
60
- subject { composite_io(part(''), part('abcd'), part(''), part('1234'), part('')) }
61
-
62
- it 'allows to read in chunks' do
63
- expect(subject.read(6)).to eq('abcd12')
64
- expect(subject.read(6)).to eq('34')
65
- expect(subject.read(6)).to be_nil
66
- end
67
- end
68
-
69
- context 'with utf8 multibyte part' do
70
- subject { composite_io(part("\x86"), part('ファイル')) }
71
-
72
- it { expect(subject.read).to eq(String.new("\x86\xE3\x83\x95\xE3\x82\xA1\xE3\x82\xA4\xE3\x83\xAB", encoding: 'BINARY')) }
73
- it 'allows to read in chunks' do
74
- expect(subject.read(3)).to eq(String.new("\x86\xE3\x83", encoding: 'BINARY'))
75
- expect(subject.read(3)).to eq(String.new("\x95\xE3\x82", encoding: 'BINARY'))
76
- expect(subject.read(8)).to eq(String.new("\xA1\xE3\x82\xA4\xE3\x83\xAB", encoding: 'BINARY'))
77
- expect(subject.read(3)).to be_nil
78
- end
79
- end
80
- end
@@ -1,302 +0,0 @@
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::UploadIO.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::UploadIO.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::UploadIO.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::UploadIO.new(io, 'application/pdf'),
288
- Faraday::UploadIO.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