From be66aa8e76d2994eb8a0a944e0dea26ffbb3c159 Mon Sep 17 00:00:00 2001 From: Samuel Merritt Date: Thu, 20 Aug 2015 13:24:38 -0700 Subject: [PATCH] Fix 500 for bogus Range request to 0-byte object. The proxy was trying to pop a byterange off a Range header that didn't contain syntactically-valid byteranges. This worked about as well as you'd expect. Now we detect the bogus value and remove the header entirely. Change-Id: I24b92f900d33ec79880c7db2870378489d5a6810 --- swift/proxy/controllers/base.py | 7 +++++- test/unit/proxy/test_server.py | 40 +++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/swift/proxy/controllers/base.py b/swift/proxy/controllers/base.py index 554469cc06..70940f9c16 100644 --- a/swift/proxy/controllers/base.py +++ b/swift/proxy/controllers/base.py @@ -696,7 +696,12 @@ def pop_range(self): If we have no Range header, this is a no-op. """ if 'Range' in self.backend_headers: - req_range = Range(self.backend_headers['Range']) + try: + req_range = Range(self.backend_headers['Range']) + except ValueError: + # there's a Range header, but it's garbage, so get rid of it + self.backend_headers.pop('Range') + return begin, end = req_range.ranges.pop(0) if len(req_range.ranges) > 0: self.backend_headers['Range'] = str(req_range) diff --git a/test/unit/proxy/test_server.py b/test/unit/proxy/test_server.py index 04eb3d6eb7..539d6ef102 100644 --- a/test/unit/proxy/test_server.py +++ b/test/unit/proxy/test_server.py @@ -1457,6 +1457,46 @@ def test_GET_ranges(self): 'bytes 4123-4523/5800') self.assertEqual(second_range_body, obj[4123:4524]) + @unpatch_policies + def test_GET_bad_range_zero_byte(self): + prolis = _test_sockets[0] + prosrv = _test_servers[0] + sock = connect_tcp(('localhost', prolis.getsockname()[1])) + fd = sock.makefile() + + path = '/v1/a/c/o.zerobyte' + fd.write('PUT %s HTTP/1.1\r\n' + 'Host: localhost\r\n' + 'Connection: close\r\n' + 'X-Storage-Token: t\r\n' + 'Content-Length: 0\r\n' + 'Content-Type: application/octet-stream\r\n' + '\r\n' % (path,)) + fd.flush() + headers = readuntil2crlfs(fd) + exp = 'HTTP/1.1 201' + self.assertEqual(headers[:len(exp)], exp) + + # bad byte-range + req = Request.blank( + path, + environ={'REQUEST_METHOD': 'GET'}, + headers={'Content-Type': 'application/octet-stream', + 'Range': 'bytes=spaghetti-carbonara'}) + res = req.get_response(prosrv) + self.assertEqual(res.status_int, 200) + self.assertEqual(res.body, '') + + # not a byte-range + req = Request.blank( + path, + environ={'REQUEST_METHOD': 'GET'}, + headers={'Content-Type': 'application/octet-stream', + 'Range': 'Kotta'}) + res = req.get_response(prosrv) + self.assertEqual(res.status_int, 200) + self.assertEqual(res.body, '') + @unpatch_policies def test_GET_ranges_resuming(self): prolis = _test_sockets[0]