ultra-pure-gem 0.0.1
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.
- checksums.yaml +7 -0
- data/ultra-pure-gem.gemspec +12 -0
- data/webmock-3.26.2/CHANGELOG.md +2148 -0
- data/webmock-3.26.2/LICENSE +20 -0
- data/webmock-3.26.2/README.md +1229 -0
- data/webmock-3.26.2/lib/webmock/api.rb +111 -0
- data/webmock-3.26.2/lib/webmock/assertion_failure.rb +13 -0
- data/webmock-3.26.2/lib/webmock/callback_registry.rb +37 -0
- data/webmock-3.26.2/lib/webmock/config.rb +20 -0
- data/webmock-3.26.2/lib/webmock/cucumber.rb +12 -0
- data/webmock-3.26.2/lib/webmock/deprecation.rb +11 -0
- data/webmock-3.26.2/lib/webmock/errors.rb +19 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/async_http_client_adapter.rb +228 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/curb_adapter.rb +354 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +239 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/excon_adapter.rb +167 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/http_lib_adapter.rb +9 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/http_lib_adapter_registry.rb +21 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb/client.rb +17 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb/request.rb +28 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb/response.rb +95 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb/streamer.rb +44 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb/webmock.rb +77 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb_adapter.rb +39 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/httpclient_adapter.rb +260 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/manticore_adapter.rb +147 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/net_http.rb +310 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/net_http_response.rb +36 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/patron_adapter.rb +132 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb +190 -0
- data/webmock-3.26.2/lib/webmock/matchers/any_arg_matcher.rb +15 -0
- data/webmock-3.26.2/lib/webmock/matchers/hash_argument_matcher.rb +23 -0
- data/webmock-3.26.2/lib/webmock/matchers/hash_excluding_matcher.rb +17 -0
- data/webmock-3.26.2/lib/webmock/matchers/hash_including_matcher.rb +19 -0
- data/webmock-3.26.2/lib/webmock/minitest.rb +43 -0
- data/webmock-3.26.2/lib/webmock/rack_response.rb +73 -0
- data/webmock-3.26.2/lib/webmock/request_body_diff.rb +66 -0
- data/webmock-3.26.2/lib/webmock/request_execution_verifier.rb +79 -0
- data/webmock-3.26.2/lib/webmock/request_pattern.rb +428 -0
- data/webmock-3.26.2/lib/webmock/request_registry.rb +37 -0
- data/webmock-3.26.2/lib/webmock/request_signature.rb +56 -0
- data/webmock-3.26.2/lib/webmock/request_signature_snippet.rb +63 -0
- data/webmock-3.26.2/lib/webmock/request_stub.rb +134 -0
- data/webmock-3.26.2/lib/webmock/response.rb +161 -0
- data/webmock-3.26.2/lib/webmock/responses_sequence.rb +42 -0
- data/webmock-3.26.2/lib/webmock/rspec/matchers/request_pattern_matcher.rb +80 -0
- data/webmock-3.26.2/lib/webmock/rspec/matchers/webmock_matcher.rb +69 -0
- data/webmock-3.26.2/lib/webmock/rspec/matchers.rb +29 -0
- data/webmock-3.26.2/lib/webmock/rspec.rb +44 -0
- data/webmock-3.26.2/lib/webmock/stub_registry.rb +84 -0
- data/webmock-3.26.2/lib/webmock/stub_request_snippet.rb +40 -0
- data/webmock-3.26.2/lib/webmock/test_unit.rb +22 -0
- data/webmock-3.26.2/lib/webmock/util/hash_counter.rb +45 -0
- data/webmock-3.26.2/lib/webmock/util/hash_keys_stringifier.rb +27 -0
- data/webmock-3.26.2/lib/webmock/util/hash_validator.rb +19 -0
- data/webmock-3.26.2/lib/webmock/util/headers.rb +77 -0
- data/webmock-3.26.2/lib/webmock/util/parsers/json.rb +72 -0
- data/webmock-3.26.2/lib/webmock/util/parsers/parse_error.rb +7 -0
- data/webmock-3.26.2/lib/webmock/util/parsers/xml.rb +16 -0
- data/webmock-3.26.2/lib/webmock/util/query_mapper.rb +283 -0
- data/webmock-3.26.2/lib/webmock/util/uri.rb +113 -0
- data/webmock-3.26.2/lib/webmock/util/values_stringifier.rb +22 -0
- data/webmock-3.26.2/lib/webmock/util/version_checker.rb +113 -0
- data/webmock-3.26.2/lib/webmock/version.rb +5 -0
- data/webmock-3.26.2/lib/webmock/webmock.rb +175 -0
- data/webmock-3.26.2/lib/webmock.rb +61 -0
- metadata +106 -0
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
begin
|
|
4
|
+
require 'curb'
|
|
5
|
+
rescue LoadError
|
|
6
|
+
# curb not found
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
if defined?(Curl)
|
|
10
|
+
WebMock::VersionChecker.new('Curb', Curl::CURB_VERSION, '0.7.16', '1.2.2', ['0.8.7']).check_version!
|
|
11
|
+
|
|
12
|
+
module WebMock
|
|
13
|
+
module HttpLibAdapters
|
|
14
|
+
class CurbAdapter < HttpLibAdapter
|
|
15
|
+
adapter_for :curb
|
|
16
|
+
|
|
17
|
+
OriginalCurlEasy = Curl::Easy unless const_defined?(:OriginalCurlEasy)
|
|
18
|
+
|
|
19
|
+
def self.enable!
|
|
20
|
+
Curl.send(:remove_const, :Easy)
|
|
21
|
+
Curl.send(:const_set, :Easy, Curl::WebMockCurlEasy)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.disable!
|
|
25
|
+
Curl.send(:remove_const, :Easy)
|
|
26
|
+
Curl.send(:const_set, :Easy, OriginalCurlEasy)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Borrowed from Patron:
|
|
30
|
+
# http://github.com/toland/patron/blob/master/lib/patron/response.rb
|
|
31
|
+
def self.parse_header_string(header_string)
|
|
32
|
+
status, headers = nil, {}
|
|
33
|
+
|
|
34
|
+
header_string.split(/\r\n/).each do |header|
|
|
35
|
+
if header =~ %r{\AHTTP/(1\.[01]|2) (\d{3})\s*(.*)}
|
|
36
|
+
status = $3
|
|
37
|
+
else
|
|
38
|
+
parts = header.split(':', 2)
|
|
39
|
+
unless parts.empty?
|
|
40
|
+
parts[1].strip! unless parts[1].nil?
|
|
41
|
+
if headers.has_key?(parts[0])
|
|
42
|
+
headers[parts[0]] = [headers[parts[0]]] unless headers[parts[0]].kind_of? Array
|
|
43
|
+
headers[parts[0]] << parts[1]
|
|
44
|
+
else
|
|
45
|
+
headers[parts[0]] = parts[1]
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
return status, headers
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
module Curl
|
|
58
|
+
class WebMockCurlEasy < Curl::Easy
|
|
59
|
+
def curb_or_webmock
|
|
60
|
+
request_signature = build_request_signature
|
|
61
|
+
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
|
|
62
|
+
|
|
63
|
+
if webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
|
|
64
|
+
build_curb_response(webmock_response)
|
|
65
|
+
WebMock::CallbackRegistry.invoke_callbacks(
|
|
66
|
+
{lib: :curb}, request_signature, webmock_response)
|
|
67
|
+
invoke_curb_callbacks
|
|
68
|
+
true
|
|
69
|
+
elsif WebMock.net_connect_allowed?(request_signature.uri)
|
|
70
|
+
res = yield
|
|
71
|
+
if WebMock::CallbackRegistry.any_callbacks?
|
|
72
|
+
webmock_response = build_webmock_response
|
|
73
|
+
WebMock::CallbackRegistry.invoke_callbacks(
|
|
74
|
+
{lib: :curb, real_request: true}, request_signature,
|
|
75
|
+
webmock_response)
|
|
76
|
+
end
|
|
77
|
+
res
|
|
78
|
+
else
|
|
79
|
+
raise WebMock::NetConnectNotAllowedError.new(request_signature)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def build_request_signature
|
|
84
|
+
method = @webmock_method.to_s.downcase.to_sym
|
|
85
|
+
|
|
86
|
+
uri = WebMock::Util::URI.heuristic_parse(self.url)
|
|
87
|
+
uri.path = uri.normalized_path.gsub("[^:]//","/")
|
|
88
|
+
|
|
89
|
+
headers = headers_as_hash(self.headers).merge(basic_auth_headers)
|
|
90
|
+
|
|
91
|
+
request_body = case method
|
|
92
|
+
when :post, :patch
|
|
93
|
+
self.post_body || @post_body
|
|
94
|
+
when :put
|
|
95
|
+
@put_data
|
|
96
|
+
else
|
|
97
|
+
nil
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
if defined?( @on_debug )
|
|
101
|
+
@on_debug.call("Trying 127.0.0.1...\r\n", 0)
|
|
102
|
+
@on_debug.call('Connected to ' + uri.hostname + "\r\n", 0)
|
|
103
|
+
@debug_method = method.upcase
|
|
104
|
+
@debug_path = uri.path
|
|
105
|
+
@debug_host = uri.hostname
|
|
106
|
+
http_request = ["#{@debug_method} #{@debug_path} HTTP/1.1"]
|
|
107
|
+
http_request << "Host: #{uri.hostname}"
|
|
108
|
+
headers.each do |name, value|
|
|
109
|
+
http_request << "#{name}: #{value}"
|
|
110
|
+
end
|
|
111
|
+
@on_debug.call(http_request.join("\r\n") + "\r\n\r\n", 2)
|
|
112
|
+
if request_body
|
|
113
|
+
@on_debug.call(request_body + "\r\n", 4)
|
|
114
|
+
@on_debug.call(
|
|
115
|
+
"upload completely sent off: #{request_body.bytesize}"\
|
|
116
|
+
" out of #{request_body.bytesize} bytes\r\n", 0
|
|
117
|
+
)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
request_signature = WebMock::RequestSignature.new(
|
|
122
|
+
method,
|
|
123
|
+
uri.to_s,
|
|
124
|
+
body: request_body,
|
|
125
|
+
headers: headers
|
|
126
|
+
)
|
|
127
|
+
request_signature
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def headers_as_hash(headers)
|
|
131
|
+
if headers.is_a?(Array)
|
|
132
|
+
headers.inject({}) {|hash, header|
|
|
133
|
+
name, value = header.split(":", 2).map(&:strip)
|
|
134
|
+
hash[name] = value
|
|
135
|
+
hash
|
|
136
|
+
}
|
|
137
|
+
else
|
|
138
|
+
headers
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def basic_auth_headers
|
|
143
|
+
if self.username
|
|
144
|
+
{'Authorization' => WebMock::Util::Headers.basic_auth_header(self.username, self.password)}
|
|
145
|
+
else
|
|
146
|
+
{}
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def build_curb_response(webmock_response)
|
|
151
|
+
raise Curl::Err::TimeoutError if webmock_response.should_timeout
|
|
152
|
+
webmock_response.raise_error_if_any
|
|
153
|
+
|
|
154
|
+
@body_str = webmock_response.body
|
|
155
|
+
@response_code = webmock_response.status[0]
|
|
156
|
+
|
|
157
|
+
@header_str = "HTTP/1.1 #{webmock_response.status[0]} #{webmock_response.status[1]}\r\n".dup
|
|
158
|
+
|
|
159
|
+
@on_debug.call(@header_str, 1) if defined?( @on_debug )
|
|
160
|
+
|
|
161
|
+
if webmock_response.headers
|
|
162
|
+
@header_str << webmock_response.headers.map do |k,v|
|
|
163
|
+
header = "#{k}: #{v.is_a?(Array) ? v.join(", ") : v}"
|
|
164
|
+
@on_debug.call(header + "\r\n", 1) if defined?( @on_debug )
|
|
165
|
+
header
|
|
166
|
+
end.join("\r\n")
|
|
167
|
+
@on_debug.call("\r\n", 1) if defined?( @on_debug )
|
|
168
|
+
|
|
169
|
+
location = webmock_response.headers['Location']
|
|
170
|
+
if self.follow_location? && location
|
|
171
|
+
@last_effective_url = location
|
|
172
|
+
webmock_follow_location(location)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
@content_type = webmock_response.headers["Content-Type"]
|
|
176
|
+
@transfer_encoding = webmock_response.headers["Transfer-Encoding"]
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
@last_effective_url ||= self.url
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def webmock_follow_location(location)
|
|
183
|
+
first_url = self.url
|
|
184
|
+
self.url = location
|
|
185
|
+
|
|
186
|
+
curb_or_webmock do
|
|
187
|
+
send( :http, {'method' => @webmock_method} )
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
self.url = first_url
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def invoke_curb_callbacks
|
|
194
|
+
@on_progress.call(0.0,1.0,0.0,1.0) if defined?( @on_progress )
|
|
195
|
+
self.header_str.lines.each { |header_line| @on_header.call header_line } if defined?( @on_header )
|
|
196
|
+
if defined?( @on_body )
|
|
197
|
+
if chunked_response?
|
|
198
|
+
self.body_str.each do |chunk|
|
|
199
|
+
@on_body.call(chunk)
|
|
200
|
+
end
|
|
201
|
+
else
|
|
202
|
+
@on_body.call(self.body_str)
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
@on_complete.call(self) if defined?( @on_complete )
|
|
206
|
+
|
|
207
|
+
case response_code
|
|
208
|
+
when 200..299
|
|
209
|
+
@on_success.call(self) if defined?( @on_success )
|
|
210
|
+
when 400..499
|
|
211
|
+
@on_missing.call(self, self.response_code) if defined?( @on_missing )
|
|
212
|
+
when 500..599
|
|
213
|
+
@on_failure.call(self, self.response_code) if defined?( @on_failure )
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def chunked_response?
|
|
218
|
+
defined?( @transfer_encoding ) && @transfer_encoding == 'chunked' && self.body_str.respond_to?(:each)
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def build_webmock_response
|
|
222
|
+
status, headers =
|
|
223
|
+
WebMock::HttpLibAdapters::CurbAdapter.parse_header_string(self.header_str)
|
|
224
|
+
|
|
225
|
+
if defined?( @on_debug )
|
|
226
|
+
http_response = ["HTTP/1.0 #{@debug_method} #{@debug_path}"]
|
|
227
|
+
headers.each do |name, value|
|
|
228
|
+
http_response << "#{name}: #{value}"
|
|
229
|
+
end
|
|
230
|
+
http_response << self.body_str
|
|
231
|
+
@on_debug.call(http_response.join("\r\n") + "\r\n", 3)
|
|
232
|
+
@on_debug.call("Connection #0 to host #{@debug_host} left intact\r\n", 0)
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
webmock_response = WebMock::Response.new
|
|
236
|
+
webmock_response.status = [self.response_code, status]
|
|
237
|
+
webmock_response.body = self.body_str
|
|
238
|
+
webmock_response.headers = headers
|
|
239
|
+
webmock_response
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
###
|
|
243
|
+
### Mocks of Curl::Easy methods below here.
|
|
244
|
+
###
|
|
245
|
+
|
|
246
|
+
def http(method)
|
|
247
|
+
@webmock_method = method
|
|
248
|
+
super
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
%w[ get head delete ].each do |verb|
|
|
252
|
+
define_method "http_#{verb}" do
|
|
253
|
+
@webmock_method = verb
|
|
254
|
+
super()
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def http_put data = nil
|
|
259
|
+
@webmock_method = :put
|
|
260
|
+
@put_data = data if data
|
|
261
|
+
super
|
|
262
|
+
end
|
|
263
|
+
alias put http_put
|
|
264
|
+
|
|
265
|
+
def http_post *data
|
|
266
|
+
@webmock_method = :post
|
|
267
|
+
@post_body = data.join('&') if data && !data.empty?
|
|
268
|
+
super
|
|
269
|
+
end
|
|
270
|
+
alias post http_post
|
|
271
|
+
|
|
272
|
+
def perform
|
|
273
|
+
@webmock_method ||= :get
|
|
274
|
+
curb_or_webmock { super }
|
|
275
|
+
ensure
|
|
276
|
+
reset_webmock_method
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def put_data= data
|
|
280
|
+
@webmock_method = :put
|
|
281
|
+
@put_data = data
|
|
282
|
+
super
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
def post_body= data
|
|
286
|
+
@webmock_method = :post
|
|
287
|
+
super
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
def delete= value
|
|
291
|
+
@webmock_method = :delete if value
|
|
292
|
+
super
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
def head= value
|
|
296
|
+
@webmock_method = :head if value
|
|
297
|
+
super
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def verbose=(verbose)
|
|
301
|
+
@verbose = verbose
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
def verbose?
|
|
305
|
+
@verbose ||= false
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def body_str
|
|
309
|
+
@body_str ||= super
|
|
310
|
+
end
|
|
311
|
+
alias body body_str
|
|
312
|
+
|
|
313
|
+
def response_code
|
|
314
|
+
@response_code ||= super
|
|
315
|
+
end
|
|
316
|
+
alias code response_code
|
|
317
|
+
|
|
318
|
+
def header_str
|
|
319
|
+
@header_str ||= super
|
|
320
|
+
end
|
|
321
|
+
alias head header_str
|
|
322
|
+
|
|
323
|
+
def last_effective_url
|
|
324
|
+
@last_effective_url ||= super
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
def content_type
|
|
328
|
+
@content_type ||= super
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
%w[ success failure missing header body complete progress debug ].each do |callback|
|
|
332
|
+
class_eval <<-METHOD, __FILE__, __LINE__
|
|
333
|
+
def on_#{callback} &block
|
|
334
|
+
@on_#{callback} = block
|
|
335
|
+
super
|
|
336
|
+
end
|
|
337
|
+
METHOD
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
def reset_webmock_method
|
|
341
|
+
@webmock_method = :get
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
def reset
|
|
345
|
+
instance_variable_set(:@body_str, nil)
|
|
346
|
+
instance_variable_set(:@content_type, nil)
|
|
347
|
+
instance_variable_set(:@header_str, nil)
|
|
348
|
+
instance_variable_set(:@last_effective_url, nil)
|
|
349
|
+
instance_variable_set(:@response_code, nil)
|
|
350
|
+
super
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
end
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
begin
|
|
4
|
+
require 'em-http-request'
|
|
5
|
+
rescue LoadError
|
|
6
|
+
# em-http-request not found
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
if defined?(EventMachine::HttpClient)
|
|
10
|
+
module WebMock
|
|
11
|
+
module HttpLibAdapters
|
|
12
|
+
class EmHttpRequestAdapter < HttpLibAdapter
|
|
13
|
+
adapter_for :em_http_request
|
|
14
|
+
|
|
15
|
+
OriginalHttpClient = EventMachine::HttpClient unless const_defined?(:OriginalHttpClient)
|
|
16
|
+
OriginalHttpConnection = EventMachine::HttpConnection unless const_defined?(:OriginalHttpConnection)
|
|
17
|
+
|
|
18
|
+
def self.enable!
|
|
19
|
+
EventMachine.send(:remove_const, :HttpConnection)
|
|
20
|
+
EventMachine.send(:const_set, :HttpConnection, EventMachine::WebMockHttpConnection)
|
|
21
|
+
EventMachine.send(:remove_const, :HttpClient)
|
|
22
|
+
EventMachine.send(:const_set, :HttpClient, EventMachine::WebMockHttpClient)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.disable!
|
|
26
|
+
EventMachine.send(:remove_const, :HttpConnection)
|
|
27
|
+
EventMachine.send(:const_set, :HttpConnection, OriginalHttpConnection)
|
|
28
|
+
EventMachine.send(:remove_const, :HttpClient)
|
|
29
|
+
EventMachine.send(:const_set, :HttpClient, OriginalHttpClient)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
module EventMachine
|
|
36
|
+
if defined?(Synchrony) && HTTPMethods.instance_methods.include?(:aget)
|
|
37
|
+
# have to make the callbacks fire on the next tick in order
|
|
38
|
+
# to avoid the dreaded "double resume" exception
|
|
39
|
+
module HTTPMethods
|
|
40
|
+
%w[get head post delete put].each do |type|
|
|
41
|
+
class_eval %[
|
|
42
|
+
def #{type}(options = {}, &blk)
|
|
43
|
+
f = Fiber.current
|
|
44
|
+
|
|
45
|
+
conn = setup_request(:#{type}, options, &blk)
|
|
46
|
+
conn.callback { EM.next_tick { f.resume(conn) } }
|
|
47
|
+
conn.errback { EM.next_tick { f.resume(conn) } }
|
|
48
|
+
|
|
49
|
+
Fiber.yield
|
|
50
|
+
end
|
|
51
|
+
]
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
class WebMockHttpConnection < HttpConnection
|
|
57
|
+
def activate_connection(client)
|
|
58
|
+
request_signature = client.request_signature
|
|
59
|
+
|
|
60
|
+
if client.stubbed_webmock_response
|
|
61
|
+
conn = HttpStubConnection.new rand(10000)
|
|
62
|
+
post_init
|
|
63
|
+
|
|
64
|
+
@deferred = false
|
|
65
|
+
@conn = conn
|
|
66
|
+
|
|
67
|
+
conn.parent = self
|
|
68
|
+
conn.pending_connect_timeout = @connopts.connect_timeout
|
|
69
|
+
conn.comm_inactivity_timeout = @connopts.inactivity_timeout
|
|
70
|
+
|
|
71
|
+
finalize_request(client)
|
|
72
|
+
@conn.set_deferred_status :succeeded
|
|
73
|
+
elsif WebMock.net_connect_allowed?(request_signature.uri)
|
|
74
|
+
super
|
|
75
|
+
else
|
|
76
|
+
raise WebMock::NetConnectNotAllowedError.new(request_signature)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def drop_client
|
|
81
|
+
@clients.shift
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
class WebMockHttpClient < EventMachine::HttpClient
|
|
86
|
+
include HttpEncoding
|
|
87
|
+
|
|
88
|
+
def uri
|
|
89
|
+
@req.uri
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def setup(response, uri, error = nil)
|
|
93
|
+
@last_effective_url = @uri = uri
|
|
94
|
+
if error
|
|
95
|
+
on_error(error)
|
|
96
|
+
@conn.drop_client
|
|
97
|
+
fail(self)
|
|
98
|
+
else
|
|
99
|
+
@conn.receive_data(response)
|
|
100
|
+
succeed(self)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def connection_completed
|
|
105
|
+
@state = :response_header
|
|
106
|
+
send_request(*headers_and_body_processed_by_middleware)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def send_request(head, body)
|
|
110
|
+
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
|
|
111
|
+
|
|
112
|
+
if stubbed_webmock_response
|
|
113
|
+
WebMock::CallbackRegistry.invoke_callbacks({lib: :em_http_request}, request_signature, stubbed_webmock_response)
|
|
114
|
+
@uri ||= nil
|
|
115
|
+
EM.next_tick {
|
|
116
|
+
setup(make_raw_response(stubbed_webmock_response), @uri,
|
|
117
|
+
stubbed_webmock_response.should_timeout ? Errno::ETIMEDOUT : nil)
|
|
118
|
+
}
|
|
119
|
+
self
|
|
120
|
+
elsif WebMock.net_connect_allowed?(request_signature.uri)
|
|
121
|
+
super
|
|
122
|
+
else
|
|
123
|
+
raise WebMock::NetConnectNotAllowedError.new(request_signature)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def unbind(reason = nil)
|
|
128
|
+
if !stubbed_webmock_response && WebMock::CallbackRegistry.any_callbacks?
|
|
129
|
+
webmock_response = build_webmock_response
|
|
130
|
+
WebMock::CallbackRegistry.invoke_callbacks(
|
|
131
|
+
{lib: :em_http_request, real_request: true},
|
|
132
|
+
request_signature,
|
|
133
|
+
webmock_response)
|
|
134
|
+
end
|
|
135
|
+
@request_signature = nil
|
|
136
|
+
remove_instance_variable(:@stubbed_webmock_response)
|
|
137
|
+
|
|
138
|
+
super
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def request_signature
|
|
142
|
+
@request_signature ||= build_request_signature
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def stubbed_webmock_response
|
|
146
|
+
unless defined?(@stubbed_webmock_response)
|
|
147
|
+
@stubbed_webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
@stubbed_webmock_response
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def get_response_cookie(name)
|
|
154
|
+
name = name.to_s
|
|
155
|
+
|
|
156
|
+
raw_cookie = response_header.cookie
|
|
157
|
+
raw_cookie = [raw_cookie] if raw_cookie.is_a? String
|
|
158
|
+
|
|
159
|
+
cookie = raw_cookie.detect { |c| c.start_with? name }
|
|
160
|
+
cookie and cookie.split('=', 2)[1]
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
private
|
|
164
|
+
|
|
165
|
+
def build_webmock_response
|
|
166
|
+
webmock_response = WebMock::Response.new
|
|
167
|
+
webmock_response.status = [response_header.status, response_header.http_reason]
|
|
168
|
+
webmock_response.headers = response_header
|
|
169
|
+
webmock_response.body = response
|
|
170
|
+
webmock_response
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def headers_and_body_processed_by_middleware
|
|
174
|
+
@headers_and_body_processed_by_middleware ||= begin
|
|
175
|
+
head, body = build_request, @req.body
|
|
176
|
+
@conn.middleware.each do |m|
|
|
177
|
+
head, body = m.request(self, head, body) if m.respond_to?(:request)
|
|
178
|
+
end
|
|
179
|
+
[head, body]
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def build_request_signature
|
|
184
|
+
headers, body = headers_and_body_processed_by_middleware
|
|
185
|
+
|
|
186
|
+
method = @req.method
|
|
187
|
+
uri = @req.uri.clone
|
|
188
|
+
query = @req.query
|
|
189
|
+
|
|
190
|
+
uri.query = encode_query(@req.uri, query).slice(/\?(.*)/, 1)
|
|
191
|
+
|
|
192
|
+
body = form_encode_body(body) if body.is_a?(Hash)
|
|
193
|
+
|
|
194
|
+
if headers['authorization'] && headers['authorization'].is_a?(Array)
|
|
195
|
+
headers['Authorization'] = WebMock::Util::Headers.basic_auth_header(headers.delete('authorization'))
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
WebMock::RequestSignature.new(
|
|
199
|
+
method.downcase.to_sym,
|
|
200
|
+
uri.to_s,
|
|
201
|
+
body: body || (@req.file && File.read(@req.file)),
|
|
202
|
+
headers: headers
|
|
203
|
+
)
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def make_raw_response(response)
|
|
207
|
+
response.raise_error_if_any
|
|
208
|
+
|
|
209
|
+
status, headers, body = response.status, response.headers, response.body
|
|
210
|
+
headers ||= {}
|
|
211
|
+
|
|
212
|
+
response_string = []
|
|
213
|
+
response_string << "HTTP/1.1 #{status[0]} #{status[1]}"
|
|
214
|
+
|
|
215
|
+
headers["Content-Length"] = body.bytesize unless headers["Content-Length"]
|
|
216
|
+
headers.each do |header, value|
|
|
217
|
+
if header =~ /set-cookie/i
|
|
218
|
+
[value].flatten.each do |cookie|
|
|
219
|
+
response_string << "#{header}: #{cookie}"
|
|
220
|
+
end
|
|
221
|
+
else
|
|
222
|
+
value = value.join(", ") if value.is_a?(Array)
|
|
223
|
+
|
|
224
|
+
# WebMock's internal processing will not handle the body
|
|
225
|
+
# correctly if the header indicates that it is chunked, unless
|
|
226
|
+
# we also create all the chunks.
|
|
227
|
+
# It's far easier just to remove the header.
|
|
228
|
+
next if header =~ /transfer-encoding/i && value =~/chunked/i
|
|
229
|
+
|
|
230
|
+
response_string << "#{header}: #{value}"
|
|
231
|
+
end
|
|
232
|
+
end if headers
|
|
233
|
+
|
|
234
|
+
response_string << "" << body
|
|
235
|
+
response_string.join("\n")
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
end
|