rubygems-update 4.0.21 → 4.0.23

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -0
  3. data/Manifest.txt +1 -1
  4. data/bundler/CHANGELOG.md +28 -0
  5. data/bundler/lib/bundler/build_metadata.rb +2 -2
  6. data/bundler/lib/bundler/cli/lock.rb +14 -3
  7. data/bundler/lib/bundler/cli/platform.rb +15 -1
  8. data/bundler/lib/bundler/cli.rb +17 -5
  9. data/bundler/lib/bundler/fetcher/downloader.rb +10 -4
  10. data/bundler/lib/bundler/installer.rb +4 -0
  11. data/bundler/lib/bundler/man/bundle-lock.1 +1 -1
  12. data/bundler/lib/bundler/man/bundle-lock.1.ronn +1 -1
  13. data/bundler/lib/bundler/man/bundle-outdated.1 +1 -1
  14. data/bundler/lib/bundler/man/bundle-outdated.1.ronn +1 -1
  15. data/bundler/lib/bundler/man/bundle-update.1 +2 -2
  16. data/bundler/lib/bundler/man/bundle-update.1.ronn +2 -2
  17. data/bundler/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt +1 -1
  18. data/bundler/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb +14 -4
  19. data/bundler/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb +1 -1
  20. data/bundler/lib/bundler/vendor/connection_pool/lib/connection_pool.rb +3 -0
  21. data/bundler/lib/bundler/vendor/fileutils/lib/fileutils.rb +54 -29
  22. data/bundler/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb +1 -1
  23. data/bundler/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb +10 -1
  24. data/bundler/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +12 -6
  25. data/bundler/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb +35 -2
  26. data/bundler/lib/bundler/vendor/thor/lib/thor/base.rb +2 -1
  27. data/bundler/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +14 -6
  28. data/bundler/lib/bundler/vendor/thor/lib/thor/shell/color.rb +2 -0
  29. data/bundler/lib/bundler/vendor/thor/lib/thor/version.rb +1 -1
  30. data/bundler/lib/bundler/vendor/thor/lib/thor.rb +34 -1
  31. data/bundler/lib/bundler/vendor/uri/lib/uri/common.rb +1 -1
  32. data/bundler/lib/bundler/vendor/uri/lib/uri/generic.rb +15 -3
  33. data/bundler/lib/bundler/vendor/uri/lib/uri/version.rb +1 -1
  34. data/bundler/lib/bundler/version.rb +1 -1
  35. data/bundler/lib/bundler.rb +1 -3
  36. data/lib/rubygems/commands/exec_command.rb +3 -0
  37. data/lib/rubygems/ext/builder.rb +7 -2
  38. data/lib/rubygems/gemcutter_utilities/webauthn_listener.rb +9 -0
  39. data/lib/rubygems/installer.rb +4 -0
  40. data/lib/rubygems/package.rb +36 -5
  41. data/lib/rubygems/uninstaller.rb +1 -0
  42. data/lib/rubygems/vendor/net-http/lib/net/http/exceptions.rb +2 -1
  43. data/lib/rubygems/vendor/net-http/lib/net/http/generic_request.rb +15 -7
  44. data/lib/rubygems/vendor/net-http/lib/net/http/header.rb +64 -19
  45. data/lib/rubygems/vendor/net-http/lib/net/http/request.rb +1 -0
  46. data/lib/rubygems/vendor/net-http/lib/net/http/requests.rb +74 -25
  47. data/lib/rubygems/vendor/net-http/lib/net/http/response.rb +42 -16
  48. data/lib/rubygems/vendor/net-http/lib/net/http/responses.rb +68 -0
  49. data/lib/rubygems/vendor/net-http/lib/net/http.rb +129 -37
  50. data/lib/rubygems/vendor/net-protocol/COPYING +56 -0
  51. data/lib/rubygems/vendor/net-protocol/lib/net/protocol.rb +95 -26
  52. data/lib/rubygems/vendor/optparse/lib/optparse.rb +23 -30
  53. data/lib/rubygems/vendor/timeout/lib/timeout.rb +190 -77
  54. data/lib/rubygems/vendor/uri/lib/uri/common.rb +1 -1
  55. data/lib/rubygems/vendor/uri/lib/uri/generic.rb +15 -3
  56. data/lib/rubygems/vendor/uri/lib/uri/version.rb +1 -1
  57. data/lib/rubygems.rb +1 -1
  58. metadata +2 -2
  59. data/lib/rubygems/vendor/net-protocol/LICENSE.txt +0 -22
