Exemple #1
0
    def __init__(self, *args, **kwargs):
        swob.Response.__init__(self, *args, **kwargs)

        sw_sysmeta_headers = swob.HeaderKeyDict()
        sw_headers = swob.HeaderKeyDict()
        headers = HeaderKeyDict()
        self.is_slo = False

        for key, val in self.headers.iteritems():
            _key = key.lower()
            if _key.startswith(sysmeta_prefix('object')) or \
                    _key.startswith(sysmeta_prefix('container')):
                sw_sysmeta_headers[key] = val
            else:
                sw_headers[key] = val

        # Handle swift headers
        for key, val in sw_headers.iteritems():
            _key = key.lower()

            if _key.startswith('x-object-meta-'):
                # Note that AWS ignores user-defined headers with '=' in the
                # header name. We translated underscores to '=5F' on the way
                # in, though.
                headers['x-amz-meta-' + _key[14:].replace('=5f', '_')] = val
            elif _key in ('content-length', 'content-type', 'content-range',
                          'content-encoding', 'content-disposition',
                          'content-language', 'etag', 'last-modified',
                          'x-robots-tag', 'cache-control', 'expires',
                          'x-amz-version-id'):
                headers[key] = val
            elif _key == 'x-object-sysmeta-version-id':
                headers['x-amz-version-id'] = val
            elif _key == 'x-static-large-object':
                # for delete slo
                self.is_slo = config_true_value(val)

        # Check whether we stored the AWS-style etag on upload
        override_etag = sw_sysmeta_headers.get(sysmeta_header(
            'object', 'etag'))
        if override_etag not in (None, ''):
            # Multipart uploads in AWS have ETags like
            #   <MD5(part_etag1 || ... || part_etagN)>-<number of parts>
            headers['etag'] = override_etag
        elif self.is_slo and 'etag' in headers:
            # Many AWS clients use the presence of a '-' to decide whether
            # to attempt client-side download validation, so even if we
            # didn't store the AWS-style header, tack on a '-N'. (Use 'N'
            # because we don't actually know how many parts there are.)
            headers['etag'] += '-N'

        self.headers = headers

        if self.etag:
            # add double quotes to the etag header
            self.etag = self.etag

        # Used for pure swift header handling at the request layer
        self.sw_headers = sw_headers
        self.sysmeta_headers = sw_sysmeta_headers
Exemple #2
0
    def __call__(self, env, start_response):
        method = env['REQUEST_METHOD']
        path = env['PATH_INFO']
        _, acc, cont, obj = split_path(env['PATH_INFO'],
                                       0,
                                       4,
                                       rest_with_last=True)
        if env.get('QUERY_STRING'):
            path += '?' + env['QUERY_STRING']

        if 'swift.authorize' in env:
            resp = env['swift.authorize']()
            if resp:
                return resp(env, start_response)

        headers = swob.Request(env).headers
        self._calls.append((method, path, headers))
        self.swift_sources.append(env.get('swift.source'))

        try:
            resp_class, raw_headers, body = self._responses[(method, path)]
            headers = swob.HeaderKeyDict(raw_headers)
        except KeyError:
            if (env.get('QUERY_STRING')
                    and (method, env['PATH_INFO']) in self._responses):
                resp_class, raw_headers, body = self._responses[(
                    method, env['PATH_INFO'])]
                headers = swob.HeaderKeyDict(raw_headers)
            elif method == 'HEAD' and ('GET', path) in self._responses:
                resp_class, raw_headers, _ = self._responses[('GET', path)]
                body = None
                headers = swob.HeaderKeyDict(raw_headers)
            elif method == 'GET' and obj and path in self.uploaded:
                resp_class = swob.HTTPOk
                headers, body = self.uploaded[path]
            else:
                print "Didn't find %r in allowed responses" % (
                    (method, path), )
                raise

        # simulate object PUT
        if method == 'PUT' and obj:
            input = env['wsgi.input'].read()
            etag = md5(input).hexdigest()
            headers.setdefault('Etag', etag)
            headers.setdefault('Content-Length', len(input))

            # keep it for subsequent GET requests later
            self.uploaded[path] = (deepcopy(headers), input)
            if "CONTENT_TYPE" in env:
                self.uploaded[path][0]['Content-Type'] = env["CONTENT_TYPE"]

        # range requests ought to work, hence conditional_response=True
        req = swob.Request(env)
        resp = resp_class(req=req,
                          headers=headers,
                          body=body,
                          conditional_response=True)
        return resp(env, start_response)
