diff options
author | raggi <jftucker@gmail.com> | 2010-10-03 21:58:32 -0300 |
---|---|---|
committer | raggi <jftucker@gmail.com> | 2010-10-03 21:58:32 -0300 |
commit | 623a5fb85e645ba043e2c21039637de69a472d0b (patch) | |
tree | 7fcbb25e19032eaa2e0f903732317a8a5a239557 | |
parent | 94555f91770cbd22551c5ff58f943c9b51b4a849 (diff) | |
download | rack-623a5fb85e645ba043e2c21039637de69a472d0b.tar.gz |
Move Rack::File.byte_ranges to Rack::Utils
-rw-r--r-- | lib/rack/file.rb | 34 | ||||
-rw-r--r-- | lib/rack/utils.rb | 33 | ||||
-rw-r--r-- | test/spec_file.rb | 41 | ||||
-rw-r--r-- | test/spec_utils.rb | 43 |
4 files changed, 77 insertions, 74 deletions
diff --git a/lib/rack/file.rb b/lib/rack/file.rb index fc79fa2f..9acf05d1 100644 --- a/lib/rack/file.rb +++ b/lib/rack/file.rb @@ -62,7 +62,7 @@ module Rack self ] - ranges = self.class.byte_ranges(env, size) + ranges = Rack::Utils.byte_ranges(env, size) if ranges.nil? || ranges.length > 1 # No ranges, or multiple ranges (which we don't support): # TODO: Support multiple byte-ranges @@ -99,38 +99,6 @@ module Rack end end - # Parses the "Range:" header, if present, into an array of Range objects. - # Returns nil if the header is missing or syntactically invalid. - # Returns an empty array if none of the ranges are satisfiable. - def self.byte_ranges(env, size) - # See <http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35> - http_range = env['HTTP_RANGE'] - return nil unless http_range - ranges = [] - http_range.split(/,\s*/).each do |range_spec| - matches = range_spec.match(/bytes=(\d*)-(\d*)/) - return nil unless matches - r0,r1 = matches[1], matches[2] - if r0.empty? - return nil if r1.empty? - # suffix-byte-range-spec, represents trailing suffix of file - r0 = [size - r1.to_i, 0].max - r1 = size - 1 - else - r0 = r0.to_i - if r1.empty? - r1 = size - 1 - else - r1 = r1.to_i - return nil if r1 < r0 # backwards range is syntactically invalid - r1 = size-1 if r1 >= size - end - end - ranges << (r0..r1) if r0 <= r1 - end - ranges - end - private def fail(status, body) diff --git a/lib/rack/utils.rb b/lib/rack/utils.rb index 05175a1d..bf044207 100644 --- a/lib/rack/utils.rb +++ b/lib/rack/utils.rb @@ -262,6 +262,39 @@ module Rack end module_function :rfc2822 + # Parses the "Range:" header, if present, into an array of Range objects. + # Returns nil if the header is missing or syntactically invalid. + # Returns an empty array if none of the ranges are satisfiable. + def byte_ranges(env, size) + # See <http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35> + http_range = env['HTTP_RANGE'] + return nil unless http_range + ranges = [] + http_range.split(/,\s*/).each do |range_spec| + matches = range_spec.match(/bytes=(\d*)-(\d*)/) + return nil unless matches + r0,r1 = matches[1], matches[2] + if r0.empty? + return nil if r1.empty? + # suffix-byte-range-spec, represents trailing suffix of file + r0 = [size - r1.to_i, 0].max + r1 = size - 1 + else + r0 = r0.to_i + if r1.empty? + r1 = size - 1 + else + r1 = r1.to_i + return nil if r1 < r0 # backwards range is syntactically invalid + r1 = size-1 if r1 >= size + end + end + ranges << (r0..r1) if r0 <= r1 + end + ranges + end + module_function :byte_ranges + # Context allows the use of a compatible middleware at different points # in a request handling stack. A compatible middleware must define # #context which should take the arguments env and app. The first of which diff --git a/test/spec_file.rb b/test/spec_file.rb index 433a2d6f..f2e2506b 100644 --- a/test/spec_file.rb +++ b/test/spec_file.rb @@ -69,47 +69,6 @@ describe Rack::File do body.to_path.should.equal path end - should "ignore missing or syntactically invalid byte ranges" do - Rack::File.byte_ranges({},500).should.equal nil - Rack::File.byte_ranges({"HTTP_RANGE" => "foobar"},500).should.equal nil - Rack::File.byte_ranges({"HTTP_RANGE" => "furlongs=123-456"},500).should.equal nil - Rack::File.byte_ranges({"HTTP_RANGE" => "bytes="},500).should.equal nil - Rack::File.byte_ranges({"HTTP_RANGE" => "bytes=-"},500).should.equal nil - Rack::File.byte_ranges({"HTTP_RANGE" => "bytes=123,456"},500).should.equal nil - # A range of non-positive length is syntactically invalid and ignored: - Rack::File.byte_ranges({"HTTP_RANGE" => "bytes=456-123"},500).should.equal nil - Rack::File.byte_ranges({"HTTP_RANGE" => "bytes=456-455"},500).should.equal nil - end - - should "parse simple byte ranges" do - Rack::File.byte_ranges({"HTTP_RANGE" => "bytes=123-456"},500).should.equal [(123..456)] - Rack::File.byte_ranges({"HTTP_RANGE" => "bytes=123-"},500).should.equal [(123..499)] - Rack::File.byte_ranges({"HTTP_RANGE" => "bytes=-100"},500).should.equal [(400..499)] - Rack::File.byte_ranges({"HTTP_RANGE" => "bytes=0-0"},500).should.equal [(0..0)] - Rack::File.byte_ranges({"HTTP_RANGE" => "bytes=499-499"},500).should.equal [(499..499)] - end - - should "truncate byte ranges" do - Rack::File.byte_ranges({"HTTP_RANGE" => "bytes=123-999"},500).should.equal [(123..499)] - Rack::File.byte_ranges({"HTTP_RANGE" => "bytes=600-999"},500).should.equal [] - Rack::File.byte_ranges({"HTTP_RANGE" => "bytes=-999"},500).should.equal [(0..499)] - end - - should "ignore unsatisfiable byte ranges" do - Rack::File.byte_ranges({"HTTP_RANGE" => "bytes=500-501"},500).should.equal [] - Rack::File.byte_ranges({"HTTP_RANGE" => "bytes=500-"},500).should.equal [] - Rack::File.byte_ranges({"HTTP_RANGE" => "bytes=999-"},500).should.equal [] - Rack::File.byte_ranges({"HTTP_RANGE" => "bytes=-0"},500).should.equal [] - end - - should "handle byte ranges of empty files" do - Rack::File.byte_ranges({"HTTP_RANGE" => "bytes=123-456"},0).should.equal [] - Rack::File.byte_ranges({"HTTP_RANGE" => "bytes=0-"},0).should.equal [] - Rack::File.byte_ranges({"HTTP_RANGE" => "bytes=-100"},0).should.equal [] - Rack::File.byte_ranges({"HTTP_RANGE" => "bytes=0-0"},0).should.equal [] - Rack::File.byte_ranges({"HTTP_RANGE" => "bytes=-0"},0).should.equal [] - end - should "return correct byte range in body" do env = Rack::MockRequest.env_for("/cgi/test") env["HTTP_RANGE"] = "bytes=22-33" diff --git a/test/spec_utils.rb b/test/spec_utils.rb index 82580d13..79d0f1c1 100644 --- a/test/spec_utils.rb +++ b/test/spec_utils.rb @@ -226,6 +226,49 @@ describe Rack::Utils do end end +describe Rack::Utils, "byte_range" do + should "ignore missing or syntactically invalid byte ranges" do + Rack::Utils.byte_ranges({},500).should.equal nil + Rack::Utils.byte_ranges({"HTTP_RANGE" => "foobar"},500).should.equal nil + Rack::Utils.byte_ranges({"HTTP_RANGE" => "furlongs=123-456"},500).should.equal nil + Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes="},500).should.equal nil + Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-"},500).should.equal nil + Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123,456"},500).should.equal nil + # A range of non-positive length is syntactically invalid and ignored: + Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=456-123"},500).should.equal nil + Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=456-455"},500).should.equal nil + end + + should "parse simple byte ranges" do + Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123-456"},500).should.equal [(123..456)] + Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123-"},500).should.equal [(123..499)] + Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-100"},500).should.equal [(400..499)] + Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=0-0"},500).should.equal [(0..0)] + Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=499-499"},500).should.equal [(499..499)] + end + + should "truncate byte ranges" do + Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123-999"},500).should.equal [(123..499)] + Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=600-999"},500).should.equal [] + Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-999"},500).should.equal [(0..499)] + end + + should "ignore unsatisfiable byte ranges" do + Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=500-501"},500).should.equal [] + Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=500-"},500).should.equal [] + Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=999-"},500).should.equal [] + Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-0"},500).should.equal [] + end + + should "handle byte ranges of empty files" do + Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123-456"},0).should.equal [] + Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=0-"},0).should.equal [] + Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-100"},0).should.equal [] + Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=0-0"},0).should.equal [] + Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-0"},0).should.equal [] + end +end + describe Rack::Utils::HeaderHash do should "retain header case" do h = Rack::Utils::HeaderHash.new("Content-MD5" => "d5ff4e2a0 ...") |