Пример #1
0
 def test_validate_destination(self):
     req = Request.blank('/v/a/c/o', headers={'destination': 'c/o2'})
     src_cont, src_obj = constraints.check_destination_header(req)
     self.assertEqual(src_cont, 'c')
     self.assertEqual(src_obj, 'o2')
     req = Request.blank('/v/a/c/o', headers={'destination': 'c/subdir/o2'})
     src_cont, src_obj = constraints.check_destination_header(req)
     self.assertEqual(src_cont, 'c')
     self.assertEqual(src_obj, 'subdir/o2')
     req = Request.blank('/v/a/c/o', headers={'destination': '/c/o2'})
     src_cont, src_obj = constraints.check_destination_header(req)
     self.assertEqual(src_cont, 'c')
     self.assertEqual(src_obj, 'o2')
Пример #2
0
 def test_validate_destination(self):
     req = Request.blank("/v/a/c/o", headers={"destination": "c/o2"})
     src_cont, src_obj = constraints.check_destination_header(req)
     self.assertEqual(src_cont, "c")
     self.assertEqual(src_obj, "o2")
     req = Request.blank("/v/a/c/o", headers={"destination": "c/subdir/o2"})
     src_cont, src_obj = constraints.check_destination_header(req)
     self.assertEqual(src_cont, "c")
     self.assertEqual(src_obj, "subdir/o2")
     req = Request.blank("/v/a/c/o", headers={"destination": "/c/o2"})
     src_cont, src_obj = constraints.check_destination_header(req)
     self.assertEqual(src_cont, "c")
     self.assertEqual(src_obj, "o2")
Пример #3
0
 def COPY(self, req):
     """HTTP COPY request handler."""
     if not req.headers.get('Destination'):
         return HTTPPreconditionFailed(request=req,
                                       body='Destination header required')
     dest_account = self.account_name
     if 'Destination-Account' in req.headers:
         dest_account = req.headers.get('Destination-Account')
         dest_account = check_account_format(req, dest_account)
         req.headers['X-Copy-From-Account'] = self.account_name
         self.account_name = dest_account
         del req.headers['Destination-Account']
     dest_container, dest_object = check_destination_header(req)
     source = '/%s/%s' % (self.container_name, self.object_name)
     self.container_name = dest_container
     self.object_name = dest_object
     # re-write the existing request as a PUT instead of creating a new one
     # since this one is already attached to the posthooklogger
     req.method = 'PUT'
     req.path_info = '/v1/%s/%s/%s' % \
                     (dest_account, dest_container, dest_object)
     req.headers['Content-Length'] = 0
     req.headers['X-Copy-From'] = quote(source)
     del req.headers['Destination']
     return self.PUT(req)
Пример #4
0
 def COPY(self, req):
     """HTTP COPY request handler."""
     if not req.headers.get('Destination'):
         return HTTPPreconditionFailed(request=req,
                                       body='Destination header required')
     dest_account = self.account_name
     if 'Destination-Account' in req.headers:
         dest_account = req.headers.get('Destination-Account')
         dest_account = check_account_format(req, dest_account)
         req.headers['X-Copy-From-Account'] = self.account_name
         self.account_name = dest_account
         del req.headers['Destination-Account']
     dest_container, dest_object = check_destination_header(req)
     source = '/%s/%s' % (self.container_name, self.object_name)
     self.container_name = dest_container
     self.object_name = dest_object
     # re-write the existing request as a PUT instead of creating a new one
     # since this one is already attached to the posthooklogger
     req.method = 'PUT'
     req.path_info = '/v1/%s/%s/%s' % \
                     (dest_account, dest_container, dest_object)
     req.headers['Content-Length'] = 0
     req.headers['X-Copy-From'] = quote(source)
     del req.headers['Destination']
     return self.PUT(req)
Пример #5
0
    def object_request(self, req, version, account, container, obj,
                       allow_versioned_writes):
        account_name = unquote(account)
        container_name = unquote(container)
        object_name = unquote(obj)
        container_info = None
        resp = None
        is_enabled = config_true_value(allow_versioned_writes)
        if req.method in ('PUT', 'DELETE'):
            container_info = get_container_info(
                req.environ, self.app)
        elif req.method == 'COPY' and 'Destination' in req.headers:
            if 'Destination-Account' in req.headers:
                account_name = req.headers.get('Destination-Account')
                account_name = check_account_format(req, account_name)
            container_name, object_name = check_destination_header(req)
            req.environ['PATH_INFO'] = "/%s/%s/%s/%s" % (
                version, account_name, container_name, object_name)
            container_info = get_container_info(
                req.environ, self.app)

        if not container_info:
            return self.app

        # To maintain backwards compatibility, container version
        # location could be stored as sysmeta or not, need to check both.
        # If stored as sysmeta, check if middleware is enabled. If sysmeta
        # is not set, but versions property is set in container_info, then
        # for backwards compatibility feature is enabled.
        object_versions = container_info.get(
            'sysmeta', {}).get('versions-location')
        if object_versions and isinstance(object_versions, unicode):
            object_versions = object_versions.encode('utf-8')
        elif not object_versions:
            object_versions = container_info.get('versions')
            # if allow_versioned_writes is not set in the configuration files
            # but 'versions' is configured, enable feature to maintain
            # backwards compatibility
            if not allow_versioned_writes and object_versions:
                is_enabled = True

        if is_enabled and object_versions:
            object_versions = unquote(object_versions)
            vw_ctx = VersionedWritesContext(self.app, self.logger)
            if req.method in ('PUT', 'COPY'):
                policy_idx = req.headers.get(
                    'X-Backend-Storage-Policy-Index',
                    container_info['storage_policy'])
                resp = vw_ctx.handle_obj_versions_put(
                    req, object_versions, object_name, policy_idx)
            else:  # handle DELETE
                resp = vw_ctx.handle_obj_versions_delete(
                    req, object_versions, account_name,
                    container_name, object_name)

        if resp:
            return resp
        else:
            return self.app
