Beispiel #1
0
    def __call__(self, environ, start_response):
        # Request for this state, modified by replace_start_response()
        # and used when an error is being reported.
        state = {}

        def replacement_start_response(status, headers, exc_info=None):
            """Overrides the default response to make errors parsable."""
            try:
                status_code = int(status.split(' ')[0])
                state['status_code'] = status_code
            except (ValueError, TypeError):  # pragma: nocover
                raise Exception((
                    'ErrorDocumentMiddleware received an invalid '
                    'status %s' % status
                ))
            else:
                if (state['status_code'] / 100) not in (2, 3):
                    # Remove some headers so we can replace them later
                    # when we have the full error message and can
                    # compute the length.
                    headers = [(h, v)
                               for (h, v) in headers
                               if h not in ('Content-Length', 'Content-Type')
                               ]
                # Save the headers in case we need to modify them.
                state['headers'] = headers
                return start_response(status, headers, exc_info)

        app_iter = self.app(environ, replacement_start_response)
        if (state['status_code'] / 100) not in (2, 3):
            req = webob.Request(environ)
            # Find the first TranslationHook in the array of hooks and use the
            # translatable_error object from it
            error = None
            for hook in self.app.hooks:
                if isinstance(hook, hooks.TranslationHook):
                    error = hook.local_error.translatable_error
                    break
            user_locale = self.best_match_language(req.accept_language)
            if (req.accept.best_match(['application/json', 'application/xml'])
               == 'application/xml'):
                try:
                    # simple check xml is valid
                    fault = etree.fromstring('\n'.join(app_iter))
                    # Add the translated error to the xml data
                    if error is not None:
                        for fault_string in fault.findall('faultstring'):
                            fault_string.text = i18n.translate(error,
                                                               user_locale)
                    body = ['<error_message>' + etree.tostring(fault)
                            + '</error_message>']
                except etree.XMLSyntaxError as err:
                    LOG.error(_('Error parsing HTTP response: %s') % err)
                    body = ['<error_message>%s' % state['status_code']
                            + '</error_message>']
                state['headers'].append(('Content-Type', 'application/xml'))
            else:
                try:
                    fault = json.loads('\n'.join(app_iter))
                    if error is not None and 'faultstring' in fault:
                        fault['faultstring'] = i18n.translate(error,
                                                              user_locale)
                    body = [json.dumps({'error_message': fault})]
                except ValueError as err:
                    body = [json.dumps({'error_message': '\n'.join(app_iter)})]
                state['headers'].append(('Content-Type', 'application/json'))
            state['headers'].append(('Content-Length', str(len(body[0]))))
        else:
            body = app_iter
        return body