Exemple #3
0
    def __init__(self, *args, **kwargs):
        swob.Response.__init__(self, *args, **kwargs)

        if self.etag:
            # add double quotes to the etag header
            self.etag = self.etag

        sw_sysmeta_headers = swob.HeaderKeyDict()
        sw_headers = swob.HeaderKeyDict()
        headers = HeaderKeyDict()
        self.is_slo = False

        for key, val in self.headers.iteritems():
            _key = key.lower()
            if _key.startswith(sysmeta_prefix('object')) or \
                    _key.startswith(sysmeta_prefix('container')):
                sw_sysmeta_headers[key] = val
            else:
                sw_headers[key] = val

        # Handle swift headers
        for key, val in sw_headers.iteritems():
            _key = key.lower()

            if _key.startswith('x-object-meta-'):
                headers['x-amz-meta-' + _key[14:]] = val
            elif _key in ('content-length', 'content-type', 'content-range',
                          'content-encoding', 'content-disposition',
                          'content-language', 'etag', 'last-modified',
                          'x-robots-tag', 'cache-control', 'expires',
                          'x-amz-version-id'):
                headers[key] = val
            elif _key == 'x-object-sysmeta-version-id':
                headers['x-amz-version-id'] = val
            elif _key == 'x-static-large-object':
                # for delete slo
                self.is_slo = config_true_value(val)

        if self.is_slo:  # and 'etag' in headers
            # Multipart uploads in AWS have ETags like
            #   <MD5(part_etag1 || ... || part_etagN)>-<number of parts>
            if '-' not in headers.get('etag', ''):
                if 's3_etag' in headers.get('content-type', ''):
                    # ETag was computed at upload, and saved in content-type
                    ctype, s3_etag = extract_s3_etag(headers['content-type'])
                    headers['etag'] = '"%s"' % s3_etag
                    headers['content-type'] = ctype
                else:
                    # Many AWS clients use the presence of a '-' to decide
                    # whether to attempt client-side download validation,
                    # so tack on a '-N' ('N' because we don't actually know
                    # how many parts there are).
                    headers['etag'] = '"%s-N"' % self.etag

        self.headers = headers
        # Used for pure swift header handling at the request layer
        self.sw_headers = sw_headers
        self.sysmeta_headers = sw_sysmeta_headers
Exemple #4
0
    def test_etag_comparison_ignores_quotes(self):
        # a little future-proofing here in case we ever fix this in swob
        self.app.register(
            'HEAD', '/v1/AUTH_test/mani/festo', swob.HTTPOk, {
                'Content-Length': '0',
                'Etag': 'blah',
                'X-Object-Manifest': 'c/quotetags'
            }, None)
        self.app.register(
            'GET', '/v1/AUTH_test/c?format=json&prefix=quotetags', swob.HTTPOk,
            {'Content-Type': 'application/json; charset=utf-8'},
            json.dumps([{
                "hash": "\"abc\"",
                "bytes": 5,
                "name": "quotetags1",
                "last_modified": "2013-11-22T02:42:14.261620",
                "content-type": "application/octet-stream"
            }, {
                "hash": "def",
                "bytes": 5,
                "name": "quotetags2",
                "last_modified": "2013-11-22T02:42:14.261620",
                "content-type": "application/octet-stream"
            }]))

        req = swob.Request.blank('/v1/AUTH_test/mani/festo',
                                 environ={'REQUEST_METHOD': 'HEAD'})
        status, headers, body = self.call_dlo(req)
        headers = swob.HeaderKeyDict(headers)
        self.assertEqual(headers["Etag"],
                         '"' + hashlib.md5("abcdef").hexdigest() + '"')