Пример #6
0
    def object_request(self, req, version, account, container, obj,
                       allow_versioned_writes):
        account_name = unquote(account)
        container_name = unquote(container)
        object_name = unquote(obj)
        container_info = None
        resp = None
        is_enabled = config_true_value(allow_versioned_writes)
        if req.method in ('PUT', 'DELETE'):
            container_info = get_container_info(
                req.environ, self.app)
        elif req.method == 'COPY' and 'Destination' in req.headers:
            if 'Destination-Account' in req.headers:
                account_name = req.headers.get('Destination-Account')
                account_name = check_account_format(req, account_name)
            container_name, object_name = check_destination_header(req)
            req.environ['PATH_INFO'] = "/%s/%s/%s/%s" % (
                version, account_name, container_name, object_name)
            container_info = get_container_info(
                req.environ, self.app)

        if not container_info:
            return self.app

        # To maintain backwards compatibility, container version
        # location could be stored as sysmeta or not, need to check both.
        # If stored as sysmeta, check if middleware is enabled. If sysmeta
        # is not set, but versions property is set in container_info, then
        # for backwards compatibility feature is enabled.
        object_versions = container_info.get(
            'sysmeta', {}).get('versions-location')
        if object_versions and isinstance(object_versions, six.text_type):
            object_versions = object_versions.encode('utf-8')
        elif not object_versions:
            object_versions = container_info.get('versions')
            # if allow_versioned_writes is not set in the configuration files
            # but 'versions' is configured, enable feature to maintain
            # backwards compatibility
            if not allow_versioned_writes and object_versions:
                is_enabled = True

        if is_enabled and object_versions:
            object_versions = unquote(object_versions)
            vw_ctx = VersionedWritesContext(self.app, self.logger)
            if req.method in ('PUT', 'COPY'):
                policy_idx = req.headers.get(
                    'X-Backend-Storage-Policy-Index',
                    container_info['storage_policy'])
                resp = vw_ctx.handle_obj_versions_put(
                    req, object_versions, object_name, policy_idx)
            else:  # handle DELETE
                resp = vw_ctx.handle_obj_versions_delete(
                    req, object_versions, account_name,
                    container_name, object_name)

        if resp:
            return resp
        else:
            return self.app
Пример #7
0
 def test_validate_destination(self):
     req = Request.blank(
         '/v/a/c/o',
         headers={'destination': 'c/o2'})
     src_cont, src_obj = constraints.check_destination_header(req)
     self.assertEqual(src_cont, 'c')
     self.assertEqual(src_obj, 'o2')
     req = Request.blank(
         '/v/a/c/o',
         headers={'destination': 'c/subdir/o2'})
     src_cont, src_obj = constraints.check_destination_header(req)
     self.assertEqual(src_cont, 'c')
     self.assertEqual(src_obj, 'subdir/o2')
     req = Request.blank(
         '/v/a/c/o',
         headers={'destination': '/c/o2'})
     src_cont, src_obj = constraints.check_destination_header(req)
     self.assertEqual(src_cont, 'c')
     self.assertEqual(src_obj, 'o2')
