Index: boto/s3/connection.py |
diff --git a/boto/s3/connection.py b/boto/s3/connection.py |
index 25ba4aba5a763de2784eabd2dd051308672d4a92..80209b7dbc5abbedd4170ee958201c9a808754f0 100644 |
--- a/boto/s3/connection.py |
+++ b/boto/s3/connection.py |
@@ -27,7 +27,6 @@ import time |
import boto.utils |
from boto.connection import AWSAuthConnection |
from boto import handler |
-from boto.provider import Provider |
from boto.s3.bucket import Bucket |
from boto.s3.key import Key |
from boto.resultset import ResultSet |
@@ -64,7 +63,10 @@ def assert_case_insensitive(f): |
return f(*args, **kwargs) |
return wrapper |
-class _CallingFormat: |
+class _CallingFormat(object): |
+ |
+ def get_bucket_server(self, server, bucket): |
+ return '' |
def build_url_base(self, connection, protocol, server, bucket, key=''): |
url_base = '%s://' % protocol |
@@ -79,12 +81,14 @@ class _CallingFormat: |
return self.get_bucket_server(server, bucket) |
def build_auth_path(self, bucket, key=''): |
+ key = boto.utils.get_utf8_value(key) |
path = '' |
if bucket != '': |
path = '/' + bucket |
return path + '/%s' % urllib.quote(key) |
def build_path_base(self, bucket, key=''): |
+ key = boto.utils.get_utf8_value(key) |
return '/%s' % urllib.quote(key) |
class SubdomainCallingFormat(_CallingFormat): |
@@ -105,15 +109,25 @@ class OrdinaryCallingFormat(_CallingFormat): |
return server |
def build_path_base(self, bucket, key=''): |
+ key = boto.utils.get_utf8_value(key) |
path_base = '/' |
if bucket: |
path_base += "%s/" % bucket |
return path_base + urllib.quote(key) |
+class ProtocolIndependentOrdinaryCallingFormat(OrdinaryCallingFormat): |
+ |
+ def build_url_base(self, connection, protocol, server, bucket, key=''): |
+ url_base = '//' |
+ url_base += self.build_host(server, bucket) |
+ url_base += connection.get_path(self.build_path_base(bucket, key)) |
+ return url_base |
+ |
class Location: |
DEFAULT = '' # US Classic Region |
EU = 'EU' |
USWest = 'us-west-1' |
+ APNortheast = 'ap-northeast-1' |
APSoutheast = 'ap-southeast-1' |
class S3Connection(AWSAuthConnection): |
@@ -125,15 +139,15 @@ class S3Connection(AWSAuthConnection): |
is_secure=True, port=None, proxy=None, proxy_port=None, |
proxy_user=None, proxy_pass=None, |
host=DefaultHost, debug=0, https_connection_factory=None, |
- calling_format=SubdomainCallingFormat(), path='/', provider='aws', |
- bucket_class=Bucket): |
+ calling_format=SubdomainCallingFormat(), path='/', |
+ provider='aws', bucket_class=Bucket, security_token=None): |
self.calling_format = calling_format |
self.bucket_class = bucket_class |
AWSAuthConnection.__init__(self, host, |
aws_access_key_id, aws_secret_access_key, |
is_secure, port, proxy, proxy_port, proxy_user, proxy_pass, |
debug=debug, https_connection_factory=https_connection_factory, |
- path=path, provider=provider) |
+ path=path, provider=provider, security_token=security_token) |
def _required_auth_capability(self): |
return ['s3'] |
@@ -143,7 +157,7 @@ class S3Connection(AWSAuthConnection): |
yield bucket |
def __contains__(self, bucket_name): |
- return not (self.lookup(bucket_name) is None) |
+ return not (self.lookup(bucket_name) is None) |
def set_bucket_class(self, bucket_class): |
""" |
@@ -170,8 +184,10 @@ class S3Connection(AWSAuthConnection): |
def build_post_form_args(self, bucket_name, key, expires_in = 6000, |
- acl = None, success_action_redirect = None, max_content_length = None, |
- http_method = "http", fields=None, conditions=None): |
+ acl = None, success_action_redirect = None, |
+ max_content_length = None, |
+ http_method = "http", fields=None, |
+ conditions=None): |
""" |
Taken from the AWS book Python examples and modified for use with boto |
This only returns the arguments required for the post form, not the actual form |
@@ -261,13 +277,22 @@ class S3Connection(AWSAuthConnection): |
return {"action": url, "fields": fields} |
- def generate_url(self, expires_in, method, bucket='', key='', |
- headers=None, query_auth=True, force_http=False): |
+ def generate_url(self, expires_in, method, bucket='', key='', headers=None, |
+ query_auth=True, force_http=False, response_headers=None): |
if not headers: |
headers = {} |
expires = int(time.time() + expires_in) |
auth_path = self.calling_format.build_auth_path(bucket, key) |
auth_path = self.get_path(auth_path) |
+ # Arguments to override response headers become part of the canonical |
+ # string to be signed. |
+ if response_headers: |
+ response_hdrs = ["%s=%s" % (k, v) for k, v in |
+ response_headers.items()] |
+ delimiter = '?' if '?' not in auth_path else '&' |
+ auth_path = "%s%s%s" % (auth_path, delimiter, '&'.join(response_hdrs)) |
+ else: |
+ response_headers = {} |
c_string = boto.utils.canonical_string(method, auth_path, headers, |
expires, self.provider) |
b64_hmac = self._auth_handler.sign_string(c_string) |
@@ -275,11 +300,13 @@ class S3Connection(AWSAuthConnection): |
self.calling_format.build_path_base(bucket, key) |
if query_auth: |
query_part = '?' + self.QueryString % (encoded_canonical, expires, |
- self.aws_access_key_id) |
- sec_hdr = self.provider.security_token_header |
- if sec_hdr in headers: |
- query_part += ('&%s=%s' % (sec_hdr, |
- urllib.quote(headers[sec_hdr]))); |
+ self.aws_access_key_id) |
+ # The response headers must also be GET parameters in the URL. |
+ headers.update(response_headers) |
+ hdrs = [ '%s=%s'%(name, urllib.quote(val)) for name,val in headers.items() ] |
+ q_str = '&'.join(hdrs) |
+ if q_str: |
+ query_part += '&' + q_str |
else: |
query_part = '' |
if force_http: |
@@ -304,11 +331,13 @@ class S3Connection(AWSAuthConnection): |
def get_canonical_user_id(self, headers=None): |
""" |
- Convenience method that returns the "CanonicalUserID" of the user who's credentials |
- are associated with the connection. The only way to get this value is to do a GET |
- request on the service which returns all buckets associated with the account. As part |
- of that response, the canonical userid is returned. This method simply does all of |
- that and then returns just the user id. |
+ Convenience method that returns the "CanonicalUserID" of the |
+ user who's credentials are associated with the connection. |
+ The only way to get this value is to do a GET request on the |
+ service which returns all buckets associated with the account. |
+ As part of that response, the canonical userid is returned. |
+ This method simply does all of that and then returns just the |
+ user id. |
:rtype: string |
:return: A string containing the canonical user id. |