webmock 3.14.0 → 3.25.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.
Files changed (144) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +213 -3
  3. data/README.md +66 -20
  4. data/lib/webmock/api.rb +2 -0
  5. data/lib/webmock/assertion_failure.rb +2 -0
  6. data/lib/webmock/callback_registry.rb +2 -0
  7. data/lib/webmock/config.rb +2 -0
  8. data/lib/webmock/cucumber.rb +2 -0
  9. data/lib/webmock/deprecation.rb +2 -0
  10. data/lib/webmock/errors.rb +2 -0
  11. data/lib/webmock/http_lib_adapters/async_http_client_adapter.rb +16 -4
  12. data/lib/webmock/http_lib_adapters/curb_adapter.rb +4 -2
  13. data/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +17 -7
  14. data/lib/webmock/http_lib_adapters/excon_adapter.rb +2 -0
  15. data/lib/webmock/http_lib_adapters/http_lib_adapter.rb +2 -0
  16. data/lib/webmock/http_lib_adapters/http_lib_adapter_registry.rb +2 -0
  17. data/lib/webmock/http_lib_adapters/http_rb/client.rb +3 -3
  18. data/lib/webmock/http_lib_adapters/http_rb/request.rb +17 -5
  19. data/lib/webmock/http_lib_adapters/http_rb/response.rb +32 -9
  20. data/lib/webmock/http_lib_adapters/http_rb/streamer.rb +10 -2
  21. data/lib/webmock/http_lib_adapters/http_rb/webmock.rb +8 -2
  22. data/lib/webmock/http_lib_adapters/http_rb_adapter.rb +7 -5
  23. data/lib/webmock/http_lib_adapters/httpclient_adapter.rb +26 -25
  24. data/lib/webmock/http_lib_adapters/manticore_adapter.rb +2 -0
  25. data/lib/webmock/http_lib_adapters/net_http.rb +46 -121
  26. data/lib/webmock/http_lib_adapters/net_http_response.rb +2 -0
  27. data/lib/webmock/http_lib_adapters/patron_adapter.rb +3 -1
  28. data/lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb +18 -2
  29. data/lib/webmock/matchers/any_arg_matcher.rb +2 -0
  30. data/lib/webmock/matchers/hash_argument_matcher.rb +2 -0
  31. data/lib/webmock/matchers/hash_excluding_matcher.rb +2 -0
  32. data/lib/webmock/matchers/hash_including_matcher.rb +2 -0
  33. data/lib/webmock/minitest.rb +2 -0
  34. data/lib/webmock/rack_response.rb +5 -1
  35. data/lib/webmock/request_body_diff.rb +2 -0
  36. data/lib/webmock/request_execution_verifier.rb +2 -0
  37. data/lib/webmock/request_pattern.rb +35 -12
  38. data/lib/webmock/request_registry.rb +2 -0
  39. data/lib/webmock/request_signature.rb +4 -2
  40. data/lib/webmock/request_signature_snippet.rb +2 -0
  41. data/lib/webmock/request_stub.rb +34 -0
  42. data/lib/webmock/response.rb +15 -13
  43. data/lib/webmock/responses_sequence.rb +2 -0
  44. data/lib/webmock/rspec/matchers/request_pattern_matcher.rb +2 -0
  45. data/lib/webmock/rspec/matchers/webmock_matcher.rb +2 -0
  46. data/lib/webmock/rspec/matchers.rb +2 -0
  47. data/lib/webmock/rspec.rb +2 -0
  48. data/lib/webmock/stub_registry.rb +2 -0
  49. data/lib/webmock/stub_request_snippet.rb +2 -0
  50. data/lib/webmock/test_unit.rb +2 -0
  51. data/lib/webmock/util/hash_counter.rb +12 -6
  52. data/lib/webmock/util/hash_keys_stringifier.rb +2 -0
  53. data/lib/webmock/util/hash_validator.rb +2 -0
  54. data/lib/webmock/util/headers.rb +23 -10
  55. data/lib/webmock/util/parsers/json.rb +72 -0
  56. data/lib/webmock/util/parsers/parse_error.rb +7 -0
  57. data/lib/webmock/util/parsers/xml.rb +16 -0
  58. data/lib/webmock/util/query_mapper.rb +2 -0
  59. data/lib/webmock/util/uri.rb +3 -1
  60. data/lib/webmock/util/values_stringifier.rb +2 -0
  61. data/lib/webmock/util/version_checker.rb +7 -5
  62. data/lib/webmock/version.rb +3 -1
  63. data/lib/webmock/webmock.rb +12 -0
  64. data/lib/webmock.rb +4 -2
  65. metadata +66 -185
  66. data/.gemtest +0 -0
  67. data/.github/workflows/CI.yml +0 -37
  68. data/.gitignore +0 -34
  69. data/.rspec-tm +0 -2
  70. data/Gemfile +0 -9
  71. data/Rakefile +0 -38
  72. data/lib/webmock/util/json.rb +0 -67
  73. data/minitest/test_helper.rb +0 -34
  74. data/minitest/test_webmock.rb +0 -9
  75. data/minitest/webmock_spec.rb +0 -60
  76. data/spec/acceptance/async_http_client/async_http_client_spec.rb +0 -375
  77. data/spec/acceptance/async_http_client/async_http_client_spec_helper.rb +0 -73
  78. data/spec/acceptance/curb/curb_spec.rb +0 -499
  79. data/spec/acceptance/curb/curb_spec_helper.rb +0 -147
  80. data/spec/acceptance/em_http_request/em_http_request_spec.rb +0 -462
  81. data/spec/acceptance/em_http_request/em_http_request_spec_helper.rb +0 -77
  82. data/spec/acceptance/excon/excon_spec.rb +0 -77
  83. data/spec/acceptance/excon/excon_spec_helper.rb +0 -52
  84. data/spec/acceptance/http_rb/http_rb_spec.rb +0 -93
  85. data/spec/acceptance/http_rb/http_rb_spec_helper.rb +0 -54
  86. data/spec/acceptance/httpclient/httpclient_spec.rb +0 -217
  87. data/spec/acceptance/httpclient/httpclient_spec_helper.rb +0 -57
  88. data/spec/acceptance/manticore/manticore_spec.rb +0 -107
  89. data/spec/acceptance/manticore/manticore_spec_helper.rb +0 -35
  90. data/spec/acceptance/net_http/net_http_shared.rb +0 -153
  91. data/spec/acceptance/net_http/net_http_spec.rb +0 -369
  92. data/spec/acceptance/net_http/net_http_spec_helper.rb +0 -64
  93. data/spec/acceptance/net_http/real_net_http_spec.rb +0 -20
  94. data/spec/acceptance/patron/patron_spec.rb +0 -125
  95. data/spec/acceptance/patron/patron_spec_helper.rb +0 -54
  96. data/spec/acceptance/shared/allowing_and_disabling_net_connect.rb +0 -313
  97. data/spec/acceptance/shared/callbacks.rb +0 -148
  98. data/spec/acceptance/shared/complex_cross_concern_behaviors.rb +0 -36
  99. data/spec/acceptance/shared/enabling_and_disabling_webmock.rb +0 -95
  100. data/spec/acceptance/shared/precedence_of_stubs.rb +0 -15
  101. data/spec/acceptance/shared/request_expectations.rb +0 -930
  102. data/spec/acceptance/shared/returning_declared_responses.rb +0 -409
  103. data/spec/acceptance/shared/stubbing_requests.rb +0 -678
  104. data/spec/acceptance/typhoeus/typhoeus_hydra_spec.rb +0 -135
  105. data/spec/acceptance/typhoeus/typhoeus_hydra_spec_helper.rb +0 -60
  106. data/spec/acceptance/webmock_shared.rb +0 -41
  107. data/spec/fixtures/test.txt +0 -1
  108. data/spec/quality_spec.rb +0 -84
  109. data/spec/spec_helper.rb +0 -48
  110. data/spec/support/example_curl_output.txt +0 -22
  111. data/spec/support/failures.rb +0 -9
  112. data/spec/support/my_rack_app.rb +0 -53
  113. data/spec/support/network_connection.rb +0 -19
  114. data/spec/support/webmock_server.rb +0 -70
  115. data/spec/unit/api_spec.rb +0 -175
  116. data/spec/unit/errors_spec.rb +0 -129
  117. data/spec/unit/http_lib_adapters/http_lib_adapter_registry_spec.rb +0 -17
  118. data/spec/unit/http_lib_adapters/http_lib_adapter_spec.rb +0 -12
  119. data/spec/unit/matchers/hash_excluding_matcher_spec.rb +0 -61
  120. data/spec/unit/matchers/hash_including_matcher_spec.rb +0 -87
  121. data/spec/unit/rack_response_spec.rb +0 -112
  122. data/spec/unit/request_body_diff_spec.rb +0 -90
  123. data/spec/unit/request_execution_verifier_spec.rb +0 -208
  124. data/spec/unit/request_pattern_spec.rb +0 -736
  125. data/spec/unit/request_registry_spec.rb +0 -95
  126. data/spec/unit/request_signature_snippet_spec.rb +0 -89
  127. data/spec/unit/request_signature_spec.rb +0 -155
  128. data/spec/unit/request_stub_spec.rb +0 -199
  129. data/spec/unit/response_spec.rb +0 -286
  130. data/spec/unit/stub_registry_spec.rb +0 -103
  131. data/spec/unit/stub_request_snippet_spec.rb +0 -115
  132. data/spec/unit/util/hash_counter_spec.rb +0 -39
  133. data/spec/unit/util/hash_keys_stringifier_spec.rb +0 -27
  134. data/spec/unit/util/headers_spec.rb +0 -28
  135. data/spec/unit/util/json_spec.rb +0 -33
  136. data/spec/unit/util/query_mapper_spec.rb +0 -157
  137. data/spec/unit/util/uri_spec.rb +0 -371
  138. data/spec/unit/util/version_checker_spec.rb +0 -65
  139. data/spec/unit/webmock_spec.rb +0 -60
  140. data/test/http_request.rb +0 -24
  141. data/test/shared_test.rb +0 -108
  142. data/test/test_helper.rb +0 -23
  143. data/test/test_webmock.rb +0 -12
  144. data/webmock.gemspec +0 -54