@@ -179,7 +179,9 @@
179
179
  # - #each_value: Passes each string field value to the block.
180
180
  #
181
181
  module Gem::Net::HTTPHeader
182
+ # The maximum length of HTTP header keys.
182
183
  MAX_KEY_LENGTH = 1024
184
+ # The maximum length of HTTP header values.
183
185
  MAX_FIELD_LENGTH = 65536
184
186
 
185
187
  def initialize_http_header(initheader) #:nodoc:
@@ -191,11 +193,9 @@ module Gem::Net::HTTPHeader
191
193
  warn "net/http: nil HTTP header: #{key}", uplevel: 3 if $VERBOSE
192
194
  else
193
195
  value = value.strip # raise error for invalid byte sequences
194
- if key.to_s.bytesize > MAX_KEY_LENGTH
195
- raise ArgumentError, "too long (#{key.bytesize} bytes) header: #{key[0, 30].inspect}..."
196
- end
196
+ validate_field_name(key)
197
197
  if value.to_s.bytesize > MAX_FIELD_LENGTH
198
- raise ArgumentError, "header #{key} has too long field value: #{value.bytesize}"
198
+ raise ArgumentError, "header #{key} has too long field value: #{value.bytesize} bytes (limit #{MAX_FIELD_LENGTH})"
199
199
  end
200
200
  if value.count("\r\n") > 0
201
201
  raise ArgumentError, "header #{key} has field value #{value.inspect}, this cannot include CR/LF"
@@ -261,20 +261,34 @@ module Gem::Net::HTTPHeader
261
261
  def add_field(key, val)
262
262
  stringified_downcased_key = key.downcase.to_s
263
263
  if @header.key?(stringified_downcased_key)
264
- append_field_value(@header[stringified_downcased_key], val)
264
+ append_field_value(@header[stringified_downcased_key], val, key)
265
265
  else
266
266
  set_field(key, val)
267
267
  end
268
268
  end
269
269
 
270
+ # :stopdoc:
271
+ private def validate_field_name(key)
272
+ if key.to_s.bytesize > MAX_KEY_LENGTH
273
+ raise ArgumentError, "too long (#{key.to_s.bytesize} bytes) header: #{key.to_s[0, 30].inspect}..."
274
+ end
275
+ if /[\x00-\x1f\x7f:]/n.match?(key.to_s.b)
276
+ raise ArgumentError, "header field name cannot include control characters or colon: #{key.to_s[0, 30].inspect}"
277
+ end
278
+ end
279
+
270
280
  private def set_field(key, val)
281
+ validate_field_name(key)
271
282
  case val
272
283
  when Enumerable
273
284
  ary = []
274
- append_field_value(ary, val)
285
+ append_field_value(ary, val, key)
275
286
  @header[key.downcase.to_s] = ary
276
287
  else
277
288
  val = val.to_s # for compatibility use to_s instead of to_str
289
+ if val.bytesize > MAX_FIELD_LENGTH
290
+ raise ArgumentError, "header #{key} has too long field value: #{val.bytesize} bytes (limit #{MAX_FIELD_LENGTH})"
291
+ end
278
292
  if val.b.count("\r\n") > 0
279
293
  raise ArgumentError, 'header field value cannot include CR/LF'
280
294
  end
@@ -282,18 +296,22 @@ module Gem::Net::HTTPHeader
282
296
  end
283
297
  end
284
298
 
285
- private def append_field_value(ary, val)
299
+ private def append_field_value(ary, val, key)
286
300
  case val
287
301
  when Enumerable
288
- val.each{|x| append_field_value(ary, x)}
302
+ val.each{|x| append_field_value(ary, x, key)}
289
303
  else
290
304
  val = val.to_s
305
+ if val.bytesize > MAX_FIELD_LENGTH
306
+ raise ArgumentError, "header #{key} has too long field value: #{val.bytesize} bytes (limit #{MAX_FIELD_LENGTH})"
307
+ end
291
308
  if /[\r\n]/n.match?(val.b)
292
309
  raise ArgumentError, 'header field value cannot include CR/LF'
293
310
  end
294
311
  ary.push val
