em-http-request 1.1.2 → 1.1.7
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/.travis.yml +7 -0
- data/README.md +5 -4
- data/em-http-request.gemspec +2 -2
- data/lib/em-http.rb +1 -0
- data/lib/em-http/client.rb +35 -12
- data/lib/em-http/decoders.rb +1 -2
- data/lib/em-http/http_client_options.rb +7 -6
- data/lib/em-http/http_connection.rb +114 -10
- data/lib/em-http/http_connection_options.rb +29 -3
- data/lib/em-http/http_encoding.rb +10 -3
- data/lib/em-http/http_header.rb +5 -5
- data/lib/em-http/middleware/json_response.rb +1 -1
- data/lib/em-http/version.rb +1 -1
- data/lib/em/io_streamer.rb +49 -0
- data/spec/client_spec.rb +114 -2
- data/spec/dns_spec.rb +2 -2
- data/spec/external_spec.rb +3 -3
- data/spec/gzip_spec.rb +23 -0
- data/spec/helper.rb +1 -0
- data/spec/http_proxy_spec.rb +241 -63
- data/spec/pipelining_spec.rb +4 -4
- data/spec/redirect_spec.rb +65 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/ssl_spec.rb +52 -1
- data/spec/stallion.rb +20 -5
- data/spec/stub_server.rb +6 -3
- metadata +39 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c7562e4d20c35c54a9319250e665a883c810546cb657d8f897591e113999ed3a
|
4
|
+
data.tar.gz: 643bf26ea7bfa2a85d6e4257a475295c16eca044ff0d04341537793f07d5bd04
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d9d1f441081a034f29447cb99b26c73ef7767a989c31df007e1ecfc6ea8db1f4cbe00fb26c0f81b59108f53b54dfbccd51ea9140fd5286efaca6095b45943ad
|
7
|
+
data.tar.gz: 690dc944373085313c41c484edd25366036a3da46855b6a153aab65c19aed961d94d202de07cb3f5f8406585bb5c3a66998913debcba4d02796fb1c8f04be7c1
|
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
# EM-HTTP-Request
|
1
|
+
# EM-HTTP-Request
|
2
|
+
|
3
|
+
[](http://rubygems.org/gems/em-http-request) [](https://travis-ci.org/igrigorik/em-http-request)
|
2
4
|
|
3
5
|
Async (EventMachine) HTTP client, with support for:
|
4
6
|
|
@@ -10,7 +12,7 @@ Async (EventMachine) HTTP client, with support for:
|
|
10
12
|
- Streaming file uploads
|
11
13
|
- HTTP proxy and SOCKS5 support
|
12
14
|
- Basic Auth & OAuth
|
13
|
-
- Connection-level &
|
15
|
+
- Connection-level & global middleware support
|
14
16
|
- HTTP parser via [http_parser.rb](https://github.com/tmm1/http_parser.rb)
|
15
17
|
- Works wherever EventMachine runs: Rubinius, JRuby, MRI
|
16
18
|
|
@@ -18,7 +20,7 @@ Async (EventMachine) HTTP client, with support for:
|
|
18
20
|
|
19
21
|
gem install em-http-request
|
20
22
|
|
21
|
-
- Introductory [screencast](http://everburning.com/news/eventmachine-screencast-em-http-request
|
23
|
+
- Introductory [screencast](http://everburning.com/news/eventmachine-screencast-em-http-request)
|
22
24
|
- [Issuing GET/POST/etc requests](https://github.com/igrigorik/em-http-request/wiki/Issuing-Requests)
|
23
25
|
- [Issuing parallel requests with Multi interface](https://github.com/igrigorik/em-http-request/wiki/Parallel-Requests)
|
24
26
|
- [Handling Redirects & Timeouts](https://github.com/igrigorik/em-http-request/wiki/Redirects-and-Timeouts)
|
@@ -54,7 +56,6 @@ Several higher-order Ruby projects have incorporated em-http and other Ruby HTTP
|
|
54
56
|
- [Firering](https://github.com/EmmanuelOga/firering) - Eventmachine powered Campfire API
|
55
57
|
- [RDaneel](https://github.com/hasmanydevelopers/RDaneel) - Ruby crawler which respects robots.txt
|
56
58
|
- [em-eventsource](https://github.com/AF83/em-eventsource) - EventSource client for EventMachine
|
57
|
-
- [sinatra-synchrony](https://github.com/kyledrake/sinatra-synchrony) - Sinatra plugin for synchronous use of EM
|
58
59
|
- and many others.. drop me a link if you want yours included!
|
59
60
|
|
60
61
|
### License
|
data/em-http-request.gemspec
CHANGED
@@ -16,14 +16,14 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.rubyforge_project = 'em-http-request'
|
17
17
|
|
18
18
|
s.add_dependency 'addressable', '>= 2.3.4'
|
19
|
-
s.add_dependency 'cookiejar'
|
19
|
+
s.add_dependency 'cookiejar', '!= 0.3.1'
|
20
20
|
s.add_dependency 'em-socksify', '>= 0.3'
|
21
21
|
s.add_dependency 'eventmachine', '>= 1.0.3'
|
22
22
|
s.add_dependency 'http_parser.rb', '>= 0.6.0'
|
23
23
|
|
24
24
|
s.add_development_dependency 'mongrel', '~> 1.2.0.pre2'
|
25
25
|
s.add_development_dependency 'multi_json'
|
26
|
-
s.add_development_dependency 'rack'
|
26
|
+
s.add_development_dependency 'rack', '< 2.0'
|
27
27
|
s.add_development_dependency 'rake'
|
28
28
|
s.add_development_dependency 'rspec'
|
29
29
|
|
data/lib/em-http.rb
CHANGED
data/lib/em-http/client.rb
CHANGED
@@ -21,7 +21,7 @@ module EventMachine
|
|
21
21
|
|
22
22
|
CRLF="\r\n"
|
23
23
|
|
24
|
-
attr_accessor :state, :response
|
24
|
+
attr_accessor :state, :response, :conn
|
25
25
|
attr_reader :response_header, :error, :content_charset, :req, :cookies
|
26
26
|
|
27
27
|
def initialize(conn, options)
|
@@ -100,14 +100,13 @@ module EventMachine
|
|
100
100
|
|
101
101
|
@cookies.clear
|
102
102
|
@cookies = @cookiejar.get(@response_header.location).map(&:to_s) if @req.pass_cookies
|
103
|
-
@req.set_uri(@response_header.location)
|
104
103
|
|
105
|
-
@conn.redirect(self)
|
104
|
+
@conn.redirect(self, @response_header.location)
|
106
105
|
else
|
107
106
|
succeed(self)
|
108
107
|
end
|
109
108
|
|
110
|
-
rescue
|
109
|
+
rescue => e
|
111
110
|
on_error(e.message)
|
112
111
|
end
|
113
112
|
else
|
@@ -156,11 +155,16 @@ module EventMachine
|
|
156
155
|
|
157
156
|
# Set the User-Agent if it hasn't been specified
|
158
157
|
if !head.key?('user-agent')
|
159
|
-
head['user-agent'] =
|
158
|
+
head['user-agent'] = 'EventMachine HttpClient'
|
160
159
|
elsif head['user-agent'].nil?
|
161
160
|
head.delete('user-agent')
|
162
161
|
end
|
163
162
|
|
163
|
+
# Set the Accept-Encoding header if none is provided
|
164
|
+
if !head.key?('accept-encoding') && req.compressed
|
165
|
+
head['accept-encoding'] = 'gzip, compressed'
|
166
|
+
end
|
167
|
+
|
164
168
|
# Set the auth from the URI if given
|
165
169
|
head['Authorization'] = @req.uri.userinfo.split(/:/, 2) if @req.uri.userinfo
|
166
170
|
|
@@ -178,7 +182,7 @@ module EventMachine
|
|
178
182
|
# Set the Content-Length if body is given,
|
179
183
|
# or we're doing an empty post or put
|
180
184
|
if body
|
181
|
-
head['content-length']
|
185
|
+
head['content-length'] ||= body.respond_to?(:bytesize) ? body.bytesize : body.size
|
182
186
|
elsif @req.method == 'POST' or @req.method == 'PUT'
|
183
187
|
# wont happen if body is set and we already set content-length above
|
184
188
|
head['content-length'] ||= 0
|
@@ -189,16 +193,13 @@ module EventMachine
|
|
189
193
|
head['content-type'] = 'application/x-www-form-urlencoded'
|
190
194
|
end
|
191
195
|
|
192
|
-
request_header ||= encode_request(@req.method, @req.uri, query, @conn.connopts
|
196
|
+
request_header ||= encode_request(@req.method, @req.uri, query, @conn.connopts)
|
193
197
|
request_header << encode_headers(head)
|
194
198
|
request_header << CRLF
|
195
199
|
@conn.send_data request_header
|
196
200
|
|
197
|
-
|
198
|
-
|
199
|
-
elsif @req.file
|
200
|
-
@conn.stream_file_data @req.file, :http_chunks => false
|
201
|
-
end
|
201
|
+
@req_body = body || (@req.file && Pathname.new(@req.file))
|
202
|
+
send_request_body unless @req.headers['expect'] == '100-continue'
|
202
203
|
end
|
203
204
|
|
204
205
|
def on_body_data(data)
|
@@ -222,6 +223,28 @@ module EventMachine
|
|
222
223
|
end
|
223
224
|
end
|
224
225
|
|
226
|
+
def request_body_pending?
|
227
|
+
!!@req_body
|
228
|
+
end
|
229
|
+
|
230
|
+
def send_request_body
|
231
|
+
return if @req_body.nil?
|
232
|
+
|
233
|
+
if @req_body.is_a?(String)
|
234
|
+
@conn.send_data @req_body
|
235
|
+
|
236
|
+
elsif @req_body.is_a?(Pathname)
|
237
|
+
@conn.stream_file_data @req_body.to_path, http_chunks: false
|
238
|
+
|
239
|
+
elsif @req_body.respond_to?(:read) && @req_body.respond_to?(:eof?) # IO or IO-like object
|
240
|
+
@conn.stream_data @req_body
|
241
|
+
|
242
|
+
else
|
243
|
+
raise "Don't know how to send request body: #{@req_body.inspect}"
|
244
|
+
end
|
245
|
+
@req_body = nil
|
246
|
+
end
|
247
|
+
|
225
248
|
def parse_response_header(header, version, status)
|
226
249
|
@response_header.raw = header
|
227
250
|
header.each do |key, val|
|
data/lib/em-http/decoders.rb
CHANGED
@@ -127,7 +127,6 @@ module EventMachine::HttpDecoders
|
|
127
127
|
|
128
128
|
def extract_stream(compressed)
|
129
129
|
@data << compressed
|
130
|
-
pos = @pos
|
131
130
|
|
132
131
|
while !eof? && !finished?
|
133
132
|
buffer = ""
|
@@ -208,7 +207,7 @@ module EventMachine::HttpDecoders
|
|
208
207
|
end
|
209
208
|
|
210
209
|
if finished?
|
211
|
-
compressed[(@pos -
|
210
|
+
compressed[(@pos - (@data.length - compressed.length))..-1]
|
212
211
|
else
|
213
212
|
""
|
214
213
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class HttpClientOptions
|
2
2
|
attr_reader :uri, :method, :host, :port
|
3
3
|
attr_reader :headers, :file, :body, :query, :path
|
4
|
-
attr_reader :keepalive, :pass_cookies, :decoding
|
4
|
+
attr_reader :keepalive, :pass_cookies, :decoding, :compressed
|
5
5
|
|
6
6
|
attr_accessor :followed, :redirects
|
7
7
|
|
@@ -12,31 +12,31 @@ class HttpClientOptions
|
|
12
12
|
|
13
13
|
@method = method.to_s.upcase
|
14
14
|
@headers = options[:head] || {}
|
15
|
-
@query = options[:query]
|
16
|
-
|
17
15
|
|
18
16
|
@file = options[:file]
|
19
17
|
@body = options[:body]
|
20
18
|
|
21
19
|
@pass_cookies = options.fetch(:pass_cookies, true) # pass cookies between redirects
|
22
20
|
@decoding = options.fetch(:decoding, true) # auto-decode compressed response
|
21
|
+
@compressed = options.fetch(:compressed, true) # auto-negotiated compressed response
|
23
22
|
|
24
|
-
set_uri(uri, options[:path])
|
23
|
+
set_uri(uri, options[:path], options[:query])
|
25
24
|
end
|
26
25
|
|
27
26
|
def follow_redirect?; @followed < @redirects; end
|
28
27
|
def ssl?; @uri.scheme == "https" || @uri.port == 443; end
|
29
28
|
def no_body?; @method == "HEAD"; end
|
30
29
|
|
31
|
-
def set_uri(uri, path = nil)
|
30
|
+
def set_uri(uri, path = nil, query = nil)
|
32
31
|
uri = uri.kind_of?(Addressable::URI) ? uri : Addressable::URI::parse(uri.to_s)
|
33
32
|
uri.path = path if path
|
34
33
|
uri.path = '/' if uri.path.empty?
|
35
34
|
|
36
35
|
@uri = uri
|
37
36
|
@path = uri.path
|
38
|
-
@host = uri.
|
37
|
+
@host = uri.hostname
|
39
38
|
@port = uri.port
|
39
|
+
@query = query
|
40
40
|
|
41
41
|
# Make sure the ports are set as Addressable::URI doesn't
|
42
42
|
# set the port if it isn't there
|
@@ -44,5 +44,6 @@ class HttpClientOptions
|
|
44
44
|
@port = @uri.scheme == "https" ? 443 : 80
|
45
45
|
end
|
46
46
|
|
47
|
+
uri
|
47
48
|
end
|
48
49
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'em/io_streamer'
|
2
|
+
|
1
3
|
module EventMachine
|
2
4
|
|
3
5
|
module HTTPMethods
|
@@ -20,7 +22,11 @@ module EventMachine
|
|
20
22
|
end
|
21
23
|
|
22
24
|
def receive_data(data)
|
23
|
-
|
25
|
+
begin
|
26
|
+
@parent.receive_data data
|
27
|
+
rescue EventMachine::Connectify::CONNECTError => e
|
28
|
+
@parent.close(e.message)
|
29
|
+
end
|
24
30
|
end
|
25
31
|
|
26
32
|
def connection_completed
|
@@ -30,6 +36,62 @@ module EventMachine
|
|
30
36
|
def unbind(reason=nil)
|
31
37
|
@parent.unbind(reason)
|
32
38
|
end
|
39
|
+
|
40
|
+
# TLS verification support, original implementation by Mislav Marohnić
|
41
|
+
# https://github.com/lostisland/faraday/blob/63cf47c95b573539f047c729bd9ad67560bc83ff/lib/faraday/adapter/em_http_ssl_patch.rb
|
42
|
+
def ssl_verify_peer(cert_string)
|
43
|
+
cert = nil
|
44
|
+
begin
|
45
|
+
cert = OpenSSL::X509::Certificate.new(cert_string)
|
46
|
+
rescue OpenSSL::X509::CertificateError
|
47
|
+
return false
|
48
|
+
end
|
49
|
+
|
50
|
+
@last_seen_cert = cert
|
51
|
+
|
52
|
+
if certificate_store.verify(@last_seen_cert)
|
53
|
+
begin
|
54
|
+
certificate_store.add_cert(@last_seen_cert)
|
55
|
+
rescue OpenSSL::X509::StoreError => e
|
56
|
+
raise e unless e.message == 'cert already in hash table'
|
57
|
+
end
|
58
|
+
true
|
59
|
+
else
|
60
|
+
raise OpenSSL::SSL::SSLError.new(%(unable to verify the server certificate for "#{host}"))
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def ssl_handshake_completed
|
65
|
+
unless verify_peer?
|
66
|
+
warn "[WARNING; em-http-request] TLS hostname validation is disabled (use 'tls: {verify_peer: true}'), see" +
|
67
|
+
" CVE-2020-13482 and https://github.com/igrigorik/em-http-request/issues/339 for details" unless parent.connopts.tls.has_key?(:verify_peer)
|
68
|
+
return true
|
69
|
+
end
|
70
|
+
|
71
|
+
unless OpenSSL::SSL.verify_certificate_identity(@last_seen_cert, host)
|
72
|
+
raise OpenSSL::SSL::SSLError.new(%(host "#{host}" does not match the server certificate))
|
73
|
+
else
|
74
|
+
true
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def verify_peer?
|
79
|
+
parent.connopts.tls[:verify_peer]
|
80
|
+
end
|
81
|
+
|
82
|
+
def host
|
83
|
+
parent.connopts.host
|
84
|
+
end
|
85
|
+
|
86
|
+
def certificate_store
|
87
|
+
@certificate_store ||= begin
|
88
|
+
store = OpenSSL::X509::Store.new
|
89
|
+
store.set_default_paths
|
90
|
+
ca_file = parent.connopts.tls[:cert_chain_file]
|
91
|
+
store.add_file(ca_file) if ca_file
|
92
|
+
store
|
93
|
+
end
|
94
|
+
end
|
33
95
|
end
|
34
96
|
|
35
97
|
class HttpConnection
|
@@ -37,8 +99,8 @@ module EventMachine
|
|
37
99
|
include Socksify
|
38
100
|
include Connectify
|
39
101
|
|
40
|
-
attr_reader :deferred
|
41
|
-
attr_accessor :error, :connopts, :uri
|
102
|
+
attr_reader :deferred, :conn
|
103
|
+
attr_accessor :error, :connopts, :uri
|
42
104
|
|
43
105
|
def initialize
|
44
106
|
@deferred = true
|
@@ -97,7 +159,7 @@ module EventMachine
|
|
97
159
|
@conn.callback { c.connection_completed }
|
98
160
|
|
99
161
|
middleware.each do |m|
|
100
|
-
c.callback
|
162
|
+
c.callback(&m.method(:response)) if m.respond_to?(:response)
|
101
163
|
end
|
102
164
|
|
103
165
|
@clients.push c
|
@@ -114,8 +176,21 @@ module EventMachine
|
|
114
176
|
@p = Http::Parser.new
|
115
177
|
@p.header_value_type = :mixed
|
116
178
|
@p.on_headers_complete = proc do |h|
|
117
|
-
client
|
118
|
-
|
179
|
+
if client
|
180
|
+
if @p.status_code == 100
|
181
|
+
client.send_request_body
|
182
|
+
@p.reset!
|
183
|
+
else
|
184
|
+
client.parse_response_header(h, @p.http_version, @p.status_code)
|
185
|
+
:reset if client.req.no_body?
|
186
|
+
end
|
187
|
+
else
|
188
|
+
# if we receive unexpected data without a pending client request
|
189
|
+
# reset the parser to avoid firing any further callbacks and close
|
190
|
+
# the connection because we're processing invalid HTTP
|
191
|
+
@p.reset!
|
192
|
+
unbind
|
193
|
+
end
|
119
194
|
end
|
120
195
|
|
121
196
|
@p.on_body = proc do |b|
|
@@ -152,9 +227,9 @@ module EventMachine
|
|
152
227
|
@peer = @conn.get_peername
|
153
228
|
|
154
229
|
if @connopts.socks_proxy?
|
155
|
-
socksify(client.req.uri.
|
230
|
+
socksify(client.req.uri.hostname, client.req.uri.inferred_port, *@connopts.proxy[:authorization]) { start }
|
156
231
|
elsif @connopts.connect_proxy?
|
157
|
-
connectify(client.req.uri.
|
232
|
+
connectify(client.req.uri.hostname, client.req.uri.inferred_port, *@connopts.proxy[:authorization]) { start }
|
158
233
|
else
|
159
234
|
start
|
160
235
|
end
|
@@ -165,8 +240,33 @@ module EventMachine
|
|
165
240
|
@conn.succeed
|
166
241
|
end
|
167
242
|
|
168
|
-
def redirect(client)
|
169
|
-
|
243
|
+
def redirect(client, new_location)
|
244
|
+
old_location = client.req.uri
|
245
|
+
new_location = client.req.set_uri(new_location)
|
246
|
+
|
247
|
+
if client.req.keepalive
|
248
|
+
# Application requested a keep-alive connection but one of the requests
|
249
|
+
# hits a cross-origin redirect. We need to open a new connection and
|
250
|
+
# let both connections proceed simultaneously.
|
251
|
+
if old_location.origin != new_location.origin
|
252
|
+
conn = HttpConnection.new
|
253
|
+
client.conn = conn
|
254
|
+
conn.connopts = @connopts
|
255
|
+
conn.connopts.https = new_location.scheme == "https"
|
256
|
+
conn.uri = client.req.uri
|
257
|
+
conn.activate_connection(client)
|
258
|
+
|
259
|
+
# If the redirect is a same-origin redirect on a keep-alive request
|
260
|
+
# then immidiately dispatch the request over existing connection.
|
261
|
+
else
|
262
|
+
@clients.push client
|
263
|
+
client.connection_completed
|
264
|
+
end
|
265
|
+
else
|
266
|
+
# If connection is not keep-alive the unbind will fire and we'll
|
267
|
+
# reconnect using the same connection object.
|
268
|
+
@pending.push client
|
269
|
+
end
|
170
270
|
end
|
171
271
|
|
172
272
|
def unbind(reason = nil)
|
@@ -208,6 +308,10 @@ module EventMachine
|
|
208
308
|
@conn.stream_file_data filename, args
|
209
309
|
end
|
210
310
|
|
311
|
+
def stream_data(io, opts = {})
|
312
|
+
EventMachine::IOStreamer.new(self, io, opts)
|
313
|
+
end
|
314
|
+
|
211
315
|
private
|
212
316
|
|
213
317
|
def client
|
@@ -1,13 +1,13 @@
|
|
1
1
|
class HttpConnectionOptions
|
2
2
|
attr_reader :host, :port, :tls, :proxy, :bind, :bind_port
|
3
3
|
attr_reader :connect_timeout, :inactivity_timeout
|
4
|
+
attr_writer :https
|
4
5
|
|
5
6
|
def initialize(uri, options)
|
6
7
|
@connect_timeout = options[:connect_timeout] || 5 # default connection setup timeout
|
7
8
|
@inactivity_timeout = options[:inactivity_timeout] ||= 10 # default connection inactivity (post-setup) timeout
|
8
9
|
|
9
10
|
@tls = options[:tls] || options[:ssl] || {}
|
10
|
-
@proxy = options[:proxy]
|
11
11
|
|
12
12
|
if bind = options[:bind]
|
13
13
|
@bind = bind[:host] || '0.0.0.0'
|
@@ -20,12 +20,15 @@ class HttpConnectionOptions
|
|
20
20
|
uri = uri.kind_of?(Addressable::URI) ? uri : Addressable::URI::parse(uri.to_s)
|
21
21
|
@https = uri.scheme == "https"
|
22
22
|
uri.port ||= (@https ? 443 : 80)
|
23
|
+
@tls[:sni_hostname] = uri.hostname
|
23
24
|
|
24
|
-
|
25
|
+
@proxy = options[:proxy] || proxy_from_env
|
26
|
+
|
27
|
+
if proxy
|
25
28
|
@host = proxy[:host]
|
26
29
|
@port = proxy[:port]
|
27
30
|
else
|
28
|
-
@host = uri.
|
31
|
+
@host = uri.hostname
|
29
32
|
@port = uri.port
|
30
33
|
end
|
31
34
|
end
|
@@ -41,4 +44,27 @@ class HttpConnectionOptions
|
|
41
44
|
def socks_proxy?
|
42
45
|
@proxy && (@proxy[:type] == :socks5)
|
43
46
|
end
|
47
|
+
|
48
|
+
def proxy_from_env
|
49
|
+
# TODO: Add support for $http_no_proxy or $no_proxy ?
|
50
|
+
proxy_str = if @https
|
51
|
+
ENV['HTTPS_PROXY'] || ENV['https_proxy']
|
52
|
+
else
|
53
|
+
ENV['HTTP_PROXY'] || ENV['http_proxy']
|
54
|
+
|
55
|
+
# Fall-back to $ALL_PROXY if none of the above env-vars have values
|
56
|
+
end || ENV['ALL_PROXY']
|
57
|
+
|
58
|
+
# Addressable::URI::parse will return `nil` if given `nil` and an empty URL for an empty string
|
59
|
+
# so, let's short-circuit that:
|
60
|
+
return if !proxy_str || proxy_str.empty?
|
61
|
+
|
62
|
+
proxy_env_uri = Addressable::URI::parse(proxy_str)
|
63
|
+
{ :host => proxy_env_uri.host, :port => proxy_env_uri.port, :type => :http }
|
64
|
+
|
65
|
+
rescue Addressable::URI::InvalidURIError
|
66
|
+
# An invalid env-var shouldn't crash the config step, IMHO.
|
67
|
+
# We should somehow log / warn about this, perhaps...
|
68
|
+
return
|
69
|
+
end
|
44
70
|
end
|