@@ -1,12 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module HTTP
2
4
  class Response
3
5
  def to_webmock
4
6
  webmock_response = ::WebMock::Response.new
5
7
 
6
8
  webmock_response.status = [status.to_i, reason]
9
+
7
10
  webmock_response.body = body.to_s
8
- webmock_response.headers = headers.to_h
11
+ # This call is used to reset the body of the response to enable it to be streamed if necessary.
12
+ # The `body.to_s` call above reads the body, which allows WebMock to trigger any registered callbacks.
13
+ # However, once the body is read to_s, it cannot be streamed again and attempting to do so
14
+ # will raise a "HTTP::StateError: body has already been consumed" error.
15
+ # To avoid this error, we replace the original body with a new one.
16
+ # The new body has its @stream attribute set to new Streamer, instead of the original Connection.
17
+ # Unfortunately, it's not possible to reset the original body to its initial streaming state.
18
+ # Therefore, this replacement is the best workaround currently available.
19
+ reset_body_to_allow_it_to_be_streamed!(webmock_response)
9
20
 
21
+ webmock_response.headers = headers.to_h
10
22
  webmock_response
11
23
  end
12
24
 
@@ -19,13 +31,7 @@ module HTTP
19
31
  # HTTP.rb 3.0+ uses a keyword argument to pass the encoding, but 1.x
