[前][次][番号順一覧][スレッド一覧]

ruby-changes:23713

From: naruse <ko1@a...>
Date: Wed, 23 May 2012 22:09:37 +0900 (JST)
Subject: [ruby-changes:23713] naruse:r35764 (trunk): * lib/net/http/header.rb (Net::HTTPHeader#range): fix broken parser of

naruse	2012-05-23 22:09:26 +0900 (Wed, 23 May 2012)

  New Revision: 35764

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=35764

  Log:
    * lib/net/http/header.rb (Net::HTTPHeader#range): fix broken parser of
      HTTP Range request. Old one can't parse invalid specs and multiple
      specs correctly.

  Modified files:
    trunk/ChangeLog
    trunk/lib/net/http/header.rb
    trunk/test/net/http/test_httpheader.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 35763)
+++ ChangeLog	(revision 35764)
@@ -1,3 +1,9 @@
+Wed May 23 22:06:14 2012  NARUSE, Yui  <naruse@r...>
+
+	* lib/net/http/header.rb (Net::HTTPHeader#range): fix broken parser of
+	  HTTP Range request. Old one can't parse invalid specs and multiple
+	  specs correctly.
+
 Wed May 23 10:18:54 2012  NAKAMURA Usaku  <usa@r...>
 
 	* win32/win32.c (finish_overlapped_socket, overlapped_socket_io):
Index: lib/net/http/header.rb
===================================================================
--- lib/net/http/header.rb	(revision 35763)
+++ lib/net/http/header.rb	(revision 35764)
@@ -177,18 +177,44 @@
   # HTTP header field, or +nil+ if there is no such header.
   def range
     return nil unless @header['range']
-    self['Range'].split(/,/).map {|spec|
-      m = /bytes\s*=\s*(\d+)?\s*-\s*(\d+)?/i.match(spec) or
-              raise HTTPHeaderSyntaxError, "wrong Range: #{spec}"
+
+    value = self['Range']
+    # byte-range-set = *( "," OWS ) ( byte-range-spec / suffix-byte-range-spec )
+    #   *( OWS "," [ OWS ( byte-range-spec / suffix-byte-range-spec ) ] )
+    # corrected collected ABNF
+    # http://tools.ietf.org/html/draft-ietf-httpbis-p5-range-19#section-5.4.1
+    # http://tools.ietf.org/html/draft-ietf-httpbis-p5-range-19#appendix-C
+    # http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-19#section-3.2.5
+    unless /\Abytes=((?:,[ \t]*)*(?:\d+-\d*|-\d+)(?:[ \t]*,(?:[ \t]*\d+-\d*|-\d+)?)*)\z/ =~ value
+      raise Net::HTTPHeaderSyntaxError, "invalid syntax for byte-ranges-specifier: '#{value}'"
+    end
+
+    byte_range_set = $1
+    result = byte_range_set.split(/,/).map {|spec|
+      m = /(\d+)?\s*-\s*(\d+)?/i.match(spec) or
+              raise Net::HTTPHeaderSyntaxError, "invalid byte-range-spec: '#{spec}'"
       d1 = m[1].to_i
       d2 = m[2].to_i
-      if    m[1] and m[2] then  d1..d2
-      elsif m[1]          then  d1..-1
-      elsif          m[2] then -d2..-1
+      if m[1] and m[2]
+        if d1 > d2
+          raise Net::HTTPHeaderSyntaxError, "last-byte-pos MUST greater than or equal to first-byte-pos but '#{spec}'"
+        end
+        d1..d2
+      elsif m[1]
+        d1..-1
+      elsif m[2]
+        -d2..-1
       else
-        raise HTTPHeaderSyntaxError, 'range is not specified'
+        raise Net::HTTPHeaderSyntaxError, 'range is not specified'
       end
     }
+    # if result.empty?
+    # byte-range-set must include at least one byte-range-spec or suffix-byte-range-spec
+    # but above regexp already denies it.
+    if result.size == 1 && result[0].begin == 0 && result[0].end == -1
+      raise Net::HTTPHeaderSyntaxError, 'only one suffix-byte-range-spec with zero suffix-length'
+    end
+    result
   end
 
   # Sets the HTTP Range: header.
Index: test/net/http/test_httpheader.rb
===================================================================
--- test/net/http/test_httpheader.rb	(revision 35763)
+++ test/net/http/test_httpheader.rb	(revision 35764)
@@ -156,17 +156,34 @@
   end
 
   def test_range
-    try_range(1..5,     '1-5')
-    try_range(234..567, '234-567')
-    try_range(-5..-1,   '-5')
-    try_range(1..-1,    '1-')
+    try_range([1..5],     '1-5')
+    try_invalid_range('5-1')
+    try_range([234..567], '234-567')
+    try_range([-5..-1],   '-5')
+    try_invalid_range('-0')
+    try_range([1..-1],    '1-')
+    try_range([0..0,-1..-1],    '0-0,-1')
+    try_range([1..2, 3..4], '1-2,3-4')
+    try_range([1..2, 3..4], '1-2 , 3-4')
+    try_range([1..2, 1..4], '1-2,1-4')
+
+    try_invalid_range('invalid')
+    try_invalid_range(' 12-')
+    try_invalid_range('12- ')
+    try_invalid_range('123-abc')
+    try_invalid_range('abc-123')
   end
 
   def try_range(r, s)
     @c['range'] = "bytes=#{s}"
-    assert_equal r, Array(@c.range)[0]
+    assert_equal r, @c.range
   end
 
+  def try_invalid_range(s)
+    @c['range'] = "bytes=#{s}"
+    assert_raise(Net::HTTPHeaderSyntaxError, s){ @c.range }
+  end
+
   def test_range=
     @c.range = 0..499
     assert_equal 'bytes=0-499', @c['range']

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]