Ejemplo n.º 1
0
def page_not_found(response, request):
    """Return a JSON 404 error response."""
    config_key = 'trailing_slash_redirect_enabled'
    redirect_enabled = request.registry.settings[config_key]
    trailing_slash_redirection_enabled = asbool(redirect_enabled)

    querystring = request.url[(request.url.rindex(request.path) +
                               len(request.path)):]

    errno = ERRORS.MISSING_RESOURCE
    error_msg = 'The resource you are looking for could not be found.'

    if not request.path.startswith('/{}'.format(request.registry.route_prefix)):
        errno = ERRORS.VERSION_NOT_AVAILABLE
        error_msg = ('The requested API version is not available '
                     'on this server.')
    elif trailing_slash_redirection_enabled:
        redirect = None

        if request.path.endswith('/'):
            path = request.path.rstrip('/')
            redirect = '{}{}'.format(path, querystring)
        elif request.path == '/{}'.format(request.registry.route_prefix):
            # Case for /v0 -> /v0/
            redirect = '/{}/{}'.format(request.registry.route_prefix, querystring)

        if redirect:
            return reapply_cors(request, HTTPTemporaryRedirect(redirect))

    if response.content_type != 'application/json':
        response = http_error(httpexceptions.HTTPNotFound(),
                              errno=errno,
                              message=error_msg)
    return reapply_cors(request, response)
Ejemplo n.º 2
0
def page_not_found(response, request):
    """Return a JSON 404 error response."""
    config_key = "trailing_slash_redirect_enabled"
    redirect_enabled = request.registry.settings[config_key]
    trailing_slash_redirection_enabled = asbool(redirect_enabled)

    querystring = request.url[(request.url.rindex(request.path) + len(request.path)) :]

    errno = ERRORS.MISSING_RESOURCE
    error_msg = "The resource you are looking for could not be found."

    if not request.path.startswith(f"/{request.registry.route_prefix}"):
        errno = ERRORS.VERSION_NOT_AVAILABLE
        error_msg = "The requested API version is not available " "on this server."
    elif trailing_slash_redirection_enabled:
        redirect = None

        if request.path.endswith("/"):
            path = request.path.rstrip("/")
            redirect = f"{path}{querystring}"
        elif request.path == f"/{request.registry.route_prefix}":
            # Case for /v0 -> /v0/
            redirect = f"/{request.registry.route_prefix}/{querystring}"

        if redirect:
            return reapply_cors(request, HTTPTemporaryRedirect(redirect))

    if response.content_type != "application/json":
        response = http_error(httpexceptions.HTTPNotFound(), errno=errno, message=error_msg)
    return reapply_cors(request, response)
Ejemplo n.º 3
0
    def _redirect_to_version_view(request):
        if request.method.lower() == "options":
            # CORS responses should always have status 200.
            return utils.reapply_cors(request, Response())

        querystring = request.url[(request.url.rindex(request.path) + len(request.path)) :]
        redirect = "/{}{}{}".format(route_prefix, request.path, querystring)
        raise HTTPTemporaryRedirect(redirect)
Ejemplo n.º 4
0
def method_not_allowed(context, request):
    if context.content_type == 'application/json':
        return context

    response = http_error(context,
                          errno=ERRORS.METHOD_NOT_ALLOWED,
                          message='Method not allowed on this endpoint.')
    return reapply_cors(request, response)
Ejemplo n.º 5
0
    def _redirect_to_version_view(request):
        if request.method.lower() == 'options':
            # CORS responses should always have status 200.
            return utils.reapply_cors(request, Response())

        querystring = request.url[(request.url.rindex(request.path) +
                                   len(request.path)):]
        redirect = '/{}{}{}'.format(route_prefix, request.path, querystring)
        raise HTTPTemporaryRedirect(redirect)