20
32
  # and 2.x use a positional argument, and 0.x don't support supplying
21
33
  # the encoding.
22
- body = if HTTP::VERSION < "1.0.0"
23
- Body.new(Streamer.new(webmock_response.body))
24
- elsif HTTP::VERSION < "3.0.0"
25
- Body.new(Streamer.new(webmock_response.body), webmock_response.body.encoding)
26
- else
27
- Body.new(Streamer.new(webmock_response.body), encoding: webmock_response.body.encoding)
28
- end
34
+ body = build_http_rb_response_body_from_webmock_response(webmock_response)
29
35
 
30
36
  return new(status, "1.1", headers, body, uri) if HTTP::VERSION < "1.0.0"
31
37
 
@@ -49,7 +55,18 @@ module HTTP
49
55
  })
50
56
  end
51
57
 
52
- private
58
+ def build_http_rb_response_body_from_webmock_response(webmock_response)
59
+ if HTTP::VERSION < "1.0.0"
60
+ Body.new(Streamer.new(webmock_response.body))
61
+ elsif HTTP::VERSION < "3.0.0"
62
+ Body.new(Streamer.new(webmock_response.body), webmock_response.body.encoding)
63
+ else
64
+ Body.new(
65
+ Streamer.new(webmock_response.body, encoding: webmock_response.body.encoding),
66
+ encoding: webmock_response.body.encoding
67
+ )
68
+ end
69
+ end
53
70
 
54
71
  def normalize_uri(uri)
55
72
  return unless uri
@@ -60,5 +77,11 @@ module HTTP
60
77
  uri
61
78
  end
62
79
  end
80
+
81
+ private
82
+
83
+ def reset_body_to_allow_it_to_be_streamed!(webmock_response)
84
+ @body = self.class.build_http_rb_response_body_from_webmock_response(webmock_response)
85
+ end
63
86
  end
64
87
  end
@@ -1,8 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module HTTP
2
4
  class Response
