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.

@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- excon (0.18.5)
4
+ excon (0.19.0)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
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
  -------------------
@@ -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
 
@@ -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.18.5'
17
- s.date = '2013-02-22'
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
@@ -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::Connection.new(url, params)
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
@@ -1,10 +1,6 @@
1
1
  module Excon
2
2
  class Connection
3
- VALID_CONNECTION_KEYS = [:body, :family, :headers, :host, :path, :port, :query, :scheme, :user, :password,
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(url, params = {})
50
- assert_valid_keys_for_argument!(params, VALID_CONNECTION_KEYS)
51
- uri = URI.parse(url)
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 uri.user || uri.password
87
- @data[:headers]['Authorization'] ||= 'Basic ' << ['' << uri.user.to_s << ':' << uri.password.to_s].pack('m').delete(Excon::CR_NL)
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 => request_error
247
- reset
248
- if datum[:idempotent] && [Excon::Errors::Timeout, Excon::Errors::SocketError,
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.
@@ -29,7 +29,47 @@ module Excon
29
29
 
30
30
  REDACTED = 'REDACTED'
31
31
 
32
- VERSION = '0.18.5'
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
@@ -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
 
@@ -5,6 +5,11 @@ module Excon
5
5
  @stack = stack
6
6
  end
7
7
 
8
+ def error_call(datum)
9
+ # do stuff
10
+ @stack.error_call(datum)
11
+ end
12
+
8
13
  def request_call(datum)
9
14
  # do stuff
10
15
  @stack.request_call(datum)
@@ -6,7 +6,7 @@ module Excon
6
6
  raise(
7
7
  Excon::Errors.status_error(
8
8
  datum.reject {|key,value| key == :response},
9
- datum[:response]
9
+ Excon::Response.new(datum[:response])
10
10
  )
11
11
  )
12
12
  else
@@ -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]
@@ -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
@@ -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.18.5
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-22 00:00:00.000000000 Z
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: -3422335355113761229
233
+ hash: 4361906214434444580
233
234
  required_rubygems_version: !ruby/object:Gem::Requirement
234
235
  none: false
235
236
  requirements: