faraday 1.4.1 → 2.14.2

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 (94) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +198 -4
  3. data/LICENSE.md +1 -1
  4. data/README.md +34 -20
  5. data/Rakefile +6 -1
  6. data/examples/client_spec.rb +67 -13
  7. data/examples/client_test.rb +81 -16
  8. data/lib/faraday/adapter/test.rb +117 -52
  9. data/lib/faraday/adapter.rb +12 -20
  10. data/lib/faraday/connection.rb +86 -134
  11. data/lib/faraday/encoders/flat_params_encoder.rb +3 -2
  12. data/lib/faraday/encoders/nested_params_encoder.rb +15 -7
  13. data/lib/faraday/error.rb +65 -15
  14. data/lib/faraday/logging/formatter.rb +30 -17
  15. data/lib/faraday/middleware.rb +44 -3
  16. data/lib/faraday/middleware_registry.rb +17 -63
  17. data/lib/faraday/options/connection_options.rb +7 -6
  18. data/lib/faraday/options/env.rb +88 -65
  19. data/lib/faraday/options/proxy_options.rb +17 -6
  20. data/lib/faraday/options/request_options.rb +8 -7
  21. data/lib/faraday/options/ssl_options.rb +62 -45
  22. data/lib/faraday/options.rb +8 -7
  23. data/lib/faraday/rack_builder.rb +46 -47
  24. data/lib/faraday/request/authorization.rb +37 -38
  25. data/lib/faraday/request/instrumentation.rb +5 -1
  26. data/lib/faraday/request/json.rb +70 -0
  27. data/lib/faraday/request/url_encoded.rb +5 -1
  28. data/lib/faraday/request.rb +20 -37
  29. data/lib/faraday/response/json.rb +74 -0
  30. data/lib/faraday/response/logger.rb +13 -7
  31. data/lib/faraday/response/raise_error.rb +45 -18
  32. data/lib/faraday/response.rb +15 -21
  33. data/lib/faraday/utils/headers.rb +18 -7
  34. data/lib/faraday/utils.rb +11 -7
  35. data/lib/faraday/version.rb +1 -1
  36. data/lib/faraday.rb +12 -32
  37. data/spec/faraday/adapter/test_spec.rb +182 -0
  38. data/spec/faraday/connection_spec.rb +219 -92
  39. data/spec/faraday/error_spec.rb +122 -7
  40. data/spec/faraday/middleware_registry_spec.rb +31 -0
  41. data/spec/faraday/middleware_spec.rb +163 -2
  42. data/spec/faraday/options/env_spec.rb +8 -2
  43. data/spec/faraday/options/options_spec.rb +1 -1
  44. data/spec/faraday/options/proxy_options_spec.rb +42 -0
  45. data/spec/faraday/params_encoders/nested_spec.rb +10 -1
  46. data/spec/faraday/rack_builder_spec.rb +26 -54
  47. data/spec/faraday/request/authorization_spec.rb +54 -24
  48. data/spec/faraday/request/instrumentation_spec.rb +5 -7
  49. data/spec/faraday/request/json_spec.rb +199 -0
  50. data/spec/faraday/request/url_encoded_spec.rb +12 -2
  51. data/spec/faraday/request_spec.rb +14 -15
  52. data/spec/faraday/response/json_spec.rb +206 -0
  53. data/spec/faraday/response/logger_spec.rb +84 -5
  54. data/spec/faraday/response/raise_error_spec.rb +133 -16
  55. data/spec/faraday/response_spec.rb +10 -1
  56. data/spec/faraday/utils/headers_spec.rb +31 -4
  57. data/spec/faraday/utils_spec.rb +66 -2
  58. data/spec/faraday_spec.rb +10 -4
  59. data/spec/spec_helper.rb +6 -5
  60. data/spec/support/fake_safe_buffer.rb +1 -1
  61. data/spec/support/faraday_middleware_subclasses.rb +18 -0
  62. data/spec/support/helper_methods.rb +0 -37
  63. data/spec/support/shared_examples/adapter.rb +2 -2
  64. data/spec/support/shared_examples/request_method.rb +22 -21
  65. metadata +27 -81
  66. data/lib/faraday/adapter/em_http.rb +0 -289
  67. data/lib/faraday/adapter/em_http_ssl_patch.rb +0 -62
  68. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +0 -69
  69. data/lib/faraday/adapter/em_synchrony.rb +0 -153
  70. data/lib/faraday/adapter/httpclient.rb +0 -152
  71. data/lib/faraday/adapter/patron.rb +0 -132
  72. data/lib/faraday/adapter/rack.rb +0 -75
  73. data/lib/faraday/adapter/typhoeus.rb +0 -15
  74. data/lib/faraday/autoload.rb +0 -92
  75. data/lib/faraday/dependency_loader.rb +0 -37
  76. data/lib/faraday/file_part.rb +0 -128
  77. data/lib/faraday/param_part.rb +0 -53
  78. data/lib/faraday/request/basic_authentication.rb +0 -20
  79. data/lib/faraday/request/multipart.rb +0 -106
  80. data/lib/faraday/request/retry.rb +0 -239
  81. data/lib/faraday/request/token_authentication.rb +0 -20
  82. data/spec/faraday/adapter/em_http_spec.rb +0 -47
  83. data/spec/faraday/adapter/em_synchrony_spec.rb +0 -16
  84. data/spec/faraday/adapter/excon_spec.rb +0 -49
  85. data/spec/faraday/adapter/httpclient_spec.rb +0 -73
  86. data/spec/faraday/adapter/net_http_spec.rb +0 -64
  87. data/spec/faraday/adapter/patron_spec.rb +0 -18
  88. data/spec/faraday/adapter/rack_spec.rb +0 -8
  89. data/spec/faraday/adapter/typhoeus_spec.rb +0 -7
  90. data/spec/faraday/composite_read_io_spec.rb +0 -80
  91. data/spec/faraday/request/multipart_spec.rb +0 -302
  92. data/spec/faraday/request/retry_spec.rb +0 -242
  93. data/spec/faraday/response/middleware_spec.rb +0 -68
  94. data/spec/support/webmock_rack_app.rb +0 -68