3
5
  class Streamer
4
- def initialize(str)
6
+ def initialize(str, encoding: Encoding::BINARY)
5
7
  @io = StringIO.new str
8
+ @encoding = encoding
6
9
  end
7
10
 
8
11
  def readpartial(size = nil, outbuf = nil)
@@ -14,13 +17,18 @@ module HTTP
14
17
  end
15
18
  end
16
19
 
17
- @io.read size, outbuf
20
+ chunk = @io.read size, outbuf
21
+ chunk.force_encoding(@encoding) if chunk
18
22
  end
19
23
 
20
24
  def close
21
25
  @io.close
22
26
  end
23
27
 
28
+ def finished_request?
29
+ @io.eof?
30
+ end
31
+
24
32
  def sequence_id
25
33
  -1
26
34
  end
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module HTTP
2
4
  class WebMockPerform
3
- def initialize(request, &perform)
5
+ def initialize(request, options, &perform)
4
6
  @request = request
7
+ @options = options
5
8
  @perform = perform
6
9
  @request_signature = nil
7
10
  end
@@ -38,7 +41,10 @@ module HTTP
38
41
  webmock_response.raise_error_if_any
39
42
 
40
43
  invoke_callbacks(webmock_response, real_request: false)
41
- ::HTTP::Response.from_webmock @request, webmock_response, request_signature
44
+ response = ::HTTP::Response.from_webmock @request, webmock_response, request_signature
45
+
46
+ @options.features.each { |_name, feature| response = feature.wrap_response(response) }
47
+ response
42
48
  end
43
49
 
44
50
  def raise_timeout_error
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  require "http"
3
5
  rescue LoadError
@@ -29,9 +31,9 @@ if defined?(HTTP) && defined?(HTTP::VERSION)
29
31
  end
30
32
  end
31
33
 
32
- require "webmock/http_lib_adapters/http_rb/client"
33
- require "webmock/http_lib_adapters/http_rb/request"
34
- require "webmock/http_lib_adapters/http_rb/response"
35
- require "webmock/http_lib_adapters/http_rb/streamer"
36
- require "webmock/http_lib_adapters/http_rb/webmock"
34
+ require_relative "http_rb/client"
35
+ require_relative "http_rb/request"
36
+ require_relative "http_rb/response"
37
+ require_relative "http_rb/streamer"
38
+ require_relative "http_rb/webmock"
37
39
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  require 'httpclient'
3
5
  require 'jsonclient' # defined in 'httpclient' gem as well
@@ -43,6 +45,8 @@ if defined?(::HTTPClient)
43
45
  end
44
46
 
45
47
  module WebMockHTTPClients
48
+ WEBMOCK_HTTPCLIENT_RESPONSES = :webmock_httpclient_responses
49
+ WEBMOCK_HTTPCLIENT_REQUEST_SIGNATURES = :webmock_httpclient_request_signatures
46
50
 
47
51
  REQUEST_RESPONSE_LOCK = Mutex.new
48
52
 
@@ -55,12 +59,14 @@ if defined?(::HTTPClient)
55
59
  end
56
60
 
57
61
  def do_get(req, proxy, conn, stream = false, &block)
62
+ clear_thread_variables unless conn.async_thread
63
+
58
64
  request_signature = build_request_signature(req, :reuse_existing)
59
65
 
60
66
  WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
61
67
 
62
68
  if webmock_responses[request_signature]
63
- webmock_response = synchronize_request_response { webmock_responses.delete(request_signature) }
69
+ webmock_response = webmock_responses.delete(request_signature)
64
70
  response = build_httpclient_response(webmock_response, stream, req.header, &block)
65
71
  @request_filter.each do |filter|
66
72
  filter.filter_response(req, response)
@@ -71,7 +77,7 @@ if defined?(::HTTPClient)
71
77
  res
72
78
  elsif WebMock.net_connect_allowed?(request_signature.uri)
73
79
  # in case there is a nil entry in the hash...
74
- synchronize_request_response { webmock_responses.delete(request_signature) }
80
+ webmock_responses.delete(request_signature)
75
81
 
76
82
  res = if stream
77
83
  do_get_stream_without_webmock(req, proxy, conn, &block)
@@ -101,12 +107,16 @@ if defined?(::HTTPClient)
101
107
  end
102
108
 
103
109
  def do_request_async(method, uri, query, body, extheader)
110
+ clear_thread_variables
104
111
  req = create_request(method, uri, query, body, extheader)
105
112
  request_signature = build_request_signature(req)
