import logging import json from flask import request, make_response, current_app from werkzeug.exceptions import HTTPException from app import analytics from auth.auth_context import get_authenticated_user, get_validated_token logger = logging.getLogger(__name__) DEFAULT_MESSAGE = {} DEFAULT_MESSAGE[400] = 'Invalid Request' DEFAULT_MESSAGE[401] = 'Unauthorized' DEFAULT_MESSAGE[403] = 'Permission Denied' DEFAULT_MESSAGE[404] = 'Not Found' DEFAULT_MESSAGE[409] = 'Conflict' DEFAULT_MESSAGE[501] = 'Not Implemented' def _abort(status_code, data_object, headers): # Add CORS headers to all errors options_resp = current_app.make_default_options_response() headers['Access-Control-Allow-Origin'] = '*' headers['Access-Control-Allow-Methods'] = options_resp.headers['allow'] headers['Access-Control-Max-Age'] = str(21600) headers['Access-Control-Allow-Headers'] = ['Authorization', 'Content-Type'] resp = make_response(json.dumps(data_object), status_code, headers) # Report the abort to the user. # Raising HTTPException as workaround for https://github.com/pallets/werkzeug/issues/1098 new_exception = HTTPException(response=resp) new_exception.code = status_code raise new_exception def exact_abort(status_code, message=None): data = {} if message is not None: data['error'] = message _abort(status_code, data, {}) def abort(status_code, message=None, issue=None, headers=None, **kwargs): message = (str(message) % kwargs if message else DEFAULT_MESSAGE.get(status_code, '')) params = dict(request.view_args or {}) params.update(kwargs) params['url'] = request.url params['status_code'] = status_code params['message'] = message # Add the user information. auth_user = get_authenticated_user() auth_token = get_validated_token() if auth_user: analytics.track(auth_user.username, 'http_error', params) message = '%s (user: %s)' % (message, auth_user.username) elif auth_token: analytics.track(auth_token.code, 'http_error', params) message = '%s (token: %s)' % (message, auth_token.friendly_name or auth_token.code) # Log the abort. logger.error('Error %s: %s; Arguments: %s' % (status_code, message, params)) # Calculate the issue URL (if the issue ID was supplied). issue_url = None if issue: issue_url = 'http://docs.quay.io/issues/%s.html' % (issue) # Create the final response data and message. data = {} data['error'] = message if issue_url: data['info_url'] = issue_url if headers is None: headers = {} _abort(status_code, data, headers)