faraday 1.0.0 → 2.9.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 (101) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +299 -1
  3. data/LICENSE.md +1 -1
  4. data/README.md +35 -23
  5. data/Rakefile +3 -1
  6. data/examples/client_spec.rb +68 -14
  7. data/examples/client_test.rb +80 -15
  8. data/lib/faraday/adapter/test.rb +117 -52
  9. data/lib/faraday/adapter.rb +6 -20
  10. data/lib/faraday/adapter_registry.rb +3 -1
  11. data/lib/faraday/connection.rb +73 -132
  12. data/lib/faraday/encoders/flat_params_encoder.rb +9 -2
  13. data/lib/faraday/encoders/nested_params_encoder.rb +20 -8
  14. data/lib/faraday/error.rb +37 -8
  15. data/lib/faraday/logging/formatter.rb +28 -15
  16. data/lib/faraday/methods.rb +6 -0
  17. data/lib/faraday/middleware.rb +17 -5
  18. data/lib/faraday/middleware_registry.rb +17 -63
  19. data/lib/faraday/options/connection_options.rb +7 -6
  20. data/lib/faraday/options/env.rb +85 -62
  21. data/lib/faraday/options/proxy_options.rb +11 -3
  22. data/lib/faraday/options/request_options.rb +7 -6
  23. data/lib/faraday/options/ssl_options.rb +56 -45
  24. data/lib/faraday/options.rb +11 -14
  25. data/lib/faraday/rack_builder.rb +35 -32
  26. data/lib/faraday/request/authorization.rb +37 -36
  27. data/lib/faraday/request/instrumentation.rb +5 -1
  28. data/lib/faraday/request/json.rb +70 -0
  29. data/lib/faraday/request/url_encoded.rb +8 -2
  30. data/lib/faraday/request.rb +22 -29
  31. data/lib/faraday/response/json.rb +73 -0
  32. data/lib/faraday/response/logger.rb +8 -4
  33. data/lib/faraday/response/raise_error.rb +41 -3
  34. data/lib/faraday/response.rb +10 -23
  35. data/lib/faraday/utils/headers.rb +9 -4
  36. data/lib/faraday/utils.rb +22 -10
  37. data/lib/faraday/version.rb +5 -0
  38. data/lib/faraday.rb +49 -58
  39. data/spec/faraday/adapter/test_spec.rb +442 -0
  40. data/spec/faraday/connection_spec.rb +207 -90
  41. data/spec/faraday/error_spec.rb +45 -5
  42. data/spec/faraday/middleware_registry_spec.rb +31 -0
  43. data/spec/faraday/middleware_spec.rb +50 -6
  44. data/spec/faraday/options/env_spec.rb +8 -2
  45. data/spec/faraday/options/options_spec.rb +1 -1
  46. data/spec/faraday/options/proxy_options_spec.rb +15 -0
  47. data/spec/faraday/params_encoders/flat_spec.rb +8 -0
  48. data/spec/faraday/params_encoders/nested_spec.rb +16 -0
  49. data/spec/faraday/rack_builder_spec.rb +171 -50
  50. data/spec/faraday/request/authorization_spec.rb +54 -24
  51. data/spec/faraday/request/instrumentation_spec.rb +5 -7
  52. data/spec/faraday/request/json_spec.rb +199 -0
  53. data/spec/faraday/request/url_encoded_spec.rb +25 -2
  54. data/spec/faraday/request_spec.rb +11 -10
  55. data/spec/faraday/response/json_spec.rb +189 -0
  56. data/spec/faraday/response/logger_spec.rb +38 -0
  57. data/spec/faraday/response/raise_error_spec.rb +105 -0
  58. data/spec/faraday/response_spec.rb +3 -1
  59. data/spec/faraday/utils/headers_spec.rb +22 -4
  60. data/spec/faraday/utils_spec.rb +63 -1
  61. data/spec/faraday_spec.rb +8 -4
  62. data/spec/spec_helper.rb +6 -5
  63. data/spec/support/fake_safe_buffer.rb +1 -1
  64. data/spec/support/helper_methods.rb +0 -37
  65. data/spec/support/shared_examples/adapter.rb +4 -3
  66. data/spec/support/shared_examples/request_method.rb +60 -31
  67. metadata +19 -44
  68. data/UPGRADING.md +0 -55
  69. data/lib/faraday/adapter/em_http.rb +0 -285
  70. data/lib/faraday/adapter/em_http_ssl_patch.rb +0 -62
  71. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +0 -69
  72. data/lib/faraday/adapter/em_synchrony.rb +0 -150
  73. data/lib/faraday/adapter/excon.rb +0 -124
  74. data/lib/faraday/adapter/httpclient.rb +0 -151
  75. data/lib/faraday/adapter/net_http.rb +0 -209
  76. data/lib/faraday/adapter/net_http_persistent.rb +0 -91
  77. data/lib/faraday/adapter/patron.rb +0 -132
  78. data/lib/faraday/adapter/rack.rb +0 -75
  79. data/lib/faraday/adapter/typhoeus.rb +0 -15
  80. data/lib/faraday/autoload.rb +0 -95
  81. data/lib/faraday/dependency_loader.rb +0 -37
  82. data/lib/faraday/file_part.rb +0 -128
  83. data/lib/faraday/param_part.rb +0 -53
  84. data/lib/faraday/request/basic_authentication.rb +0 -20
  85. data/lib/faraday/request/multipart.rb +0 -99
  86. data/lib/faraday/request/retry.rb +0 -239
  87. data/lib/faraday/request/token_authentication.rb +0 -20
  88. data/spec/faraday/adapter/em_http_spec.rb +0 -47
  89. data/spec/faraday/adapter/em_synchrony_spec.rb +0 -16
  90. data/spec/faraday/adapter/excon_spec.rb +0 -49
  91. data/spec/faraday/adapter/httpclient_spec.rb +0 -73
  92. data/spec/faraday/adapter/net_http_persistent_spec.rb +0 -57
  93. data/spec/faraday/adapter/net_http_spec.rb +0 -64
  94. data/spec/faraday/adapter/patron_spec.rb +0 -18
  95. data/spec/faraday/adapter/rack_spec.rb +0 -8
  96. data/spec/faraday/adapter/typhoeus_spec.rb +0 -7
  97. data/spec/faraday/composite_read_io_spec.rb +0 -80
  98. data/spec/faraday/request/multipart_spec.rb +0 -274
  99. data/spec/faraday/request/retry_spec.rb +0 -242
  100. data/spec/faraday/response/middleware_spec.rb +0 -52
  101. data/spec/support/webmock_rack_app.rb +0 -68
