about summary refs log tree commit homepage
path: root/lib/rainbows/response/range.rb
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2010-07-22 05:42:16 +0000
committerEric Wong <normalperson@yhbt.net>2010-07-22 09:09:37 +0000
commit416d3a0f868571319a2b29b0034d2dba68e4d5b3 (patch)
tree081bdbdcce23063667c707212ceda45bbc322675 /lib/rainbows/response/range.rb
parent015daa81f26afc59d1da857b8bbedfb80eb532b1 (diff)
downloadrainbows-416d3a0f868571319a2b29b0034d2dba68e4d5b3.tar.gz
The FileStreamer class of EventMachine (and by extension
NeverBlock) unfortunately doesn't handle this.  It's possible
to do with Revactor (since it uses Rev under the covers),
but we'll support what we can easily for now.
Diffstat (limited to 'lib/rainbows/response/range.rb')
-rw-r--r--lib/rainbows/response/range.rb34
1 files changed, 34 insertions, 0 deletions
diff --git a/lib/rainbows/response/range.rb b/lib/rainbows/response/range.rb
new file mode 100644
index 0000000..4c0d4a1
--- /dev/null
+++ b/lib/rainbows/response/range.rb
@@ -0,0 +1,34 @@
+# -*- encoding: binary -*-
+# :enddoc:
+module Rainbows::Response::Range
+  HTTP_RANGE = 'HTTP_RANGE'
+  Content_Range = 'Content-Range'.freeze
+  Content_Length = 'Content-Length'.freeze
+
+  # This does not support multipart responses (does anybody actually
+  # use those?) +headers+ is always a Rack::Utils::HeaderHash
+  def parse_range(env, status, headers)
+    if 200 == status.to_i &&
+        (clen = headers[Content_Length]) &&
+        /\Abytes=(\d+-\d*|\d*-\d+)\z/ =~ env[HTTP_RANGE]
+      a, b = $1.split(/-/)
+      clen = clen.to_i
+      if b.nil? # bytes=M-
+        offset = a.to_i
+        count = clen - offset
+      elsif a.empty? # bytes=-N
+        offset = clen - b.to_i
+        count = clen - offset
+      else  # bytes=M-N
+        offset = a.to_i
+        count = b.to_i + 1 - offset
+      end
+      raise Rainbows::Response416 if count <= 0 || offset >= clen
+      count = clen if count > clen
+      headers[Content_Length] = count.to_s
+      headers[Content_Range] = "bytes #{offset}-#{offset+count-1}/#{clen}"
+      [ status, offset, count ]
+    end
+    # nil if no status
+  end
+end