import email import io from urllib.request import BaseHandler, URLError, url2pathname, addinfourl import boto.s3.connection class _FileLikeKey(io.BufferedIOBase): def __init__(self, key): self.read = key.read class S3Handler(BaseHandler): def s3_open(self, req): # The implementation was inspired mainly by the code behind # urllib.request.FileHandler.file_open(). bucket_name = req.host key_name = url2pathname(req.selector)[1:] if not bucket_name or not key_name: raise URLError('url must be in the format s3:///') try: conn = self._conn except AttributeError: conn = self._conn = boto.s3.connection.S3Connection() bucket = conn.get_bucket(bucket_name, validate=False) key = bucket.get_key(key_name) origurl = 's3://{}/{}'.format(bucket_name, key_name) if key is None: raise URLError('no such resource: {}'.format(origurl)) headers = [ ('Content-type', key.content_type), ('Content-encoding', key.content_encoding), ('Content-language', key.content_language), ('Content-length', key.size), ('Etag', key.etag), ('Last-modified', key.last_modified), ] headers = email.message_from_string( '\n'.join('{}: {}'.format(key, value) for key, value in headers if value is not None)) return addinfourl(_FileLikeKey(key), headers, origurl)