@@ -11,8 +11,10 @@ RSpec.describe Faraday::Response::RaiseError do
11
11
  stub.get('forbidden') { [403, { 'X-Reason' => 'because' }, 'keep looking'] }
12
12
  stub.get('not-found') { [404, { 'X-Reason' => 'because' }, 'keep looking'] }
13
13
  stub.get('proxy-error') { [407, { 'X-Reason' => 'because' }, 'keep looking'] }
14
+ stub.get('request-timeout') { [408, { 'X-Reason' => 'because' }, 'keep looking'] }
14
15
  stub.get('conflict') { [409, { 'X-Reason' => 'because' }, 'keep looking'] }
15
16
  stub.get('unprocessable-entity') { [422, { 'X-Reason' => 'because' }, 'keep looking'] }
17
+ stub.get('too-many-requests') { [429, { 'X-Reason' => 'because' }, 'keep looking'] }
16
18
  stub.get('4xx') { [499, { 'X-Reason' => 'because' }, 'keep looking'] }
17
19
  stub.get('nil-status') { [nil, { 'X-Reason' => 'nil' }, 'fail'] }
18
20
  stub.get('server-error') { [500, { 'X-Error' => 'bailout' }, 'fail'] }
@@ -29,6 +31,9 @@ RSpec.describe Faraday::Response::RaiseError do
29
31
  expect(ex.message).to eq('the server responded with status 400')
30
32
  expect(ex.response[:headers]['X-Reason']).to eq('because')
31
33
  expect(ex.response[:status]).to eq(400)
34
+ expect(ex.response_status).to eq(400)
35
+ expect(ex.response_body).to eq('keep looking')
36
+ expect(ex.response_headers['X-Reason']).to eq('because')
32
37
  end
33
38
  end
34
39
 
@@ -37,6 +42,9 @@ RSpec.describe Faraday::Response::RaiseError do
37
42
  expect(ex.message).to eq('the server responded with status 401')
38
43
  expect(ex.response[:headers]['X-Reason']).to eq('because')
39
44
  expect(ex.response[:status]).to eq(401)
45
+ expect(ex.response_status).to eq(401)
46
+ expect(ex.response_body).to eq('keep looking')
47
+ expect(ex.response_headers['X-Reason']).to eq('because')
40
48
  end