106
- synchronize_request_response { webmock_request_signatures << request_signature }
113
+ webmock_request_signatures << request_signature
107
114
 
108
115
  if webmock_responses[request_signature] || WebMock.net_connect_allowed?(request_signature.uri)
109
- super
116
+ conn = super
117
+ conn.async_thread[WEBMOCK_HTTPCLIENT_REQUEST_SIGNATURES] = Thread.current[WEBMOCK_HTTPCLIENT_REQUEST_SIGNATURES]
118
+ conn.async_thread[WEBMOCK_HTTPCLIENT_RESPONSES] = Thread.current[WEBMOCK_HTTPCLIENT_RESPONSES]
119
+ conn
110
120
  else
111
121
  raise WebMock::NetConnectNotAllowedError.new(request_signature)
112
122
  end
@@ -155,14 +165,14 @@ if defined?(::HTTPClient)
155
165
  end
156
166
 
157
167
  def build_request_signature(req, reuse_existing = false)
158
- uri = WebMock::Util::URI.heuristic_parse(req.header.request_uri.to_s)
159
- uri.query = WebMock::Util::QueryMapper.values_to_query(req.header.request_query, notation: WebMock::Config.instance.query_values_notation) if req.header.request_query
160
- uri.port = req.header.request_uri.port
161
-
162
168
  @request_filter.each do |filter|
163
169
  filter.filter_request(req)
164
170
  end
165
171
 
172
+ uri = WebMock::Util::URI.heuristic_parse(req.header.request_uri.to_s)
173
+ uri.query = WebMock::Util::QueryMapper.values_to_query(req.header.request_query, notation: WebMock::Config.instance.query_values_notation) if req.header.request_query
174
+ uri.port = req.header.request_uri.port
175
+
166
176
  headers = req.header.all.inject({}) do |hdrs, header|
167
177
  hdrs[header[0]] ||= []
168
178
  hdrs[header[0]] << header[1]
@@ -186,22 +196,18 @@ if defined?(::HTTPClient)
186
196
  end
187
197
 
188
198
  def webmock_responses
189
- @webmock_responses ||= Hash.new do |hash, request_signature|
190
- synchronize_request_response do
191
- hash[request_signature] = WebMock::StubRegistry.instance.response_for_request(request_signature)
192
- end
199
+ Thread.current[WEBMOCK_HTTPCLIENT_RESPONSES] ||= Hash.new do |hash, request_signature|
200
+ hash[request_signature] = WebMock::StubRegistry.instance.response_for_request(request_signature)
193
201
  end
194
202
  end
195
203
 
196
204
  def webmock_request_signatures
197
- @webmock_request_signatures ||= []
205
+ Thread.current[WEBMOCK_HTTPCLIENT_REQUEST_SIGNATURES] ||= []
198
206
  end
199
207
 
200
208
  def previous_signature_for(signature)
201
- synchronize_request_response do
202
- return nil unless index = webmock_request_signatures.index(signature)
203
- webmock_request_signatures.delete_at(index)
204
- end
209
+ return nil unless index = webmock_request_signatures.index(signature)
210
+ webmock_request_signatures.delete_at(index)
205
211
  end
206
212
 
207
213
  private
@@ -217,14 +223,9 @@ if defined?(::HTTPClient)
217
223
  end
218
224
  end
219
225
 
220
- def synchronize_request_response
221
- if REQUEST_RESPONSE_LOCK.owned?
222
- yield
223
- else
224
- REQUEST_RESPONSE_LOCK.synchronize do
225
- yield
226
- end
227
- end
226
+ def clear_thread_variables
227
+ Thread.current[WEBMOCK_HTTPCLIENT_REQUEST_SIGNATURES] = nil
228
+ Thread.current[WEBMOCK_HTTPCLIENT_RESPONSES] = nil
228
229
  end
229
230
  end
230
231
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  require 'manticore'
3
5
  rescue LoadError
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'net/http'
2
4
  require 'net/https'
3
5
  require 'stringio'
@@ -10,24 +12,25 @@ module WebMock
10
12
  adapter_for :net_http
11
13
 
12
14
  OriginalNetHTTP = Net::HTTP unless const_defined?(:OriginalNetHTTP)
13
- OriginalNetBufferedIO = Net::BufferedIO unless const_defined?(:OriginalNetBufferedIO)
15
+ # This will be removed in Ruby 3.5. In Ruby 3.4, const_remove will warn.
16
+ HAS_LEGACY_CONSTANT = Net.const_defined?(:HTTPSession)
14
17
 
15
18
  def self.enable!