@@ -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
@@ -37,10 +37,10 @@ shared_examples 'adapter examples' do |**options|
37
37
 
38
38
  let(:conn) do
39
39
  conn_options[:ssl] ||= {}
40
- 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'
41
42
 
42
43
  Faraday.new(remote, conn_options) do |conn|
43
- conn.request :multipart
44
44
  conn.request :url_encoded
45
45
  conn.response :raise_error
46
46
  conn.adapter described_class, *adapter_options
@@ -79,7 +79,7 @@ shared_examples 'a request method' do |http_method|
79
79
 
80
80
  on_feature :request_body_on_query_methods do
81
81
  it 'sends request body' do
82
- request_stub.with(Hash[:body, 'test'])
82
+ request_stub.with({ body: 'test' })
83
83
  res = if query_or_body == :body
84
84
  conn.public_send(http_method, '/', 'test')
85
85
  else
@@ -93,7 +93,7 @@ shared_examples 'a request method' do |http_method|
93
93
 
94
94
  it 'sends url encoded parameters' do
95
95
  payload = { name: 'zack' }
96
- request_stub.with(Hash[query_or_body, payload])
96
+ request_stub.with({ query_or_body => payload })
97
97
  res = conn.public_send(http_method, '/', payload)
98
98
  if query_or_body == :query
99
99
  expect(res.env.request_body).to be_nil
@@ -104,7 +104,7 @@ shared_examples 'a request method' do |http_method|
104
104
 
105
105
  it 'sends url encoded nested parameters' do
106
106
  payload = { name: { first: 'zack' } }
107
- request_stub.with(Hash[query_or_body, payload])
107
+ request_stub.with({ query_or_body => payload })
108
108
  conn.public_send(http_method, '/', payload)
109
109
  end
110
110
 
@@ -126,19 +126,6 @@ shared_examples 'a request method' do |http_method|
126
126
  expect { conn.public_send(http_method, '/') }.to raise_error(exc)
127
127
  end
128
128
 