Exemple #5
0
    def check_copy_source(self, app):
        """
        check_copy_source checks the copy source existence and if copying an
        object to itself, for illegal request parameters

        :returns: the source HEAD response
        """
        if 'x-oss-copy-source' not in self.headers:
            self.req.headers['x-object-meta-object-type'] = 'Normal'
            return None

        src_path = unquote(self.headers['x-oss-copy-source'])
        src_path = src_path if src_path.startswith('/') else \
            ('/' + src_path)
        src_bucket, src_obj = split_path(src_path, 0, 2, True)
        headers = swob.HeaderKeyDict()
        headers.update(self._copy_source_headers())

        src_resp = self.get_response(app,
                                     'HEAD',
                                     src_bucket,
                                     src_obj,
                                     headers=headers)
        if src_resp.status_int == 304:  # pylint: disable-msg=E1101
            raise PreconditionFailed()

        self.headers['x-oss-copy-source'] = \
            '/' + self.headers['x-oss-copy-source'].lstrip('/')
        source_container, source_obj = \
            split_path(self.headers['x-oss-copy-source'], 1, 2, True)

        return src_resp
Exemple #6
0
    def test_get_undersize_segment(self):
        # If we send a Content-Length header to the client, it's based on the
        # container listing. If a segment gets smaller by the time we get to
        # it (like if a client uploads a smaller segment w/the same name), we
        # need to raise an exception so that the connection will be closed by
        # the WSGI server. Otherwise, the WSGI server will be waiting for the
        # next request, the client will still be waiting for the rest of the
        # response, and nobody will be happy.

        # Shrink it by a single byte
        self.app.register(
            'GET', '/v1/AUTH_test/c/seg_03',
            swob.HTTPOk, {'Content-Length': '4', 'Etag': md5hex("cccc")},
            'cccc')

        req = swob.Request.blank(
            '/v1/AUTH_test/mancon/manifest',
            environ={'REQUEST_METHOD': 'GET'})
        status, headers, body, exc = self.call_dlo(req, expect_exception=True)
        headers = swob.HeaderKeyDict(headers)

        self.assertEqual(status, '200 OK')  # sanity check
        self.assertEqual(headers.get('Content-Length'), '25')  # sanity check
        self.assertEqual(body, 'aaaaabbbbbccccdddddeeeee')
        self.assertTrue(isinstance(exc, exceptions.SegmentError))
Exemple #7
0
    def check_copy_source(self, app):
        """
        check_copy_source checks the copy source existence

        :return : last modified str if copy-source header exist
                  otherwise None
        """
        if 'X-Amz-Copy-Source' in self.headers:
            src_path = self.headers['X-Amz-Copy-Source']
            src_path = src_path if src_path.startswith('/') else \
                ('/' + src_path)
            src_bucket, src_obj = split_path(src_path, 0, 2, True)
            headers = swob.HeaderKeyDict()
            headers.update(self._copy_source_headers())

            src_resp = self.get_response(app,
                                         'HEAD',
                                         src_bucket,
                                         src_obj,
                                         headers=headers)
            if src_resp.status_int == 304:  # pylint: disable-msg=E1101
                raise PreconditionFailed()
            return src_resp.last_modified.isoformat()[:-6]

        return None
Exemple #8
0
    def test_get_oversize_segment(self):
        # If we send a Content-Length header to the client, it's based on the
        # container listing. If a segment gets bigger by the time we get to it
        # (like if a client uploads a bigger segment w/the same name), we need
        # to not send anything beyond the length we promised. Also, we should
        # probably raise an exception.

        # This is now longer than the original seg_03+seg_04+seg_05 combined
        self.app.register('GET', '/v1/AUTH_test/c/seg_03', swob.HTTPOk, {
            'Content-Length': '20',
            'Etag': 'seg03-etag'
        }, 'cccccccccccccccccccc')

        req = swob.Request.blank('/v1/AUTH_test/mancon/manifest',
                                 environ={'REQUEST_METHOD': 'GET'})
        status, headers, body, exc = self.call_dlo(req, expect_exception=True)
        headers = swob.HeaderKeyDict(headers)

        self.assertEqual(status, '200 OK')  # sanity check
        self.assertEqual(headers.get('Content-Length'), '25')  # sanity check
        self.assertEqual(body, 'aaaaabbbbbccccccccccccccc')
        self.assertTrue(isinstance(exc, exceptions.SegmentError))
        self.assertEqual(
            self.app.calls,
            [('GET', '/v1/AUTH_test/mancon/manifest'),
             ('GET', '/v1/AUTH_test/c?format=json&prefix=seg'),
             ('GET', '/v1/AUTH_test/c/seg_01?multipart-manifest=get'),
             ('GET', '/v1/AUTH_test/c/seg_02?multipart-manifest=get'),
             ('GET', '/v1/AUTH_test/c/seg_03?multipart-manifest=get')])
