faraday 0.9.1 → 0.16.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 +5 -5
- data/LICENSE.md +1 -1
- data/README.md +30 -195
- data/lib/faraday/adapter/em_http.rb +148 -99
- data/lib/faraday/adapter/em_http_ssl_patch.rb +24 -18
- data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +18 -15
- data/lib/faraday/adapter/em_synchrony.rb +107 -49
- data/lib/faraday/adapter/excon.rb +102 -55
- data/lib/faraday/adapter/httpclient.rb +80 -36
- data/lib/faraday/adapter/net_http.rb +119 -44
- data/lib/faraday/adapter/net_http_persistent.rb +68 -27
- data/lib/faraday/adapter/patron.rb +76 -34
- data/lib/faraday/adapter/rack.rb +28 -12
- data/lib/faraday/adapter/test.rb +136 -52
- data/lib/faraday/adapter/typhoeus.rb +7 -115
- data/lib/faraday/adapter.rb +43 -20
- data/lib/faraday/adapter_registry.rb +28 -0
- data/lib/faraday/autoload.rb +47 -36
- data/lib/faraday/connection.rb +359 -165
- data/lib/faraday/dependency_loader.rb +37 -0
- data/lib/faraday/encoders/flat_params_encoder.rb +94 -0
- data/lib/faraday/encoders/nested_params_encoder.rb +171 -0
- data/lib/faraday/error.rb +71 -24
- data/lib/faraday/file_part.rb +128 -0
- data/lib/faraday/logging/formatter.rb +92 -0
- data/lib/faraday/middleware.rb +4 -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 +21 -0
- data/lib/faraday/options/ssl_options.rb +59 -0
- data/lib/faraday/options.rb +57 -185
- data/lib/faraday/param_part.rb +53 -0
- data/lib/faraday/parameters.rb +4 -180
- data/lib/faraday/rack_builder.rb +74 -38
- 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 +212 -121
- 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 +36 -14
- data/lib/faraday/response.rb +29 -18
- data/lib/faraday/utils/headers.rb +139 -0
- data/lib/faraday/utils/params_hash.rb +61 -0
- data/lib/faraday/utils.rb +28 -216
- data/lib/faraday.rb +102 -204
- data/spec/external_adapters/faraday_specs_setup.rb +14 -0
- metadata +24 -94
- data/.document +0 -6
- data/CHANGELOG.md +0 -20
- data/CONTRIBUTING.md +0 -36
- data/Gemfile +0 -25
- data/Rakefile +0 -71
- data/faraday.gemspec +0 -34
- data/lib/faraday/upload_io.rb +0 -67
- data/script/cached-bundle +0 -46
- data/script/console +0 -7
- data/script/generate_certs +0 -42
- data/script/package +0 -7
- data/script/proxy-server +0 -42
- data/script/release +0 -17
- data/script/s3-put +0 -71
- data/script/server +0 -36
- data/script/test +0 -172
- data/test/adapters/default_test.rb +0 -14
- data/test/adapters/em_http_test.rb +0 -20
- data/test/adapters/em_synchrony_test.rb +0 -20
- data/test/adapters/excon_test.rb +0 -20
- data/test/adapters/httpclient_test.rb +0 -21
- data/test/adapters/integration.rb +0 -254
- data/test/adapters/logger_test.rb +0 -82
- data/test/adapters/net_http_persistent_test.rb +0 -20
- data/test/adapters/net_http_test.rb +0 -14
- data/test/adapters/patron_test.rb +0 -20
- data/test/adapters/rack_test.rb +0 -31
- data/test/adapters/test_middleware_test.rb +0 -114
- data/test/adapters/typhoeus_test.rb +0 -28
- data/test/authentication_middleware_test.rb +0 -65
- data/test/composite_read_io_test.rb +0 -111
- data/test/connection_test.rb +0 -522
- data/test/env_test.rb +0 -218
- data/test/helper.rb +0 -81
- data/test/live_server.rb +0 -67
- data/test/middleware/instrumentation_test.rb +0 -88
- data/test/middleware/retry_test.rb +0 -177
- data/test/middleware_stack_test.rb +0 -173
- data/test/multibyte.txt +0 -1
- data/test/options_test.rb +0 -252
- data/test/parameters_test.rb +0 -64
- data/test/request_middleware_test.rb +0 -142
- data/test/response_middleware_test.rb +0 -72
- data/test/strawberry.rb +0 -2
- data/test/utils_test.rb +0 -58
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 010e4dd27187eb834e8a0c185cab419a1b69c6e3f8a5728f6681109b7848091d
|
|
4
|
+
data.tar.gz: ccd678f8acf84929c15a19b7a6ca1b22b2d634eabfae21c84c4a0f0ba97fb8b6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 150271b18c60bf5b55cc7e74f39fb01d6c83eecc39119d425fe8d399829ba728183900a5a948dbb874f432fc95996b88c367e87b5274b45addbd15d6175d7bc0
|
|
7
|
+
data.tar.gz: 3f4ef0b5d787aeffef29d79af04297a62a6b1ae77f034858b7d68ac4bdcfc00734c976cb8dff8b76b0af007590c6f4a5376797c14d3798cc13193aed96689d0c
|
data/LICENSE.md
CHANGED
data/README.md
CHANGED
|
@@ -1,200 +1,32 @@
|
|
|
1
|
-
# Faraday
|
|
1
|
+
# 
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
* Net::HTTP
|
|
10
|
-
* [Excon][]
|
|
11
|
-
* [Typhoeus][]
|
|
12
|
-
* [Patron][]
|
|
13
|
-
* [EventMachine][]
|
|
14
|
-
* [HTTPClient][]
|
|
15
|
-
|
|
16
|
-
It also includes a Rack adapter for hitting loaded Rack applications through
|
|
17
|
-
Rack::Test, and a Test adapter for stubbing requests by hand.
|
|
18
|
-
|
|
19
|
-
## Usage
|
|
20
|
-
|
|
21
|
-
```ruby
|
|
22
|
-
conn = Faraday.new(:url => 'http://sushi.com') do |faraday|
|
|
23
|
-
faraday.request :url_encoded # form-encode POST params
|
|
24
|
-
faraday.response :logger # log requests to STDOUT
|
|
25
|
-
faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
## GET ##
|
|
29
|
-
|
|
30
|
-
response = conn.get '/nigiri/sake.json' # GET http://sushi.com/nigiri/sake.json
|
|
31
|
-
response.body
|
|
32
|
-
|
|
33
|
-
conn.get '/nigiri', { :name => 'Maguro' } # GET http://sushi.com/nigiri?name=Maguro
|
|
34
|
-
|
|
35
|
-
conn.get do |req| # GET http://sushi.com/search?page=2&limit=100
|
|
36
|
-
req.url '/search', :page => 2
|
|
37
|
-
req.params['limit'] = 100
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
## POST ##
|
|
41
|
-
|
|
42
|
-
conn.post '/nigiri', { :name => 'Maguro' } # POST "name=maguro" to http://sushi.com/nigiri
|
|
43
|
-
|
|
44
|
-
# post payload as JSON instead of "www-form-urlencoded" encoding:
|
|
45
|
-
conn.post do |req|
|
|
46
|
-
req.url '/nigiri'
|
|
47
|
-
req.headers['Content-Type'] = 'application/json'
|
|
48
|
-
req.body = '{ "name": "Unagi" }'
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
## Per-request options ##
|
|
52
|
-
|
|
53
|
-
conn.get do |req|
|
|
54
|
-
req.url '/search'
|
|
55
|
-
req.options.timeout = 5 # open/read timeout in seconds
|
|
56
|
-
req.options.open_timeout = 2 # connection open timeout in seconds
|
|
57
|
-
end
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
If you don't need to set up anything, you can roll with just the default middleware
|
|
61
|
-
stack and default adapter (see [Faraday::RackBuilder#initialize](https://github.com/lostisland/faraday/blob/master/lib/faraday/rack_builder.rb)):
|
|
62
|
-
|
|
63
|
-
```ruby
|
|
64
|
-
response = Faraday.get 'http://sushi.com/nigiri/sake.json'
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## Advanced middleware usage
|
|
68
|
-
|
|
69
|
-
The order in which middleware is stacked is important. Like with Rack, the
|
|
70
|
-
first middleware on the list wraps all others, while the last middleware is the
|
|
71
|
-
innermost one, so that must be the adapter.
|
|
72
|
-
|
|
73
|
-
```ruby
|
|
74
|
-
Faraday.new(...) do |conn|
|
|
75
|
-
# POST/PUT params encoders:
|
|
76
|
-
conn.request :multipart
|
|
77
|
-
conn.request :url_encoded
|
|
78
|
-
|
|
79
|
-
conn.adapter :net_http
|
|
80
|
-
end
|
|
81
|
-
```
|
|
3
|
+
[](https://rubygems.org/gems/faraday)
|
|
4
|
+
[](https://circleci.com/gh/lostisland/faraday/tree/master)
|
|
5
|
+
[](https://codeclimate.com/github/lostisland/faraday/test_coverage)
|
|
6
|
+
[](https://codeclimate.com/github/lostisland/faraday/maintainability)
|
|
7
|
+
[](https://gitter.im/lostisland/faraday?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
|
82
8
|
|
|
83
|
-
This request middleware setup affects POST/PUT requests in the following way:
|
|
84
9
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
already encoded or of another type
|
|
89
|
-
|
|
90
|
-
Swapping middleware means giving the other priority. Specifying the
|
|
91
|
-
"Content-Type" for the request is explicitly stating which middleware should
|
|
92
|
-
process it.
|
|
93
|
-
|
|
94
|
-
Examples:
|
|
95
|
-
|
|
96
|
-
```ruby
|
|
97
|
-
# uploading a file:
|
|
98
|
-
payload[:profile_pic] = Faraday::UploadIO.new('/path/to/avatar.jpg', 'image/jpeg')
|
|
99
|
-
|
|
100
|
-
# "Multipart" middleware detects files and encodes with "multipart/form-data":
|
|
101
|
-
conn.put '/profile', payload
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
## Writing middleware
|
|
105
|
-
|
|
106
|
-
Middleware are classes that implement a `call` instance method. They hook into
|
|
107
|
-
the request/response cycle.
|
|
108
|
-
|
|
109
|
-
```ruby
|
|
110
|
-
def call(request_env)
|
|
111
|
-
# do something with the request
|
|
112
|
-
# request_env[:request_headers].merge!(...)
|
|
113
|
-
|
|
114
|
-
@app.call(request_env).on_complete do |response_env|
|
|
115
|
-
# do something with the response
|
|
116
|
-
# response_env[:response_headers].merge!(...)
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
It's important to do all processing of the response only in the `on_complete`
|
|
122
|
-
block. This enables middleware to work in parallel mode where requests are
|
|
123
|
-
asynchronous.
|
|
124
|
-
|
|
125
|
-
The `env` is a hash with symbol keys that contains info about the request and,
|
|
126
|
-
later, response. Some keys are:
|
|
127
|
-
|
|
128
|
-
```
|
|
129
|
-
# request phase
|
|
130
|
-
:method - :get, :post, ...
|
|
131
|
-
:url - URI for the current request; also contains GET parameters
|
|
132
|
-
:body - POST parameters for :post/:put requests
|
|
133
|
-
:request_headers
|
|
134
|
-
|
|
135
|
-
# response phase
|
|
136
|
-
:status - HTTP response status code, such as 200
|
|
137
|
-
:body - the response body
|
|
138
|
-
:response_headers
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
## Using Faraday for testing
|
|
142
|
-
|
|
143
|
-
```ruby
|
|
144
|
-
# It's possible to define stubbed request outside a test adapter block.
|
|
145
|
-
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
|
146
|
-
stub.get('/tamago') { |env| [200, {}, 'egg'] }
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
# You can pass stubbed request to the test adapter or define them in a block
|
|
150
|
-
# or a combination of the two.
|
|
151
|
-
test = Faraday.new do |builder|
|
|
152
|
-
builder.adapter :test, stubs do |stub|
|
|
153
|
-
stub.get('/ebi') { |env| [ 200, {}, 'shrimp' ]}
|
|
154
|
-
end
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
# It's also possible to stub additional requests after the connection has
|
|
158
|
-
# been initialized. This is useful for testing.
|
|
159
|
-
stubs.get('/uni') { |env| [ 200, {}, 'urchin' ]}
|
|
160
|
-
|
|
161
|
-
resp = test.get '/tamago'
|
|
162
|
-
resp.body # => 'egg'
|
|
163
|
-
resp = test.get '/ebi'
|
|
164
|
-
resp.body # => 'shrimp'
|
|
165
|
-
resp = test.get '/uni'
|
|
166
|
-
resp.body # => 'urchin'
|
|
167
|
-
resp = test.get '/else' #=> raises "no such stub" error
|
|
168
|
-
|
|
169
|
-
# If you like, you can treat your stubs as mocks by verifying that all of
|
|
170
|
-
# the stubbed calls were made. NOTE that this feature is still fairly
|
|
171
|
-
# experimental: It will not verify the order or count of any stub, only that
|
|
172
|
-
# it was called once during the course of the test.
|
|
173
|
-
stubs.verify_stubbed_calls
|
|
174
|
-
```
|
|
10
|
+
Faraday is an HTTP client library that provides a common interface over many
|
|
11
|
+
adapters (such as Net::HTTP) and embraces the concept of Rack middleware when
|
|
12
|
+
processing the request/response cycle.
|
|
175
13
|
|
|
176
|
-
##
|
|
14
|
+
## Getting Started
|
|
177
15
|
|
|
178
|
-
|
|
179
|
-
|
|
16
|
+
The best starting point is the [Faraday Website][website], with its introduction and explanation.
|
|
17
|
+
Need more details? See the [Faraday API Documentation][apidoc] to see how it works internally.
|
|
180
18
|
|
|
181
19
|
## Supported Ruby versions
|
|
182
20
|
|
|
183
|
-
This library aims to support and is [tested against][
|
|
21
|
+
This library aims to support and is [tested against][circle_ci] the following Ruby
|
|
184
22
|
implementations:
|
|
185
23
|
|
|
186
|
-
*
|
|
187
|
-
* MRI 1.9.2
|
|
188
|
-
* MRI 1.9.3
|
|
189
|
-
* MRI 2.0.0
|
|
190
|
-
* MRI 2.1.0
|
|
191
|
-
* [JRuby][]
|
|
192
|
-
* [Rubinius][]
|
|
24
|
+
* Ruby 2.3+
|
|
193
25
|
|
|
194
26
|
If something doesn't work on one of these Ruby versions, it's a bug.
|
|
195
27
|
|
|
196
28
|
This library may inadvertently work (or seem to work) on other Ruby
|
|
197
|
-
implementations, however support will only be provided for the versions listed
|
|
29
|
+
implementations and versions, however support will only be provided for the versions listed
|
|
198
30
|
above.
|
|
199
31
|
|
|
200
32
|
If you would like this library to support another Ruby version, you may
|
|
@@ -204,17 +36,20 @@ implementation, you will be responsible for providing patches in a timely
|
|
|
204
36
|
fashion. If critical issues for a particular implementation exist at the time
|
|
205
37
|
of a major release, support for that Ruby version may be dropped.
|
|
206
38
|
|
|
207
|
-
##
|
|
39
|
+
## Contribute
|
|
208
40
|
|
|
209
|
-
|
|
210
|
-
|
|
41
|
+
Do you want to contribute to Faraday?
|
|
42
|
+
Open the issues page and check for the `help wanted` label!
|
|
43
|
+
But before you start coding, please read our [Contributing Guide][contributing]
|
|
211
44
|
|
|
212
|
-
|
|
213
|
-
[
|
|
214
|
-
|
|
215
|
-
[
|
|
216
|
-
[
|
|
217
|
-
[
|
|
218
|
-
[
|
|
219
|
-
[
|
|
220
|
-
[
|
|
45
|
+
## Copyright
|
|
46
|
+
© 2009 - 2019, the [Faraday Team][faraday_team]. Website and branding design by [Elena Lo Piccolo](https://elelopic.design).
|
|
47
|
+
|
|
48
|
+
[website]: https://lostisland.github.io/faraday
|
|
49
|
+
[faraday_team]: https://lostisland.github.io/faraday/team
|
|
50
|
+
[contributing]: https://github.com/lostisland/faraday/blob/master/.github/CONTRIBUTING.md
|
|
51
|
+
[apidoc]: http://www.rubydoc.info/gems/faraday
|
|
52
|
+
[circle_ci]: https://circleci.com/gh/lostisland/faraday
|
|
53
|
+
[jruby]: http://jruby.org/
|
|
54
|
+
[rubinius]: http://rubini.us/
|
|
55
|
+
[license]: LICENSE.md
|
|
@@ -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,53 @@ 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
|
-
timeout, open_timeout = request_options(env)
|
|
73
|
+
timeout, open_timeout = request_options(env)
|
|
74
|
+
.values_at(:timeout, :open_timeout)
|
|
63
75
|
options[:connect_timeout] = options[:inactivity_timeout] = timeout
|
|
64
76
|
options[:connect_timeout] = open_timeout if open_timeout
|
|
65
77
|
end
|
|
66
78
|
|
|
79
|
+
# Reads out compression header settings from env into options
|
|
67
80
|
def configure_compression(options, env)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
81
|
+
return unless (env[:method] == :get) &&
|
|
82
|
+
!options[:head].key?('accept-encoding')
|
|
83
|
+
|
|
84
|
+
options[:head]['accept-encoding'] = 'gzip, compressed'
|
|
71
85
|
end
|
|
72
86
|
|
|
73
87
|
def request_options(env)
|
|
@@ -81,7 +95,8 @@ module Faraday
|
|
|
81
95
|
|
|
82
96
|
self.supports_parallel = true
|
|
83
97
|
|
|
84
|
-
|
|
98
|
+
# @return [Manager]
|
|
99
|
+
def self.setup_parallel_manager(_options = nil)
|
|
85
100
|
Manager.new
|
|
86
101
|
end
|
|
87
102
|
|
|
@@ -94,89 +109,113 @@ module Faraday
|
|
|
94
109
|
def perform_request(env)
|
|
95
110
|
if parallel?(env)
|
|
96
111
|
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
|
-
}
|
|
112
|
+
manager.add do
|
|
113
|
+
perform_single_request(env)
|
|
114
|
+
.callback { env[:response].finish(env) }
|
|
115
|
+
end
|
|
116
|
+
elsif EventMachine.reactor_running?
|
|
117
|
+
# EM is running: instruct upstream that this is an async request
|
|
118
|
+
env[:parallel_manager] = true
|
|
119
|
+
perform_single_request(env)
|
|
120
|
+
.callback { env[:response].finish(env) }
|
|
121
|
+
.errback do
|
|
122
|
+
# TODO: no way to communicate the error in async mode
|
|
123
|
+
raise NotImplementedError
|
|
112
124
|
end
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
perform_single_request(env)
|
|
118
|
-
callback {
|
|
119
|
-
errback
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
125
|
+
else
|
|
126
|
+
error = nil
|
|
127
|
+
# start EM, block until request is completed
|
|
128
|
+
EventMachine.run do
|
|
129
|
+
perform_single_request(env)
|
|
130
|
+
.callback { EventMachine.stop }
|
|
131
|
+
.errback do |client|
|
|
132
|
+
error = error_message(client)
|
|
133
|
+
EventMachine.stop
|
|
134
|
+
end
|
|
123
135
|
end
|
|
136
|
+
raise_error(error) if error
|
|
124
137
|
end
|
|
125
|
-
rescue EventMachine::Connectify::CONNECTError =>
|
|
126
|
-
if
|
|
127
|
-
raise
|
|
128
|
-
|
|
129
|
-
raise Error::ConnectionFailed, err
|
|
138
|
+
rescue EventMachine::Connectify::CONNECTError => e
|
|
139
|
+
if e.message.include?('Proxy Authentication Required')
|
|
140
|
+
raise Faraday::ConnectionFailed,
|
|
141
|
+
%(407 "Proxy Authentication Required ")
|
|
130
142
|
end
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
raise
|
|
143
|
+
|
|
144
|
+
raise Faraday::ConnectionFailed, e
|
|
145
|
+
rescue StandardError => e
|
|
146
|
+
if defined?(OpenSSL) && e.is_a?(OpenSSL::SSL::SSLError)
|
|
147
|
+
raise Faraday::SSLError, e
|
|
136
148
|
end
|
|
149
|
+
|
|
150
|
+
raise
|
|
137
151
|
end
|
|
138
152
|
|
|
139
153
|
# TODO: reuse the connection to support pipelining
|
|
140
154
|
def perform_single_request(env)
|
|
141
|
-
req =
|
|
142
|
-
req.setup_request(env[:method], request_config(env))
|
|
143
|
-
|
|
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|
|
|
144
169
|
client.response_header.each do |name, value|
|
|
145
|
-
|
|
170
|
+
headers[name.to_sym] = value
|
|
146
171
|
end
|
|
147
172
|
end
|
|
148
|
-
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def create_request(env)
|
|
177
|
+
EventMachine::HttpRequest.new(
|
|
178
|
+
env[:url], connection_config(env).merge(@connection_options)
|
|
179
|
+
)
|
|
149
180
|
end
|
|
150
181
|
|
|
151
182
|
def error_message(client)
|
|
152
|
-
client.error
|
|
183
|
+
client.error || 'request failed'
|
|
153
184
|
end
|
|
154
185
|
|
|
155
186
|
def raise_error(msg)
|
|
156
|
-
|
|
157
|
-
if msg
|
|
158
|
-
|
|
159
|
-
msg =
|
|
187
|
+
error_class = Faraday::ClientError
|
|
188
|
+
if timeout_message?(msg)
|
|
189
|
+
error_class = Faraday::TimeoutError
|
|
190
|
+
msg = 'request timed out'
|
|
160
191
|
elsif msg == Errno::ECONNREFUSED
|
|
161
|
-
|
|
162
|
-
msg =
|
|
163
|
-
elsif msg ==
|
|
164
|
-
|
|
192
|
+
error_class = Faraday::ConnectionFailed
|
|
193
|
+
msg = 'connection refused'
|
|
194
|
+
elsif msg == 'connection closed by server'
|
|
195
|
+
error_class = Faraday::ConnectionFailed
|
|
165
196
|
end
|
|
166
|
-
raise
|
|
197
|
+
raise error_class, msg
|
|
167
198
|
end
|
|
168
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]
|
|
169
206
|
def parallel?(env)
|
|
170
207
|
!!env[:parallel_manager]
|
|
171
208
|
end
|
|
172
209
|
|
|
173
|
-
#
|
|
210
|
+
# This parallel manager is designed to start an EventMachine loop
|
|
174
211
|
# and block until all registered requests have been completed.
|
|
175
212
|
class Manager
|
|
213
|
+
# @see reset
|
|
176
214
|
def initialize
|
|
177
215
|
reset
|
|
178
216
|
end
|
|
179
217
|
|
|
218
|
+
# Re-initializes instance variables
|
|
180
219
|
def reset
|
|
181
220
|
@registered_procs = []
|
|
182
221
|
@num_registered = 0
|
|
@@ -185,27 +224,30 @@ module Faraday
|
|
|
185
224
|
@running = false
|
|
186
225
|
end
|
|
187
226
|
|
|
188
|
-
|
|
227
|
+
# @return [Boolean]
|
|
228
|
+
def running?
|
|
229
|
+
@running
|
|
230
|
+
end
|
|
189
231
|
|
|
190
|
-
def add
|
|
232
|
+
def add(&block)
|
|
191
233
|
if running?
|
|
192
234
|
perform_request { yield }
|
|
193
235
|
else
|
|
194
|
-
@registered_procs <<
|
|
236
|
+
@registered_procs << block
|
|
195
237
|
end
|
|
196
238
|
@num_registered += 1
|
|
197
239
|
end
|
|
198
240
|
|
|
199
241
|
def run
|
|
200
|
-
if @num_registered
|
|
242
|
+
if @num_registered.positive?
|
|
201
243
|
@running = true
|
|
202
244
|
EventMachine.run do
|
|
203
245
|
@registered_procs.each do |proc|
|
|
204
246
|
perform_request(&proc)
|
|
205
247
|
end
|
|
206
248
|
end
|
|
207
|
-
|
|
208
|
-
raise Faraday::
|
|
249
|
+
unless @errors.empty?
|
|
250
|
+
raise Faraday::ClientError, @errors.first || 'connection failed'
|
|
209
251
|
end
|
|
210
252
|
end
|
|
211
253
|
ensure
|
|
@@ -214,24 +256,31 @@ module Faraday
|
|
|
214
256
|
|
|
215
257
|
def perform_request
|
|
216
258
|
client = yield
|
|
217
|
-
client.callback
|
|
218
|
-
|
|
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
|
|
219
267
|
end
|
|
220
268
|
|
|
221
269
|
def check_finished
|
|
222
|
-
if @num_succeeded + @errors.size == @num_registered
|
|
223
|
-
EventMachine.stop
|
|
224
|
-
end
|
|
270
|
+
EventMachine.stop if @num_succeeded + @errors.size == @num_registered
|
|
225
271
|
end
|
|
226
272
|
end
|
|
227
273
|
end
|
|
228
274
|
end
|
|
229
275
|
end
|
|
230
276
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
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
|