129
- # Can't send files on get, head and delete methods
130
- if method_with_body?(http_method)
131
- it 'sends files' do
132
- payload = { uploaded_file: multipart_file }
133
- request_stub.with(headers: { 'Content-Type' => %r{\Amultipart/form-data} }) do |request|
134
- # WebMock does not support matching body for multipart/form-data requests yet :(
135
- # https://github.com/bblimke/webmock/issues/623
136
- request.body.include?('RubyMultipartPost')
137
- end
138
- conn.public_send(http_method, '/', payload)
139
- end
140
- end
141
-
142
129
  on_feature :reason_phrase_parse do
143
130
  it 'parses the reason phrase' do
144
131
  request_stub.to_return(status: [200, 'OK'])
@@ -166,12 +153,19 @@ shared_examples 'a request method' do |http_method|
166
153
  let(:streamed) { [] }
167
154
 
168
155
  context 'when response is empty' do
169
- it do
156
+ it 'handles streaming' do
157
+ env = nil
170
158
  conn.public_send(http_method, '/') do |req|
171
- 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
172
163
  end
173
164
 
174
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)
175
169
  end
176
170
  end
177
171
 
@@ -179,12 +173,19 @@ shared_examples 'a request method' do |http_method|
179
173
  before { request_stub.to_return(body: big_string) }
180
174
 
181
175
  it 'handles streaming' do
176
+ env = nil
182
177
  response = conn.public_send(http_method, '/') do |req|
183
- 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
184
182
  end
185
183
 
186
184
  expect(response.body).to eq('')
187
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)
188
189
  end
189
190
  end
190
191
  end
@@ -199,11 +200,11 @@ shared_examples 'a request method' do |http_method|
199
200
  @payload2 = { b: '2' }
200
201
 
201
202
  request_stub
202
- .with(Hash[query_or_body, @payload1])
203
+ .with({ query_or_body => @payload1 })
203
204
  .to_return(body: @payload1.to_json)
204
205
 
205
206
  stub_request(http_method, remote)
206
- .with(Hash[query_or_body, @payload2])
207
+ .with({ query_or_body => @payload2 })
207
208
  .to_return(body: @payload2.to_json)
208
209
 
209
210
  conn.in_parallel do
metadata CHANGED
@@ -1,94 +1,64 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: faraday
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.1
4
+ version: 2.14.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - "@technoweenie"
8
8
  - "@iMacTia"
9
9
  - "@olleolleolle"
10
- autorequire:
11
10
  bindir: bin
12
11
  cert_chain: []
13
- date: 2021-04-18 00:00:00.000000000 Z
12
+ date: 1980-01-02 00:00:00.000000000 Z
14
13
  dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: faraday-excon
17
- requirement: !ruby/object:Gem::Requirement
18
- requirements:
19
- - - "~>"
20
- - !ruby/object:Gem::Version
21
- version: '1.1'
22
- type: :runtime
23
- prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
25
- requirements:
26
- - - "~>"
27
- - !ruby/object:Gem::Version
28
- version: '1.1'
29
14
  - !ruby/object:Gem::Dependency
30
15
  name: faraday-net_http
31
16
  requirement: !ruby/object:Gem::Requirement
32
17
  requirements:
33
- - - "~>"
34
- - !ruby/object:Gem::Version
35
- version: '1.0'
36
- type: :runtime
37
- prerelease: false
38
- version_requirements: !ruby/object:Gem::Requirement
39
- requirements:
40
- - - "~>"
18
+ - - ">="
41
19
  - !ruby/object:Gem::Version
42
- version: '1.0'
43
- - !ruby/object:Gem::Dependency
44
- name: faraday-net_http_persistent
45
- requirement: !ruby/object:Gem::Requirement
46
- requirements:
47
- - - "~>"
20
+ version: '2.0'
21
+ - - "<"
48
22
  - !ruby/object:Gem::Version
49
- version: '1.1'
23
+ version: '3.5'
50
24
  type: :runtime
51
25
  prerelease: false
52
26
  version_requirements: !ruby/object:Gem::Requirement
53
27
  requirements:
54
- - - "~>"
28
+ - - ">="
55
29
  - !ruby/object:Gem::Version