Exemple #9
0
    def __call__(self, env, start_response):
        method = env['REQUEST_METHOD']
        path = env['PATH_INFO']
        _, acc, cont, obj = split_path(env['PATH_INFO'],
                                       0,
                                       4,
                                       rest_with_last=True)

        self.calls.append((method, path))

        try:
            resp_class, raw_headers, body = self._responses[(method, path)]
            headers = swob.HeaderKeyDict(raw_headers)
        except KeyError:
            if method == 'GET' and obj and path in self.uploaded:
                resp_class = swob.HTTPOk
                headers, body = self.uploaded[path]
            else:
                raise

        # simulate object PUT
        if method == 'PUT' and obj:
            input = env['wsgi.input'].read()
            etag = md5(input).hexdigest()
            headers.setdefault('Etag', etag)
            headers.setdefault('Content-Length', len(input))

            # keep it for subsequent GET requests later
            self.uploaded[path] = (deepcopy(headers), input)
            if "CONTENT_TYPE" in env:
                self.uploaded[path][0]['Content-Type'] = env["CONTENT_TYPE"]

        return resp_class(headers=headers, body=body)(env, start_response)
Exemple #10
0
        def getheaders(self):
            etag = self.etag
            if not etag:
                if isinstance(self.body, str):
                    etag = '"' + md5(self.body).hexdigest() + '"'
                else:
                    etag = '"68b329da9893e34099c7d8ad5cb9c940"'

            headers = swob.HeaderKeyDict({
                'content-length': len(self.body),
                'content-type': 'x-application/test',
                'x-timestamp': self.timestamp,
                'x-backend-timestamp': self.timestamp,
                'last-modified': self.timestamp,
                'x-object-meta-test': 'testing',
                'x-delete-at': '9876543210',
                'etag': etag,
                'x-works': 'yes',
            })
            if self.status // 100 == 2:
                headers['x-account-container-count'] = \
                    kwargs.get('count', 12345)
            if not self.timestamp:
                # when timestamp is None, HeaderKeyDict raises KeyError
                headers.pop('x-timestamp', None)
            try:
                if container_ts_iter.next() is False:
                    headers['x-container-timestamp'] = '1'
            except StopIteration:
                pass
            am_slow, value = self.get_slow()
            if am_slow:
                headers['content-length'] = '4'
            headers.update(self.headers)
            return headers.items()
    def call_mware(self, req, expect_exception=False):
        status = [None]
        headers = [None]

        def start_response(s, h, ei=None):
            status[0] = s
            headers[0] = h

        body_iter = self.undelete(req.environ, start_response)
        body = ''
        caught_exc = None
        try:
            for chunk in body_iter:
                body += chunk
        except Exception as exc:
            if expect_exception:
                caught_exc = exc
            else:
                raise

        headerdict = swob.HeaderKeyDict(headers[0])
        if expect_exception:
            return status[0], headerdict, body, caught_exc
        else:
            return status[0], headerdict, body
Exemple #12
0
    def test_get_range_many_segments_satisfiable(self):
        req = swob.Request.blank('/v1/AUTH_test/mancon/manifest-many-segments',
                                 environ={'REQUEST_METHOD': 'GET'},
                                 headers={'Range': 'bytes=3-12'})
        with mock.patch(LIMIT, 3):
            status, headers, body = self.call_dlo(req)
        headers = swob.HeaderKeyDict(headers)
        self.assertEqual(status, "206 Partial Content")
        self.assertEqual(headers["Content-Length"], "10")
        # The /15 here indicates that this is a 15-byte object. DLO can't tell
        # if there are more segments or not without fetching more container
        # listings, though, so we just go with the sum of the lengths of the
        # segments we can see. In an ideal world, this would be "bytes 3-12/*"
        # to indicate that we don't know the full object length. However, RFC
        # 2616 section 14.16 explicitly forbids us from doing that:
        #
        #   A response with status code 206 (Partial Content) MUST NOT include
        #   a Content-Range field with a byte-range-resp-spec of "*".
        #
        # Since the truth is forbidden, we lie.
        self.assertEqual(headers["Content-Range"], "bytes 3-12/15")
        self.assertEqual(body, "aabbbbbccc")

        self.assertEqual(
            self.app.calls,
            [('GET', '/v1/AUTH_test/mancon/manifest-many-segments'),
             ('GET', '/v1/AUTH_test/c?format=json&prefix=seg_'),
             ('GET', '/v1/AUTH_test/c/seg_01?multipart-manifest=get'),
             ('GET', '/v1/AUTH_test/c/seg_02?multipart-manifest=get'),
             ('GET', '/v1/AUTH_test/c/seg_03?multipart-manifest=get')])
