excon 0.0.14 → 0.0.15
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.
Potentially problematic release.
This version of excon might be problematic. Click here for more details.
- data/Rakefile +2 -19
- data/VERSION +1 -1
- data/benchmarks/excon_vs.rb +1 -1
- data/excon.gemspec +2 -4
- data/lib/excon.rb +1 -21
- data/lib/excon/connection.rb +100 -145
- data/tests/config.ru +1 -1
- data/tests/test_helper.rb +3 -3
- metadata +2 -4
- data/Gemfile +0 -14
- data/tests/mock_tests.rb +0 -40
data/Rakefile
CHANGED
@@ -16,25 +16,8 @@ rescue LoadError
|
|
16
16
|
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
17
17
|
end
|
18
18
|
|
19
|
-
require 'rake
|
20
|
-
Rake
|
21
|
-
test.libs << 'lib' << 'test'
|
22
|
-
test.pattern = 'test/**/*_test.rb'
|
23
|
-
test.verbose = true
|
24
|
-
end
|
25
|
-
|
26
|
-
begin
|
27
|
-
require 'rcov/rcovtask'
|
28
|
-
Rcov::RcovTask.new do |test|
|
29
|
-
test.libs << 'test'
|
30
|
-
test.pattern = 'test/**/*_test.rb'
|
31
|
-
test.verbose = true
|
32
|
-
end
|
33
|
-
rescue LoadError
|
34
|
-
task :rcov do
|
35
|
-
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
36
|
-
end
|
37
|
-
end
|
19
|
+
require 'shindo/rake'
|
20
|
+
Shindo::Rake.new
|
38
21
|
|
39
22
|
task :test => :check_dependencies
|
40
23
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.15
|
data/benchmarks/excon_vs.rb
CHANGED
data/excon.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{excon}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.15"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Wesley Beary"]
|
12
|
-
s.date = %q{2010-01-
|
12
|
+
s.date = %q{2010-01-06}
|
13
13
|
s.description = %q{speed, persistence, http(s)}
|
14
14
|
s.email = %q{wbeary@engineyard.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -18,7 +18,6 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.files = [
|
19
19
|
".document",
|
20
20
|
".gitignore",
|
21
|
-
"Gemfile",
|
22
21
|
"README.rdoc",
|
23
22
|
"Rakefile",
|
24
23
|
"VERSION",
|
@@ -31,7 +30,6 @@ Gem::Specification.new do |s|
|
|
31
30
|
"lib/excon/errors.rb",
|
32
31
|
"lib/excon/response.rb",
|
33
32
|
"tests/config.ru",
|
34
|
-
"tests/mock_tests.rb",
|
35
33
|
"tests/test_helper.rb",
|
36
34
|
"tests/threaded_tests.rb"
|
37
35
|
]
|
data/lib/excon.rb
CHANGED
@@ -8,6 +8,7 @@ require 'openssl'
|
|
8
8
|
require 'socket'
|
9
9
|
require 'uri'
|
10
10
|
|
11
|
+
require 'excon/connection'
|
11
12
|
require 'excon/errors'
|
12
13
|
require 'excon/response'
|
13
14
|
|
@@ -15,29 +16,8 @@ module Excon
|
|
15
16
|
|
16
17
|
CHUNK_SIZE = 1048576 # 1 megabyte
|
17
18
|
|
18
|
-
def self.reload
|
19
|
-
load 'excon/connection.rb'
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.mock!
|
23
|
-
@mocking = true
|
24
|
-
@mocks = {}
|
25
|
-
|
26
|
-
def self.mocks
|
27
|
-
@mocks
|
28
|
-
end
|
29
|
-
|
30
|
-
self.reload
|
31
|
-
end
|
32
|
-
|
33
|
-
def self.mocking?
|
34
|
-
!!@mocking
|
35
|
-
end
|
36
|
-
|
37
19
|
def self.new(url)
|
38
20
|
Excon::Connection.new(url)
|
39
21
|
end
|
40
22
|
|
41
23
|
end
|
42
|
-
|
43
|
-
Excon.reload
|
data/lib/excon/connection.rb
CHANGED
@@ -1,175 +1,130 @@
|
|
1
|
-
|
1
|
+
module Excon
|
2
|
+
class Connection
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
def initialize(url)
|
7
|
-
@uri = URI.parse(url)
|
8
|
-
Thread.current[:_excon_connections] ||= {}
|
9
|
-
end
|
4
|
+
def initialize(url)
|
5
|
+
@uri = URI.parse(url)
|
6
|
+
end
|
10
7
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
8
|
+
def request(params)
|
9
|
+
begin
|
10
|
+
params[:path] ||= ''
|
11
|
+
unless params[:path][0..0] == '/'
|
12
|
+
params[:path] = "/#{params[:path]}"
|
13
|
+
end
|
14
|
+
if params[:query] && !params[:query].empty?
|
15
|
+
params[:path] << "?#{params[:query]}"
|
16
|
+
end
|
17
|
+
request = "#{params[:method]} #{params[:path]} HTTP/1.1\r\n"
|
18
|
+
params[:headers] ||= {}
|
19
|
+
params[:headers]['Host'] = params[:host] || @uri.host
|
20
|
+
if params[:body] && !params[:headers]['Content-Length']
|
21
|
+
params[:headers]['Content-Length'] = params[:body].length
|
22
|
+
end
|
23
|
+
for key, value in params[:headers]
|
24
|
+
request << "#{key}: #{value}\r\n"
|
25
|
+
end
|
26
|
+
request << "\r\n"
|
27
|
+
socket.write(request)
|
28
|
+
|
29
|
+
if params[:body]
|
30
|
+
if params[:body].is_a?(String)
|
31
|
+
socket.write(params[:body])
|
32
|
+
else
|
33
|
+
while chunk = params[:body].read(CHUNK_SIZE)
|
34
|
+
socket.write(chunk)
|
35
|
+
end
|
28
36
|
end
|
29
|
-
|
30
|
-
connection.write(request)
|
37
|
+
end
|
31
38
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
39
|
+
response = Excon::Response.new
|
40
|
+
response.status = socket.readline[9..11].to_i
|
41
|
+
while true
|
42
|
+
data = socket.readline.chop!
|
43
|
+
unless data.empty?
|
44
|
+
key, value = data.split(': ')
|
45
|
+
response.headers[key] = value
|
46
|
+
else
|
47
|
+
break
|
40
48
|
end
|
49
|
+
end
|
41
50
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
response.headers[key] = value
|
49
|
-
else
|
50
|
-
break
|
51
|
-
end
|
51
|
+
unless params[:method] == 'HEAD'
|
52
|
+
block = if !params[:block] || (params[:expects] && ![*params[:expects]].include?(response.status))
|
53
|
+
response.body = ''
|
54
|
+
lambda { |chunk| response.body << chunk }
|
55
|
+
else
|
56
|
+
params[:block]
|
52
57
|
end
|
53
58
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
params[:block]
|
59
|
+
if response.headers['Content-Length']
|
60
|
+
remaining = response.headers['Content-Length'].to_i
|
61
|
+
while remaining > 0
|
62
|
+
block.call(socket.read([CHUNK_SIZE, remaining].min))
|
63
|
+
remaining -= CHUNK_SIZE
|
60
64
|
end
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
while true
|
70
|
-
chunk_size = connection.readline.chop!.to_i(16)
|
71
|
-
chunk = connection.read(chunk_size + 2).chop! # 2 == "/r/n".length
|
72
|
-
if chunk_size > 0
|
73
|
-
block.call(chunk)
|
74
|
-
else
|
75
|
-
break
|
76
|
-
end
|
65
|
+
elsif response.headers['Transfer-Encoding'] == 'chunked'
|
66
|
+
while true
|
67
|
+
chunk_size = socket.readline.chop!.to_i(16)
|
68
|
+
chunk = socket.read(chunk_size + 2).chop! # 2 == "/r/n".length
|
69
|
+
if chunk_size > 0
|
70
|
+
block.call(chunk)
|
71
|
+
else
|
72
|
+
break
|
77
73
|
end
|
78
|
-
elsif response.headers['Connection'] == 'close'
|
79
|
-
block.call(connection.read)
|
80
|
-
Thread.current[:_excon_connections][@uri.to_s] = nil
|
81
74
|
end
|
75
|
+
elsif response.headers['Connection'] == 'close'
|
76
|
+
block.call(socket.read)
|
77
|
+
reset_socket
|
82
78
|
end
|
83
|
-
rescue => connection_error
|
84
|
-
Thread.current[:_excon_connections][@uri.to_s] = nil
|
85
|
-
raise(connection_error)
|
86
|
-
end
|
87
|
-
|
88
|
-
if params[:expects] && ![*params[:expects]].include?(response.status)
|
89
|
-
Thread.current[:_excon_connections][@uri.to_s] = nil
|
90
|
-
raise(Excon::Errors.status_error(params, response))
|
91
|
-
else
|
92
|
-
response
|
93
|
-
end
|
94
|
-
|
95
|
-
rescue => request_error
|
96
|
-
if params[:idempotent] &&
|
97
|
-
(!request_error.is_a?(Excon::Errors::Error) || response.status != 404)
|
98
|
-
retries_remaining ||= 4
|
99
|
-
retries_remaining -= 1
|
100
|
-
if retries_remaining > 0
|
101
|
-
retry
|
102
|
-
end
|
103
|
-
else
|
104
|
-
raise(request_error)
|
105
79
|
end
|
80
|
+
rescue => socket_error
|
81
|
+
reset_socket
|
82
|
+
raise(socket_error)
|
106
83
|
end
|
107
84
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
end
|
114
|
-
Thread.current[:_excon_connections][@uri.to_s]
|
85
|
+
if params[:expects] && ![*params[:expects]].include?(response.status)
|
86
|
+
reset_socket
|
87
|
+
raise(Excon::Errors.status_error(params, response))
|
88
|
+
else
|
89
|
+
response
|
115
90
|
end
|
116
91
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
connection.sync_close = true
|
125
|
-
connection.connect
|
92
|
+
rescue => request_error
|
93
|
+
if params[:idempotent] &&
|
94
|
+
(!request_error.is_a?(Excon::Errors::Error) || response.status != 404)
|
95
|
+
retries_remaining ||= 4
|
96
|
+
retries_remaining -= 1
|
97
|
+
if retries_remaining > 0
|
98
|
+
retry
|
126
99
|
end
|
127
|
-
|
128
|
-
|
100
|
+
else
|
101
|
+
raise(request_error)
|
129
102
|
end
|
130
103
|
end
|
131
|
-
end
|
132
104
|
|
133
|
-
|
105
|
+
private
|
134
106
|
|
135
|
-
|
136
|
-
|
107
|
+
def reset_socket
|
108
|
+
new_socket = TCPSocket.open(@uri.host, @uri.port)
|
137
109
|
|
138
|
-
|
110
|
+
if @uri.scheme == 'https'
|
111
|
+
@ssl_context = OpenSSL::SSL::SSLContext.new
|
112
|
+
@ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
113
|
+
new_socket = OpenSSL::SSL::SSLSocket.new(new_socket, @ssl_context)
|
114
|
+
new_socket.sync_close = true
|
115
|
+
new_socket.connect
|
139
116
|
end
|
140
117
|
|
141
|
-
|
142
|
-
|
143
|
-
if key == params
|
144
|
-
response = Excon.mocks[key]
|
145
|
-
break
|
146
|
-
end
|
147
|
-
end
|
148
|
-
unless response
|
149
|
-
response = Excon::Response.new
|
150
|
-
response.status = 404
|
151
|
-
response.headers = { 'Content-Length' => 0 }
|
152
|
-
end
|
153
|
-
|
154
|
-
if params[:expects] && ![*params[:expects]].include?(response.status)
|
155
|
-
raise(Excon::Errors.status_error(params[:expects], response.status, response))
|
156
|
-
else
|
157
|
-
response
|
158
|
-
end
|
118
|
+
Thread.current[:_excon_sockets][@uri.to_s] = new_socket
|
119
|
+
end
|
159
120
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
if retries_remaining > 0
|
165
|
-
retry
|
166
|
-
end
|
167
|
-
else
|
168
|
-
raise(request_error)
|
169
|
-
end
|
121
|
+
def socket
|
122
|
+
Thread.current[:_excon_sockets] ||= {}
|
123
|
+
if !Thread.current[:_excon_sockets][@uri.to_s] || Thread.current[:_excon_sockets][@uri.to_s].closed?
|
124
|
+
reset_socket
|
170
125
|
end
|
171
|
-
|
126
|
+
Thread.current[:_excon_sockets][@uri.to_s]
|
172
127
|
end
|
173
|
-
end
|
174
128
|
|
129
|
+
end
|
175
130
|
end
|
data/tests/config.ru
CHANGED
data/tests/test_helper.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib/excon'))
|
2
2
|
|
3
|
-
|
3
|
+
require 'open4'
|
4
4
|
|
5
5
|
def local_file(*parts)
|
6
6
|
File.expand_path(File.join(File.dirname(__FILE__), *parts))
|
7
7
|
end
|
8
8
|
|
9
|
-
def with_rackup(configru = local_file('config.ru')
|
10
|
-
pid, w, r, e = Open4.popen4("
|
9
|
+
def with_rackup(configru = local_file('config.ru'))
|
10
|
+
pid, w, r, e = Open4.popen4("rackup #{configru}")
|
11
11
|
while `lsof -p #{pid} -P -i | grep ruby | grep TCP`.chomp.empty?; end
|
12
12
|
yield
|
13
13
|
Process.kill(9, pid)
|
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.0.
|
4
|
+
version: 0.0.15
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wesley Beary
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-06 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -24,7 +24,6 @@ extra_rdoc_files:
|
|
24
24
|
files:
|
25
25
|
- .document
|
26
26
|
- .gitignore
|
27
|
-
- Gemfile
|
28
27
|
- README.rdoc
|
29
28
|
- Rakefile
|
30
29
|
- VERSION
|
@@ -37,7 +36,6 @@ files:
|
|
37
36
|
- lib/excon/errors.rb
|
38
37
|
- lib/excon/response.rb
|
39
38
|
- tests/config.ru
|
40
|
-
- tests/mock_tests.rb
|
41
39
|
- tests/test_helper.rb
|
42
40
|
- tests/threaded_tests.rb
|
43
41
|
has_rdoc: true
|
data/Gemfile
DELETED
data/tests/mock_tests.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
|
2
|
-
|
3
|
-
Excon.mock!
|
4
|
-
|
5
|
-
request = {
|
6
|
-
:host => 'www.google.com',
|
7
|
-
:method => 'GET',
|
8
|
-
:path => '/'
|
9
|
-
}
|
10
|
-
response = Excon::Response.new({
|
11
|
-
:status => 200,
|
12
|
-
:headers => { 'Content-Length' => '11' },
|
13
|
-
:body => 'Hello World'
|
14
|
-
})
|
15
|
-
Excon.mocks[request] = response
|
16
|
-
|
17
|
-
Shindo.tests do
|
18
|
-
|
19
|
-
before do
|
20
|
-
@connection = Excon.new('http://www.google.com')
|
21
|
-
@response = @connection.request({
|
22
|
-
:host => 'www.google.com',
|
23
|
-
:method => 'GET',
|
24
|
-
:path => '/'
|
25
|
-
})
|
26
|
-
end
|
27
|
-
|
28
|
-
test("status => 200") do
|
29
|
-
@response.status == 200
|
30
|
-
end
|
31
|
-
|
32
|
-
test("headers => { 'Content-Length' => '11' }") do
|
33
|
-
@response.headers == { 'Content-Length' => '11' }
|
34
|
-
end
|
35
|
-
|
36
|
-
test("body => 'Hello World") do
|
37
|
-
@response.body == 'Hello World'
|
38
|
-
end
|
39
|
-
|
40
|
-
end
|