56
- version: '1.1'
30
+ version: '2.0'
31
+ - - "<"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.5'
57
34
  - !ruby/object:Gem::Dependency
58
- name: multipart-post
35
+ name: json
59
36
  requirement: !ruby/object:Gem::Requirement
60
37
  requirements:
61
38
  - - ">="
62
39
  - !ruby/object:Gem::Version
63
- version: '1.2'
64
- - - "<"
65
- - !ruby/object:Gem::Version
66
- version: '3'
40
+ version: '0'
67
41
  type: :runtime
68
42
  prerelease: false
69
43
  version_requirements: !ruby/object:Gem::Requirement
70
44
  requirements:
71
45
  - - ">="
72
46
  - !ruby/object:Gem::Version
73
- version: '1.2'
74
- - - "<"
75
- - !ruby/object:Gem::Version
76
- version: '3'
47
+ version: '0'
77
48
  - !ruby/object:Gem::Dependency
78
- name: ruby2_keywords
49
+ name: logger
79
50
  requirement: !ruby/object:Gem::Requirement
80
51
  requirements:
81
52
  - - ">="
82
53
  - !ruby/object:Gem::Version
83
- version: 0.0.4
54
+ version: '0'
84
55
  type: :runtime
85
56
  prerelease: false
86
57
  version_requirements: !ruby/object:Gem::Requirement
87
58
  requirements:
88
59
  - - ">="
89
60
  - !ruby/object:Gem::Version
90
- version: 0.0.4
91
- description:
61
+ version: '0'
92
62
  email: technoweenie@gmail.com
93
63
  executables: []
94
64
  extensions: []
@@ -102,23 +72,12 @@ files:
102
72
  - examples/client_test.rb
103
73
  - lib/faraday.rb
104
74
  - lib/faraday/adapter.rb
105
- - lib/faraday/adapter/em_http.rb
106
- - lib/faraday/adapter/em_http_ssl_patch.rb
107
- - lib/faraday/adapter/em_synchrony.rb
108
- - lib/faraday/adapter/em_synchrony/parallel_manager.rb
109
- - lib/faraday/adapter/httpclient.rb
110
- - lib/faraday/adapter/patron.rb
111
- - lib/faraday/adapter/rack.rb
112
75
  - lib/faraday/adapter/test.rb
113
- - lib/faraday/adapter/typhoeus.rb
114
76
  - lib/faraday/adapter_registry.rb
115
- - lib/faraday/autoload.rb
116
77
  - lib/faraday/connection.rb
117
- - lib/faraday/dependency_loader.rb
118
78
  - lib/faraday/encoders/flat_params_encoder.rb
119
79
  - lib/faraday/encoders/nested_params_encoder.rb
120
80
  - lib/faraday/error.rb
121
- - lib/faraday/file_part.rb
122
81
  - lib/faraday/logging/formatter.rb
123
82
  - lib/faraday/methods.rb
124
83
  - lib/faraday/middleware.rb
@@ -129,18 +88,15 @@ files:
129
88
  - lib/faraday/options/proxy_options.rb
130
89
  - lib/faraday/options/request_options.rb
131
90
  - lib/faraday/options/ssl_options.rb
132
- - lib/faraday/param_part.rb
133
91
  - lib/faraday/parameters.rb
134
92
  - lib/faraday/rack_builder.rb
135
93
  - lib/faraday/request.rb
136
94
  - lib/faraday/request/authorization.rb
137
- - lib/faraday/request/basic_authentication.rb
138
95
  - lib/faraday/request/instrumentation.rb
139
- - lib/faraday/request/multipart.rb
140
- - lib/faraday/request/retry.rb
141
- - lib/faraday/request/token_authentication.rb
96
+ - lib/faraday/request/json.rb
142
97
  - lib/faraday/request/url_encoded.rb
143
98
  - lib/faraday/response.rb
99
+ - lib/faraday/response/json.rb
144
100
  - lib/faraday/response/logger.rb
145
101
  - lib/faraday/response/raise_error.rb
146
102
  - lib/faraday/utils.rb
@@ -148,20 +104,12 @@ files:
148
104
  - lib/faraday/utils/params_hash.rb
149
105
  - lib/faraday/version.rb