Exemple #13
0
    def __init__(self, *args, **kwargs):
        swob.Response.__init__(self, *args, **kwargs)

        if self.etag:
            # add double quotes to the etag header
            self.headers['etag'] = self.etag

        sw_sysmeta_headers = swob.HeaderKeyDict()
        sw_headers = swob.HeaderKeyDict()
        headers = HeaderKeyDict()
        self.is_slo = False

        for key, val in self.headers.iteritems():
            _key = key.lower()
            if _key.startswith(sysmeta_prefix('object')) or \
                    _key.startswith(sysmeta_prefix('container')):
                sw_sysmeta_headers[key] = val
            else:
                sw_headers[key] = val

        # Handle swift headers
        for key, val in sw_headers.iteritems():
            _key = key.lower()

            if _key.startswith('x-object-meta-'):
                if any(_str in _key
                       for _str in ('object-type', 'hash-crc64ecma')):
                    headers['x-oss-' + _key[14:]] = val
                else:
                    headers['x-oss-meta-' + _key[14:]] = val
            elif _key.startswith('x-container-meta-'):
                headers['x-oss-meta-' + _key[17:]] = val
            elif _key in ('content-length', 'content-type', 'content-range',
                          'content-encoding', 'content-disposition',
                          'content-language', 'etag', 'last-modified',
                          'x-robots-tag', 'cache-control', 'expires'):
                headers[key] = val
            elif _key == 'x-static-large-object':
                # for delete slo
                self.is_slo = config_true_value(val)

        if headers['x-oss-meta-location'] is None:
            headers['x-oss-meta-location'] = ''
        self.headers = headers
        # Used for pure swift header handling at the request layer
        self.sw_headers = sw_headers
        self.sysmeta_headers = sw_sysmeta_headers
Exemple #14
0
 def test_get_range_on_segment_boundaries(self):
     req = swob.Request.blank('/v1/AUTH_test/mancon/manifest',
                              environ={'REQUEST_METHOD': 'GET'},
                              headers={'Range': 'bytes=10-19'})
     status, headers, body = self.call_dlo(req)
     headers = swob.HeaderKeyDict(headers)
     self.assertEqual(status, "206 Partial Content")
     self.assertEqual(headers["Content-Length"], "10")
     self.assertEqual(body, "cccccddddd")
Exemple #15
0
 def test_get_suffix_range(self):
     req = swob.Request.blank('/v1/AUTH_test/mancon/manifest',
                              environ={'REQUEST_METHOD': 'GET'},
                              headers={'Range': 'bytes=-40'})
     status, headers, body = self.call_dlo(req)
     headers = swob.HeaderKeyDict(headers)
     self.assertEqual(status, "206 Partial Content")
     self.assertEqual(headers["Content-Length"], "25")
     self.assertEqual(body, "aaaaabbbbbcccccdddddeeeee")
Exemple #16
0
    def check_copy_source(self, app):
        """
        check_copy_source checks the copy source existence and if copying an
        object to itself, for illegal request parameters

        :returns: the source HEAD response
        """
        try:
            src_path = self.headers['X-Amz-Copy-Source']
        except KeyError:
            return None

        if '?' in src_path:
            src_path, qs = src_path.split('?', 1)
            query = parse_qsl(qs, True)
            if not query:
                pass  # ignore it
            elif len(query) > 1 or query[0][0] != 'versionId':
                raise InvalidArgument('X-Amz-Copy-Source',
                                      self.headers['X-Amz-Copy-Source'],
                                      'Unsupported copy source parameter.')
            elif query[0][1] != 'null':
                # TODO: once we support versioning, we'll need to translate
                # src_path to the proper location in the versions container
                raise S3NotImplemented('Versioning is not yet supported')
            self.headers['X-Amz-Copy-Source'] = src_path

        src_path = unquote(src_path)
        src_path = src_path if src_path.startswith('/') else ('/' + src_path)
        src_bucket, src_obj = split_path(src_path, 0, 2, True)

        headers = swob.HeaderKeyDict()
        headers.update(self._copy_source_headers())

        src_resp = self.get_response(app, 'HEAD', src_bucket, src_obj,
                                     headers=headers)
        if src_resp.status_int == 304:  # pylint: disable-msg=E1101
            raise PreconditionFailed()

        self.headers['X-Amz-Copy-Source'] = \
            '/' + self.headers['X-Amz-Copy-Source'].lstrip('/')
        source_container, source_obj = \
            split_path(self.headers['X-Amz-Copy-Source'], 1, 2, True)

        if (self.container_name == source_container and
                self.object_name == source_obj and
                self.headers.get('x-amz-metadata-directive',
                                 'COPY') == 'COPY'):
            raise InvalidRequest("This copy request is illegal "
                                 "because it is trying to copy an "
                                 "object to itself without "
                                 "changing the object's metadata, "
                                 "storage class, website redirect "
                                 "location or encryption "
                                 "attributes.")
        return src_resp
