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.
- data/Gemfile.lock +1 -1
- data/README.md +8 -1
- data/changelog.txt +10 -0
- data/excon.gemspec +4 -2
- data/lib/excon.rb +14 -6
- data/lib/excon/connection.rb +18 -20
- data/lib/excon/constants.rb +4 -1
- data/lib/excon/errors.rb +17 -1
- data/lib/excon/response.rb +1 -1
- data/lib/excon/socket.rb +8 -2
- data/lib/excon/ssl_socket.rb +1 -1
- data/tests/errors_tests.rb +49 -0
- data/tests/requests_tests.rb +15 -0
- data/tests/servers/error.rb +20 -0
- metadata +5 -3
data/Gemfile.lock
CHANGED
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-
|
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
|
data/changelog.txt
CHANGED
@@ -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
|
|
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-
|
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
|
data/lib/excon.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
|
data/lib/excon/connection.rb
CHANGED
@@ -4,29 +4,29 @@ module Excon
|
|
4
4
|
attr_reader :data
|
5
5
|
|
6
6
|
def connection
|
7
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
172
|
-
|
173
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
344
|
+
Excon.display_warning("The following keys are invalid: #{invalid_keys.map(&:inspect).join(', ')}")
|
347
345
|
end
|
348
346
|
end
|
349
347
|
|
data/lib/excon/constants.rb
CHANGED
@@ -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.
|
78
|
+
VERSION = '0.23.0'
|
76
79
|
|
77
80
|
unless ::IO.const_defined?(:WaitReadable)
|
78
81
|
class ::IO
|
data/lib/excon/errors.rb
CHANGED
@@ -121,7 +121,23 @@ module Excon
|
|
121
121
|
}
|
122
122
|
|
123
123
|
error, message = @errors[response[:status]] || [Excon::Errors::HTTPStatusError, 'Unknown']
|
124
|
-
|
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
|
data/lib/excon/response.rb
CHANGED
@@ -106,7 +106,7 @@ module Excon
|
|
106
106
|
end
|
107
107
|
|
108
108
|
def params
|
109
|
-
|
109
|
+
Excon.display_warning("Excon::Response#params is deprecated use Excon::Response#data instead (#{caller.first})")
|
110
110
|
data
|
111
111
|
end
|
112
112
|
|
data/lib/excon/socket.rb
CHANGED
@@ -6,11 +6,11 @@ module Excon
|
|
6
6
|
attr_accessor :data
|
7
7
|
|
8
8
|
def params
|
9
|
-
|
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
|
-
|
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
|
data/lib/excon/ssl_socket.rb
CHANGED
@@ -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
|
-
|
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
|
data/tests/requests_tests.rb
CHANGED
@@ -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.
|
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-
|
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:
|
238
|
+
hash: -3656231066806112421
|
237
239
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
238
240
|
none: false
|
239
241
|
requirements:
|