Merge pull request #298 from kouk/ranged_get

support ranged get in S3
This commit is contained in:
Steve Pulec 2015-02-14 08:35:23 -05:00
commit 53a6d2466b
2 changed files with 46 additions and 2 deletions

View File

@ -215,6 +215,28 @@ class ResponseObject(_TemplateEnvironmentMixin):
return 200, headers, template.render(deleted=deleted_names, delete_errors=error_names)
def _handle_range_header(self, request, headers, response_content):
length = len(response_content)
last = length - 1
_, rspec = request.headers.get('range').split('=')
if ',' in rspec:
raise NotImplementedError(
"Multiple range specifiers not supported")
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
elif end is not None: # suffix byte range
begin = length - end
end = last
else:
return 400, headers, ""
if begin < 0 or end > length or begin > min(end, last):
return 416, headers, ""
headers['content-range'] = "bytes {0}-{1}/{2}".format(
begin, end, length)
return 206, headers, response_content[begin:end + 1]
def key_response(self, request, full_url, headers):
try:
response = self._key_response(request, full_url, headers)
@ -222,10 +244,14 @@ class ResponseObject(_TemplateEnvironmentMixin):
response = s3error.code, headers, s3error.description
if isinstance(response, six.string_types):
return 200, headers, response
status_code = 200
response_content = response
else:
status_code, headers, response_content = response
return status_code, headers, response_content
if status_code == 200 and 'range' in request.headers:
return self._handle_range_header(request, headers, response_content)
return status_code, headers, response_content
def _key_response(self, request, full_url, headers):
parsed_url = urlparse(full_url)

View File

@ -753,3 +753,21 @@ def test_bucket_location():
conn = boto.s3.connect_to_region("us-west-2")
bucket = conn.create_bucket('mybucket')
bucket.get_location().should.equal("us-west-2")
@mock_s3
def test_ranged_get():
conn = boto.connect_s3()
bucket = conn.create_bucket('mybucket')
key = Key(bucket)
key.key = 'bigkey'
rep = b"0123456789"
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-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])
key.get_contents_as_string(headers={'Range': 'bytes=50-'}).should.equal(rep * 5)
key.get_contents_as_string(headers={'Range': 'bytes=-60'}).should.equal(rep * 6)
key.size.should.equal(100)