Exemple #17
0
 def test_get_range_overlapping_end(self):
     req = swob.Request.blank('/v1/AUTH_test/mancon/manifest',
                              environ={'REQUEST_METHOD': 'GET'},
                              headers={'Range': 'bytes=18-30'})
     status, headers, body = self.call_dlo(req)
     headers = swob.HeaderKeyDict(headers)
     self.assertEqual(status, "206 Partial Content")
     self.assertEqual(headers["Content-Length"], "7")
     self.assertEqual(headers["Content-Range"], "bytes 18-24/25")
     self.assertEqual(body, "ddeeeee")
Exemple #18
0
    def test_head_large_object_too_many_segments(self):
        req = swob.Request.blank('/v1/AUTH_test/mancon/manifest-many-segments',
                                 environ={'REQUEST_METHOD': 'HEAD'})
        with mock.patch(LIMIT, 3):
            status, headers, body = self.call_dlo(req)
        headers = swob.HeaderKeyDict(headers)

        # etag is manifest's etag
        self.assertEqual(headers["Etag"], "etag-manyseg")
        self.assertEqual(headers.get("Content-Length"), None)
Exemple #19
0
 def test_head_large_object(self):
     expected_etag = '"%s"' % md5hex(
         md5hex("aaaaa") + md5hex("bbbbb") + md5hex("ccccc") +
         md5hex("ddddd") + md5hex("eeeee"))
     req = swob.Request.blank('/v1/AUTH_test/mancon/manifest',
                              environ={'REQUEST_METHOD': 'HEAD'})
     status, headers, body = self.call_dlo(req)
     headers = swob.HeaderKeyDict(headers)
     self.assertEqual(headers["Etag"], expected_etag)
     self.assertEqual(headers["Content-Length"], "25")
Exemple #20
0
 def test_head_large_object(self):
     expected_etag = '"%s"' % hashlib.md5("seg01-etag" + "seg02-etag" +
                                          "seg03-etag" + "seg04-etag" +
                                          "seg05-etag").hexdigest()
     req = swob.Request.blank('/v1/AUTH_test/mancon/manifest',
                              environ={'REQUEST_METHOD': 'HEAD'})
     status, headers, body = self.call_dlo(req)
     headers = swob.HeaderKeyDict(headers)
     self.assertEqual(headers["Etag"], expected_etag)
     self.assertEqual(headers["Content-Length"], "25")