295
312
  end
296
313
  end
314
+ # :startdoc:
297
315
 
298
316
  # Returns the array field value for the given +key+,
299
317
  # or +nil+ if there is no such field;
@@ -490,7 +508,7 @@ module Gem::Net::HTTPHeader
490
508
 
491
509
  alias canonical_each each_capitalized
492
510
 
493
- def capitalize(name)
511
+ def capitalize(name) # :nodoc:
494
512
  name.to_s.split('-'.freeze).map {|s| s.capitalize }.join('-'.freeze)
495
513
  end
496
514
  private :capitalize
@@ -613,11 +631,35 @@ module Gem::Net::HTTPHeader
613
631
  # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
614
632
  # res.content_length # => nil
615
633
  #
634
+ # The value must consist of digits only.
635
+ # Multiple <tt>'Content-Length'</tt> values are accepted
636
+ # only when they are all identical;
637
+ # otherwise Gem::Net::HTTPHeaderSyntaxError is raised.
638
+ # See {RFC 9110 Section 8.6}[https://www.rfc-editor.org/rfc/rfc9110.html#section-8.6].
616
639
  def content_length
617
- return nil unless key?('Content-Length')
618
- len = self['Content-Length'].slice(/\d+/) or
619
- raise Gem::Net::HTTPHeaderSyntaxError, 'wrong Content-Length format'
620
- len.to_i
640
+ values = @header['content-length']
641
+ return nil if values.nil?
642
+
643
+ lengths = []
644
+ values.each do |value|
645
+ value = value.strip
646
+ if value.empty?
647
+ raise Gem::Net::HTTPHeaderSyntaxError,
648
+ "empty Content-Length value"
649
+ end
650
+ lengths.concat(value.split(/\s*,\s*/, -1))
651
+ end
652
+ if lengths.uniq.size != 1
653
+ raise Gem::Net::HTTPHeaderSyntaxError,
654
+ "Content-Length has multiple different values: " +
655
+ values.join(", ")
656
+ end
657
+ length = lengths.first
658
+ unless /\A\d+\z/.match?(length)
659
+ raise Gem::Net::HTTPHeaderSyntaxError,
660
+ "wrong Content-Length format: #{length}"
661
+ end
662
+ length.to_i
621
663
  end
622
664
 
623
665
  # Sets the value of field <tt>'Content-Length'</tt> to the given numeric;
@@ -643,7 +685,7 @@ module Gem::Net::HTTPHeader
643
685
  end
644
686
 
645
687
  # Returns +true+ if field <tt>'Transfer-Encoding'</tt>
646
- # exists and has value <tt>'chunked'</tt>,
688
+ # exists and has <tt>'chunked'</tt> as its final transfer coding,
647
689
  # +false+ otherwise;
648
690
  # see {Transfer-Encoding response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#transfer-encoding-response-header]:
649
691
  #
@@ -651,10 +693,13 @@ module Gem::Net::HTTPHeader
651
693
  # res['Transfer-Encoding'] # => "chunked"
652
694
  # res.chunked? # => true
653
695
  #
696
+ # <tt>'gzip, chunked'</tt> is chunked but <tt>'chunked, gzip'</tt> is not,
697
+ # because only the final transfer coding frames the message.
698
+ # See {RFC 9112 Section 6.3}[https://www.rfc-editor.org/rfc/rfc9112.html#section-6.3].
654
699
  def chunked?
655
700
  return false unless @header['transfer-encoding']
656
701
  field = self['Transfer-Encoding']
657
- (/(?:\A|[^\-\w])chunked(?![\-\w])/i =~ field) ? true : false
702
+ (/(?:\A|[^\-\w])chunked(?![\-\w])\s*(?:,\s*)*\z/i =~ field) ? true : false
658
703
  end
659
704
 
660
705
  # Returns a Range object representing the value of field
@@ -770,7 +815,7 @@ module Gem::Net::HTTPHeader
770
815
  #
771
816
  # Gem::Net::HTTPHeader#content_type= is an alias for Gem::Net::HTTPHeader#set_content_type.
772
817
  def set_content_type(type, params = {})
773
- @header['content-type'] = [type + params.map{|k,v|"; #{k}=#{v}"}.join('')]
818
+ set_field('Content-Type', type + params.map{|k,v|"; #{k}=#{v}"}.join(''))
774
819
  end