150
106
  - spec/external_adapters/faraday_specs_setup.rb
151
- - spec/faraday/adapter/em_http_spec.rb
152
- - spec/faraday/adapter/em_synchrony_spec.rb
153
- - spec/faraday/adapter/excon_spec.rb
154
- - spec/faraday/adapter/httpclient_spec.rb
155
- - spec/faraday/adapter/net_http_spec.rb
156
- - spec/faraday/adapter/patron_spec.rb
157
- - spec/faraday/adapter/rack_spec.rb
158
107
  - spec/faraday/adapter/test_spec.rb
159
- - spec/faraday/adapter/typhoeus_spec.rb
160
108
  - spec/faraday/adapter_registry_spec.rb
161
109
  - spec/faraday/adapter_spec.rb
162
- - spec/faraday/composite_read_io_spec.rb
163
110
  - spec/faraday/connection_spec.rb
164
111
  - spec/faraday/error_spec.rb
112
+ - spec/faraday/middleware_registry_spec.rb
165
113
  - spec/faraday/middleware_spec.rb
166
114
  - spec/faraday/options/env_spec.rb
167
115
  - spec/faraday/options/options_spec.rb
@@ -172,12 +120,11 @@ files:
172
120
  - spec/faraday/rack_builder_spec.rb
173
121
  - spec/faraday/request/authorization_spec.rb
174
122
  - spec/faraday/request/instrumentation_spec.rb
175
- - spec/faraday/request/multipart_spec.rb
176
- - spec/faraday/request/retry_spec.rb
123
+ - spec/faraday/request/json_spec.rb
177
124
  - spec/faraday/request/url_encoded_spec.rb
178
125
  - spec/faraday/request_spec.rb
126
+ - spec/faraday/response/json_spec.rb
179
127
  - spec/faraday/response/logger_spec.rb
180
- - spec/faraday/response/middleware_spec.rb
181
128
  - spec/faraday/response/raise_error_spec.rb
182
129
  - spec/faraday/response_spec.rb
183
130
  - spec/faraday/utils/headers_spec.rb
@@ -186,21 +133,21 @@ files:
186
133
  - spec/spec_helper.rb
187
134
  - spec/support/disabling_stub.rb
188
135
  - spec/support/fake_safe_buffer.rb
136
+ - spec/support/faraday_middleware_subclasses.rb
189
137
  - spec/support/helper_methods.rb
190
138
  - spec/support/shared_examples/adapter.rb
191
139
  - spec/support/shared_examples/params_encoder.rb
192
140
  - spec/support/shared_examples/request_method.rb
193
141
  - spec/support/streaming_response_checker.rb
194
- - spec/support/webmock_rack_app.rb
195
142
  homepage: https://lostisland.github.io/faraday
196
143
  licenses:
197
144
  - MIT
198
145
  metadata:
199
146
  homepage_uri: https://lostisland.github.io/faraday
200
- changelog_uri: https://github.com/lostisland/faraday/releases/tag/v1.4.1
147
+ changelog_uri: https://github.com/lostisland/faraday/releases/tag/v2.14.2
201
148
  source_code_uri: https://github.com/lostisland/faraday
202
149
  bug_tracker_uri: https://github.com/lostisland/faraday/issues
203
- post_install_message:
150
+ rubygems_mfa_required: 'true'
204
151
  rdoc_options: []
205
152
  require_paths:
206
153
  - lib
@@ -209,15 +156,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
209
156
  requirements:
210
157
  - - ">="
211
158
  - !ruby/object:Gem::Version
212
- version: '2.4'
159
+ version: '3.0'
213
160
  required_rubygems_version: !ruby/object:Gem::Requirement
214
161
  requirements:
215
162
  - - ">="
216
163
  - !ruby/object:Gem::Version
217
164
  version: '0'
218
165
  requirements: []
219
- rubygems_version: 3.0.3.1
220
- signing_key:
166
+ rubygems_version: 3.6.9
221
167
  specification_version: 4
222
168
  summary: HTTP/REST API client library.
223
169
  test_files: []