Beispiel #2
0
    def __call__(self, environ, start_response):
        # Request for this state, modified by replace_start_response()
        # and used when an error is being reported.
        state = {}

        def replacement_start_response(status, headers, exc_info=None):
            """Overrides the default response to make errors parsable."""
            try:
                status_code = int(status.split(' ')[0])
                state['status_code'] = status_code
            except (ValueError, TypeError):  # pragma: nocover
                raise Exception((
                    'ErrorDocumentMiddleware received an invalid '
                    'status %s' % status
                ))
            else:
                if (state['status_code'] // 100) not in (2, 3):
                    # Remove some headers so we can replace them later
                    # when we have the full error message and can
                    # compute the length.
                    headers = [(h, v)
                               for (h, v) in headers
                               if h not in ('Content-Length', 'Content-Type')
                               ]
                # Save the headers in case we need to modify them.
                state['headers'] = headers
                return start_response(status, headers, exc_info)

        app_iter = self.app(environ, replacement_start_response)
        if (state['status_code'] // 100) not in (2, 3):
            req = webob.Request(environ)
            error = environ.get('translatable_error')
            user_locale = self.best_match_language(req.accept_language)
            if (req.accept.best_match(['application/json', 'application/xml'])
               == 'application/xml'):
                content_type = 'application/xml'
                try:
                    # simple check xml is valid
                    fault = etree.fromstring(b'\n'.join(app_iter))
                    # Add the translated error to the xml data
                    if error is not None:
                        for fault_string in fault.findall('faultstring'):
                            fault_string.text = i18n.translate(error,
                                                               user_locale)
                    error_message = etree.tostring(fault)
                    body = b''.join((b'<error_message>',
                                     error_message,
                                     b'</error_message>'))
                except etree.XMLSyntaxError as err:
                    LOG.error(_('Error parsing HTTP response: %s'), err)
                    error_message = state['status_code']
                    body = '<error_message>%s</error_message>' % error_message
                    if six.PY3:
                        body = body.encode('utf-8')
            else:
                content_type = 'application/json'
                app_data = b'\n'.join(app_iter)
                if six.PY3:
                    app_data = app_data.decode('utf-8')
                try:
                    fault = json.loads(app_data)
                    if error is not None and 'faultstring' in fault:
                        fault['faultstring'] = i18n.translate(error,
                                                              user_locale)
                except ValueError as err:
                    fault = app_data
                body = json.dumps({'error_message': fault})
                if six.PY3:
                    body = body.encode('utf-8')

            state['headers'].append(('Content-Length', str(len(body))))
            state['headers'].append(('Content-Type', content_type))
            body = [body]
        else:
            body = app_iter
        return body
    def __call__(self, environ, start_response):
        # Request for this state, modified by replace_start_response()
        # and used when an error is being reported.
        state = {}

        def replacement_start_response(status, headers, exc_info=None):
            """Overrides the default response to make errors parsable."""
            try:
                status_code = int(status.split(' ')[0])
                state['status_code'] = status_code
            except (ValueError, TypeError):  # pragma: nocover
                raise Exception((
                    'ErrorDocumentMiddleware received an invalid '
                    'status %s' % status
                ))
            else:
                if (state['status_code'] // 100) not in (2, 3):
                    # Remove some headers so we can replace them later
                    # when we have the full error message and can
                    # compute the length.
                    headers = [(h, v)
                               for (h, v) in headers
                               if h not in ('Content-Length', 'Content-Type')
                               ]
                # Save the headers in case we need to modify them.
                state['headers'] = headers
                return start_response(status, headers, exc_info)

        app_iter = self.app(environ, replacement_start_response)
        if (state['status_code'] // 100) not in (2, 3):
            req = webob.Request(environ)
            error = environ.get('translatable_error')
            user_locale = self.best_match_language(req.accept_language)
            if (req.accept.best_match(['application/json', 'application/xml'])
               == 'application/xml'):
                content_type = 'application/xml'
                try:
                    # simple check xml is valid
                    fault = etree.fromstring(b'\n'.join(app_iter))
                    # Add the translated error to the xml data
                    if error is not None:
                        for fault_string in fault.findall('faultstring'):
                            fault_string.text = i18n.translate(error,
                                                               user_locale)
                    error_message = etree.tostring(fault)
                    body = b''.join((b'<error_message>',
                                     error_message,
                                     b'</error_message>'))
                except etree.XMLSyntaxError as err:
                    LOG.error('Error parsing HTTP response: %s', err)
                    error_message = state['status_code']
                    body = '<error_message>%s</error_message>' % error_message
                    if six.PY3:
                        body = body.encode('utf-8')
            else:
                content_type = 'application/json'
                app_data = b'\n'.join(app_iter)
                if six.PY3:
                    app_data = app_data.decode('utf-8')
                try:
                    fault = json.loads(app_data)
                    if error is not None and 'faultstring' in fault:
                        fault['faultstring'] = i18n.translate(error,
                                                              user_locale)
                except ValueError as err:
                    fault = app_data
                body = json.dumps({'error_message': fault})
                if six.PY3:
                    body = body.encode('utf-8')

            state['headers'].append(('Content-Length', str(len(body))))
            state['headers'].append(('Content-Type', content_type))
            body = [body]
        else:
            body = app_iter
        return body