Exemple #21
0
    def test_obj_put_legacy_updates(self):
        ts = (normalize_timestamp(t) for t in itertools.count(int(time())))
        policy = POLICIES.get_by_index(0)
        # setup updater
        conf = {
            'devices': self.devices_dir,
            'mount_check': 'false',
            'swift_dir': self.testdir,
        }
        async_dir = os.path.join(self.sda1, get_async_dir(policy))
        os.mkdir(async_dir)

        account, container, obj = 'a', 'c', 'o'
        # write an async
        for op in ('PUT', 'DELETE'):
            self.logger._clear()
            daemon = object_updater.ObjectUpdater(conf, logger=self.logger)
            dfmanager = DiskFileManager(conf, daemon.logger)
            # don't include storage-policy-index in headers_out pickle
            headers_out = swob.HeaderKeyDict({
                'x-size': 0,
                'x-content-type': 'text/plain',
                'x-etag': 'd41d8cd98f00b204e9800998ecf8427e',
                'x-timestamp': next(ts),
            })
            data = {
                'op': op,
                'account': account,
                'container': container,
                'obj': obj,
                'headers': headers_out
            }
            dfmanager.pickle_async_update(self.sda1, account, container, obj,
                                          data, next(ts), policy)

            request_log = []

            def capture(*args, **kwargs):
                request_log.append((args, kwargs))

            # run once
            fake_status_codes = [200, 200, 200]
            with mocked_http_conn(*fake_status_codes, give_connect=capture):
                daemon.run_once()
            self.assertEqual(len(fake_status_codes), len(request_log))
            for request_args, request_kwargs in request_log:
                ip, part, method, path, headers, qs, ssl = request_args
                self.assertEqual(method, op)
                self.assertEqual(headers['X-Backend-Storage-Policy-Index'],
                                 str(int(policy)))
            self.assertEqual(daemon.logger.get_increment_counts(), {
                'successes': 1,
                'unlinks': 1,
                'async_pendings': 1
            })
Exemple #22
0
    def __init__(self, *args, **kwargs):
        swob.Response.__init__(self, *args, **kwargs)

        if self.etag:
            # add double quotes to the etag header
            self.etag = self.etag

        sw_sysmeta_headers = swob.HeaderKeyDict()
        sw_headers = swob.HeaderKeyDict()
        headers = HeaderKeyDict()
        self.is_slo = False

        for key, val in self.headers.iteritems():
            _key = key.lower()
            if _key.startswith(sysmeta_prefix('object')) or \
                    _key.startswith(sysmeta_prefix('container')):
                sw_sysmeta_headers[key] = val
            else:
                sw_headers[key] = val

        # Handle swift headers
        for key, val in sw_headers.iteritems():
            _key = key.lower()

            if _key.startswith('x-object-meta-'):
                # Note that AWS ignores user-defined headers with '=' in the
                # header name. We translated underscores to '=5F' on the way
                # in, though.
                headers['x-amz-meta-' + _key[14:].replace('=5f', '_')] = val
            elif _key in ('content-length', 'content-type', 'content-range',
                          'content-encoding', 'content-disposition',
                          'content-language', 'etag', 'last-modified',
                          'x-robots-tag', 'cache-control', 'expires'):
                headers[key] = val
            elif _key == 'x-static-large-object':
                # for delete slo
                self.is_slo = config_true_value(val)

        self.headers = headers
        # Used for pure swift header handling at the request layer
        self.sw_headers = sw_headers
        self.sysmeta_headers = sw_sysmeta_headers
Exemple #23
0
    def test_if_none_match_does_not_match(self):
        req = swob.Request.blank('/v1/AUTH_test/mancon/manifest',
                                 environ={'REQUEST_METHOD': 'GET'},
                                 headers={'If-None-Match': 'not it'})

        status, headers, body = self.call_dlo(req)
        headers = swob.HeaderKeyDict(headers)

        self.assertEqual(status, '200 OK')
        self.assertEqual(headers['Content-Length'], '25')
        self.assertEqual(body, 'aaaaabbbbbcccccdddddeeeee')
Exemple #24
0
    def test_if_match_does_not_match(self):
        req = swob.Request.blank('/v1/AUTH_test/mancon/manifest',
                                 environ={'REQUEST_METHOD': 'GET'},
                                 headers={'If-Match': 'not it'})

        status, headers, body = self.call_dlo(req)
        headers = swob.HeaderKeyDict(headers)

        self.assertEqual(status, '412 Precondition Failed')
        self.assertEqual(headers['Content-Length'], '0')
        self.assertEqual(body, '')
Exemple #25
0
 def test_get_suffix_range_many_segments(self):
     req = swob.Request.blank('/v1/AUTH_test/mancon/manifest-many-segments',
                              environ={'REQUEST_METHOD': 'GET'},
                              headers={'Range': 'bytes=-5'})
     with mock.patch(LIMIT, 3):
         status, headers, body = self.call_dlo(req)
     headers = swob.HeaderKeyDict(headers)
     self.assertEqual(status, "200 OK")
     self.assertEqual(headers.get("Content-Length"), None)
     self.assertEqual(headers.get("Content-Range"), None)
     self.assertEqual(body, "aaaaabbbbbcccccdddddeeeee")