775
820
 
776
821
  alias content_type= set_content_type
@@ -957,12 +1002,12 @@ module Gem::Net::HTTPHeader
957
1002
  @header['proxy-authorization'] = [basic_encode(account, password)]
958
1003
  end
959
1004
 
960
- def basic_encode(account, password)
1005
+ def basic_encode(account, password) # :nodoc:
961
1006
  'Basic ' + ["#{account}:#{password}"].pack('m0')
962
1007
  end
963
1008
  private :basic_encode
964
1009
 
965
- # Returns whether the HTTP session is to be closed.
1010
+ # Returns whether the HTTP session is to be closed.
966
1011
  def connection_close?
967
1012
  token = /(?:\A|,)\s*close\s*(?:\z|,)/i
968
1013
  @header['connection']&.grep(token) {return true}
@@ -970,7 +1015,7 @@ module Gem::Net::HTTPHeader
970
1015
  false
971
1016
  end
972
1017
 
973
- # Returns whether the HTTP session is to be kept alive.
1018
+ # Returns whether the HTTP session is to be kept alive.
974
1019
  def connection_keep_alive?
975
1020
  token = /(?:\A|,)\s*keep-alive\s*(?:\z|,)/i
976
1021
  @header['connection']&.grep(token) {return true}
@@ -61,6 +61,7 @@
61
61
  # - Gem::Net::HTTP::Options
62
62
  # - Gem::Net::HTTP::Trace
63
63
  # - Gem::Net::HTTP::Patch
64
+ # - Gem::Net::HTTP::Query
64
65
  #
65
66
  # Subclasses for WebDAV requests:
66
67
  #
@@ -19,9 +19,9 @@
19
19
  #
20
20
  # - Request body: optional.
21
21
  # - Response body: yes.
22
- # - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: yes.
23
- # - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
24
- # - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: yes.
22
+ # - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: yes.
23
+ # - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
24
+ # - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: yes.
25
25
  #
26
26
  # Related:
27
27
  #
@@ -29,6 +29,7 @@
29
29
  # - Gem::Net::HTTP#get: sends +GET+ request, returns response object.
30
30
  #
31
31
  class Gem::Net::HTTP::Get < Gem::Net::HTTPRequest
32
+ # :stopdoc:
32
33
  METHOD = 'GET'
33
34
  REQUEST_HAS_BODY = false
34
35
  RESPONSE_HAS_BODY = true
@@ -51,15 +52,16 @@ end
51
52
  #
52
53
  # - Request body: optional.
53
54
  # - Response body: no.
54
- # - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: yes.
55
- # - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
56
- # - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: yes.
55
+ # - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: yes.
56
+ # - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
57
+ # - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: yes.
57
58
  #
58
59
  # Related:
59
60
  #
60
61
  # - Gem::Net::HTTP#head: sends +HEAD+ request, returns response object.
61
62
  #
62
63
  class Gem::Net::HTTP::Head < Gem::Net::HTTPRequest
64
+ # :stopdoc:
63
65
  METHOD = 'HEAD'
64
66
  REQUEST_HAS_BODY = false
65
67
  RESPONSE_HAS_BODY = false
@@ -85,9 +87,9 @@ end
85
87
  #
86
88
  # - Request body: yes.
87
89
  # - Response body: yes.
88
- # - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: no.
89
- # - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: no.
90
- # - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: yes.
90
+ # - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: no.
91
+ # - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: no.
92
+ # - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: yes.
91
93
  #
92
94
  # Related:
93
95
  #
@@ -95,6 +97,7 @@ end
95
97
  # - Gem::Net::HTTP#post: sends +POST+ request, returns response object.
96
98
  #
97
99
  class Gem::Net::HTTP::Post < Gem::Net::HTTPRequest
100
+ # :stopdoc:
98
101
  METHOD = 'POST'
99
102
  REQUEST_HAS_BODY = true
100
103
  RESPONSE_HAS_BODY = true
@@ -120,9 +123,9 @@ end
120
123
  #
121
124
  # - Request body: yes.
122
125
  # - Response body: yes.
123
- # - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: no.
124
- # - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
125
- # - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: no.
126
+ # - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: no.
127
+ # - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
128
+ # - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: no.
126
129
  #
127
130
  # Related:
128
131
  #