41
49
  end
42
50
 
@@ -45,6 +53,9 @@ RSpec.describe Faraday::Response::RaiseError do
45
53
  expect(ex.message).to eq('the server responded with status 403')
46
54
  expect(ex.response[:headers]['X-Reason']).to eq('because')
47
55
  expect(ex.response[:status]).to eq(403)
56
+ expect(ex.response_status).to eq(403)
57
+ expect(ex.response_body).to eq('keep looking')
58
+ expect(ex.response_headers['X-Reason']).to eq('because')
48
59
  end
49
60
  end
50
61
 
@@ -53,6 +64,9 @@ RSpec.describe Faraday::Response::RaiseError do
53
64
  expect(ex.message).to eq('the server responded with status 404')
54
65
  expect(ex.response[:headers]['X-Reason']).to eq('because')
55
66
  expect(ex.response[:status]).to eq(404)
67
+ expect(ex.response_status).to eq(404)
68
+ expect(ex.response_body).to eq('keep looking')
69
+ expect(ex.response_headers['X-Reason']).to eq('because')
56
70
  end
57
71
  end
58
72
 
@@ -61,6 +75,20 @@ RSpec.describe Faraday::Response::RaiseError do
61
75
  expect(ex.message).to eq('407 "Proxy Authentication Required"')
62
76
  expect(ex.response[:headers]['X-Reason']).to eq('because')
63
77
  expect(ex.response[:status]).to eq(407)
78
+ expect(ex.response_status).to eq(407)
79
+ expect(ex.response_body).to eq('keep looking')
80
+ expect(ex.response_headers['X-Reason']).to eq('because')
81
+ end
82
+ end
83
+
84
+ it 'raises Faraday::RequestTimeoutError for 408 responses' do
85
+ expect { conn.get('request-timeout') }.to raise_error(Faraday::RequestTimeoutError) do |ex|
86
+ expect(ex.message).to eq('the server responded with status 408')
87
+ expect(ex.response[:headers]['X-Reason']).to eq('because')
88
+ expect(ex.response[:status]).to eq(408)
89
+ expect(ex.response_status).to eq(408)
90
+ expect(ex.response_body).to eq('keep looking')
91
+ expect(ex.response_headers['X-Reason']).to eq('because')
64
92
  end
65
93
  end
66
94
 
@@ -69,6 +97,9 @@ RSpec.describe Faraday::Response::RaiseError do
69
97
  expect(ex.message).to eq('the server responded with status 409')
70
98
  expect(ex.response[:headers]['X-Reason']).to eq('because')
71
99
  expect(ex.response[:status]).to eq(409)
100
+ expect(ex.response_status).to eq(409)
101
+ expect(ex.response_body).to eq('keep looking')
102
+ expect(ex.response_headers['X-Reason']).to eq('because')
72
103
  end
73
104
  end
74
105
 
@@ -77,6 +108,20 @@ RSpec.describe Faraday::Response::RaiseError do
77
108
  expect(ex.message).to eq('the server responded with status 422')
78
109
  expect(ex.response[:headers]['X-Reason']).to eq('because')
79
110
  expect(ex.response[:status]).to eq(422)
111
+ expect(ex.response_status).to eq(422)
112
+ expect(ex.response_body).to eq('keep looking')
113
+ expect(ex.response_headers['X-Reason']).to eq('because')
114
+ end
115
+ end
116
+
117
+ it 'raises Faraday::TooManyRequestsError for 429 responses' do
118
+ expect { conn.get('too-many-requests') }.to raise_error(Faraday::TooManyRequestsError) do |ex|
119
+ expect(ex.message).to eq('the server responded with status 429')
120
+ expect(ex.response[:headers]['X-Reason']).to eq('because')
121
+ expect(ex.response[:status]).to eq(429)
122
+ expect(ex.response_status).to eq(429)
123
+ expect(ex.response_body).to eq('keep looking')
124
+ expect(ex.response_headers['X-Reason']).to eq('because')
80
125
  end
81
126
  end
82
127
 
@@ -85,6 +130,9 @@ RSpec.describe Faraday::Response::RaiseError do
85
130
  expect(ex.message).to eq('http status could not be derived from the server response')
86
131
  expect(ex.response[:headers]['X-Reason']).to eq('nil')
87
132
  expect(ex.response[:status]).to be_nil