Ejemplo n.º 6
0
def error(context, request):
    """Catch server errors and trace them."""
    if isinstance(context, httpexceptions.Response):
        return reapply_cors(request, context)

    if isinstance(context, storage_exceptions.IntegrityError):
        error_msg = 'Integrity constraint violated, please retry.'
        response = http_error(httpexceptions.HTTPConflict(),
                              errno=ERRORS.CONSTRAINT_VIOLATED,
                              message=error_msg)
        retry_after = request.registry.settings['retry_after_seconds']
        response.headers['Retry-After'] = str(retry_after)
        return reapply_cors(request, response)

    # Log some information about current request.
    extra = {
      'path': request.path,
      'method': request.method,
    }
    qs = dict(request_GET(request))
    if qs:
        extra['querystring'] = qs
    # Take errno from original exception, or undefined if unknown/unhandled.
    try:
        extra['errno'] = context.errno.value
    except AttributeError:
        extra['errno'] = ERRORS.UNDEFINED.value

    if isinstance(context, storage_exceptions.BackendError):
        logger.critical(context.original, extra=extra, exc_info=context)
        response = httpexceptions.HTTPServiceUnavailable()
        return service_unavailable(response, request)

    # Within the exception view, sys.exc_info() will return null.
    # see https://github.com/python/cpython/blob/ce9e62544/Lib/logging/__init__.py#L1460-L1462
    logger.error(context, extra=extra, exc_info=context)

    error_msg = 'A programmatic error occured, developers have been informed.'
    info = request.registry.settings['error_info_link']
    response = http_error(httpexceptions.HTTPInternalServerError(),
                          message=error_msg,
                          info=info)

    return reapply_cors(request, response)
Ejemplo n.º 7
0
    def _redirect_to_version_view(request):
        if request.method.lower() == 'options':
            # CORS responses should always have status 200.
            return utils.reapply_cors(request, Response())

        path = request.matchdict['path']
        querystring = request.url[(request.url.rindex(request.path) +
                                   len(request.path)):]
        redirect = '/%s/%s%s' % (route_prefix, path, querystring)
        raise HTTPTemporaryRedirect(redirect)
Ejemplo n.º 8
0
def error(context, request):
    """Catch server errors and trace them."""
    if isinstance(context, httpexceptions.Response):
        return reapply_cors(request, context)

    if isinstance(context, storage_exceptions.BackendError):
        logger.critical(context.original, exc_info=True)
        response = httpexceptions.HTTPServiceUnavailable()
        return service_unavailable(response, request)

    logger.error(context, exc_info=True)

    error_msg = "A programmatic error occured, developers have been informed."
    info = request.registry.settings['error_info_link']
    response = http_error(httpexceptions.HTTPInternalServerError(),
                          message=error_msg,
                          info=info)

    return reapply_cors(request, response)
Ejemplo n.º 9
0
def error(context, request):
    """Catch server errors and trace them."""
    if isinstance(context, httpexceptions.Response):
        return reapply_cors(request, context)

    if isinstance(context, storage_exceptions.BackendError):
        logger.critical(context.original, exc_info=True)
        response = httpexceptions.HTTPServiceUnavailable()
        return service_unavailable(response, request)

    logger.error(context, exc_info=True)

    error_msg = "A programmatic error occured, developers have been informed."
    info = request.registry.settings['error_info_link']
    response = http_error(httpexceptions.HTTPInternalServerError(),
                          message=error_msg,
                          info=info)

    return reapply_cors(request, response)
Ejemplo n.º 10
0
def service_unavailable(response, request):
    if response.content_type != 'application/json':
        error_msg = ('Service temporary unavailable '
                     'due to overloading or maintenance, please retry later.')
        response = http_error(response, errno=ERRORS.BACKEND,
                              message=error_msg)

    retry_after = request.registry.settings['retry_after_seconds']
    response.headers['Retry-After'] = str(retry_after)
    return reapply_cors(request, response)
Ejemplo n.º 11
0
    def _redirect_to_version_view(request):
        if request.method.lower() == "options":
            # CORS responses should always have status 200.
            return utils.reapply_cors(request, Response())

        querystring = request.url[(request.url.rindex(request.path) + len(request.path)) :]
        redirect = f"/{route_prefix}{request.path}{querystring}"
        resp = HTTPTemporaryRedirect(redirect)
        if cache_seconds >= 0:
            resp.cache_expires(cache_seconds)
        raise resp
