webmock 3.19.1 → 3.22.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 379567500380d6df66bea0edab72f977ddbcab8fc2cc79f9c2e4c535c46cfeb4
4
- data.tar.gz: fbab14a1e3a2d7a5563f293e735f521dc47481e7d574f4ace0e5cefa9a15fb8e
3
+ metadata.gz: ecff3692887f15d1f0e2e19df92093a40d4f6e5f7e4686d7e18ee4efaadf190f
4
+ data.tar.gz: 6cf4e165350b7878223e28687db13d57df6fe07d90f50a087527d5d001b305e6
5
5
  SHA512:
6
- metadata.gz: 768bc4817766c1b5d2c799c8453bf59411d69f36c4d3b6dfc0630f2a830efa4b72b78dd999cce146bf8f4754a05fbd0dbbddcc72a7389f8b48b8546d4d98dba0
7
- data.tar.gz: ca14f9cffef86ef82b52985f5ad58f662cbffcb33b86050ffd6e9390efaf5892eed0469595f153d7b0d8a8e6141a75a1e47cdd8076178385a92fe99593c8b3c3
6
+ metadata.gz: 566cf68fd9c0ee2de8c5e54693e0caa2b956c537f9b82362b7eb7547214349b7966029d6cf12dcac0ca930b0b0f9ad2c32c7dace3a2bd84d43eecd488b194144
7
+ data.tar.gz: a69faa775b378ee5108525cd431ab9bf242ac93afeb5fc351a7549aa852099fc9c84ceef4a6dccf265e7e27ed5e0894937a1abbc4fa9a641d9fb9c51c0e8ff90
data/CHANGELOG.md CHANGED
@@ -1,11 +1,62 @@
1
1
  # Changelog
2
2
 