133
+ expect(ex.response_status).to be_nil
134
+ expect(ex.response_body).to eq('fail')
135
+ expect(ex.response_headers['X-Reason']).to eq('nil')
88
136
  end
89
137
  end
90
138
 
@@ -93,6 +141,9 @@ RSpec.describe Faraday::Response::RaiseError do
93
141
  expect(ex.message).to eq('the server responded with status 499')
94
142
  expect(ex.response[:headers]['X-Reason']).to eq('because')
95
143
  expect(ex.response[:status]).to eq(499)
144
+ expect(ex.response_status).to eq(499)
145
+ expect(ex.response_body).to eq('keep looking')
146
+ expect(ex.response_headers['X-Reason']).to eq('because')
96
147
  end
97
148
  end
98
149
 
@@ -101,6 +152,60 @@ RSpec.describe Faraday::Response::RaiseError do
101
152
  expect(ex.message).to eq('the server responded with status 500')
102
153
  expect(ex.response[:headers]['X-Error']).to eq('bailout')
103
154
  expect(ex.response[:status]).to eq(500)
155
+ expect(ex.response_status).to eq(500)
156
+ expect(ex.response_body).to eq('fail')
157
+ expect(ex.response_headers['X-Error']).to eq('bailout')
158
+ end
159
+ end
160
+
161
+ describe 'request info' do
162
+ let(:conn) do
163
+ Faraday.new do |b|
164
+ b.response :raise_error, **middleware_options
165
+ b.adapter :test do |stub|
166
+ stub.post(url, request_body, request_headers) do
167
+ [400, { 'X-Reason' => 'because' }, 'keep looking']
168
+ end
169
+ end
170
+ end
171
+ end
172
+ let(:middleware_options) { {} }
173
+ let(:request_body) { JSON.generate({ 'item' => 'sth' }) }
174
+ let(:request_headers) { { 'Authorization' => 'Basic 123' } }
175
+ let(:url_path) { 'request' }
176
+ let(:query_params) { 'full=true' }
177
+ let(:url) { "#{url_path}?#{query_params}" }
178
+
179
+ subject(:perform_request) do
180
+ conn.post url do |req|
181
+ req.headers['Authorization'] = 'Basic 123'
182
+ req.body = request_body
183
+ end
184
+ end
185
+
186
+ it 'returns the request info in the exception' do
187
+ expect { perform_request }.to raise_error(Faraday::BadRequestError) do |ex|
188
+ expect(ex.response[:request][:method]).to eq(:post)
189
+ expect(ex.response[:request][:url]).to eq(URI("http:/#{url}"))
190
+ expect(ex.response[:request][:url_path]).to eq("/#{url_path}")
191
+ expect(ex.response[:request][:params]).to eq({ 'full' => 'true' })
192
+ expect(ex.response[:request][:headers]).to match(a_hash_including(request_headers))
193
+ expect(ex.response[:request][:body]).to eq(request_body)
194
+ end
195
+ end
196
+
197
+ context 'when the include_request option is set to false' do
198
+ let(:middleware_options) { { include_request: false } }
199
+
200
+ it 'does not include request info in the exception' do
201
+ expect { perform_request }.to raise_error(Faraday::BadRequestError) do |ex|
202
+ expect(ex.response.keys).to contain_exactly(
203
+ :status,
204
+ :headers,
205
+ :body
206
+ )
207
+ end
208
+ end
104
209
  end
105
210
  end
106
211
  end
@@ -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://sushi.com/\r\n\r\n" }
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
- it { expect(subject['location']).to eq('http://sushi.com/') }
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
@@ -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
- "HTTP/1.x 200 OK\r\nContent-Type: application/json; charset=UTF-8\r\n\r\n"
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
data/spec/faraday_spec.rb CHANGED
@@ -18,10 +18,14 @@ RSpec.describe Faraday do
18
18
  end
19
19
 
20
20
  it 'uses method_missing on Faraday if there is no proxyable method' do
21
- expect { Faraday.this_method_does_not_exist }.to raise_error(
22
- NoMethodError,
23
- "undefined method `this_method_does_not_exist' for Faraday:Module"
24
- )
21
+ expected_message =
22
+ if RUBY_VERSION >= '3.3'
23
+ "undefined method `this_method_does_not_exist' for module Faraday"
24
+ else
25
+ "undefined method `this_method_does_not_exist' for Faraday:Module"
26
+ end
27
+
28
+ expect { Faraday.this_method_does_not_exist }.to raise_error(NoMethodError, expected_message)
25
29
  end
