1 import base64
2 import hmac
3 import httplib
4 import sha
5 import socket
6 import urllib
7 from time import gmtime, strftime
8
9 import s3
10 from s3.parsers import parseError
11
12 PORTS_BY_SECURITY = { True: 443, False: 80 }
13
16 self._pub_key = pub_key
17 self._priv_key = priv_key
18 self._host = host
19 if not port:
20 self._port = PORTS_BY_SECURITY[secure]
21 else:
22 self._port = port
23 self._secure = secure
24
25 if (secure):
26 self._conn = httplib.HTTPSConnection("%s:%d" % (self._host, self._port))
27 else:
28 self._conn = httplib.HTTPConnection("%s:%d" % (self._host, self._port))
29 self._set_debug(debug)
30
32 self._debug = debug
33 self._conn.set_debuglevel(debug)
34
35
37 """C.clone() -> new connection to s3"""
38 return S3Connection(self._pub_key, self._priv_key, secure=self._secure, host=self._host, port=self._port, debug=self._debug)
39
40
42 xamzs = [k for k in headers.keys() if k.startswith("x-amz-")]
43 xamzs.sort()
44 auth_parts = [method,
45 headers.get("Content-MD5", ""),
46 headers.get("Content-Type", ""),
47 headers.get("Date", ""),]
48 auth_parts.extend([k + ":" + headers[k].strip() for k in xamzs])
49
50 auth_parts.append(path)
51 auth_str = "\n".join(auth_parts)
52 auth_str = base64.encodestring(
53 hmac.new(self._priv_key, auth_str, sha).digest()).strip()
54 return "AWS %s:%s" % (self._pub_key, auth_str)
55
57 if not headers:
58 headers = {}
59 headers["Date"] = strftime("%a, %d %b %Y %H:%M:%S GMT", gmtime())
60 if length is not None:
61 headers["Content-Length"] = length
62 headers["Authorization"] = self._auth_header_value(method, path, headers)
63 return headers
64
66 p = ''
67 if params:
68 p = '?' + urllib.urlencode(params)
69 return p
70
71 - def _path(self, bucket=None, obj=None):
72 if bucket is None:
73 return "/"
74 bucket = "/" + bucket
75 if obj is None:
76 return bucket
77 return bucket + "/" + urllib.quote(obj)
78
80 if hasattr(io, "len"):
81 return io.len
82 o_pos = io.tell()
83 io.seek(0, 2)
84 length = io.tell() - o_pos
85 io.seek(o_pos, 0)
86 return length
87
89 method = attr.upper()
90 def f(bucket=None, obj=None, send_io=None, params=None, headers=None):
91 path = self._path(bucket, obj)
92 length = None
93 if isinstance(headers, dict) and headers.has_key("Content-Length"):
94 length = headers["Content-Length"]
95 elif send_io is not None:
96 length = self._io_len(send_io)
97 headers = self._headers(method, path, length=length, headers=headers)
98
99 def do_c():
100 self._conn.putrequest(method, path + self._params(params))
101 for k,v in headers.items():
102 self._conn.putheader(k, v)
103 self._conn.endheaders()
104
105 retry = False
106 try:
107 do_c()
108 except socket.error, e:
109
110
111 if e[0] == 32:
112 retry = True
113 if retry:
114 do_c()
115
116 if send_io is not None:
117 data = send_io.read(httplib.MAXAMOUNT)
118 while len(data) > 0:
119 self._conn.send(data)
120 data = send_io.read(httplib.MAXAMOUNT)
121 send_io.read()
122 try:
123 r = self._conn.getresponse()
124 except httplib.ResponseNotReady, e:
125 e.args += ('You are probably overlapping S3 ops, like doing f = bucket.get(k); bucket.keys(); f.read(). Try using bucket.clone() such as f = bucket.clone().get(k)',)
126 raise e
127 if r.status < 200 or r.status > 299:
128 raise parseError(r.read())
129 if not method == "GET":
130 r.read()
131 return r
132 return f
133