Passed
Push — develop ( f534b1...a82689 )
by Plexxi
06:09 queued 03:13
created

ErrorHandlingMiddleware   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 70
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 70
rs 10
wmc 15

2 Methods

Rating   Name   Duplication   Size   Complexity  
F __call__() 0 66 14
A __init__() 0 2 1
1
# Licensed to the StackStorm, Inc ('StackStorm') under one or more
2
# contributor license agreements.  See the NOTICE file distributed with
3
# this work for additional information regarding copyright ownership.
4
# The ASF licenses this file to You under the Apache License, Version 2.0
5
# (the "License"); you may not use this file except in compliance with
6
# the License.  You may obtain a copy of the License at
7
#
8
#     http://www.apache.org/licenses/LICENSE-2.0
9
#
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS,
12
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
# See the License for the specific language governing permissions and
14
# limitations under the License.
15
16
import traceback
17
18
from mongoengine import ValidationError
19
20
from st2common.exceptions import db as db_exceptions
21
from st2common.exceptions import rbac as rbac_exceptions
22
from st2common.exceptions.apivalidation import ValueValidationException
23
from st2common import log as logging
24
from st2common.router import exc, Response, NotFoundException
25
from st2common.util.debugging import is_enabled as is_debugging_enabled
26
from st2common.util.jsonify import json_encode
27
28
29
LOG = logging.getLogger(__name__)
30
31
32
class ErrorHandlingMiddleware(object):
33
    def __init__(self, app):
34
        self.app = app
35
36
    def __call__(self, environ, start_response):
37
        try:
38
            try:
39
                return self.app(environ, start_response)
40
            except NotFoundException:
41
                raise exc.HTTPNotFound()
42
        except Exception as e:
43
            status = getattr(e, 'code', exc.HTTPInternalServerError.code)
44
45
            if hasattr(e, 'detail') and not getattr(e, 'comment'):
46
                setattr(e, 'comment', getattr(e, 'detail'))
47
48
            if hasattr(e, 'body') and isinstance(getattr(e, 'body', None), dict):
49
                body = getattr(e, 'body', None)
50
            else:
51
                body = {}
52
53
            if isinstance(e, exc.HTTPException):
54
                status_code = status
55
                message = str(e)
56
            elif isinstance(e, db_exceptions.StackStormDBObjectNotFoundError):
57
                status_code = exc.HTTPNotFound.code
58
                message = str(e)
59
            elif isinstance(e, db_exceptions.StackStormDBObjectConflictError):
60
                status_code = exc.HTTPConflict.code
61
                message = str(e)
62
                body['conflict-id'] = getattr(e, 'conflict_id', None)
63
            elif isinstance(e, rbac_exceptions.AccessDeniedError):
64
                status_code = exc.HTTPForbidden.code
65
                message = str(e)
66
            elif isinstance(e, (ValueValidationException, ValueError, ValidationError)):
67
                status_code = exc.HTTPBadRequest.code
68
                message = getattr(e, 'message', str(e))
69
            else:
70
                status_code = exc.HTTPInternalServerError.code
71
                message = 'Internal Server Error'
72
73
            # Log the error
74
            is_internal_server_error = status_code == exc.HTTPInternalServerError.code
75
            error_msg = getattr(e, 'comment', str(e))
76
            extra = {
77
                'exception_class': e.__class__.__name__,
78
                'exception_message': str(e),
79
                'exception_data': e.__dict__
80
            }
81
82
            if is_internal_server_error:
83
                LOG.exception('API call failed: %s', error_msg, extra=extra)
84
                LOG.exception(traceback.format_exc())
85
            else:
86
                LOG.debug('API call failed: %s', error_msg, extra=extra)
87
88
                if is_debugging_enabled():
89
                    LOG.debug(traceback.format_exc())
90
91
            body['faultstring'] = message
92
93
            response_body = json_encode(body)
94
            headers = {
95
                'Content-Type': 'application/json',
96
                'Content-Length': str(len(response_body))
97
            }
98
99
            resp = Response(response_body, status=status_code, headers=headers)
100
101
            return resp(environ, start_response)
0 ignored issues
show
Bug introduced by
resp does not seem to be callable.
Loading history...
102