webmock 3.14.0 → 3.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/CI.yml +1 -0
- data/CHANGELOG.md +86 -2
- data/README.md +12 -3
- data/lib/webmock/http_lib_adapters/async_http_client_adapter.rb +6 -1
- data/lib/webmock/http_lib_adapters/curb_adapter.rb +2 -2
- data/lib/webmock/http_lib_adapters/http_rb/client.rb +1 -3
- data/lib/webmock/http_lib_adapters/http_rb/response.rb +4 -1
- data/lib/webmock/http_lib_adapters/http_rb/streamer.rb +4 -2
- data/lib/webmock/http_lib_adapters/http_rb/webmock.rb +6 -2
- data/lib/webmock/http_lib_adapters/net_http.rb +22 -115
- data/lib/webmock/request_pattern.rb +23 -7
- data/lib/webmock/request_signature.rb +2 -2
- data/lib/webmock/request_stub.rb +15 -0
- data/lib/webmock/response.rb +8 -8
- data/lib/webmock/version.rb +1 -1
- data/lib/webmock/webmock.rb +10 -0
- data/minitest/webmock_spec.rb +1 -1
- data/spec/acceptance/async_http_client/async_http_client_spec.rb +5 -5
- data/spec/acceptance/curb/curb_spec.rb +11 -0
- data/spec/acceptance/em_http_request/em_http_request_spec.rb +1 -1
- data/spec/acceptance/em_http_request/em_http_request_spec_helper.rb +1 -1
- data/spec/acceptance/excon/excon_spec.rb +2 -2
- data/spec/acceptance/net_http/net_http_shared.rb +46 -9
- data/spec/acceptance/net_http/net_http_spec.rb +49 -23
- data/spec/acceptance/net_http/real_net_http_spec.rb +1 -1
- data/spec/acceptance/patron/patron_spec.rb +19 -21
- data/spec/acceptance/shared/allowing_and_disabling_net_connect.rb +14 -14
- data/spec/acceptance/shared/callbacks.rb +2 -2
- data/spec/acceptance/shared/complex_cross_concern_behaviors.rb +1 -1
- data/spec/unit/request_pattern_spec.rb +12 -0
- data/spec/unit/request_signature_spec.rb +21 -1
- data/spec/unit/request_stub_spec.rb +35 -0
- data/spec/unit/response_spec.rb +29 -1
- data/spec/unit/webmock_spec.rb +54 -0
- data/webmock.gemspec +4 -4
- metadata +29 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a7e964f28dd42787fd854c5fcc87dba4cd61ef214c3dee485d9bd0d71fc1cdd
|
4
|
+
data.tar.gz: f6921a9b14ccd71f18b4674aca8d4d24bf377545a4ef8c56862f95cc56b6e8a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 80e85d1bb83018bdaab80aed649134757ee8ac591b98e9ccf1b6df10c0d8930db167dd5fd3bb039dd56a955d22c0cc6b1a1227bb88e8f3e56d31d0e1c9d7708e
|
7
|
+
data.tar.gz: c67f1f8486d6ee932bd9d01dff2bfcec35d9c3e3ed937e50e1f56d34f664ca11db4c9399c51e82da9316245c1d4727c726b9e307646aef80477764609ecf95ee
|
data/.github/workflows/CI.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,89 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
# 3.18.1
|
4
|
+
|
5
|
+
* Reverted simplified connection handing in Net::HTTP adapter due to https://github.com/bblimke/webmock/issues/999
|
6
|
+
|
7
|
+
# 3.18.0
|
8
|
+
|
9
|
+
* Net::BufferedIO is not replaced anymore.
|
10
|
+
|
11
|
+
Thanks to [Ray Zane](https://github.com/rzane)
|
12
|
+
|
13
|
+
* Simplified connection handing in Net::HTTP adapter.
|
14
|
+
|
15
|
+
Thanks to [Ray Zane](https://github.com/rzane)
|
16
|
+
|
17
|
+
# 3.17.1
|
18
|
+
|
19
|
+
* Fixed Syntax Error
|
20
|
+
|
21
|
+
Thanks to [Mark Spangler](https://github.com/mspangler)
|
22
|
+
|
23
|
+
# 3.17.0
|
24
|
+
|
25
|
+
* Minimum required Ruby version is 2.3
|
26
|
+
|
27
|
+
Thanks to [Go Sueyoshi](https://github.com/sue445)
|
28
|
+
|
29
|
+
* When using Net::HTTP, stubbed socket StubSocket#close and StubSocket#closed? behave more like the real sockets.
|
30
|
+
|
31
|
+
Thanks to [Ray Zane](https://github.com/rzane)
|
32
|
+
|
33
|
+
* Added `peeraddr`, `ssl_version` and `cipher` methods to stubbed sockets used by Net::HTTP.
|
34
|
+
|
35
|
+
Thanks to [Ray Zane](https://github.com/rzane)
|
36
|
+
|
37
|
+
* Added support for matching top-level array in JSON request body.
|
38
|
+
|
39
|
+
E.g.
|
40
|
+
|
41
|
+
````
|
42
|
+
stub_request(:post, 'www.example.com').with(body: [{a: 1}])
|
43
|
+
````
|
44
|
+
|
45
|
+
Thanks to [Cedric Sohrauer](https://github.com/cedrics)
|
46
|
+
|
47
|
+
# 3.16.2
|
48
|
+
|
49
|
+
* Minimum required Ruby version is 2.0.
|
50
|
+
|
51
|
+
# 3.16.0 (yanked)
|
52
|
+
|
53
|
+
* Fix leaky file descriptors and reuse socket for persistent connections.
|
54
|
+
|
55
|
+
Thanks to [Ray Zane](https://github.com/rzane)
|
56
|
+
|
57
|
+
* Allow specifying for what URIs or hosts, Net::HTTP should connect on start.
|
58
|
+
|
59
|
+
Thanks to [Ray Zane](https://github.com/rzane)
|
60
|
+
|
61
|
+
# 3.15.2
|
62
|
+
|
63
|
+
* Minimum required Ruby version is 2.0.
|
64
|
+
|
65
|
+
# 3.15.0 (yanked)
|
66
|
+
|
67
|
+
* fixed async-http adapter on Windows
|
68
|
+
|
69
|
+
Thanks to [Pavel Rosický](https://github.com/ahorek)
|
70
|
+
|
71
|
+
* Support for http.rb >= 5.0.2
|
72
|
+
|
73
|
+
Thanks to [ojab](https://github.com/ojab)
|
74
|
+
|
75
|
+
* Curb adapter supports headers with `:` character in the header value
|
76
|
+
|
77
|
+
Thanks to [Giorgio Gambino](https://github.com/mrbuzz)
|
78
|
+
|
79
|
+
* Support for matching body of JSON or application/x-www-form-urlencoded requests with content type header including charset.
|
80
|
+
|
81
|
+
Thanks to [Timmitry](https://github.com/Timmitry)
|
82
|
+
|
83
|
+
* Prevent double-wrapping http.rb features on non-stubbed requests
|
84
|
+
|
85
|
+
Thanks to [Michael Fairley](https://github.com/michaelfairley)
|
86
|
+
|
3
87
|
# 3.14.0
|
4
88
|
|
5
89
|
* Bump Addressable from 2.3.6 to 2.8.0
|
@@ -605,9 +689,9 @@
|
|
605
689
|
* `WebMock.disable_net_connect` accepts `:allow` option with an object that responds to `#call`, receiving a `URI` object and returning a boolean:
|
606
690
|
|
607
691
|
|
608
|
-
|
692
|
+
denylist = ['google.com', 'facebook.com', 'apple.com']
|
609
693
|
allowed_sites = lambda{|uri|
|
610
|
-
|
694
|
+
denylist.none?{|site| uri.host.include?(site) }
|
611
695
|
}
|
612
696
|
WebMock.disable_net_connect!(:allow => allowed_sites)
|
613
697
|
|
data/README.md
CHANGED
@@ -550,9 +550,9 @@ RestClient.get('sample.org', '/bar') # ===> Failure
|
|
550
550
|
With an object that responds to `#call`, receiving a `URI` object and returning a boolean:
|
551
551
|
|
552
552
|
```ruby
|
553
|
-
|
553
|
+
denylist = ['google.com', 'facebook.com', 'apple.com']
|
554
554
|
allowed_sites = lambda{|uri|
|
555
|
-
|
555
|
+
denylist.none?{|site| uri.host.include?(site) }
|
556
556
|
}
|
557
557
|
WebMock.disable_net_connect!(allow: allowed_sites)
|
558
558
|
|
@@ -1161,13 +1161,22 @@ People who submitted patches and new features or suggested improvements. Many th
|
|
1161
1161
|
* Alex Vondrak
|
1162
1162
|
* Will Storey
|
1163
1163
|
* Eduardo Hernandez
|
1164
|
+
* ojab
|
1165
|
+
* Giorgio Gambino
|
1166
|
+
* Timmitry
|
1167
|
+
* Michael Fairley
|
1168
|
+
* Ray Zane
|
1169
|
+
* Go Sueyoshi
|
1170
|
+
* Cedric Sohrauer
|
1171
|
+
* Akira Matsuda
|
1172
|
+
* Mark Spangler
|
1164
1173
|
|
1165
1174
|
For a full list of contributors you can visit the
|
1166
1175
|
[contributors](https://github.com/bblimke/webmock/contributors) page.
|
1167
1176
|
|
1168
1177
|
## Background
|
1169
1178
|
|
1170
|
-
Thank you Fakeweb! This library was inspired by [FakeWeb](
|
1179
|
+
Thank you Fakeweb! This library was inspired by [FakeWeb](https://github.com/chrisk/fakeweb).
|
1171
1180
|
I imported some solutions from that project to WebMock. I also copied some code i.e Net:HTTP adapter.
|
1172
1181
|
Fakeweb architecture unfortunately didn't allow me to extend it easily with the features I needed.
|
1173
1182
|
I also preferred some things to work differently i.e request stub precedence.
|
@@ -151,7 +151,12 @@ if defined?(Async::HTTP)
|
|
151
151
|
private
|
152
152
|
|
153
153
|
def create_connected_sockets
|
154
|
-
|
154
|
+
pair = begin
|
155
|
+
Async::IO::Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM)
|
156
|
+
rescue Errno::EAFNOSUPPORT
|
157
|
+
Async::IO::Socket.pair(Socket::AF_INET, Socket::SOCK_STREAM)
|
158
|
+
end
|
159
|
+
pair.tap do |sockets|
|
155
160
|
sockets.each do |socket|
|
156
161
|
socket.instance_variable_set :@alpn_protocol, nil
|
157
162
|
socket.instance_eval do
|
@@ -5,7 +5,7 @@ rescue LoadError
|
|
5
5
|
end
|
6
6
|
|
7
7
|
if defined?(Curl)
|
8
|
-
WebMock::VersionChecker.new('Curb', Curl::CURB_VERSION, '0.7.16', '0.
|
8
|
+
WebMock::VersionChecker.new('Curb', Curl::CURB_VERSION, '0.7.16', '1.0.1', ['0.8.7']).check_version!
|
9
9
|
|
10
10
|
module WebMock
|
11
11
|
module HttpLibAdapters
|
@@ -128,7 +128,7 @@ if defined?(Curl)
|
|
128
128
|
def headers_as_hash(headers)
|
129
129
|
if headers.is_a?(Array)
|
130
130
|
headers.inject({}) {|hash, header|
|
131
|
-
name, value = header.split(":").map(&:strip)
|
131
|
+
name, value = header.split(":", 2).map(&:strip)
|
132
132
|
hash[name] = value
|
133
133
|
hash
|
134
134
|
}
|
@@ -5,9 +5,7 @@ module HTTP
|
|
5
5
|
def perform(request, options)
|
6
6
|
return __perform__(request, options) unless webmock_enabled?
|
7
7
|
|
8
|
-
|
9
|
-
options.features.each { |_name, feature| response = feature.wrap_response(response) }
|
10
|
-
response
|
8
|
+
WebMockPerform.new(request, options) { __perform__(request, options) }.exec
|
11
9
|
end
|
12
10
|
|
13
11
|
def webmock_enabled?
|
@@ -24,7 +24,10 @@ module HTTP
|
|
24
24
|
elsif HTTP::VERSION < "3.0.0"
|
25
25
|
Body.new(Streamer.new(webmock_response.body), webmock_response.body.encoding)
|
26
26
|
else
|
27
|
-
Body.new(
|
27
|
+
Body.new(
|
28
|
+
Streamer.new(webmock_response.body, encoding: webmock_response.body.encoding),
|
29
|
+
encoding: webmock_response.body.encoding
|
30
|
+
)
|
28
31
|
end
|
29
32
|
|
30
33
|
return new(status, "1.1", headers, body, uri) if HTTP::VERSION < "1.0.0"
|
@@ -1,8 +1,9 @@
|
|
1
1
|
module HTTP
|
2
2
|
class Response
|
3
3
|
class Streamer
|
4
|
-
def initialize(str)
|
4
|
+
def initialize(str, encoding: Encoding::BINARY)
|
5
5
|
@io = StringIO.new str
|
6
|
+
@encoding = encoding
|
6
7
|
end
|
7
8
|
|
8
9
|
def readpartial(size = nil, outbuf = nil)
|
@@ -14,7 +15,8 @@ module HTTP
|
|
14
15
|
end
|
15
16
|
end
|
16
17
|
|
17
|
-
@io.read size, outbuf
|
18
|
+
chunk = @io.read size, outbuf
|
19
|
+
chunk.force_encoding(@encoding) if chunk
|
18
20
|
end
|
19
21
|
|
20
22
|
def close
|
@@ -1,7 +1,8 @@
|
|
1
1
|
module HTTP
|
2
2
|
class WebMockPerform
|
3
|
-
def initialize(request, &perform)
|
3
|
+
def initialize(request, options, &perform)
|
4
4
|
@request = request
|
5
|
+
@options = options
|
5
6
|
@perform = perform
|
6
7
|
@request_signature = nil
|
7
8
|
end
|
@@ -38,7 +39,10 @@ module HTTP
|
|
38
39
|
webmock_response.raise_error_if_any
|
39
40
|
|
40
41
|
invoke_callbacks(webmock_response, real_request: false)
|
41
|
-
::HTTP::Response.from_webmock @request, webmock_response, request_signature
|
42
|
+
response = ::HTTP::Response.from_webmock @request, webmock_response, request_signature
|
43
|
+
|
44
|
+
@options.features.each { |_name, feature| response = feature.wrap_response(response) }
|
45
|
+
response
|
42
46
|
end
|
43
47
|
|
44
48
|
def raise_timeout_error
|
@@ -10,24 +10,19 @@ module WebMock
|
|
10
10
|
adapter_for :net_http
|
11
11
|
|
12
12
|
OriginalNetHTTP = Net::HTTP unless const_defined?(:OriginalNetHTTP)
|
13
|
-
OriginalNetBufferedIO = Net::BufferedIO unless const_defined?(:OriginalNetBufferedIO)
|
14
13
|
|
15
14
|
def self.enable!
|
16
|
-
Net.send(:remove_const, :BufferedIO)
|
17
15
|
Net.send(:remove_const, :HTTP)
|
18
16
|
Net.send(:remove_const, :HTTPSession)
|
19
17
|
Net.send(:const_set, :HTTP, @webMockNetHTTP)
|
20
18
|
Net.send(:const_set, :HTTPSession, @webMockNetHTTP)
|
21
|
-
Net.send(:const_set, :BufferedIO, Net::WebMockNetBufferedIO)
|
22
19
|
end
|
23
20
|
|
24
21
|
def self.disable!
|
25
|
-
Net.send(:remove_const, :BufferedIO)
|
26
22
|
Net.send(:remove_const, :HTTP)
|
27
23
|
Net.send(:remove_const, :HTTPSession)
|
28
24
|
Net.send(:const_set, :HTTP, OriginalNetHTTP)
|
29
25
|
Net.send(:const_set, :HTTPSession, OriginalNetHTTP)
|
30
|
-
Net.send(:const_set, :BufferedIO, OriginalNetBufferedIO)
|
31
26
|
|
32
27
|
#copy all constants from @webMockNetHTTP to original Net::HTTP
|
33
28
|
#in case any constants were added to @webMockNetHTTP instead of Net::HTTP
|
@@ -98,13 +93,8 @@ module WebMock
|
|
98
93
|
after_request.call(response)
|
99
94
|
}
|
100
95
|
if started?
|
101
|
-
|
102
|
-
|
103
|
-
else
|
104
|
-
start_with_connect_without_finish {
|
105
|
-
super_with_after_request.call
|
106
|
-
}
|
107
|
-
end
|
96
|
+
ensure_actual_connection
|
97
|
+
super_with_after_request.call
|
108
98
|
else
|
109
99
|
start_with_connect {
|
110
100
|
super_with_after_request.call
|
@@ -119,32 +109,33 @@ module WebMock
|
|
119
109
|
raise IOError, 'HTTP session already opened' if @started
|
120
110
|
if block_given?
|
121
111
|
begin
|
112
|
+
@socket = Net::HTTP.socket_type.new
|
122
113
|
@started = true
|
123
114
|
return yield(self)
|
124
115
|
ensure
|
125
116
|
do_finish
|
126
117
|
end
|
127
118
|
end
|
119
|
+
@socket = Net::HTTP.socket_type.new
|
128
120
|
@started = true
|
129
121
|
self
|
130
122
|
end
|
131
123
|
|
132
124
|
|
133
|
-
def
|
134
|
-
if
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
end
|
125
|
+
def ensure_actual_connection
|
126
|
+
if @socket.is_a?(StubSocket)
|
127
|
+
@socket&.close
|
128
|
+
@socket = nil
|
129
|
+
do_start
|
139
130
|
end
|
140
|
-
do_start
|
141
|
-
self
|
142
131
|
end
|
143
132
|
|
144
133
|
alias_method :start_with_connect, :start
|
145
134
|
|
146
135
|
def start(&block)
|
147
|
-
|
136
|
+
uri = Addressable::URI.parse(WebMock::NetHTTPUtility.get_uri(self))
|
137
|
+
|
138
|
+
if WebMock.net_http_connect_on_start?(uri)
|
148
139
|
super(&block)
|
149
140
|
else
|
150
141
|
start_without_connect(&block)
|
@@ -169,7 +160,7 @@ module WebMock
|
|
169
160
|
response.extend Net::WebMockHTTPResponse
|
170
161
|
|
171
162
|
if webmock_response.should_timeout
|
172
|
-
raise
|
163
|
+
raise Net::OpenTimeout, "execution expired"
|
173
164
|
end
|
174
165
|
|
175
166
|
webmock_response.raise_error_if_any
|
@@ -179,16 +170,6 @@ module WebMock
|
|
179
170
|
response
|
180
171
|
end
|
181
172
|
|
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
173
|
def build_webmock_response(net_http_response)
|
193
174
|
webmock_response = WebMock::Response.new
|
194
175
|
webmock_response.status = [
|
@@ -222,31 +203,21 @@ module WebMock
|
|
222
203
|
end
|
223
204
|
end
|
224
205
|
|
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
206
|
class StubSocket #:nodoc:
|
239
207
|
|
240
208
|
attr_accessor :read_timeout, :continue_timeout, :write_timeout
|
241
209
|
|
242
210
|
def initialize(*args)
|
211
|
+
@closed = false
|
243
212
|
end
|
244
213
|
|
245
214
|
def closed?
|
246
|
-
@closed
|
215
|
+
@closed
|
247
216
|
end
|
248
217
|
|
249
218
|
def close
|
219
|
+
@closed = true
|
220
|
+
nil
|
250
221
|
end
|
251
222
|
|
252
223
|
def readuntil(*args)
|
@@ -258,57 +229,13 @@ class StubSocket #:nodoc:
|
|
258
229
|
|
259
230
|
class StubIO
|
260
231
|
def setsockopt(*args); end
|
232
|
+
def peer_cert; end
|
233
|
+
def peeraddr; ["AF_INET", 443, "127.0.0.1", "127.0.0.1"] end
|
234
|
+
def ssl_version; "TLSv1.3" end
|
235
|
+
def cipher; ["TLS_AES_128_GCM_SHA256", "TLSv1.3", 128, 128] end
|
261
236
|
end
|
262
237
|
end
|
263
238
|
|
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
239
|
module WebMock
|
313
240
|
module NetHTTPUtility
|
314
241
|
|
@@ -325,7 +252,6 @@ module WebMock
|
|
325
252
|
method = request.method.downcase.to_sym
|
326
253
|
|
327
254
|
headers = Hash[*request.to_hash.map {|k,v| [k, v]}.inject([]) {|r,x| r + x}]
|
328
|
-
validate_headers(headers)
|
329
255
|
|
330
256
|
if request.body_stream
|
331
257
|
body = request.body_stream.read
|
@@ -341,7 +267,7 @@ module WebMock
|
|
341
267
|
WebMock::RequestSignature.new(method, uri, body: request.body, headers: headers)
|
342
268
|
end
|
343
269
|
|
344
|
-
def self.get_uri(net_http, path)
|
270
|
+
def self.get_uri(net_http, path = nil)
|
345
271
|
protocol = net_http.use_ssl? ? "https" : "http"
|
346
272
|
|
347
273
|
hostname = net_http.address
|
@@ -350,25 +276,6 @@ module WebMock
|
|
350
276
|
"#{protocol}://#{hostname}:#{net_http.port}#{path}"
|
351
277
|
end
|
352
278
|
|
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
279
|
def self.check_right_http_connection
|
373
280
|
@was_right_http_connection_loaded = defined?(RightHttpConnection)
|
374
281
|
end
|
@@ -281,6 +281,8 @@ module WebMock
|
|
281
281
|
if (@pattern).is_a?(Hash)
|
282
282
|
return true if @pattern.empty?
|
283
283
|
matching_body_hashes?(body_as_hash(body, content_type), @pattern, content_type)
|
284
|
+
elsif (@pattern).is_a?(Array)
|
285
|
+
matching_body_array?(body_as_hash(body, content_type), @pattern, content_type)
|
284
286
|
elsif (@pattern).is_a?(WebMock::Matchers::HashIncludingMatcher)
|
285
287
|
@pattern == body_as_hash(body, content_type)
|
286
288
|
else
|
@@ -344,19 +346,33 @@ module WebMock
|
|
344
346
|
def matching_body_hashes?(query_parameters, pattern, content_type)
|
345
347
|
return false unless query_parameters.is_a?(Hash)
|
346
348
|
return false unless query_parameters.keys.sort == pattern.keys.sort
|
347
|
-
|
349
|
+
|
350
|
+
query_parameters.all? do |key, actual|
|
348
351
|
expected = pattern[key]
|
352
|
+
matching_values(actual, expected, content_type)
|
353
|
+
end
|
354
|
+
end
|
349
355
|
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
+
def matching_body_array?(query_parameters, pattern, content_type)
|
357
|
+
return false unless query_parameters.is_a?(Array)
|
358
|
+
return false unless query_parameters.length == pattern.length
|
359
|
+
|
360
|
+
query_parameters.each_with_index do |actual, index|
|
361
|
+
expected = pattern[index]
|
362
|
+
return false unless matching_values(actual, expected, content_type)
|
356
363
|
end
|
364
|
+
|
357
365
|
true
|
358
366
|
end
|
359
367
|
|
368
|
+
def matching_values(actual, expected, content_type)
|
369
|
+
return matching_body_hashes?(actual, expected, content_type) if actual.is_a?(Hash) && expected.is_a?(Hash)
|
370
|
+
return matching_body_array?(actual, expected, content_type) if actual.is_a?(Array) && expected.is_a?(Array)
|
371
|
+
|
372
|
+
expected = WebMock::Util::ValuesStringifier.stringify_values(expected) if url_encoded_body?(content_type)
|
373
|
+
expected === actual
|
374
|
+
end
|
375
|
+
|
360
376
|
def empty_string?(string)
|
361
377
|
string.nil? || string == ""
|
362
378
|
end
|
@@ -35,11 +35,11 @@ module WebMock
|
|
35
35
|
alias == eql?
|
36
36
|
|
37
37
|
def url_encoded?
|
38
|
-
!!(headers
|
38
|
+
!!(headers&.fetch('Content-Type', nil)&.start_with?('application/x-www-form-urlencoded'))
|
39
39
|
end
|
40
40
|
|
41
41
|
def json_headers?
|
42
|
-
!!(headers
|
42
|
+
!!(headers&.fetch('Content-Type', nil)&.start_with?('application/json'))
|
43
43
|
end
|
44
44
|
|
45
45
|
private
|
data/lib/webmock/request_stub.rb
CHANGED
@@ -24,6 +24,21 @@ module WebMock
|
|
24
24
|
end
|
25
25
|
alias_method :and_return, :to_return
|
26
26
|
|
27
|
+
def to_return_json(*response_hashes)
|
28
|
+
raise ArgumentError, '#to_return_json does not support passing a block' if block_given?
|
29
|
+
|
30
|
+
json_response_hashes = [*response_hashes].flatten.map do |resp_h|
|
31
|
+
headers, body = resp_h.values_at(:headers, :body)
|
32
|
+
resp_h.merge(
|
33
|
+
headers: {content_type: 'application/json'}.merge(headers.to_h),
|
34
|
+
body: body.is_a?(Hash) ? body.to_json : body
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
to_return(json_response_hashes)
|
39
|
+
end
|
40
|
+
alias_method :and_return_json, :to_return_json
|
41
|
+
|
27
42
|
def to_rack(app, options={})
|
28
43
|
@responses_sequences << ResponsesSequence.new([RackResponse.new(app)])
|
29
44
|
end
|
data/lib/webmock/response.rb
CHANGED
@@ -14,8 +14,11 @@ module WebMock
|
|
14
14
|
|
15
15
|
class Response
|
16
16
|
def initialize(options = {})
|
17
|
-
|
17
|
+
case options
|
18
|
+
when IO, StringIO
|
18
19
|
self.options = read_raw_response(options)
|
20
|
+
when String
|
21
|
+
self.options = read_raw_response(StringIO.new(options))
|
19
22
|
else
|
20
23
|
self.options = options
|
21
24
|
end
|
@@ -120,13 +123,8 @@ module WebMock
|
|
120
123
|
end
|
121
124
|
end
|
122
125
|
|
123
|
-
def read_raw_response(
|
124
|
-
|
125
|
-
string = raw_response.read
|
126
|
-
raw_response.close
|
127
|
-
raw_response = string
|
128
|
-
end
|
129
|
-
socket = ::Net::BufferedIO.new(raw_response)
|
126
|
+
def read_raw_response(io)
|
127
|
+
socket = ::Net::BufferedIO.new(io)
|
130
128
|
response = ::Net::HTTPResponse.read_new(socket)
|
131
129
|
transfer_encoding = response.delete('transfer-encoding') #chunks were already read by curl
|
132
130
|
response.reading_body(socket, true) {}
|
@@ -138,6 +136,8 @@ module WebMock
|
|
138
136
|
options[:body] = response.read_body
|
139
137
|
options[:status] = [response.code.to_i, response.message]
|
140
138
|
options
|
139
|
+
ensure
|
140
|
+
socket.close
|
141
141
|
end
|
142
142
|
|
143
143
|
InvalidBody = Class.new(StandardError)
|
data/lib/webmock/version.rb
CHANGED
data/lib/webmock/webmock.rb
CHANGED
@@ -70,6 +70,16 @@ module WebMock
|
|
70
70
|
Config.instance.allow && net_connect_explicit_allowed?(Config.instance.allow, uri) )
|
71
71
|
end
|
72
72
|
|
73
|
+
def self.net_http_connect_on_start?(uri)
|
74
|
+
allowed = Config.instance.net_http_connect_on_start || false
|
75
|
+
|
76
|
+
if [true, false].include?(allowed)
|
77
|
+
allowed
|
78
|
+
else
|
79
|
+
net_connect_explicit_allowed?(allowed, uri)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
73
83
|
def self.net_connect_explicit_allowed?(allowed, uri=nil)
|
74
84
|
case allowed
|
75
85
|
when Array
|
data/minitest/webmock_spec.rb
CHANGED
@@ -20,7 +20,7 @@ require File.expand_path(File.dirname(__FILE__) + '/test_helper')
|
|
20
20
|
end
|
21
21
|
|
22
22
|
it "should raise error on non stubbed request" do
|
23
|
-
|
23
|
+
expect { http_request(:get, "http://www.example.net/") }.must_raise(WebMock::NetConnectNotAllowedError)
|
24
24
|
end
|
25
25
|
|
26
26
|
it "should verify that expected request occured" do
|