@@ -1,289 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Faraday
4
- class Adapter
5
- # EventMachine adapter. This adapter is useful for either asynchronous
6
- # requests when in an EM reactor loop, or for making parallel requests in
7
- # synchronous code.
8
- class EMHttp < Faraday::Adapter
9
- # Options is a module containing helpers to convert the Faraday env object
10
- # into options hashes for EMHTTP method calls.
11
- module Options
12
- # @return [Hash]
13
- def connection_config(env)
14
- options = {}
15
- configure_proxy(options, env)
16
- configure_timeout(options, env)
17
- configure_socket(options, env)
18
- configure_ssl(options, env)
19
- options
20
- end
21
-
22
- def request_config(env)
23
- options = {
24
- body: read_body(env),
25
- head: env[:request_headers]
26
- # keepalive: true,
27
- # file: 'path/to/file', # stream data off disk
28
- }
29
- configure_compression(options, env)
30
- options
31
- end
32
-
33
- def read_body(env)
34
- body = env[:body]
35
- body.respond_to?(:read) ? body.read : body
36
- end
37
-
38
- # Reads out proxy settings from env into options
39
- def configure_proxy(options, env)
40
- proxy = request_options(env)[:proxy]
41
- return unless proxy
42
-
43
- options[:proxy] = {
44
- host: proxy[:uri].host,
45
- port: proxy[:uri].port,
46
- authorization: [proxy[:user], proxy[:password]]
47
- }
48
- end
49
-
50
- # Reads out host and port settings from env into options
51
- def configure_socket(options, env)
52
- bind = request_options(env)[:bind]
53
- return unless bind
54
-
55
- options[:bind] = {
56
- host: bind[:host],
57
- port: bind[:port]
58
- }
59
- end
60
-
61
- # Reads out SSL certificate settings from env into options
62
- def configure_ssl(options, env)
63
- return unless env[:url].scheme == 'https' && env[:ssl]
64
-
65
- options[:ssl] = {
66
- cert_chain_file: env[:ssl][:ca_file],
67
- verify_peer: env[:ssl].fetch(:verify, true)
68
- }
69
- end
70
-
71
- # Reads out timeout settings from env into options
72
- def configure_timeout(options, env)
73
- req = request_options(env)
74
- options[:inactivity_timeout] = request_timeout(:read, req)
75
- options[:connect_timeout] = request_timeout(:open, req)
76
- end
77
-
78
- # Reads out compression header settings from env into options
79
- def configure_compression(options, env)
80
- return unless (env[:method] == :get) &&
81
- !options[:head].key?('accept-encoding')
82
-
83
- options[:head]['accept-encoding'] = 'gzip, compressed'
84
- end
85
-
86
- def request_options(env)
87
- env[:request]
88
- end
89
- end
90
-
91
- include Options
92
-
93
- dependency do
94
- require 'em-http'
95
-
96
- begin
97
- require 'openssl'
98
- rescue LoadError
99
- warn 'Warning: no such file to load -- openssl. ' \
100
- 'Make sure it is installed if you want HTTPS support'
101
- else
102
- require 'em-http/version'
103
- if EventMachine::HttpRequest::VERSION < '1.1.6'
104
- require 'faraday/adapter/em_http_ssl_patch'
105
- end
106
- end
107
- end
108
-
109
- self.supports_parallel = true
110
-
111
- # @return [Manager]
112
- def self.setup_parallel_manager(_options = nil)
113
- Manager.new
114
- end
115
-
116
- def call(env)
117
- super
118
- perform_request env
119
- @app.call env
120
- end
121
-
122
- def perform_request(env)
123
- if parallel?(env)
124
- manager = env[:parallel_manager]
125
- manager.add do
126
- perform_single_request(env)
127
- .callback { env[:response].finish(env) }
128
- end
129
- elsif EventMachine.reactor_running?
130
- # EM is running: instruct upstream that this is an async request
131
- env[:parallel_manager] = true
132
- perform_single_request(env)
133
- .callback { env[:response].finish(env) }
134
- .errback do
135
- # TODO: no way to communicate the error in async mode
136
- raise NotImplementedError
137
- end
138
- else
139
- error = nil
140
- # start EM, block until request is completed
141
- EventMachine.run do
142
- perform_single_request(env)
143
- .callback { EventMachine.stop }
144
- .errback do |client|
145
- error = error_message(client)
146
- EventMachine.stop
147
- end
148
- end
149
- raise_error(error) if error
150
- end
151
- rescue EventMachine::Connectify::CONNECTError => e
152
- if e.message.include?('Proxy Authentication Required')
153
- raise Faraday::ConnectionFailed,
154
- %(407 "Proxy Authentication Required ")
155
- end
156
-
157
- raise Faraday::ConnectionFailed, e
158
- rescue StandardError => e
159
- if defined?(::OpenSSL::SSL::SSLError) && \
160
- e.is_a?(::OpenSSL::SSL::SSLError)
161
- raise Faraday::SSLError, e
162
- end
163
-
164
- raise
165
- end
166
-
167
- # TODO: reuse the connection to support pipelining
168
- def perform_single_request(env)
169
- req = create_request(env)
170
- req = req.setup_request(env[:method], request_config(env))
171
- req.callback do |client|
172
- if env[:request].stream_response?
173
- warn "Streaming downloads for #{self.class.name} " \
174
- 'are not yet implemented.'
175
- env[:request].on_data.call(
176
- client.response,
177
- client.response.bytesize
178
- )
179
- end
180
- status = client.response_header.status
181
- reason = client.response_header.http_reason
182
- save_response(env, status, client.response, nil, reason) do |headers|
183
- client.response_header.each do |name, value|
184
- headers[name.to_sym] = value
185
- end
186
- end
187
- end
188
- end
189
-
190
- def create_request(env)
191
- EventMachine::HttpRequest.new(
192
- env[:url], connection_config(env).merge(@connection_options)
193
- )
194
- end
195
-
196
- def error_message(client)
197
- client.error || 'request failed'
198
- end
199
-
200
- def raise_error(msg)
201
- error_class = Faraday::ClientError
202
- if timeout_message?(msg)
203
- error_class = Faraday::TimeoutError
204
- msg = 'request timed out'
205
- elsif msg == Errno::ECONNREFUSED
206
- error_class = Faraday::ConnectionFailed
207
- msg = 'connection refused'
208
- elsif msg == 'connection closed by server'
209
- error_class = Faraday::ConnectionFailed
210
- end
211
- raise error_class, msg
212
- end
213
-
214
- def timeout_message?(msg)
215
- msg == Errno::ETIMEDOUT ||
216
- (msg.is_a?(String) && msg.include?('timeout error'))
217
- end
218
-
219
- # @return [Boolean]
220
- def parallel?(env)
221
- !!env[:parallel_manager]
222
- end
223
-
224
- # This parallel manager is designed to start an EventMachine loop
225
- # and block until all registered requests have been completed.
226
- class Manager
227
- # @see reset
228
- def initialize
229
- reset
230
- end
231
-
232
- # Re-initializes instance variables
233
- def reset
234
- @registered_procs = []
235
- @num_registered = 0
236
- @num_succeeded = 0
237
- @errors = []
238
- @running = false
239
- end
240
-
241
- # @return [Boolean]
242
- def running?
243
- @running
244
- end
245
-
246
- def add(&block)
247
- if running?
248
- perform_request(&block)
249
- else
250
- @registered_procs << block
251
- end
252
- @num_registered += 1
253
- end
254
-
255
- def run
256
- if @num_registered.positive?
257
- @running = true
258
- EventMachine.run do
259
- @registered_procs.each do |proc|
260
- perform_request(&proc)
261
- end
262
- end
263
- unless @errors.empty?
264
- raise Faraday::ClientError, @errors.first || 'connection failed'
265
- end
266
- end
267
- ensure
268
- reset
269
- end
270
-
271
- def perform_request
272
- client = yield
273
- client.callback do
274
- @num_succeeded += 1
275
- check_finished
276
- end
277
- client.errback do
278
- @errors << client.error
279
- check_finished
280
- end
281
- end
282
-
283
- def check_finished
284
- EventMachine.stop if @num_succeeded + @errors.size == @num_registered
285
- end
286
- end
287
- end
288
- end
289
- end