net-http 0.1.1 → 0.3.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: a306a97039eef1800016a611dee36fa0d342b5f234bf6e0a512d981abd12ce8d
4
- data.tar.gz: 39583accf1ec3b888c4e368eb0d3cf41add46ebfd18a6d7dcbea1cc69712f219
3
+ metadata.gz: 83d503ad3cfa67ad617fbfe5f168b22759f54eba460aceedba49245dd09d36d0
4
+ data.tar.gz: 57ae006e8c77d3d1bac46a6693e6377ad38e0d690669b9f1a2a447926e2a626b
5
5
  SHA512:
6
- metadata.gz: 21ab016c4d12100c405aec7b8426d81f4a88ac2bc7019353d729837d17e3a95899df04818f787319c32f29b349b7527b7903a65a897e8353382d5461070465c7
7
- data.tar.gz: 38593be710550d52aaf31d50d746e7f5da92fb1c3d4b451968bda3c0af9b033acefc2fd404f6a083025d340d8abebd7d2061fa77343f081b78bd48c19aa82b39
6
+ metadata.gz: 131cb53d9b3ae85db640cf78f1a43f660908cfd8f753cd41f5bea7179a92e5efd328e2f91fced1bc4e8cc69152ca9d95bc32544031cc79654c157f4573506a86
7
+ data.tar.gz: 3753128576e206b26a75f2828b5502cfc341854273f385a0771a988dfa69a6482351767f607d4bee211dbdac94937980b69c10c57e1cf69df41147a31621f2ce
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: 'github-actions'
4
+ directory: '/'
5
+ schedule:
6
+ interval: 'weekly'
@@ -7,18 +7,16 @@ jobs:
7
7
  name: build (${{ matrix.ruby }} / ${{ matrix.os }})
8
8
  strategy:
9
9
  matrix:
10
- ruby: [ 2.7, 2.6, head ]
10
+ ruby: [ 3.1, '3.0', 2.7, 2.6, head ]
11
11
  os: [ ubuntu-latest, macos-latest ]
12
12
  runs-on: ${{ matrix.os }}
13
13
  steps:
14
- - uses: actions/checkout@master
14
+ - uses: actions/checkout@v3
15
15
  - name: Set up Ruby
16
16
  uses: ruby/setup-ruby@v1
17
17
  with:
18
18
  ruby-version: ${{ matrix.ruby }}
19
19
  - name: Install dependencies
20
- run: |
21
- gem install bundler --no-document
22
- bundle install
20
+ run: bundle install
23
21
  - name: Run test
24
22
  run: rake test
data/Gemfile CHANGED
@@ -4,3 +4,4 @@ gemspec
4
4
 
5
5
  gem "rake"
6
6
  gem "test-unit"
7
+ gem "webrick"
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Net::Http
1
+ # Net::HTTP
2
2
 
3
3
  Net::HTTP provides a rich library which can be used to build HTTP
4
4
  user-agents. For more details about HTTP see
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ end
9
9
 
10
10
  task :sync_tool do
11
11
  require 'fileutils'
12
- FileUtils.cp "../ruby/tool/lib/test/unit/core_assertions.rb", "./test/lib"
12
+ FileUtils.cp "../ruby/tool/lib/core_assertions.rb", "./test/lib"
13
13
  FileUtils.cp "../ruby/tool/lib/envutil.rb", "./test/lib"
14
14
  FileUtils.cp "../ruby/tool/lib/find_executable.rb", "./test/lib"
15
15
  end
@@ -5,22 +5,36 @@
5
5
 
6
6
  class Net::HTTP
7
7
  ProxyMod = ProxyDelta
8
- end
9
-
10
- module Net
11
- HTTPSession = Net::HTTP
8
+ deprecate_constant :ProxyMod
12
9
  end
13
10
 
14
11
  module Net::NetPrivate
15
12
  HTTPRequest = ::Net::HTTPRequest
13
+ deprecate_constant :HTTPRequest
16
14
  end
17
15
 
18
- Net::HTTPInformationCode = Net::HTTPInformation
19
- Net::HTTPSuccessCode = Net::HTTPSuccess
20
- Net::HTTPRedirectionCode = Net::HTTPRedirection
21
- Net::HTTPRetriableCode = Net::HTTPRedirection
22
- Net::HTTPClientErrorCode = Net::HTTPClientError
23
- Net::HTTPFatalErrorCode = Net::HTTPClientError
24
- Net::HTTPServerErrorCode = Net::HTTPServerError
25
- Net::HTTPResponceReceiver = Net::HTTPResponse
16
+ module Net
17
+ HTTPSession = HTTP
26
18
 
