~tribaal/txaws/xss-hardening

« back to all changes in this revision

Viewing changes to txaws/ec2/exception.py

Merge 461960-update-error-wrapper [r=free.ekanayaka] [f=461960]

This branch refactors the error handling for txAWS, not only addressing the
original scope of the ticket (handling ConnectionRefusedError) but also
adding support for handling Amazon-originated 500-errors, non-AWS 400 and 500
errors, and handing improperly configured endpoints that are returning HTML.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Copyright (c) 2009 Canonical Ltd <duncan.mcgreggor@canonical.com>
2
2
# Licenced under the txaws licence available at /LICENSE in the txaws source.
3
3
 
4
 
from txaws.exception import AWSError
 
4
from txaws.exception import AWSError, AWSResponseParseError
5
5
from txaws.util import XML
6
6
 
7
7
 
16
16
        self.original = xml_bytes
17
17
        self.errors = []
18
18
        self.request_id = ""
 
19
        self.host_id = ""
19
20
        self.parse()
20
21
 
21
22
    def __str__(self):
26
27
            self.__class__.__name__, self._get_error_code_string())
27
28
 
28
29
    def _set_request_id(self, tree):
29
 
        requestIDNode = tree.find(".//RequestID")
30
 
        if hasattr(requestIDNode, "text"):
31
 
            text = requestIDNode.text
 
30
        request_id_node = tree.find(".//RequestID")
 
31
        if hasattr(request_id_node, "text"):
 
32
            text = request_id_node.text
32
33
            if text:
33
 
                self.requestID = text
 
34
                self.request_id = text
34
35
 
35
 
    def _set_errors(self, tree):
36
 
        errorsNode = tree.find(".//Errors")
37
 
        if errorsNode:
38
 
            for error in errorsNode:
 
36
    def _set_400_errors(self, tree):
 
37
        errors_node = tree.find(".//Errors")
 
38
        if errors_node:
 
39
            for error in errors_node:
39
40
                data = self._node_to_dict(error)
40
41
                if data:
41
42
                    self.errors.append(data)
42
43
 
 
44
    def _set_host_id(self, tree):
 
45
        host_id = tree.find(".//HostID")
 
46
        if hasattr(host_id, "text"):
 
47
            text = host_id.text
 
48
            if text:
 
49
                self.host_id = text
 
50
 
 
51
    def _set_500_error(self, tree):
 
52
        self._set_request_id(tree)
 
53
        self._set_host_id(tree)
 
54
        data = self._node_to_dict(tree)
 
55
        if data:
 
56
            self.errors.append(data)
 
57
 
43
58
    def _get_error_code_string(self):
44
59
        count = len(self.errors)
45
60
        error_code = self.get_error_codes()
63
78
                data[child.tag] = child.text
64
79
        return data
65
80
 
 
81
    def _check_for_html(self, tree):
 
82
        if tree.tag == "html":
 
83
            message = "Could not parse HTML in the response."
 
84
            raise AWSResponseParseError(message)
 
85
 
66
86
    def parse(self, xml_bytes=""):
67
87
        if not xml_bytes:
68
88
            xml_bytes = self.original
69
89
        tree = XML(xml_bytes.strip())
 
90
        self._check_for_html(tree)
70
91
        self._set_request_id(tree)
71
 
        self._set_errors(tree)
 
92
        if self.status >= 500:
 
93
            self._set_500_error(tree)
 
94
        else:
 
95
            self._set_400_errors(tree)
72
96
 
73
97
    def has_error(self, errorString):
74
98
        for error in self.errors: