webmock 3.14.0 → 3.24.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 +4 -4
- data/CHANGELOG.md +207 -3
- data/README.md +65 -20
- data/lib/webmock/api.rb +2 -0
- data/lib/webmock/assertion_failure.rb +2 -0
- data/lib/webmock/callback_registry.rb +2 -0
- data/lib/webmock/config.rb +2 -0
- data/lib/webmock/cucumber.rb +2 -0
- data/lib/webmock/deprecation.rb +2 -0
- data/lib/webmock/errors.rb +2 -0
- data/lib/webmock/http_lib_adapters/async_http_client_adapter.rb +16 -4
- data/lib/webmock/http_lib_adapters/curb_adapter.rb +4 -2
- data/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +17 -7
- data/lib/webmock/http_lib_adapters/excon_adapter.rb +2 -0
- data/lib/webmock/http_lib_adapters/http_lib_adapter.rb +2 -0
- data/lib/webmock/http_lib_adapters/http_lib_adapter_registry.rb +2 -0
- data/lib/webmock/http_lib_adapters/http_rb/client.rb +3 -3
- data/lib/webmock/http_lib_adapters/http_rb/request.rb +17 -5
- data/lib/webmock/http_lib_adapters/http_rb/response.rb +32 -9
- data/lib/webmock/http_lib_adapters/http_rb/streamer.rb +10 -2
- data/lib/webmock/http_lib_adapters/http_rb/webmock.rb +8 -2
- data/lib/webmock/http_lib_adapters/http_rb_adapter.rb +7 -5
- data/lib/webmock/http_lib_adapters/httpclient_adapter.rb +26 -25
- data/lib/webmock/http_lib_adapters/manticore_adapter.rb +2 -0
- data/lib/webmock/http_lib_adapters/net_http.rb +28 -117
- data/lib/webmock/http_lib_adapters/net_http_response.rb +2 -0
- data/lib/webmock/http_lib_adapters/patron_adapter.rb +3 -1
- data/lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb +18 -2
- data/lib/webmock/matchers/any_arg_matcher.rb +2 -0
- data/lib/webmock/matchers/hash_argument_matcher.rb +2 -0
- data/lib/webmock/matchers/hash_excluding_matcher.rb +2 -0
- data/lib/webmock/matchers/hash_including_matcher.rb +2 -0
- data/lib/webmock/minitest.rb +2 -0
- data/lib/webmock/rack_response.rb +5 -1
- data/lib/webmock/request_body_diff.rb +2 -0
- data/lib/webmock/request_execution_verifier.rb +2 -0
- data/lib/webmock/request_pattern.rb +35 -12
- data/lib/webmock/request_registry.rb +2 -0
- data/lib/webmock/request_signature.rb +4 -2
- data/lib/webmock/request_signature_snippet.rb +2 -0
- data/lib/webmock/request_stub.rb +34 -0
- data/lib/webmock/response.rb +15 -13
- data/lib/webmock/responses_sequence.rb +2 -0
- data/lib/webmock/rspec/matchers/request_pattern_matcher.rb +2 -0
- data/lib/webmock/rspec/matchers/webmock_matcher.rb +2 -0
- data/lib/webmock/rspec/matchers.rb +2 -0
- data/lib/webmock/rspec.rb +2 -0
- data/lib/webmock/stub_registry.rb +2 -0
- data/lib/webmock/stub_request_snippet.rb +2 -0
- data/lib/webmock/test_unit.rb +2 -0
- data/lib/webmock/util/hash_counter.rb +12 -6
- data/lib/webmock/util/hash_keys_stringifier.rb +2 -0
- data/lib/webmock/util/hash_validator.rb +2 -0
- data/lib/webmock/util/headers.rb +23 -10
- data/lib/webmock/util/parsers/json.rb +72 -0
- data/lib/webmock/util/parsers/parse_error.rb +7 -0
- data/lib/webmock/util/parsers/xml.rb +16 -0
- data/lib/webmock/util/query_mapper.rb +2 -0
- data/lib/webmock/util/uri.rb +3 -1
- data/lib/webmock/util/values_stringifier.rb +2 -0
- data/lib/webmock/util/version_checker.rb +7 -5
- data/lib/webmock/version.rb +3 -1
- data/lib/webmock/webmock.rb +12 -0
- data/lib/webmock.rb +4 -2
- metadata +66 -182
- data/.gemtest +0 -0
- data/.github/workflows/CI.yml +0 -37
- data/.gitignore +0 -34
- data/.rspec-tm +0 -2
- data/Gemfile +0 -9
- data/Rakefile +0 -38
- data/lib/webmock/util/json.rb +0 -67
- data/minitest/test_helper.rb +0 -34
- data/minitest/test_webmock.rb +0 -9
- data/minitest/webmock_spec.rb +0 -60
- data/spec/acceptance/async_http_client/async_http_client_spec.rb +0 -375
- data/spec/acceptance/async_http_client/async_http_client_spec_helper.rb +0 -73
- data/spec/acceptance/curb/curb_spec.rb +0 -499
- data/spec/acceptance/curb/curb_spec_helper.rb +0 -147
- data/spec/acceptance/em_http_request/em_http_request_spec.rb +0 -462
- data/spec/acceptance/em_http_request/em_http_request_spec_helper.rb +0 -77
- data/spec/acceptance/excon/excon_spec.rb +0 -77
- data/spec/acceptance/excon/excon_spec_helper.rb +0 -52
- data/spec/acceptance/http_rb/http_rb_spec.rb +0 -93
- data/spec/acceptance/http_rb/http_rb_spec_helper.rb +0 -54
- data/spec/acceptance/httpclient/httpclient_spec.rb +0 -217
- data/spec/acceptance/httpclient/httpclient_spec_helper.rb +0 -57
- data/spec/acceptance/manticore/manticore_spec.rb +0 -107
- data/spec/acceptance/manticore/manticore_spec_helper.rb +0 -35
- data/spec/acceptance/net_http/net_http_shared.rb +0 -153
- data/spec/acceptance/net_http/net_http_spec.rb +0 -369
- data/spec/acceptance/net_http/net_http_spec_helper.rb +0 -64
- data/spec/acceptance/net_http/real_net_http_spec.rb +0 -20
- data/spec/acceptance/patron/patron_spec.rb +0 -125
- data/spec/acceptance/patron/patron_spec_helper.rb +0 -54
- data/spec/acceptance/shared/allowing_and_disabling_net_connect.rb +0 -313
- data/spec/acceptance/shared/callbacks.rb +0 -148
- data/spec/acceptance/shared/complex_cross_concern_behaviors.rb +0 -36
- data/spec/acceptance/shared/enabling_and_disabling_webmock.rb +0 -95
- data/spec/acceptance/shared/precedence_of_stubs.rb +0 -15
- data/spec/acceptance/shared/request_expectations.rb +0 -930
- data/spec/acceptance/shared/returning_declared_responses.rb +0 -409
- data/spec/acceptance/shared/stubbing_requests.rb +0 -678
- data/spec/acceptance/typhoeus/typhoeus_hydra_spec.rb +0 -135
- data/spec/acceptance/typhoeus/typhoeus_hydra_spec_helper.rb +0 -60
- data/spec/acceptance/webmock_shared.rb +0 -41
- data/spec/fixtures/test.txt +0 -1
- data/spec/quality_spec.rb +0 -84
- data/spec/spec_helper.rb +0 -48
- data/spec/support/example_curl_output.txt +0 -22
- data/spec/support/failures.rb +0 -9
- data/spec/support/my_rack_app.rb +0 -53
- data/spec/support/network_connection.rb +0 -19
- data/spec/support/webmock_server.rb +0 -70
- data/spec/unit/api_spec.rb +0 -175
- data/spec/unit/errors_spec.rb +0 -129
- data/spec/unit/http_lib_adapters/http_lib_adapter_registry_spec.rb +0 -17
- data/spec/unit/http_lib_adapters/http_lib_adapter_spec.rb +0 -12
- data/spec/unit/matchers/hash_excluding_matcher_spec.rb +0 -61
- data/spec/unit/matchers/hash_including_matcher_spec.rb +0 -87
- data/spec/unit/rack_response_spec.rb +0 -112
- data/spec/unit/request_body_diff_spec.rb +0 -90
- data/spec/unit/request_execution_verifier_spec.rb +0 -208
- data/spec/unit/request_pattern_spec.rb +0 -736
- data/spec/unit/request_registry_spec.rb +0 -95
- data/spec/unit/request_signature_snippet_spec.rb +0 -89
- data/spec/unit/request_signature_spec.rb +0 -155
- data/spec/unit/request_stub_spec.rb +0 -199
- data/spec/unit/response_spec.rb +0 -286
- data/spec/unit/stub_registry_spec.rb +0 -103
- data/spec/unit/stub_request_snippet_spec.rb +0 -115
- data/spec/unit/util/hash_counter_spec.rb +0 -39
- data/spec/unit/util/hash_keys_stringifier_spec.rb +0 -27
- data/spec/unit/util/headers_spec.rb +0 -28
- data/spec/unit/util/json_spec.rb +0 -33
- data/spec/unit/util/query_mapper_spec.rb +0 -157
- data/spec/unit/util/uri_spec.rb +0 -371
- data/spec/unit/util/version_checker_spec.rb +0 -65
- data/spec/unit/webmock_spec.rb +0 -60
- data/test/http_request.rb +0 -24
- data/test/shared_test.rb +0 -108
- data/test/test_helper.rb +0 -23
- data/test/test_webmock.rb +0 -12
- 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
|
-
|
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 =
|
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
|
-
|
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
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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 =
|
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
|
-
|
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
|
-
|
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
|
-
|
190
|
-
|
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
|
-
|
205
|
+
Thread.current[WEBMOCK_HTTPCLIENT_REQUEST_SIGNATURES] ||= []
|
198
206
|
end
|
199
207
|
|
200
208
|
def previous_signature_for(signature)
|
201
|
-
|
202
|
-
|
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
|
221
|
-
|
222
|
-
|
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
|
require 'net/http'
|
2
4
|
require 'net/https'
|
3
5
|
require 'stringio'
|
@@ -10,24 +12,19 @@ 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)
|
14
15
|
|
15
16
|
def self.enable!
|
16
|
-
Net.send(:remove_const, :BufferedIO)
|
17
17
|
Net.send(:remove_const, :HTTP)
|
18
18
|
Net.send(:remove_const, :HTTPSession)
|
19
19
|
Net.send(:const_set, :HTTP, @webMockNetHTTP)
|
20
20
|
Net.send(:const_set, :HTTPSession, @webMockNetHTTP)
|
21
|
-
Net.send(:const_set, :BufferedIO, Net::WebMockNetBufferedIO)
|
22
21
|
end
|
23
22
|
|
24
23
|
def self.disable!
|
25
|
-
Net.send(:remove_const, :BufferedIO)
|
26
24
|
Net.send(:remove_const, :HTTP)
|
27
25
|
Net.send(:remove_const, :HTTPSession)
|
28
26
|
Net.send(:const_set, :HTTP, OriginalNetHTTP)
|
29
27
|
Net.send(:const_set, :HTTPSession, OriginalNetHTTP)
|
30
|
-
Net.send(:const_set, :BufferedIO, OriginalNetBufferedIO)
|
31
28
|
|
32
29
|
#copy all constants from @webMockNetHTTP to original Net::HTTP
|
33
30
|
#in case any constants were added to @webMockNetHTTP instead of Net::HTTP
|
@@ -80,7 +77,7 @@ module WebMock
|
|
80
77
|
@socket = Net::HTTP.socket_type.new
|
81
78
|
WebMock::CallbackRegistry.invoke_callbacks(
|
82
79
|
{lib: :net_http}, request_signature, webmock_response)
|
83
|
-
build_net_http_response(webmock_response, &block)
|
80
|
+
build_net_http_response(webmock_response, request.uri, &block)
|
84
81
|
elsif WebMock.net_connect_allowed?(request_signature.uri)
|
85
82
|
check_right_http_connection
|
86
83
|
after_request = lambda do |response|
|
@@ -98,13 +95,8 @@ module WebMock
|
|
98
95
|
after_request.call(response)
|
99
96
|
}
|
100
97
|
if started?
|
101
|
-
|
102
|
-
|
103
|
-
else
|
104
|
-
start_with_connect_without_finish {
|
105
|
-
super_with_after_request.call
|
106
|
-
}
|
107
|
-
end
|
98
|
+
ensure_actual_connection
|
99
|
+
super_with_after_request.call
|
108
100
|
else
|
109
101
|
start_with_connect {
|
110
102
|
super_with_after_request.call
|
@@ -119,39 +111,40 @@ module WebMock
|
|
119
111
|
raise IOError, 'HTTP session already opened' if @started
|
120
112
|
if block_given?
|
121
113
|
begin
|
114
|
+
@socket = Net::HTTP.socket_type.new
|
122
115
|
@started = true
|
123
116
|
return yield(self)
|
124
117
|
ensure
|
125
118
|
do_finish
|
126
119
|
end
|
127
120
|
end
|
121
|
+
@socket = Net::HTTP.socket_type.new
|
128
122
|
@started = true
|
129
123
|
self
|
130
124
|
end
|
131
125
|
|
132
126
|
|
133
|
-
def
|
134
|
-
if
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
end
|
127
|
+
def ensure_actual_connection
|
128
|
+
if @socket.is_a?(StubSocket)
|
129
|
+
@socket&.close
|
130
|
+
@socket = nil
|
131
|
+
do_start
|
139
132
|
end
|
140
|
-
do_start
|
141
|
-
self
|
142
133
|
end
|
143
134
|
|
144
135
|
alias_method :start_with_connect, :start
|
145
136
|
|
146
137
|
def start(&block)
|
147
|
-
|
138
|
+
uri = Addressable::URI.parse(WebMock::NetHTTPUtility.get_uri(self))
|
139
|
+
|
140
|
+
if WebMock.net_http_connect_on_start?(uri)
|
148
141
|
super(&block)
|
149
142
|
else
|
150
143
|
start_without_connect(&block)
|
151
144
|
end
|
152
145
|
end
|
153
146
|
|
154
|
-
def build_net_http_response(webmock_response, &block)
|
147
|
+
def build_net_http_response(webmock_response, request_uri, &block)
|
155
148
|
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
149
|
body = webmock_response.body
|
157
150
|
body = nil if webmock_response.status[0].to_s == '204'
|
@@ -166,10 +159,12 @@ module WebMock
|
|
166
159
|
|
167
160
|
response.instance_variable_set(:@read, true)
|
168
161
|
|
162
|
+
response.uri = request_uri
|
163
|
+
|
169
164
|
response.extend Net::WebMockHTTPResponse
|
170
165
|
|
171
166
|
if webmock_response.should_timeout
|
172
|
-
raise
|
167
|
+
raise Net::OpenTimeout, "execution expired"
|
173
168
|
end
|
174
169
|
|
175
170
|
webmock_response.raise_error_if_any
|
@@ -179,16 +174,6 @@ module WebMock
|
|
179
174
|
response
|
180
175
|
end
|
181
176
|
|
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
177
|
def build_webmock_response(net_http_response)
|
193
178
|
webmock_response = WebMock::Response.new
|
194
179
|
webmock_response.status = [
|
@@ -222,31 +207,21 @@ module WebMock
|
|
222
207
|
end
|
223
208
|
end
|
224
209
|
|
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
210
|
class StubSocket #:nodoc:
|
239
211
|
|
240
212
|
attr_accessor :read_timeout, :continue_timeout, :write_timeout
|
241
213
|
|
242
214
|
def initialize(*args)
|
215
|
+
@closed = false
|
243
216
|
end
|
244
217
|
|
245
218
|
def closed?
|
246
|
-
@closed
|
219
|
+
@closed
|
247
220
|
end
|
248
221
|
|
249
222
|
def close
|
223
|
+
@closed = true
|
224
|
+
nil
|
250
225
|
end
|
251
226
|
|
252
227
|
def readuntil(*args)
|
@@ -258,57 +233,13 @@ class StubSocket #:nodoc:
|
|
258
233
|
|
259
234
|
class StubIO
|
260
235
|
def setsockopt(*args); end
|
236
|
+
def peer_cert; end
|
237
|
+
def peeraddr; ["AF_INET", 443, "127.0.0.1", "127.0.0.1"] end
|
238
|
+
def ssl_version; "TLSv1.3" end
|
239
|
+
def cipher; ["TLS_AES_128_GCM_SHA256", "TLSv1.3", 128, 128] end
|
261
240
|
end
|
262
241
|
end
|
263
242
|
|
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
243
|
module WebMock
|
313
244
|
module NetHTTPUtility
|
314
245
|
|
@@ -325,7 +256,6 @@ module WebMock
|
|
325
256
|
method = request.method.downcase.to_sym
|
326
257
|
|
327
258
|
headers = Hash[*request.to_hash.map {|k,v| [k, v]}.inject([]) {|r,x| r + x}]
|
328
|
-
validate_headers(headers)
|
329
259
|
|
330
260
|
if request.body_stream
|
331
261
|
body = request.body_stream.read
|
@@ -341,7 +271,7 @@ module WebMock
|
|
341
271
|
WebMock::RequestSignature.new(method, uri, body: request.body, headers: headers)
|
342
272
|
end
|
343
273
|
|
344
|
-
def self.get_uri(net_http, path)
|
274
|
+
def self.get_uri(net_http, path = nil)
|
345
275
|
protocol = net_http.use_ssl? ? "https" : "http"
|
346
276
|
|
347
277
|
hostname = net_http.address
|
@@ -350,25 +280,6 @@ module WebMock
|
|
350
280
|
"#{protocol}://#{hostname}:#{net_http.port}#{path}"
|
351
281
|
end
|
352
282
|
|
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
283
|
def self.check_right_http_connection
|
373
284
|
@was_right_http_connection_loaded = defined?(RightHttpConnection)
|
374
285
|
end
|
@@ -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
|
data/lib/webmock/minitest.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module WebMock
|
2
4
|
class RackResponse < Response
|
3
5
|
def initialize(app)
|
@@ -45,7 +47,9 @@ module WebMock
|
|
45
47
|
# Rack-specific variables
|
46
48
|
env['rack.input'] = StringIO.new(body)
|
47
49
|
env['rack.errors'] = $stderr
|
48
|
-
|
50
|
+
if !Rack.const_defined?(:RELEASE) || Rack::RELEASE < "3"
|
51
|
+
env['rack.version'] = Rack::VERSION
|
52
|
+
end
|
49
53
|
env['rack.url_scheme'] = uri.scheme
|
50
54
|
env['rack.run_once'] = true
|
51
55
|
env['rack.session'] = session
|