19
+ HTTPInformationCode = HTTPInformation
20
+ HTTPSuccessCode = HTTPSuccess
21
+ HTTPRedirectionCode = HTTPRedirection
22
+ HTTPRetriableCode = HTTPRedirection
23
+ HTTPClientErrorCode = HTTPClientError
24
+ HTTPFatalErrorCode = HTTPClientError
25
+ HTTPServerErrorCode = HTTPServerError
26
+ HTTPResponseReceiver = HTTPResponse
27
+
28
+ HTTPResponceReceiver = HTTPResponse # Typo since 2001
29
+
30
+ deprecate_constant :HTTPSession,
31
+ :HTTPInformationCode,
32
+ :HTTPSuccessCode,
33
+ :HTTPRedirectionCode,
34
+ :HTTPRetriableCode,
35
+ :HTTPClientErrorCode,
36
+ :HTTPFatalErrorCode,
37
+ :HTTPServerErrorCode,
38
+ :HTTPResponseReceiver,
39
+ :HTTPResponceReceiver
40
+ end
@@ -1,33 +1,34 @@
1
1
  # frozen_string_literal: false
2
- # Net::HTTP exception class.
3
- # You cannot use Net::HTTPExceptions directly; instead, you must use
4
- # its subclasses.
5
- module Net::HTTPExceptions
6
- def initialize(msg, res) #:nodoc:
7
- super msg
8
- @response = res
2
+ module Net
3
+ # Net::HTTP exception class.
4
+ # You cannot use Net::HTTPExceptions directly; instead, you must use
5
+ # its subclasses.
6
+ module HTTPExceptions
7
+ def initialize(msg, res) #:nodoc:
8
+ super msg
9
+ @response = res
10
+ end
11
+ attr_reader :response
12
+ alias data response #:nodoc: obsolete
9
13
  end
10
- attr_reader :response
11
- alias data response #:nodoc: obsolete
12
- end
13
- class Net::HTTPError < Net::ProtocolError
14
- include Net::HTTPExceptions
15
- end
16
- class Net::HTTPRetriableError < Net::ProtoRetriableError
17
- include Net::HTTPExceptions
18
- end
19
- class Net::HTTPServerException < Net::ProtoServerError
20
- # We cannot use the name "HTTPServerError", it is the name of the response.
21
- include Net::HTTPExceptions
22
- end
23
14
 
24
- # for compatibility
25
- Net::HTTPClientException = Net::HTTPServerException
15
+ class HTTPError < ProtocolError
16
+ include HTTPExceptions
17
+ end
26
18
 
27
- class Net::HTTPFatalError < Net::ProtoFatalError
28
- include Net::HTTPExceptions
29
- end
19
+ class HTTPRetriableError < ProtoRetriableError
20
+ include HTTPExceptions
21
+ end
30
22
 
31
- module Net
23
+ class HTTPClientException < ProtoServerError
24
+ include HTTPExceptions
25
+ end
26
+
27
+ class HTTPFatalError < ProtoFatalError
28
+ include HTTPExceptions
29
+ end
30
+
31
+ # We cannot use the name "HTTPServerError", it is the name of the response.
32
+ HTTPServerException = HTTPClientException # :nodoc:
32
33
  deprecate_constant(:HTTPServerException)
33
34
  end
@@ -15,7 +15,8 @@ class Net::HTTPGenericRequest
15
15
 
16
16
  if URI === uri_or_path then
17
17
  raise ArgumentError, "not an HTTP URI" unless URI::HTTP === uri_or_path
18
- raise ArgumentError, "no host component for URI" unless uri_or_path.hostname
18
+ hostname = uri_or_path.hostname
19
+ raise ArgumentError, "no host component for URI" unless (hostname && hostname.length > 0)
19
20
  @uri = uri_or_path.dup
20
21
  host = @uri.hostname.dup
21
22
  host << ":".freeze << @uri.port.to_s if @uri.port != @uri.default_port
@@ -31,12 +32,12 @@ class Net::HTTPGenericRequest
31
32
 
32
33
  @decode_content = false
33
34
 
34
- if @response_has_body and Net::HTTP::HAVE_ZLIB then
35
+ if Net::HTTP::HAVE_ZLIB then
35
36
  if !initheader ||
36
37
  !initheader.keys.any? { |k|
37
38
  %w[accept-encoding range].include? k.downcase
38
39
  } then
39
- @decode_content = true
40
+ @decode_content = true if @response_has_body
40
41
  initheader = initheader ? initheader.dup : {}
41
42
  initheader["accept-encoding"] =
42
43
  "gzip;q=1.0,deflate;q=0.6,identity;q=0.3"
@@ -143,7 +144,7 @@ class Net::HTTPGenericRequest
143
144
  end
144
145
 
145
146
  if host = self['host']
146
- host.sub!(/:.*/s, ''.freeze)
147
+ host.sub!(/:.*/m, ''.freeze)
147
148
  elsif host = @uri.host
148
149
  else
149
150
  host = addr
