webmock 3.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +7 -0
  2. data/.gemtest +0 -0
  3. data/.gitignore +34 -0
  4. data/.rspec-tm +2 -0
  5. data/.travis.yml +19 -0
  6. data/CHANGELOG.md +1698 -0
  7. data/Gemfile +9 -0
  8. data/LICENSE +20 -0
  9. data/README.md +1125 -0
  10. data/Rakefile +28 -0
  11. data/lib/webmock.rb +59 -0
  12. data/lib/webmock/api.rb +109 -0
  13. data/lib/webmock/assertion_failure.rb +11 -0
  14. data/lib/webmock/callback_registry.rb +35 -0
  15. data/lib/webmock/config.rb +18 -0
  16. data/lib/webmock/cucumber.rb +10 -0
  17. data/lib/webmock/deprecation.rb +9 -0
  18. data/lib/webmock/errors.rb +17 -0
  19. data/lib/webmock/http_lib_adapters/async_http_client_adapter.rb +214 -0
  20. data/lib/webmock/http_lib_adapters/curb_adapter.rb +347 -0
  21. data/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +228 -0
  22. data/lib/webmock/http_lib_adapters/excon_adapter.rb +162 -0
  23. data/lib/webmock/http_lib_adapters/http_lib_adapter.rb +7 -0
  24. data/lib/webmock/http_lib_adapters/http_lib_adapter_registry.rb +19 -0
  25. data/lib/webmock/http_lib_adapters/http_rb/client.rb +14 -0
  26. data/lib/webmock/http_lib_adapters/http_rb/request.rb +16 -0
  27. data/lib/webmock/http_lib_adapters/http_rb/response.rb +43 -0
  28. data/lib/webmock/http_lib_adapters/http_rb/streamer.rb +29 -0
  29. data/lib/webmock/http_lib_adapters/http_rb/webmock.rb +68 -0
  30. data/lib/webmock/http_lib_adapters/http_rb_adapter.rb +37 -0
  31. data/lib/webmock/http_lib_adapters/httpclient_adapter.rb +242 -0
  32. data/lib/webmock/http_lib_adapters/manticore_adapter.rb +130 -0
  33. data/lib/webmock/http_lib_adapters/net_http.rb +361 -0
  34. data/lib/webmock/http_lib_adapters/net_http_response.rb +34 -0
  35. data/lib/webmock/http_lib_adapters/patron_adapter.rb +130 -0
  36. data/lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb +174 -0
  37. data/lib/webmock/matchers/any_arg_matcher.rb +13 -0
  38. data/lib/webmock/matchers/hash_argument_matcher.rb +21 -0
  39. data/lib/webmock/matchers/hash_excluding_matcher.rb +15 -0
  40. data/lib/webmock/matchers/hash_including_matcher.rb +17 -0
  41. data/lib/webmock/minitest.rb +41 -0
  42. data/lib/webmock/rack_response.rb +69 -0
  43. data/lib/webmock/request_body_diff.rb +64 -0
  44. data/lib/webmock/request_execution_verifier.rb +77 -0
  45. data/lib/webmock/request_pattern.rb +370 -0
  46. data/lib/webmock/request_registry.rb +35 -0
  47. data/lib/webmock/request_signature.rb +54 -0
  48. data/lib/webmock/request_signature_snippet.rb +61 -0
  49. data/lib/webmock/request_stub.rb +100 -0
  50. data/lib/webmock/response.rb +153 -0
  51. data/lib/webmock/responses_sequence.rb +40 -0
  52. data/lib/webmock/rspec.rb +41 -0
  53. data/lib/webmock/rspec/matchers.rb +27 -0
  54. data/lib/webmock/rspec/matchers/request_pattern_matcher.rb +78 -0
  55. data/lib/webmock/rspec/matchers/webmock_matcher.rb +67 -0
  56. data/lib/webmock/stub_registry.rb +67 -0
  57. data/lib/webmock/stub_request_snippet.rb +38 -0
  58. data/lib/webmock/test_unit.rb +22 -0
  59. data/lib/webmock/util/hash_counter.rb +39 -0
  60. data/lib/webmock/util/hash_keys_stringifier.rb +25 -0
  61. data/lib/webmock/util/hash_validator.rb +17 -0
  62. data/lib/webmock/util/headers.rb +64 -0
  63. data/lib/webmock/util/json.rb +67 -0
  64. data/lib/webmock/util/query_mapper.rb +281 -0
  65. data/lib/webmock/util/uri.rb +110 -0
  66. data/lib/webmock/util/values_stringifier.rb +20 -0
  67. data/lib/webmock/util/version_checker.rb +111 -0
  68. data/lib/webmock/version.rb +3 -0
  69. data/lib/webmock/webmock.rb +161 -0
  70. data/minitest/test_helper.rb +34 -0
  71. data/minitest/test_webmock.rb +9 -0
  72. data/minitest/webmock_spec.rb +60 -0
  73. data/spec/acceptance/async_http_client/async_http_client_spec.rb +349 -0
  74. data/spec/acceptance/async_http_client/async_http_client_spec_helper.rb +73 -0
  75. data/spec/acceptance/curb/curb_spec.rb +492 -0
  76. data/spec/acceptance/curb/curb_spec_helper.rb +147 -0
  77. data/spec/acceptance/em_http_request/em_http_request_spec.rb +406 -0
  78. data/spec/acceptance/em_http_request/em_http_request_spec_helper.rb +77 -0
  79. data/spec/acceptance/excon/excon_spec.rb +77 -0
  80. data/spec/acceptance/excon/excon_spec_helper.rb +50 -0
  81. data/spec/acceptance/http_rb/http_rb_spec.rb +82 -0
  82. data/spec/acceptance/http_rb/http_rb_spec_helper.rb +54 -0
  83. data/spec/acceptance/httpclient/httpclient_spec.rb +217 -0
  84. data/spec/acceptance/httpclient/httpclient_spec_helper.rb +57 -0
  85. data/spec/acceptance/manticore/manticore_spec.rb +56 -0
  86. data/spec/acceptance/manticore/manticore_spec_helper.rb +35 -0
  87. data/spec/acceptance/net_http/net_http_shared.rb +153 -0
  88. data/spec/acceptance/net_http/net_http_spec.rb +331 -0
  89. data/spec/acceptance/net_http/net_http_spec_helper.rb +64 -0
  90. data/spec/acceptance/net_http/real_net_http_spec.rb +20 -0
  91. data/spec/acceptance/patron/patron_spec.rb +125 -0
  92. data/spec/acceptance/patron/patron_spec_helper.rb +54 -0
  93. data/spec/acceptance/shared/allowing_and_disabling_net_connect.rb +313 -0
  94. data/spec/acceptance/shared/callbacks.rb +148 -0
  95. data/spec/acceptance/shared/complex_cross_concern_behaviors.rb +36 -0
  96. data/spec/acceptance/shared/enabling_and_disabling_webmock.rb +95 -0
  97. data/spec/acceptance/shared/precedence_of_stubs.rb +15 -0
  98. data/spec/acceptance/shared/request_expectations.rb +930 -0
  99. data/spec/acceptance/shared/returning_declared_responses.rb +409 -0
  100. data/spec/acceptance/shared/stubbing_requests.rb +643 -0
  101. data/spec/acceptance/typhoeus/typhoeus_hydra_spec.rb +135 -0
  102. data/spec/acceptance/typhoeus/typhoeus_hydra_spec_helper.rb +60 -0
  103. data/spec/acceptance/webmock_shared.rb +41 -0
  104. data/spec/fixtures/test.txt +1 -0
  105. data/spec/quality_spec.rb +84 -0
  106. data/spec/spec_helper.rb +48 -0
  107. data/spec/support/example_curl_output.txt +22 -0
  108. data/spec/support/failures.rb +9 -0
  109. data/spec/support/my_rack_app.rb +53 -0
  110. data/spec/support/network_connection.rb +19 -0
  111. data/spec/support/webmock_server.rb +70 -0
  112. data/spec/unit/api_spec.rb +175 -0
  113. data/spec/unit/errors_spec.rb +129 -0
  114. data/spec/unit/http_lib_adapters/http_lib_adapter_registry_spec.rb +17 -0
  115. data/spec/unit/http_lib_adapters/http_lib_adapter_spec.rb +12 -0
  116. data/spec/unit/matchers/hash_excluding_matcher_spec.rb +61 -0
  117. data/spec/unit/matchers/hash_including_matcher_spec.rb +87 -0
  118. data/spec/unit/rack_response_spec.rb +112 -0
  119. data/spec/unit/request_body_diff_spec.rb +90 -0
  120. data/spec/unit/request_execution_verifier_spec.rb +208 -0
  121. data/spec/unit/request_pattern_spec.rb +601 -0
  122. data/spec/unit/request_registry_spec.rb +95 -0
  123. data/spec/unit/request_signature_snippet_spec.rb +89 -0
  124. data/spec/unit/request_signature_spec.rb +155 -0
  125. data/spec/unit/request_stub_spec.rb +199 -0
  126. data/spec/unit/response_spec.rb +282 -0
  127. data/spec/unit/stub_registry_spec.rb +103 -0
  128. data/spec/unit/stub_request_snippet_spec.rb +115 -0
  129. data/spec/unit/util/hash_counter_spec.rb +39 -0
  130. data/spec/unit/util/hash_keys_stringifier_spec.rb +27 -0
  131. data/spec/unit/util/headers_spec.rb +28 -0
  132. data/spec/unit/util/json_spec.rb +33 -0
  133. data/spec/unit/util/query_mapper_spec.rb +157 -0
  134. data/spec/unit/util/uri_spec.rb +361 -0
  135. data/spec/unit/util/version_checker_spec.rb +65 -0
  136. data/spec/unit/webmock_spec.rb +19 -0
  137. data/test/http_request.rb +24 -0
  138. data/test/shared_test.rb +108 -0
  139. data/test/test_helper.rb +23 -0
  140. data/test/test_webmock.rb +6 -0
  141. data/webmock.gemspec +45 -0
  142. metadata +496 -0
