From 2cdab4cab9c6de844da802c2bc546cf2e62a6288 Mon Sep 17 00:00:00 2001 From: MurphyMarkW Date: Mon, 29 Jun 2015 20:25:22 -0500 Subject: [PATCH 1/7] Fixes last-byte-pos interpretation. --- moto/s3/responses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moto/s3/responses.py b/moto/s3/responses.py index 3fe391cd3..f9e8f9e6d 100644 --- a/moto/s3/responses.py +++ b/moto/s3/responses.py @@ -252,7 +252,7 @@ class ResponseObject(_TemplateEnvironmentMixin): toint = lambda i: int(i) if i else None begin, end = map(toint, rspec.split('-')) if begin is not None: # byte range - end = last if end is None else end + end = last if end is None else min(end, last) elif end is not None: # suffix byte range begin = length - end end = last From f64d0b99ac044fc4a46174e860c4918d8843d42f Mon Sep 17 00:00:00 2001 From: MurphyMarkW Date: Mon, 29 Jun 2015 20:26:00 -0500 Subject: [PATCH 2/7] Tests for last-byte-pos behavior. --- tests/test_s3/test_s3.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_s3/test_s3.py b/tests/test_s3/test_s3.py index 662b22cbb..7af0ce8a6 100644 --- a/tests/test_s3/test_s3.py +++ b/tests/test_s3/test_s3.py @@ -793,6 +793,7 @@ def test_ranged_get(): key.set_contents_from_string(rep * 10) key.get_contents_as_string(headers={'Range': 'bytes=0-'}).should.equal(rep * 10) key.get_contents_as_string(headers={'Range': 'bytes=0-99'}).should.equal(rep * 10) + key.get_contents_as_string(headers={'Range': 'bytes=0-100'}).should.equal(rep * 10) key.get_contents_as_string(headers={'Range': 'bytes=0-0'}).should.equal(b'0') key.get_contents_as_string(headers={'Range': 'bytes=99-99'}).should.equal(b'9') key.get_contents_as_string(headers={'Range': 'bytes=50-54'}).should.equal(rep[:5]) From 723b743381432b4412629574dab92871c3a00746 Mon Sep 17 00:00:00 2001 From: MurphyMarkW Date: Tue, 30 Jun 2015 00:26:42 -0500 Subject: [PATCH 3/7] Modifies check for last-byte-pos. --- moto/s3/responses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moto/s3/responses.py b/moto/s3/responses.py index f9e8f9e6d..b6113fafe 100644 --- a/moto/s3/responses.py +++ b/moto/s3/responses.py @@ -258,7 +258,7 @@ class ResponseObject(_TemplateEnvironmentMixin): end = last else: return 400, headers, "" - if begin < 0 or end > length or begin > min(end, last): + if begin < 0 or end > last or begin > min(end, last): return 416, headers, "" headers['content-range'] = "bytes {0}-{1}/{2}".format( begin, end, length) From 10c3a37613676008ba3773513ee24c720dc4d279 Mon Sep 17 00:00:00 2001 From: MurphyMarkW Date: Tue, 30 Jun 2015 00:27:10 -0500 Subject: [PATCH 4/7] Adds test for explicit last-byte-pos > length. --- tests/test_s3/test_s3.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_s3/test_s3.py b/tests/test_s3/test_s3.py index 7af0ce8a6..bc0efce91 100644 --- a/tests/test_s3/test_s3.py +++ b/tests/test_s3/test_s3.py @@ -794,6 +794,7 @@ def test_ranged_get(): key.get_contents_as_string(headers={'Range': 'bytes=0-'}).should.equal(rep * 10) key.get_contents_as_string(headers={'Range': 'bytes=0-99'}).should.equal(rep * 10) key.get_contents_as_string(headers={'Range': 'bytes=0-100'}).should.equal(rep * 10) + key.get_contents_as_string(headers={'Range': 'bytes=0-700'}).should.equal(rep * 10) key.get_contents_as_string(headers={'Range': 'bytes=0-0'}).should.equal(b'0') key.get_contents_as_string(headers={'Range': 'bytes=99-99'}).should.equal(b'9') key.get_contents_as_string(headers={'Range': 'bytes=50-54'}).should.equal(rep[:5]) From b82d0264dce60a572df85b36d7bc35f971c9843c Mon Sep 17 00:00:00 2001 From: MurphyMarkW Date: Tue, 30 Jun 2015 02:04:30 -0500 Subject: [PATCH 5/7] Fixes suffix range requests to truncate ranges. --- moto/s3/responses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moto/s3/responses.py b/moto/s3/responses.py index b6113fafe..adaefc230 100644 --- a/moto/s3/responses.py +++ b/moto/s3/responses.py @@ -254,7 +254,7 @@ class ResponseObject(_TemplateEnvironmentMixin): if begin is not None: # byte range end = last if end is None else min(end, last) elif end is not None: # suffix byte range - begin = length - end + begin = length - min(end, length) end = last else: return 400, headers, "" From 0fcbdd52e063838a6d815cc8b3debd1383bb326d Mon Sep 17 00:00:00 2001 From: MurphyMarkW Date: Tue, 30 Jun 2015 02:04:58 -0500 Subject: [PATCH 6/7] Adds / moves around tests for different ranges. --- tests/test_s3/test_s3.py | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/tests/test_s3/test_s3.py b/tests/test_s3/test_s3.py index bc0efce91..ce9a10740 100644 --- a/tests/test_s3/test_s3.py +++ b/tests/test_s3/test_s3.py @@ -791,13 +791,35 @@ def test_ranged_get(): key.key = 'bigkey' rep = b"0123456789" key.set_contents_from_string(rep * 10) + + # Implicitly bounded range requests. key.get_contents_as_string(headers={'Range': 'bytes=0-'}).should.equal(rep * 10) + key.get_contents_as_string(headers={'Range': 'bytes=50-'}).should.equal(rep * 5) + key.get_contents_as_string(headers={'Range': 'bytes=99-'}).should.equal(rep[-1]) + + # Explicitly bounded range requests starting from the first byte. + key.get_contents_as_string(headers={'Range': 'bytes=0-0'}).should.equal(b'0') + key.get_contents_as_string(headers={'Range': 'bytes=0-49'}).should.equal(rep * 5) key.get_contents_as_string(headers={'Range': 'bytes=0-99'}).should.equal(rep * 10) key.get_contents_as_string(headers={'Range': 'bytes=0-100'}).should.equal(rep * 10) key.get_contents_as_string(headers={'Range': 'bytes=0-700'}).should.equal(rep * 10) - key.get_contents_as_string(headers={'Range': 'bytes=0-0'}).should.equal(b'0') - key.get_contents_as_string(headers={'Range': 'bytes=99-99'}).should.equal(b'9') + + # Explicitly bounded range requests starting from the / a middle byte. key.get_contents_as_string(headers={'Range': 'bytes=50-54'}).should.equal(rep[:5]) - key.get_contents_as_string(headers={'Range': 'bytes=50-'}).should.equal(rep * 5) + key.get_contents_as_string(headers={'Range': 'bytes=50-99'}).should.equal(rep * 5) + key.get_contents_as_string(headers={'Range': 'bytes=50-100'}).should.equal(rep * 5) + key.get_contents_as_string(headers={'Range': 'bytes=50-700'}).should.equal(rep * 5) + + # Explicitly bounded range requests starting from the last byte. + key.get_contents_as_string(headers={'Range': 'bytes=99-99'}).should.equal(b'9') + key.get_contents_as_string(headers={'Range': 'bytes=99-100'}).should.equal(b'9') + key.get_contents_as_string(headers={'Range': 'bytes=99-700'}).should.equal(b'9') + + # Suffix range requests. + key.get_contents_as_string(headers={'Range': 'bytes=-1'}).should.equal(rep[-1]) key.get_contents_as_string(headers={'Range': 'bytes=-60'}).should.equal(rep * 6) + key.get_contents_as_string(headers={'Range': 'bytes=-100'}).should.equal(rep * 10) + key.get_contents_as_string(headers={'Range': 'bytes=-101'}).should.equal(rep * 10) + key.get_contents_as_string(headers={'Range': 'bytes=-700'}).should.equal(rep * 10) + key.size.should.equal(100) From 5b9c874a2384d325253a3916ab7791c5c40bc986 Mon Sep 17 00:00:00 2001 From: MurphyMarkW Date: Tue, 30 Jun 2015 13:02:38 -0500 Subject: [PATCH 7/7] Ensures all tests compare using bytes / bytearrays in 3.x. --- tests/test_s3/test_s3.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_s3/test_s3.py b/tests/test_s3/test_s3.py index ce9a10740..43f25c748 100644 --- a/tests/test_s3/test_s3.py +++ b/tests/test_s3/test_s3.py @@ -795,7 +795,7 @@ def test_ranged_get(): # Implicitly bounded range requests. key.get_contents_as_string(headers={'Range': 'bytes=0-'}).should.equal(rep * 10) key.get_contents_as_string(headers={'Range': 'bytes=50-'}).should.equal(rep * 5) - key.get_contents_as_string(headers={'Range': 'bytes=99-'}).should.equal(rep[-1]) + key.get_contents_as_string(headers={'Range': 'bytes=99-'}).should.equal(b'9') # Explicitly bounded range requests starting from the first byte. key.get_contents_as_string(headers={'Range': 'bytes=0-0'}).should.equal(b'0') @@ -816,7 +816,7 @@ def test_ranged_get(): key.get_contents_as_string(headers={'Range': 'bytes=99-700'}).should.equal(b'9') # Suffix range requests. - key.get_contents_as_string(headers={'Range': 'bytes=-1'}).should.equal(rep[-1]) + key.get_contents_as_string(headers={'Range': 'bytes=-1'}).should.equal(b'9') key.get_contents_as_string(headers={'Range': 'bytes=-60'}).should.equal(rep * 6) key.get_contents_as_string(headers={'Range': 'bytes=-100'}).should.equal(rep * 10) key.get_contents_as_string(headers={'Range': 'bytes=-101'}).should.equal(rep * 10)