@@ -202,9 +203,7 @@ class Net::HTTPGenericRequest
202
203
  IO.copy_stream(f, chunker)
203
204
  chunker.finish
204
205
  else
205
- # copy_stream can sendfile() to sock.io unless we use SSL.
206
- # If sock.io is an SSLSocket, copy_stream will hit SSL_write()
207
- IO.copy_stream(f, sock.io)
206
+ IO.copy_stream(f, sock)
208
207
  end
209
208
  end
210
209
 
@@ -338,9 +338,10 @@ module Net::HTTPHeader
338
338
  # fits inside the full entity body, as range of byte offsets.
339
339
  def content_range
340
340
  return nil unless @header['content-range']
341
- m = %r<bytes\s+(\d+)-(\d+)/(\d+|\*)>i.match(self['Content-Range']) or
341
+ m = %r<\A\s*(\w+)\s+(\d+)-(\d+)/(\d+|\*)>.match(self['Content-Range']) or
342
342
  raise Net::HTTPHeaderSyntaxError, 'wrong Content-Range format'
343
- m[1].to_i .. m[2].to_i
343
+ return unless m[1] == 'bytes'
344
+ m[2].to_i .. m[3].to_i
344
345
  end
345
346
 
346
347
  # The length of the range represented in Content-Range: header.
@@ -84,6 +84,8 @@ class Net::HTTPResponse
84
84
  @read = false
85
85
  @uri = nil
86
86
  @decode_content = false
87
+ @body_encoding = false
88
+ @ignore_eof = true
87
89
  end
88
90
 
89
91
  # The HTTP version supported by the server.
@@ -106,6 +108,22 @@ class Net::HTTPResponse
106
108
  # Accept-Encoding header from the user.
107
109
  attr_accessor :decode_content
108
110
 
111
+ # The encoding to use for the response body. If Encoding, use that encoding.
112
+ # If other true value, attempt to detect the appropriate encoding, and use
113
+ # that.
114
+ attr_reader :body_encoding
115
+
116
+ # Set the encoding to use for the response body. If given a String, find
117
+ # the related Encoding.
118
+ def body_encoding=(value)
119
+ value = Encoding.find(value) if value.is_a?(String)
120
+ @body_encoding = value
121
+ end
122
+
123
+ # Whether to ignore EOF when reading bodies with a specified Content-Length
124
+ # header.
125
+ attr_accessor :ignore_eof
126
+
109
127
  def inspect
110
128
  "#<#{self.class} #{@code} #{@message} readbody=#{@read}>"
111
129
  end
@@ -214,6 +232,17 @@ class Net::HTTPResponse
214
232
  end
215
233
  @read = true
216
234
 
235
+ case enc = @body_encoding
236
+ when Encoding, false, nil
237
+ # Encoding: force given encoding
238
+ # false/nil: do not force encoding
239
+ else
240
+ # other value: detect encoding from body
241
+ enc = detect_encoding(@body)
242
+ end
243
+
244
+ @body.force_encoding(enc) if enc
245
+
217
246
  @body
218
247
  end
219
248
 
@@ -245,6 +274,141 @@ class Net::HTTPResponse
245
274
 
246
275
  private
247
276
 
