faraday 1.1.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,286 +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 'em-http'
94
-
95
- self.supports_parallel = true
96
-
97
- # @return [Manager]
98
- def self.setup_parallel_manager(_options = nil)
99
- Manager.new
100
- end
101
-
102
- def call(env)
103
- super
104
- perform_request env
105
- @app.call env
106
- end
107
-
108
- def perform_request(env)
109
- if parallel?(env)
110
- manager = env[:parallel_manager]
111
- manager.add do
112
- perform_single_request(env)
113
- .callback { env[:response].finish(env) }
114
- end
115
- elsif EventMachine.reactor_running?
116
- # EM is running: instruct upstream that this is an async request
117
- env[:parallel_manager] = true
118
- perform_single_request(env)
119
- .callback { env[:response].finish(env) }
120
- .errback do
121
- # TODO: no way to communicate the error in async mode
122
- raise NotImplementedError
123
- end
124
- else
125
- error = nil
126
- # start EM, block until request is completed
127
- EventMachine.run do
128
- perform_single_request(env)
129
- .callback { EventMachine.stop }
130
- .errback do |client|
131
- error = error_message(client)
132
- EventMachine.stop
133
- end
134
- end
135
- raise_error(error) if error
136
- end
137
- rescue EventMachine::Connectify::CONNECTError => e
138
- if e.message.include?('Proxy Authentication Required')
139
- raise Faraday::ConnectionFailed,
140
- %(407 "Proxy Authentication Required ")
141
- end
142
-
143
- raise Faraday::ConnectionFailed, e
144
- rescue StandardError => e
145
- if defined?(::OpenSSL::SSL::SSLError) && \
146
- e.is_a?(::OpenSSL::SSL::SSLError)
147
- raise Faraday::SSLError, e
148
- end
149
-
150
- raise
151
- end
152
-
153
- # TODO: reuse the connection to support pipelining
154
- def perform_single_request(env)
155
- req = create_request(env)
156
- req = req.setup_request(env[:method], request_config(env))
157
- req.callback do |client|
158
- if env[:request].stream_response?
159
- warn "Streaming downloads for #{self.class.name} " \
160
- 'are not yet implemented.'
161
- env[:request].on_data.call(
162
- client.response,
163
- client.response.bytesize
164
- )
165
- end
166
- status = client.response_header.status
167
- reason = client.response_header.http_reason
168
- save_response(env, status, client.response, nil, reason) do |headers|
169
- client.response_header.each do |name, value|
170
- headers[name.to_sym] = value
171
- end
172
- end
173
- end
174
- end
175
-
176
- def create_request(env)
177
- EventMachine::HttpRequest.new(
178
- env[:url], connection_config(env).merge(@connection_options)
179
- )
180
- end
181
-
182
- def error_message(client)
183
- client.error || 'request failed'
184
- end
185
-
186
- def raise_error(msg)
187
- error_class = Faraday::ClientError
188
- if timeout_message?(msg)
189
- error_class = Faraday::TimeoutError
190
- msg = 'request timed out'
191
- elsif msg == Errno::ECONNREFUSED
192
- error_class = Faraday::ConnectionFailed
193
- msg = 'connection refused'
194
- elsif msg == 'connection closed by server'
195
- error_class = Faraday::ConnectionFailed
196
- end
197
- raise error_class, msg
198
- end
199
-
200
- def timeout_message?(msg)
201
- msg == Errno::ETIMEDOUT ||
202
- (msg.is_a?(String) && msg.include?('timeout error'))
203
- end
204
-
205
- # @return [Boolean]
206
- def parallel?(env)
207
- !!env[:parallel_manager]
208
- end
209
-
210
- # This parallel manager is designed to start an EventMachine loop
211
- # and block until all registered requests have been completed.
212
- class Manager
213
- # @see reset
214
- def initialize
215
- reset
216
- end
217
-
218
- # Re-initializes instance variables
219
- def reset
220
- @registered_procs = []
221
- @num_registered = 0
222
- @num_succeeded = 0
223
- @errors = []
224
- @running = false
225
- end
226
-
227
- # @return [Boolean]
228
- def running?
229
- @running
230
- end
231
-
232
- def add(&block)
233
- if running?
234
- perform_request(&block)
235
- else
236
- @registered_procs << block
237
- end
238
- @num_registered += 1
239
- end
240
-
241
- def run
242
- if @num_registered.positive?
243
- @running = true
244
- EventMachine.run do
245
- @registered_procs.each do |proc|
246
- perform_request(&proc)
247
- end
248
- end
249
- unless @errors.empty?
250
- raise Faraday::ClientError, @errors.first || 'connection failed'
251
- end
252
- end
253
- ensure
254
- reset
255
- end
256
-
257
- def perform_request
258
- client = yield
259
- client.callback do
260
- @num_succeeded += 1
261
- check_finished
262
- end
263
- client.errback do
264
- @errors << client.error
265
- check_finished
266
- end
267
- end
268
-
269
- def check_finished
270
- EventMachine.stop if @num_succeeded + @errors.size == @num_registered
271
- end
272
- end
273
- end
274
- end
275
- end
276
-
277
- if Faraday::Adapter::EMHttp.loaded?
278
- begin
279
- require 'openssl'
280
- rescue LoadError
281
- warn 'Warning: no such file to load -- openssl. ' \
282
- 'Make sure it is installed if you want HTTPS support'
283
- else
284
- require 'faraday/adapter/em_http_ssl_patch'
285
- end
286
- end
@@ -1,62 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'openssl'
4
- require 'em-http'
5
-
6
- # EventMachine patch to make SSL work.
7
- module EmHttpSslPatch
8
- def ssl_verify_peer(cert_string)
9
- begin
10
- @last_seen_cert = OpenSSL::X509::Certificate.new(cert_string)
11
- rescue OpenSSL::X509::CertificateError
12
- return false
13
- end
14
-
15
- unless certificate_store.verify(@last_seen_cert)
16
- raise OpenSSL::SSL::SSLError,
17
- %(unable to verify the server certificate for "#{host}")
18
- end
19
-
20
- begin
21
- certificate_store.add_cert(@last_seen_cert)
22
- rescue OpenSSL::X509::StoreError => e
23
- raise e unless e.message == 'cert already in hash table'
24
- end
25
- true
26
- end
27
-
28
- def ssl_handshake_completed
29
- return true unless verify_peer?
30
-
31
- unless verified_cert_identity?
32
- raise OpenSSL::SSL::SSLError,
33
- %(host "#{host}" does not match the server certificate)
34
- end
35
-
36
- true
37
- end
38
-
39
- def verify_peer?
40
- parent.connopts.tls[:verify_peer]
41
- end
42
-
43
- def verified_cert_identity?
44
- OpenSSL::SSL.verify_certificate_identity(@last_seen_cert, host)
45
- end
46
-
47
- def host
48
- parent.uri.host
49
- end
50
-
51
- def certificate_store
52
- @certificate_store ||= begin
53
- store = OpenSSL::X509::Store.new
54
- store.set_default_paths
55
- ca_file = parent.connopts.tls[:cert_chain_file]
56
- store.add_file(ca_file) if ca_file
57
- store
58
- end
59
- end
60
- end
61
-
62
- EventMachine::HttpStubConnection.include(EmHttpSslPatch)
@@ -1,150 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'uri'
4
-
5
- module Faraday
6
- class Adapter
7
- # EventMachine Synchrony adapter.
8
- class EMSynchrony < Faraday::Adapter
9
- include EMHttp::Options
10
-
11
- dependency do
12
- require 'em-synchrony/em-http'
13
- require 'em-synchrony/em-multi'
14
- require 'fiber'
15
- end
16
-
17
- self.supports_parallel = true
18
-
19
- # @return [ParallelManager]
20
- def self.setup_parallel_manager(_options = nil)
21
- ParallelManager.new
22
- end
23
-
24
- def call(env)
25
- super
26
- request = create_request(env)
27
-
28
- http_method = env[:method].to_s.downcase.to_sym
29
-
30
- if env[:parallel_manager]
31
- # Queue requests for parallel execution.
32
- execute_parallel_request(env, request, http_method)
33
- else
34
- # Execute single request.
35
- execute_single_request(env, request, http_method)
36
- end
37
-
38
- @app.call env
39
- rescue Errno::ECONNREFUSED
40
- raise Faraday::ConnectionFailed, $ERROR_INFO
41
- rescue EventMachine::Connectify::CONNECTError => e
42
- if e.message.include?('Proxy Authentication Required')
43
- raise Faraday::ConnectionFailed,
44
- %(407 "Proxy Authentication Required")
45
- end
46
-
47
- raise Faraday::ConnectionFailed, e
48
- rescue Errno::ETIMEDOUT => e
49
- raise Faraday::TimeoutError, e
50
- rescue RuntimeError => e
51
- if e.message == 'connection closed by server'
52
- raise Faraday::ConnectionFailed, e
53
- end
54
-
55
- raise Faraday::TimeoutError, e if e.message.include?('timeout error')
56
-
57
- raise
58
- rescue StandardError => e
59
- if defined?(OpenSSL) && e.is_a?(OpenSSL::SSL::SSLError)
60
- raise Faraday::SSLError, e
61
- end
62
-
63
- raise
64
- end
65
-
66
- def create_request(env)
67
- EventMachine::HttpRequest.new(
68
- Utils::URI(env[:url].to_s),
69
- connection_config(env).merge(@connection_options)
70
- )
71
- end
72
-
73
- private
74
-
75
- def execute_parallel_request(env, request, http_method)
76
- env[:parallel_manager].add(request, http_method,
77
- request_config(env)) do |resp|
78
- if (req = env[:request]).stream_response?
79
- warn "Streaming downloads for #{self.class.name} " \
80
- 'are not yet implemented.'
81
- req.on_data.call(resp.response, resp.response.bytesize)
82
- end
83
-
84
- save_response(env, resp.response_header.status,
85
- resp.response) do |resp_headers|
86
- resp.response_header.each do |name, value|
87
- resp_headers[name.to_sym] = value
88
- end
89
- end
90
-
91
- # Finalize the response object with values from `env`.
92
- env[:response].finish(env)
93
- end
94
- end
95
-
96
- def execute_single_request(env, request, http_method)
97
- block = -> { request.send(http_method, request_config(env)) }
98
- client = call_block(block)
99
-
100
- raise client.error if client&.error
101
-
102
- if env[:request].stream_response?
103
- warn "Streaming downloads for #{self.class.name} " \
104
- 'are not yet implemented.'
105
- env[:request].on_data.call(
106
- client.response,
107
- client.response.bytesize
108
- )
109
- end
110
- status = client.response_header.status
111
- reason = client.response_header.http_reason
112
- save_response(env, status, client.response, nil, reason) do |headers|
113
- client.response_header.each do |name, value|
114
- headers[name.to_sym] = value
115
- end
116
- end
117
- end
118
-
119
- def call_block(block)
120
- client = nil
121
-
122
- if EM.reactor_running?
123
- client = block.call
124
- else
125
- EM.run do
126
- Fiber.new do
127
- client = block.call
128
- EM.stop
129
- end.resume
130
- end
131
- end
132
-
133
- client
134
- end
135
- end
136
- end
137
- end
138
-
139
- require 'faraday/adapter/em_synchrony/parallel_manager'
140
-
141
- if Faraday::Adapter::EMSynchrony.loaded?
142
- begin
143
- require 'openssl'
144
- rescue LoadError
145
- warn 'Warning: no such file to load -- openssl. ' \
146
- 'Make sure it is installed if you want HTTPS support'
147
- else
148
- require 'faraday/adapter/em_http_ssl_patch'
149
- end
150
- end