excon 0.18.5 → 0.19.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of excon might be problematic. Click here for more details.
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/changelog.txt +13 -0
- data/excon.gemspec +4 -3
- data/lib/excon.rb +16 -2
- data/lib/excon/connection.rb +19 -34
- data/lib/excon/constants.rb +41 -1
- data/lib/excon/errors.rb +1 -2
- data/lib/excon/middlewares/base.rb +5 -0
- data/lib/excon/middlewares/expects.rb +1 -1
- data/lib/excon/middlewares/idempotent.rb +18 -0
- data/lib/excon/middlewares/instrumentor.rb +7 -0
- data/tests/basic_tests.rb +18 -0
- data/tests/{idempotent_tests.rb → middlewares/idempotent_tests.rb} +0 -0
- data/tests/middlewares/mock_tests.rb +9 -0
- metadata +5 -4
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -106,7 +106,7 @@ Pipelining Requests
|
|
106
106
|
You can make use of HTTP pipelining to improve performance. Insead of the normal request/response cyle, pipelining sends a series of requests and then receives a series of responses. You can take advantage of this using the `requests` method, which takes an array of params where each is a hash like request would receive and returns an array of responses.
|
107
107
|
|
108
108
|
connection = Excon.new('http://geemus.com/')
|
109
|
-
connection.requests([{:method => :get, :method => :get}])
|
109
|
+
connection.requests([{:method => :get}, {:method => :get}])
|
110
110
|
|
111
111
|
Streaming Responses
|
112
112
|
-------------------
|
data/changelog.txt
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
0.19.0 02/27/2013
|
2
|
+
=================
|
3
|
+
|
4
|
+
fix requests (pipeline) example in README
|
5
|
+
make StubNotFound inherit from StandardError (not Excon::Errors::Error)
|
6
|
+
idempotent reimplemented as middleware
|
7
|
+
remaining idempotent/instrumentor functionality moved to middleware
|
8
|
+
move uri parsing to Excon.new
|
9
|
+
allow for configurable URI parser (ie Addressable vs URI)
|
10
|
+
move VALID_CONNECTION_KEYS to constants
|
11
|
+
move idempotent tests to middleware directory
|
12
|
+
fix output of expects middleware to pass response objects instead of hashes
|
13
|
+
|
1
14
|
0.18.5 02/22/2013
|
2
15
|
=================
|
3
16
|
|
data/excon.gemspec
CHANGED
@@ -13,8 +13,8 @@ Gem::Specification.new do |s|
|
|
13
13
|
## If your rubyforge_project name is different, then edit it and comment out
|
14
14
|
## the sub! line in the Rakefile
|
15
15
|
s.name = 'excon'
|
16
|
-
s.version = '0.
|
17
|
-
s.date = '2013-02-
|
16
|
+
s.version = '0.19.0'
|
17
|
+
s.date = '2013-02-27'
|
18
18
|
s.rubyforge_project = 'excon'
|
19
19
|
|
20
20
|
## Make sure your summary is short. The description may be as long
|
@@ -98,6 +98,7 @@ Gem::Specification.new do |s|
|
|
98
98
|
lib/excon/errors.rb
|
99
99
|
lib/excon/middlewares/base.rb
|
100
100
|
lib/excon/middlewares/expects.rb
|
101
|
+
lib/excon/middlewares/idempotent.rb
|
101
102
|
lib/excon/middlewares/instrumentor.rb
|
102
103
|
lib/excon/middlewares/mock.rb
|
103
104
|
lib/excon/response.rb
|
@@ -109,7 +110,7 @@ Gem::Specification.new do |s|
|
|
109
110
|
tests/basic_tests.rb
|
110
111
|
tests/data/xs
|
111
112
|
tests/header_tests.rb
|
112
|
-
tests/idempotent_tests.rb
|
113
|
+
tests/middlewares/idempotent_tests.rb
|
113
114
|
tests/middlewares/instrumentation_tests.rb
|
114
115
|
tests/middlewares/mock_tests.rb
|
115
116
|
tests/proxy_tests.rb
|
data/lib/excon.rb
CHANGED
@@ -22,8 +22,9 @@ module Excon
|
|
22
22
|
:idempotent => false,
|
23
23
|
:instrumentor_name => 'excon',
|
24
24
|
:middlewares => [
|
25
|
-
Excon::Middleware::Instrumentor,
|
26
25
|
Excon::Middleware::Expects,
|
26
|
+
Excon::Middleware::Idempotent,
|
27
|
+
Excon::Middleware::Instrumentor,
|
27
28
|
Excon::Middleware::Mock
|
28
29
|
],
|
29
30
|
:mock => false,
|
@@ -32,6 +33,7 @@ module Excon
|
|
32
33
|
:retry_limit => DEFAULT_RETRY_LIMIT,
|
33
34
|
:ssl_ca_file => DEFAULT_CA_FILE,
|
34
35
|
:ssl_verify_peer => RbConfig::CONFIG['host_os'] !~ /mswin|win32|dos|cygwin|mingw/i,
|
36
|
+
:uri_parser => URI,
|
35
37
|
:write_timeout => 60
|
36
38
|
}
|
37
39
|
end
|
@@ -50,6 +52,7 @@ require 'excon/connection'
|
|
50
52
|
require 'excon/errors'
|
51
53
|
require 'excon/middlewares/base'
|
52
54
|
require 'excon/middlewares/expects'
|
55
|
+
require 'excon/middlewares/idempotent'
|
53
56
|
require 'excon/middlewares/instrumentor'
|
54
57
|
require 'excon/middlewares/mock'
|
55
58
|
require 'excon/response'
|
@@ -106,7 +109,18 @@ module Excon
|
|
106
109
|
# @param [Hash<Symbol, >] params One or more option params to set on the Connection instance
|
107
110
|
# @return [Connection] A new Excon::Connection instance
|
108
111
|
def new(url, params = {})
|
109
|
-
Excon
|
112
|
+
uri_parser = params[:uri_parser] || Excon.defaults[:uri_parser]
|
113
|
+
uri = uri_parser.parse(url)
|
114
|
+
params.merge!({
|
115
|
+
:host => uri.host,
|
116
|
+
:path => uri.path,
|
117
|
+
:port => uri.port.to_s,
|
118
|
+
:query => uri.query,
|
119
|
+
:scheme => uri.scheme,
|
120
|
+
:user => (URI.decode(uri.user) if uri.user),
|
121
|
+
:password => (URI.decode(uri.password) if uri.password),
|
122
|
+
})
|
123
|
+
Excon::Connection.new(params)
|
110
124
|
end
|
111
125
|
|
112
126
|
# push an additional stub onto the list to check for mock requests
|
data/lib/excon/connection.rb
CHANGED
@@ -1,10 +1,6 @@
|
|
1
1
|
module Excon
|
2
2
|
class Connection
|
3
|
-
|
4
|
-
:instrumentor, :instrumentor_name, :ssl_ca_file, :ssl_verify_peer, :chunk_size,
|
5
|
-
:nonblock, :retry_limit, :connect_timeout, :read_timeout, :write_timeout, :captures,
|
6
|
-
:exception, :expects, :mock, :proxy, :method, :idempotent, :request_block, :response_block,
|
7
|
-
:middlewares, :retries_remaining, :connection, :stack, :response, :pipeline]
|
3
|
+
|
8
4
|
attr_reader :data
|
9
5
|
|
10
6
|
def params
|
@@ -33,7 +29,6 @@ module Excon
|
|
33
29
|
private :assert_valid_keys_for_argument!
|
34
30
|
|
35
31
|
# Initializes a new Connection instance
|
36
|
-
# @param [String] url The destination URL
|
37
32
|
# @param [Hash<Symbol, >] params One or more optional params
|
38
33
|
# @option params [String] :body Default text to be sent over a socket. Only used if :body absent in Connection#request params
|
39
34
|
# @option params [Hash<Symbol, String>] :headers The default headers to supply in a request. Only used if params[:headers] is not supplied to Connection#request
|
@@ -46,21 +41,14 @@ module Excon
|
|
46
41
|
# @option params [Fixnum] :retry_limit Set how many times we'll retry a failed request. (Default 4)
|
47
42
|
# @option params [Class] :instrumentor Responds to #instrument as in ActiveSupport::Notifications
|
48
43
|
# @option params [String] :instrumentor_name Name prefix for #instrument events. Defaults to 'excon'
|
49
|
-
def initialize(
|
50
|
-
assert_valid_keys_for_argument!(params, VALID_CONNECTION_KEYS)
|
51
|
-
|
52
|
-
@data = Excon.defaults.merge({
|
53
|
-
:host => uri.host,
|
54
|
-
:path => uri.path,
|
55
|
-
:port => uri.port.to_s,
|
56
|
-
:query => uri.query,
|
57
|
-
:scheme => uri.scheme,
|
58
|
-
:user => (URI.decode(uri.user) if uri.user),
|
59
|
-
:password => (URI.decode(uri.password) if uri.password),
|
60
|
-
}).merge!(params)
|
44
|
+
def initialize(params = {})
|
45
|
+
assert_valid_keys_for_argument!(params, Excon::VALID_CONNECTION_KEYS)
|
46
|
+
@data = Excon.defaults.dup
|
61
47
|
# merge does not deep-dup, so make sure headers is not the original
|
62
48
|
@data[:headers] = @data[:headers].dup
|
63
49
|
|
50
|
+
@data.merge!(params)
|
51
|
+
|
64
52
|
if @data[:scheme] == HTTPS && (ENV.has_key?('https_proxy') || ENV.has_key?('HTTPS_PROXY'))
|
65
53
|
@data[:proxy] = setup_proxy(ENV['https_proxy'] || ENV['HTTPS_PROXY'])
|
66
54
|
elsif (ENV.has_key?('http_proxy') || ENV.has_key?('HTTP_PROXY'))
|
@@ -83,14 +71,20 @@ module Excon
|
|
83
71
|
end
|
84
72
|
|
85
73
|
# Use Basic Auth if url contains a login
|
86
|
-
if
|
87
|
-
@data[:headers]['Authorization'] ||= 'Basic ' << ['' <<
|
74
|
+
if @data[:user] || @data[:password]
|
75
|
+
@data[:headers]['Authorization'] ||= 'Basic ' << ['' << @data[:user].to_s << ':' << @data[:password].to_s].pack('m').delete(Excon::CR_NL)
|
88
76
|
end
|
89
77
|
|
90
|
-
@socket_key = '' << @data[:host] << ':' << @data[:port]
|
78
|
+
@socket_key = '' << @data[:host] << ':' << @data[:port].to_s
|
91
79
|
reset
|
92
80
|
end
|
93
81
|
|
82
|
+
def error_call(datum)
|
83
|
+
if datum[:error]
|
84
|
+
raise(datum[:error])
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
94
88
|
def request_call(datum)
|
95
89
|
begin
|
96
90
|
if datum.has_key?(:response)
|
@@ -210,7 +204,7 @@ module Excon
|
|
210
204
|
datum = @data.merge(params)
|
211
205
|
assert_valid_keys_for_argument!(params, VALID_CONNECTION_KEYS)
|
212
206
|
datum[:headers] = @data[:headers].merge(datum[:headers] || {})
|
213
|
-
datum[:headers]['Host'] ||= '' << datum[:host] << ':' << datum[:port]
|
207
|
+
datum[:headers]['Host'] ||= '' << datum[:host] << ':' << datum[:port].to_s
|
214
208
|
datum[:retries_remaining] ||= datum[:retry_limit]
|
215
209
|
|
216
210
|
# if path is empty or doesn't start with '/', insert one
|
@@ -243,18 +237,9 @@ module Excon
|
|
243
237
|
else
|
244
238
|
datum
|
245
239
|
end
|
246
|
-
rescue =>
|
247
|
-
|
248
|
-
|
249
|
-
Excon::Errors::HTTPStatusError].any? {|ex| request_error.kind_of? ex } && datum[:retries_remaining] > 1
|
250
|
-
datum[:retries_remaining] -= 1
|
251
|
-
request(datum, &block)
|
252
|
-
else
|
253
|
-
if datum.has_key?(:instrumentor)
|
254
|
-
datum[:instrumentor].instrument("#{datum[:instrumentor_name]}.error", :error => request_error)
|
255
|
-
end
|
256
|
-
raise(request_error)
|
257
|
-
end
|
240
|
+
rescue => error
|
241
|
+
datum[:error] = error
|
242
|
+
datum[:stack].error_call(datum)
|
258
243
|
end
|
259
244
|
|
260
245
|
# Sends the supplied requests to the destination host using pipelining.
|
data/lib/excon/constants.rb
CHANGED
@@ -29,7 +29,47 @@ module Excon
|
|
29
29
|
|
30
30
|
REDACTED = 'REDACTED'
|
31
31
|
|
32
|
-
|
32
|
+
VALID_CONNECTION_KEYS = [
|
33
|
+
:body,
|
34
|
+
:captures,
|
35
|
+
:chunk_size,
|
36
|
+
:connect_timeout,
|
37
|
+
:connection,
|
38
|
+
:error,
|
39
|
+
:exception,
|
40
|
+
:expects,
|
41
|
+
:family,
|
42
|
+
:headers,
|
43
|
+
:host,
|
44
|
+
:idempotent,
|
45
|
+
:instrumentor,
|
46
|
+
:instrumentor_name,
|
47
|
+
:method,
|
48
|
+
:middlewares,
|
49
|
+
:mock,
|
50
|
+
:nonblock,
|
51
|
+
:password,
|
52
|
+
:path,
|
53
|
+
:pipeline,
|
54
|
+
:port,
|
55
|
+
:proxy,
|
56
|
+
:query,
|
57
|
+
:read_timeout,
|
58
|
+
:request_block,
|
59
|
+
:response,
|
60
|
+
:response_block,
|
61
|
+
:retries_remaining,
|
62
|
+
:retry_limit,
|
63
|
+
:scheme,
|
64
|
+
:uri_parser,
|
65
|
+
:user,
|
66
|
+
:ssl_ca_file,
|
67
|
+
:ssl_verify_peer,
|
68
|
+
:stack,
|
69
|
+
:write_timeout
|
70
|
+
]
|
71
|
+
|
72
|
+
VERSION = '0.19.0'
|
33
73
|
|
34
74
|
unless ::IO.const_defined?(:WaitReadable)
|
35
75
|
class ::IO
|
data/lib/excon/errors.rb
CHANGED
@@ -2,6 +2,7 @@ module Excon
|
|
2
2
|
module Errors
|
3
3
|
|
4
4
|
class Error < StandardError; end
|
5
|
+
class StubNotFound < StandardError; end
|
5
6
|
|
6
7
|
class SocketError < Error
|
7
8
|
attr_reader :socket_error
|
@@ -23,8 +24,6 @@ module Excon
|
|
23
24
|
|
24
25
|
class ProxyConnectionError < Error; end
|
25
26
|
|
26
|
-
class StubNotFound < Error; end
|
27
|
-
|
28
27
|
class HTTPStatusError < Error
|
29
28
|
attr_reader :request, :response
|
30
29
|
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Excon
|
2
|
+
module Middleware
|
3
|
+
class Idempotent < Excon::Middleware::Base
|
4
|
+
def error_call(datum)
|
5
|
+
if datum[:idempotent] && [Excon::Errors::Timeout, Excon::Errors::SocketError,
|
6
|
+
Excon::Errors::HTTPStatusError].any? {|ex| datum[:error].kind_of?(ex) } && datum[:retries_remaining] > 1
|
7
|
+
# reduces remaining retries, reset connection, and restart request_call
|
8
|
+
datum[:retries_remaining] -= 1
|
9
|
+
datum[:connection].reset
|
10
|
+
datum.delete(:error)
|
11
|
+
datum[:connection].request(datum)
|
12
|
+
else
|
13
|
+
@stack.error_call(datum)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,6 +1,13 @@
|
|
1
1
|
module Excon
|
2
2
|
module Middleware
|
3
3
|
class Instrumentor < Excon::Middleware::Base
|
4
|
+
def error_call(datum)
|
5
|
+
if datum.has_key?(:instrumentor)
|
6
|
+
datum[:instrumentor].instrument("#{datum[:instrumentor_name]}.error", :error => datum[:error])
|
7
|
+
end
|
8
|
+
@stack.error_call(datum)
|
9
|
+
end
|
10
|
+
|
4
11
|
def request_call(datum)
|
5
12
|
if datum.has_key?(:instrumentor)
|
6
13
|
if datum[:retries_remaining] < datum[:retry_limit]
|
data/tests/basic_tests.rb
CHANGED
@@ -2,6 +2,24 @@ with_rackup('basic.ru') do
|
|
2
2
|
Shindo.tests('Excon basics') do
|
3
3
|
basic_tests
|
4
4
|
end
|
5
|
+
|
6
|
+
Shindo.tests('explicit uri passed to connection') do
|
7
|
+
connection = Excon::Connection.new({
|
8
|
+
:host => '127.0.0.1',
|
9
|
+
:nonblock => false,
|
10
|
+
:port => 9292,
|
11
|
+
:scheme => 'http',
|
12
|
+
:ssl_verify_peer => false
|
13
|
+
})
|
14
|
+
|
15
|
+
tests('GET /content-length/100') do
|
16
|
+
response = connection.request(:method => :get, :path => '/content-length/100')
|
17
|
+
|
18
|
+
tests('response[:status]').returns(200) do
|
19
|
+
response[:status]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
5
23
|
end
|
6
24
|
|
7
25
|
with_rackup('basic_auth.ru') do
|
File without changes
|
@@ -167,6 +167,15 @@ Shindo.tests('Excon stubs') do
|
|
167
167
|
connection.request(:expects => 200, :method => :get, :path => '/')
|
168
168
|
end
|
169
169
|
|
170
|
+
tests("Expects exception should contain response object") do
|
171
|
+
begin
|
172
|
+
connection.request(:expects => 200, :method => :get, :path => '/')
|
173
|
+
rescue Excon::Errors::NotFound => e
|
174
|
+
returns(Excon::Response) { e.response.class }
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
|
170
179
|
test("request(:expects => 200, :method => :get, :path => '/') with block does not invoke the block since it raises an error") do
|
171
180
|
block_called = false
|
172
181
|
begin
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: excon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.19.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2013-02-
|
14
|
+
date: 2013-02-27 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: activesupport
|
@@ -179,6 +179,7 @@ files:
|
|
179
179
|
- lib/excon/errors.rb
|
180
180
|
- lib/excon/middlewares/base.rb
|
181
181
|
- lib/excon/middlewares/expects.rb
|
182
|
+
- lib/excon/middlewares/idempotent.rb
|
182
183
|
- lib/excon/middlewares/instrumentor.rb
|
183
184
|
- lib/excon/middlewares/mock.rb
|
184
185
|
- lib/excon/response.rb
|
@@ -190,7 +191,7 @@ files:
|
|
190
191
|
- tests/basic_tests.rb
|
191
192
|
- tests/data/xs
|
192
193
|
- tests/header_tests.rb
|
193
|
-
- tests/idempotent_tests.rb
|
194
|
+
- tests/middlewares/idempotent_tests.rb
|
194
195
|
- tests/middlewares/instrumentation_tests.rb
|
195
196
|
- tests/middlewares/mock_tests.rb
|
196
197
|
- tests/proxy_tests.rb
|
@@ -229,7 +230,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
229
230
|
version: '0'
|
230
231
|
segments:
|
231
232
|
- 0
|
232
|
-
hash:
|
233
|
+
hash: 4361906214434444580
|
233
234
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
234
235
|
none: false
|
235
236
|
requirements:
|