16
- Net.send(:remove_const, :BufferedIO)
17
19
  Net.send(:remove_const, :HTTP)
18
- Net.send(:remove_const, :HTTPSession)
19
20
  Net.send(:const_set, :HTTP, @webMockNetHTTP)
20
- Net.send(:const_set, :HTTPSession, @webMockNetHTTP)
21
- Net.send(:const_set, :BufferedIO, Net::WebMockNetBufferedIO)
21
+ if HAS_LEGACY_CONSTANT
22
+ remove_silently(Net, :HTTPSession)
23
+ Net.send(:const_set, :HTTPSession, @webMockNetHTTP)
24
+ end
22
25
  end
23
26
 
24
27
  def self.disable!
25
- Net.send(:remove_const, :BufferedIO)
26
28
  Net.send(:remove_const, :HTTP)
27
- Net.send(:remove_const, :HTTPSession)
28
29
  Net.send(:const_set, :HTTP, OriginalNetHTTP)
29
- Net.send(:const_set, :HTTPSession, OriginalNetHTTP)
30
- Net.send(:const_set, :BufferedIO, OriginalNetBufferedIO)
30
+ if HAS_LEGACY_CONSTANT
31
+ remove_silently(Net, :HTTPSession)
32
+ Net.send(:const_set, :HTTPSession, OriginalNetHTTP)
33
+ end
31
34
 
32
35
  #copy all constants from @webMockNetHTTP to original Net::HTTP
33
36
  #in case any constants were added to @webMockNetHTTP instead of Net::HTTP
@@ -40,6 +43,14 @@ module WebMock
40
43
  end
41
44
  end
42
45
 
46
+ def self.remove_silently(mod, const) #:nodoc:
47
+ # Don't warn on removing the deprecated constant
48
+ verbose, $VERBOSE = $VERBOSE, nil
49
+ mod.send(:remove_const, const)
50
+ ensure
51
+ $VERBOSE = verbose
52
+ end
53
+
43
54
  @webMockNetHTTP = Class.new(Net::HTTP) do
44
55
  class << self
45
56
  def socket_type
@@ -80,7 +91,7 @@ module WebMock
80
91
  @socket = Net::HTTP.socket_type.new
81
92
  WebMock::CallbackRegistry.invoke_callbacks(
82
93
  {lib: :net_http}, request_signature, webmock_response)
83
- build_net_http_response(webmock_response, &block)
94
+ build_net_http_response(webmock_response, request.uri, &block)
84
95
  elsif WebMock.net_connect_allowed?(request_signature.uri)
85
96
  check_right_http_connection
86
97
  after_request = lambda do |response|
@@ -98,13 +109,8 @@ module WebMock
98
109
  after_request.call(response)
99
110
  }
100
111
  if started?
101
- if WebMock::Config.instance.net_http_connect_on_start
102
- super_with_after_request.call
103
- else
104
- start_with_connect_without_finish {
105
- super_with_after_request.call
106
- }
107
- end
112
+ ensure_actual_connection
113
+ super_with_after_request.call
108
114
  else
