excon 0.9.1 → 0.9.2
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/changelog.txt +6 -0
- data/excon.gemspec +2 -2
- data/lib/excon/connection.rb +80 -66
- data/lib/excon/constants.rb +5 -1
- data/lib/excon/response.rb +0 -1
- data/lib/excon/socket.rb +12 -2
- data/tests/stub_tests.rb +41 -0
- metadata +3 -3
data/changelog.txt
CHANGED
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.9.
|
17
|
-
s.date = '2011-12-
|
16
|
+
s.version = '0.9.2'
|
17
|
+
s.date = '2011-12-16'
|
18
18
|
s.rubyforge_project = 'excon'
|
19
19
|
|
20
20
|
## Make sure your summary is short. The description may be as long
|
data/lib/excon/connection.rb
CHANGED
@@ -139,87 +139,87 @@ module Excon
|
|
139
139
|
|
140
140
|
def request_kernel(params, &block)
|
141
141
|
begin
|
142
|
-
if params[:mock]
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
request << params[:path]
|
142
|
+
response = if params[:mock]
|
143
|
+
invoke_stub(params, &block)
|
144
|
+
else
|
145
|
+
socket.params = params
|
146
|
+
# start with "METHOD /path"
|
147
|
+
request = params[:method].to_s.upcase << ' '
|
148
|
+
if @proxy
|
149
|
+
request << params[:scheme] << '://' << params[:host] << ':' << params[:port]
|
150
|
+
end
|
151
|
+
request << params[:path]
|
153
152
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
153
|
+
# add query to path, if there is one
|
154
|
+
case params[:query]
|
155
|
+
when String
|
156
|
+
request << '?' << params[:query]
|
157
|
+
when Hash
|
158
|
+
request << '?'
|
159
|
+
for key, values in params[:query]
|
160
|
+
if values.nil?
|
161
|
+
request << key.to_s << '&'
|
162
|
+
else
|
163
|
+
for value in [*values]
|
164
|
+
request << key.to_s << '=' << CGI.escape(value.to_s) << '&'
|
165
|
+
end
|
166
166
|
end
|
167
167
|
end
|
168
|
+
request.chop! # remove trailing '&'
|
168
169
|
end
|
169
|
-
request.chop! # remove trailing '&'
|
170
|
-
end
|
171
170
|
|
172
|
-
|
173
|
-
|
171
|
+
# finish first line with "HTTP/1.1\r\n"
|
172
|
+
request << HTTP_1_1
|
174
173
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
174
|
+
# calculate content length and set to handle non-ascii
|
175
|
+
unless params[:headers].has_key?('Content-Length')
|
176
|
+
params[:headers]['Content-Length'] = case params[:body]
|
177
|
+
when File
|
178
|
+
params[:body].binmode
|
179
|
+
File.size(params[:body])
|
180
|
+
when String
|
181
|
+
if FORCE_ENC
|
182
|
+
params[:body].force_encoding('BINARY')
|
183
|
+
end
|
184
|
+
params[:body].length
|
185
|
+
else
|
186
|
+
0
|
184
187
|
end
|
185
|
-
params[:body].length
|
186
|
-
else
|
187
|
-
0
|
188
188
|
end
|
189
|
-
end
|
190
189
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
190
|
+
# add headers to request
|
191
|
+
for key, values in params[:headers]
|
192
|
+
for value in [*values]
|
193
|
+
request << key.to_s << ': ' << value.to_s << CR_NL
|
194
|
+
end
|
195
195
|
end
|
196
|
-
end
|
197
196
|
|
198
|
-
|
199
|
-
|
197
|
+
# add additional "\r\n" to indicate end of headers
|
198
|
+
request << CR_NL
|
200
199
|
|
201
|
-
|
202
|
-
|
200
|
+
# write out the request, sans body
|
201
|
+
socket.write(request)
|
203
202
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
203
|
+
# write out the body
|
204
|
+
if params[:body]
|
205
|
+
if params[:body].is_a?(String)
|
206
|
+
socket.write(params[:body])
|
207
|
+
else
|
208
|
+
while chunk = params[:body].read(CHUNK_SIZE)
|
209
|
+
socket.write(chunk)
|
210
|
+
end
|
211
211
|
end
|
212
212
|
end
|
213
|
-
end
|
214
213
|
|
215
|
-
|
216
|
-
|
214
|
+
# read the response
|
215
|
+
response = Excon::Response.parse(socket, params, &block)
|
217
216
|
|
218
|
-
|
219
|
-
|
220
|
-
|
217
|
+
if response.headers['Connection'] == 'close'
|
218
|
+
reset
|
219
|
+
end
|
221
220
|
|
222
|
-
|
221
|
+
response
|
222
|
+
end
|
223
223
|
rescue Excon::Errors::StubNotFound => stub_not_found
|
224
224
|
raise(stub_not_found)
|
225
225
|
rescue => socket_error
|
@@ -237,9 +237,23 @@ module Excon
|
|
237
237
|
|
238
238
|
def invoke_stub(params)
|
239
239
|
for stub, response in Excon.stubs
|
240
|
-
|
241
|
-
|
242
|
-
|
240
|
+
headers_match = !stub.has_key?(:headers) || stub[:headers].keys.all? do |key|
|
241
|
+
case value = stub[:headers][key]
|
242
|
+
when Regexp
|
243
|
+
value =~ params[:headers][key]
|
244
|
+
else
|
245
|
+
value =~ params[:headers][key]
|
246
|
+
end
|
247
|
+
end
|
248
|
+
non_headers_match = (stub.keys - [:headers]).all? do |key|
|
249
|
+
case value = stub[key]
|
250
|
+
when Regexp
|
251
|
+
value =~ params[key]
|
252
|
+
else
|
253
|
+
value == params[key]
|
254
|
+
end
|
255
|
+
end
|
256
|
+
if headers_match && non_headers_match
|
243
257
|
response_attributes = case response
|
244
258
|
when Proc
|
245
259
|
response.call(params)
|
data/lib/excon/constants.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Excon
|
2
2
|
unless const_defined?(:VERSION)
|
3
|
-
VERSION = '0.9.
|
3
|
+
VERSION = '0.9.2'
|
4
4
|
end
|
5
5
|
|
6
6
|
unless const_defined?(:CHUNK_SIZE)
|
@@ -31,6 +31,10 @@ module Excon
|
|
31
31
|
HTTPS = 'https'
|
32
32
|
end
|
33
33
|
|
34
|
+
unless const_defined?(:NO_ENTITY)
|
35
|
+
NO_ENTITY = [204, 205, 304].freeze
|
36
|
+
end
|
37
|
+
|
34
38
|
unless ::IO.const_defined?(:WaitReadable)
|
35
39
|
class ::IO
|
36
40
|
module WaitReadable; end
|
data/lib/excon/response.rb
CHANGED
data/lib/excon/socket.rb
CHANGED
@@ -102,7 +102,11 @@ module Excon
|
|
102
102
|
end
|
103
103
|
|
104
104
|
def write(data)
|
105
|
-
|
105
|
+
# We normally return from the return in the else block below, but
|
106
|
+
# we guard that data is still something in case we get weird
|
107
|
+
# values and String#[] returns nil. (This behavior has been observed
|
108
|
+
# in the wild, so this is a simple defensive mechanism)
|
109
|
+
while data
|
106
110
|
begin
|
107
111
|
# I wish that this API accepted a start position, then we wouldn't
|
108
112
|
# have to slice data when there is a short write.
|
@@ -127,7 +131,13 @@ module Excon
|
|
127
131
|
end
|
128
132
|
else
|
129
133
|
# Fast, common case.
|
130
|
-
|
134
|
+
# The >= seems weird, why would it have written MORE than we
|
135
|
+
# requested. But we're getting some weird behavior when @socket
|
136
|
+
# is an OpenSSL socket, where it seems like it's saying it wrote
|
137
|
+
# more (perhaps due to SSL packet overhead?).
|
138
|
+
#
|
139
|
+
# Pretty weird, but this is a simple defensive mechanism.
|
140
|
+
return if written >= data.size
|
131
141
|
|
132
142
|
# This takes advantage of the fact that most ruby implementations
|
133
143
|
# have Copy-On-Write strings. Thusly why requesting a subrange
|
data/tests/stub_tests.rb
CHANGED
@@ -44,6 +44,34 @@ Shindo.tests('Excon stubs') do
|
|
44
44
|
|
45
45
|
end
|
46
46
|
|
47
|
+
tests("stub({:path => %r{/tests/(\S+)}}, {:body => $1, :status => 200})") do
|
48
|
+
|
49
|
+
Excon.stub({:path => %r{/tests/(\S+)}}) do |params|
|
50
|
+
{
|
51
|
+
:body => /tests\/(\S+)/.match(params[:path]).captures.first,
|
52
|
+
:status => 200
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
connection = Excon.new('http://127.0.0.1:9292', :mock => true)
|
57
|
+
response = connection.request(:method => :get, :path => '/tests/test')
|
58
|
+
|
59
|
+
tests('response.body').returns('test') do
|
60
|
+
response.body
|
61
|
+
end
|
62
|
+
|
63
|
+
tests('response.headers').returns({}) do
|
64
|
+
response.headers
|
65
|
+
end
|
66
|
+
|
67
|
+
tests('response.status').returns(200) do
|
68
|
+
response.status
|
69
|
+
end
|
70
|
+
|
71
|
+
Excon.stubs.clear
|
72
|
+
|
73
|
+
end
|
74
|
+
|
47
75
|
tests("stub({:body => 'body', :method => :get}) {|params| {:body => params[:body], :headers => params[:headers], :status => 200}}") do
|
48
76
|
|
49
77
|
Excon.stub({:body => 'body', :method => :get}) {|params| {:body => params[:body], :headers => params[:headers], :status => 200}}
|
@@ -97,6 +125,19 @@ Shindo.tests('Excon stubs') do
|
|
97
125
|
|
98
126
|
Excon.stubs.clear
|
99
127
|
|
128
|
+
tests("stub({}, {:status => 404}") do
|
129
|
+
|
130
|
+
connection = Excon.new('http://127.0.0.1:9292', :mock => true)
|
131
|
+
Excon.stub({}, {:status => 404})
|
132
|
+
|
133
|
+
tests("request(:expects => 200, :method => :get, :path => '/')").raises(Excon::Errors::NotFound) do
|
134
|
+
connection.request(:expects => 200, :method => :get, :path => '/')
|
135
|
+
end
|
136
|
+
|
137
|
+
Excon.stubs.clear
|
138
|
+
|
139
|
+
end
|
140
|
+
|
100
141
|
tests('mock = false') do
|
101
142
|
with_rackup('basic.ru') do
|
102
143
|
basic_tests
|
metadata
CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 9
|
8
|
-
-
|
8
|
+
- 2
|
9
9
|
segments_generated: true
|
10
|
-
version: 0.9.
|
10
|
+
version: 0.9.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- dpiddy (Dan Peterson)
|
@@ -17,7 +17,7 @@ autorequire:
|
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
19
|
|
20
|
-
date: 2011-12-
|
20
|
+
date: 2011-12-16 00:00:00 -06:00
|
21
21
|
default_executable:
|
22
22
|
dependencies:
|
23
23
|
- !ruby/object:Gem::Dependency
|