26
30
 
27
31
  it 'proxied methods can be accessed' do
data/spec/spec_helper.rb CHANGED
@@ -29,14 +29,15 @@ SimpleCov.start do
29
29
  minimum_coverage_by_file 26
30
30
  end
31
31
 
32
- # Ensure all /lib files are loaded
33
- # so they will be included in the test coverage report.
34
- Dir['./lib/**/*.rb'].sort.each { |file| require file }
35
-
36
32
  require 'faraday'
37
33
  require 'pry'
38
34
 
39
- Dir['./spec/support/**/*.rb'].sort.each { |f| require f }
35
+ # Ensure all /lib files are loaded
36
+ # so they will be included in the test coverage report.
37
+ Dir['./lib/**/*.rb'].each { |file| require file }
38
+
39
+ # Load all Rspec support files
40
+ Dir['./spec/support/**/*.rb'].each { |file| require file }
40
41
 
41
42
  RSpec.configure do |config|
42
43
  # rspec-expectations config goes here. You can use an alternate
@@ -8,7 +8,7 @@ FakeSafeBuffer = Struct.new(:string) do
8
8
 
9
9
  def gsub(regex)
10
10
  string.gsub(regex) do
11
- match, = $&, '' =~ /a/
11
+ match, = Regexp.last_match(0), '' =~ /a/ # rubocop:disable Performance/StringInclude
12
12
  yield(match)
13
13
  end
14
14
  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['SSL_FILE']
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, remote) }
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?
@@ -1,5 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ shared_examples 'proxy examples' do
4
+ it 'handles requests with proxy' do
5
+ res = conn.public_send(http_method, '/')
6
+
7
+ expect(res.status).to eq(200)
8
+ end
9
+
10
+ it 'handles proxy failures' do
11
+ request_stub.to_return(status: 407)
12
+
13
+ expect { conn.public_send(http_method, '/') }.to raise_error(Faraday::ProxyAuthError)
14
+ end
15
+ end
16
+
3
17
  shared_examples 'a request method' do |http_method|
4
18
  let(:query_or_body) { method_with_body?(http_method) ? :body : :query }
5
19
  let(:response) { conn.public_send(http_method, '/') }
@@ -13,8 +27,8 @@ shared_examples 'a request method' do |http_method|
13
27
  end
14
28
 
15
29
  it 'handles headers with multiple values' do
16
- request_stub.to_return(headers: { 'Set-Cookie' => 'one, two' })
17
- expect(response.headers['set-cookie']).to eq('one, two')
30
+ request_stub.to_return(headers: { 'Set-Cookie' => 'name=value' })
31
+ expect(response.headers['set-cookie']).to eq('name=value')
18
32
  end
19
33
 
20
34
  it 'retrieves the response headers' do
@@ -65,7 +79,7 @@ shared_examples 'a request method' do |http_method|
65
79
 
66
80
  on_feature :request_body_on_query_methods do
67
81
  it 'sends request body' do
68
- request_stub.with(Hash[:body, 'test'])
82
+ request_stub.with({ body: 'test' })
69
83
  res = if query_or_body == :body
70
84
  conn.public_send(http_method, '/', 'test')
71
85
  else
@@ -79,7 +93,7 @@ shared_examples 'a request method' do |http_method|
79
93
 
80
94
  it 'sends url encoded parameters' do
81
95
  payload = { name: 'zack' }
82
- request_stub.with(Hash[query_or_body, payload])
96
+ request_stub.with({ query_or_body => payload })
83
97
  res = conn.public_send(http_method, '/', payload)
84
98
  if query_or_body == :query
85
99
  expect(res.env.request_body).to be_nil
@@ -90,7 +104,7 @@ shared_examples 'a request method' do |http_method|
90
104
 
91
105
  it 'sends url encoded nested parameters' do
92
106
  payload = { name: { first: 'zack' } }
93
- request_stub.with(Hash[query_or_body, payload])
107
+ request_stub.with({ query_or_body => payload })
94
108
  conn.public_send(http_method, '/', payload)
95
109
  end
96
110
 
@@ -112,19 +126,6 @@ shared_examples 'a request method' do |http_method|
112
126
  expect { conn.public_send(http_method, '/') }.to raise_error(exc)
113
127
  end
114
128
 
