@@ -53,7 +53,7 @@ def forward_request(self, method, path, data, headers): |
53 | 53 | if new_response: |
54 | 54 | return new_response |
55 | 55 | elif action == 'SetQueueAttributes': |
56 | | - self._set_queue_attributes(req_data) |
| 56 | + self._set_queue_attributes(path, req_data, headers) |
57 | 57 |
|
58 | 58 | if 'QueueName' in req_data: |
59 | 59 | encoded_data = urlencode(req_data, doseq=True) if method == 'POST' else '' |
@@ -80,67 +80,69 @@ def return_response(self, method, path, data, headers, response, request_handler |
80 | 80 | # Allow CORS preflight requests to succeed. |
81 | 81 | return 200 |
82 | 82 |
|
83 | | - if method == 'POST' and path == '/': |
84 | | - region_name = extract_region_from_auth_header(headers) |
85 | | - req_data = urlparse.parse_qs(to_str(data)) |
86 | | - action = req_data.get('Action', [None])[0] |
87 | | - content_str = content_str_original = to_str(response.content) |
88 | | - |
89 | | - self._fire_event(req_data, response) |
90 | | - |
91 | | - # patch the response and add missing attributes |
92 | | - if action == 'GetQueueAttributes': |
93 | | - content_str = self._add_queue_attributes(req_data, content_str) |
94 | | - |
95 | | - # patch the response and return the correct endpoint URLs / ARNs |
96 | | - if action in ('CreateQueue', 'GetQueueUrl', 'ListQueues', 'GetQueueAttributes'): |
97 | | - if config.USE_SSL and '<QueueUrl>http://' in content_str: |
98 | | - # return https://... if we're supposed to use SSL |
99 | | - content_str = re.sub(r'<QueueUrl>\s*http://', r'<QueueUrl>https://', content_str) |
100 | | - # expose external hostname:port |
101 | | - external_port = SQS_PORT_EXTERNAL or get_external_port(headers, request_handler) |
102 | | - content_str = re.sub(r'<QueueUrl>\s*([a-z]+)://[^<]*:([0-9]+)/([^<]*)\s*</QueueUrl>', |
103 | | - r'<QueueUrl>\1://%s:%s/\3</QueueUrl>' % (HOSTNAME_EXTERNAL, external_port), content_str) |
104 | | - # fix queue ARN |
105 | | - content_str = re.sub(r'<([a-zA-Z0-9]+)>\s*arn:aws:sqs:elasticmq:([^<]+)</([a-zA-Z0-9]+)>', |
106 | | - r'<\1>arn:aws:sqs:%s:\2</\3>' % (region_name), content_str) |
107 | | - |
108 | | - if content_str_original != content_str: |
109 | | - # if changes have been made, return patched response |
110 | | - new_response = Response() |
111 | | - new_response.status_code = response.status_code |
112 | | - new_response.headers = response.headers |
113 | | - new_response._content = content_str |
114 | | - new_response.headers['content-length'] = len(new_response._content) |
115 | | - return new_response |
116 | | - |
117 | | - # Since the following 2 API calls are not implemented in ElasticMQ, we're mocking them |
118 | | - # and letting them to return an empty response |
119 | | - if action == 'TagQueue': |
120 | | - new_response = Response() |
121 | | - new_response.status_code = 200 |
122 | | - new_response._content = (""" |
123 | | - <?xml version="1.0"?> |
124 | | - <TagQueueResponse> |
125 | | - <ResponseMetadata> |
126 | | - <RequestId>{}</RequestId> |
127 | | - </ResponseMetadata> |
128 | | - </TagQueueResponse> |
129 | | - """).strip().format(uuid.uuid4()) |
130 | | - return new_response |
131 | | - elif action == 'ListQueueTags': |
132 | | - new_response = Response() |
133 | | - new_response.status_code = 200 |
134 | | - new_response._content = (""" |
135 | | - <?xml version="1.0"?> |
136 | | - <ListQueueTagsResponse xmlns="{}"> |
137 | | - <ListQueueTagsResult/> |
138 | | - <ResponseMetadata> |
139 | | - <RequestId>{}</RequestId> |
140 | | - </ResponseMetadata> |
141 | | - </ListQueueTagsResponse> |
142 | | - """).strip().format(XMLNS_SQS, uuid.uuid4()) |
143 | | - return new_response |
| 83 | + if method != 'POST': |
| 84 | + return |
| 85 | + |
| 86 | + region_name = extract_region_from_auth_header(headers) |
| 87 | + req_data = urlparse.parse_qs(to_str(data)) |
| 88 | + action = req_data.get('Action', [None])[0] |
| 89 | + content_str = content_str_original = to_str(response.content) |
| 90 | + |
| 91 | + self._fire_event(req_data, response) |
| 92 | + |
| 93 | + # patch the response and add missing attributes |
| 94 | + if action == 'GetQueueAttributes': |
| 95 | + content_str = self._add_queue_attributes(path, req_data, content_str, headers) |
| 96 | + |
| 97 | + # patch the response and return the correct endpoint URLs / ARNs |
| 98 | + if action in ('CreateQueue', 'GetQueueUrl', 'ListQueues', 'GetQueueAttributes'): |
| 99 | + if config.USE_SSL and '<QueueUrl>http://' in content_str: |
| 100 | + # return https://... if we're supposed to use SSL |
| 101 | + content_str = re.sub(r'<QueueUrl>\s*http://', r'<QueueUrl>https://', content_str) |
| 102 | + # expose external hostname:port |
| 103 | + external_port = SQS_PORT_EXTERNAL or get_external_port(headers, request_handler) |
| 104 | + content_str = re.sub(r'<QueueUrl>\s*([a-z]+)://[^<]*:([0-9]+)/([^<]*)\s*</QueueUrl>', |
| 105 | + r'<QueueUrl>\1://%s:%s/\3</QueueUrl>' % (HOSTNAME_EXTERNAL, external_port), content_str) |
| 106 | + # fix queue ARN |
| 107 | + content_str = re.sub(r'<([a-zA-Z0-9]+)>\s*arn:aws:sqs:elasticmq:([^<]+)</([a-zA-Z0-9]+)>', |
| 108 | + r'<\1>arn:aws:sqs:%s:\2</\3>' % (region_name), content_str) |
| 109 | + |
| 110 | + if content_str_original != content_str: |
| 111 | + # if changes have been made, return patched response |
| 112 | + new_response = Response() |
| 113 | + new_response.status_code = response.status_code |
| 114 | + new_response.headers = response.headers |
| 115 | + new_response._content = content_str |
| 116 | + new_response.headers['content-length'] = len(new_response._content) |
| 117 | + return new_response |
| 118 | + |
| 119 | + # Since the following 2 API calls are not implemented in ElasticMQ, we're mocking them |
| 120 | + # and letting them to return an empty response |
| 121 | + if action == 'TagQueue': |
| 122 | + new_response = Response() |
| 123 | + new_response.status_code = 200 |
| 124 | + new_response._content = (""" |
| 125 | + <?xml version="1.0"?> |
| 126 | + <TagQueueResponse> |
| 127 | + <ResponseMetadata> |
| 128 | + <RequestId>{}</RequestId> |
| 129 | + </ResponseMetadata> |
| 130 | + </TagQueueResponse> |
| 131 | + """).strip().format(uuid.uuid4()) |
| 132 | + return new_response |
| 133 | + elif action == 'ListQueueTags': |
| 134 | + new_response = Response() |
| 135 | + new_response.status_code = 200 |
| 136 | + new_response._content = (""" |
| 137 | + <?xml version="1.0"?> |
| 138 | + <ListQueueTagsResponse xmlns="{}"> |
| 139 | + <ListQueueTagsResult/> |
| 140 | + <ResponseMetadata> |
| 141 | + <RequestId>{}</RequestId> |
| 142 | + </ResponseMetadata> |
| 143 | + </ListQueueTagsResponse> |
| 144 | + """).strip().format(XMLNS_SQS, uuid.uuid4()) |
| 145 | + return new_response |
144 | 146 |
|
145 | 147 | # Format of the message Name attribute is MessageAttribute.<int id>.<field> |
146 | 148 | # Format of the Value attributes is MessageAttribute.<int id>.Value.DataType |
@@ -225,7 +227,7 @@ def _format_attributes(self, req_data): |
225 | 227 | return result |
226 | 228 |
|
227 | 229 | def _send_message(self, path, data, req_data, headers): |
228 | | - queue_url = req_data.get('QueueUrl', [path.partition('?')[0]])[0] |
| 230 | + queue_url = self._queue_url(path, req_data, headers) |
229 | 231 | queue_name = queue_url[queue_url.rindex('/') + 1:] |
230 | 232 | message_body = req_data.get('MessageBody', [None])[0] |
231 | 233 | message_attributes = self.format_message_attributes(req_data) |
@@ -244,17 +246,17 @@ def _send_message(self, path, data, req_data, headers): |
244 | 246 | new_response.status_code = 200 |
245 | 247 | return new_response |
246 | 248 |
|
247 | | - def _set_queue_attributes(self, req_data): |
248 | | - queue_url = req_data['QueueUrl'][0] |
| 249 | + def _set_queue_attributes(self, path, req_data, headers): |
| 250 | + queue_url = self._queue_url(path, req_data, headers) |
249 | 251 | attrs = self._format_attributes(req_data) |
250 | 252 | # select only the attributes in UNSUPPORTED_ATTRIBUTE_NAMES |
251 | 253 | attrs = dict([(k, v) for k, v in attrs.items() if k in UNSUPPORTED_ATTRIBUTE_NAMES]) |
252 | 254 | QUEUE_ATTRIBUTES[queue_url] = QUEUE_ATTRIBUTES.get(queue_url) or {} |
253 | 255 | QUEUE_ATTRIBUTES[queue_url].update(attrs) |
254 | 256 |
|
255 | | - def _add_queue_attributes(self, req_data, content_str): |
| 257 | + def _add_queue_attributes(self, path, req_data, content_str, headers): |
256 | 258 | flags = re.MULTILINE | re.DOTALL |
257 | | - queue_url = req_data['QueueUrl'][0] |
| 259 | + queue_url = self._queue_url(path, req_data, headers) |
258 | 260 | regex = r'(.*<GetQueueAttributesResult>)(.*)(</GetQueueAttributesResult>.*)' |
259 | 261 | attrs = re.sub(regex, r'\2', content_str, flags=flags) |
260 | 262 | for key, value in QUEUE_ATTRIBUTES.get(queue_url, {}).items(): |
@@ -280,6 +282,16 @@ def _fire_event(self, req_data, response): |
280 | 282 | if event_type and queue_url: |
281 | 283 | event_publisher.fire_event(event_type, payload={'u': event_publisher.get_hash(queue_url)}) |
282 | 284 |
|
| 285 | + def _queue_url(self, path, req_data, headers): |
| 286 | + queue_url = req_data.get('QueueUrl') |
| 287 | + if queue_url: |
| 288 | + return queue_url[0] |
| 289 | + url = config.TEST_SQS_URL |
| 290 | + if headers.get('Host'): |
| 291 | + url = 'http%s://%s' % ('s' if config.USE_SSL else '', headers['Host']) |
| 292 | + queue_url = '%s%s' % (url, path.partition('?')[0]) |
| 293 | + return queue_url |
| 294 | + |
283 | 295 |
|
284 | 296 | # extract the external port used by the client to make the request |
285 | 297 | def get_external_port(headers, request_handler): |
|