excon 0.0.2 → 0.0.3
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/VERSION +1 -1
- data/excon.gemspec +2 -2
- data/lib/excon.rb +23 -1
- data/lib/excon/connection.rb +118 -87
- data/lib/excon/response.rb +4 -3
- data/test/test.rb +16 -1
- metadata +2 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.3
|
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.3"
|
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{2009-
|
12
|
+
s.date = %q{2009-11-03}
|
13
13
|
s.description = %q{speed, persistence, http(s)}
|
14
14
|
s.email = %q{wbeary@engineyard.com}
|
15
15
|
s.extra_rdoc_files = [
|
data/lib/excon.rb
CHANGED
@@ -8,14 +8,36 @@ require 'openssl'
|
|
8
8
|
require 'socket'
|
9
9
|
require 'uri'
|
10
10
|
|
11
|
-
require 'excon/connection'
|
12
11
|
require 'excon/errors'
|
13
12
|
require 'excon/response'
|
14
13
|
|
15
14
|
module Excon
|
16
15
|
|
16
|
+
CHUNK_SIZE = 1048576 # 1 megabyte
|
17
|
+
|
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
|
+
|
17
37
|
def self.new(url)
|
18
38
|
Excon::Connection.new(url)
|
19
39
|
end
|
20
40
|
|
21
41
|
end
|
42
|
+
|
43
|
+
Excon.reload
|
data/lib/excon/connection.rb
CHANGED
@@ -1,111 +1,142 @@
|
|
1
|
-
|
2
|
-
class Connection
|
1
|
+
unless Excon.mocking?
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
end
|
3
|
+
module Excon
|
4
|
+
class Connection
|
7
5
|
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
def initialize(url)
|
7
|
+
@uri = URI.parse(url)
|
8
|
+
end
|
11
9
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
18
|
-
if params[:query] && !params[:query].empty?
|
19
|
-
params[:path] << "?#{params[:query]}"
|
20
|
-
end
|
21
|
-
request = "#{params[:method]} #{params[:path]} HTTP/1.1\r\n"
|
22
|
-
params[:headers] ||= {}
|
23
|
-
params[:headers]['Host'] = params[:host] || @uri.host
|
24
|
-
if params[:body] && !params[:headers]['Content-Length']
|
25
|
-
params[:headers]['Content-Length'] = params[:body].length
|
26
|
-
end
|
27
|
-
for key, value in params[:headers]
|
28
|
-
request << "#{key}: #{value}\r\n"
|
29
|
-
end
|
30
|
-
request << "\r\n"
|
31
|
-
connection.write(request)
|
32
|
-
|
33
|
-
if params[:body]
|
34
|
-
if params[:body].is_a?(String)
|
35
|
-
connection.write(params[:body])
|
36
|
-
else
|
37
|
-
while chunk = params[:body].read(CHUNK_SIZE)
|
38
|
-
connection.write(chunk)
|
39
|
-
end
|
10
|
+
def request(params)
|
11
|
+
begin
|
12
|
+
params[:path] ||= ''
|
13
|
+
unless params[:path][0..0] == '/'
|
14
|
+
params[:path] = "/#{params[:path]}"
|
40
15
|
end
|
41
|
-
|
16
|
+
if params[:query] && !params[:query].empty?
|
17
|
+
params[:path] << "?#{params[:query]}"
|
18
|
+
end
|
19
|
+
request = "#{params[:method]} #{params[:path]} HTTP/1.1\r\n"
|
20
|
+
params[:headers] ||= {}
|
21
|
+
params[:headers]['Host'] = params[:host] || @uri.host
|
22
|
+
if params[:body] && !params[:headers]['Content-Length']
|
23
|
+
params[:headers]['Content-Length'] = params[:body].length
|
24
|
+
end
|
25
|
+
for key, value in params[:headers]
|
26
|
+
request << "#{key}: #{value}\r\n"
|
27
|
+
end
|
28
|
+
request << "\r\n"
|
29
|
+
connection.write(request)
|
42
30
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
break
|
31
|
+
if params[:body]
|
32
|
+
if params[:body].is_a?(String)
|
33
|
+
connection.write(params[:body])
|
34
|
+
else
|
35
|
+
while chunk = params[:body].read(CHUNK_SIZE)
|
36
|
+
connection.write(chunk)
|
37
|
+
end
|
38
|
+
end
|
52
39
|
end
|
53
|
-
end
|
54
40
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
41
|
+
response = Excon::Response.new
|
42
|
+
response.status = connection.readline[9..11].to_i
|
43
|
+
while true
|
44
|
+
data = connection.readline.chop!
|
45
|
+
unless data.empty?
|
46
|
+
header = data.split(': ')
|
47
|
+
response.headers[header[0]] = header[1]
|
48
|
+
else
|
49
|
+
break
|
50
|
+
end
|
59
51
|
end
|
60
52
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
params[:block].
|
65
|
-
remaining -= CHUNK_SIZE
|
53
|
+
unless params[:method] == 'HEAD'
|
54
|
+
if !params[:block] || (params[:expects] && ![*params[:expects]].include?(response.status))
|
55
|
+
response.body = ''
|
56
|
+
params[:block] = lambda { |chunk| response.body << chunk }
|
66
57
|
end
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
58
|
+
|
59
|
+
if response.headers['Content-Length']
|
60
|
+
remaining = response.headers['Content-Length'].to_i
|
61
|
+
while remaining > 0
|
62
|
+
params[:block].call(connection.read([CHUNK_SIZE, remaining].min))
|
63
|
+
remaining -= CHUNK_SIZE
|
64
|
+
end
|
65
|
+
elsif response.headers['Transfer-Encoding'] == 'chunked'
|
66
|
+
while true
|
67
|
+
chunk_size = connection.readline.chomp!.to_i(16)
|
68
|
+
chunk = connection.read(chunk_size + 2).chop! # 2 == "/r/n".length
|
69
|
+
if chunk_size > 0
|
70
|
+
params[:block].call(chunk)
|
71
|
+
else
|
72
|
+
break
|
73
|
+
end
|
75
74
|
end
|
75
|
+
elsif response.headers['Connection'] == 'close'
|
76
|
+
params[:block].call(connection.read)
|
77
|
+
@connection = nil
|
76
78
|
end
|
77
|
-
elsif response.headers['Connection'] == 'close'
|
78
|
-
params[:block].call(connection.read)
|
79
|
-
@connection = nil
|
80
79
|
end
|
80
|
+
rescue => connection_error
|
81
|
+
@connection = nil
|
82
|
+
raise(connection_error)
|
83
|
+
end
|
84
|
+
|
85
|
+
if params[:expects] && ![*params[:expects]].include?(response.status)
|
86
|
+
raise(Excon::Errors.status_error(params[:expects], response.status, response))
|
87
|
+
else
|
88
|
+
response
|
81
89
|
end
|
82
|
-
rescue => connection_error
|
83
|
-
@connection = nil
|
84
|
-
raise(connection_error)
|
85
90
|
end
|
86
91
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
92
|
+
private
|
93
|
+
|
94
|
+
def connection
|
95
|
+
if !@connection || @connection.closed?
|
96
|
+
@connection = TCPSocket.open(@uri.host, @uri.port)
|
97
|
+
if @uri.scheme == 'https'
|
98
|
+
@ssl_context = OpenSSL::SSL::SSLContext.new
|
99
|
+
@ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
100
|
+
@connection = OpenSSL::SSL::SSLSocket.new(@connection, @ssl_context)
|
101
|
+
@connection.sync_close = true
|
102
|
+
@connection.connect
|
103
|
+
end
|
104
|
+
end
|
105
|
+
@connection
|
91
106
|
end
|
107
|
+
|
92
108
|
end
|
109
|
+
end
|
110
|
+
|
111
|
+
else
|
93
112
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
113
|
+
module Excon
|
114
|
+
class Connection
|
115
|
+
|
116
|
+
def initialize(url)
|
117
|
+
end
|
118
|
+
|
119
|
+
def request(params)
|
120
|
+
for key in Excon.mocks.keys
|
121
|
+
if key == params
|
122
|
+
response = Excon.mocks[key]
|
123
|
+
break
|
124
|
+
end
|
125
|
+
end
|
126
|
+
unless response
|
127
|
+
response = Excon::Response.new
|
128
|
+
response.status = 404
|
129
|
+
response.headers = { 'Content-Length' => 0 }
|
130
|
+
end
|
131
|
+
|
132
|
+
if params[:expects] && ![*params[:expects]].include?(response.status)
|
133
|
+
raise(Excon::Errors.status_error(params[:expects], response.status, response))
|
134
|
+
else
|
135
|
+
response
|
105
136
|
end
|
106
137
|
end
|
107
|
-
@connection
|
108
|
-
end
|
109
138
|
|
139
|
+
end
|
110
140
|
end
|
141
|
+
|
111
142
|
end
|
data/lib/excon/response.rb
CHANGED
@@ -3,9 +3,10 @@ module Excon
|
|
3
3
|
|
4
4
|
attr_accessor :body, :headers, :status
|
5
5
|
|
6
|
-
def initialize
|
7
|
-
@body
|
8
|
-
@headers = {}
|
6
|
+
def initialize(attributes = {})
|
7
|
+
@body = attributes[:body] || ''
|
8
|
+
@headers = attributes[:headers] || {}
|
9
|
+
@status = attributes[:status]
|
9
10
|
end
|
10
11
|
|
11
12
|
end
|
data/test/test.rb
CHANGED
@@ -1,11 +1,26 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), '..', 'lib/excon')
|
2
2
|
|
3
|
+
Excon.mock!
|
4
|
+
|
5
|
+
request = {
|
6
|
+
:host => 'www.google.com',
|
7
|
+
:method => 'GET',
|
8
|
+
:path => '/'
|
9
|
+
}
|
10
|
+
response = {
|
11
|
+
:status => 200,
|
12
|
+
:headers => { 'Content-Length' => '11' },
|
13
|
+
:body => 'Hello World'
|
14
|
+
}
|
15
|
+
Excon.mocks[request] = response
|
16
|
+
|
3
17
|
x = Excon.new('http://www.google.com')
|
4
18
|
|
5
19
|
10.times do
|
6
20
|
p x.request(
|
21
|
+
:host => 'www.google.com',
|
7
22
|
:method => 'GET',
|
8
|
-
:path
|
23
|
+
:path => '/'
|
9
24
|
)
|
10
25
|
end
|
11
26
|
|
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.3
|
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: 2009-
|
12
|
+
date: 2009-11-03 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|