Package s3 :: Module generator
[hide private]
[frames] | no frames]

Source Code for Module s3.generator

  1  import s3 
  2  import re 
  3  import sha 
  4  import hmac 
  5  import time 
  6  import base64 
  7  import urllib 
  8   
  9  PORTS_BY_SECURITY = { True: 443, False: 80 } 
 10   
 11  DEFAULT_EXPIRES_IN = 60 
 12   
13 -class S3Generator(object):
14 """ 15 Generator class 16 17 Objects of this class are used for generating authenticated URLs for accessing 18 Amazon's S3 service. 19 """ 20
21 - def __init__(self, pub_key, priv_key, secure=True, host=s3.DEFAULT_HOST, port=None):
22 self._pub_key = pub_key 23 self._priv_key = priv_key 24 self._host = host 25 if not port: 26 self._port = PORTS_BY_SECURITY[secure] 27 else: 28 self._port = port 29 if (secure): 30 self.protocol = 'https' 31 else: 32 self.protocol = 'http' 33 self._secure = secure 34 self.server_name = "%s:%d" % (self._host, self._port) 35 self._expires_in = DEFAULT_EXPIRES_IN 36 self._expires = None
37
38 - def set_expires_in(self, expires_in):
39 """ 40 Set relative expiration time from the url creation moment. 41 42 @param expires_in: Relative expiration time 43 @type expires_in: int 44 """ 45 self._expires_in = expires_in 46 self._expires = None
47
48 - def set_expires(self, expires):
49 """ 50 Set absolute expiration time. 51 52 @param expires: Absolute expiration time 53 @type expires: time.time() 54 """ 55 self._expires = expires 56 self._expires_in = None
57 58
59 - def make_bare_url(self, bucket, key=''):
60 """ 61 Make an unauthorised URL. 62 """ 63 return self.protocol + '://' + self.server_name + '/' + bucket + '/' + key
64 65
66 - def _auth_header_value(self, method, path, headers):
67 xamzs = [k for k in headers.keys() if k.startswith("x-amz-")] 68 xamzs.sort() 69 auth_parts = [method, 70 headers.get("Content-MD5", ""), 71 headers.get("Content-Type", ""), 72 headers.get("Date", ""),] 73 auth_parts.extend([k + ":" + headers[k].strip() for k in xamzs]) 74 75 # Don't include anything after the first ?, unless there is an acl or torrent parameter 76 stripped_path = path.split('?')[0] 77 if re.search("[&?]acl($|=|&)", path): 78 stripped_path += "?acl" 79 elif re.search("[&?]torrent($|=|&)", path): 80 stripped_path += "?torrent" 81 82 auth_parts.append(stripped_path) 83 auth_str = "\n".join(auth_parts) 84 auth_str = base64.encodestring( 85 hmac.new(self._priv_key, auth_str, sha).digest()).strip() 86 return urllib.quote_plus(auth_str)
87 88
89 - def _headers(self, headers=None, length=None, expires=None):
90 if not headers: 91 headers = {} 92 headers["Date"] = str(expires) 93 if length is not None: 94 headers["Content-Length"] = length 95 return headers
96 97
98 - def _params(self, params, acl=False):
99 p = '' 100 if params: 101 if acl: 102 arg_div = '&' 103 else: 104 arg_div = '?' 105 p = arg_div + urllib.urlencode(params) 106 return p
107 108
109 - def _path(self, bucket=None, key=None, acl=False):
110 if bucket is None: 111 path = "/" 112 else: 113 path = "/" + bucket 114 if key is not None: 115 path += "/" + urllib.quote(key) 116 if acl: 117 path += '?acl' 118 return path
119 120
121 - def _io_len(self, io):
122 if hasattr(io, "len"): 123 return io.len 124 o_pos = io.tell() 125 io.seek(0, 2) 126 length = io.tell() - o_pos 127 io.seek(o_pos, 0) 128 return length
129 130
131 - def _generate(self, method, bucket=None, key=None, 132 send_io=None, params=None, headers=None, acl=False):
133 expires = 0 134 if self._expires_in != None: 135 expires = int(time.time() + self._expires_in) 136 elif self._expires != None: 137 expires = int(self._expires) 138 139 path = self._path(bucket, key, acl) 140 length = None 141 if isinstance(headers, dict) and headers.has_key("Content-Length"): 142 length = headers["Content-Length"] 143 elif send_io is not None: 144 length = self._io_len(send_io) 145 headers = self._headers(headers=headers, length=length, expires=expires) 146 signature = self._auth_header_value(method, path, headers) 147 path += self._params(params, acl) 148 if '?' in path: 149 arg_div = '&' 150 else: 151 arg_div = '?' 152 query_part = "Signature=%s&Expires=%d&AWSAccessKeyId=%s" % (signature, expires, self._pub_key) 153 154 return self.protocol + '://' + self.server_name + path + arg_div + query_part
155 156
157 - def create_bucket(self, name, headers={}):
158 """ 159 Create a bucket. 160 161 @param name: Name for the new bucket 162 @type name: string 163 @param headers: Additional headers 164 @type headers: dict 165 @return: Authenticated URL for creating a bucket 166 @rtype: string 167 """ 168 return self._generate('PUT', bucket=name, headers=headers)
169
170 - def list_bucket(self, name, params={}, headers={}):
171 """ 172 List a bucket's content. 173 174 @param name: Bucket's name 175 @type name: string 176 @param params: Additional parameters 177 @type params: dict 178 @param headers: Additional headers 179 @type headers: dict 180 @return: Authenticated URL for listing bucket's content 181 @rtype: string 182 """ 183 return self._generate('GET', bucket=name, params=params, headers=headers)
184
185 - def delete_bucket(self, name, headers={}):
186 """ 187 Delete a bucket. 188 189 @param name: Name of the bucket that should be deleted 190 @type name: string 191 @param headers: Additional headers 192 @type headers: dict 193 @return: Authenticated URL for delete a bucket 194 @rtype: string 195 """ 196 return self._generate('DELETE', bucket=name, headers=headers)
197
198 - def list_buckets(self, headers={}):
199 """ 200 List all buckets 201 202 @param headers: Additional headers 203 @type headers: dict 204 @return: Authenticated URL for listing all buckets 205 @rtype: string 206 """ 207 return self._generate('GET', headers=headers)
208 209
210 - def put(self, bucket, key, obj, headers={}):
211 headers.update(obj.get_meta_for_headers()) 212 return self._generate('PUT', bucket=bucket, key=key, headers=headers)
213
214 - def get(self, bucket, key, headers={}):
215 return self._generate('GET', bucket=bucket, key=key, headers=headers)
216
217 - def delete(self, bucket, key, headers={}):
218 return self._generate('DELETE', bucket=bucket, key=key, headers=headers)
219
220 - def get_bucket_acl(self, name, headers={}):
221 """ 222 Get acl information for a bucket. 223 224 @param name: Bucket name 225 @type name: string 226 @param headers: Additional headers 227 @type headers: dict 228 @return: Authenticated URL for getting acl information for a bucket 229 @rtype: string 230 """ 231 return self.get_acl(name, None, headers)
232
233 - def get_acl(self, bucket, key=None, headers={}):
234 """ 235 Get acl information for an object. 236 237 @param bucket: Bucket's name 238 @type bucket: string 239 @param key: Object's name 240 @type key: string 241 @param headers: Additional headers 242 @type headers: dict 243 @return: Authenticated URL for getting acl information for an object 244 """ 245 return self._generate('GET', acl=True, bucket=bucket, key=key, headers=headers)
246
247 - def put_bucket_acl(self, name, acl_xml_document, headers={}):
248 return self.put_acl(name, '', acl_xml_document, headers)
249 250 # don't really care what the doc is here.
251 - def put_acl(self, bucket, key, acl_xml_document, headers={}):
252 return self._generate('PUT', acl=True, bucket=bucket, key=key, headers=headers)
253