@@ -130,6 +133,7 @@ end
130
133
  # - Gem::Net::HTTP#put: sends +PUT+ request, returns response object.
131
134
  #
132
135
  class Gem::Net::HTTP::Put < Gem::Net::HTTPRequest
136
+ # :stopdoc:
133
137
  METHOD = 'PUT'
134
138
  REQUEST_HAS_BODY = true
135
139
  RESPONSE_HAS_BODY = true
@@ -153,15 +157,16 @@ end
153
157
  #
154
158
  # - Request body: optional.
155
159
  # - Response body: yes.
156
- # - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: no.
157
- # - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
158
- # - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: no.
160
+ # - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: no.
161
+ # - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
162
+ # - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: no.
159
163
  #
160
164
  # Related:
161
165
  #
162
166
  # - Gem::Net::HTTP#delete: sends +DELETE+ request, returns response object.
163
167
  #
164
168
  class Gem::Net::HTTP::Delete < Gem::Net::HTTPRequest
169
+ # :stopdoc:
165
170
  METHOD = 'DELETE'
166
171
  REQUEST_HAS_BODY = false
167
172
  RESPONSE_HAS_BODY = true
@@ -184,15 +189,16 @@ end
184
189
  #
185
190
  # - Request body: optional.
186
191
  # - Response body: yes.
187
- # - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: yes.
188
- # - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
189
- # - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: no.
192
+ # - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: yes.
193
+ # - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
194
+ # - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: no.
190
195
  #
191
196
  # Related:
192
197
  #
193
198
  # - Gem::Net::HTTP#options: sends +OPTIONS+ request, returns response object.
194
199
  #
195
200
  class Gem::Net::HTTP::Options < Gem::Net::HTTPRequest
201
+ # :stopdoc:
196
202
  METHOD = 'OPTIONS'
197
203
  REQUEST_HAS_BODY = false
198
204
  RESPONSE_HAS_BODY = true
@@ -215,15 +221,16 @@ end
215
221
  #
216
222
  # - Request body: no.
217
223
  # - Response body: yes.
218
- # - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: yes.
219
- # - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
220
- # - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: no.
224
+ # - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: yes.
225
+ # - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
226
+ # - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: no.
221
227
  #
222
228
  # Related:
223
229
  #
224
230
  # - Gem::Net::HTTP#trace: sends +TRACE+ request, returns response object.
225
231
  #
226
232
  class Gem::Net::HTTP::Trace < Gem::Net::HTTPRequest
233
+ # :stopdoc:
227
234
  METHOD = 'TRACE'
228
235
  REQUEST_HAS_BODY = false
229
236
  RESPONSE_HAS_BODY = true
@@ -249,20 +256,56 @@ end
249
256
  #
250
257
  # - Request body: yes.
251
258
  # - Response body: yes.
252
- # - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: no.
253
- # - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: no.
254
- # - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: no.
259
+ # - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: no.
260
+ # - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: no.
261
+ # - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: no.
255
262
  #
256
263
  # Related:
257
264
  #
258
265
  # - Gem::Net::HTTP#patch: sends +PATCH+ request, returns response object.
259
266
  #
260
267
  class Gem::Net::HTTP::Patch < Gem::Net::HTTPRequest
268
+ # :stopdoc:
261
269
  METHOD = 'PATCH'
262
270
  REQUEST_HAS_BODY = true
263
271
  RESPONSE_HAS_BODY = true
264
272
  end
265
273
 
274
+ # \Class for representing
275
+ # {HTTP method QUERY}[https://www.rfc-editor.org/rfc/rfc10008.html]:
276
+ #
277
+ # require 'rubygems/vendor/net-http/lib/net/http'
278
+ # uri = Gem::URI('http://example.com')
279
+ # hostname = uri.hostname # => "example.com"
280
+ # uri.path = '/posts'
281
+ # req = Gem::Net::HTTP::Query.new(uri) # => #<Gem::Net::HTTP::Query QUERY>
282
+ # req.body = '{"title": "foo","body": "bar","userId": 1}'
283
+ # req.content_type = 'application/json'
284
+ # res = Gem::Net::HTTP.start(hostname) do |http|
285
+ # http.request(req)
286
+ # end
287
+ #
288
+ # See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
289
+ #
290
+ # Properties:
291
+ #
292
+ # - Request body: yes.
293
+ # - Response body: yes.
294
+ # - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: yes.
295
+ # - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
296
+ # - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: yes.
297
+ #
298
+ # Related:
299
+ #
300
+ # - Gem::Net::HTTP#query: sends +QUERY+ request, returns response object.
301
+ #
302
+ class Gem::Net::HTTP::Query < Gem::Net::HTTPRequest
303
+ # :stopdoc:
304
+ METHOD = 'QUERY'
305
+ REQUEST_HAS_BODY = true
306
+ RESPONSE_HAS_BODY = true
307
+ end
308
+
266
309
  #
