excon 0.22.1 → 0.23.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.22.1)
4
+ excon (0.23.0)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
data/README.md CHANGED
@@ -83,6 +83,13 @@ Both one-off and persistent connections support many other options. Here are a f
83
83
  # set longer write_timeout (default is 60 seconds)
84
84
  connection.request(:write_timeout => 360)
85
85
 
86
+ # Enable the socket option TCP_NODELAY on the underlying socket.
87
+ #
88
+ # This can improve response time when sending frequent short
89
+ # requests in time-sensitive scenarios.
90
+ #
91
+ connection = Excon.new('http://geemus.com/', :tcp_nodelay => true)
92
+
86
93
  These options can be combined to make pretty much any request you might need.
87
94
 
88
95
  Excon can also expect one or more HTTP status code in response, raising an exception if the response does not meet the criteria.
@@ -251,7 +258,7 @@ Copyright
251
258
 
252
259
  (The MIT License)
253
260
 
254
- Copyright (c) 2010-2011 {geemus (Wesley Beary)}[http://github.com/geemus]
261
+ Copyright (c) 2010-2013 {geemus (Wesley Beary)}[http://github.com/geemus]
255
262
 
256
263
  Permission is hereby granted, free of charge, to any person obtaining
257
264
  a copy of this software and associated documentation files (the
@@ -1,3 +1,13 @@
1
+ 0.23.0 06/10/2013
2
+ =================
3
+
4
+ defer writing request/headers to allow all-in-one
5
+ allow opt-in for request/response error info
6
+ add configurable TCP_NODELAY
7
+ consolidate warning display
8
+ respect ruby verbosity conventions
9
+ fix copyright years in notice
10
+
1
11
  0.22.1 05/17/2013
2
12
  =================
3
13
 
@@ -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.22.1'
17
- s.date = '2013-05-17'
16
+ s.version = '0.23.0'
17
+ s.date = '2013-06-10'
18
18
  s.rubyforge_project = 'excon'
19
19
 
20
20
  ## Make sure your summary is short. The description may be as long
@@ -111,6 +111,7 @@ Gem::Specification.new do |s|
111
111
  tests/data/excon.cert.crt
112
112
  tests/data/excon.cert.key
113
113
  tests/data/xs
114
+ tests/errors_tests.rb
114
115
  tests/header_tests.rb
115
116
  tests/middlewares/idempotent_tests.rb
116
117
  tests/middlewares/instrumentation_tests.rb
@@ -134,6 +135,7 @@ Gem::Specification.new do |s|
134
135
  tests/requests_tests.rb
135
136
  tests/servers/bad.rb
136
137
  tests/servers/eof.rb
138
+ tests/servers/error.rb
137
139
  tests/test_helper.rb
138
140
  tests/thread_safety_tests.rb
139
141
  tests/timeout_tests.rb
@@ -18,6 +18,8 @@ module Excon
18
18
  @defaults ||= {
19
19
  :chunk_size => CHUNK_SIZE || DEFAULT_CHUNK_SIZE,
20
20
  :connect_timeout => 60,
21
+ :debug_request => false,
22
+ :debug_response => false,
21
23
  :headers => {},
22
24
  :idempotent => false,
23
25
  :instrumentor_name => 'excon',
@@ -34,6 +36,7 @@ module Excon
34
36
  :retry_limit => DEFAULT_RETRY_LIMIT,
35
37
  :ssl_ca_file => DEFAULT_CA_FILE,
36
38
  :ssl_verify_peer => RbConfig::CONFIG['host_os'] !~ /mswin|win32|dos|cygwin|mingw/i,
39
+ :tcp_nodelay => false,
37
40
  :uri_parser => URI,
38
41
  :write_timeout => 60
39
42
  }
@@ -64,9 +67,14 @@ require 'excon/standard_instrumentor'
64
67
  module Excon
65
68
  class << self
66
69
 
70
+ def display_warning(warning)
71
+ # Ruby convention mandates complete silence when VERBOSE == nil
72
+ $stderr.puts(warning) if !ENV['VERBOSE'].nil?
73
+ end
74
+
67
75
  # Status of mocking
68
76
  def mock
69
- $stderr.puts("Excon#mock is deprecated, pass Excon.defaults[:mock] instead (#{caller.first})")
77
+ display_warning("Excon#mock is deprecated, pass Excon.defaults[:mock] instead (#{caller.first}")
70
78
  self.defaults[:mock]
71
79
  end
72
80
 
@@ -74,33 +82,33 @@ module Excon
74
82
  # false is the default and works as expected
75
83
  # true returns a value from stubs or raises
76
84
  def mock=(new_mock)
77
- $stderr.puts("Excon#mock is deprecated, pass Excon.defaults[:mock]= instead (#{caller.first})")
85
+ display_warning("Excon#mock is deprecated, pass Excon.defaults[:mock]= instead (#{caller.first})")
78
86
  self.defaults[:mock] = new_mock
79
87
  end
80
88
 
81
89
  # @return [String] The filesystem path to the SSL Certificate Authority
82
90
  def ssl_ca_path
83
- $stderr.puts("Excon#ssl_ca_path is deprecated, use Excon.defaults[:ssl_ca_path] instead (#{caller.first})")
91
+ display_warning("Excon#ssl_ca_path is deprecated, use Excon.defaults[:ssl_ca_path] instead (#{caller.first})")
84
92
  self.defaults[:ssl_ca_path]
85
93
  end
86
94
 
87
95
  # Change path to the SSL Certificate Authority
88
96
  # @return [String] The filesystem path to the SSL Certificate Authority
89
97
  def ssl_ca_path=(new_ssl_ca_path)
90
- $stderr.puts("Excon#ssl_ca_path= is deprecated, use Excon.defaults[:ssl_ca_path]= instead (#{caller.first})")
98
+ display_warning("Excon#ssl_ca_path= is deprecated, use Excon.defaults[:ssl_ca_path]= instead (#{caller.first})")
91
99
  self.defaults[:ssl_ca_path] = new_ssl_ca_path
92
100
  end
93
101
 
94
102
  # @return [true, false] Whether or not to verify the peer's SSL certificate / chain
95
103
  def ssl_verify_peer
96
- $stderr.puts("Excon#ssl_verify_peer= is deprecated, use Excon.defaults[:ssl_verify_peer]= instead (#{caller.first})")
104
+ display_warning("Excon#ssl_verify_peer= is deprecated, use Excon.defaults[:ssl_verify_peer]= instead (#{caller.first})")
97
105
  self.defaults[:ssl_verify_peer]
98
106
  end
99
107
 
100
108
  # Change the status of ssl peer verification
101
109
  # @see Excon#ssl_verify_peer (attr_reader)
102
110
  def ssl_verify_peer=(new_ssl_verify_peer)
103
- $stderr.puts("Excon#ssl_verify_peer is deprecated, use Excon.defaults[:ssl_verify_peer] instead (#{caller.first})")
111
+ display_warning("Excon#ssl_verify_peer is deprecated, use Excon.defaults[:ssl_verify_peer] instead (#{caller.first})")
104
112
  self.defaults[:ssl_verify_peer] = new_ssl_verify_peer
105
113
  end
106
114
 
@@ -4,29 +4,29 @@ module Excon
4
4
  attr_reader :data
5
5
 
6
6
  def connection
7
- $stderr.puts("Excon::Connection#connection is deprecated use Excon::Connection#data instead (#{caller.first})")
7
+ Excon.display_warning("Excon::Connection#connection is deprecated use Excon::Connection#data instead (#{caller.first})")
8
8
  @data
9
9
  end
10
10
  def connection=(new_params)
11
- $stderr.puts("Excon::Connection#connection= is deprecated use Excon::Connection#data= instead (#{caller.first})")
11
+ Excon.display_warning("Excon::Connection#connection= is deprecated use Excon::Connection#data= instead (#{caller.first})")
12
12
  @data = new_params
13
13
  end
14
14
 
15
15
  def params
16
- $stderr.puts("Excon::Connection#params is deprecated use Excon::Connection#data instead (#{caller.first})")
16
+ display_waring("Excon::Connection#params is deprecated use Excon::Connection#data instead (#{caller.first})")
17
17
  @data
18
18
  end
19
19
  def params=(new_params)
20
- $stderr.puts("Excon::Connection#params= is deprecated use Excon::Connection#data= instead (#{caller.first})")
20
+ Excon.display_warning("Excon::Connection#params= is deprecated use Excon::Connection#data= instead (#{caller.first})")
21
21
  @data = new_params
22
22
  end
23
23
 
24
24
  def proxy
25
- $stderr.puts("Excon::Connection#proxy is deprecated use Excon::Connection#data[:proxy] instead (#{caller.first})")
25
+ Excon.display_warning("Excon::Connection#proxy is deprecated use Excon::Connection#data[:proxy] instead (#{caller.first})")
26
26
  @data[:proxy]
27
27
  end
28
28
  def proxy=(new_proxy)
29
- $stderr.puts("Excon::Connection#proxy= is deprecated use Excon::Connection#data[:proxy]= instead (#{caller.first})")
29
+ Excon.display_warning("Excon::Connection#proxy= is deprecated use Excon::Connection#data[:proxy]= instead (#{caller.first})") if !ENV['VERBOSE'].nil?
30
30
  @data[:proxy] = new_proxy
31
31
  end
32
32
 
@@ -149,12 +149,9 @@ module Excon
149
149
  # add additional "\r\n" to indicate end of headers
150
150
  request << CR_NL
151
151
 
152
- # write out the request, sans body
153
- socket.write(request)
154
-
155
- # write out the body
156
152
  if datum.has_key?(:request_block)
157
- while true
153
+ socket.write(request) # write out request + headers
154
+ while true # write out body with chunked encoding
158
155
  chunk = datum[:request_block].call
159
156
  if FORCE_ENC
160
157
  chunk.force_encoding('BINARY')
@@ -167,11 +164,10 @@ module Excon
167
164
  end
168
165
  end
169
166
  elsif !datum[:body].nil?
170
- if datum[:body].is_a?(String)
171
- unless datum[:body].empty?
172
- socket.write(datum[:body])
173
- end
174
- else
167
+ if datum[:body].is_a?(String) # write out string body
168
+ socket.write(request << datum[:body]) # write out request + headers + body
169
+ else # write out file body
170
+ socket.write(request) # write out request + headers
175
171
  if datum[:body].respond_to?(:binmode)
176
172
  datum[:body].binmode
177
173
  end
@@ -182,6 +178,8 @@ module Excon
182
178
  socket.write(chunk)
183
179
  end
184
180
  end
181
+ else # write out nil body
182
+ socket.write(request) # write out request + headers
185
183
  end
186
184
  end
187
185
  rescue => error
@@ -232,7 +230,7 @@ module Excon
232
230
  end
233
231
 
234
232
  if block_given?
235
- $stderr.puts("Excon requests with a block are deprecated, pass :response_block instead (#{caller.first})")
233
+ Excon.display_warning("Excon requests with a block are deprecated, pass :response_block instead (#{caller.first})")
236
234
  datum[:response_block] = Proc.new
237
235
  end
238
236
 
@@ -289,12 +287,12 @@ module Excon
289
287
  end
290
288
 
291
289
  def retry_limit=(new_retry_limit)
292
- $stderr.puts("Excon::Connection#retry_limit= is deprecated, pass :retry_limit to the initializer (#{caller.first})")
290
+ Excon.display_warning("Excon::Connection#retry_limit= is deprecated, pass :retry_limit to the initializer (#{caller.first})")
293
291
  @data[:retry_limit] = new_retry_limit
294
292
  end
295
293
 
296
294
  def retry_limit
297
- $stderr.puts("Excon::Connection#retry_limit is deprecated, pass :retry_limit to the initializer (#{caller.first})")
295
+ Excon.display_warning("Excon::Connection#retry_limit is deprecated, pass :retry_limit to the initializer (#{caller.first})")
298
296
  @data[:retry_limit] ||= DEFAULT_RETRY_LIMIT
299
297
  end
300
298
 
@@ -343,7 +341,7 @@ module Excon
343
341
  def invalid_keys_warning(argument, valid_keys)
344
342
  invalid_keys = argument.keys - valid_keys
345
343
  unless invalid_keys.empty?
346
- $stderr.puts("The following keys are invalid: #{invalid_keys.map(&:inspect).join(', ')}")
344
+ Excon.display_warning("The following keys are invalid: #{invalid_keys.map(&:inspect).join(', ')}")
347
345
  end
348
346
  end
349
347
 
@@ -37,6 +37,8 @@ module Excon
37
37
  :client_cert,
38
38
  :connect_timeout,
39
39
  :connection,
40
+ :debug_request,
41
+ :debug_response,
40
42
  :error,
41
43
  :exception,
42
44
  :expects,
@@ -64,6 +66,7 @@ module Excon
64
66
  :retries_remaining,
65
67
  :retry_limit,
66
68
  :scheme,
69
+ :tcp_nodelay,
67
70
  :uri_parser,
68
71
  :user,
69
72
  :ssl_ca_file,
@@ -72,7 +75,7 @@ module Excon
72
75
  :write_timeout
73
76
  ]
74
77
 
75
- VERSION = '0.22.1'
78
+ VERSION = '0.23.0'
76
79
 
77
80
  unless ::IO.const_defined?(:WaitReadable)
78
81
  class ::IO
@@ -121,7 +121,23 @@ module Excon
121
121
  }
122
122
 
123
123
  error, message = @errors[response[:status]] || [Excon::Errors::HTTPStatusError, 'Unknown']
124
- error.new("Expected(#{request[:expects].inspect}) <=> Actual(#{response[:status]} #{message})", request, response)
124
+
125
+ message = "Expected(#{request[:expects].inspect}) <=> Actual(#{response[:status]} #{message})"
126
+
127
+ if request[:debug_request]
128
+ # scrub authorization
129
+ req = request.dup
130
+ req.reject! {|key, value| [:connection, :stack].include?(key)}
131
+ if req.has_key?(:headers) && req[:headers].has_key?('Authorization')
132
+ req[:headers] = req[:headers].dup
133
+ req[:headers]['Authorization'] = REDACTED
134
+ end
135
+ message << "\n request => #{req.inspect}"
136
+ end
137
+
138
+ message << "\n response => #{response.inspect}" if request[:debug_response]
139
+
140
+ error.new(message, request, response)
125
141
  end
126
142
 
127
143
  end
@@ -106,7 +106,7 @@ module Excon
106
106
  end
107
107
 
108
108
  def params
109
- $stderr.puts("Excon::Response#params is deprecated use Excon::Response#data instead (#{caller.first})")
109
+ Excon.display_warning("Excon::Response#params is deprecated use Excon::Response#data instead (#{caller.first})")
110
110
  data
111
111
  end
112
112
 
@@ -6,11 +6,11 @@ module Excon
6
6
  attr_accessor :data
7
7
 
8
8
  def params
9
- $stderr.puts("Excon::Socket#params is deprecated use Excon::Socket#data instead (#{caller.first})")
9
+ Excon.display_warning("Excon::Socket#params is deprecated use Excon::Socket#data instead (#{caller.first})")
10
10
  @data
11
11
  end
12
12
  def params=(new_params)
13
- $stderr.puts("Excon::Socket#params= is deprecated use Excon::Socket#data= instead (#{caller.first})")
13
+ Excon.display_warning("Excon::Socket#params= is deprecated use Excon::Socket#data= instead (#{caller.first})")
14
14
  @data = new_params
15
15
  end
16
16
 
@@ -198,6 +198,12 @@ module Excon
198
198
  # this will be our last encountered exception
199
199
  raise exception
200
200
  end
201
+
202
+ if @data[:tcp_nodelay]
203
+ @socket.setsockopt(::Socket::IPPROTO_TCP,
204
+ ::Socket::TCP_NODELAY,
205
+ true)
206
+ end
201
207
  end
202
208
 
203
209
  end
@@ -82,7 +82,7 @@ module Excon
82
82
  def check_nonblock_support
83
83
  # backwards compatability for things lacking nonblock
84
84
  if !DEFAULT_NONBLOCK && @data[:nonblock]
85
- $stderr.puts("Excon nonblock is not supported by your OpenSSL::SSL::SSLSocket")
85
+ Excon.display_warning("Excon nonblock is not supported by your OpenSSL::SSL::SSLSocket")
86
86
  @data[:nonblock] = false
87
87
  end
88
88
  end
@@ -0,0 +1,49 @@
1
+ Shindo.tests('HTTPStatusError request/response debugging') do
2
+
3
+ with_server('error') do
4
+
5
+ tests('message does not include response or response info').returns(true) do
6
+ begin
7
+ Excon.get('http://127.0.0.1:9292/error/not_found', :expects => 200)
8
+ rescue => err
9
+ err.message.include?('Expected(200) <=> Actual(404 Not Found)') &&
10
+ !err.message.include?('request =>') &&
11
+ !err.message.include?('response =>')
12
+ end
13
+ end
14
+
15
+ tests('message includes only response info').returns(true) do
16
+ begin
17
+ Excon.get('http://127.0.0.1:9292/error/not_found', :expects => 200,
18
+ :debug_response => true)
19
+ rescue => err
20
+ err.message.include?('Expected(200) <=> Actual(404 Not Found)') &&
21
+ !err.message.include?('request =>') &&
22
+ !!(err.message =~ /response =>(.*)server says not found/)
23
+ end
24
+ end
25
+
26
+ tests('message includes only request info').returns(true) do
27
+ begin
28
+ Excon.get('http://127.0.0.1:9292/error/not_found', :expects => 200,
29
+ :debug_request => true)
30
+ rescue => err
31
+ err.message.include?('Expected(200) <=> Actual(404 Not Found)') &&
32
+ !!(err.message =~ /request =>(.*)error\/not_found/) &&
33
+ !err.message.include?('response =>')
34
+ end
35
+ end
36
+
37
+ tests('message include request and response info').returns(true) do
38
+ begin
39
+ Excon.get('http://127.0.0.1:9292/error/not_found', :expects => 200,
40
+ :debug_request => true, :debug_response => true)
41
+ rescue => err
42
+ err.message.include?('Expected(200) <=> Actual(404 Not Found)') &&
43
+ !!(err.message =~ /request =>(.*)not_found/) &&
44
+ !!(err.message =~ /response =>(.*)server says not found/)
45
+ end
46
+ end
47
+
48
+ end
49
+ end
@@ -28,4 +28,19 @@ with_rackup('basic.ru') do
28
28
  end
29
29
 
30
30
  end
31
+
32
+ Shindo.tests('requests should succeed with tcp_nodelay') do
33
+
34
+ connection = Excon.new('http://127.0.0.1:9292', :tcp_nodelay => true)
35
+
36
+ tests('GET /content-length/100') do
37
+ responses = connection.requests([
38
+ {:method => :get, :path => '/content-length/100'}
39
+ ])
40
+
41
+ tests('get content length is 100').returns('100') do
42
+ responses.last.headers['Content-Length']
43
+ end
44
+ end
45
+ end
31
46
  end
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "eventmachine"
4
+
5
+ module ErrorServer
6
+ def receive_data(data)
7
+ case data
8
+ when %r{^GET /error/not_found\s}
9
+ send_data "HTTP/1.1 404 Not Found\r\n"
10
+ send_data "\r\n"
11
+ send_data "server says not found"
12
+ close_connection(true)
13
+ end
14
+ end
15
+ end
16
+
17
+ EM.run do
18
+ EM.start_server("127.0.0.1", 9292, ErrorServer)
19
+ $stderr.puts "ready"
20
+ end
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.22.1
4
+ version: 0.23.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-05-17 00:00:00.000000000 Z
14
+ date: 2013-06-10 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: activesupport
@@ -192,6 +192,7 @@ files:
192
192
  - tests/data/excon.cert.crt
193
193
  - tests/data/excon.cert.key
194
194
  - tests/data/xs
195
+ - tests/errors_tests.rb
195
196
  - tests/header_tests.rb
196
197
  - tests/middlewares/idempotent_tests.rb
197
198
  - tests/middlewares/instrumentation_tests.rb
@@ -215,6 +216,7 @@ files:
215
216
  - tests/requests_tests.rb
216
217
  - tests/servers/bad.rb
217
218
  - tests/servers/eof.rb
219
+ - tests/servers/error.rb
218
220
  - tests/test_helper.rb
219
221
  - tests/thread_safety_tests.rb
220
222
  - tests/timeout_tests.rb
@@ -233,7 +235,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
233
235
  version: '0'
234
236
  segments:
235
237
  - 0
236
- hash: 1091167854522942329
238
+ hash: -3656231066806112421
237
239
  required_rubygems_version: !ruby/object:Gem::Requirement
238
240
  none: false
239
241
  requirements: