net-http 0.9.1 → 0.10.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ad9408074d86908c8284d26a13f9ba35d86948726c5e42ce453d40639be9d255
4
- data.tar.gz: b23103da88f3b5cf36274fb39b07e6889c86fbe6e9abf4cb86ed6bc2c9ce9448
3
+ metadata.gz: 7ef5db5bbe7d235bad14b04a257948207798e176d4f1d03029801615aa26823c
4
+ data.tar.gz: 1677b07e53a693f5d784a39e4d76a447868b5d435f3269561ccc772dd0345d10
5
5
  SHA512:
6
- metadata.gz: 5448ae667eff55826562b25f79a8f2e2991a79e1a763d1695429286b59e7e1ef25ffe2c22d9320dcf112daca3571112c7baae4a34c1b43caed6b0a944974c089
7
- data.tar.gz: 7679a6cf608155d9dabb09a9ed969deddb315662d220087fb80ba2b4e6f9d8519c714c501048b5c55a48625bb013313435461813197c63f0de6aed4dbabd68dc
6
+ metadata.gz: fd9e8e4ec27ff431f0a36acde5d6caecdebf34c5a625a6023b02bade546e7133bb6b12b3a0594d6cb3c5824577e093ef8677a209b9b35a2ee727b5b1906bf77e
7
+ data.tar.gz: b04a6747ae31dedd05716b221f9c9a6e668587cd025094f91f4b7c487feb85d769d4b8ff0d22ee55a79b96755324e447094579bf2306fc3acb363bb547e38b3d
data/README.md CHANGED
@@ -81,6 +81,8 @@ res = Net::HTTP.post_form(uri, 'q' => ['ruby', 'perl'], 'max' => '50')
81
81
  puts res.body