109
115
  start_with_connect {
110
116
  super_with_after_request.call
@@ -119,39 +125,40 @@ module WebMock
119
125
  raise IOError, 'HTTP session already opened' if @started
120
126
  if block_given?
121
127
  begin
128
+ @socket = Net::HTTP.socket_type.new
122
129
  @started = true
123
130
  return yield(self)
124
131
  ensure
125
132
  do_finish
126
133
  end
127
134
  end
135
+ @socket = Net::HTTP.socket_type.new
128
136
  @started = true
129
137
  self
130
138
  end
131
139
 
132
140
 
133
- def start_with_connect_without_finish # :yield: http
134
- if block_given?
135
- begin
136
- do_start
137
- return yield(self)
138
- end
141
+ def ensure_actual_connection
142
+ if @socket.is_a?(StubSocket)
143
+ @socket&.close
144
+ @socket = nil
145
+ do_start
139
146
  end
140
- do_start
141
- self
142
147
  end
143
148
 
144
149
  alias_method :start_with_connect, :start
145
150
 
146
151
  def start(&block)
147
- if WebMock::Config.instance.net_http_connect_on_start
152
+ uri = Addressable::URI.parse(WebMock::NetHTTPUtility.get_uri(self))
153
+
154
+ if WebMock.net_http_connect_on_start?(uri)
148
155
  super(&block)
149
156
  else
150
157
  start_without_connect(&block)
151
158
  end
152
159
  end
153
160
 
154
- def build_net_http_response(webmock_response, &block)
161
+ def build_net_http_response(webmock_response, request_uri, &block)
155
162
  response = Net::HTTPResponse.send(:response_class, webmock_response.status[0].to_s).new("1.0", webmock_response.status[0].to_s, webmock_response.status[1])
156
163
  body = webmock_response.body
157
164
  body = nil if webmock_response.status[0].to_s == '204'
@@ -166,10 +173,12 @@ module WebMock
166
173
 
167
174
  response.instance_variable_set(:@read, true)
168
175
 
176
+ response.uri = request_uri
177
+
169
178
  response.extend Net::WebMockHTTPResponse
170
179
 
171
180
  if webmock_response.should_timeout
172
- raise timeout_exception, "execution expired"
181
+ raise Net::OpenTimeout, "execution expired"
173
182
  end
174
183
 
175
184
  webmock_response.raise_error_if_any
@@ -179,16 +188,6 @@ module WebMock
179
188
  response
180
189
  end
181
190
 
182
- def timeout_exception
183
- if defined?(Net::OpenTimeout)
184
- # Ruby 2.x
185
- Net::OpenTimeout
186
- else
187
- # Fallback, if things change
188
- Timeout::Error
189
- end
190
- end
191
-
192
191
  def build_webmock_response(net_http_response)
193
192
  webmock_response = WebMock::Response.new
194
193
  webmock_response.status = [
@@ -222,31 +221,21 @@ module WebMock
222
221
  end
223
222
  end
224
223
 
225
- # patch for StringIO behavior in Ruby 2.2.3
226
- # https://github.com/bblimke/webmock/issues/558
227
- class PatchedStringIO < StringIO #:nodoc:
228
-
229
- alias_method :orig_read_nonblock, :read_nonblock
230
-
231
- def read_nonblock(size, *args, **kwargs)
232
- args.reject! {|arg| !arg.is_a?(Hash)}
233
- orig_read_nonblock(size, *args, **kwargs)
234
- end
235
-
236
- end
237
-
238
224
  class StubSocket #:nodoc:
239
225
 
240
226
  attr_accessor :read_timeout, :continue_timeout, :write_timeout
241
227
 
242
228
  def initialize(*args)
229
+ @closed = false
243
230
  end
244
231
 
245
232
  def closed?
246
- @closed ||= true
233
+ @closed
247
234
  end
248
235
 
249
236
  def close
237
+ @closed = true
238
+ nil
250
239
  end
251
240
 
252
241
  def readuntil(*args)
@@ -258,57 +247,13 @@ class StubSocket #:nodoc:
258
247
 
259
248
  class StubIO
260
249
  def setsockopt(*args); end
250
+ def peer_cert; end
251
+ def peeraddr; ["AF_INET", 443, "127.0.0.1", "127.0.0.1"] end
252
+ def ssl_version; "TLSv1.3" end
253
+ def cipher; ["TLS_AES_128_GCM_SHA256", "TLSv1.3", 128, 128] end
261
254
  end
262
255
  end
263
256
 
264
- module Net #:nodoc: all
265
-
266
- class WebMockNetBufferedIO < BufferedIO
267
- def initialize(io, *args, **kwargs)
268
- io = case io
269
- when Socket, OpenSSL::SSL::SSLSocket, IO
270
- io
271
- when StringIO
272
- PatchedStringIO.new(io.string)
273
- when String
274
- PatchedStringIO.new(io)
275
- end
276
- raise "Unable to create local socket" unless io
277
-
278
- # Prior to 2.4.0 `BufferedIO` only takes a single argument (`io`) with no
279
- # options. Here we pass through our full set of arguments only if we're
280
- # on 2.4.0 or later, and use a simplified invocation otherwise.
281
- if RUBY_VERSION >= '2.4.0'
282
- super
283
- else
284
- super(io)
285
- end
286
- end
287
-
288
- if RUBY_VERSION >= '2.6.0'
289
- # https://github.com/ruby/ruby/blob/7d02441f0d6e5c9d0a73a024519eba4f69e36dce/lib/net/protocol.rb#L208
290
- # Modified version of method from ruby, so that nil is always passed into orig_read_nonblock to avoid timeout
291
- def rbuf_fill
292
- case rv = @io.read_nonblock(BUFSIZE, nil, exception: false)
293
- when String
294
- return if rv.nil?
295
- @rbuf << rv
296
- rv.clear
297
- return
298
- when :wait_readable
299
- @io.to_io.wait_readable(@read_timeout) or raise Net::ReadTimeout
300
- when :wait_writable
301
- @io.to_io.wait_writable(@read_timeout) or raise Net::ReadTimeout
302
- when nil
303
- raise EOFError, 'end of file reached'
304
- end while true
305
- end
306
- end
307
- end
308
-
309
- end
310
-
311
-
312
257
  module WebMock
313
258
  module NetHTTPUtility
314
259
 
@@ -325,7 +270,6 @@ module WebMock
325
270
  method = request.method.downcase.to_sym
326
271
 
327
272
  headers = Hash[*request.to_hash.map {|k,v| [k, v]}.inject([]) {|r,x| r + x}]
328
- validate_headers(headers)
329
273
 
330
274
  if request.body_stream
331
275
  body = request.body_stream.read
@@ -341,7 +285,7 @@ module WebMock
341
285
  WebMock::RequestSignature.new(method, uri, body: request.body, headers: headers)
342
286
  end
343
287
 
344
- def self.get_uri(net_http, path)
288
+ def self.get_uri(net_http, path = nil)
345
289
  protocol = net_http.use_ssl? ? "https" : "http"
346
290
 
347
291
  hostname = net_http.address
@@ -350,25 +294,6 @@ module WebMock
350
294
  "#{protocol}://#{hostname}:#{net_http.port}#{path}"
351
295
  end
352
296
 
353
- def self.validate_headers(headers)
354
- # For Ruby versions < 2.3.0, if you make a request with headers that are symbols
355
- # Net::HTTP raises a NoMethodError
356
- #
357
- # WebMock normalizes headers when creating a RequestSignature,
358
- # and will update all headers from symbols to strings.
359
- #
360
- # This could create a false positive in a test suite with WebMock.
361
- #
362
- # So before this point, WebMock raises an ArgumentError if any of the headers are symbols
363
- # instead of the cryptic NoMethodError "undefined method `split' ...` from Net::HTTP
364
- if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.3.0')
365
- header_as_symbol = headers.keys.find {|header| header.is_a? Symbol}
366
- if header_as_symbol
367
- raise ArgumentError.new("Net:HTTP does not accept headers as symbols")
368
- end
369
- end
370
- end
371
-
372
297
  def self.check_right_http_connection
373
298
  @was_right_http_connection_loaded = defined?(RightHttpConnection)
374
299
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This code is entierly copied from VCR (http://github.com/myronmarston/vcr) by courtesy of Myron Marston
2
4
 
3
5
  # A Net::HTTP response that has already been read raises an IOError when #read_body
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  require 'patron'
3
5
  rescue LoadError
4
6
  # patron not found
5
7
  end
6
8
 
7
- if defined?(::Patron)
9
+ if defined?(::Patron::Session)
8
10
  module WebMock
9
11
  module HttpLibAdapters
10
12
  class PatronAdapter < ::WebMock::HttpLibAdapter
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  require 'typhoeus'
3
5
  rescue LoadError
@@ -94,7 +96,14 @@ if defined?(Typhoeus)
94
96
  status_message: "",
95
97
  body: "",
96
98
  headers: {},
97
- return_code: :operation_timedout
99
+ return_code: :operation_timedout,
100
+ total_time: 0.0,
101
+ starttransfer_time: 0.0,
102
+ appconnect_time: 0.0,
103
+ pretransfer_time: 0.0,
104
+ connect_time: 0.0,
105
+ namelookup_time: 0.0,
106
+ redirect_time: 0.0
98
107
  )
99
108
  else
100
109
  ::Typhoeus::Response.new(
@@ -102,7 +111,14 @@ if defined?(Typhoeus)
102
111
  status_message: webmock_response.status[1],
103
112
  body: webmock_response.body,
104
113
  headers: webmock_response.headers,
105
- effective_url: request_signature.uri
114
+ effective_url: request_signature.uri,
115
+ total_time: 0.0,
116
+ starttransfer_time: 0.0,
117
+ appconnect_time: 0.0,
118
+ pretransfer_time: 0.0,
119
+ connect_time: 0.0,
120
+ namelookup_time: 0.0,
121
+ redirect_time: 0.0
106
122
  )
107
123
  end
108
124
  response.mock = :webmock
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
  module Matchers
3
5
  # this is a based on RSpec::Mocks::ArgumentMatchers::AnyArgMatcher
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
  module Matchers
3
5
  # Base class for Hash matchers
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
  module Matchers
3
5
  # this is a based on RSpec::Mocks::ArgumentMatchers::HashExcludingMatcher
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
  module Matchers
3
5
  # this is a based on RSpec::Mocks::ArgumentMatchers::HashIncludingMatcher
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  require 'minitest/test'
3
5
  test_class = Minitest::Test