net-http-persistent 1.0
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/.autotest +7 -0
- data/History.txt +6 -0
- data/Manifest.txt +8 -0
- data/README.txt +44 -0
- data/Rakefile +13 -0
- data/lib/net/http/faster.rb +27 -0
- data/lib/net/http/persistent.rb +215 -0
- data/test/test_net_http_persistent.rb +244 -0
- metadata +147 -0
- metadata.gz.sig +0 -0
data.tar.gz.sig
ADDED
Binary file
|
data/.autotest
ADDED
data/History.txt
ADDED
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
= net_http_persistent
|
2
|
+
|
3
|
+
* http://seattlerb.rubyforge.org/net-http-persistent
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Persistent connections using Net::HTTP plus a speed fix for 1.8. It's
|
8
|
+
thread-safe too!
|
9
|
+
|
10
|
+
== FEATURES/PROBLEMS:
|
11
|
+
|
12
|
+
* Supports SSL
|
13
|
+
* Thread-safe
|
14
|
+
* Pure ruby
|
15
|
+
* Timeout-less speed boost for 1.8 (by Aaron Patterson)
|
16
|
+
|
17
|
+
== INSTALL:
|
18
|
+
|
19
|
+
gem install net-http-persistent
|
20
|
+
|
21
|
+
== LICENSE:
|
22
|
+
|
23
|
+
(The MIT License)
|
24
|
+
|
25
|
+
Copyright (c) 2010 Eric Hodel, Aaron Patterson
|
26
|
+
|
27
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
28
|
+
a copy of this software and associated documentation files (the
|
29
|
+
'Software'), to deal in the Software without restriction, including
|
30
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
31
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
32
|
+
permit persons to whom the Software is furnished to do so, subject to
|
33
|
+
the following conditions:
|
34
|
+
|
35
|
+
The above copyright notice and this permission notice shall be
|
36
|
+
included in all copies or substantial portions of the Software.
|
37
|
+
|
38
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
39
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
40
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
41
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
42
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
43
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
44
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'net/protocol'
|
2
|
+
|
3
|
+
##
|
4
|
+
# Aaron Patterson's monkeypatch (accepted into 1.9.1) to fix Net::HTTP's speed
|
5
|
+
# problems.
|
6
|
+
#
|
7
|
+
# http://gist.github.com/251244
|
8
|
+
|
9
|
+
class Net::BufferedIO #:nodoc:
|
10
|
+
alias :old_rbuf_fill :rbuf_fill
|
11
|
+
|
12
|
+
def rbuf_fill
|
13
|
+
if @io.respond_to? :read_nonblock then
|
14
|
+
begin
|
15
|
+
@rbuf << @io.read_nonblock(65536)
|
16
|
+
rescue Errno::EWOULDBLOCK => e
|
17
|
+
retry if IO.select [@io], nil, nil, @read_timeout
|
18
|
+
raise Timeout::Error, e.message
|
19
|
+
end
|
20
|
+
else # SSL sockets do not have read_nonblock
|
21
|
+
timeout @read_timeout do
|
22
|
+
@rbuf << @io.sysread(65536)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,215 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/http/faster'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
##
|
6
|
+
# Persistent connections for Net::HTTP
|
7
|
+
#
|
8
|
+
# Net::HTTP::Persistent maintains persistent connections across all the
|
9
|
+
# servers you wish to talk to. For each host:port you communicate with a
|
10
|
+
# single persistent connection is created.
|
11
|
+
#
|
12
|
+
# Multiple Net::HTTP::Persistent objects will share the same set of
|
13
|
+
# connections.
|
14
|
+
#
|
15
|
+
# Example:
|
16
|
+
#
|
17
|
+
# uri = URI.parse 'http://example.com/awesome/web/service'
|
18
|
+
# http = Net::HTTP::Persistent
|
19
|
+
# stuff = http.request uri # performs a GET
|
20
|
+
#
|
21
|
+
# # perform a POST
|
22
|
+
# post_uri = uri + 'create'
|
23
|
+
# post = Net::HTTP::Post.new uri.path
|
24
|
+
# post.set_form_data 'some' => 'cool data'
|
25
|
+
# http.request post_uri, post # URI is always required
|
26
|
+
|
27
|
+
class Net::HTTP::Persistent
|
28
|
+
|
29
|
+
##
|
30
|
+
# The version of Net::HTTP::Persistent use are using
|
31
|
+
|
32
|
+
VERSION = '1.0'
|
33
|
+
|
34
|
+
##
|
35
|
+
# Error class for errors raised by Net::HTTP::Persistent. Various
|
36
|
+
# SystemCallErrors are re-raised with a human-readable message under this
|
37
|
+
# class.
|
38
|
+
|
39
|
+
class Error < StandardError; end
|
40
|
+
|
41
|
+
##
|
42
|
+
# This client's OpenSSL::X509::Certificate
|
43
|
+
|
44
|
+
attr_accessor :certificate
|
45
|
+
|
46
|
+
##
|
47
|
+
# An SSL certificate authority. Setting this will set verify_mode to
|
48
|
+
# VERIFY_PEER.
|
49
|
+
|
50
|
+
attr_accessor :ca_file
|
51
|
+
|
52
|
+
##
|
53
|
+
# Headers that are added to every request
|
54
|
+
|
55
|
+
attr_reader :headers
|
56
|
+
|
57
|
+
##
|
58
|
+
# The value sent in the Keep-Alive header. Defaults to 30 seconds
|
59
|
+
|
60
|
+
attr_accessor :keep_alive
|
61
|
+
|
62
|
+
##
|
63
|
+
# This client's SSL private key
|
64
|
+
|
65
|
+
attr_accessor :private_key
|
66
|
+
|
67
|
+
##
|
68
|
+
# SSL verification callback. Used when ca_file is set.
|
69
|
+
|
70
|
+
attr_accessor :verify_callback
|
71
|
+
|
72
|
+
##
|
73
|
+
# HTTPS verify mode. Set to OpenSSL::SSL::VERIFY_NONE to ignore certificate
|
74
|
+
# problems.
|
75
|
+
#
|
76
|
+
# You can use +verify_mode+ to override any default values.
|
77
|
+
|
78
|
+
attr_accessor :verify_mode
|
79
|
+
|
80
|
+
def initialize # :nodoc:
|
81
|
+
@keep_alive = 30
|
82
|
+
@headers = {}
|
83
|
+
|
84
|
+
@certificate = nil
|
85
|
+
@ca_file = nil
|
86
|
+
@private_key = nil
|
87
|
+
@verify_callback = nil
|
88
|
+
@verify_mode = nil
|
89
|
+
end
|
90
|
+
|
91
|
+
##
|
92
|
+
# Creates a new connection for +uri+
|
93
|
+
|
94
|
+
def connection_for uri
|
95
|
+
Thread.current[:net_http_persistent_connections] ||= {}
|
96
|
+
connections = Thread.current[:net_http_persistent_connections]
|
97
|
+
|
98
|
+
connection_id = [uri.host, uri.port].join ':'
|
99
|
+
|
100
|
+
connections[connection_id] ||= Net::HTTP.new uri.host, uri.port
|
101
|
+
connection = connections[connection_id]
|
102
|
+
|
103
|
+
ssl connection if uri.scheme == 'https' and not connection.started?
|
104
|
+
|
105
|
+
connection.start unless connection.started?
|
106
|
+
|
107
|
+
connection
|
108
|
+
rescue Errno::ECONNREFUSED
|
109
|
+
raise Error, "connection refused: #{connection.address}:#{connection.port}"
|
110
|
+
end
|
111
|
+
|
112
|
+
##
|
113
|
+
# Returns an error message containing the number of requests performed on
|
114
|
+
# this connection
|
115
|
+
|
116
|
+
def error_message connection
|
117
|
+
requests =
|
118
|
+
Thread.current[:net_http_persistent_requests][connection.object_id]
|
119
|
+
|
120
|
+
"after #{requests} requests on #{connection.object_id}"
|
121
|
+
end
|
122
|
+
|
123
|
+
##
|
124
|
+
# Finishes then restarts the Net::HTTP +connection+
|
125
|
+
|
126
|
+
def reset connection
|
127
|
+
Thread.current[:net_http_persistent_requests].delete connection.object_id
|
128
|
+
|
129
|
+
begin
|
130
|
+
connection.finish
|
131
|
+
rescue IOError
|
132
|
+
end
|
133
|
+
|
134
|
+
connection.start
|
135
|
+
rescue Errno::ECONNREFUSED
|
136
|
+
raise Error, "connection refused: #{connection.address}:#{connection.port}"
|
137
|
+
rescue Errno::EHOSTDOWN
|
138
|
+
raise Error, "host down: #{connection.address}:#{connection.port}"
|
139
|
+
end
|
140
|
+
|
141
|
+
##
|
142
|
+
# Makes a request on +uri+. If +req+ is nil a Net::HTTP::Get is performed
|
143
|
+
# against +uri+.
|
144
|
+
#
|
145
|
+
# +req+ must be a Net::HTTPRequest subclass (see Net::HTTP for a list).
|
146
|
+
|
147
|
+
def request uri, req = nil
|
148
|
+
Thread.current[:net_http_persistent_requests] ||= Hash.new 0
|
149
|
+
retried = false
|
150
|
+
bad_response = false
|
151
|
+
|
152
|
+
req = Net::HTTP::Get.new uri.request_uri unless req
|
153
|
+
|
154
|
+
headers.each do |pair|
|
155
|
+
req.add_field(*pair)
|
156
|
+
end
|
157
|
+
|
158
|
+
req.add_field 'Connection', 'keep-alive'
|
159
|
+
req.add_field 'Keep-Alive', @keep_alive
|
160
|
+
|
161
|
+
connection = connection_for uri
|
162
|
+
connection_id = connection.object_id
|
163
|
+
|
164
|
+
begin
|
165
|
+
count = Thread.current[:net_http_persistent_requests][connection_id] += 1
|
166
|
+
response = connection.request req
|
167
|
+
|
168
|
+
rescue Net::HTTPBadResponse => e
|
169
|
+
message = error_message connection
|
170
|
+
|
171
|
+
reset connection
|
172
|
+
|
173
|
+
raise Error, "too many bad responses #{message}" if bad_response
|
174
|
+
|
175
|
+
bad_response = true
|
176
|
+
retry
|
177
|
+
rescue IOError, EOFError, Timeout::Error,
|
178
|
+
Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE => e
|
179
|
+
due_to = "(due to #{e.message} - #{e.class})"
|
180
|
+
message = error_message connection
|
181
|
+
|
182
|
+
reset connection
|
183
|
+
|
184
|
+
raise Error, "too many connection resets #{due_to} #{message}" if retried
|
185
|
+
|
186
|
+
retried = true
|
187
|
+
retry
|
188
|
+
end
|
189
|
+
|
190
|
+
response
|
191
|
+
end
|
192
|
+
|
193
|
+
##
|
194
|
+
# Enables SSL on +connection+
|
195
|
+
|
196
|
+
def ssl connection
|
197
|
+
require 'net/https'
|
198
|
+
connection.use_ssl = true
|
199
|
+
|
200
|
+
if @ca_file then
|
201
|
+
connection.ca_file = @ca_file
|
202
|
+
connection.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
203
|
+
connection.verify_callback = @verify_callback if @verify_callback
|
204
|
+
end
|
205
|
+
|
206
|
+
if @certificate and @private_key then
|
207
|
+
connection.cert = @certificate
|
208
|
+
connection.key = @private_key
|
209
|
+
end
|
210
|
+
|
211
|
+
connection.verify_mode = @verify_mode if @verify_mode
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|
215
|
+
|
@@ -0,0 +1,244 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'net/http/persistent'
|
3
|
+
require 'openssl'
|
4
|
+
|
5
|
+
class TestNetHttpPersistent < MiniTest::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@http = Net::HTTP::Persistent.new
|
9
|
+
@uri = URI.parse 'http://example.com/path'
|
10
|
+
end
|
11
|
+
|
12
|
+
def teardown
|
13
|
+
Thread.current[:net_http_persistent_connections] = nil
|
14
|
+
Thread.current[:net_http_persistent_requests] = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def connection
|
18
|
+
c = Object.new
|
19
|
+
# Net::HTTP
|
20
|
+
def c.finish; @finish = true end
|
21
|
+
def c.request(req) @req = req; :response end
|
22
|
+
def c.reset; @reset = true end
|
23
|
+
def c.start; end
|
24
|
+
|
25
|
+
# util
|
26
|
+
def c.req() @req; end
|
27
|
+
def c.reset?; @reset end
|
28
|
+
def c.started?; true end
|
29
|
+
conns["#{@uri.host}:#{@uri.port}"] = c
|
30
|
+
c
|
31
|
+
end
|
32
|
+
|
33
|
+
def conns
|
34
|
+
Thread.current[:net_http_persistent_connections] ||= {}
|
35
|
+
end
|
36
|
+
|
37
|
+
def reqs
|
38
|
+
Thread.current[:net_http_persistent_requests] ||= {}
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_connection_for
|
42
|
+
c = @http.connection_for @uri
|
43
|
+
|
44
|
+
assert c.started?
|
45
|
+
|
46
|
+
assert_includes conns.keys, 'example.com:80'
|
47
|
+
assert_same c, conns['example.com:80']
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_connection_for_cached
|
51
|
+
cached = Object.new
|
52
|
+
def cached.started?; true end
|
53
|
+
conns['example.com:80'] = cached
|
54
|
+
|
55
|
+
c = @http.connection_for @uri
|
56
|
+
|
57
|
+
assert c.started?
|
58
|
+
|
59
|
+
assert_same cached, c
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_connection_for_refused
|
63
|
+
cached = Object.new
|
64
|
+
def cached.address; 'example.com' end
|
65
|
+
def cached.port; 80 end
|
66
|
+
def cached.start; raise Errno::ECONNREFUSED end
|
67
|
+
def cached.started?; false end
|
68
|
+
conns['example.com:80'] = cached
|
69
|
+
|
70
|
+
e = assert_raises Net::HTTP::Persistent::Error do
|
71
|
+
@http.connection_for @uri
|
72
|
+
end
|
73
|
+
|
74
|
+
assert_match %r%connection refused%, e
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_error_message
|
78
|
+
c = Object.new
|
79
|
+
reqs[c.object_id] = 5
|
80
|
+
|
81
|
+
assert_equal "after 5 requests on #{c.object_id}", @http.error_message(c)
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_reset
|
85
|
+
c = Object.new
|
86
|
+
def c.finish; @finished = true end
|
87
|
+
def c.finished?; @finished end
|
88
|
+
def c.start; @started = true end
|
89
|
+
def c.started?; @started end
|
90
|
+
reqs[c.object_id] = 5
|
91
|
+
|
92
|
+
@http.reset c
|
93
|
+
|
94
|
+
assert c.started?
|
95
|
+
assert c.finished?
|
96
|
+
assert_nil reqs[c.object_id]
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_reset_io_error
|
100
|
+
c = Object.new
|
101
|
+
def c.finish; @finished = true; raise IOError end
|
102
|
+
def c.finished?; @finished end
|
103
|
+
def c.start; @started = true end
|
104
|
+
def c.started?; @started end
|
105
|
+
reqs[c.object_id] = 5
|
106
|
+
|
107
|
+
@http.reset c
|
108
|
+
|
109
|
+
assert c.started?
|
110
|
+
assert c.finished?
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_reset_host_down
|
114
|
+
c = Object.new
|
115
|
+
def c.address; 'example.com' end
|
116
|
+
def c.finish; end
|
117
|
+
def c.port; 80 end
|
118
|
+
def c.start; raise Errno::EHOSTDOWN end
|
119
|
+
reqs[c.object_id] = 5
|
120
|
+
|
121
|
+
e = assert_raises Net::HTTP::Persistent::Error do
|
122
|
+
@http.reset c
|
123
|
+
end
|
124
|
+
|
125
|
+
assert_match %r%host down%, e
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_reset_refused
|
129
|
+
c = Object.new
|
130
|
+
def c.address; 'example.com' end
|
131
|
+
def c.finish; end
|
132
|
+
def c.port; 80 end
|
133
|
+
def c.start; raise Errno::ECONNREFUSED end
|
134
|
+
reqs[c.object_id] = 5
|
135
|
+
|
136
|
+
e = assert_raises Net::HTTP::Persistent::Error do
|
137
|
+
@http.reset c
|
138
|
+
end
|
139
|
+
|
140
|
+
assert_match %r%connection refused%, e
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_request
|
144
|
+
@http.headers['user-agent'] = 'test ua'
|
145
|
+
c = connection
|
146
|
+
|
147
|
+
res = @http.request @uri
|
148
|
+
req = c.req
|
149
|
+
|
150
|
+
assert_equal :response, res
|
151
|
+
|
152
|
+
assert_kind_of Net::HTTP::Get, req
|
153
|
+
assert_equal '/path', req.path
|
154
|
+
assert_equal 'keep-alive', req['connection']
|
155
|
+
assert_equal '30', req['keep-alive']
|
156
|
+
assert_equal 'test ua', req['user-agent']
|
157
|
+
|
158
|
+
assert_equal 1, reqs[c.object_id]
|
159
|
+
end
|
160
|
+
|
161
|
+
def test_request_bad_response
|
162
|
+
c = connection
|
163
|
+
def c.request(*a) raise Net::HTTPBadResponse end
|
164
|
+
|
165
|
+
e = assert_raises Net::HTTP::Persistent::Error do
|
166
|
+
@http.request @uri
|
167
|
+
end
|
168
|
+
|
169
|
+
assert_equal 0, reqs[c.object_id]
|
170
|
+
assert_match %r%too many bad responses%, e.message
|
171
|
+
end
|
172
|
+
|
173
|
+
def test_request_reset
|
174
|
+
c = connection
|
175
|
+
def c.request(*a) raise Errno::ECONNRESET end
|
176
|
+
|
177
|
+
e = assert_raises Net::HTTP::Persistent::Error do
|
178
|
+
@http.request @uri
|
179
|
+
end
|
180
|
+
|
181
|
+
assert_equal 0, reqs[c.object_id]
|
182
|
+
assert_match %r%too many connection resets%, e.message
|
183
|
+
end
|
184
|
+
|
185
|
+
def test_request_post
|
186
|
+
c = connection
|
187
|
+
|
188
|
+
post = Net::HTTP::Post.new @uri.path
|
189
|
+
|
190
|
+
res = @http.request @uri, post
|
191
|
+
req = c.req
|
192
|
+
|
193
|
+
assert_equal :response, res
|
194
|
+
|
195
|
+
assert_same post, req
|
196
|
+
end
|
197
|
+
|
198
|
+
def test_ssl
|
199
|
+
@http.verify_callback = :callback
|
200
|
+
c = Net::HTTP.new 'localhost', 80
|
201
|
+
|
202
|
+
@http.ssl c
|
203
|
+
|
204
|
+
assert c.use_ssl?
|
205
|
+
assert_nil c.verify_mode
|
206
|
+
assert_nil c.verify_callback
|
207
|
+
end
|
208
|
+
|
209
|
+
def test_ssl_ca_file
|
210
|
+
@http.ca_file = 'ca_file'
|
211
|
+
@http.verify_callback = :callback
|
212
|
+
c = Net::HTTP.new 'localhost', 80
|
213
|
+
|
214
|
+
@http.ssl c
|
215
|
+
|
216
|
+
assert c.use_ssl?
|
217
|
+
assert_equal OpenSSL::SSL::VERIFY_PEER, c.verify_mode
|
218
|
+
assert_equal :callback, c.verify_callback
|
219
|
+
end
|
220
|
+
|
221
|
+
def test_ssl_certificate
|
222
|
+
@http.certificate = :cert
|
223
|
+
@http.private_key = :key
|
224
|
+
c = Net::HTTP.new 'localhost', 80
|
225
|
+
|
226
|
+
@http.ssl c
|
227
|
+
|
228
|
+
assert c.use_ssl?
|
229
|
+
assert_equal :cert, c.cert
|
230
|
+
assert_equal :key, c.key
|
231
|
+
end
|
232
|
+
|
233
|
+
def test_ssl_verify_mode
|
234
|
+
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
235
|
+
c = Net::HTTP.new 'localhost', 80
|
236
|
+
|
237
|
+
@http.ssl c
|
238
|
+
|
239
|
+
assert c.use_ssl?
|
240
|
+
assert_equal OpenSSL::SSL::VERIFY_NONE, c.verify_mode
|
241
|
+
end
|
242
|
+
|
243
|
+
end
|
244
|
+
|
metadata
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: net-http-persistent
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 15
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: "1.0"
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Eric Hodel
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain:
|
16
|
+
- |
|
17
|
+
-----BEGIN CERTIFICATE-----
|
18
|
+
MIIDNjCCAh6gAwIBAgIBADANBgkqhkiG9w0BAQUFADBBMRAwDgYDVQQDDAdkcmJy
|
19
|
+
YWluMRgwFgYKCZImiZPyLGQBGRYIc2VnbWVudDcxEzARBgoJkiaJk/IsZAEZFgNu
|
20
|
+
ZXQwHhcNMDcxMjIxMDIwNDE0WhcNMDgxMjIwMDIwNDE0WjBBMRAwDgYDVQQDDAdk
|
21
|
+
cmJyYWluMRgwFgYKCZImiZPyLGQBGRYIc2VnbWVudDcxEzARBgoJkiaJk/IsZAEZ
|
22
|
+
FgNuZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbbgLrGLGIDE76
|
23
|
+
LV/cvxdEzCuYuS3oG9PrSZnuDweySUfdp/so0cDq+j8bqy6OzZSw07gdjwFMSd6J
|
24
|
+
U5ddZCVywn5nnAQ+Ui7jMW54CYt5/H6f2US6U0hQOjJR6cpfiymgxGdfyTiVcvTm
|
25
|
+
Gj/okWrQl0NjYOYBpDi+9PPmaH2RmLJu0dB/NylsDnW5j6yN1BEI8MfJRR+HRKZY
|
26
|
+
mUtgzBwF1V4KIZQ8EuL6I/nHVu07i6IkrpAgxpXUfdJQJi0oZAqXurAV3yTxkFwd
|
27
|
+
g62YrrW26mDe+pZBzR6bpLE+PmXCzz7UxUq3AE0gPHbiMXie3EFE0oxnsU3lIduh
|
28
|
+
sCANiQ8BAgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQW
|
29
|
+
BBS5k4Z75VSpdM0AclG2UvzFA/VW5DANBgkqhkiG9w0BAQUFAAOCAQEAHagT4lfX
|
30
|
+
kP/hDaiwGct7XPuVGbrOsKRVD59FF5kETBxEc9UQ1clKWngf8JoVuEoKD774dW19
|
31
|
+
bU0GOVWO+J6FMmT/Cp7nuFJ79egMf/gy4gfUfQMuvfcr6DvZUPIs9P/TlK59iMYF
|
32
|
+
DIOQ3DxdF3rMzztNUCizN4taVscEsjCcgW6WkUJnGdqlu3OHWpQxZBJkBTjPCoc6
|
33
|
+
UW6on70SFPmAy/5Cq0OJNGEWBfgD9q7rrs/X8GGwUWqXb85RXnUVi/P8Up75E0ag
|
34
|
+
14jEc90kN+C7oI/AGCBN0j6JnEtYIEJZibjjDJTSMWlUKKkj30kq7hlUC2CepJ4v
|
35
|
+
x52qPcexcYZR7w==
|
36
|
+
-----END CERTIFICATE-----
|
37
|
+
|
38
|
+
date: 2010-05-04 00:00:00 -07:00
|
39
|
+
default_executable:
|
40
|
+
dependencies:
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rubyforge
|
43
|
+
prerelease: false
|
44
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
hash: 9
|
50
|
+
segments:
|
51
|
+
- 2
|
52
|
+
- 0
|
53
|
+
- 3
|
54
|
+
version: 2.0.3
|
55
|
+
type: :development
|
56
|
+
version_requirements: *id001
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
name: gemcutter
|
59
|
+
prerelease: false
|
60
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
hash: 11
|
66
|
+
segments:
|
67
|
+
- 0
|
68
|
+
- 5
|
69
|
+
- 0
|
70
|
+
version: 0.5.0
|
71
|
+
type: :development
|
72
|
+
version_requirements: *id002
|
73
|
+
- !ruby/object:Gem::Dependency
|
74
|
+
name: hoe
|
75
|
+
prerelease: false
|
76
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
hash: 27
|
82
|
+
segments:
|
83
|
+
- 2
|
84
|
+
- 5
|
85
|
+
- 0
|
86
|
+
version: 2.5.0
|
87
|
+
type: :development
|
88
|
+
version_requirements: *id003
|
89
|
+
description: |-
|
90
|
+
Persistent connections using Net::HTTP plus a speed fix for 1.8. It's
|
91
|
+
thread-safe too!
|
92
|
+
email:
|
93
|
+
- drbrain@segment7.net
|
94
|
+
executables: []
|
95
|
+
|
96
|
+
extensions: []
|
97
|
+
|
98
|
+
extra_rdoc_files:
|
99
|
+
- History.txt
|
100
|
+
- Manifest.txt
|
101
|
+
- README.txt
|
102
|
+
files:
|
103
|
+
- .autotest
|
104
|
+
- History.txt
|
105
|
+
- Manifest.txt
|
106
|
+
- README.txt
|
107
|
+
- Rakefile
|
108
|
+
- lib/net/http/faster.rb
|
109
|
+
- lib/net/http/persistent.rb
|
110
|
+
- test/test_net_http_persistent.rb
|
111
|
+
has_rdoc: true
|
112
|
+
homepage: http://seattlerb.rubyforge.org/net-http-persistent
|
113
|
+
licenses: []
|
114
|
+
|
115
|
+
post_install_message:
|
116
|
+
rdoc_options:
|
117
|
+
- --main
|
118
|
+
- README.txt
|
119
|
+
require_paths:
|
120
|
+
- lib
|
121
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
122
|
+
none: false
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
hash: 3
|
127
|
+
segments:
|
128
|
+
- 0
|
129
|
+
version: "0"
|
130
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
|
+
none: false
|
132
|
+
requirements:
|
133
|
+
- - ">="
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
hash: 3
|
136
|
+
segments:
|
137
|
+
- 0
|
138
|
+
version: "0"
|
139
|
+
requirements: []
|
140
|
+
|
141
|
+
rubyforge_project: seattlerb
|
142
|
+
rubygems_version: 1.3.7.pre.1
|
143
|
+
signing_key:
|
144
|
+
specification_version: 3
|
145
|
+
summary: Persistent connections using Net::HTTP plus a speed fix for 1.8
|
146
|
+
test_files:
|
147
|
+
- test/test_net_http_persistent.rb
|
metadata.gz.sig
ADDED
Binary file
|