277
+ # :nodoc:
278
+ def detect_encoding(str, encoding=nil)
279
+ if encoding
280
+ elsif encoding = type_params['charset']
281
+ elsif encoding = check_bom(str)
282
+ else
283
+ encoding = case content_type&.downcase
284
+ when %r{text/x(?:ht)?ml|application/(?:[^+]+\+)?xml}
285
+ /\A<xml[ \t\r\n]+
286
+ version[ \t\r\n]*=[ \t\r\n]*(?:"[0-9.]+"|'[0-9.]*')[ \t\r\n]+
287
+ encoding[ \t\r\n]*=[ \t\r\n]*
288
+ (?:"([A-Za-z][\-A-Za-z0-9._]*)"|'([A-Za-z][\-A-Za-z0-9._]*)')/x =~ str
289
+ encoding = $1 || $2 || Encoding::UTF_8
290
+ when %r{text/html.*}
291
+ sniff_encoding(str)
292
+ end
293
+ end
294
+ return encoding
295
+ end
296
+
297
+ # :nodoc:
298
+ def sniff_encoding(str, encoding=nil)
299
+ # the encoding sniffing algorithm
300
+ # http://www.w3.org/TR/html5/parsing.html#determining-the-character-encoding
301
+ if enc = scanning_meta(str)
302
+ enc
303
+ # 6. last visited page or something
304
+ # 7. frequency
305
+ elsif str.ascii_only?
306
+ Encoding::US_ASCII
307
+ elsif str.dup.force_encoding(Encoding::UTF_8).valid_encoding?
308
+ Encoding::UTF_8
309
+ end
310
+ # 8. implementation-defined or user-specified
311
+ end
312
+
313
+ # :nodoc:
314
+ def check_bom(str)
315
+ case str.byteslice(0, 2)
316
+ when "\xFE\xFF"
317
+ return Encoding::UTF_16BE
318
+ when "\xFF\xFE"
319
+ return Encoding::UTF_16LE
320
+ end
321
+ if "\xEF\xBB\xBF" == str.byteslice(0, 3)
322
+ return Encoding::UTF_8
323
+ end
324
+ nil
325
+ end
326
+
327
+ # :nodoc:
328
+ def scanning_meta(str)
329
+ require 'strscan'
330
+ ss = StringScanner.new(str)
331
+ if ss.scan_until(/<meta[\t\n\f\r ]*/)
332
+ attrs = {} # attribute_list
333
+ got_pragma = false
334
+ need_pragma = nil
335
+ charset = nil
336
+
337
+ # step: Attributes
338
+ while attr = get_attribute(ss)
339
+ name, value = *attr
340
+ next if attrs[name]
341
+ attrs[name] = true
342
+ case name
343
+ when 'http-equiv'
344
+ got_pragma = true if value == 'content-type'
345
+ when 'content'
346
+ encoding = extracting_encodings_from_meta_elements(value)
347
+ unless charset
348
+ charset = encoding
349
+ end
350
+ need_pragma = true
351
+ when 'charset'
352
+ need_pragma = false
353
+ charset = value
354
+ end
355
+ end
356
+
357
+ # step: Processing
358
+ return if need_pragma.nil?
359
+ return if need_pragma && !got_pragma
360
+
361
+ charset = Encoding.find(charset) rescue nil
362
+ return unless charset
363
+ charset = Encoding::UTF_8 if charset == Encoding::UTF_16
364
+ return charset # tentative
365
+ end
366
+ nil
367
+ end
368
+
369
+ def get_attribute(ss)
370
+ ss.scan(/[\t\n\f\r \/]*/)
371
+ if ss.peek(1) == '>'
372
+ ss.getch
373
+ return nil
374
+ end
375
+ name = ss.scan(/[^=\t\n\f\r \/>]*/)
376
+ name.downcase!
377
+ raise if name.empty?
378
+ ss.skip(/[\t\n\f\r ]*/)
379
+ if ss.getch != '='
380
+ value = ''
381
+ return [name, value]
382
+ end
383
+ ss.skip(/[\t\n\f\r ]*/)
384
+ case ss.peek(1)
385
+ when '"'
386
+ ss.getch
387
+ value = ss.scan(/[^"]+/)
388
+ value.downcase!
389
+ ss.getch
390
+ when "'"
391
+ ss.getch
392
+ value = ss.scan(/[^']+/)
393
+ value.downcase!
394
+ ss.getch
395
+ when '>'
396
+ value = ''
397
+ else
398
+ value = ss.scan(/[^\t\n\f\r >]+/)
399
+ value.downcase!
400
+ end
401
+ [name, value]
402
+ end
403
+
404
+ def extracting_encodings_from_meta_elements(value)
405
+ # http://dev.w3.org/html5/spec/fetching-resources.html#algorithm-for-extracting-an-encoding-from-a-meta-element
406
+ if /charset[\t\n\f\r ]*=(?:"([^"]*)"|'([^']*)'|["']|\z|([^\t\n\f\r ;]+))/i =~ value
407
+ return $1 || $2 || $3
408
+ end
409
+ return nil
410
+ end
411
+
248
412
  ##
249
413
  # Checks for a supported Content-Encoding header and yields an Inflate
250
414
  # wrapper for this response's socket when zlib is present. If the
@@ -272,6 +436,9 @@ class Net::HTTPResponse
272
436
  ensure
273
437
  begin
274
438
  inflate_body_io.finish
439
+ if self['content-length']
440
+ self['content-length'] = inflate_body_io.bytes_inflated.to_s
441
+ end
275
442
  rescue => err
276
443
  # Ignore #finish's error if there is an exception from yield
277
444
  raise err if success
@@ -297,7 +464,7 @@ class Net::HTTPResponse
297
464
 
298
465
  clen = content_length()
299
466
  if clen
300
- @socket.read clen, dest, true # ignore EOF
467
+ @socket.read clen, dest, @ignore_eof
301
468
  return
302
469
  end
303
470
  clen = range_length()
@@ -373,6 +540,14 @@ class Net::HTTPResponse
373
540
  @inflate.finish
374
541
  end
375
542
 
543
+ ##
544
+ # The number of bytes inflated, used to update the Content-Length of
545
+ # the response.
546
+
547
+ def bytes_inflated
548
+ @inflate.total_out
549
+ end
550
+
376
551
  ##
377
552
  # Returns a Net::ReadAdapter that inflates each read chunk into +dest+.
378
553
  #