Ejemplo n.º 12
0
def default_bucket(request):
    if request.method.lower() == 'options':
        path = request.path.replace('default', 'unknown')
        subrequest = build_request(request, {
            'method': 'OPTIONS',
            'path': path
        })
        return request.invoke_subrequest(subrequest)

    if Authenticated not in request.effective_principals:
        # Pass through the forbidden_view_config
        raise httpexceptions.HTTPForbidden()

    settings = request.registry.settings

    if asbool(settings['readonly']):
        raise httpexceptions.HTTPMethodNotAllowed()

    bucket_id = request.default_bucket_id
    path = request.path.replace('/buckets/default', '/buckets/%s' % bucket_id)
    querystring = request.url[(request.url.index(request.path) +
                               len(request.path)):]

    try:
        # If 'id' is provided as 'default', replace with actual bucket id.
        body = request.json
        body['data']['id'] = body['data']['id'].replace('default', bucket_id)
    except:
        body = request.body

    # Make sure bucket exists
    create_bucket(request, bucket_id)

    # Make sure the collection exists
    create_collection(request, bucket_id)

    subrequest = build_request(request, {
        'method': request.method,
        'path': path + querystring,
        'body': body,
    })
    subrequest.bound_data = request.bound_data

    try:
        response = request.invoke_subrequest(subrequest)
    except httpexceptions.HTTPException as error:
        is_redirect = error.status_code < 400
        if error.content_type == 'application/json' or is_redirect:
            response = reapply_cors(subrequest, error)
        else:
            # Ask the upper level to format the error.
            raise error
    return response
Ejemplo n.º 13
0
def default_bucket(request):
    if request.method.lower() == 'options':
        path = request.path.replace('default', 'unknown')
        subrequest = build_request(request, {
            'method': 'OPTIONS',
            'path': path
        })
        return request.invoke_subrequest(subrequest)

    if Authenticated not in request.effective_principals:
        # Pass through the forbidden_view_config
        raise httpexceptions.HTTPForbidden()

    settings = request.registry.settings

    if asbool(settings['readonly']):
        raise httpexceptions.HTTPMethodNotAllowed()

    bucket_id = request.default_bucket_id

    # Implicit object creations.
    # Make sure bucket exists
    create_bucket(request, bucket_id)
    # Make sure the collection exists
    create_collection(request, bucket_id)

    path = request.path.replace('/buckets/default',
                                '/buckets/{}'.format(bucket_id))
    querystring = request.url[(request.url.index(request.path) +
                               len(request.path)):]
    try:
        # If 'id' is provided as 'default', replace with actual bucket id.
        body = request.json
        body['data']['id'] = body['data']['id'].replace('default', bucket_id)
    except:
        body = request.body or {"data": {}}
    subrequest = build_request(request, {
        'method': request.method,
        'path': path + querystring,
        'body': body,
    })
    subrequest.bound_data = request.bound_data

    try:
        response = request.invoke_subrequest(subrequest)
    except httpexceptions.HTTPException as error:
        is_redirect = error.status_code < 400
        if error.content_type == 'application/json' or is_redirect:
            response = reapply_cors(subrequest, error)
        else:
            # Ask the upper level to format the error.
            raise error
    return response
Ejemplo n.º 14
0
def default_bucket(request):
    if request.method.lower() == "options":
        path = request.path.replace("default", "unknown")
        subrequest = build_request(request, {
            "method": "OPTIONS",
            "path": path
        })
        return request.invoke_subrequest(subrequest)

    if Authenticated not in request.effective_principals:
        # Pass through the forbidden_view_config
        raise httpexceptions.HTTPForbidden()

    settings = request.registry.settings

    if asbool(settings["readonly"]):
        raise httpexceptions.HTTPMethodNotAllowed()

    bucket_id = request.default_bucket_id

    # Implicit object creations.
    # Make sure bucket exists
    create_bucket(request, bucket_id)
    # Make sure the collection exists
    create_collection(request, bucket_id)

    path = request.path.replace("/buckets/default", f"/buckets/{bucket_id}")
    querystring = request.url[(request.url.index(request.path) +
                               len(request.path)):]
    try:
        # If 'id' is provided as 'default', replace with actual bucket id.
        body = request.json
        body["data"]["id"] = body["data"]["id"].replace("default", bucket_id)
    except Exception:
        body = request.body or {"data": {}}
    subrequest = build_request(request, {
        "method": request.method,
        "path": path + querystring,
        "body": body
    })
    subrequest.bound_data = request.bound_data

    try:
        response = request.invoke_subrequest(subrequest)
    except httpexceptions.HTTPException as error:
        is_redirect = error.status_code < 400
        if error.content_type == "application/json" or is_redirect:
            response = reapply_cors(subrequest, error)
        else:
            # Ask the upper level to format the error.
            raise error
    return response