Пример #8
0
    def object_request(self, req, api_version, account, container, obj,
                       allow_versioned_writes):
        account_name = unquote(account)
        container_name = unquote(container)
        object_name = unquote(obj)
        container_info = None
        resp = None
        is_enabled = config_true_value(allow_versioned_writes)
        if req.method in ('PUT', 'DELETE'):
            container_info = get_container_info(req.environ, self.app)
        elif req.method == 'COPY' and 'Destination' in req.headers:
            if 'Destination-Account' in req.headers:
                account_name = req.headers.get('Destination-Account')
                account_name = check_account_format(req, account_name)
            container_name, object_name = check_destination_header(req)
            req.environ['PATH_INFO'] = "/%s/%s/%s/%s" % (
                api_version, account_name, container_name, object_name)
            container_info = get_container_info(req.environ, self.app)

        if not container_info:
            return self.app

        # To maintain backwards compatibility, container version
        # location could be stored as sysmeta or not, need to check both.
        # If stored as sysmeta, check if middleware is enabled. If sysmeta
        # is not set, but versions property is set in container_info, then
        # for backwards compatibility feature is enabled.
        versions_cont = container_info.get('sysmeta',
                                           {}).get('versions-location')
        if not versions_cont:
            versions_cont = container_info.get('versions')
            # if allow_versioned_writes is not set in the configuration files
            # but 'versions' is configured, enable feature to maintain
            # backwards compatibility
            if not allow_versioned_writes and versions_cont:
                is_enabled = True

        if is_enabled and versions_cont:
            versions_cont = unquote(versions_cont).split('/')[0]
            vw_ctx = VersionedWritesContext(self.app, self.logger)
            if req.method in ('PUT', 'COPY'):
                resp = vw_ctx.handle_obj_versions_put(req, versions_cont,
                                                      api_version,
                                                      account_name,
                                                      object_name)
            else:  # handle DELETE
                resp = vw_ctx.handle_obj_versions_delete(
                    req, versions_cont, api_version, account_name,
                    container_name, object_name)

        if resp:
            return resp
        else:
            return self.app
Пример #9
0
    def COPY(self):
        """
        COPY handler on Proxy
        """
        if not self.request.headers.get('Destination'):
            return HTTPPreconditionFailed(request=self.request,
                                          body='Destination header required')

        params = self.verify_access_to_storlet()
        self.gateway.augmentStorletRequest(self.request, params)
        self._validate_copy_request()
        dest_container, dest_object = check_destination_header(self.request)

        # re-write the existing request as a PUT instead of creating a new one
        # TODO(eranr): do we want a new sub_request or re-write existing one as
        # we do below. See proxy obj controller COPY.
        self.request.method = 'PUT'
        self.request.path_info = '/v1/%s/%s/%s' % \
                                 (self.account, dest_container, dest_object)
        self.request.headers['Content-Length'] = 0
        del self.request.headers['Destination']

        return self.base_handle_copy_request(self.container, self.obj,
                                             dest_container, dest_object)
Пример #10
0
    def __call__(self, req):
        try:
            (version, account, container, obj) = req.split_path(3, 4, True)
        except ValueError:
            return self.app

        # verify new quota headers are properly formatted
        if not obj and req.method in ('PUT', 'POST'):
            val = req.headers.get('X-Container-Meta-Quota-Bytes')
            if val and not val.isdigit():
                return HTTPBadRequest(body='Invalid bytes quota.')
            val = req.headers.get('X-Container-Meta-Quota-Count')
            if val and not val.isdigit():
                return HTTPBadRequest(body='Invalid count quota.')

        # check user uploads against quotas
        elif obj and req.method in ('PUT', 'COPY'):
            container_info = None
            if req.method == 'PUT':
                container_info = get_container_info(
                    req.environ, self.app, swift_source='CQ')
            if req.method == 'COPY' and 'Destination' in req.headers:
                dest_account = account
                if 'Destination-Account' in req.headers:
                    dest_account = req.headers.get('Destination-Account')
                    dest_account = check_account_format(req, dest_account)
                dest_container, dest_object = check_destination_header(req)
                path_info = req.environ['PATH_INFO']
                req.environ['PATH_INFO'] = "/%s/%s/%s/%s" % (
                    version, dest_account, dest_container, dest_object)
                try:
                    container_info = get_container_info(
                        req.environ, self.app, swift_source='CQ')
                finally:
                    req.environ['PATH_INFO'] = path_info
            if not container_info or not is_success(container_info['status']):
                # this will hopefully 404 later
                return self.app

            if 'quota-bytes' in container_info.get('meta', {}) and \
                    'bytes' in container_info and \
                    container_info['meta']['quota-bytes'].isdigit():
                content_length = (req.content_length or 0)
                if 'x-copy-from' in req.headers or req.method == 'COPY':
                    if 'x-copy-from' in req.headers:
                        container, obj = check_copy_from_header(req)
                    path = '/%s/%s/%s/%s' % (version, account,
                                             container, obj)
                    object_info = get_object_info(req.environ, self.app, path)
                    if not object_info or not object_info['length']:
                        content_length = 0
                    else:
                        content_length = int(object_info['length'])
                new_size = int(container_info['bytes']) + content_length
                if int(container_info['meta']['quota-bytes']) < new_size:
                    return self.bad_response(req, container_info)

            if 'quota-count' in container_info.get('meta', {}) and \
                    'object_count' in container_info and \
                    container_info['meta']['quota-count'].isdigit():
                new_count = int(container_info['object_count']) + 1
                if int(container_info['meta']['quota-count']) < new_count:
                    return self.bad_response(req, container_info)

        return self.app