]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/commitdiff
filenode.py: Fix partial HTTP Range header handling according to RFC2616
authorfrancois <francois@ctrlaltdel.ch>
Tue, 18 Nov 2008 14:41:35 +0000 (07:41 -0700)
committerfrancois <francois@ctrlaltdel.ch>
Tue, 18 Nov 2008 14:41:35 +0000 (07:41 -0700)
Tahoe webapi was failing on HTTP request containing a partial Range header.
This change allows movies players like mplayer to seek in movie files stored in
tahoe.

Associated tests for GET and HEAD methods are also included

src/allmydata/test/test_web.py
src/allmydata/web/filenode.py

index 6e7a117502c7207cf9d4d2ef043ffc7693ca4393..64e6a59e7b2432e26e95d2c1db2c892edd7a16b4 100644 (file)
@@ -552,6 +552,20 @@ class Web(WebMixin, testutil.StallMixin, unittest.TestCase):
         d.addCallback(_got)
         return d
 
+    def test_GET_FILEURL_partial_range(self):
+        headers = {"range": "bytes=5-"}
+        length  = len(self.BAR_CONTENTS)
+        d = self.GET(self.public_url + "/foo/bar.txt", headers=headers,
+                     return_response=True)
+        def _got((res, status, headers)):
+            self.failUnlessEqual(int(status), 206)
+            self.failUnless(headers.has_key("content-range"))
+            self.failUnlessEqual(headers["content-range"][0],
+                                 "bytes 5-%d/%d" % (length-1, length))
+            self.failUnlessEqual(res, self.BAR_CONTENTS[5:])
+        d.addCallback(_got)
+        return d
+
     def test_HEAD_FILEURL_range(self):
         headers = {"range": "bytes=1-10"}
         d = self.HEAD(self.public_url + "/foo/bar.txt", headers=headers,
@@ -565,6 +579,19 @@ class Web(WebMixin, testutil.StallMixin, unittest.TestCase):
         d.addCallback(_got)
         return d
 
+    def test_HEAD_FILEURL_partial_range(self):
+        headers = {"range": "bytes=5-"}
+        length  = len(self.BAR_CONTENTS)
+        d = self.HEAD(self.public_url + "/foo/bar.txt", headers=headers,
+                     return_response=True)
+        def _got((res, status, headers)):
+            self.failUnlessEqual(int(status), 206)
+            self.failUnless(headers.has_key("content-range"))
+            self.failUnlessEqual(headers["content-range"][0],
+                                 "bytes 5-%d/%d" % (length-1, length))
+        d.addCallback(_got)
+        return d
+
     def test_GET_FILEURL_range_bad(self):
         headers = {"range": "BOGUS=fizbop-quarnak"}
         d = self.shouldFail2(error.Error, "test_GET_FILEURL_range_bad",
index 4c20079449e26471b73b82b4788725d1fb4aca58..e8d522290c851307dfc65b0122dfbfbd0845c626 100644 (file)
@@ -374,7 +374,14 @@ class FileDownloader(rend.Page):
             start, end = bytesrange[1].split('-')
             if start:
                 offset = int(start)
-            if end:
+                if not end:
+                    # RFC 2616 says:
+                    #
+                    # "If the last-byte-pos value is absent, or if the value is
+                    # greater than or equal to the current length of the
+                    # entity-body, last-byte-pos is taken to be equal to one less
+                    # than the current length of the entity- body in bytes."
+                    end = filesize - 1
                 size = int(end) - offset + 1
             req.setResponseCode(http.PARTIAL_CONTENT)
             req.setHeader('content-range',"bytes %s-%s/%s" %