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.

@@ -1,3 +1,9 @@
1
+ 0.9.2 12/16/11
2
+ ==============
3
+
4
+ * update mocks to allow for regex based matching
5
+ * fixes for write_nonblock+OpenSSL weirdness
6
+
1
7
  0.9.1 12/15/11
2
8
  ==============
3
9
 
@@ -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.1'
17
- s.date = '2011-12-15'
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
@@ -139,87 +139,87 @@ module Excon
139
139
 
140
140
  def request_kernel(params, &block)
141
141
  begin
142
- if params[:mock]
143
- return invoke_stub(params, &block)
144
- end
145
-
146
- socket.params = params
147
- # start with "METHOD /path"
148
- request = params[:method].to_s.upcase << ' '
149
- if @proxy
150
- request << params[:scheme] << '://' << params[:host] << ':' << params[:port]
151
- end
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
- # add query to path, if there is one
155
- case params[:query]
156
- when String
157
- request << '?' << params[:query]
158
- when Hash
159
- request << '?'
160
- for key, values in params[:query]
161
- if values.nil?
162
- request << key.to_s << '&'
163
- else
164
- for value in [*values]
165
- request << key.to_s << '=' << CGI.escape(value.to_s) << '&'
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
- # finish first line with "HTTP/1.1\r\n"
173
- request << HTTP_1_1
171
+ # finish first line with "HTTP/1.1\r\n"
172
+ request << HTTP_1_1
174
173
 
175
- # calculate content length and set to handle non-ascii
176
- unless params[:headers].has_key?('Content-Length')
177
- params[:headers]['Content-Length'] = case params[:body]
178
- when File
179
- params[:body].binmode
180
- File.size(params[:body])
181
- when String
182
- if FORCE_ENC
183
- params[:body].force_encoding('BINARY')
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
- # add headers to request
192
- for key, values in params[:headers]
193
- for value in [*values]
194
- request << key.to_s << ': ' << value.to_s << CR_NL
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
- # add additional "\r\n" to indicate end of headers
199
- request << CR_NL
197
+ # add additional "\r\n" to indicate end of headers
198
+ request << CR_NL
200
199
 
201
- # write out the request, sans body
202
- socket.write(request)
200
+ # write out the request, sans body
201
+ socket.write(request)
203
202
 
204
- # write out the body
205
- if params[:body]
206
- if params[:body].is_a?(String)
207
- socket.write(params[:body])
208
- else
209
- while chunk = params[:body].read(CHUNK_SIZE)
210
- socket.write(chunk)
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
- # read the response
216
- response = Excon::Response.parse(socket, params, &block)
214
+ # read the response
215
+ response = Excon::Response.parse(socket, params, &block)
217
216
 
218
- if response.headers['Connection'] == 'close'
219
- reset
220
- end
217
+ if response.headers['Connection'] == 'close'
218
+ reset
219
+ end
221
220
 
222
- response
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
- # all specified non-headers params match and no headers were specified or all specified headers match
241
- if (stub.keys - [:headers]).all? {|key| stub[key] == params[key] } &&
242
- (!stub.has_key?(:headers) || stub[:headers].keys.all? {|key| stub[:headers][key] == params[:headers][key]})
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)
@@ -1,6 +1,6 @@
1
1
  module Excon
2
2
  unless const_defined?(:VERSION)
3
- VERSION = '0.9.1'
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
@@ -1,6 +1,5 @@
1
1
  module Excon
2
2
  class Response
3
- NO_ENTITY = [204, 205, 304].freeze
4
3
 
5
4
  attr_accessor :body, :headers, :status
6
5
 
@@ -102,7 +102,11 @@ module Excon
102
102
  end
103
103
 
104
104
  def write(data)
105
- while true
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
- return if written == data.size
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
@@ -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
- - 1
8
+ - 2
9
9
  segments_generated: true
10
- version: 0.9.1
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-15 00:00:00 -06:00
20
+ date: 2011-12-16 00:00:00 -06:00
21
21
  default_executable:
22
22
  dependencies:
23
23
  - !ruby/object:Gem::Dependency