Ejemplo n.º 15
0
def default_bucket(request):
    if request.method.lower() == "options":
        path = request.path.replace("default", "unknown")
        subrequest = build_request(request, {"method": "OPTIONS", "path": path})
        return request.invoke_subrequest(subrequest)

    if Authenticated not in request.effective_principals:
        # Pass through the forbidden_view_config
        raise httpexceptions.HTTPForbidden()

    settings = request.registry.settings

    if asbool(settings["readonly"]):
        raise httpexceptions.HTTPMethodNotAllowed()

    bucket_id = request.default_bucket_id

    # Implicit object creations.
    # Make sure bucket exists
    create_bucket(request, bucket_id)
    # Make sure the collection exists
    create_collection(request, bucket_id)

    path = request.path.replace("/buckets/default", "/buckets/{}".format(bucket_id))
    querystring = request.url[(request.url.index(request.path) + len(request.path)) :]
    try:
        # If 'id' is provided as 'default', replace with actual bucket id.
        body = request.json
        body["data"]["id"] = body["data"]["id"].replace("default", bucket_id)
    except Exception:
        body = request.body or {"data": {}}
    subrequest = build_request(
        request, {"method": request.method, "path": path + querystring, "body": body}
    )
    subrequest.bound_data = request.bound_data

    try:
        response = request.invoke_subrequest(subrequest)
    except httpexceptions.HTTPException as error:
        is_redirect = error.status_code < 400
        if error.content_type == "application/json" or is_redirect:
            response = reapply_cors(subrequest, error)
        else:
            # Ask the upper level to format the error.
            raise error
    return response
Ejemplo n.º 16
0
def json_error_handler(request):
    """Cornice JSON error handler, returning consistant JSON formatted errors
    from schema validation errors.

    This is meant to be used is custom services in your applications.

    .. code-block:: python

        upload = Service(name="upload", path='/upload',
                         error_handler=errors.json_error_handler)

    .. warning::

        Only the first error of the list is formatted in the response.
        (c.f. HTTP API).
    """
    errors = request.errors
    sorted_errors = sorted(errors, key=lambda x: str(x["name"]))
    # In Cornice, we call error handler if at least one error was set.
    error = sorted_errors[0]
    name = error["name"]
    description = error["description"]

    if isinstance(description, bytes):
        description = error["description"].decode("utf-8")

    if name is not None:
        if str(name) in description:
            message = description
        else:
            message = "{name} in {location}: {description}".format_map(error)
    else:
        message = "{location}: {description}".format_map(error)

    response = http_error(
        httpexceptions.HTTPBadRequest(),
        code=errors.status,
        errno=ERRORS.INVALID_PARAMETERS.value,
        error="Invalid parameters",
        message=message,
        details=errors,
    )
    response.status = errors.status
    response = reapply_cors(request, response)
    return response
Ejemplo n.º 17
0
def json_error_handler(request):
    """Cornice JSON error handler, returning consistant JSON formatted errors
    from schema validation errors.

    This is meant to be used is custom services in your applications.

    .. code-block:: python

        upload = Service(name="upload", path='/upload',
                         error_handler=errors.json_error_handler)

    .. warning::

        Only the first error of the list is formatted in the response.
        (c.f. HTTP API).
    """
    errors = request.errors
    sorted_errors = sorted(errors, key=lambda x: str(x["name"]))
    # In Cornice, we call error handler if at least one error was set.
    error = sorted_errors[0]
    name = error["name"]
    description = error["description"]

    if isinstance(description, bytes):
        description = error["description"].decode("utf-8")

    if name is not None:
        if name in description:
            message = description
        else:
            message = "{name} in {location}: {description}".format_map(error)
    else:
        message = "{location}: {description}".format_map(error)

    response = http_error(
        httpexceptions.HTTPBadRequest(),
        code=errors.status,
        errno=ERRORS.INVALID_PARAMETERS.value,
        error="Invalid parameters",
        message=message,
        details=errors,
    )
    response.status = errors.status
    response = reapply_cors(request, response)
    return response
Ejemplo n.º 18
0
def authorization_required(response, request):
    """Distinguish authentication required (``401 Unauthorized``) from
    not allowed (``403 Forbidden``).
    """
    if Authenticated not in request.effective_principals:
        error_msg = "Please authenticate yourself to use this endpoint."
        response = http_error(httpexceptions.HTTPUnauthorized(),
                              errno=ERRORS.MISSING_AUTH_TOKEN,
                              message=error_msg)
        response.headers.extend(forget(request))
        return response

    if response.content_type != "application/json":
        error_msg = "This user cannot access this resource."
        response = http_error(httpexceptions.HTTPForbidden(),
                              errno=ERRORS.FORBIDDEN,
                              message=error_msg)
    return reapply_cors(request, response)