@@ -0,0 +1,347 @@
1
+ begin
2
+ require 'curb'
3
+ rescue LoadError
4
+ # curb not found
5
+ end
6
+
7
+ if defined?(Curl)
8
+ WebMock::VersionChecker.new('Curb', Curl::CURB_VERSION, '0.7.16', '0.9.1', ['0.8.7']).check_version!
9
+
10
+ module WebMock
11
+ module HttpLibAdapters
12
+ class CurbAdapter < HttpLibAdapter
13
+ adapter_for :curb
14
+
15
+ OriginalCurlEasy = Curl::Easy unless const_defined?(:OriginalCurlEasy)
16
+
17
+ def self.enable!
18
+ Curl.send(:remove_const, :Easy)
19
+ Curl.send(:const_set, :Easy, Curl::WebMockCurlEasy)
20
+ end
21
+
22
+ def self.disable!
23
+ Curl.send(:remove_const, :Easy)
24
+ Curl.send(:const_set, :Easy, OriginalCurlEasy)
25
+ end
26
+
27
+ # Borrowed from Patron:
28
+ # http://github.com/toland/patron/blob/master/lib/patron/response.rb
29
+ def self.parse_header_string(header_string)
30
+ status, headers = nil, {}
31
+
32
+ header_string.split(/\r\n/).each do |header|
33
+ if header =~ %r|^HTTP/1.[01] \d\d\d (.*)|
34
+ status = $1
35
+ else
36
+ parts = header.split(':', 2)
37
+ unless parts.empty?
38
+ parts[1].strip! unless parts[1].nil?
39
+ if headers.has_key?(parts[0])
40
+ headers[parts[0]] = [headers[parts[0]]] unless headers[parts[0]].kind_of? Array
41
+ headers[parts[0]] << parts[1]
42
+ else
43
+ headers[parts[0]] = parts[1]
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ return status, headers
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ module Curl
56
+ class WebMockCurlEasy < Curl::Easy
57
+ def curb_or_webmock
58
+ request_signature = build_request_signature
59
+ WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
60
+
61
+ if webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
62
+ build_curb_response(webmock_response)
63
+ WebMock::CallbackRegistry.invoke_callbacks(
64
+ {lib: :curb}, request_signature, webmock_response)
65
+ invoke_curb_callbacks
66
+ true
67
+ elsif WebMock.net_connect_allowed?(request_signature.uri)
68
+ res = yield
69
+ if WebMock::CallbackRegistry.any_callbacks?
70
+ webmock_response = build_webmock_response
71
+ WebMock::CallbackRegistry.invoke_callbacks(
72
+ {lib: :curb, real_request: true}, request_signature,
73
+ webmock_response)
74
+ end
75
+ res
76
+ else
77
+ raise WebMock::NetConnectNotAllowedError.new(request_signature)
78
+ end
79
+ end
80
+
81
+ def build_request_signature
82
+ method = @webmock_method.to_s.downcase.to_sym
83
+
84
+ uri = WebMock::Util::URI.heuristic_parse(self.url)
85
+ uri.path = uri.normalized_path.gsub("[^:]//","/")
86
+
87
+ headers = headers_as_hash(self.headers).merge(basic_auth_headers)
88
+
89
+ request_body = case method
90
+ when :post, :patch
91
+ self.post_body || @post_body
92
+ when :put
93
+ @put_data
94
+ else
95
+ nil
96
+ end
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
+
119
+ request_signature = WebMock::RequestSignature.new(
120
+ method,
121
+ uri.to_s,
122
+ body: request_body,
123
+ headers: headers
124
+ )
125
+ request_signature
126
+ end
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
+
148
+ def build_curb_response(webmock_response)
149
+ raise Curl::Err::TimeoutError if webmock_response.should_timeout
150
+ webmock_response.raise_error_if_any
151
+
152
+ @body_str = webmock_response.body
153
+ @response_code = webmock_response.status[0]
154
+
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
+
159
+ if webmock_response.headers
160
+ @header_str << webmock_response.headers.map do |k,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
164
+ end.join("\r\n")
165
+ @on_debug.call("\r\n", 1) if defined?( @on_debug )
166
+
167
+ location = webmock_response.headers['Location']
168
+ if self.follow_location? && location
169
+ @last_effective_url = location
170
+ webmock_follow_location(location)
171
+ end
172
+
173
+ @content_type = webmock_response.headers["Content-Type"]
174
+ @transfer_encoding = webmock_response.headers["Transfer-Encoding"]
175
+ end
176
+
177
+ @last_effective_url ||= self.url
178
+ end
179
+
180
+ def webmock_follow_location(location)
181
+ first_url = self.url
182
+ self.url = location
183
+
184
+ curb_or_webmock do
185
+ send( :http, {'method' => @webmock_method} )
186
+ end
187
+
188
+ self.url = first_url
189
+ end
190
+
191
+ def invoke_curb_callbacks
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 )
204
+
205
+ case response_code
206
+ when 200..299
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 )
212
+ end
213
+ end
214
+
215
+ def chunked_response?
216
+ defined?( @transfer_encoding ) && @transfer_encoding == 'chunked' && self.body_str.respond_to?(:each)
217
+ end
218
+
219
+ def build_webmock_response
220
+ status, headers =
221
+ WebMock::HttpLibAdapters::CurbAdapter.parse_header_string(self.header_str)
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
+
233
+ webmock_response = WebMock::Response.new
234
+ webmock_response.status = [self.response_code, status]
235
+ webmock_response.body = self.body_str
236
+ webmock_response.headers = headers
237
+ webmock_response
238
+ end
239
+
240
+ ###
241
+ ### Mocks of Curl::Easy methods below here.
242
+ ###
243
+
244
+ def http(method)
245
+ @webmock_method = method
246
+ super
247
+ end
248
+
249
+ %w[ get head delete ].each do |verb|
250
+ define_method "http_#{verb}" do
251
+ @webmock_method = verb
252
+ super()
253
+ end
254
+ end
255
+
256
+ def http_put data = nil
257
+ @webmock_method = :put
258
+ @put_data = data if data
259
+ super
260
+ end
261
+ alias put http_put
262
+
263
+ def http_post *data
264
+ @webmock_method = :post
265
+ @post_body = data.join('&') if data && !data.empty?
266
+ super
267
+ end
268
+ alias post http_post
269
+
270
+ def perform
271
+ @webmock_method ||= :get
272
+ curb_or_webmock { super }
273
+ ensure
274
+ reset_webmock_method
275
+ end
276
+
277
+ def put_data= data
278
+ @webmock_method = :put
279
+ @put_data = data
280
+ super
281
+ end
282
+
283
+ def post_body= data
284
+ @webmock_method = :post
285
+ super
286
+ end
287
+
288
+ def delete= value
289
+ @webmock_method = :delete if value
290
+ super
291
+ end
292
+
293
+ def head= value
294
+ @webmock_method = :head if value
295
+ super
296
+ end
297
+
298
+ def verbose=(verbose)
299
+ @verbose = verbose
300
+ end
301
+
302
+ def verbose?
303
+ @verbose ||= false
304
+ end
305
+
306
+ def body_str
307
+ @body_str ||= super
308
+ end
309
+ alias body body_str
310
+
311
+ def response_code
312
+ @response_code ||= super
313
+ end
314
+
315
+ def header_str
316
+ @header_str ||= super
317
+ end
318
+ alias head header_str
319
+
320
+ def last_effective_url
321
+ @last_effective_url ||= super
322
+ end
323
+
324
+ def content_type
325
+ @content_type ||= super
326
+ end
327
+
328
+ %w[ success failure missing header body complete progress debug ].each do |callback|
329
+ class_eval <<-METHOD, __FILE__, __LINE__
330
+ def on_#{callback} &block
331
+ @on_#{callback} = block
332
+ super
333
+ end
334
+ METHOD
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
+ super
344
+ end
345
+ end
346
+ end
347
+ end
@@ -0,0 +1,228 @@
1
+ begin
2
+ require 'em-http-request'
3
+ rescue LoadError
4
+ # em-http-request not found
5
+ end
6
+
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 send_request(head, body)
103
+ WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
104
+
105
+ if stubbed_webmock_response
106
+ WebMock::CallbackRegistry.invoke_callbacks({lib: :em_http_request}, request_signature, stubbed_webmock_response)
107
+ @uri ||= nil
108
+ EM.next_tick {
109
+ setup(make_raw_response(stubbed_webmock_response), @uri,
110
+ stubbed_webmock_response.should_timeout ? "WebMock timeout error" : nil)
111
+ }
112
+ self
113
+ elsif WebMock.net_connect_allowed?(request_signature.uri)
114
+ super
115
+ else
116
+ raise WebMock::NetConnectNotAllowedError.new(request_signature)
117
+ end
118
+ end
119
+
120
+ def unbind(reason = nil)
121
+ if !stubbed_webmock_response && WebMock::CallbackRegistry.any_callbacks?
122
+ webmock_response = build_webmock_response
123
+ WebMock::CallbackRegistry.invoke_callbacks(
124
+ {lib: :em_http_request, real_request: true},
125
+ request_signature,
126
+ webmock_response)
127
+ end
128
+ @request_signature = nil
129
+ remove_instance_variable(:@stubbed_webmock_response)
130
+
131
+ super
132
+ end
133
+
134
+ def request_signature
135
+ @request_signature ||= build_request_signature
136
+ end
137
+
138
+ def stubbed_webmock_response
139
+ unless defined?(@stubbed_webmock_response)
140
+ @stubbed_webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
141
+ end
142
+
143
+ @stubbed_webmock_response
144
+ end
145
+
146
+ def get_response_cookie(name)
147
+ name = name.to_s
148
+
149
+ raw_cookie = response_header.cookie
150
+ raw_cookie = [raw_cookie] if raw_cookie.is_a? String
151
+
152
+ cookie = raw_cookie.select { |c| c.start_with? name }.first
153
+ cookie and cookie.split('=', 2)[1]
154
+ end
155
+
156
+ private
157
+
158
+ def build_webmock_response
159
+ webmock_response = WebMock::Response.new
160
+ webmock_response.status = [response_header.status, response_header.http_reason]
161
+ webmock_response.headers = response_header
162
+ webmock_response.body = response
163
+ webmock_response
164
+ end
165
+
166
+ def build_request_signature
167
+ headers, body = @req.headers, @req.body
168
+
169
+ @conn.middleware.select {|m| m.respond_to?(:request) }.each do |m|
170
+ headers, body = m.request(self, headers, body)
171
+ end
172
+
173
+ method = @req.method
174
+ uri = @req.uri.clone
175
+ query = @req.query
176
+
177
+ uri.query = encode_query(@req.uri, query).slice(/\?(.*)/, 1)
178
+
179
+ body = form_encode_body(body) if body.is_a?(Hash)
180
+
181
+ headers = @req.headers
182
+
183
+ if headers['authorization'] && headers['authorization'].is_a?(Array)
184
+ headers['Authorization'] = WebMock::Util::Headers.basic_auth_header(headers.delete('authorization'))
185
+ end
186
+
187
+ WebMock::RequestSignature.new(
188
+ method.downcase.to_sym,
189
+ uri.to_s,
190
+ body: body || (@req.file && File.read(@req.file)),
191
+ headers: headers
192
+ )
193
+ end
194
+
195
+ def make_raw_response(response)
196
+ response.raise_error_if_any
197
+
198
+ status, headers, body = response.status, response.headers, response.body
199
+ headers ||= {}
200
+
201
+ response_string = []
202
+ response_string << "HTTP/1.1 #{status[0]} #{status[1]}"
203
+
204
+ headers["Content-Length"] = body.bytesize unless headers["Content-Length"]
205
+ headers.each do |header, value|
206
+ if header =~ /set-cookie/i
207
+ [value].flatten.each do |cookie|
208
+ response_string << "#{header}: #{cookie}"
209
+ end
210
+ else
211
+ value = value.join(", ") if value.is_a?(Array)
212
+
213
+ # WebMock's internal processing will not handle the body
214
+ # correctly if the header indicates that it is chunked, unless
215
+ # we also create all the chunks.
216
+ # It's far easier just to remove the header.
217
+ next if header =~ /transfer-encoding/i && value =~/chunked/i
218
+
219
+ response_string << "#{header}: #{value}"
220
+ end
221
+ end if headers
222
+
223
+ response_string << "" << body
224
+ response_string.join("\n")
225
+ end
226
+ end
227
+ end
228
+ end