267
310
  # WebDAV methods --- RFC2518
268
311
  #
@@ -285,6 +328,7 @@ end
285
328
  # - Gem::Net::HTTP#propfind: sends +PROPFIND+ request, returns response object.
286
329
  #
287
330
  class Gem::Net::HTTP::Propfind < Gem::Net::HTTPRequest
331
+ # :stopdoc:
288
332
  METHOD = 'PROPFIND'
289
333
  REQUEST_HAS_BODY = true
290
334
  RESPONSE_HAS_BODY = true
@@ -308,6 +352,7 @@ end
308
352
  # - Gem::Net::HTTP#proppatch: sends +PROPPATCH+ request, returns response object.
309
353
  #
310
354
  class Gem::Net::HTTP::Proppatch < Gem::Net::HTTPRequest
355
+ # :stopdoc:
311
356
  METHOD = 'PROPPATCH'
312
357
  REQUEST_HAS_BODY = true
313
358
  RESPONSE_HAS_BODY = true
@@ -331,6 +376,7 @@ end
331
376
  # - Gem::Net::HTTP#mkcol: sends +MKCOL+ request, returns response object.
332
377
  #
333
378
  class Gem::Net::HTTP::Mkcol < Gem::Net::HTTPRequest
379
+ # :stopdoc:
334
380
  METHOD = 'MKCOL'
335
381
  REQUEST_HAS_BODY = true
336
382
  RESPONSE_HAS_BODY = true
@@ -354,6 +400,7 @@ end
354
400
  # - Gem::Net::HTTP#copy: sends +COPY+ request, returns response object.
355
401
  #
356
402
  class Gem::Net::HTTP::Copy < Gem::Net::HTTPRequest
403
+ # :stopdoc:
357
404
  METHOD = 'COPY'
358
405
  REQUEST_HAS_BODY = false
359
406
  RESPONSE_HAS_BODY = true
@@ -377,6 +424,7 @@ end
377
424
  # - Gem::Net::HTTP#move: sends +MOVE+ request, returns response object.
378
425
  #
379
426
  class Gem::Net::HTTP::Move < Gem::Net::HTTPRequest
427
+ # :stopdoc:
380
428
  METHOD = 'MOVE'
381
429
  REQUEST_HAS_BODY = false
382
430
  RESPONSE_HAS_BODY = true
@@ -400,6 +448,7 @@ end
400
448
  # - Gem::Net::HTTP#lock: sends +LOCK+ request, returns response object.
401
449
  #
402
450
  class Gem::Net::HTTP::Lock < Gem::Net::HTTPRequest
451
+ # :stopdoc:
403
452
  METHOD = 'LOCK'
404
453
  REQUEST_HAS_BODY = true
405
454
  RESPONSE_HAS_BODY = true
@@ -423,8 +472,8 @@ end
423
472
  # - Gem::Net::HTTP#unlock: sends +UNLOCK+ request, returns response object.
424
473
  #
425
474
  class Gem::Net::HTTP::Unlock < Gem::Net::HTTPRequest
475
+ # :stopdoc:
426
476
  METHOD = 'UNLOCK'
427
477
  REQUEST_HAS_BODY = true
428
478
  RESPONSE_HAS_BODY = true
429
479
  end
430
-
@@ -133,6 +133,13 @@
133
133
  # there is a protocol error.
134
134
  #
135
135
  class Gem::Net::HTTPResponse
136
+ # The maximum total size in bytes of the response header.
137
+ MAX_RESPONSE_HEADER_LENGTH = 1024 * 1024 # 1 MiB
138
+
139
+ # The maximum number of informational (1xx) responses accepted before the
140
+ # final response.
141
+ MAX_INFORMATIONAL_RESPONSES = 100
142
+
136
143
  class << self