Ejemplo n.º 19
0
def authorization_required(response, request):
    """Distinguish authentication required (``401 Unauthorized``) from
    not allowed (``403 Forbidden``).
    """
    if Authenticated not in request.effective_principals:
        error_msg = "Please authenticate yourself to use this endpoint."
        response = http_error(httpexceptions.HTTPUnauthorized(),
                              errno=ERRORS.MISSING_AUTH_TOKEN,
                              message=error_msg)
        response.headers.extend(forget(request))
        return response

    if response.content_type != "application/json":
        error_msg = "This user cannot access this resource."
        response = http_error(httpexceptions.HTTPForbidden(),
                              errno=ERRORS.FORBIDDEN,
                              message=error_msg)
    return reapply_cors(request, response)
Ejemplo n.º 20
0
def json_error_handler(request):
    """Cornice JSON error handler, returning consistant JSON formatted errors
    from schema validation errors.

    This is meant to be used is custom services in your applications.

    .. code-block:: python

        upload = Service(name="upload", path='/upload',
                         error_handler=errors.json_error_handler)

    .. warning::

        Only the first error of the list is formatted in the response.
        (c.f. HTTP API).
    """
    errors = request.errors
    assert len(errors) != 0

    sorted_errors = sorted(errors, key=lambda x: six.text_type(x['name']))
    error = sorted_errors[0]
    name = error['name']
    description = error['description']

    if isinstance(description, six.binary_type):
        description = error['description'].decode('utf-8')

    if name is not None:
        if name in description:
            message = description
        else:
            message = '%(name)s in %(location)s: %(description)s' % error
    else:
        message = '%(location)s: %(description)s' % error

    response = http_error(httpexceptions.HTTPBadRequest(),
                          code=errors.status,
                          errno=ERRORS.INVALID_PARAMETERS.value,
                          error='Invalid parameters',
                          message=message,
                          details=errors)
    response.status = errors.status
    response = reapply_cors(request, response)
    return response
Ejemplo n.º 21
0
def json_error_handler(errors):
    """Cornice JSON error handler, returning consistant JSON formatted errors
    from schema validation errors.

    This is meant to be used is custom services in your applications.

    .. code-block:: python

        upload = Service(name="upload", path='/upload',
                         error_handler=errors.json_error_handler)

    .. warning::

        Only the first error of the list is formatted in the response.
        (c.f. protocol).
    """
    assert len(errors) != 0

    sorted_errors = sorted(errors, key=lambda x: six.text_type(x['name']))
    error = sorted_errors[0]
    name = error['name']
    description = error['description']

    if isinstance(description, six.binary_type):
        description = error['description'].decode('utf-8')

    if name is not None:
        if name in description:
            message = description
        else:
            message = '%(name)s in %(location)s: %(description)s' % error
    else:
        message = '%(location)s: %(description)s' % error

    response = http_error(httpexceptions.HTTPBadRequest(),
                          code=errors.status,
                          errno=ERRORS.INVALID_PARAMETERS.value,
                          error='Invalid parameters',
                          message=message,
                          details=errors)
    response.status = errors.status
    response = reapply_cors(errors.request, response)
    return response
Ejemplo n.º 22
0
    def eos_tween(request):
        eos_date = registry.settings["eos"]
        eos_url = registry.settings["eos_url"]
        eos_message = registry.settings["eos_message"]
        if not eos_date:
            return handler(request)

        eos_date = dateparser.parse(eos_date)
        if eos_date > datetime.now():
            code = "soft-eol"
            request.response = handler(request)
        else:
            code = "hard-eol"
            request.response = errors.http_error(
                HTTPGone(), errno=errors.ERRORS.SERVICE_DEPRECATED, message=deprecation_msg
            )

        errors.send_alert(request, eos_message, url=eos_url, code=code)
        return utils.reapply_cors(request, request.response)
Ejemplo n.º 23
0
    def wrap_view(request, *args, **kwargs):
        response = view(request, *args, **kwargs)

        # We need to re-apply the CORS checks done by Cornice, since we're
        # recreating the response from scratch.
        return reapply_cors(request, response)
Ejemplo n.º 24
0
    def wrap_view(request, *args, **kwargs):
        response = view(request, *args, **kwargs)

        # We need to re-apply the CORS checks done by Cornice, since we're
        # recreating the response from scratch.
        return reapply_cors(request, response)