excon 0.6.6 → 0.7.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/excon.gemspec +3 -2
- data/lib/excon.rb +2 -0
- data/lib/excon/connection.rb +12 -80
- data/lib/excon/constants.rb +1 -1
- data/lib/excon/socket.rb +114 -0
- metadata +6 -5
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 = '2011-09-
|
16
|
+
s.version = '0.7.0'
|
17
|
+
s.date = '2011-09-12'
|
18
18
|
s.rubyforge_project = 'excon'
|
19
19
|
|
20
20
|
## Make sure your summary is short. The description may be as long
|
@@ -90,6 +90,7 @@ Gem::Specification.new do |s|
|
|
90
90
|
lib/excon/constants.rb
|
91
91
|
lib/excon/errors.rb
|
92
92
|
lib/excon/response.rb
|
93
|
+
lib/excon/socket.rb
|
93
94
|
tests/basic_tests.rb
|
94
95
|
tests/header_tests.rb
|
95
96
|
tests/idempotent_tests.rb
|
data/lib/excon.rb
CHANGED
@@ -2,6 +2,7 @@ $:.unshift(File.dirname(__FILE__)) unless
|
|
2
2
|
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
3
|
|
4
4
|
require 'cgi'
|
5
|
+
require 'forwardable'
|
5
6
|
require 'openssl'
|
6
7
|
require 'rbconfig'
|
7
8
|
require 'socket'
|
@@ -11,6 +12,7 @@ require 'excon/constants'
|
|
11
12
|
require 'excon/connection'
|
12
13
|
require 'excon/errors'
|
13
14
|
require 'excon/response'
|
15
|
+
require 'excon/socket'
|
14
16
|
|
15
17
|
module Excon
|
16
18
|
class << self
|
data/lib/excon/connection.rb
CHANGED
@@ -20,13 +20,16 @@ module Excon
|
|
20
20
|
def initialize(url, params = {})
|
21
21
|
uri = URI.parse(url)
|
22
22
|
@connection = {
|
23
|
-
:
|
24
|
-
:
|
25
|
-
:
|
26
|
-
:
|
27
|
-
:
|
28
|
-
:
|
29
|
-
:
|
23
|
+
:connect_timeout => 60,
|
24
|
+
:headers => {},
|
25
|
+
:host => uri.host,
|
26
|
+
:mock => Excon.mock,
|
27
|
+
:path => uri.path,
|
28
|
+
:port => uri.port.to_s,
|
29
|
+
:query => uri.query,
|
30
|
+
:read_timeout => 60,
|
31
|
+
:scheme => uri.scheme,
|
32
|
+
:write_timeout => 60
|
30
33
|
}.merge!(params)
|
31
34
|
|
32
35
|
# use proxy from the environment if present
|
@@ -36,7 +39,7 @@ module Excon
|
|
36
39
|
@proxy = setup_proxy(params[:proxy])
|
37
40
|
end
|
38
41
|
|
39
|
-
if https
|
42
|
+
if @connection[:scheme] == 'https'
|
40
43
|
# use https_proxy if that has been specified
|
41
44
|
if ENV.has_key?('https_proxy')
|
42
45
|
@proxy = setup_proxy(ENV['https_proxy'])
|
@@ -157,7 +160,6 @@ module Excon
|
|
157
160
|
|
158
161
|
# write out the request, sans body
|
159
162
|
socket.write(request)
|
160
|
-
socket.flush
|
161
163
|
|
162
164
|
# write out the body
|
163
165
|
if params[:body]
|
@@ -223,85 +225,15 @@ module Excon
|
|
223
225
|
end
|
224
226
|
|
225
227
|
private
|
226
|
-
def connect
|
227
|
-
new_socket = open_socket
|
228
|
-
|
229
|
-
if https?
|
230
|
-
# create ssl context
|
231
|
-
ssl_context = OpenSSL::SSL::SSLContext.new
|
232
|
-
|
233
|
-
if Excon.ssl_verify_peer
|
234
|
-
# turn verification on
|
235
|
-
ssl_context.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
236
|
-
|
237
|
-
if Excon.ssl_ca_path
|
238
|
-
ssl_context.ca_path = Excon.ssl_ca_path
|
239
|
-
else
|
240
|
-
# use default cert store
|
241
|
-
store = OpenSSL::X509::Store.new
|
242
|
-
store.set_default_paths
|
243
|
-
ssl_context.cert_store = store
|
244
|
-
end
|
245
|
-
else
|
246
|
-
# turn verification off
|
247
|
-
ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
248
|
-
end
|
249
|
-
|
250
|
-
if @connection.has_key?(:client_cert) && @connection.has_key?(:client_key)
|
251
|
-
ssl_context.cert = OpenSSL::X509::Certificate.new(File.read(@connection[:client_cert]))
|
252
|
-
ssl_context.key = OpenSSL::PKey::RSA.new(File.read(@connection[:client_key]))
|
253
|
-
end
|
254
|
-
|
255
|
-
new_socket = open_ssl_socket(new_socket, ssl_context)
|
256
|
-
end
|
257
|
-
|
258
|
-
new_socket
|
259
|
-
end
|
260
|
-
|
261
|
-
def open_ssl_socket(socket, ssl_context)
|
262
|
-
|
263
|
-
new_socket = OpenSSL::SSL::SSLSocket.new(socket, ssl_context)
|
264
|
-
new_socket.sync_close = true
|
265
|
-
|
266
|
-
if @proxy
|
267
|
-
new_socket << "CONNECT " << @connection[:host] << ":" << @connection[:port] << HTTP_1_1
|
268
|
-
new_socket << "Host: " << @connection[:host] << ":" << @connection[:port] << CR_NL << CR_NL
|
269
|
-
|
270
|
-
# eat the proxy's connection response
|
271
|
-
while line = new_socket.readline.strip
|
272
|
-
break if line.empty?
|
273
|
-
end
|
274
|
-
end
|
275
|
-
|
276
|
-
new_socket.connect
|
277
|
-
# verify connection
|
278
|
-
if Excon.ssl_verify_peer
|
279
|
-
new_socket.post_connection_check(@connection[:host])
|
280
|
-
end
|
281
|
-
new_socket
|
282
|
-
end
|
283
|
-
|
284
|
-
def open_socket
|
285
|
-
if @proxy
|
286
|
-
socket = TCPSocket.open(@proxy[:host], @proxy[:port])
|
287
|
-
else
|
288
|
-
socket = TCPSocket.open(@connection[:host], @connection[:port])
|
289
|
-
end
|
290
|
-
socket
|
291
|
-
end
|
292
228
|
|
293
229
|
def socket
|
294
|
-
sockets[@socket_key] ||=
|
230
|
+
sockets[@socket_key] ||= Excon::Socket.new(@connection, @proxy)
|
295
231
|
end
|
296
232
|
|
297
233
|
def sockets
|
298
234
|
Thread.current[:_excon_sockets] ||= {}
|
299
235
|
end
|
300
236
|
|
301
|
-
def https?
|
302
|
-
@connection[:scheme] == 'https'
|
303
|
-
end
|
304
|
-
|
305
237
|
def setup_proxy(proxy)
|
306
238
|
uri = URI.parse(proxy)
|
307
239
|
unless uri.host and uri.port and uri.scheme
|
data/lib/excon/constants.rb
CHANGED
data/lib/excon/socket.rb
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
module Excon
|
2
|
+
class Socket
|
3
|
+
|
4
|
+
extend Forwardable
|
5
|
+
|
6
|
+
def_delegators(:@socket, :close, :close)
|
7
|
+
def_delegators(:@socket, :readline, :readline)
|
8
|
+
|
9
|
+
def initialize(connection_params = {}, proxy = {})
|
10
|
+
@connection_params, @proxy = connection_params, proxy
|
11
|
+
@read_buffer, @write_buffer = '', ''
|
12
|
+
|
13
|
+
@socket = ::Socket.new(::Socket::Constants::AF_INET, ::Socket::Constants::SOCK_STREAM, 0)
|
14
|
+
|
15
|
+
# nonblocking connect
|
16
|
+
if @proxy
|
17
|
+
sockaddr = ::Socket.sockaddr_in(@proxy[:port], @proxy[:host])
|
18
|
+
else
|
19
|
+
sockaddr = ::Socket.sockaddr_in(@connection_params[:port], @connection_params[:host])
|
20
|
+
end
|
21
|
+
begin
|
22
|
+
@socket.connect_nonblock(sockaddr)
|
23
|
+
rescue Errno::EINPROGRESS
|
24
|
+
IO.select(nil, [@socket], nil, @connection_params[:connect_timeout])
|
25
|
+
begin
|
26
|
+
@socket.connect_nonblock(sockaddr)
|
27
|
+
rescue Errno::EISCONN
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# ssl setup
|
32
|
+
if @connection_params[:scheme] == 'https'
|
33
|
+
# create ssl context
|
34
|
+
ssl_context = OpenSSL::SSL::SSLContext.new
|
35
|
+
|
36
|
+
if Excon.ssl_verify_peer
|
37
|
+
# turn verification on
|
38
|
+
ssl_context.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
39
|
+
|
40
|
+
if Excon.ssl_ca_path
|
41
|
+
ssl_context.ca_path = Excon.ssl_ca_path
|
42
|
+
else
|
43
|
+
# use default cert store
|
44
|
+
store = OpenSSL::X509::Store.new
|
45
|
+
store.set_default_paths
|
46
|
+
ssl_context.cert_store = store
|
47
|
+
end
|
48
|
+
else
|
49
|
+
# turn verification off
|
50
|
+
ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
51
|
+
end
|
52
|
+
|
53
|
+
if @connection_params.has_key?(:client_cert) && @connection_params.has_key?(:client_key)
|
54
|
+
ssl_context.cert = OpenSSL::X509::Certificate.new(File.read(@connection_params[:client_cert]))
|
55
|
+
ssl_context.key = OpenSSL::PKey::RSA.new(File.read(@connection_params[:client_key]))
|
56
|
+
end
|
57
|
+
|
58
|
+
@socket = OpenSSL::SSL::SSLSocket.new(@socket, ssl_context)
|
59
|
+
@socket.sync_close = true
|
60
|
+
|
61
|
+
if @proxy
|
62
|
+
@socket << "CONNECT " << @connection_params[:host] << ":" << @connection_params[:port] << HTTP_1_1
|
63
|
+
@socket << "Host: " << @connection_params[:host] << ":" << @connection_params[:port] << CR_NL << CR_NL
|
64
|
+
|
65
|
+
# eat the proxy's connection response
|
66
|
+
while line = @socket.readline.strip
|
67
|
+
break if line.empty?
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
if @connection_params[:scheme] == 'https'
|
73
|
+
# verify connection
|
74
|
+
if Excon.ssl_verify_peer
|
75
|
+
@socket.post_connection_check(@connection_params[:host])
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
@socket
|
80
|
+
end
|
81
|
+
|
82
|
+
def read(max_length)
|
83
|
+
begin
|
84
|
+
until @read_buffer.length >= max_length
|
85
|
+
@read_buffer << @socket.read_nonblock(max_length)
|
86
|
+
end
|
87
|
+
rescue Errno::EAGAIN, Errno::EWOULDBLOCK
|
88
|
+
if IO.select([@socket], nil, nil, @connection_params[:read_timeout])
|
89
|
+
retry
|
90
|
+
else
|
91
|
+
raise(Timeout::Error)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
@read_buffer.slice!(0, max_length)
|
95
|
+
end
|
96
|
+
|
97
|
+
def write(data)
|
98
|
+
@write_buffer << data
|
99
|
+
until @write_buffer.empty?
|
100
|
+
begin
|
101
|
+
max_length = [@write_buffer.length, Excon::CHUNK_SIZE].min
|
102
|
+
@socket.write_nonblock(@write_buffer.slice!(0, max_length))
|
103
|
+
rescue Errno::EAGAIN, Errno::EWOULDBLOCK
|
104
|
+
if IO.select(nil [@socket], nil, @connection_params[:write_timeout])
|
105
|
+
retry
|
106
|
+
else
|
107
|
+
raise(Timeout::Error)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: excon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 3
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 7
|
9
|
+
- 0
|
10
|
+
version: 0.7.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- geemus (Wesley Beary)
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-09-
|
18
|
+
date: 2011-09-12 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: open4
|
@@ -111,6 +111,7 @@ files:
|
|
111
111
|
- lib/excon/constants.rb
|
112
112
|
- lib/excon/errors.rb
|
113
113
|
- lib/excon/response.rb
|
114
|
+
- lib/excon/socket.rb
|
114
115
|
- tests/basic_tests.rb
|
115
116
|
- tests/header_tests.rb
|
116
117
|
- tests/idempotent_tests.rb
|