Beispiel #1
0
def _validate_and_prep_request_headers(req):
    """
    Validate that the value from x-symlink-target header is well formatted
    and that the x-symlink-target-etag header (if present) does not contain
    problematic characters. We assume the caller ensures that
    x-symlink-target header is present in req.headers.

    :param req: HTTP request object
    :returns: a tuple, the full versioned path to the object (as a WSGI string)
              and the X-Symlink-Target-Etag header value which may be None
    :raise: HTTPPreconditionFailed if x-symlink-target value
            is not well formatted.
    :raise: HTTPBadRequest if the x-symlink-target value points to the request
            path.
    :raise: HTTPBadRequest if the x-symlink-target-etag value contains
            a semicolon, double-quote, or backslash.
    """
    # N.B. check_path_header doesn't assert the leading slash and
    # copy middleware may accept the format. In the symlink, API
    # says apparently to use "container/object" format so add the
    # validation first, here.
    error_body = 'X-Symlink-Target header must be of the form ' \
                 '<container name>/<object name>'
    if wsgi_unquote(req.headers[TGT_OBJ_SYMLINK_HDR]).startswith('/'):
        raise HTTPPreconditionFailed(body=error_body,
                                     request=req,
                                     content_type='text/plain')

    # check container and object format
    container, obj = check_path_header(req, TGT_OBJ_SYMLINK_HDR, 2, error_body)
    req.headers[TGT_OBJ_SYMLINK_HDR] = wsgi_quote('%s/%s' % (container, obj))

    # Check account format if it exists
    account = check_account_format(
        req, wsgi_unquote(req.headers[TGT_ACCT_SYMLINK_HDR])) \
        if TGT_ACCT_SYMLINK_HDR in req.headers else None

    # Extract request path
    _junk, req_acc, req_cont, req_obj = req.split_path(4, 4, True)

    if account:
        req.headers[TGT_ACCT_SYMLINK_HDR] = wsgi_quote(account)
    else:
        account = req_acc

    # Check if symlink targets the symlink itself or not
    if (account, container, obj) == (req_acc, req_cont, req_obj):
        raise HTTPBadRequest(body='Symlink cannot target itself',
                             request=req,
                             content_type='text/plain')
    etag = req.headers.get(TGT_ETAG_SYMLINK_HDR, None)
    if etag and any(c in etag for c in ';"\\'):
        # See cgi.parse_header for why the above chars are problematic
        raise HTTPBadRequest(body='Bad %s format' %
                             TGT_ETAG_SYMLINK_HDR.title(),
                             request=req,
                             content_type='text/plain')
    if not (etag or req.headers.get('Content-Type')):
        req.headers['Content-Type'] = 'application/symlink'
    return '/v1/%s/%s/%s' % (account, container, obj), etag
Beispiel #2
0
def _check_symlink_header(req):
    """
    Validate that the value from x-symlink-target header is
    well formatted. We assume the caller ensures that
    x-symlink-target header is present in req.headers.

    :param req: HTTP request object
    :raise: HTTPPreconditionFailed if x-symlink-target value
            is not well formatted.
    :raise: HTTPBadRequest if the x-symlink-target value points to the request
            path.
    """
    # N.B. check_path_header doesn't assert the leading slash and
    # copy middleware may accept the format. In the symlink, API
    # says apparently to use "container/object" format so add the
    # validation first, here.
    error_body = 'X-Symlink-Target header must be of the form ' \
                 '<container name>/<object name>'
    try:
        if wsgi_unquote(req.headers[TGT_OBJ_SYMLINK_HDR]).startswith('/'):
            raise HTTPPreconditionFailed(body=error_body,
                                         request=req,
                                         content_type='text/plain')
    except TypeError:
        raise HTTPPreconditionFailed(body=error_body,
                                     request=req,
                                     content_type='text/plain')

    # check container and object format
    container, obj = check_path_header(req, TGT_OBJ_SYMLINK_HDR, 2, error_body)
    req.headers[TGT_OBJ_SYMLINK_HDR] = wsgi_quote('%s/%s' % (container, obj))

    # Check account format if it exists
    try:
        account = check_account_format(
            req, wsgi_unquote(req.headers[TGT_ACCT_SYMLINK_HDR])) \
            if TGT_ACCT_SYMLINK_HDR in req.headers else None
    except TypeError:
        raise HTTPPreconditionFailed(
            body='Account name cannot contain slashes',
            request=req,
            content_type='text/plain')

    # Extract request path
    _junk, req_acc, req_cont, req_obj = req.split_path(4, 4, True)

    if account:
        req.headers[TGT_ACCT_SYMLINK_HDR] = wsgi_quote(account)
    else:
        account = req_acc

    # Check if symlink targets the symlink itself or not
    if (account, container, obj) == (req_acc, req_cont, req_obj):
        raise HTTPBadRequest(body='Symlink cannot target itself',
                             request=req,
                             content_type='text/plain')
Beispiel #3
0
def _check_destination_header(req):
    """
    Validate that the value from destination header is
    well formatted. We assume the caller ensures that
    destination header is present in req.headers.

    :param req: HTTP request object
    :returns: A tuple with container name and object name
    :raise HTTPPreconditionFailed: if destination value
            is not well formatted.
    """
    return check_path_header(
        req, 'Destination', 2, 'Destination header must be of the form '
        '<container name>/<object name>')
Beispiel #4
0
def _check_destination_header(req):
    """
    Validate that the value from destination header is
    well formatted. We assume the caller ensures that
    destination header is present in req.headers.

    :param req: HTTP request object
    :returns: A tuple with container name and object name
    :raise HTTPPreconditionFailed: if destination value
            is not well formatted.
    """
    return check_path_header(req, 'Destination', 2,
                             'Destination header must be of the form '
                             '<container name>/<object name>')
Beispiel #5
0
def _check_symlink_header(req):
    """
    Validate that the value from x-symlink-target header is
    well formatted. We assume the caller ensures that
    x-symlink-target header is present in req.headers.

    :param req: HTTP request object
    :raise: HTTPPreconditionFailed if x-symlink-target value
            is not well formatted.
    :raise: HTTPBadRequest if the x-symlink-target value points to the request
            path.
    """
    # N.B. check_path_header doesn't assert the leading slash and
    # copy middleware may accept the format. In the symlink, API
    # says apparently to use "container/object" format so add the
    # validation first, here.
    if unquote(req.headers[TGT_OBJ_SYMLINK_HDR]).startswith('/'):
        raise HTTPPreconditionFailed(
            body='X-Symlink-Target header must be of the '
                 'form <container name>/<object name>',
            request=req, content_type='text/plain')

    # check container and object format
    container, obj = check_path_header(
        req, TGT_OBJ_SYMLINK_HDR, 2,
        'X-Symlink-Target header must be of the '
        'form <container name>/<object name>')

    # Check account format if it exists
    account = check_account_format(
        req, unquote(req.headers[TGT_ACCT_SYMLINK_HDR])) \
        if TGT_ACCT_SYMLINK_HDR in req.headers else None

    # Extract request path
    _junk, req_acc, req_cont, req_obj = req.split_path(4, 4, True)

    if not account:
        account = req_acc

    # Check if symlink targets the symlink itself or not
    if (account, container, obj) == (req_acc, req_cont, req_obj):
        raise HTTPBadRequest(
            body='Symlink cannot target itself',
            request=req, content_type='text/plain')