115
- # Can't send files on get, head and delete methods
116
- if method_with_body?(http_method)
117
- it 'sends files' do
118
- payload = { uploaded_file: multipart_file }
119
- request_stub.with(headers: { 'Content-Type' => %r{\Amultipart/form-data} }) do |request|
120
- # WebMock does not support matching body for multipart/form-data requests yet :(
121
- # https://github.com/bblimke/webmock/issues/623
122
- request.body =~ /RubyMultipartPost/
123
- end
124
- conn.public_send(http_method, '/', payload)
125
- end
126
- end
127
-
128
129
  on_feature :reason_phrase_parse do
129
130
  it 'parses the reason phrase' do
130
131
  request_stub.to_return(status: [200, 'OK'])
@@ -152,12 +153,19 @@ shared_examples 'a request method' do |http_method|
152
153
  let(:streamed) { [] }
153
154
 
154
155
  context 'when response is empty' do
155
- it do
156
+ it 'handles streaming' do
157
+ env = nil
156
158
  conn.public_send(http_method, '/') do |req|
157
- req.options.on_data = proc { |*args| streamed << args }
159
+ req.options.on_data = proc do |chunk, size, block_env|
160
+ streamed << [chunk, size]
161
+ env ||= block_env
162
+ end
158
163
  end
159
164
 
160
165
  expect(streamed).to eq([['', 0]])
166
+ # TODO: enable this after updating all existing adapters to the new streaming API
167
+ # expect(env).to be_a(Faraday::Env)
168
+ # expect(env.status).to eq(200)
161
169
  end
162
170
  end
163
171
 
@@ -165,12 +173,19 @@ shared_examples 'a request method' do |http_method|
165
173
  before { request_stub.to_return(body: big_string) }
166
174
 
167
175
  it 'handles streaming' do
176
+ env = nil
168
177
  response = conn.public_send(http_method, '/') do |req|
169
- req.options.on_data = proc { |*args| streamed << args }
178
+ req.options.on_data = proc do |chunk, size, block_env|
179
+ streamed << [chunk, size]
180
+ env ||= block_env
181
+ end
170
182
  end
171
183
 
172
184
  expect(response.body).to eq('')
173
185
  check_streaming_response(streamed, chunk_size: 16 * 1024)
186
+ # TODO: enable this after updating all existing adapters to the new streaming API
187
+ # expect(env).to be_a(Faraday::Env)
188
+ # expect(env.status).to eq(200)
174
189
  end
175
190
  end
176
191
  end
@@ -185,11 +200,11 @@ shared_examples 'a request method' do |http_method|
185
200
  @payload2 = { b: '2' }
186
201
 
187
202
  request_stub
188
- .with(Hash[query_or_body, @payload1])
203
+ .with({ query_or_body => @payload1 })
189
204
  .to_return(body: @payload1.to_json)
190
205
 
191
206
  stub_request(http_method, remote)
192
- .with(Hash[query_or_body, @payload2])
207
+ .with({ query_or_body => @payload2 })
193
208
  .to_return(body: @payload2.to_json)
194
209
 
195
210
  conn.in_parallel do
@@ -218,17 +233,31 @@ shared_examples 'a request method' do |http_method|
218
233
  end
219
234
  end
220
235
 
221
- it 'handles requests with proxy' do
222
- conn_options[:proxy] = 'http://google.co.uk'
236
+ context 'when a proxy is provided as option' do
237
+ before do
238
+ conn_options[:proxy] = 'http://env-proxy.com:80'
239
+ end
223
240
 
224
- res = conn.public_send(http_method, '/')
225
- expect(res.status).to eq(200)
241
+ include_examples 'proxy examples'
226
242
  end
227
243
 
228
- it 'handles proxy failures' do
229
- conn_options[:proxy] = 'http://google.co.uk'
230
- request_stub.to_return(status: 407)
244
+ context 'when http_proxy env variable is set' do
245
+ let(:proxy_url) { 'http://env-proxy.com:80' }
231
246
 
232
- expect { conn.public_send(http_method, '/') }.to raise_error(Faraday::ProxyAuthError)
247
+ around do |example|
248
+ with_env 'http_proxy' => proxy_url do
249
+ example.run
250
+ end
251
+ end
252
+
253
+ include_examples 'proxy examples'
254
+
255
+ context 'when the env proxy is ignored' do
256
+ around do |example|
257
+ with_env_proxy_disabled(&example)
258
+ end
259
+
260
+ include_examples 'proxy examples'
261
+ end
233
262
  end
234
263
  end