faraday 0.9.2 → 1.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +276 -0
- data/LICENSE.md +1 -1
- data/README.md +27 -217
- data/Rakefile +7 -0
- data/UPGRADING.md +55 -0
- data/examples/client_spec.rb +65 -0
- data/examples/client_test.rb +79 -0
- data/lib/faraday/adapter/em_http.rb +149 -101
- data/lib/faraday/adapter/em_http_ssl_patch.rb +25 -19
- data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +18 -15
- data/lib/faraday/adapter/em_synchrony.rb +106 -56
- data/lib/faraday/adapter/excon.rb +98 -55
- data/lib/faraday/adapter/httpclient.rb +89 -55
- data/lib/faraday/adapter/net_http.rb +132 -53
- data/lib/faraday/adapter/net_http_persistent.rb +70 -28
- data/lib/faraday/adapter/patron.rb +92 -38
- data/lib/faraday/adapter/rack.rb +30 -13
- data/lib/faraday/adapter/test.rb +136 -52
- data/lib/faraday/adapter/typhoeus.rb +7 -115
- data/lib/faraday/adapter.rb +89 -20
- data/lib/faraday/adapter_registry.rb +28 -0
- data/lib/faraday/autoload.rb +47 -36
- data/lib/faraday/connection.rb +345 -168
- data/lib/faraday/dependency_loader.rb +37 -0
- data/lib/faraday/encoders/flat_params_encoder.rb +98 -0
- data/lib/faraday/encoders/nested_params_encoder.rb +171 -0
- data/lib/faraday/error.rb +108 -29
- data/lib/faraday/file_part.rb +128 -0
- data/lib/faraday/logging/formatter.rb +105 -0
- data/lib/faraday/middleware.rb +12 -28
- data/lib/faraday/middleware_registry.rb +129 -0
- data/lib/faraday/options/connection_options.rb +22 -0
- data/lib/faraday/options/env.rb +181 -0
- data/lib/faraday/options/proxy_options.rb +28 -0
- data/lib/faraday/options/request_options.rb +22 -0
- data/lib/faraday/options/ssl_options.rb +59 -0
- data/lib/faraday/options.rb +57 -194
- data/lib/faraday/param_part.rb +53 -0
- data/lib/faraday/parameters.rb +4 -196
- data/lib/faraday/rack_builder.rb +74 -39
- data/lib/faraday/request/authorization.rb +42 -31
- data/lib/faraday/request/basic_authentication.rb +14 -7
- data/lib/faraday/request/instrumentation.rb +45 -27
- data/lib/faraday/request/multipart.rb +81 -45
- data/lib/faraday/request/retry.rb +211 -126
- data/lib/faraday/request/token_authentication.rb +15 -10
- data/lib/faraday/request/url_encoded.rb +41 -23
- data/lib/faraday/request.rb +84 -30
- data/lib/faraday/response/logger.rb +22 -48
- data/lib/faraday/response/raise_error.rb +38 -14
- data/lib/faraday/response.rb +27 -16
- data/lib/faraday/utils/headers.rb +139 -0
- data/lib/faraday/utils/params_hash.rb +61 -0
- data/lib/faraday/utils.rb +28 -228
- data/lib/faraday.rb +102 -204
- data/spec/external_adapters/faraday_specs_setup.rb +14 -0
- data/spec/faraday/adapter/em_http_spec.rb +47 -0
- data/spec/faraday/adapter/em_synchrony_spec.rb +16 -0
- data/spec/faraday/adapter/excon_spec.rb +49 -0
- data/spec/faraday/adapter/httpclient_spec.rb +73 -0
- data/spec/faraday/adapter/net_http_persistent_spec.rb +57 -0
- data/spec/faraday/adapter/net_http_spec.rb +64 -0
- data/spec/faraday/adapter/patron_spec.rb +18 -0
- data/spec/faraday/adapter/rack_spec.rb +8 -0
- data/spec/faraday/adapter/typhoeus_spec.rb +7 -0
- data/spec/faraday/adapter_registry_spec.rb +28 -0
- data/spec/faraday/adapter_spec.rb +55 -0
- data/spec/faraday/composite_read_io_spec.rb +80 -0
- data/spec/faraday/connection_spec.rb +691 -0
- data/spec/faraday/error_spec.rb +45 -0
- data/spec/faraday/middleware_spec.rb +26 -0
- data/spec/faraday/options/env_spec.rb +70 -0
- data/spec/faraday/options/options_spec.rb +297 -0
- data/spec/faraday/options/proxy_options_spec.rb +37 -0
- data/spec/faraday/options/request_options_spec.rb +19 -0
- data/spec/faraday/params_encoders/flat_spec.rb +34 -0
- data/spec/faraday/params_encoders/nested_spec.rb +134 -0
- data/spec/faraday/rack_builder_spec.rb +196 -0
- data/spec/faraday/request/authorization_spec.rb +88 -0
- data/spec/faraday/request/instrumentation_spec.rb +76 -0
- data/spec/faraday/request/multipart_spec.rb +274 -0
- data/spec/faraday/request/retry_spec.rb +242 -0
- data/spec/faraday/request/url_encoded_spec.rb +70 -0
- data/spec/faraday/request_spec.rb +109 -0
- data/spec/faraday/response/logger_spec.rb +220 -0
- data/spec/faraday/response/middleware_spec.rb +52 -0
- data/spec/faraday/response/raise_error_spec.rb +106 -0
- data/spec/faraday/response_spec.rb +75 -0
- data/spec/faraday/utils/headers_spec.rb +82 -0
- data/spec/faraday/utils_spec.rb +56 -0
- data/spec/faraday_spec.rb +37 -0
- data/spec/spec_helper.rb +132 -0
- data/spec/support/disabling_stub.rb +14 -0
- data/spec/support/fake_safe_buffer.rb +15 -0
- data/spec/support/helper_methods.rb +133 -0
- data/spec/support/shared_examples/adapter.rb +104 -0
- data/spec/support/shared_examples/params_encoder.rb +18 -0
- data/spec/support/shared_examples/request_method.rb +234 -0
- data/spec/support/streaming_response_checker.rb +35 -0
- data/spec/support/webmock_rack_app.rb +68 -0
- metadata +110 -64
- data/lib/faraday/upload_io.rb +0 -67
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Requires Ruby with test-unit and faraday gems.
|
|
4
|
+
# ruby client_test.rb
|
|
5
|
+
|
|
6
|
+
require 'faraday'
|
|
7
|
+
require 'json'
|
|
8
|
+
require 'test/unit'
|
|
9
|
+
|
|
10
|
+
# Example API client
|
|
11
|
+
class Client
|
|
12
|
+
def initialize(conn)
|
|
13
|
+
@conn = conn
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def sushi(jname)
|
|
17
|
+
res = @conn.get("/#{jname}")
|
|
18
|
+
data = JSON.parse(res.body)
|
|
19
|
+
data['name']
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Example API client test
|
|
24
|
+
class ClientTest < Test::Unit::TestCase
|
|
25
|
+
def test_sushi_name
|
|
26
|
+
stubs = Faraday::Adapter::Test::Stubs.new
|
|
27
|
+
stubs.get('/ebi') do |env|
|
|
28
|
+
# optional: you can inspect the Faraday::Env
|
|
29
|
+
assert_equal '/ebi', env.url.path
|
|
30
|
+
[
|
|
31
|
+
200,
|
|
32
|
+
{ 'Content-Type': 'application/javascript' },
|
|
33
|
+
'{"name": "shrimp"}'
|
|
34
|
+
]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# uncomment to trigger stubs.verify_stubbed_calls failure
|
|
38
|
+
# stubs.get('/unused') { [404, {}, ''] }
|
|
39
|
+
|
|
40
|
+
cli = client(stubs)
|
|
41
|
+
assert_equal 'shrimp', cli.sushi('ebi')
|
|
42
|
+
stubs.verify_stubbed_calls
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def test_sushi_404
|
|
46
|
+
stubs = Faraday::Adapter::Test::Stubs.new
|
|
47
|
+
stubs.get('/ebi') do
|
|
48
|
+
[
|
|
49
|
+
404,
|
|
50
|
+
{ 'Content-Type': 'application/javascript' },
|
|
51
|
+
'{}'
|
|
52
|
+
]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
cli = client(stubs)
|
|
56
|
+
assert_nil cli.sushi('ebi')
|
|
57
|
+
stubs.verify_stubbed_calls
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def test_sushi_exception
|
|
61
|
+
stubs = Faraday::Adapter::Test::Stubs.new
|
|
62
|
+
stubs.get('/ebi') do
|
|
63
|
+
raise Faraday::ConnectionFailed, nil
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
cli = client(stubs)
|
|
67
|
+
assert_raise Faraday::ConnectionFailed do
|
|
68
|
+
cli.sushi('ebi')
|
|
69
|
+
end
|
|
70
|
+
stubs.verify_stubbed_calls
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def client(stubs)
|
|
74
|
+
conn = Faraday.new do |builder|
|
|
75
|
+
builder.adapter :test, stubs
|
|
76
|
+
end
|
|
77
|
+
Client.new(conn)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Faraday
|
|
2
4
|
class Adapter
|
|
3
|
-
# EventMachine adapter is useful for either asynchronous
|
|
4
|
-
# when in EM reactor loop or for making parallel requests in
|
|
5
|
+
# EventMachine adapter. This adapter is useful for either asynchronous
|
|
6
|
+
# requests when in an EM reactor loop, or for making parallel requests in
|
|
5
7
|
# synchronous code.
|
|
6
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.
|
|
7
11
|
module Options
|
|
12
|
+
# @return [Hash]
|
|
8
13
|
def connection_config(env)
|
|
9
14
|
options = {}
|
|
10
15
|
configure_proxy(options, env)
|
|
@@ -16,10 +21,10 @@ module Faraday
|
|
|
16
21
|
|
|
17
22
|
def request_config(env)
|
|
18
23
|
options = {
|
|
19
|
-
:
|
|
20
|
-
:
|
|
21
|
-
# :
|
|
22
|
-
# :
|
|
24
|
+
body: read_body(env),
|
|
25
|
+
head: env[:request_headers]
|
|
26
|
+
# keepalive: true,
|
|
27
|
+
# file: 'path/to/file', # stream data off disk
|
|
23
28
|
}
|
|
24
29
|
configure_compression(options, env)
|
|
25
30
|
options
|
|
@@ -30,44 +35,52 @@ module Faraday
|
|
|
30
35
|
body.respond_to?(:read) ? body.read : body
|
|
31
36
|
end
|
|
32
37
|
|
|
38
|
+
# Reads out proxy settings from env into options
|
|
33
39
|
def configure_proxy(options, env)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
+
}
|
|
41
48
|
end
|
|
42
49
|
|
|
50
|
+
# Reads out host and port settings from env into options
|
|
43
51
|
def configure_socket(options, env)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
52
|
+
bind = request_options(env)[:bind]
|
|
53
|
+
return unless bind
|
|
54
|
+
|
|
55
|
+
options[:bind] = {
|
|
56
|
+
host: bind[:host],
|
|
57
|
+
port: bind[:port]
|
|
58
|
+
}
|
|
50
59
|
end
|
|
51
60
|
|
|
61
|
+
# Reads out SSL certificate settings from env into options
|
|
52
62
|
def configure_ssl(options, env)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
+
}
|
|
59
69
|
end
|
|
60
70
|
|
|
71
|
+
# Reads out timeout settings from env into options
|
|
61
72
|
def configure_timeout(options, env)
|
|
62
|
-
|
|
63
|
-
options[:
|
|
64
|
-
options[:connect_timeout] =
|
|
73
|
+
req = request_options(env)
|
|
74
|
+
options[:inactivity_timeout] = request_timeout(:read, req)
|
|
75
|
+
options[:connect_timeout] = request_timeout(:open, req)
|
|
65
76
|
end
|
|
66
77
|
|
|
78
|
+
# Reads out compression header settings from env into options
|
|
67
79
|
def configure_compression(options, env)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
80
|
+
return unless (env[:method] == :get) &&
|
|
81
|
+
!options[:head].key?('accept-encoding')
|
|
82
|
+
|
|
83
|
+
options[:head]['accept-encoding'] = 'gzip, compressed'
|
|
71
84
|
end
|
|
72
85
|
|
|
73
86
|
def request_options(env)
|
|
@@ -81,7 +94,8 @@ module Faraday
|
|
|
81
94
|
|
|
82
95
|
self.supports_parallel = true
|
|
83
96
|
|
|
84
|
-
|
|
97
|
+
# @return [Manager]
|
|
98
|
+
def self.setup_parallel_manager(_options = nil)
|
|
85
99
|
Manager.new
|
|
86
100
|
end
|
|
87
101
|
|
|
@@ -94,89 +108,113 @@ module Faraday
|
|
|
94
108
|
def perform_request(env)
|
|
95
109
|
if parallel?(env)
|
|
96
110
|
manager = env[:parallel_manager]
|
|
97
|
-
manager.add
|
|
98
|
-
perform_single_request(env)
|
|
99
|
-
callback { env[:response].finish(env) }
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
error = error_message(client)
|
|
110
|
-
EventMachine.stop
|
|
111
|
-
}
|
|
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
|
|
112
123
|
end
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
perform_single_request(env)
|
|
118
|
-
callback {
|
|
119
|
-
errback
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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
|
|
123
134
|
end
|
|
135
|
+
raise_error(error) if error
|
|
124
136
|
end
|
|
125
|
-
rescue EventMachine::Connectify::CONNECTError =>
|
|
126
|
-
if
|
|
127
|
-
raise
|
|
128
|
-
|
|
129
|
-
raise Error::ConnectionFailed, err
|
|
137
|
+
rescue EventMachine::Connectify::CONNECTError => e
|
|
138
|
+
if e.message.include?('Proxy Authentication Required')
|
|
139
|
+
raise Faraday::ConnectionFailed,
|
|
140
|
+
%(407 "Proxy Authentication Required ")
|
|
130
141
|
end
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
raise
|
|
142
|
+
|
|
143
|
+
raise Faraday::ConnectionFailed, e
|
|
144
|
+
rescue StandardError => e
|
|
145
|
+
if defined?(OpenSSL) && e.is_a?(OpenSSL::SSL::SSLError)
|
|
146
|
+
raise Faraday::SSLError, e
|
|
136
147
|
end
|
|
148
|
+
|
|
149
|
+
raise
|
|
137
150
|
end
|
|
138
151
|
|
|
139
152
|
# TODO: reuse the connection to support pipelining
|
|
140
153
|
def perform_single_request(env)
|
|
141
|
-
req =
|
|
142
|
-
req.setup_request(env[:method], request_config(env))
|
|
143
|
-
|
|
154
|
+
req = create_request(env)
|
|
155
|
+
req = req.setup_request(env[:method], request_config(env))
|
|
156
|
+
req.callback do |client|
|
|
157
|
+
if env[:request].stream_response?
|
|
158
|
+
warn "Streaming downloads for #{self.class.name} " \
|
|
159
|
+
'are not yet implemented.'
|
|
160
|
+
env[:request].on_data.call(
|
|
161
|
+
client.response,
|
|
162
|
+
client.response.bytesize
|
|
163
|
+
)
|
|
164
|
+
end
|
|
165
|
+
status = client.response_header.status
|
|
166
|
+
reason = client.response_header.http_reason
|
|
167
|
+
save_response(env, status, client.response, nil, reason) do |headers|
|
|
144
168
|
client.response_header.each do |name, value|
|
|
145
|
-
|
|
169
|
+
headers[name.to_sym] = value
|
|
146
170
|
end
|
|
147
171
|
end
|
|
148
|
-
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def create_request(env)
|
|
176
|
+
EventMachine::HttpRequest.new(
|
|
177
|
+
env[:url], connection_config(env).merge(@connection_options)
|
|
178
|
+
)
|
|
149
179
|
end
|
|
150
180
|
|
|
151
181
|
def error_message(client)
|
|
152
|
-
client.error
|
|
182
|
+
client.error || 'request failed'
|
|
153
183
|
end
|
|
154
184
|
|
|
155
185
|
def raise_error(msg)
|
|
156
|
-
|
|
157
|
-
if msg
|
|
158
|
-
|
|
159
|
-
msg =
|
|
186
|
+
error_class = Faraday::ClientError
|
|
187
|
+
if timeout_message?(msg)
|
|
188
|
+
error_class = Faraday::TimeoutError
|
|
189
|
+
msg = 'request timed out'
|
|
160
190
|
elsif msg == Errno::ECONNREFUSED
|
|
161
|
-
|
|
162
|
-
msg =
|
|
163
|
-
elsif msg ==
|
|
164
|
-
|
|
191
|
+
error_class = Faraday::ConnectionFailed
|
|
192
|
+
msg = 'connection refused'
|
|
193
|
+
elsif msg == 'connection closed by server'
|
|
194
|
+
error_class = Faraday::ConnectionFailed
|
|
165
195
|
end
|
|
166
|
-
raise
|
|
196
|
+
raise error_class, msg
|
|
167
197
|
end
|
|
168
198
|
|
|
199
|
+
def timeout_message?(msg)
|
|
200
|
+
msg == Errno::ETIMEDOUT ||
|
|
201
|
+
(msg.is_a?(String) && msg.include?('timeout error'))
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# @return [Boolean]
|
|
169
205
|
def parallel?(env)
|
|
170
206
|
!!env[:parallel_manager]
|
|
171
207
|
end
|
|
172
208
|
|
|
173
|
-
#
|
|
209
|
+
# This parallel manager is designed to start an EventMachine loop
|
|
174
210
|
# and block until all registered requests have been completed.
|
|
175
211
|
class Manager
|
|
212
|
+
# @see reset
|
|
176
213
|
def initialize
|
|
177
214
|
reset
|
|
178
215
|
end
|
|
179
216
|
|
|
217
|
+
# Re-initializes instance variables
|
|
180
218
|
def reset
|
|
181
219
|
@registered_procs = []
|
|
182
220
|
@num_registered = 0
|
|
@@ -185,27 +223,30 @@ module Faraday
|
|
|
185
223
|
@running = false
|
|
186
224
|
end
|
|
187
225
|
|
|
188
|
-
|
|
226
|
+
# @return [Boolean]
|
|
227
|
+
def running?
|
|
228
|
+
@running
|
|
229
|
+
end
|
|
189
230
|
|
|
190
|
-
def add
|
|
231
|
+
def add(&block)
|
|
191
232
|
if running?
|
|
192
233
|
perform_request { yield }
|
|
193
234
|
else
|
|
194
|
-
@registered_procs <<
|
|
235
|
+
@registered_procs << block
|
|
195
236
|
end
|
|
196
237
|
@num_registered += 1
|
|
197
238
|
end
|
|
198
239
|
|
|
199
240
|
def run
|
|
200
|
-
if @num_registered
|
|
241
|
+
if @num_registered.positive?
|
|
201
242
|
@running = true
|
|
202
243
|
EventMachine.run do
|
|
203
244
|
@registered_procs.each do |proc|
|
|
204
245
|
perform_request(&proc)
|
|
205
246
|
end
|
|
206
247
|
end
|
|
207
|
-
|
|
208
|
-
raise Faraday::
|
|
248
|
+
unless @errors.empty?
|
|
249
|
+
raise Faraday::ClientError, @errors.first || 'connection failed'
|
|
209
250
|
end
|
|
210
251
|
end
|
|
211
252
|
ensure
|
|
@@ -214,24 +255,31 @@ module Faraday
|
|
|
214
255
|
|
|
215
256
|
def perform_request
|
|
216
257
|
client = yield
|
|
217
|
-
client.callback
|
|
218
|
-
|
|
258
|
+
client.callback do
|
|
259
|
+
@num_succeeded += 1
|
|
260
|
+
check_finished
|
|
261
|
+
end
|
|
262
|
+
client.errback do
|
|
263
|
+
@errors << client.error
|
|
264
|
+
check_finished
|
|
265
|
+
end
|
|
219
266
|
end
|
|
220
267
|
|
|
221
268
|
def check_finished
|
|
222
|
-
if @num_succeeded + @errors.size == @num_registered
|
|
223
|
-
EventMachine.stop
|
|
224
|
-
end
|
|
269
|
+
EventMachine.stop if @num_succeeded + @errors.size == @num_registered
|
|
225
270
|
end
|
|
226
271
|
end
|
|
227
272
|
end
|
|
228
273
|
end
|
|
229
274
|
end
|
|
230
275
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
276
|
+
if Faraday::Adapter::EMHttp.loaded?
|
|
277
|
+
begin
|
|
278
|
+
require 'openssl'
|
|
279
|
+
rescue LoadError
|
|
280
|
+
warn 'Warning: no such file to load -- openssl. ' \
|
|
281
|
+
'Make sure it is installed if you want HTTPS support'
|
|
282
|
+
else
|
|
283
|
+
require 'faraday/adapter/em_http_ssl_patch'
|
|
284
|
+
end
|
|
285
|
+
end
|
|
@@ -1,45 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'openssl'
|
|
2
4
|
require 'em-http'
|
|
3
5
|
|
|
6
|
+
# EventMachine patch to make SSL work.
|
|
4
7
|
module EmHttpSslPatch
|
|
5
8
|
def ssl_verify_peer(cert_string)
|
|
6
|
-
cert = nil
|
|
7
9
|
begin
|
|
8
|
-
|
|
10
|
+
@last_seen_cert = OpenSSL::X509::Certificate.new(cert_string)
|
|
9
11
|
rescue OpenSSL::X509::CertificateError
|
|
10
12
|
return false
|
|
11
13
|
end
|
|
12
14
|
|
|
13
|
-
@last_seen_cert
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
else
|
|
23
|
-
raise OpenSSL::SSL::SSLError.new(%(unable to verify the server certificate for "#{host}"))
|
|
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
24
|
end
|
|
25
|
+
true
|
|
25
26
|
end
|
|
26
27
|
|
|
27
28
|
def ssl_handshake_completed
|
|
28
29
|
return true unless verify_peer?
|
|
29
30
|
|
|
30
|
-
unless
|
|
31
|
-
raise OpenSSL::SSL::SSLError
|
|
32
|
-
|
|
33
|
-
true
|
|
31
|
+
unless verified_cert_identity?
|
|
32
|
+
raise OpenSSL::SSL::SSLError,
|
|
33
|
+
%(host "#{host}" does not match the server certificate)
|
|
34
34
|
end
|
|
35
|
+
|
|
36
|
+
true
|
|
35
37
|
end
|
|
36
38
|
|
|
37
39
|
def verify_peer?
|
|
38
40
|
parent.connopts.tls[:verify_peer]
|
|
39
41
|
end
|
|
40
42
|
|
|
43
|
+
def verified_cert_identity?
|
|
44
|
+
OpenSSL::SSL.verify_certificate_identity(@last_seen_cert, host)
|
|
45
|
+
end
|
|
46
|
+
|
|
41
47
|
def host
|
|
42
|
-
parent.
|
|
48
|
+
parent.uri.host
|
|
43
49
|
end
|
|
44
50
|
|
|
45
51
|
def certificate_store
|
|
@@ -53,4 +59,4 @@ module EmHttpSslPatch
|
|
|
53
59
|
end
|
|
54
60
|
end
|
|
55
61
|
|
|
56
|
-
EventMachine::HttpStubConnection.
|
|
62
|
+
EventMachine::HttpStubConnection.include(EmHttpSslPatch)
|
|
@@ -1,16 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Faraday
|
|
2
4
|
class Adapter
|
|
3
5
|
class EMSynchrony < Faraday::Adapter
|
|
6
|
+
# A parallel manager for EMSynchrony.
|
|
4
7
|
class ParallelManager
|
|
5
|
-
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
+
# Add requests to queue.
|
|
9
|
+
#
|
|
10
|
+
# @param request [EM::HttpRequest]
|
|
11
|
+
# @param method [Symbol, String] HTTP method
|
|
12
|
+
# @param args [Array] the rest of the positional arguments
|
|
8
13
|
def add(request, method, *args, &block)
|
|
9
14
|
queue << {
|
|
10
|
-
:
|
|
11
|
-
:
|
|
12
|
-
:
|
|
13
|
-
:
|
|
15
|
+
request: request,
|
|
16
|
+
method: method,
|
|
17
|
+
args: args,
|
|
18
|
+
block: block
|
|
14
19
|
}
|
|
15
20
|
end
|
|
16
21
|
|
|
@@ -19,19 +24,18 @@ module Faraday
|
|
|
19
24
|
def run
|
|
20
25
|
result = nil
|
|
21
26
|
if !EM.reactor_running?
|
|
22
|
-
EM.run
|
|
27
|
+
EM.run do
|
|
23
28
|
Fiber.new do
|
|
24
29
|
result = perform
|
|
25
30
|
EM.stop
|
|
26
31
|
end.resume
|
|
27
|
-
|
|
32
|
+
end
|
|
28
33
|
else
|
|
29
34
|
result = perform
|
|
30
35
|
end
|
|
31
36
|
result
|
|
32
37
|
end
|
|
33
38
|
|
|
34
|
-
|
|
35
39
|
private
|
|
36
40
|
|
|
37
41
|
# The request queue.
|
|
@@ -59,8 +63,7 @@ module Faraday
|
|
|
59
63
|
# Block fiber until all requests have returned.
|
|
60
64
|
multi.perform
|
|
61
65
|
end
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
end # Faraday
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|