82
82
  ```
83
83
 
84
+ See the [documentation](https://docs.ruby-lang.org/en/master/Net/HTTP.html) for more details.
85
+
84
86
  ## Development
85
87
 
86
88
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -336,6 +336,9 @@ class Net::HTTPGenericRequest
336
336
  boundary = opt[:boundary]
337
337
  require 'securerandom' unless defined?(SecureRandom)
338
338
  boundary ||= SecureRandom.urlsafe_base64(40)
339
+ if /[\r\n]/.match?(boundary.to_s)
340
+ raise ArgumentError, "multipart boundary cannot include CR/LF"
341
+ end
339
342
  chunked_p = chunked?
340
343
 
341
344
  buf = +''
@@ -349,7 +352,10 @@ class Net::HTTPGenericRequest
349
352
  buf << "--#{boundary}\r\n"
350
353
  if filename
351
354
  filename = quote_string(filename, charset)
352
- type = h[:content_type] || 'application/octet-stream'
355
+ type = (h[:content_type] || 'application/octet-stream').to_s
356
+ if /[\r\n]/.match?(type)
357
+ raise ArgumentError, "field content type cannot include CR/LF"
358
+ end
353
359
  buf << "Content-Disposition: form-data; " \
354
360
  "name=\"#{key}\"; filename=\"#{filename}\"\r\n" \
355
361
  "Content-Type: #{type}\r\n\r\n"
@@ -384,6 +390,9 @@ class Net::HTTPGenericRequest
384
390
 
385
391
  def quote_string(str, charset)
386
392
  str = str.encode(charset, fallback:->(c){'&#%d;'%c.encode("UTF-8").ord}) if charset
393
+ if /[\r\n]/.match?(str)
394
+ raise ArgumentError, "multipart field name or filename cannot include CR/LF"
395
+ end
387
396
  str.gsub(/[\\"]/, '\\\\\&')
388
397
  end
389
398
 
@@ -193,11 +193,9 @@ module Net::HTTPHeader
193
193
  warn "net/http: nil HTTP header: #{key}", uplevel: 3 if $VERBOSE
194
194
  else
195
195
  value = value.strip # raise error for invalid byte sequences
196
- if key.to_s.bytesize > MAX_KEY_LENGTH
197
- raise ArgumentError, "too long (#{key.bytesize} bytes) header: #{key[0, 30].inspect}..."
198
- end
196
+ validate_field_name(key)
199
197
  if value.to_s.bytesize > MAX_FIELD_LENGTH
200
- 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})"
201
199
  end
202
200
  if value.count("\r\n") > 0
203
201
  raise ArgumentError, "header #{key} has field value #{value.inspect}, this cannot include CR/LF"
@@ -263,21 +261,34 @@ module Net::HTTPHeader
263
261
  def add_field(key, val)
264
262
  stringified_downcased_key = key.downcase.to_s
265
263
  if @header.key?(stringified_downcased_key)
266
- append_field_value(@header[stringified_downcased_key], val)
264
+ append_field_value(@header[stringified_downcased_key], val, key)
267
265
  else
268
266
  set_field(key, val)
269
267
  end
270
268
  end
271
269
 
272
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
+
273
280
  private def set_field(key, val)
281
+ validate_field_name(key)
274
282
  case val
275
283
  when Enumerable
276
284
  ary = []
277
- append_field_value(ary, val)
285
+ append_field_value(ary, val, key)
278
286
  @header[key.downcase.to_s] = ary
279
287
  else
280
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
281
292
  if val.b.count("\r\n") > 0
282
293
  raise ArgumentError, 'header field value cannot include CR/LF'
283
294
  end
@@ -285,12 +296,15 @@ module Net::HTTPHeader
285
296
  end
286
297
  end
287
298
 
288
- private def append_field_value(ary, val)
299
+ private def append_field_value(ary, val, key)
289
300
  case val
290
301
  when Enumerable
291
- val.each{|x| append_field_value(ary, x)}
302
+ val.each{|x| append_field_value(ary, x, key)}
292
303
  else
293
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
294
308
  if /[\r\n]/n.match?(val.b)
295
309
  raise ArgumentError, 'header field value cannot include CR/LF'
296
310
  end
@@ -617,11 +631,35 @@ module Net::HTTPHeader
617
631
  # res = Net::HTTP.get_response(hostname, '/todos/1')
618
632
  # res.content_length # => nil
619
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 Net::HTTPHeaderSyntaxError is raised.
638
+ # See {RFC 9110 Section 8.6}[https://www.rfc-editor.org/rfc/rfc9110.html#section-8.6].
620
639
  def content_length
621
- return nil unless key?('Content-Length')
622
- len = self['Content-Length'].slice(/\d+/) or
623
- raise Net::HTTPHeaderSyntaxError, 'wrong Content-Length format'
624
- 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 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 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 Net::HTTPHeaderSyntaxError,
660
+ "wrong Content-Length format: #{length}"
661
+ end
662
+ length.to_i
625
663
  end
626
664
 
627
665
  # Sets the value of field <tt>'Content-Length'</tt> to the given numeric;
@@ -647,7 +685,7 @@ module Net::HTTPHeader
647
685
  end
648
686
 
649
687
  # Returns +true+ if field <tt>'Transfer-Encoding'</tt>
650
- # exists and has value <tt>'chunked'</tt>,
688
+ # exists and has <tt>'chunked'</tt> as its final transfer coding,
651
689
  # +false+ otherwise;
652
690
  # see {Transfer-Encoding response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#transfer-encoding-response-header]:
653
691
  #
@@ -655,10 +693,13 @@ module Net::HTTPHeader
655
693
  # res['Transfer-Encoding'] # => "chunked"
656
694
  # res.chunked? # => true
657
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].
658
699
  def chunked?
659
700
  return false unless @header['transfer-encoding']
660
701
  field = self['Transfer-Encoding']
661
- (/(?:\A|[^\-\w])chunked(?![\-\w])/i =~ field) ? true : false
702
+ (/(?:\A|[^\-\w])chunked(?![\-\w])\s*(?:,\s*)*\z/i =~ field) ? true : false
662
703
  end
663
704
 
664
705
  # Returns a Range object representing the value of field
@@ -774,7 +815,7 @@ module Net::HTTPHeader
774
815
  #
775
816
  # Net::HTTPHeader#content_type= is an alias for Net::HTTPHeader#set_content_type.
776
817
  def set_content_type(type, params = {})
777
- @header['content-type'] = [type + params.map{|k,v|"; #{k}=#{v}"}.join('')]
818
+ set_field('Content-Type', type + params.map{|k,v|"; #{k}=#{v}"}.join(''))
778
819
  end
779
820
 
780
821
  alias content_type= set_content_type
@@ -61,6 +61,7 @@
61
61
  # - Net::HTTP::Options
62
62
  # - Net::HTTP::Trace
63
63
  # - Net::HTTP::Patch
64
+ # - 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
  #
@@ -52,9 +52,9 @@ end
52
52
  #
53
53
  # - Request body: optional.
54
54
  # - Response body: no.
55
- # - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: yes.
56
- # - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
57
- # - {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.
58
58
  #
59
59
  # Related:
60
60
  #
@@ -87,9 +87,9 @@ end
87
87
  #
88
88
  # - Request body: yes.
89
89
  # - Response body: yes.
90
- # - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: no.
91
- # - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: no.
92
- # - {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.
93
93
  #
94
94
  # Related:
95
95
  #
@@ -123,9 +123,9 @@ end
123
123
  #
124
124
  # - Request body: yes.
125
125
  # - Response body: yes.
126
- # - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: no.
127
- # - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
128
- # - {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.
129
129
  #
130
130
  # Related:
131
131
  #
@@ -157,9 +157,9 @@ end
157
157
  #
158
158
  # - Request body: optional.
159
159
  # - Response body: yes.
160
- # - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: no.
161
- # - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
162
- # - {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.
163
163
  #
164
164
  # Related:
165
165
  #
@@ -189,9 +189,9 @@ end
189
189
  #
190
190
  # - Request body: optional.
191
191
  # - Response body: yes.
192
- # - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: yes.
193
- # - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
194
- # - {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.
195
195
  #
196
196
  # Related:
197
197
  #
@@ -221,9 +221,9 @@ end
221
221
  #
222
222
  # - Request body: no.
223
223
  # - Response body: yes.
224
- # - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: yes.
225
- # - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
226
- # - {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.
227
227
  #
228
228
  # Related:
229
229
  #
@@ -256,9 +256,9 @@ end
256
256
  #
257
257
  # - Request body: yes.
258
258
  # - Response body: yes.
259
- # - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: no.
260
- # - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: no.
261
- # - {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.
262
262
  #
263
263
  # Related:
264
264
  #
@@ -271,6 +271,41 @@ class Net::HTTP::Patch < Net::HTTPRequest
271
271
  RESPONSE_HAS_BODY = true
272
272
  end
273
273
 
274
+ # \Class for representing
275
+ # {HTTP method QUERY}[https://www.rfc-editor.org/rfc/rfc10008.html]:
276
+ #
277
+ # require 'net/http'
278
+ # uri = URI('http://example.com')
279
+ # hostname = uri.hostname # => "example.com"
280
+ # uri.path = '/posts'
281
+ # req = Net::HTTP::Query.new(uri) # => #<Net::HTTP::Query QUERY>
282
+ # req.body = '{"title": "foo","body": "bar","userId": 1}'
283
+ # req.content_type = 'application/json'
284
+ # res = Net::HTTP.start(hostname) do |http|
285
+ # http.request(req)
286
+ # end
287
+ #
288
+ # See {Request Headers}[rdoc-ref: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
+ # - Net::HTTP#query: sends +QUERY+ request, returns response object.
301
+ #
302
+ class Net::HTTP::Query < Net::HTTPRequest
303
+ # :stopdoc:
304
+ METHOD = 'QUERY'
305
+ REQUEST_HAS_BODY = true
306
+ RESPONSE_HAS_BODY = true
307
+ end
308
+
274
309
  #
275
310
  # WebDAV methods --- RFC2518
276
311
  #
@@ -133,6 +133,13 @@
133
133
  # there is a protocol error.
134
134
  #
135
135
  class 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,11 +159,17 @@ class 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 Net::ReadLimitExceeded
165
+ raise Net::HTTPBadResponse, 'response line too long'
166
+ end
167
+
155
168
  private
156
169
  # :stopdoc:
157
170
 
158
171
  def read_status_line(sock)
159
- str = sock.readline
172
+ str = read_line(sock, MAX_RESPONSE_HEADER_LENGTH).chop
160
173
  m = /\AHTTP(?:\/(\d+\.\d+))?\s+(\d\d\d)(?:\s+(.*))?\z/in.match(str) or
161
174
  raise Net::HTTPBadResponse, "wrong status line: #{str.dump}"
162
175
  m.captures
@@ -170,12 +183,19 @@ class Net::HTTPResponse
170
183
 
171
184
  def each_response_header(sock)
172
185
  key = value = nil
186
+ remaining = MAX_RESPONSE_HEADER_LENGTH
173
187
  while true
174
- line = sock.readuntil("\n", true).sub(/\s+\z/, '')
188
+ line = read_line(sock, MAX_RESPONSE_HEADER_LENGTH, true)
189
+ remaining -= line.bytesize
190
+ raise Net::HTTPBadResponse, 'response header too large' if remaining < 0
191
+ line = line.chomp
175
192
  break if line.empty?
176
193
  if line[0] == ?\s or line[0] == ?\t and value
177
- value << ' ' unless value.empty?
178
- value << line.strip
194
+ folded = line.strip
195
+ unless folded.empty?
196
+ value << ' ' unless value.empty?
197
+ value << folded
198
+ end
179
199
  else
180
200
  yield key, value if key
181
201
  key, value = line.strip.split(/\s*:\s*/, 2)
@@ -599,15 +619,20 @@ class Net::HTTPResponse
599
619
 
600
620
  @socket = inflate_body_io
601
621
 
602
- clen = content_length()
603
- if clen
604
- @socket.read clen, dest, @ignore_eof
605
- return
606
- end
607
- clen = range_length()
608
- if clen
609
- @socket.read clen, dest
610
- 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
611
636
  end
612
637
  @socket.read_all dest
613
638
  end
@@ -623,7 +648,7 @@ class Net::HTTPResponse
623
648
  def read_chunked(dest, chunk_data_io) # :nodoc:
624
649
  total = 0
625
650
  while true
626
- line = @socket.readline
651
+ line = self.class.read_line(@socket, MAX_RESPONSE_HEADER_LENGTH).chop
627
652
  hexlen = line.slice(/[0-9a-fA-F]+/) or
628
653
  raise Net::HTTPBadResponse, "wrong chunk size line: #{line}"
629
654
  len = hexlen.hex
@@ -635,7 +660,7 @@ class Net::HTTPResponse
635
660
  @socket.read 2 # \r\n
636
661
  end
637
662
  end
638
- until @socket.readline.empty?
663
+ until self.class.read_line(@socket, MAX_RESPONSE_HEADER_LENGTH).chop.empty?
639
664
  # none
640
665
  end
641
666
  end
data/lib/net/http.rb CHANGED
@@ -37,7 +37,7 @@ module Net #:nodoc:
37
37
  # For information about \HTTP, see:
38
38
  #
39
39
  # - {Hypertext Transfer Protocol}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol].
40
- # - {Technical overview}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Technical_overview].
40
+ # - {Technology}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Technology].
41
41
  #
42
42
  # == About the Examples
43
43
  #
@@ -72,7 +72,7 @@ module Net #:nodoc:
72
72
  #
73
73
  # - If performance is important, consider using sessions, which lower request overhead.
74
74
  # This {session}[rdoc-ref:Net::HTTP@Sessions] has multiple requests for
75
- # {HTTP methods}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods]
75
+ # {HTTP methods}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Method]
76
76
  # and {WebDAV methods}[https://en.wikipedia.org/wiki/WebDAV#Implementation]:
77
77
  #
78
78
  # Net::HTTP.start(hostname) do |http|
@@ -82,6 +82,7 @@ module Net #:nodoc:
82
82
  # body = 'Some text'
83
83
  # http.post(path, body) # Can also have a block.
84
84
  # http.put(path, body)
85
+ # http.query(path, body) # Can also have a block.
85
86
  # http.delete(path)
86
87
  # http.options(path)
87
88
  # http.trace(path)
@@ -198,7 +199,7 @@ module Net #:nodoc:
198
199
  # In the block, you can use these instance methods,
199
200
  # each of which that sends a single request:
200
201
  #
201
- # - {HTTP methods}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods]:
202
+ # - {HTTP methods}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Method]:
202
203
  #
203
204
  # - #get, #request_get: GET.
204
205
  # - #head, #request_head: HEAD.
@@ -207,6 +208,7 @@ module Net #:nodoc:
207
208
  # - #options: OPTIONS.
208
209
  # - #trace: TRACE.
209
210
  # - #patch: PATCH.
211
+ # - #query, #request_query: QUERY.
210
212
  #
211
213
  # - {WebDAV methods}[https://en.wikipedia.org/wiki/WebDAV#Implementation]:
212
214
  #
@@ -447,7 +449,7 @@ module Net #:nodoc:
447
449
  # if the response has header <tt>'Content-Range'</tt>.
448
450
  #
449
451
  # Otherwise decompression (or not) depends on the value of header
450
- # {Content-Encoding}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-encoding-response-header]:
452
+ # {Content-Encoding}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Content-Encoding_2]:
451
453
  #
452
454
  # - <tt>'deflate'</tt>, <tt>'gzip'</tt>, or <tt>'x-gzip'</tt>:
453
455
  # decompresses the body and deletes the header.
@@ -460,7 +462,7 @@ module Net #:nodoc:
460
462
  #
461
463
  # First, what's elsewhere. Class Net::HTTP:
462
464
  #
463
- # - Inherits from {class Object}[https://docs.ruby-lang.org/en/master/Object.html#class-Object-label-What-27s+Here].
465
+ # - Inherits from {class Object}[https://docs.ruby-lang.org/en/master/Object.html#class-object-whats-here].
464
466
  #
465
467
  # This is a categorized summary of methods and attributes.
466
468
  #
@@ -553,6 +555,8 @@ module Net #:nodoc:
553
555
  # Sends a PROPPATCH request and returns a response object.
554
556
  # - {#put}[rdoc-ref:Net::HTTP#put]:
555
557
  # Sends a PUT request and returns a response object.
558
+ # - {#query}[rdoc-ref:Net::HTTP#query]:
559
+ # Sends a QUERY request and returns a response object.
556
560
  # - {#request}[rdoc-ref:Net::HTTP#request]:
557
561
  # Sends a request and returns a response object.
558
562
  # - {#request_get}[rdoc-ref:Net::HTTP#request_get]:
@@ -724,7 +728,7 @@ module Net #:nodoc:
724
728
  class HTTP < Protocol
725
729
 
726
730
  # :stopdoc:
727
- VERSION = "0.9.1"
731
+ VERSION = "0.10.0"
728
732
  HTTPVersion = '1.1'
729
733
  begin
730
734
  require 'zlib'
@@ -1304,7 +1308,7 @@ module Net #:nodoc:
1304
1308
 
1305
1309
  # Sets whether to determine the proxy from environment variable
1306
1310
  # '<tt>ENV['http_proxy']</tt>';
1307
- # see {Proxy Using ENV['http_proxy']}[rdoc-ref:Net::HTTP@Proxy+Using+-27ENV-5B-27http_proxy-27-5D-27].
1311
+ # see {Proxy Using ENV}[rdoc-ref:Net::HTTP@Proxy+Using+ENVHTTPProxy].
1308
1312
  attr_writer :proxy_from_env
1309
1313
 
1310
1314
  # Sets the proxy address;
@@ -1550,11 +1554,11 @@ module Net #:nodoc:
1550
1554
  attr_accessor :cert_store
1551
1555
 
1552
1556
  # Sets or returns the available SSL ciphers.
1553
- # See {OpenSSL::SSL::SSLContext#ciphers=}[OpenSSL::SSL::SSL::Context#ciphers=].
1557
+ # See {OpenSSL::SSL::SSLContext#ciphers=}[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html#method-i-ciphers-3D].
1554
1558
  attr_accessor :ciphers
1555
1559
 
1556
1560
  # Sets or returns the extra X509 certificates to be added to the certificate chain.
1557
- # See {OpenSSL::SSL::SSLContext#add_certificate}[OpenSSL::SSL::SSL::Context#add_certificate].
1561
+ # See {OpenSSL::SSL::SSLContext#add_certificate}[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html#method-i-add_certificate].
1558
1562
  attr_accessor :extra_chain_cert
1559
1563
 
1560
1564
  # Sets or returns the OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object.
@@ -1564,15 +1568,15 @@ module Net #:nodoc:
1564
1568
  attr_accessor :ssl_timeout
1565
1569
 
1566
1570
  # Sets or returns the SSL version.
1567
- # See {OpenSSL::SSL::SSLContext#ssl_version=}[OpenSSL::SSL::SSL::Context#ssl_version=].
1571
+ # See {OpenSSL::SSL::SSLContext#ssl_version=}[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html#method-i-ssl_version-3D].
1568
1572
  attr_accessor :ssl_version
1569
1573
 
1570
1574
  # Sets or returns the minimum SSL version.
1571
- # See {OpenSSL::SSL::SSLContext#min_version=}[OpenSSL::SSL::SSL::Context#min_version=].
1575
+ # See {OpenSSL::SSL::SSLContext#min_version=}[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html#method-i-min_version-3D].
1572
1576
  attr_accessor :min_version
1573
1577
 
1574
1578
  # Sets or returns the maximum SSL version.
1575
- # See {OpenSSL::SSL::SSLContext#max_version=}[OpenSSL::SSL::SSL::Context#max_version=].
1579
+ # See {OpenSSL::SSL::SSLContext#max_version=}[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html#method-i-max_version-3D].
1576
1580
  attr_accessor :max_version
1577
1581
 
1578
1582
  # Sets or returns the callback for the server certification verification.
@@ -1588,7 +1592,7 @@ module Net #:nodoc:
1588
1592
 
1589
1593
  # Sets or returns whether to verify that the server certificate is valid
1590
1594
  # for the hostname.
1591
- # See {OpenSSL::SSL::SSLContext#verify_hostname=}[OpenSSL::SSL::SSL::Context#verify_hostname=].
1595
+ # See {OpenSSL::SSL::SSLContext#verify_hostname=}[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html#attribute-i-verify_hostname].
1592
1596
  attr_accessor :verify_hostname
1593
1597
 
1594
1598
  # Returns the X509 certificate chain (an array of strings)
@@ -2101,6 +2105,25 @@ module Net #:nodoc:
2101
2105
  send_entity(path, data, initheader, dest, Patch, &block)
2102
2106
  end
2103
2107
 
2108
+ # Sends a QUERY request to the server;
2109
+ # returns an instance of a subclass of Net::HTTPResponse.
2110
+ #
2111
+ # The request is based on the Net::HTTP::Query object
2112
+ # created from string +path+, string +data+, and initial headers hash +initheader+.
2113
+ #
2114
+ # data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
2115
+ # http = Net::HTTP.new(hostname)
2116
+ # http.query('/todos/1', data) # => #<Net::HTTPOK 200 OK readbody=true>
2117
+ #
2118
+ # Related:
2119
+ #
2120
+ # - Net::HTTP::Query: request class for \HTTP method QUERY.
2121
+ # - Net::HTTP.query: sends QUERY request, returns response body.
2122
+ #
2123
+ def query(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+
2124
+ send_entity(path, data, initheader, dest, Query, &block)
2125
+ end
2126
+
2104
2127
  # Sends a PUT request to the server;
2105
2128
  # returns an instance of a subclass of Net::HTTPResponse.
2106
2129
  #
@@ -2335,6 +2358,36 @@ module Net #:nodoc:
2335
2358
  request Put.new(path, initheader), data, &block
2336
2359
  end
2337
2360
 
2361
+ # Sends a QUERY request to the server;
2362
+ # returns an instance of a subclass of Net::HTTPResponse.
2363
+ #
2364
+ # The request is based on the Net::HTTP::Query object
2365
+ # created from string +path+, string +body+, and initial headers hash +initheader+.
2366
+ #
2367
+ # http = Net::HTTP.new(hostname)
2368
+ # http.query('/todos/1', 'xyzzy')
2369
+ # # => #<Net::HTTPOK 200 OK readbody=true>
2370
+ #
2371
+ # With no block given, returns the response object:
2372
+ #
2373
+ # http = Net::HTTP.new(hostname)
2374
+ # http.request_query('/todos') # => #<Net::HTTPOK 200 OK readbody=true>
2375
+ #
2376
+ # With a block given, calls the block with the response object
2377
+ # and returns the response object:
2378
+ #
2379
+ # http.request_query('/todos') do |res|
2380
+ # p res
2381
+ # end # => #<Net::HTTPOK 200 OK readbody=true>
2382
+ #
2383
+ # Output:
2384
+ #
2385
+ # #<Net::HTTPOK 200 OK readbody=false>
2386
+ #
2387
+ def request_query(path, data, initheader = nil, &block) # :yield: +response+
2388
+ request Query.new(path, initheader), data, &block
2389
+ end
2390
+
2338
2391
  alias get2 request_get #:nodoc: obsolete
2339
2392
  alias head2 request_head #:nodoc: obsolete
2340
2393
  alias post2 request_post #:nodoc: obsolete
@@ -2430,7 +2483,7 @@ module Net #:nodoc:
2430
2483
 
2431
2484
  # :stopdoc:
2432
2485
 
2433
- IDEMPOTENT_METHODS_ = %w/GET HEAD PUT DELETE OPTIONS TRACE/.freeze # :nodoc:
2486
+ IDEMPOTENT_METHODS_ = %w/GET HEAD PUT DELETE OPTIONS TRACE QUERY/.freeze # :nodoc:
2434
2487
 
2435
2488
  def transport_request(req)
2436
2489
  count = 0
@@ -2444,11 +2497,17 @@ module Net #:nodoc:
2444
2497
  # still read the received response.
2445
2498
  end
2446
2499
 
2500
+ informational_count = 0
2447
2501
  begin
2448
2502
  res = HTTPResponse.read_new(@socket)
2449
2503
  res.decode_content = req.decode_content
2450
2504
  res.body_encoding = @response_body_encoding
2451
2505
  res.ignore_eof = @ignore_eof
2506
+ if res.kind_of?(HTTPInformation)
2507
+ informational_count += 1
2508
+ raise HTTPBadResponse, 'too many informational responses' if
2509
+ informational_count > HTTPResponse::MAX_INFORMATIONAL_RESPONSES
2510
+ end
2452
2511
  end while res.kind_of?(HTTPInformation)
2453
2512
 
2454
2513
  res.uri = req.uri
data/sig/manifest.yaml ADDED
@@ -0,0 +1,3 @@
1
+ dependencies:
2
+ - name: net-protocol
3
+ - name: uri