137
144
  # true if the response has a body.
138
145
  def body_permitted?
@@ -152,10 +159,17 @@ class Gem::Net::HTTPResponse
152
159
  res
153
160
  end
154
161
 
162
+ def read_line(sock, limit, ignore_eof = false) #:nodoc: internal use only
163
+ sock.readuntil("\n", ignore_eof, limit: limit)
164
+ rescue Gem::Net::ReadLimitExceeded
165
+ raise Gem::Net::HTTPBadResponse, 'response line too long'
166
+ end
167
+
155
168
  private
169
+ # :stopdoc:
156
170
 
157
171
  def read_status_line(sock)
158
- str = sock.readline
172
+ str = read_line(sock, MAX_RESPONSE_HEADER_LENGTH).chop
159
173
  m = /\AHTTP(?:\/(\d+\.\d+))?\s+(\d\d\d)(?:\s+(.*))?\z/in.match(str) or
160
174
  raise Gem::Net::HTTPBadResponse, "wrong status line: #{str.dump}"
161
175
  m.captures
@@ -169,12 +183,19 @@ class Gem::Net::HTTPResponse
169
183
 
170
184
  def each_response_header(sock)
171
185
  key = value = nil
186
+ remaining = MAX_RESPONSE_HEADER_LENGTH
172
187
  while true
173
- line = sock.readuntil("\n", true).sub(/\s+\z/, '')
188
+ line = read_line(sock, MAX_RESPONSE_HEADER_LENGTH, true)
189
+ remaining -= line.bytesize
190
+ raise Gem::Net::HTTPBadResponse, 'response header too large' if remaining < 0
191
+ line = line.chomp
174
192
  break if line.empty?
175
193
  if line[0] == ?\s or line[0] == ?\t and value
176
- value << ' ' unless value.empty?
177
- value << line.strip
194
+ folded = line.strip
195
+ unless folded.empty?
196
+ value << ' ' unless value.empty?
197
+ value << folded
198
+ end
178
199
  else
179
200
  yield key, value if key
180
201
  key, value = line.strip.split(/\s*:\s*/, 2)
@@ -259,7 +280,7 @@ class Gem::Net::HTTPResponse
259
280
  # header.
260
281
  attr_accessor :ignore_eof
261
282
 
262
- def inspect
283
+ def inspect # :nodoc:
263
284
  "#<#{self.class} #{@code} #{@message} readbody=#{@read}>"
264
285
  end
265
286
 
@@ -598,15 +619,20 @@ class Gem::Net::HTTPResponse
598
619
 
599
620
  @socket = inflate_body_io
600
621
 
601
- clen = content_length()
602
- if clen
603
- @socket.read clen, dest, @ignore_eof
604
- return
605
- end
606
- clen = range_length()
607
- if clen
608
- @socket.read clen, dest
609
- return
622
+ # Transfer-Encoding overrides Content-Length, so a body that is not
623
+ # chunk-framed runs until the server closes the connection.
624
+ # See RFC 9112 Section 6.3.
625
+ unless @header['transfer-encoding']
626
+ clen = content_length()
627
+ if clen
628
+ @socket.read clen, dest, @ignore_eof
629
+ return
630
+ end
631
+ clen = range_length()
632
+ if clen
633
+ @socket.read clen, dest
634
+ return
635
+ end
610
636
  end
611
637
  @socket.read_all dest
612
638
  end
@@ -622,7 +648,7 @@ class Gem::Net::HTTPResponse
622
648
  def read_chunked(dest, chunk_data_io) # :nodoc:
623
649
  total = 0
624
650
  while true
625
- line = @socket.readline
651
+ line = self.class.read_line(@socket, MAX_RESPONSE_HEADER_LENGTH).chop
626
652
  hexlen = line.slice(/[0-9a-fA-F]+/) or
627
653
  raise Gem::Net::HTTPBadResponse, "wrong chunk size line: #{line}"
628
654
  len = hexlen.hex
@@ -634,7 +660,7 @@ class Gem::Net::HTTPResponse
634
660
  @socket.read 2 # \r\n
635
661
  end
636
662
  end
637
- until @socket.readline.empty?
663
+ until self.class.read_line(@socket, MAX_RESPONSE_HEADER_LENGTH).chop.empty?
638
664
  # none
639
665
  end
640
666
  end