Exemple #26
0
    def test_error_fetching_second_segment(self):
        self.app.register('GET', '/v1/AUTH_test/c/seg_02', swob.HTTPForbidden,
                          {}, None)

        req = swob.Request.blank('/v1/AUTH_test/mancon/manifest',
                                 environ={'REQUEST_METHOD': 'GET'})
        status, headers, body, exc = self.call_dlo(req, expect_exception=True)
        headers = swob.HeaderKeyDict(headers)

        self.assertTrue(isinstance(exc, exceptions.SegmentError))
        self.assertEqual(status, "200 OK")
        self.assertEqual(''.join(body), "aaaaa")  # first segment made it out
Exemple #27
0
 def test_get_range_many_segments_satisfiability_unknown(self):
     req = swob.Request.blank('/v1/AUTH_test/mancon/manifest-many-segments',
                              environ={'REQUEST_METHOD': 'GET'},
                              headers={'Range': 'bytes=10-22'})
     with mock.patch(LIMIT, 3):
         status, headers, body = self.call_dlo(req)
     headers = swob.HeaderKeyDict(headers)
     self.assertEqual(status, "200 OK")
     # this requires multiple pages of container listing, so we can't send
     # a Content-Length header
     self.assertEqual(headers.get("Content-Length"), None)
     self.assertEqual(body, "aaaaabbbbbcccccdddddeeeee")
Exemple #28
0
    def __init__(self, *args, **kwargs):
        swob.Response.__init__(self, *args, **kwargs)

        if self.etag:
            # add double quotes to the etag header
            self.etag = self.etag

        sw_sysmeta_headers = swob.HeaderKeyDict()
        sw_headers = swob.HeaderKeyDict()
        headers = HeaderKeyDict()

        for key, val in self.headers.iteritems():
            _key = key.lower()
            if _key.startswith(sysmeta_prefix('object')) or \
                    _key.startswith(sysmeta_prefix('container')):
                sw_sysmeta_headers[key] = val
            else:
                sw_headers[key] = val

        # Handle swift headers
        for key, val in sw_headers.iteritems():
            _key = key.lower()

            if _key.startswith('x-object-meta-'):
                headers['x-amz-meta-' + _key[14:]] = val
            elif _key in ('content-length', 'content-type',
                          'content-range', 'content-encoding',
                          'etag', 'last-modified'):
                headers[key] = val
            elif _key == 'x-container-object-count':
                # for ceph/s3tests
                headers['x-rgw-object-count'] = val
            elif _key == 'x-container-bytes-used':
                # for ceph/s3tests
                headers['x-rgw-bytes-used'] = val

        self.headers = headers
        # Used for pure swift header handling at the request layer
        self.sw_headers = sw_headers
        self.sysmeta_headers = sw_sysmeta_headers
Exemple #29
0
 def test_get_range(self):
     req = swob.Request.blank('/v1/AUTH_test/mancon/manifest',
                              environ={'REQUEST_METHOD': 'GET'},
                              headers={'Range': 'bytes=8-17'})
     status, headers, body = self.call_dlo(req)
     headers = swob.HeaderKeyDict(headers)
     self.assertEqual(status, "206 Partial Content")
     self.assertEqual(headers["Content-Length"], "10")
     self.assertEqual(body, "bbcccccddd")
     expected_etag = '"%s"' % md5hex(
         md5hex("aaaaa") + md5hex("bbbbb") + md5hex("ccccc") +
         md5hex("ddddd") + md5hex("eeeee"))
     self.assertEqual(headers.get("Etag"), expected_etag)
Exemple #30
0
 def test_get_multi_range(self):
     # DLO doesn't support multi-range GETs. The way that you express that
     # in HTTP is to return a 200 response containing the whole entity.
     req = swob.Request.blank('/v1/AUTH_test/mancon/manifest-many-segments',
                              environ={'REQUEST_METHOD': 'GET'},
                              headers={'Range': 'bytes=5-9,15-19'})
     with mock.patch(LIMIT, 3):
         status, headers, body = self.call_dlo(req)
     headers = swob.HeaderKeyDict(headers)
     self.assertEqual(status, "200 OK")
     self.assertEqual(headers.get("Content-Length"), None)
     self.assertEqual(headers.get("Content-Range"), None)
     self.assertEqual(body, "aaaaabbbbbcccccdddddeeeee")