persistent_http 1.0.1 → 1.0.2
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.
- data/History.md +17 -0
- data/LICENSE +1 -1
- data/Rakefile +31 -13
- data/lib/persistent_http.rb +6 -3
- metadata +46 -69
- data/.gitignore +0 -4
- data/History.txt +0 -4
- data/VERSION +0 -1
- data/persistent_http.gemspec +0 -53
- data/test/persistent_http_test.rb +0 -647
data/History.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
PersistentHttp Changelog
|
2
|
+
=====================
|
3
|
+
|
4
|
+
1.0.2
|
5
|
+
|
6
|
+
- Allow options to request to allow changing of read_timeout and possibly other params.
|
7
|
+
- Add ECONNREFUSED as a retriable exception.
|
8
|
+
|
9
|
+
1.0.1
|
10
|
+
|
11
|
+
- Bug fixes.
|
12
|
+
- Forgot gene_pool dependency
|
13
|
+
|
14
|
+
1.0.0
|
15
|
+
|
16
|
+
- Initial release
|
17
|
+
|
data/LICENSE
CHANGED
data/Rakefile
CHANGED
@@ -1,17 +1,35 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
require 'rubygems'
|
2
|
-
require 'rake'
|
3
|
-
|
4
3
|
begin
|
5
|
-
require '
|
6
|
-
Jeweler::Tasks.new do |gemspec|
|
7
|
-
gemspec.name = "persistent_http"
|
8
|
-
gemspec.summary = "Persistent HTTP connections using a connection pool"
|
9
|
-
gemspec.description = "Persistent HTTP connections using a connection pool"
|
10
|
-
gemspec.email = "bradpardee@gmail.com"
|
11
|
-
gemspec.homepage = "http://github.com/bpardee/persistent_http"
|
12
|
-
gemspec.authors = ["Brad Pardee"]
|
13
|
-
gemspec.add_dependency 'gene_pool', [">= 1.0.1"]
|
14
|
-
end
|
4
|
+
require 'bundler/setup'
|
15
5
|
rescue LoadError
|
16
|
-
puts
|
6
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'rake'
|
10
|
+
#require 'rake/dsl_definition'
|
11
|
+
require 'rdoc/task'
|
12
|
+
require 'rake/testtask'
|
13
|
+
require 'rake/clean'
|
14
|
+
|
15
|
+
desc "Build gem"
|
16
|
+
task :gem do |t|
|
17
|
+
system 'gem build persistent_http.gemspec'
|
18
|
+
end
|
19
|
+
|
20
|
+
Rake::TestTask.new(:test) do |t|
|
21
|
+
t.libs << 'lib'
|
22
|
+
t.libs << 'test'
|
23
|
+
t.pattern = 'test/**/*_test.rb'
|
24
|
+
t.verbose = false
|
25
|
+
end
|
26
|
+
|
27
|
+
task :default => :test
|
28
|
+
|
29
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
30
|
+
rdoc.rdoc_dir = 'rdoc'
|
31
|
+
rdoc.title = 'PersistentHttp'
|
32
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
33
|
+
rdoc.rdoc_files.include('README.rdoc')
|
34
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
17
35
|
end
|
data/lib/persistent_http.rb
CHANGED
@@ -258,7 +258,7 @@ class PersistentHTTP
|
|
258
258
|
# If there is an error and the request is idempontent according to RFC 2616
|
259
259
|
# it will be retried automatically.
|
260
260
|
|
261
|
-
def request
|
261
|
+
def request(req = nil, options = {}, &block)
|
262
262
|
retried = false
|
263
263
|
bad_response = false
|
264
264
|
|
@@ -273,12 +273,15 @@ class PersistentHTTP
|
|
273
273
|
|
274
274
|
@pool.with_connection do |connection|
|
275
275
|
begin
|
276
|
+
options.each do |key, value|
|
277
|
+
connection.send("#{key}=", value)
|
278
|
+
end
|
276
279
|
response = connection.request req, &block
|
277
280
|
@http_version ||= response.http_version
|
278
281
|
@count_hash[connection.object_id] += 1
|
279
282
|
return response
|
280
283
|
|
281
|
-
rescue
|
284
|
+
rescue Timeout::Error => e
|
282
285
|
due_to = "(due to #{e.message} - #{e.class})"
|
283
286
|
message = error_message connection
|
284
287
|
@logger.info "#{name}: Removing connection #{due_to} #{message}" if @logger
|
@@ -298,7 +301,7 @@ class PersistentHTTP
|
|
298
301
|
retry
|
299
302
|
end
|
300
303
|
|
301
|
-
rescue IOError, EOFError, Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE => e
|
304
|
+
rescue IOError, EOFError, Errno::ECONNABORTED, Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::EPIPE => e
|
302
305
|
due_to = "(due to #{e.message} - #{e.class})"
|
303
306
|
message = error_message connection
|
304
307
|
if retried or not (idempotent? req or @force_retry)
|
metadata
CHANGED
@@ -1,85 +1,62 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: persistent_http
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
- 1
|
7
|
-
- 0
|
8
|
-
- 1
|
9
|
-
version: 1.0.1
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.2
|
5
|
+
prerelease:
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
12
|
-
|
7
|
+
authors:
|
8
|
+
- Brad Pardee
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
- 0
|
30
|
-
- 1
|
31
|
-
version: 1.0.1
|
32
|
-
type: :runtime
|
33
|
-
version_requirements: *id001
|
12
|
+
date: 2012-02-03 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: gene_pool
|
16
|
+
requirement: &70318434795540 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.0.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70318434795540
|
34
25
|
description: Persistent HTTP connections using a connection pool
|
35
|
-
email:
|
26
|
+
email:
|
27
|
+
- bradpardee@gmail.com
|
36
28
|
executables: []
|
37
|
-
|
38
29
|
extensions: []
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
- README.rdoc
|
48
|
-
- Rakefile
|
49
|
-
- VERSION
|
50
|
-
- lib/persistent_http.rb
|
51
|
-
- lib/persistent_http/faster.rb
|
52
|
-
- persistent_http.gemspec
|
53
|
-
- test/persistent_http_test.rb
|
54
|
-
has_rdoc: true
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- lib/persistent_http/faster.rb
|
33
|
+
- lib/persistent_http.rb
|
34
|
+
- LICENSE
|
35
|
+
- Rakefile
|
36
|
+
- History.md
|
37
|
+
- README.rdoc
|
55
38
|
homepage: http://github.com/bpardee/persistent_http
|
56
39
|
licenses: []
|
57
|
-
|
58
40
|
post_install_message:
|
59
|
-
rdoc_options:
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
requirements:
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
-
|
73
|
-
|
74
|
-
segments:
|
75
|
-
- 0
|
76
|
-
version: "0"
|
41
|
+
rdoc_options: []
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ! '>='
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
77
56
|
requirements: []
|
78
|
-
|
79
57
|
rubyforge_project:
|
80
|
-
rubygems_version: 1.
|
58
|
+
rubygems_version: 1.8.10
|
81
59
|
signing_key:
|
82
60
|
specification_version: 3
|
83
61
|
summary: Persistent HTTP connections using a connection pool
|
84
|
-
test_files:
|
85
|
-
- test/persistent_http_test.rb
|
62
|
+
test_files: []
|
data/.gitignore
DELETED
data/History.txt
DELETED
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
1.0.1
|
data/persistent_http.gemspec
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
-
# -*- encoding: utf-8 -*-
|
5
|
-
|
6
|
-
Gem::Specification.new do |s|
|
7
|
-
s.name = %q{persistent_http}
|
8
|
-
s.version = "1.0.1"
|
9
|
-
|
10
|
-
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
-
s.authors = ["Brad Pardee"]
|
12
|
-
s.date = %q{2010-10-04}
|
13
|
-
s.description = %q{Persistent HTTP connections using a connection pool}
|
14
|
-
s.email = %q{bradpardee@gmail.com}
|
15
|
-
s.extra_rdoc_files = [
|
16
|
-
"LICENSE",
|
17
|
-
"README.rdoc"
|
18
|
-
]
|
19
|
-
s.files = [
|
20
|
-
".gitignore",
|
21
|
-
"History.txt",
|
22
|
-
"LICENSE",
|
23
|
-
"README.rdoc",
|
24
|
-
"Rakefile",
|
25
|
-
"VERSION",
|
26
|
-
"lib/persistent_http.rb",
|
27
|
-
"lib/persistent_http/faster.rb",
|
28
|
-
"persistent_http.gemspec",
|
29
|
-
"test/persistent_http_test.rb"
|
30
|
-
]
|
31
|
-
s.homepage = %q{http://github.com/bpardee/persistent_http}
|
32
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
33
|
-
s.require_paths = ["lib"]
|
34
|
-
s.rubygems_version = %q{1.3.6}
|
35
|
-
s.summary = %q{Persistent HTTP connections using a connection pool}
|
36
|
-
s.test_files = [
|
37
|
-
"test/persistent_http_test.rb"
|
38
|
-
]
|
39
|
-
|
40
|
-
if s.respond_to? :specification_version then
|
41
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
42
|
-
s.specification_version = 3
|
43
|
-
|
44
|
-
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
45
|
-
s.add_runtime_dependency(%q<gene_pool>, [">= 1.0.1"])
|
46
|
-
else
|
47
|
-
s.add_dependency(%q<gene_pool>, [">= 1.0.1"])
|
48
|
-
end
|
49
|
-
else
|
50
|
-
s.add_dependency(%q<gene_pool>, [">= 1.0.1"])
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
@@ -1,647 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'test/unit'
|
3
|
-
require 'shoulda'
|
4
|
-
require 'persistent_http'
|
5
|
-
require 'openssl'
|
6
|
-
require 'stringio'
|
7
|
-
require 'logger'
|
8
|
-
|
9
|
-
CMD_SUCCESS = 'success'
|
10
|
-
CMD_SLEEP = 'sleep'
|
11
|
-
CMD_BAD_RESPONSE = 'bad_response'
|
12
|
-
CMD_EOF_ERROR = 'eof_error'
|
13
|
-
CMD_CONNRESET = 'connreset'
|
14
|
-
CMD_ECHO = 'echo'
|
15
|
-
|
16
|
-
PASS = 'pass'
|
17
|
-
FAIL = 'fail'
|
18
|
-
|
19
|
-
DUMMY_OPEN_TIMEOUT_FOR_HOSTDOWN = 9000
|
20
|
-
DUMMY_OPEN_TIMEOUT_FOR_CONNREFUSED = 9001
|
21
|
-
|
22
|
-
$debug = false
|
23
|
-
$count = -1
|
24
|
-
|
25
|
-
class Net::HTTP
|
26
|
-
def connect
|
27
|
-
raise Errno::EHOSTDOWN if open_timeout == DUMMY_OPEN_TIMEOUT_FOR_HOSTDOWN
|
28
|
-
raise Errno::ECONNREFUSED if open_timeout == DUMMY_OPEN_TIMEOUT_FOR_CONNREFUSED
|
29
|
-
end
|
30
|
-
|
31
|
-
def successful_response
|
32
|
-
r = Net::HTTPResponse.allocate
|
33
|
-
def r.http_version() '1.1'; end
|
34
|
-
def r.read_body() :read_body; end
|
35
|
-
yield r if block_given?
|
36
|
-
r
|
37
|
-
end
|
38
|
-
|
39
|
-
def request(req, &block)
|
40
|
-
$count += 1
|
41
|
-
puts "path=#{req.path} count=#{$count}" if $debug
|
42
|
-
args = req.path[1..-1].split('/')
|
43
|
-
cmd = args.shift
|
44
|
-
i = $count % args.size if args.size > 0
|
45
|
-
puts "i=#{i}" if $debug
|
46
|
-
if cmd == CMD_ECHO
|
47
|
-
res = successful_response(&block)
|
48
|
-
eval "def res.body() \"#{req.body}\" end"
|
49
|
-
return res
|
50
|
-
elsif cmd == CMD_SUCCESS || args[i] == PASS
|
51
|
-
return successful_response(&block)
|
52
|
-
end
|
53
|
-
case cmd
|
54
|
-
when CMD_SLEEP
|
55
|
-
sleep args[i].to_i
|
56
|
-
return successful_response(&block)
|
57
|
-
when CMD_BAD_RESPONSE
|
58
|
-
raise Net::HTTPBadResponse.new('Dummy bad response')
|
59
|
-
when CMD_EOF_ERROR
|
60
|
-
raise EOFError.new('Dummy EOF error')
|
61
|
-
when CMD_CONNRESET
|
62
|
-
raise Errno::ECONNRESET
|
63
|
-
else
|
64
|
-
return successful_response(&block)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
class PersistentHTTP
|
70
|
-
attr_reader :pool
|
71
|
-
|
72
|
-
# Make private methods public
|
73
|
-
send(:public, *(self.private_instance_methods - Object.private_instance_methods))
|
74
|
-
end
|
75
|
-
|
76
|
-
class PersistentHTTPTest < Test::Unit::TestCase
|
77
|
-
|
78
|
-
def clear_proxy_env
|
79
|
-
ENV.delete 'http_proxy'
|
80
|
-
ENV.delete 'HTTP_PROXY'
|
81
|
-
ENV.delete 'http_proxy_user'
|
82
|
-
ENV.delete 'HTTP_PROXY_USER'
|
83
|
-
ENV.delete 'http_proxy_pass'
|
84
|
-
ENV.delete 'HTTP_PROXY_PASS'
|
85
|
-
end
|
86
|
-
|
87
|
-
def uri_for(*args)
|
88
|
-
'/' + args.join('/')
|
89
|
-
end
|
90
|
-
|
91
|
-
def get_request(*args)
|
92
|
-
puts "uri=#{uri_for(args)}" if $debug
|
93
|
-
$count = -1
|
94
|
-
return Net::HTTP::Get.new(uri_for(args))
|
95
|
-
end
|
96
|
-
|
97
|
-
def post_request(*args)
|
98
|
-
puts "uri=#{uri_for(args)}" if $debug
|
99
|
-
$count = -1
|
100
|
-
return Net::HTTP::Post.new(uri_for(args))
|
101
|
-
end
|
102
|
-
|
103
|
-
def http_and_io(options={})
|
104
|
-
io = StringIO.new
|
105
|
-
logger = Logger.new(io)
|
106
|
-
logger.level = Logger::INFO
|
107
|
-
default_options = {:name => 'TestNetHTTPPersistent', :logger => logger, :pool_size => 1}
|
108
|
-
http = PersistentHTTP.new(default_options.merge(options))
|
109
|
-
[http, io]
|
110
|
-
end
|
111
|
-
|
112
|
-
context 'simple setup' do
|
113
|
-
setup do
|
114
|
-
@io = StringIO.new
|
115
|
-
logger = Logger.new(@io)
|
116
|
-
logger.level = Logger::INFO
|
117
|
-
@http = PersistentHTTP.new(:host => 'example.com', :name => 'TestNetHTTPPersistent', :logger => logger)
|
118
|
-
@http.headers['user-agent'] = 'test ua'
|
119
|
-
end
|
120
|
-
|
121
|
-
should 'have options set' do
|
122
|
-
assert_equal @http.proxy_uri, nil
|
123
|
-
assert_equal 'TestNetHTTPPersistent', @http.name
|
124
|
-
end
|
125
|
-
|
126
|
-
should 'handle escape' do
|
127
|
-
assert_equal nil, @http.escape(nil)
|
128
|
-
assert_equal '%20', @http.escape(' ')
|
129
|
-
end
|
130
|
-
|
131
|
-
should 'handle error' do
|
132
|
-
req = get_request CMD_EOF_ERROR, PASS, PASS, PASS, PASS, FAIL, PASS, PASS
|
133
|
-
6.times do
|
134
|
-
@http.request(req)
|
135
|
-
end
|
136
|
-
assert_match "after 4 requests on", @io.string
|
137
|
-
end
|
138
|
-
|
139
|
-
should 'handle finish' do
|
140
|
-
c = Object.new
|
141
|
-
def c.finish; @finished = true end
|
142
|
-
def c.finished?; @finished end
|
143
|
-
def c.start; @started = true end
|
144
|
-
def c.started?; @started end
|
145
|
-
|
146
|
-
@http.finish c
|
147
|
-
|
148
|
-
assert !c.started?
|
149
|
-
assert c.finished?
|
150
|
-
end
|
151
|
-
|
152
|
-
should 'handle finish io error' do
|
153
|
-
c = Object.new
|
154
|
-
def c.finish; @finished = true; raise IOError end
|
155
|
-
def c.finished?; @finished end
|
156
|
-
def c.start; @started = true end
|
157
|
-
def c.started?; @started end
|
158
|
-
|
159
|
-
@http.finish c
|
160
|
-
|
161
|
-
assert !c.started?
|
162
|
-
assert c.finished?
|
163
|
-
end
|
164
|
-
|
165
|
-
should 'fill in http version' do
|
166
|
-
assert_nil @http.http_version
|
167
|
-
@http.request(get_request(CMD_SUCCESS))
|
168
|
-
assert_equal '1.1', @http.http_version
|
169
|
-
end
|
170
|
-
|
171
|
-
should 'handle idempotent' do
|
172
|
-
assert @http.idempotent? Net::HTTP::Delete.new '/'
|
173
|
-
assert @http.idempotent? Net::HTTP::Get.new '/'
|
174
|
-
assert @http.idempotent? Net::HTTP::Head.new '/'
|
175
|
-
assert @http.idempotent? Net::HTTP::Options.new '/'
|
176
|
-
assert @http.idempotent? Net::HTTP::Put.new '/'
|
177
|
-
assert @http.idempotent? Net::HTTP::Trace.new '/'
|
178
|
-
|
179
|
-
assert !@http.idempotent?(Net::HTTP::Post.new '/')
|
180
|
-
end
|
181
|
-
|
182
|
-
should 'handle normalize_uri' do
|
183
|
-
assert_equal 'http://example', @http.normalize_uri('example')
|
184
|
-
assert_equal 'http://example', @http.normalize_uri('http://example')
|
185
|
-
assert_equal 'https://example', @http.normalize_uri('https://example')
|
186
|
-
end
|
187
|
-
|
188
|
-
should 'handle simple request' do
|
189
|
-
req = get_request(CMD_SUCCESS)
|
190
|
-
res = @http.request(req)
|
191
|
-
|
192
|
-
assert_kind_of Net::HTTPResponse, res
|
193
|
-
|
194
|
-
assert_kind_of Net::HTTP::Get, req
|
195
|
-
assert_equal uri_for(CMD_SUCCESS), req.path
|
196
|
-
assert_equal 'keep-alive', req['connection']
|
197
|
-
assert_equal '30', req['keep-alive']
|
198
|
-
assert_match %r%test ua%, req['user-agent']
|
199
|
-
end
|
200
|
-
|
201
|
-
should 'handle request with block' do
|
202
|
-
body = nil
|
203
|
-
|
204
|
-
req = get_request(CMD_SUCCESS)
|
205
|
-
res = @http.request(req) do |r|
|
206
|
-
body = r.read_body
|
207
|
-
end
|
208
|
-
|
209
|
-
assert_kind_of Net::HTTPResponse, res
|
210
|
-
assert !body.nil?
|
211
|
-
|
212
|
-
assert_kind_of Net::HTTP::Get, req
|
213
|
-
assert_equal uri_for(CMD_SUCCESS), req.path
|
214
|
-
assert_equal 'keep-alive', req['connection']
|
215
|
-
assert_equal '30', req['keep-alive']
|
216
|
-
assert_match %r%test ua%, req['user-agent']
|
217
|
-
end
|
218
|
-
|
219
|
-
should 'handle bad response' do
|
220
|
-
req = get_request(CMD_BAD_RESPONSE, FAIL, FAIL)
|
221
|
-
e = assert_raises PersistentHTTP::Error do
|
222
|
-
@http.request req
|
223
|
-
end
|
224
|
-
assert_match %r%too many bad responses%, e.message
|
225
|
-
assert_match %r%Renewing connection because of bad response%, @io.string
|
226
|
-
assert_match %r%Removing connection because of too many bad responses%, @io.string
|
227
|
-
|
228
|
-
res = @http.request(get_request(CMD_SUCCESS))
|
229
|
-
assert_kind_of Net::HTTPResponse, res
|
230
|
-
end
|
231
|
-
|
232
|
-
should 'handle connection reset' do
|
233
|
-
req = get_request(CMD_CONNRESET, FAIL, FAIL)
|
234
|
-
e = assert_raises PersistentHTTP::Error do
|
235
|
-
@http.request req
|
236
|
-
end
|
237
|
-
|
238
|
-
assert_match %r%too many connection resets%, e.message
|
239
|
-
assert_match %r%Renewing connection %, @io.string
|
240
|
-
assert_match %r%Removing connection %, @io.string
|
241
|
-
|
242
|
-
res = @http.request(get_request(CMD_SUCCESS))
|
243
|
-
assert_kind_of Net::HTTPResponse, res
|
244
|
-
end
|
245
|
-
|
246
|
-
should 'retry on bad response' do
|
247
|
-
res = @http.request(get_request(CMD_BAD_RESPONSE, FAIL, PASS))
|
248
|
-
assert_match %r%Renewing connection because of bad response%, @io.string
|
249
|
-
assert_kind_of Net::HTTPResponse, res
|
250
|
-
end
|
251
|
-
|
252
|
-
should 'retry on connection reset' do
|
253
|
-
res = @http.request(get_request(CMD_CONNRESET, FAIL, PASS))
|
254
|
-
assert_match %r%Renewing connection %, @io.string
|
255
|
-
assert_kind_of Net::HTTPResponse, res
|
256
|
-
end
|
257
|
-
|
258
|
-
should 'not retry on bad response from post' do
|
259
|
-
post = post_request(CMD_BAD_RESPONSE, FAIL, PASS)
|
260
|
-
e = assert_raises PersistentHTTP::Error do
|
261
|
-
@http.request(post)
|
262
|
-
end
|
263
|
-
assert_match %r%too many bad responses%, e.message
|
264
|
-
assert_match %r%Removing connection because of too many bad responses%, @io.string
|
265
|
-
|
266
|
-
res = @http.request(get_request(CMD_SUCCESS))
|
267
|
-
assert_kind_of Net::HTTPResponse, res
|
268
|
-
end
|
269
|
-
|
270
|
-
should 'not retry on connection reset from post' do
|
271
|
-
post = post_request(CMD_CONNRESET, FAIL, PASS)
|
272
|
-
e = assert_raises PersistentHTTP::Error do
|
273
|
-
@http.request(post)
|
274
|
-
end
|
275
|
-
assert_match %r%too many connection resets%, e.message
|
276
|
-
assert_match %r%Removing connection %, @io.string
|
277
|
-
|
278
|
-
res = @http.request(get_request(CMD_SUCCESS))
|
279
|
-
assert_kind_of Net::HTTPResponse, res
|
280
|
-
end
|
281
|
-
|
282
|
-
should 'retry on bad response from post when force_retry set' do
|
283
|
-
@http.force_retry = true
|
284
|
-
post = post_request(CMD_BAD_RESPONSE, FAIL, PASS)
|
285
|
-
res = @http.request post
|
286
|
-
assert_match %r%Renewing connection because of bad response%, @io.string
|
287
|
-
assert_kind_of Net::HTTPResponse, res
|
288
|
-
end
|
289
|
-
|
290
|
-
should 'retry on connection reset from post when force_retry set' do
|
291
|
-
@http.force_retry = true
|
292
|
-
post = post_request(CMD_CONNRESET, FAIL, PASS)
|
293
|
-
res = @http.request post
|
294
|
-
assert_match %r%Renewing connection %, @io.string
|
295
|
-
assert_kind_of Net::HTTPResponse, res
|
296
|
-
end
|
297
|
-
|
298
|
-
should 'allow post' do
|
299
|
-
post = Net::HTTP::Post.new(uri_for CMD_ECHO)
|
300
|
-
post.body = 'hello PersistentHTTP'
|
301
|
-
res = @http.request(post)
|
302
|
-
assert_kind_of Net::HTTPResponse, res
|
303
|
-
assert_equal post.body, res.body
|
304
|
-
end
|
305
|
-
|
306
|
-
should 'allow ssl' do
|
307
|
-
@http.verify_callback = :callback
|
308
|
-
c = Net::HTTP.new('localhost', 80)
|
309
|
-
|
310
|
-
@http.ssl c
|
311
|
-
|
312
|
-
assert c.use_ssl?
|
313
|
-
assert_equal OpenSSL::SSL::VERIFY_NONE, c.verify_mode
|
314
|
-
assert_nil c.verify_callback
|
315
|
-
end
|
316
|
-
|
317
|
-
should 'allow ssl ca_file' do
|
318
|
-
@http.ca_file = 'ca_file'
|
319
|
-
@http.verify_callback = :callback
|
320
|
-
c = Net::HTTP.new('localhost', 80)
|
321
|
-
|
322
|
-
@http.ssl c
|
323
|
-
|
324
|
-
assert c.use_ssl?
|
325
|
-
assert_equal OpenSSL::SSL::VERIFY_PEER, c.verify_mode
|
326
|
-
assert_equal :callback, c.verify_callback
|
327
|
-
end
|
328
|
-
|
329
|
-
should 'allow ssl certificate' do
|
330
|
-
@http.certificate = :cert
|
331
|
-
@http.private_key = :key
|
332
|
-
c = Net::HTTP.new('localhost', 80)
|
333
|
-
|
334
|
-
@http.ssl c
|
335
|
-
|
336
|
-
assert c.use_ssl?
|
337
|
-
assert_equal :cert, c.cert
|
338
|
-
assert_equal :key, c.key
|
339
|
-
end
|
340
|
-
|
341
|
-
should 'allow ssl verify_mode' do
|
342
|
-
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
343
|
-
c = Net::HTTP.new('localhost', 80)
|
344
|
-
|
345
|
-
@http.ssl c
|
346
|
-
|
347
|
-
assert c.use_ssl?
|
348
|
-
assert_equal OpenSSL::SSL::VERIFY_NONE, c.verify_mode
|
349
|
-
end
|
350
|
-
end
|
351
|
-
|
352
|
-
context 'initialize proxy by env' do
|
353
|
-
setup do
|
354
|
-
clear_proxy_env
|
355
|
-
ENV['HTTP_PROXY'] = 'proxy.example'
|
356
|
-
@http = PersistentHTTP.new(:host => 'foobar', :proxy => :ENV)
|
357
|
-
end
|
358
|
-
|
359
|
-
should 'match HTTP_PROXY' do
|
360
|
-
assert_equal URI.parse('http://proxy.example'), @http.proxy_uri
|
361
|
-
assert_equal 'foobar', @http.host
|
362
|
-
end
|
363
|
-
end
|
364
|
-
|
365
|
-
context 'initialize proxy by uri' do
|
366
|
-
setup do
|
367
|
-
@proxy_uri = URI.parse 'http://proxy.example'
|
368
|
-
@proxy_uri.user = 'johndoe'
|
369
|
-
@proxy_uri.password = 'muffins'
|
370
|
-
@http = PersistentHTTP.new(:url => 'https://zulu.com/foobar', :proxy => @proxy_uri)
|
371
|
-
end
|
372
|
-
|
373
|
-
should 'match proxy_uri and have proxy connection' do
|
374
|
-
assert_equal @proxy_uri, @http.proxy_uri
|
375
|
-
assert_equal true, @http.use_ssl
|
376
|
-
assert_equal 'zulu.com', @http.host
|
377
|
-
assert_equal '/foobar', @http.default_path
|
378
|
-
|
379
|
-
@http.pool.with_connection do |c|
|
380
|
-
assert c.started?
|
381
|
-
assert c.proxy?
|
382
|
-
end
|
383
|
-
end
|
384
|
-
end
|
385
|
-
|
386
|
-
context 'initialize proxy by env' do
|
387
|
-
setup do
|
388
|
-
clear_proxy_env
|
389
|
-
ENV['HTTP_PROXY'] = 'proxy.example'
|
390
|
-
ENV['HTTP_PROXY_USER'] = 'johndoe'
|
391
|
-
ENV['HTTP_PROXY_PASS'] = 'muffins'
|
392
|
-
@http = PersistentHTTP.new(:url => 'https://zulu.com/foobar', :proxy => :ENV)
|
393
|
-
end
|
394
|
-
|
395
|
-
should 'create proxy_uri from env' do
|
396
|
-
expected = URI.parse 'http://proxy.example'
|
397
|
-
expected.user = 'johndoe'
|
398
|
-
expected.password = 'muffins'
|
399
|
-
|
400
|
-
assert_equal expected, @http.proxy_uri
|
401
|
-
end
|
402
|
-
end
|
403
|
-
|
404
|
-
context 'initialize proxy by env lower' do
|
405
|
-
setup do
|
406
|
-
clear_proxy_env
|
407
|
-
ENV['http_proxy'] = 'proxy.example'
|
408
|
-
ENV['http_proxy_user'] = 'johndoe'
|
409
|
-
ENV['http_proxy_pass'] = 'muffins'
|
410
|
-
@http = PersistentHTTP.new(:url => 'https://zulu.com/foobar', :proxy => :ENV)
|
411
|
-
end
|
412
|
-
|
413
|
-
should 'create proxy_uri from env' do
|
414
|
-
expected = URI.parse 'http://proxy.example'
|
415
|
-
expected.user = 'johndoe'
|
416
|
-
expected.password = 'muffins'
|
417
|
-
|
418
|
-
assert_equal expected, @http.proxy_uri
|
419
|
-
end
|
420
|
-
end
|
421
|
-
|
422
|
-
context 'with timeouts set' do
|
423
|
-
setup do
|
424
|
-
@http = PersistentHTTP.new(:url => 'http://example.com')
|
425
|
-
@http.open_timeout = 123
|
426
|
-
@http.read_timeout = 321
|
427
|
-
end
|
428
|
-
|
429
|
-
should 'have timeouts set' do
|
430
|
-
@http.pool.with_connection do |c|
|
431
|
-
assert c.started?
|
432
|
-
assert !c.proxy?
|
433
|
-
|
434
|
-
assert_equal 123, c.open_timeout
|
435
|
-
assert_equal 321, c.read_timeout
|
436
|
-
|
437
|
-
assert_equal 'example.com', c.address
|
438
|
-
assert_equal 80, c.port
|
439
|
-
assert !@http.use_ssl
|
440
|
-
end
|
441
|
-
end
|
442
|
-
|
443
|
-
should 'reuse same connection' do
|
444
|
-
c1, c2 = nil, nil
|
445
|
-
@http.pool.with_connection do |c|
|
446
|
-
c1 = c
|
447
|
-
assert c.started?
|
448
|
-
end
|
449
|
-
@http.pool.with_connection do |c|
|
450
|
-
c2 = c
|
451
|
-
assert c.started?
|
452
|
-
end
|
453
|
-
assert_same c1,c2
|
454
|
-
end
|
455
|
-
end
|
456
|
-
|
457
|
-
context 'with debug_output' do
|
458
|
-
setup do
|
459
|
-
@io = StringIO.new
|
460
|
-
@http = PersistentHTTP.new(:url => 'http://example.com', :debug_output => @io)
|
461
|
-
end
|
462
|
-
|
463
|
-
should 'have debug_output set' do
|
464
|
-
@http.pool.with_connection do |c|
|
465
|
-
assert c.started?
|
466
|
-
assert_equal @io, c.instance_variable_get(:@debug_output)
|
467
|
-
assert_equal 'example.com', c.address
|
468
|
-
assert_equal 80, c.port
|
469
|
-
end
|
470
|
-
end
|
471
|
-
end
|
472
|
-
|
473
|
-
context 'with host down' do
|
474
|
-
setup do
|
475
|
-
@http = PersistentHTTP.new(:url => 'http://example.com', :open_timeout => DUMMY_OPEN_TIMEOUT_FOR_HOSTDOWN)
|
476
|
-
end
|
477
|
-
|
478
|
-
should 'assert error' do
|
479
|
-
e = assert_raises PersistentHTTP::Error do
|
480
|
-
@http.request(get_request(CMD_SUCCESS))
|
481
|
-
end
|
482
|
-
assert_match %r%host down%, e.message
|
483
|
-
end
|
484
|
-
end
|
485
|
-
|
486
|
-
context 'with connection refused' do
|
487
|
-
setup do
|
488
|
-
@http = PersistentHTTP.new(:url => 'http://example.com', :open_timeout => DUMMY_OPEN_TIMEOUT_FOR_CONNREFUSED)
|
489
|
-
end
|
490
|
-
|
491
|
-
should 'assert error' do
|
492
|
-
e = assert_raises PersistentHTTP::Error do
|
493
|
-
@http.request(get_request(CMD_SUCCESS))
|
494
|
-
end
|
495
|
-
assert_match %r%connection refused%, e.message
|
496
|
-
end
|
497
|
-
end
|
498
|
-
|
499
|
-
context 'with pool size of 3' do
|
500
|
-
setup do
|
501
|
-
@http = PersistentHTTP.new(:url => 'http://example.com', :pool_size => 3)
|
502
|
-
end
|
503
|
-
|
504
|
-
should 'only allow 3 connections checked out at a time' do
|
505
|
-
@http.request(get_request(CMD_SUCCESS))
|
506
|
-
pool = @http.pool
|
507
|
-
2.times do
|
508
|
-
conns = []
|
509
|
-
pool.with_connection do |c1|
|
510
|
-
pool.with_connection do |c2|
|
511
|
-
conns << c2
|
512
|
-
pool.with_connection do |c3|
|
513
|
-
conns << c3
|
514
|
-
begin
|
515
|
-
Timeout.timeout(2) do
|
516
|
-
pool.with_connection { |c4| }
|
517
|
-
assert false, 'should NOT have been able to get 4th connection'
|
518
|
-
end
|
519
|
-
rescue Timeout::Error => e
|
520
|
-
# successfully failed to get a connection
|
521
|
-
end
|
522
|
-
@http.remove(c1)
|
523
|
-
Timeout.timeout(1) do
|
524
|
-
begin
|
525
|
-
pool.with_connection do |c4|
|
526
|
-
conns << c4
|
527
|
-
end
|
528
|
-
rescue Timeout::Error => e
|
529
|
-
assert false, 'should have been able to get 4th connection'
|
530
|
-
end
|
531
|
-
end
|
532
|
-
end
|
533
|
-
end
|
534
|
-
end
|
535
|
-
pool.with_connection do |c1|
|
536
|
-
pool.with_connection do |c2|
|
537
|
-
pool.with_connection do |c3|
|
538
|
-
assert_equal conns, [c1,c2,c3]
|
539
|
-
end
|
540
|
-
end
|
541
|
-
end
|
542
|
-
# Do it a 2nd time with finish returning an IOError
|
543
|
-
c1 = conns[0]
|
544
|
-
def c1.finish
|
545
|
-
super
|
546
|
-
raise IOError
|
547
|
-
end
|
548
|
-
end
|
549
|
-
end
|
550
|
-
|
551
|
-
should 'handle renew' do
|
552
|
-
@http.request(get_request(CMD_SUCCESS))
|
553
|
-
pool = @http.pool
|
554
|
-
2.times do
|
555
|
-
conns = []
|
556
|
-
pool.with_connection do |c1|
|
557
|
-
pool.with_connection do |c2|
|
558
|
-
conns << c2
|
559
|
-
pool.with_connection do |c3|
|
560
|
-
conns << c3
|
561
|
-
new_c1 = @http.renew(c1)
|
562
|
-
assert c1 != new_c1
|
563
|
-
conns.unshift(new_c1)
|
564
|
-
end
|
565
|
-
end
|
566
|
-
end
|
567
|
-
pool.with_connection do |c1|
|
568
|
-
pool.with_connection do |c2|
|
569
|
-
pool.with_connection do |c3|
|
570
|
-
assert_equal conns, [c1,c2,c3]
|
571
|
-
end
|
572
|
-
end
|
573
|
-
end
|
574
|
-
# Do it a 2nd time with finish returning an IOError
|
575
|
-
c1 = conns[0]
|
576
|
-
def c1.finish
|
577
|
-
super
|
578
|
-
raise IOError
|
579
|
-
end
|
580
|
-
end
|
581
|
-
end
|
582
|
-
|
583
|
-
should 'handle renew with exception' do
|
584
|
-
pool = @http.pool
|
585
|
-
[[DUMMY_OPEN_TIMEOUT_FOR_HOSTDOWN, %r%host down%], [DUMMY_OPEN_TIMEOUT_FOR_CONNREFUSED, %r%connection refused%]].each do |pair|
|
586
|
-
dummy_open_timeout = pair.first
|
587
|
-
error_message = pair.last
|
588
|
-
pool.with_connection do |c|
|
589
|
-
old_c = c
|
590
|
-
@http.open_timeout = dummy_open_timeout
|
591
|
-
e = assert_raises PersistentHTTP::Error do
|
592
|
-
new_c = @http.renew c
|
593
|
-
end
|
594
|
-
assert_match error_message, e.message
|
595
|
-
|
596
|
-
# Make sure our pool is still in good shape
|
597
|
-
@http.open_timeout = 5 # Any valid timeout will do
|
598
|
-
pool.with_connection do |c1|
|
599
|
-
assert old_c != c1
|
600
|
-
pool.with_connection do |c2|
|
601
|
-
assert old_c != c2
|
602
|
-
end
|
603
|
-
end
|
604
|
-
end
|
605
|
-
end
|
606
|
-
end
|
607
|
-
end
|
608
|
-
#
|
609
|
-
# # def test_shutdown
|
610
|
-
# # c = connection
|
611
|
-
# # cs = conns
|
612
|
-
# # rs = reqs
|
613
|
-
# #
|
614
|
-
# # orig = @http
|
615
|
-
# # @http = PersistentHTTP.new 'name'
|
616
|
-
# # c2 = connection
|
617
|
-
# #
|
618
|
-
# # orig.shutdown
|
619
|
-
# #
|
620
|
-
# # assert c.finished?
|
621
|
-
# # refute c2.finished?
|
622
|
-
# #
|
623
|
-
# # refute_same cs, conns
|
624
|
-
# # refute_same rs, reqs
|
625
|
-
# # end
|
626
|
-
# #
|
627
|
-
# # def test_shutdown_not_started
|
628
|
-
# # c = Object.new
|
629
|
-
# # def c.finish() raise IOError end
|
630
|
-
# #
|
631
|
-
# # conns["#{@uri.host}:#{@uri.port}"] = c
|
632
|
-
# #
|
633
|
-
# # @http.shutdown
|
634
|
-
# #
|
635
|
-
# # assert_nil Thread.current[@http.connection_key]
|
636
|
-
# # assert_nil Thread.current[@http.request_key]
|
637
|
-
# # end
|
638
|
-
# #
|
639
|
-
# # def test_shutdown_no_connections
|
640
|
-
# # @http.shutdown
|
641
|
-
# #
|
642
|
-
# # assert_nil Thread.current[@http.connection_key]
|
643
|
-
# # assert_nil Thread.current[@http.request_key]
|
644
|
-
# # end
|
645
|
-
#
|
646
|
-
end
|
647
|
-
|