1 import re
2 import sha
3 import hmac
4 import time
5 import base64
6 import socket
7 import urllib
8 import httplib
9
10 import sqs
11 from sqs.parsers import parseError
12
13
14 DEFAULT_CONTENT_TYPE = 'text/plain'
15 PORTS_BY_SECURITY = { True: 443, False: 80 }
16
18 """SQS Connection class.
19
20 You shoud never use this class directly. User SQSService instead.
21 """
23 self._pub_key = pub_key
24 self._priv_key = priv_key
25 self._host = host
26 if not port:
27 self._port = PORTS_BY_SECURITY[secure]
28 else:
29 self._port = port
30 self._secure = secure
31 if (secure):
32 self._conn = httplib.HTTPSConnection("%s:%d" % (self._host, self._port))
33 else:
34 self._conn = httplib.HTTPConnection("%s:%d" % (self._host, self._port))
35 self._set_debug(debug)
36
37
39 self._debug = debug
40 self._conn.set_debuglevel(debug)
41
42
44 """C.clone() -> new connection to sqs"""
45 return SQSConnection(self._pub_key, self._priv_key, self._host, self._port, self._secure, self._debug)
46
47
49 path = path.split('?')[0]
50
51 if re.search("[&?]acl($|=|&)", path):
52 path += "?acl"
53 auth_parts = [method,
54 headers.get("Content-MD5", ""),
55 headers.get("Content-Type", DEFAULT_CONTENT_TYPE),
56 headers.get("Date", time.strftime("%a, %d %b %Y %X GMT", time.gmtime())),
57 path]
58 auth_str = "\n".join(auth_parts)
59 auth_str = base64.encodestring(
60 hmac.new(self._priv_key, auth_str, sha).digest()).strip()
61 return "AWS %s:%s" % (self._pub_key, auth_str)
62
63
65 if not headers:
66 headers = {}
67 if not headers.has_key('Date'):
68 headers["Date"] = time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime())
69 if not headers.has_key('AWS-Version'):
70 headers['AWS-Version'] = sqs.VERSION
71 if not headers.has_key('Content-Type'):
72 headers['Content-Type'] = DEFAULT_CONTENT_TYPE
73 if not headers.has_key('Content-MD5'):
74 headers['Content-MD5'] = ''
75 if not headers.has_key('Content-Length'):
76 if length is not None:
77 headers['Content-Length'] = length
78 else:
79 headers['Content-Length'] = 0
80 headers["Authorization"] = self._auth_header_value(method, path, headers)
81 return headers
82
84 p = ''
85 if params:
86 p = '?' + urllib.urlencode(params)
87 return p
88
89 - def _path(self, queue=None, message=None):
90 if queue is None:
91 return "/"
92 queue = '/' + queue
93 if message is None:
94 return queue
95 return queue + "/" + message
96
98 if hasattr(io, "len"):
99 return io.len
100 o_pos = io.tell()
101 io.seek(0, 2)
102 length = io.tell() - o_pos
103 io.seek(o_pos, 0)
104 return length
105
106
108 method = attr.upper()
109 def f(queue=None, message=None, send_io=None, params=None, headers=None):
110 path = self._path(queue, message)
111 length = None
112 if isinstance(headers, dict) and headers.has_key("Content-Length"):
113 length = headers["Content-Length"]
114 elif send_io is not None:
115 length = self._io_len(send_io)
116
117 headers = self._headers(method, path, length=length, headers=headers)
118
119 def do_conn():
120 self._conn.putrequest(method, path + self._params(params))
121 for k,v in headers.items():
122 self._conn.putheader(k, v)
123 self._conn.endheaders()
124
125 retry = False
126 try:
127 do_conn()
128 except socket.error, e:
129
130
131 if e[0] == 32:
132 retry = True
133 if retry:
134 do_conn()
135
136 if send_io is not None:
137 data = send_io.read(httplib.MAXAMOUNT)
138 while len(data) > 0:
139 self._conn.send(data)
140 data = send_io.read(httplib.MAXAMOUNT)
141 send_io.read()
142 try:
143 r = self._conn.getresponse()
144 except httplib.ResponseNotReady, e:
145 e.args += ('You are probably overlapping SQS ops',)
146 raise e
147 if r.status < 200 or r.status > 299:
148 raise parseError(r.read())
149 return r
150 return f
151