3
- # 3.19.0
3
+ # 3.22.0
4
+
5
+ * Addressed an issue in the HTTPClient adapter where memoized stubbed responses and memoized request_signatures were incorrectly persisted between subsequent requests ([#1019](https://github.com/bblimke/webmock/issues/1019)). The implementation of a more robust thread-safety solution by [Tom Beauvais](https://github.com/tbeauvais) in [PR #300](https://github.com/bblimke/webmock/pull/300) not only resolved the memoization problem but also enhanced the overall thread safety of the adapter. This update ensures that stubbed responses and request signatures are correctly isolated to individual requests, improving both consistency and thread safety.
6
+
7
+
8
+ # 3.21.2
9
+
10
+ * Corrected type checking in `WebMock::Response#assert_valid_body!` to accurately recognize `Hash` objects. Additionally, improved the clarity of the error message for unsupported body types, guiding users towards proper usage.
11
+
12
+ Thanks to [Jake Robb](https://github.com/jakerobb) for reporting.
13
+
14
+ # 3.21.1
15
+
16
+ * The stubbed Net::HTTPResponse#uri now returns request.uri, aligning it with the behavior of an actual Net::HTTPResponse.
17
+
18
+ Thanks to [Abe Voelker](https://github.com/abevoelker) for reporting and to [Victor Maslov](https://github.com/Nakilon) and [Gio Lodi](https://github.com/mokagio) for the suggested solution.
19
+
20
+ # 3.21.0
21
+
22
+ * Don't use deprecated Rack::VERSION for Rack >= 3
23
+
24
+ Thanks to [Étienne Barrié](https://github.com/etiennebarrie)
25
+
26
+ * Updated HTTPClient adapter, to build request signature using the URI after filters have been applied.
27
+
28
+ Thanks to [Matt Brown](https://github.com/mattbnz)
29
+
30
+ # 3.20.0
31
+
32
+ * Optimised EmHttpRequestAdapter performance.
33
+
34
+ Thanks to [Ricardo Trindade](https://github.com/RicardoTrindade)
35
+
36
+ * Removed runtime dependency on base64.
37
+
38
+ Thanks to [Earlopain](https://github.com/Earlopain)
39
+
40
+ * Typhoeus::Response objects constructed from stubbed responses now have all timing attributes set to 0.0.
41
+
42
+ Thanks to [James Brown](https://github.com/Roguelazer)
43
+
44
+ * Optimised WebMock::Util::Headers by removing redundant freeze invocations.
45
+
46
+ Thanks to [Kazuhiro NISHIYAMA](https://github.com/znz)
47
+
48
+ * The default stubbed response body, which is an empty String, is unfrozen.
49
+
50
+ * When building signatures of requests made by http.rb, the request body encoding is now preserved.
51
+
52
+ # 3.19.1
4
53
 
5
54
  * When passing a Proc or lambda as response body to `to_return_json`, the body is evaluated at the time of request and not at the time of `to_return_json` method invocation.
6
55
 
7
56
  Thanks to [Jason Karns](https://github.com/jasonkarns) for reporting.
8
57
 
58
+ # 3.19.0
59
+
9
60
  * Do not alter real (non-stubbed) request headers when handling em-http-request requests.
10
61
 
11
62
  Thanks to [Yoann Lecuyer](https://github.com/ylecuyer)
@@ -154,7 +205,7 @@
154
205
 
155
206
  * Fixed async-http adapter to only considered requests as real if they are real.
156
207
 
157
- Thanks to Thanks to [Tony Schneider](https://github.com/tonywok) and [Samuel Williams](https://github.com/ioquatix)
208
+ Thanks to [Tony Schneider](https://github.com/tonywok) and [Samuel Williams](https://github.com/ioquatix)
158
209
 
159
210
  # 3.11.2
160
211
 
data/README.md CHANGED
@@ -606,7 +606,11 @@ which can be passed to `WebMock.allow_net_connect!` and `WebMock.disable_net_con
606
606
  WebMock.allow_net_connect!(net_http_connect_on_start: true)
607
607
  ```
608
608
 
609
- This forces WebMock Net::HTTP adapter to always connect on `Net::HTTP.start`.
609
+ This forces WebMock Net::HTTP adapter to always connect on `Net::HTTP.start`. At the time of connection being made there is no information about the request or URL yet, therefore WebMock is not able to decide whether to stub a request or not and all connections are allowed. To enable connections only to a specific domain (e.g. your test server) use:
610
+
611
+ ```ruby
612
+ WebMock.allow_net_connect!(net_http_connect_on_start: "www.example.com")
613
+ ```
610
614
 
611
615
  ## Setting Expectations
612
616
 
@@ -1189,6 +1193,15 @@ People who submitted patches and new features or suggested improvements. Many th
1189
1193
  * Yuki Inoue
1190
1194
  * Brandon Weaver
1191
1195
  * Josh Nichols
1196
+ * Ricardo Trindade
1197
+ * Earlopain
1198
+ * James Brown
1199
+ * Kazuhiro NISHIYAMA
1200
+ * Étienne Barrié
1201
+ * Matt Brown
1202
+ * Victor Maslov
1203
+ * Gio Lodi
1204
+ * Ryan Brooks
1192
1205
 
1193
1206
  For a full list of contributors you can visit the
1194
1207
  [contributors](https://github.com/bblimke/webmock/contributors) page.
@@ -156,7 +156,7 @@ if defined?(EventMachine::HttpClient)
156
156
  raw_cookie = response_header.cookie
157
157
  raw_cookie = [raw_cookie] if raw_cookie.is_a? String
158
158
 
159
- cookie = raw_cookie.select { |c| c.start_with? name }.first
159
+ cookie = raw_cookie.detect { |c| c.start_with? name }
160
160
  cookie and cookie.split('=', 2)[1]
161
161
  end
162
162
 
@@ -3,11 +3,21 @@
3
3
  module HTTP
4
4
  class Request
5
5
  def webmock_signature
6
- request_body = if defined?(HTTP::Request::Body)
7
- String.new.tap { |string| body.each { |part| string << part } }
8
- else
9
- body
10
- end
6
+ request_body = nil
7
+
8
+ if defined?(HTTP::Request::Body)
9
+ request_body = String.new
10
+ first_chunk_encoding = nil
11
+ body.each do |part|
12
+ request_body << part
13
+ first_chunk_encoding ||= part.encoding
14
+ end
15
+
16
+ request_body.force_encoding(first_chunk_encoding) if first_chunk_encoding
17
+ request_body
18
+ else
19
+ request_body = body
20
+ end
11
21
 
12
22
  ::WebMock::RequestSignature.new(verb, uri.to_s, {
13
23
  headers: headers.to_h,
@@ -45,6 +45,8 @@ if defined?(::HTTPClient)
45
45
  end
46
46
 
47
47
  module WebMockHTTPClients
48
+ WEBMOCK_HTTPCLIENT_RESPONSES = :webmock_httpclient_responses
49
+ WEBMOCK_HTTPCLIENT_REQUEST_SIGNATURES = :webmock_httpclient_request_signatures
48
50
 
49
51
  REQUEST_RESPONSE_LOCK = Mutex.new
50
52
 
@@ -57,12 +59,14 @@ if defined?(::HTTPClient)
57
59
  end
58
60
 
59
61
  def do_get(req, proxy, conn, stream = false, &block)
62
+ clear_thread_variables unless conn.async_thread
63
+
60
64
  request_signature = build_request_signature(req, :reuse_existing)
61
65
 
62
66
  WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
63
67
 
64
68
  if webmock_responses[request_signature]
65
- webmock_response = synchronize_request_response { webmock_responses.delete(request_signature) }
69
+ webmock_response = webmock_responses.delete(request_signature)
66
70
  response = build_httpclient_response(webmock_response, stream, req.header, &block)
67
71
  @request_filter.each do |filter|
68
72
  filter.filter_response(req, response)
@@ -73,7 +77,7 @@ if defined?(::HTTPClient)
73
77
  res
74
78
  elsif WebMock.net_connect_allowed?(request_signature.uri)
75
79
  # in case there is a nil entry in the hash...
76
- synchronize_request_response { webmock_responses.delete(request_signature) }
80
+ webmock_responses.delete(request_signature)
77
81
 
78
82
  res = if stream
79
83
  do_get_stream_without_webmock(req, proxy, conn, &block)
@@ -103,12 +107,16 @@ if defined?(::HTTPClient)
103
107
  end
104
108
 
105
109
  def do_request_async(method, uri, query, body, extheader)
110
+ clear_thread_variables
106
111
  req = create_request(method, uri, query, body, extheader)
107
112
  request_signature = build_request_signature(req)
108
- synchronize_request_response { webmock_request_signatures << request_signature }
113
+ webmock_request_signatures << request_signature
109
114
 
110
115
  if webmock_responses[request_signature] || WebMock.net_connect_allowed?(request_signature.uri)
111
- 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
112
120
  else
113
121
  raise WebMock::NetConnectNotAllowedError.new(request_signature)
114
122
  end
@@ -157,14 +165,14 @@ if defined?(::HTTPClient)
157
165
  end
158
166
 
159
167
  def build_request_signature(req, reuse_existing = false)
160
- uri = WebMock::Util::URI.heuristic_parse(req.header.request_uri.to_s)
161
- uri.query = WebMock::Util::QueryMapper.values_to_query(req.header.request_query, notation: WebMock::Config.instance.query_values_notation) if req.header.request_query
162
- uri.port = req.header.request_uri.port
163
-
164
168
  @request_filter.each do |filter|
165
169
  filter.filter_request(req)
166
170
  end
167
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
+
168
176
  headers = req.header.all.inject({}) do |hdrs, header|
169
177
  hdrs[header[0]] ||= []
170
178
  hdrs[header[0]] << header[1]
@@ -188,22 +196,18 @@ if defined?(::HTTPClient)
188
196
  end
189
197
 
190
198
  def webmock_responses
191
- @webmock_responses ||= Hash.new do |hash, request_signature|
192
- synchronize_request_response do
193
- hash[request_signature] = WebMock::StubRegistry.instance.response_for_request(request_signature)
194
- 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)
195
201
  end
196
202
  end
197
203
 
198
204
  def webmock_request_signatures
199
- @webmock_request_signatures ||= []
205
+ Thread.current[WEBMOCK_HTTPCLIENT_REQUEST_SIGNATURES] ||= []
200
206
  end
201
207
 
202
208
  def previous_signature_for(signature)
203
- synchronize_request_response do
204
- return nil unless index = webmock_request_signatures.index(signature)
205
- webmock_request_signatures.delete_at(index)
206
- end
209
+ return nil unless index = webmock_request_signatures.index(signature)
210
+ webmock_request_signatures.delete_at(index)
207
211
  end
208
212
 
209
213
  private
@@ -219,14 +223,9 @@ if defined?(::HTTPClient)
219
223
  end
220
224
  end
221
225
 
222
- def synchronize_request_response
223
- if REQUEST_RESPONSE_LOCK.owned?
224
- yield
225
- else
226
- REQUEST_RESPONSE_LOCK.synchronize do
227
- yield
228
- end
229
- end
226
+ def clear_thread_variables
227
+ Thread.current[WEBMOCK_HTTPCLIENT_REQUEST_SIGNATURES] = nil
228
+ Thread.current[WEBMOCK_HTTPCLIENT_RESPONSES] = nil
230
229
  end
231
230
  end
232
231
 
@@ -77,7 +77,7 @@ module WebMock
77
77
  @socket = Net::HTTP.socket_type.new
78
78
  WebMock::CallbackRegistry.invoke_callbacks(
79
79
  {lib: :net_http}, request_signature, webmock_response)
80
- build_net_http_response(webmock_response, &block)
80
+ build_net_http_response(webmock_response, request.uri, &block)
81
81
  elsif WebMock.net_connect_allowed?(request_signature.uri)
82
82
  check_right_http_connection
83
83
  after_request = lambda do |response|
@@ -144,7 +144,7 @@ module WebMock
144
144
  end
145
145
  end
146
146
 
147
- def build_net_http_response(webmock_response, &block)
147
+ def build_net_http_response(webmock_response, request_uri, &block)
148
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])
149
149
  body = webmock_response.body
150
150
  body = nil if webmock_response.status[0].to_s == '204'
@@ -159,6 +159,8 @@ module WebMock
159
159
 
160
160
  response.instance_variable_set(:@read, true)
161
161
 
162
+ response.uri = request_uri
163
+
162
164
  response.extend Net::WebMockHTTPResponse
163
165
 
164
166
  if webmock_response.should_timeout
@@ -96,7 +96,14 @@ if defined?(Typhoeus)
96
96
  status_message: "",
97
97
  body: "",
98
98
  headers: {},
99
- 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
100
107
  )
101
108
  else
102
109
  ::Typhoeus::Response.new(
@@ -104,7 +111,14 @@ if defined?(Typhoeus)
104
111
  status_message: webmock_response.status[1],
105
112
  body: webmock_response.body,
106
113
  headers: webmock_response.headers,
107
- 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
108
122
  )
109
123
  end
110
124
  response.mock = :webmock
@@ -47,7 +47,9 @@ module WebMock
47
47
  # Rack-specific variables
48
48
  env['rack.input'] = StringIO.new(body)
49
49
  env['rack.errors'] = $stderr
50
- env['rack.version'] = Rack::VERSION
50
+ if !Rack.const_defined?(:RELEASE) || Rack::RELEASE < "3"
51
+ env['rack.version'] = Rack::VERSION
52
+ end
51
53
  env['rack.url_scheme'] = uri.scheme
52
54
  env['rack.run_once'] = true
53
55
  env['rack.session'] = session
@@ -38,7 +38,7 @@ module WebMock
38
38
  end
39
39
 
40
40
  def body
41
- @body || ''
41
+ @body || String.new("")
42
42
  end
43
43
 
44
44
  def body=(body)
@@ -117,11 +117,11 @@ module WebMock
117
117
  return if @body.nil?
118
118
  return if valid_types.any? { |c| @body.is_a?(c) }
119
119
 
120
- if @body.class.is_a?(Hash)
121
- raise InvalidBody, "must be one of: #{valid_types}, but you've used a #{@body.class}' instead." \
122
- "\n What shall we encode it to? try calling .to_json .to_xml instead on the hash instead, or otherwise convert it to a string."
120
+ if @body.is_a?(Hash)
121
+ raise InvalidBody, "must be one of: #{valid_types}, but you've used a #{@body.class}. " \
122
+ "Please convert it by calling .to_json .to_xml, or otherwise convert it to a string."
123
123
  else
124
- raise InvalidBody, "must be one of: #{valid_types}. '#{@body.class}' given"
124
+ raise InvalidBody, "must be one of: #{valid_types}. '#{@body.class}' given."
125
125
  end
126
126
  end
127
127
 
@@ -1,16 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'base64'
4
-
5
3
  module WebMock
6
4
 
7
5
  module Util
8
6
 
9
7
  class Headers
10
8
 
11
- STANDARD_HEADER_DELIMITER = '-'.freeze
12
- NONSTANDARD_HEADER_DELIMITER = '_'.freeze
13
- JOIN = ', '.freeze
9
+ STANDARD_HEADER_DELIMITER = '-'
10
+ NONSTANDARD_HEADER_DELIMITER = '_'
11
+ JOIN = ', '
14
12
 
15
13
  def self.normalize_headers(headers)
16
14
  return nil unless headers
@@ -59,7 +57,8 @@ module WebMock
59
57
  end
60
58
 
61
59
  def self.basic_auth_header(*credentials)
62
- "Basic #{Base64.strict_encode64(credentials.join(':')).chomp}"
60
+ strict_base64_encoded = [credentials.join(':')].pack("m0")
61
+ "Basic #{strict_base64_encoded.chomp}"
63
62
  end
64
63
 
65
64
  def self.normalize_name(name)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module WebMock
4
- VERSION = '3.19.1' unless defined?(::WebMock::VERSION)
4
+ VERSION = '3.22.0' unless defined?(::WebMock::VERSION)
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: webmock
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.19.1
4
+ version: 3.22.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bartosz Blimke
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-29 00:00:00.000000000 Z
11
+ date: 2024-02-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -198,6 +198,20 @@ dependencies:
198
198
  - - ">="
199
199
  - !ruby/object:Gem::Version
200
200
  version: 2.2.4
201
+ - !ruby/object:Gem::Dependency
202
+ name: mutex_m
203
+ requirement: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - ">="
206
+ - !ruby/object:Gem::Version
207
+ version: '0'
208
+ type: :development
209
+ prerelease: false
210
+ version_requirements: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - ">="
213
+ - !ruby/object:Gem::Version
214
+ version: '0'
201
215
  - !ruby/object:Gem::Dependency
202
216
  name: excon
203
217
  requirement: !ruby/object:Gem::Requirement
@@ -357,9 +371,9 @@ licenses:
357
371
  - MIT
358
372
  metadata:
359
373
  bug_tracker_uri: https://github.com/bblimke/webmock/issues
360
- changelog_uri: https://github.com/bblimke/webmock/blob/v3.19.1/CHANGELOG.md
361
- documentation_uri: https://www.rubydoc.info/gems/webmock/3.19.1
362
- source_code_uri: https://github.com/bblimke/webmock/tree/v3.19.1
374
+ changelog_uri: https://github.com/bblimke/webmock/blob/v3.22.0/CHANGELOG.md
375
+ documentation_uri: https://www.rubydoc.info/gems/webmock/3.22.0
376
+ source_code_uri: https://github.com/bblimke/webmock/tree/v3.22.0
363
377
  wiki_uri: https://github.com/bblimke/webmock/wiki
364
378
  post_install_message:
365
379
  rdoc_options: []
@@ -376,7 +390,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
376
390
  - !ruby/object:Gem::Version
377
391
  version: '0'
378
392
  requirements: []
379
- rubygems_version: 3.4.19
393
+ rubygems_version: 3.5.6
380
394
  signing_key:
381
395
  specification_version: 4
382
396
  summary: Library for stubbing HTTP requests in Ruby.