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