class ExpiringObjectTest(ObjectStorageFixture):
    @classmethod
    def setUpClass(cls):
        super(ExpiringObjectTest, cls).setUpClass()
        cls.default_obj_name = cls.behaviors.VALID_OBJECT_NAME
        cls.default_obj_data = "Test Data"

    @data_driven_test(ObjectDatasetList())
    def ddtest_object_creation_with_x_delete_at(self, object_type,
                                                generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name

        start_time = calendar.timegm(time.gmtime())
        future_time = str(int(start_time + 60))
        object_headers = {'X-Delete-At': future_time}
        generate_object(container_name, object_name, headers=object_headers)

        response = self.client.get_object(container_name, object_name)

        content_length = response.headers.get('content-length')
        self.assertNotEqual(content_length, 0)

        # wait for the object to expire - future_time + 10 seconds
        time.sleep(70)

        response = self.client.get_object(container_name, object_name)

        self.assertEqual(response.status_code, 404)

    @data_driven_test(ObjectDatasetList())
    def ddtest_object_creation_with_delete_after(self, object_type,
                                                 generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        object_headers = {'X-Delete-After': '60'}
        generate_object(container_name, object_name, headers=object_headers)

        response = self.client.get_object(container_name, object_name)

        content_length = response.headers.get('content-length')
        self.assertNotEqual(content_length, 0)

        # wait for the object to expire - delete after 60 seconds + 10 seconds
        time.sleep(70)

        response = self.client.get_object(container_name, object_name)

        self.assertEqual(response.status_code, 404)
Exemple #2
0
class QuickTest(ObjectStorageFixture):
    def test_create_container(self):
        response = self.client.create_container('quick_test_container')
        self.assertTrue(response.ok)

        response = self.client.delete_container('quick_test_container')
        self.assertTrue(response.ok)

    @data_driven_test(ObjectDatasetList())
    def ddtest_create_object(self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor='quick_test_container')
        object_name = 'quick_object'
        generate_object(container_name, object_name)

        response = self.client.get_object(container_name, object_name)
        self.assertEqual(200, response.status_code, 'should return object')
                      " error: {0}".format(error))

        i = 1
        end = len(split_body) - 1

        try:
            while (i < end):
                multipart_content['value{0}'.format(i)] = \
                    split_body[i].split('\r\n\r\n')[1].strip('\r\n')
                i += 1
        except AttributeError, error:
            self.error("error parsing content. error: {0}".format(error))

        return multipart_content

    @data_driven_test(ObjectDatasetList())
    def ddtest_basic_object_range_request(self, **kwargs):
        """
        Scenario:
            Perform a get with various range request headers.

        Expected Results:
            The data returned should be within the range specified.
        """
        obj_data = "grok_one drok_two"

        headers = {'Content-Length': str(len(obj_data))}
        self.behaviors.create_object(self.container_name,
                                     self.object_name,
                                     headers=headers,
                                     data=obj_data)
Exemple #4
0
class ExpiringObjectTest(ObjectStorageFixture):
    @classmethod
    def setUpClass(cls):
        super(ExpiringObjectTest, cls).setUpClass()
        cls.default_obj_name = Constants.VALID_OBJECT_NAME
        cls.default_obj_data = Constants.VALID_OBJECT_DATA

    @data_driven_test(ObjectDatasetList())
    def ddtest_object_creation_with_x_delete_at(self, object_type,
                                                generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name

        start_time = timegm(gmtime())
        future_time = str(int(start_time + 60))
        object_headers = {'X-Delete-At': future_time}
        generate_object(container_name, object_name, headers=object_headers)

        response = self.client.get_object(container_name, object_name)

        content_length = response.headers.get('content-length')
        self.assertNotEqual(content_length, 0)

        # Wait for object to expire using interval from config
        sleep(self.objectstorage_api_config.object_deletion_wait_interval)

        response = self.client.get_object(container_name, object_name)

        self.assertEqual(response.status_code, 404)

    @data_driven_test(ObjectDatasetList())
    def ddtest_object_creation_with_x_delete_after(self, object_type,
                                                   generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        object_headers = {'X-Delete-After': '60'}
        generate_object(container_name, object_name, headers=object_headers)

        response = self.client.get_object(container_name, object_name)

        content_length = response.headers.get('content-length')
        self.assertNotEqual(content_length, 0)

        # wait for the object to expire - delete after 60 seconds + 10 seconds
        sleep(70)

        response = self.client.get_object(container_name, object_name)

        self.assertEqual(response.status_code, 404)

    @data_driven_test(ObjectDatasetList())
    def ddtest_object_creation_with_x_delete_after_with_unicode_container_name(
            self, object_type, generate_object):
        """
        Scenario:
            Create a container with a unicode name and then add
            an expiring object to it using x_delete_after

        Expected Results:
            The object should be available until the expiration time,
            then it should be deleted
        """
        delete_after = 60

        container_description = unicode(u'\u262D\u2622').encode('utf-8')
        container_name = self.create_temp_container(
            descriptor=container_description)

        object_name = self.default_obj_name
        object_headers = {'X-Delete-After': delete_after}
        generate_object(container_name, object_name, headers=object_headers)

        object_response = self.client.get_object(container_name, object_name)

        method = 'Creating Expiring Object in Unicode Container'
        expected = 200
        received = object_response.status_code

        self.assertEqual(expected,
                         received,
                         msg=STATUS_CODE_MSG.format(method=method,
                                                    expected=expected,
                                                    received=str(received)))

        # Sleep for period set as X-Delete-After(object expiration)
        sleep(delete_after)

        object_response = self.client.get_object(container_name, object_name)

        method = 'GET on expired object in Unicode Container'
        expected = 404
        received = object_response.status_code

        self.assertEqual(expected,
                         received,
                         msg=STATUS_CODE_MSG.format(method=method,
                                                    expected=expected,
                                                    received=str(received)))

    @data_driven_test(ObjectDatasetList())
    def ddtest_object_creation_with_x_delete_at_with_unicode_container_name(
            self, object_type, generate_object):
        """
        Scenario:
            Create a container with a unicode name and then add
            an expiring object to it using x_delete_at.

        Expected Results:
            The object should be available until the expiration time,
            then it should be deleted
        """
        start_time = timegm(gmtime())
        future_time = str(int(start_time + 60))

        container_description = unicode(u'\u262D\u2622').encode('utf-8')
        container_name = self.create_temp_container(
            descriptor=container_description)

        object_name = self.default_obj_name
        object_headers = {'X-Delete-At': future_time}
        generate_object(container_name, object_name, headers=object_headers)

        object_response = self.client.get_object(container_name, object_name)

        method = 'Creating Expiring Object in Unicode Container'
        expected = 200
        received = object_response.status_code

        self.assertEqual(expected,
                         received,
                         msg=STATUS_CODE_MSG.format(method=method,
                                                    expected=expected,
                                                    received=str(received)))

        # Wait for object to expire using interval from config
        sleep(self.objectstorage_api_config.object_deletion_wait_interval)

        object_response = self.client.get_object(container_name, object_name)

        method = 'GET on expired object in Unicode Container'
        expected = 404
        received = object_response.status_code

        self.assertEqual(expected,
                         received,
                         msg=STATUS_CODE_MSG.format(method=method,
                                                    expected=expected,
                                                    received=str(received)))

    @data_driven_test(ObjectDatasetList())
    def ddtest_object_deletion_with_x_delete_at(self, **kwargs):
        """
        Scenario:
            Create an object which has the X-Delete-At metadata.

        Expected Results:
            The object should be accessible before the 'delete at' time.
            The object should not be accessible after the 'delete at' time.
            The object should not be listed after the object expirer has had
                time to run.
        """
        container_name = self.behaviors.generate_unique_container_name(
            self.base_container_name)

        self.behaviors.create_container(container_name)

        self.addCleanup(self.behaviors.force_delete_containers,
                        [container_name])

        delete_after = 60
        delete_at = str(int(timegm(gmtime()) + delete_after))
        headers = {
            'Content-Length': str(len(self.default_obj_data)),
            'X-Delete-At': delete_at
        }

        resp = self.client.create_object(container_name,
                                         self.default_obj_name,
                                         headers=headers,
                                         data=self.default_obj_data)

        self.assertEqual(201, resp.status_code,
                         'Object should be created with X-Delete-At header.')

        resp = self.client.get_object(container_name, self.default_obj_name)

        self.assertEqual(200, resp.status_code,
                         'Object should exist before X-Delete-At.')

        # wait for the object to be deleted.
        sleep(self.objectstorage_api_config.object_deletion_wait_interval)

        resp = self.client.get_object(container_name, self.default_obj_name)

        self.assertEqual(404, resp.status_code,
                         'Object should be deleted after X-Delete-At.')
Exemple #5
0
class CORSTest(ObjectStorageFixture):
    @classmethod
    def setUpClass(cls):
        super(CORSTest, cls).setUpClass()

        cls.dumb_client = HTTPClient()
        cls.object_name = Constants.VALID_OBJECT_NAME

    @data_driven_test(ObjectDatasetList())
    @ObjectStorageFixture.required_features('tempurl')
    def ddtest_container_cors_with_tempurl(self, generate_object, **kwargs):
        """
        Scenario:
            Create a container with CORS headers.
            Create a object.
            Retrieve the object via TempURL.

        Expected Results:
            If no Origin is set:
                The object should be returned with no CORS headers.
            If the Origin matches the Allow-Origin set:
                The object should be returned with the CORS headers.
            If strict_cors_mode == True and the Origin does not match:
                The object should be returned with no CORS headers.
            If strict_cors_mode == False and the Origin does not match:
                The object should be returned with the CORS headers.
        """
        expose_headers = [
            'Content-Length', 'Etag', 'X-Timestamp', 'X-Trans-Id'
        ]
        container_headers = {
            'X-Container-Meta-Access-Control-Allow-Origin':
            'http://example.com',
            'X-Container-Meta-Access-Control-Max-Age':
            '5',
            'X-Container-Meta-Access-Control-Expose-Headers':
            ','.join(expose_headers)
        }

        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR, headers=container_headers)

        object_headers = {'Content-Type': 'text/plain'}
        generate_object(container_name,
                        self.object_name,
                        headers=object_headers)

        tempurl_key = self.behaviors.get_tempurl_key()
        tempurl_info = self.client.create_temp_url('GET', container_name,
                                                   self.object_name, 900,
                                                   tempurl_key)

        # Requests with no Origin should not return CORS headers.
        response = self.dumb_client.request('GET',
                                            tempurl_info.get('target_url'),
                                            params={
                                                'temp_url_sig':
                                                tempurl_info.get('signature'),
                                                'temp_url_expires':
                                                tempurl_info.get('expires')
                                            })
        self.assertTrue('Access-Control-Allow-Origin' not in response.headers,
                        'Allow-Origin header should not be returned.')
        self.assertTrue('Access-Control-Max-Age' not in response.headers,
                        'Max-Age should not be returned.')
        self.assertTrue(
            'Access-Control-Expose-Headers' not in response.headers,
            'Expose-Headers should not be returned.')

        # Requests with Origin which matches, should return CORS headers.
        response = self.dumb_client.request(
            'GET',
            tempurl_info.get('target_url'),
            params={
                'temp_url_sig': tempurl_info.get('signature'),
                'temp_url_expires': tempurl_info.get('expires')
            },
            headers={'Origin': 'http://example.com'})
        self.assertTrue('Access-Control-Allow-Origin' in response.headers,
                        'Allow-Origin header should be returned.')
        self.assertTrue('Access-Control-Expose-Headers' in response.headers,
                        'Expose-Headers should be returned.')
        self.assertTrue('Access-Control-Max-Age' not in response.headers,
                        'Max-Age should not be returned.')

        if self.objectstorage_api_config.strict_cors_mode:
            # CORS should work according to the spec.
            # Requests with Origin which does not match, should not return
            # CORS headers.
            response = self.dumb_client.request(
                'GET',
                tempurl_info.get('target_url'),
                params={
                    'temp_url_sig': tempurl_info.get('signature'),
                    'temp_url_expires': tempurl_info.get('expires')
                },
                headers={'Origin': 'http://foo.com'})
            self.assertTrue(
                'Access-Control-Allow-Origin' not in response.headers,
                'Allow-Origin header should not be returned.')
            self.assertTrue(
                'Access-Control-Expose-Headers' not in response.headers,
                'Expose-Headers should not be returned.')
            self.assertTrue('Access-Control-Max-Age' not in response.headers,
                            'Max-Age should not be returned.')
        else:
            # Early implementation of CORS.
            # Requests with Origin which does not match, should not return
            # CORS headers.
            response = self.dumb_client.request(
                'GET',
                tempurl_info.get('target_url'),
                params={
                    'temp_url_sig': tempurl_info.get('signature'),
                    'temp_url_expires': tempurl_info.get('expires')
                },
                headers={'Origin': 'http://foo.com'})
            self.assertTrue(
                'Access-Control-Allow-Origin' in response.headers,
                'Allow-Origin header should be returned with '
                'differing origin.')
            self.assertTrue(
                'Access-Control-Expose-Headers' in response.headers,
                'Expose-Headers should be returned with '
                'differing origin.')
            self.assertTrue(
                'Access-Control-Max-Age' not in response.headers,
                'Max-Age should not be returned with '
                'differing origin.')

    @ObjectStorageFixture.required_features('formpost')
    def test_container_cors_with_formpost(self):
        """
        Scenario:
            Create a container with CORS headers.
            POST an object to the container via FormPOST.

        Expected Results:
            If no Origin is set:
                The response should be returned with no CORS headers.
            If the Origin matches the Allow-Origin set:
                The response should be returned with the CORS headers.
            If strict_cors_mode == True and the Origin does not match:
                The response should be returned with no CORS headers.
            If strict_cors_mode == False and the Origin does not match:
                The response should be returned with the CORS headers.
        """
        expose_headers = [
            'Content-Length', 'Etag', 'X-Timestamp', 'X-Trans-Id'
        ]
        container_headers = {
            'X-Container-Meta-Access-Control-Allow-Origin':
            'http://example.com',
            'X-Container-Meta-Access-Control-Max-Age':
            '5',
            'X-Container-Meta-Access-Control-Expose-Headers':
            ','.join(expose_headers)
        }
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR, headers=container_headers)

        tempurl_key = self.behaviors.get_tempurl_key()
        files = [{'name': 'foo1'}]

        # Requests with no Origin should not return CORS headers.
        formpost_info = self.behaviors.create_formpost(container_name,
                                                       files,
                                                       key=tempurl_key)

        headers = formpost_info.get('headers')
        response = self.dumb_client.post(
            formpost_info.get('target_url'),
            headers=headers,
            data=formpost_info.get('body'),
            requestslib_kwargs={'allow_redirects': False})
        self.assertTrue(303, response.status_code)
        self.assertTrue('location' in response.headers)
        self.assertTrue(
            'access-control-expose-headers' not in response.headers)
        self.assertTrue('access-control-allow-origin' not in response.headers)

        # Requests with Origin which does match, should return CORS headers.
        formpost_info = self.behaviors.create_formpost(container_name,
                                                       files,
                                                       key=tempurl_key)

        headers = formpost_info.get('headers')
        headers['Origin'] = 'http://example.com'
        response = self.dumb_client.post(
            formpost_info.get('target_url'),
            headers=headers,
            data=formpost_info.get('body'),
            requestslib_kwargs={'allow_redirects': False})
        self.assertTrue(303, response.status_code)
        self.assertTrue('access-control-expose-headers' in response.headers)
        self.assertTrue('location' in response.headers)
        self.assertTrue('access-control-allow-origin' in response.headers)

        if self.objectstorage_api_config.strict_cors_mode:
            # CORS should work according to the spec.
            # Requests with Origin which does not match, should not return
            # CORS headers.
            formpost_info = self.behaviors.create_formpost(container_name,
                                                           files,
                                                           key=tempurl_key)

            headers = formpost_info.get('headers')
            headers['Origin'] = 'http://foo.com'
            response = self.dumb_client.post(
                formpost_info.get('target_url'),
                headers=headers,
                data=formpost_info.get('body'),
                requestslib_kwargs={'allow_redirects': False})
            self.assertTrue(303, response.status_code)
            self.assertTrue(
                'access-control-expose-headers' not in response.headers)
            self.assertTrue('location' not in response.headers)
            self.assertTrue(
                'access-control-allow-origin' not in response.headers)
        else:
            # Early implementation of CORS.
            # Requests with Origin which does not match, should not return
            # CORS headers.
            formpost_info = self.behaviors.create_formpost(container_name,
                                                           files,
                                                           key=tempurl_key)

            headers = formpost_info.get('headers')
            headers['Origin'] = 'http://foo.com'
            response = self.dumb_client.post(
                formpost_info.get('target_url'),
                headers=headers,
                data=formpost_info.get('body'),
                requestslib_kwargs={'allow_redirects': False})
            self.assertTrue(303, response.status_code)
            self.assertTrue(
                'access-control-expose-headers' in response.headers)
            self.assertTrue('location' in response.headers)
            self.assertTrue('access-control-allow-origin' in response.headers)

    def test_container_cors_preflight_request(self):
        """
        Scenario:
            Create a container with CORS headers:
               X-Container-Meta-Access-Control-Allow-Origin
               X-Container-Meta-Access-Control-Max-Age
               X-Container-Meta-Access-Control-Expose-Headers
            Make a preflight request using the OPTIONS call with an Origin
            that matches the container header.
            Make a preflight request using the OPTIONS call with an Origin
            that does not match the container header.

        Expected Results:
            If the Origin matches the Allow-Origin set:
                CF should return a 200.
            If the Origin does not match the Allow-Origin set:
                CF should return a 401.
        """
        expose_headers = [
            'Content-Length', 'Etag', 'X-Timestamp', 'X-Trans-Id'
        ]
        container_headers = {
            'X-Container-Meta-Access-Control-Allow-Origin':
            'http://example.com',
            'X-Container-Meta-Access-Control-Max-Age':
            '5',
            'X-Container-Meta-Access-Control-Expose-Headers':
            ','.join(expose_headers)
        }

        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR, headers=container_headers)

        container_url = '{0}/{1}'.format(self.client.storage_url,
                                         container_name)

        # OPTIONS Preflight request with matching Origin should return 200
        headers = {
            'Origin': 'http://example.com',
            'Access-Control-Request-Method': 'POST'
        }
        preflight_response = self.dumb_client.request('OPTIONS',
                                                      container_url,
                                                      headers=headers)

        self.assertEqual(preflight_response.status_code,
                         200,
                         msg="Preflight request with matching Origin should "
                         "return {0} status code, received a {1}".format(
                             "200", preflight_response.status_code))

        # OPTIONS Preflight request with non-matching Origin should return 401
        headers = {
            'Origin': 'http://test.com',
            'Access-Control-Request-Method': 'POST'
        }
        preflight_response = self.dumb_client.request('OPTIONS',
                                                      container_url,
                                                      headers=headers)

        self.assertEqual(preflight_response.status_code,
                         401,
                         msg="Preflight request with non-matching Origin "
                         "should return {0} status code, received a "
                         "{1}".format("401", preflight_response.status_code))

    @data_driven_test(ObjectDatasetList())
    @ObjectStorageFixture.required_features('tempurl')
    def ddtest_container_cors_with_wildcard_origin(self, generate_object,
                                                   **kwargs):
        """
        Scenario:
            Create a container with CORS headers:
               X-Container-Meta-Access-Control-Allow-Origin
               X-Container-Meta-Access-Control-Max-Age
               X-Container-Meta-Access-Control-Expose-Headers
            The X-Container-Meta-Access-Control-Allow-Origin header will be
            set to '*'.
            Retrieve an object with no Origin.
            Retrieve an object from a 'test' Origin.

        Expected Results:
            Retrieving the object with no Origin should not return a CORS
            header of Access-Control-Allow-Origin.
            Retrieving the object from any Origin should return a CORS
            header of Access-Control-Allow-Origin and it should be set to '*'.
        """

        expose_headers = [
            'Content-Length', 'Etag', 'X-Timestamp', 'X-Trans-Id'
        ]
        container_headers = {
            'X-Container-Meta-Access-Control-Allow-Origin':
            '*',
            'X-Container-Meta-Access-Control-Max-Age':
            '5',
            'X-Container-Meta-Access-Control-Expose-Headers':
            ','.join(expose_headers)
        }

        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR, headers=container_headers)

        object_headers = {'Content-Type': 'text/plain'}
        generate_object(container_name,
                        self.object_name,
                        headers=object_headers)

        tempurl_key = self.behaviors.get_tempurl_key()
        tempurl_info = self.client.create_temp_url('GET', container_name,
                                                   self.object_name, 900,
                                                   tempurl_key)

        # tempURL parameters
        parameters = {
            'temp_url_sig': tempurl_info.get('signature'),
            'temp_url_expires': tempurl_info.get('expires')
        }

        # Requests with no Origin should not return CORS headers.
        cors_response = self.dumb_client.request(
            'GET', tempurl_info.get('target_url'), params=parameters)
        self.assertNotIn('Access-Control-Allow-Origin',
                         cors_response.headers,
                         msg="Allow-Origin header should not be returned "
                         "when a request is made with no Origin")
        self.assertNotIn('Access-Control-Max-Age',
                         cors_response.headers,
                         msg="Max-Age header should not be returned when a "
                         "request is made with no Origin")
        self.assertNotIn('Access-Control-Expose-Headers',
                         cors_response.headers,
                         msg="Expose-Headers header should not be returned "
                         "when a request is made with no Origin")

        headers = {'Origin': 'http://example.com'}
        parameters = {
            'temp_url_sig': tempurl_info.get('signature'),
            'temp_url_expires': tempurl_info.get('expires')
        }

        # Requests with any Origin will return * as the allowed origin
        cors_response = self.dumb_client.request(
            'GET',
            tempurl_info.get('target_url'),
            params=parameters,
            headers=headers)
        self.assertIn('Access-Control-Allow-Origin',
                      cors_response.headers,
                      msg="The header Access-Control-Allow-Origin should be "
                      "returned in the list of headers: {0}".format(
                          cors_response.headers))
        self.assertEqual(
            cors_response.headers.get('Access-Control-Allow-Origin'),
            '*',
            msg="Allow-Origin header set to {0}, should be set to '*'".format(
                cors_response.headers.get('Access-Control-Allow-Origin')))

    @data_driven_test(ObjectDatasetList())
    @ObjectStorageFixture.required_features('tempurl', 'object-cors')
    def ddtest_object_cors_with_tempurl(self, generate_object, **kwargs):
        """
        Scenario:
            Create a container.
            Create a object with CORS headers.
            Retrieve the object via TempURL.

        Expected Results:
            If no Origin is set:
                The object should be returned with no CORS headers.
            If the Origin matches the Allow-Origin set:
                The object should be returned with the CORS headers.
            If strict_cors_mode == True and the Origin does not match:
                The object should be returned with no CORS headers.
            If strict_cors_mode == False and the Origin does not match:
                The object should be returned with the CORS headers.
        """
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)

        expose_headers = [
            'Content-Length', 'Etag', 'X-Timestamp', 'X-Trans-Id'
        ]
        object_headers = {
            'Content-Type': 'text/plain',
            'X-Object-Meta-Access-Control-Allow-Origin': 'http://example.com',
            'X-Object-Meta-Access-Control-Max-Age': '5',
            'X-Object-Meta-Access-Control-Expose-Headers':
            ','.join(expose_headers)
        }
        generate_object(container_name,
                        self.object_name,
                        headers=object_headers)

        tempurl_key = self.behaviors.get_tempurl_key()
        tempurl_info = self.client.create_temp_url('GET', container_name,
                                                   self.object_name, 900,
                                                   tempurl_key)

        # Requests with no Origin should not return CORS headers.
        response = self.dumb_client.request('GET',
                                            tempurl_info.get('target_url'),
                                            params={
                                                'temp_url_sig':
                                                tempurl_info.get('signature'),
                                                'temp_url_expires':
                                                tempurl_info.get('expires')
                                            })
        self.assertTrue('Access-Control-Allow-Origin' not in response.headers,
                        'Allow-Origin header should not be returned.')
        self.assertTrue('Access-Control-Max-Age' not in response.headers,
                        'Max-Age should not be returned.')
        self.assertTrue(
            'Access-Control-Expose-Headers' not in response.headers,
            'Expose-Headers should not be returned.')

        # Requests with Origin which does match, should return CORS headers.
        response = self.dumb_client.request(
            'GET',
            tempurl_info.get('target_url'),
            params={
                'temp_url_sig': tempurl_info.get('signature'),
                'temp_url_expires': tempurl_info.get('expires')
            },
            headers={'Origin': 'http://example.com'})
        self.assertTrue('Access-Control-Allow-Origin' in response.headers,
                        'Allow-Origin header should be returned.')
        self.assertTrue('Access-Control-Expose-Headers' in response.headers,
                        'Expose-Headers should be returned.')
        self.assertTrue('Access-Control-Max-Age' not in response.headers,
                        'Max-Age should not be returned.')

        if self.objectstorage_api_config.strict_cors_mode:
            # CORS should work according to the spec.
            # Requests with Origin which does not match, should not return
            # CORS headers.
            response = self.dumb_client.request(
                'GET',
                tempurl_info.get('target_url'),
                params={
                    'temp_url_sig': tempurl_info.get('signature'),
                    'temp_url_expires': tempurl_info.get('expires')
                },
                headers={'Origin': 'http://foo.com'})
            self.assertTrue(
                'Access-Control-Allow-Origin' not in response.headers,
                'Allow-Origin header should not be returned.')
            self.assertTrue('Access-Control-Max-Age' not in response.headers,
                            'Max-Age should not be returned.')
            self.assertTrue(
                'Access-Control-Expose-Headers' not in response.headers,
                'Expose-Headers should not be returned.')
        else:
            # Early implementation of CORS.
            # Requests with Origin which does not match, should not return
            # CORS headers.
            response = self.dumb_client.request(
                'GET',
                tempurl_info.get('target_url'),
                params={
                    'temp_url_sig': tempurl_info.get('signature'),
                    'temp_url_expires': tempurl_info.get('expires')
                },
                headers={'Origin': 'http://foo.com'})
            self.assertTrue(
                'Access-Control-Allow-Origin' in response.headers,
                'Allow-Origin header should be returned with '
                'differing origin.')
            self.assertTrue(
                'Access-Control-Expose-Headers' in response.headers,
                'Expose-Headers should be returned with '
                'differing origin.')
            self.assertTrue(
                'Access-Control-Max-Age' not in response.headers,
                'Max-Age should not be returned with '
                'differing origin.')

    @data_driven_test(ObjectDatasetList())
    @ObjectStorageFixture.required_features('tempurl', 'object-cors')
    def ddtest_object_override_container_cors_with_tempurl(
            self, generate_object, **kwargs):
        """
        Scenario:
            Create a container with CORS headers.
            Create a object with CORS headers.
            Retrieve the object via TempURL.

        Expected Results:
            If no Origin is set:
                The object should be returned with no CORS headers.
            If the Origin matches the object's Allow-Origin:
                The object should be returned with the CORS headers.
            If strict_cors_mode == True and the Origin does not match:
                The object should be returned with no CORS headers.
            If strict_cors_mode == False and the Origin does not match:
                The object should be returned with the CORS headers.
        """
        container_expose_headers = ['Content-Length', 'Etag']
        container_headers = {
            'X-Container-Meta-Access-Control-Allow-Origin':
            'http://foo.com',
            'X-Container-Meta-Access-Control-Expose-Headers':
            ','.join(container_expose_headers)
        }
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR, headers=container_headers)

        object_expose_headers = ['X-Timestamp', 'X-Trans-Id']
        object_headers = {
            'Content-Type':
            'text/plain',
            'X-Object-Meta-Access-Control-Allow-Origin':
            'http://bar.com',
            'X-Object-Meta-Access-Control-Expose-Headers':
            ','.join(object_expose_headers)
        }

        generate_object(container_name,
                        self.object_name,
                        headers=object_headers)

        tempurl_key = self.behaviors.get_tempurl_key()
        tempurl_info = self.client.create_temp_url('GET', container_name,
                                                   self.object_name, 900,
                                                   tempurl_key)

        # Requests with no Origin should not return CORS headers.
        response = self.dumb_client.request('GET',
                                            tempurl_info.get('target_url'),
                                            params={
                                                'temp_url_sig':
                                                tempurl_info.get('signature'),
                                                'temp_url_expires':
                                                tempurl_info.get('expires')
                                            })
        self.assertTrue('Access-Control-Allow-Origin' not in response.headers,
                        'Allow-Origin header should not be returned.')
        self.assertTrue(
            'Access-Control-Expose-Headers' not in response.headers,
            'Expose-Headers should not be returned.')

        # Requests with Origin which matches object, should return CORS
        # headers.
        response = self.dumb_client.request(
            'GET',
            tempurl_info.get('target_url'),
            params={
                'temp_url_sig': tempurl_info.get('signature'),
                'temp_url_expires': tempurl_info.get('expires')
            },
            headers={'Origin': 'http://bar.com'})
        self.assertTrue('Access-Control-Allow-Origin' in response.headers,
                        'Allow-Origin header should be returned.')
        self.assertEqual(
            'http://bar.com',
            response.headers.get('Access-Control-Allow-Origin', ''),
            'Allow-Origin header should be returned.')
        self.assertTrue('Access-Control-Expose-Headers' in response.headers,
                        'Expose-Headers should be returned.')

        if self.objectstorage_api_config.strict_cors_mode:
            # CORS should work according to the spec.

            # Requests with Origin which matches container, should not return
            # CORS headers.
            response = self.dumb_client.request(
                'GET',
                tempurl_info.get('target_url'),
                params={
                    'temp_url_sig': tempurl_info.get('signature'),
                    'temp_url_expires': tempurl_info.get('expires')
                },
                headers={'Origin': 'http://foo.com'})
            self.assertTrue(
                'Access-Control-Allow-Origin' not in response.headers,
                'Allow-Origin header should not be returned.')
            self.assertTrue(
                'Access-Control-Expose-Headers' not in response.headers,
                'Expose-Headers should not be returned.')

            # Requests with Origin which does not match, should not return
            # CORS headers.
            response = self.dumb_client.request(
                'GET',
                tempurl_info.get('target_url'),
                params={
                    'temp_url_sig': tempurl_info.get('signature'),
                    'temp_url_expires': tempurl_info.get('expires')
                },
                headers={'Origin': 'http://example.com'})
            self.assertTrue(
                'Access-Control-Allow-Origin' not in response.headers,
                'Allow-Origin header should not be returned.')
            self.assertTrue(
                'Access-Control-Expose-Headers' not in response.headers,
                'Expose-Headers should not be returned.')
        else:
            # Early implementation of CORS.

            # Requests with Origin which matches container, should not return
            # CORS headers.
            response = self.dumb_client.request(
                'GET',
                tempurl_info.get('target_url'),
                params={
                    'temp_url_sig': tempurl_info.get('signature'),
                    'temp_url_expires': tempurl_info.get('expires')
                },
                headers={'Origin': 'http://foo.com'})
            self.assertTrue('Access-Control-Allow-Origin' in response.headers,
                            'Allow-Origin header should be returned.')
            self.assertTrue(
                'Access-Control-Expose-Headers' in response.headers,
                'Expose-Headers should be returned.')

            # Requests with Origin which does not match, should not return
            # CORS headers.
            response = self.dumb_client.request(
                'GET',
                tempurl_info.get('target_url'),
                params={
                    'temp_url_sig': tempurl_info.get('signature'),
                    'temp_url_expires': tempurl_info.get('expires')
                },
                headers={'Origin': 'http://example.com'})
            self.assertTrue(
                'Access-Control-Allow-Origin' in response.headers,
                'Allow-Origin header should be returned with '
                'differing origin.')
            self.assertTrue(
                'Access-Control-Expose-Headers' in response.headers,
                'Expose-Headers should be returned with '
                'differing origin.')
Exemple #6
0
class CORSTest(ObjectStorageFixture):

    @data_driven_test(ObjectDatasetList())
    @ObjectStorageFixture.required_features('tempurl')
    def ddtest_container_cors_with_tempurl(self, object_type, generate_object):
        """
        Scenario:
            Create a container with CORS headers.
            Create a object.
            Retrieve the object via TempURL.

        Expected Results:
            If no Origin is set:
                The object should be returned with no CORS headers.
            If the Origin matches the Allow-Origin set:
                The object should be returned with the CORS headers.
            If strict_cors_mode == True and the Origin does not match:
                The object should be returned with no CORS headers.
            If strict_cors_mode == False and the Origin does not match:
                The object should be returned with the CORS headers.
        """
        expose_headers = ['Content-Length', 'Etag', 'X-Timestamp',
                          'X-Trans-Id']
        container_headers = {
            'X-Container-Meta-Access-Control-Allow-Origin':
            'http://example.com',
            'X-Container-Meta-Access-Control-Max-Age': '5',
            'X-Container-Meta-Access-Control-Expose-Headers':
            ','.join(expose_headers)}

        container_name = self.create_temp_container(
            descriptor='container-smoke', headers=container_headers)
        object_name = 'object'
        object_headers = {'Content-Type': 'text/plain'}
        generate_object(container_name, object_name, headers=object_headers)
        tempurl_key = self.behaviors.get_tempurl_key()
        tempurl_info = self.client.create_temp_url(
            'GET', container_name, object_name, 900, tempurl_key)

        dumb_client = BaseHTTPClient()

        # Requests with no Origin should not return CORS headers.
        response = dumb_client.request(
            'GET', tempurl_info.get('target_url'), params={
                'temp_url_sig': tempurl_info.get('signature'),
                'temp_url_expires': tempurl_info.get('expires')})
        self.assertTrue(
            'Access-Control-Allow-Origin' not in response.headers,
            'Allow-Origin header should not be returned.')
        self.assertTrue('Access-Control-Max-Age' not in response.headers,
                        'Max-Age should not be returned.')
        self.assertTrue(
            'Access-Control-Expose-Headers' not in response.headers,
            'Expose-Headers should not be returned.')

        # Requests with Origin which matches, should return CORS headers.
        response = dumb_client.request(
            'GET', tempurl_info.get('target_url'), params={
                'temp_url_sig': tempurl_info.get('signature'),
                'temp_url_expires': tempurl_info.get('expires')},
            headers={'Origin': 'http://example.com'})
        self.assertTrue(
            'Access-Control-Allow-Origin' in response.headers,
            'Allow-Origin header should be returned.')
        self.assertTrue(
            'Access-Control-Expose-Headers' in response.headers,
            'Expose-Headers should be returned.')
        self.assertTrue('Access-Control-Max-Age' not in response.headers,
                        'Max-Age should not be returned.')

        if self.objectstorage_api_config.strict_cors_mode:
            # CORS should work according to the spec.
            # Requests with Origin which does not match, should not return
            # CORS headers.
            response = dumb_client.request(
                'GET', tempurl_info.get('target_url'), params={
                    'temp_url_sig': tempurl_info.get('signature'),
                    'temp_url_expires': tempurl_info.get('expires')},
                headers={'Origin': 'http://foo.com'})
            self.assertTrue(
                'Access-Control-Allow-Origin' not in response.headers,
                'Allow-Origin header should not be returned.')
            self.assertTrue(
                'Access-Control-Expose-Headers' not in response.headers,
                'Expose-Headers should not be returned.')
            self.assertTrue('Access-Control-Max-Age' not in response.headers,
                            'Max-Age should not be returned.')
        else:
            # Early implementation of CORS.
            # Requests with Origin which does not match, should not return
            # CORS headers.
            response = dumb_client.request(
                'GET', tempurl_info.get('target_url'), params={
                    'temp_url_sig': tempurl_info.get('signature'),
                    'temp_url_expires': tempurl_info.get('expires')},
                headers={'Origin': 'http://foo.com'})
            self.assertTrue(
                'Access-Control-Allow-Origin' in response.headers,
                'Allow-Origin header should be returned with '
                'differing origin.')
            self.assertTrue(
                'Access-Control-Expose-Headers' in response.headers,
                'Expose-Headers should be returned with '
                'differing origin.')
            self.assertTrue('Access-Control-Max-Age' not in response.headers,
                            'Max-Age should not be returned with '
                            'differing origin.')

    @ObjectStorageFixture.required_features('formpost')
    def test_container_cors_with_formpost(self):
        """
        Scenario:
            Create a container with CORS headers.
            POST an object to the container via FormPOST.

        Expected Results:
            If no Origin is set:
                The response should be returned with no CORS headers.
            If the Origin matches the Allow-Origin set:
                The response should be returned with the CORS headers.
            If strict_cors_mode == True and the Origin does not match:
                The response should be returned with no CORS headers.
            If strict_cors_mode == False and the Origin does not match:
                The response should be returned with the CORS headers.
        """
        expose_headers = ['Content-Length', 'Etag', 'X-Timestamp',
                          'X-Trans-Id']
        container_headers = {
            'X-Container-Meta-Access-Control-Allow-Origin':
            'http://example.com',
            'X-Container-Meta-Access-Control-Max-Age': '5',
            'X-Container-Meta-Access-Control-Expose-Headers':
            ','.join(expose_headers)}
        container_name = self.create_temp_container(
            descriptor='container-smoke', headers=container_headers)

        tempurl_key = self.behaviors.get_tempurl_key()
        files = [{'name': 'foo1'}]

        # Requests with no Origin should not return CORS headers.
        formpost_info = self.client.create_formpost(
            container_name, files, key=tempurl_key)
        dumb_client = BaseHTTPClient()
        headers = formpost_info.get('headers')
        response = dumb_client.post(formpost_info.get('target_url'),
                                    headers=headers,
                                    data=formpost_info.get('body'),
                                    allow_redirects=False)
        self.assertTrue(303, response.status_code)
        self.assertTrue('location' in response.headers)
        self.assertTrue('access-control-expose-headers' not in
                        response.headers)
        self.assertTrue('access-control-allow-origin' not in response.headers)

        # Requests with Origin which does match, should return CORS headers.
        formpost_info = self.client.create_formpost(
            container_name, files, key=tempurl_key)
        dumb_client = BaseHTTPClient()
        headers = formpost_info.get('headers')
        headers['Origin'] = 'http://example.com'
        response = dumb_client.post(formpost_info.get('target_url'),
                                    headers=headers,
                                    data=formpost_info.get('body'),
                                    allow_redirects=False)
        self.assertTrue(303, response.status_code)
        self.assertTrue('access-control-expose-headers' in response.headers)
        self.assertTrue('location' in response.headers)
        self.assertTrue('access-control-allow-origin' in response.headers)

        if self.objectstorage_api_config.strict_cors_mode:
            # CORS should work according to the spec.
            # Requests with Origin which does not match, should not return
            # CORS headers.
            formpost_info = self.client.create_formpost(
                container_name, files, key=tempurl_key)
            dumb_client = BaseHTTPClient()
            headers = formpost_info.get('headers')
            headers['Origin'] = 'http://foo.com'
            response = dumb_client.post(formpost_info.get('target_url'),
                                        headers=headers,
                                        data=formpost_info.get('body'),
                                        allow_redirects=False)
            self.assertTrue(303, response.status_code)
            self.assertTrue('access-control-expose-headers' not in
                            response.headers)
            self.assertTrue('location' not in response.headers)
            self.assertTrue('access-control-allow-origin' not in
                            response.headers)
        else:
            # Early implementation of CORS.
            # Requests with Origin which does not match, should not return
            # CORS headers.
            formpost_info = self.client.create_formpost(
                container_name, files, key=tempurl_key)
            dumb_client = BaseHTTPClient()
            headers = formpost_info.get('headers')
            headers['Origin'] = 'http://foo.com'
            response = dumb_client.post(formpost_info.get('target_url'),
                                        headers=headers,
                                        data=formpost_info.get('body'),
                                        allow_redirects=False)
            self.assertTrue(303, response.status_code)
            self.assertTrue('access-control-expose-headers' in
                            response.headers)
            self.assertTrue('location' in response.headers)
            self.assertTrue('access-control-allow-origin' in response.headers)

    @data_driven_test(ObjectDatasetList())
    @ObjectStorageFixture.required_features('tempurl', 'object-cors')
    def ddtest_object_cors_with_tempurl(self, object_type, generate_object):
        """
        Scenario:
            Create a container.
            Create a object with CORS headers.
            Retrieve the object via TempURL.

        Expected Results:
            If no Origin is set:
                The object should be returned with no CORS headers.
            If the Origin matches the Allow-Origin set:
                The object should be returned with the CORS headers.
            If strict_cors_mode == True and the Origin does not match:
                The object should be returned with no CORS headers.
            If strict_cors_mode == False and the Origin does not match:
                The object should be returned with the CORS headers.
        """
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = 'object'
        expose_headers = ['Content-Length', 'Etag', 'X-Timestamp',
                          'X-Trans-Id']
        object_headers = {
            'Content-Type': 'text/plain',
            'X-Object-Meta-Access-Control-Allow-Origin':
            'http://example.com',
            'X-Object-Meta-Access-Control-Max-Age': '5',
            'X-Object-Meta-Access-Control-Expose-Headers':
            ','.join(expose_headers)}
        generate_object(container_name, object_name, headers=object_headers)
        tempurl_key = self.behaviors.get_tempurl_key()
        tempurl_info = self.client.create_temp_url(
            'GET', container_name, object_name, 900, tempurl_key)

        dumb_client = BaseHTTPClient()

        # Requests with no Origin should not return CORS headers.
        response = dumb_client.request(
            'GET', tempurl_info.get('target_url'), params={
                'temp_url_sig': tempurl_info.get('signature'),
                'temp_url_expires': tempurl_info.get('expires')})
        self.assertTrue(
            'Access-Control-Allow-Origin' not in response.headers,
            'Allow-Origin header should not be returned.')
        self.assertTrue('Access-Control-Max-Age' not in response.headers,
                        'Max-Age should not be returned.')
        self.assertTrue(
            'Access-Control-Expose-Headers' not in response.headers,
            'Expose-Headers should not be returned.')

        # Requests with Origin which does match, should return CORS headers.
        response = dumb_client.request(
            'GET', tempurl_info.get('target_url'), params={
                'temp_url_sig': tempurl_info.get('signature'),
                'temp_url_expires': tempurl_info.get('expires')},
            headers={'Origin': 'http://example.com'})
        self.assertTrue(
            'Access-Control-Allow-Origin' in response.headers,
            'Allow-Origin header should be returned.')
        self.assertTrue(
            'Access-Control-Expose-Headers' in response.headers,
            'Expose-Headers should be returned.')
        self.assertTrue('Access-Control-Max-Age' not in response.headers,
                        'Max-Age should not be returned.')

        if self.objectstorage_api_config.strict_cors_mode:
            # CORS should work according to the spec.
            # Requests with Origin which does not match, should not return
            # CORS headers.
            response = dumb_client.request(
                'GET', tempurl_info.get('target_url'), params={
                    'temp_url_sig': tempurl_info.get('signature'),
                    'temp_url_expires': tempurl_info.get('expires')},
                headers={'Origin': 'http://foo.com'})
            self.assertTrue(
                'Access-Control-Allow-Origin' not in response.headers,
                'Allow-Origin header should not be returned.')
            self.assertTrue('Access-Control-Max-Age' not in response.headers,
                            'Max-Age should not be returned.')
            self.assertTrue(
                'Access-Control-Expose-Headers' not in response.headers,
                'Expose-Headers should not be returned.')
        else:
            # Early implementation of CORS.
            # Requests with Origin which does not match, should not return
            # CORS headers.
            response = dumb_client.request(
                'GET', tempurl_info.get('target_url'), params={
                    'temp_url_sig': tempurl_info.get('signature'),
                    'temp_url_expires': tempurl_info.get('expires')},
                headers={'Origin': 'http://foo.com'})
            self.assertTrue(
                'Access-Control-Allow-Origin' in response.headers,
                'Allow-Origin header should be returned with '
                'differing origin.')
            self.assertTrue(
                'Access-Control-Expose-Headers' in response.headers,
                'Expose-Headers should be returned with '
                'differing origin.')
            self.assertTrue('Access-Control-Max-Age' not in response.headers,
                            'Max-Age should not be returned with '
                            'differing origin.')

    @data_driven_test(ObjectDatasetList())
    @ObjectStorageFixture.required_features('tempurl', 'object-cors')
    def ddtest_object_override_container_cors_with_tempurl(
            self, object_type, generate_object):
        """
        Scenario:
            Create a container with CORS headers.
            Create a object with CORS headers.
            Retrieve the object via TempURL.

        Expected Results:
            If no Origin is set:
                The object should be returned with no CORS headers.
            If the Origin matches the object's Allow-Origin:
                The object should be returned with the CORS headers.
            If strict_cors_mode == True and the Origin does not match:
                The object should be returned with no CORS headers.
            If strict_cors_mode == False and the Origin does not match:
                The object should be returned with the CORS headers.
        """
        container_expose_headers = ['Content-Length', 'Etag']
        container_headers = {
            'X-Container-Meta-Access-Control-Allow-Origin':
            'http://foo.com',
            'X-Container-Meta-Access-Control-Expose-Headers':
            ','.join(container_expose_headers)}
        container_name = self.create_temp_container(
            descriptor='container-smoke', headers=container_headers)

        object_expose_headers = ['X-Timestamp', 'X-Trans-Id']
        object_headers = {
            'Content-Type': 'text/plain',
            'X-Object-Meta-Access-Control-Allow-Origin':
            'http://bar.com',
            'X-Object-Meta-Access-Control-Expose-Headers':
            ','.join(object_expose_headers)}
        object_name = 'object'
        object_headers = {'Content-Type': 'text/plain'}
        generate_object(container_name, object_name, headers=object_headers)
        tempurl_key = self.behaviors.get_tempurl_key()
        tempurl_info = self.client.create_temp_url(
            'GET', container_name, object_name, 900, tempurl_key)

        dumb_client = BaseHTTPClient()

        # Requests with no Origin should not return CORS headers.
        response = dumb_client.request(
            'GET', tempurl_info.get('target_url'), params={
                'temp_url_sig': tempurl_info.get('signature'),
                'temp_url_expires': tempurl_info.get('expires')})
        self.assertTrue(
            'Access-Control-Allow-Origin' not in response.headers,
            'Allow-Origin header should not be returned.')
        self.assertTrue(
            'Access-Control-Expose-Headers' not in response.headers,
            'Expose-Headers should not be returned.')

        # Requests with Origin which matches object, should return CORS
        # headers.
        response = dumb_client.request(
            'GET', tempurl_info.get('target_url'), params={
                'temp_url_sig': tempurl_info.get('signature'),
                'temp_url_expires': tempurl_info.get('expires')},
            headers={'Origin': 'http://bar.com'})
        self.assertTrue(
            'Access-Control-Allow-Origin' in response.headers,
            'Allow-Origin header should be returned.')
        self.assertEqual(
            'http://bar.com', response.headers.get(
                'Access-Control-Allow-Origin', ''),
            'Allow-Origin header should be returned.')
        self.assertTrue(
            'Access-Control-Expose-Headers' in response.headers,
            'Expose-Headers should be returned.')

        if self.objectstorage_api_config.strict_cors_mode:
            # CORS should work according to the spec.

            # Requests with Origin which matches container, should not return
            # CORS headers.
            response = dumb_client.request(
                'GET', tempurl_info.get('target_url'), params={
                    'temp_url_sig': tempurl_info.get('signature'),
                    'temp_url_expires': tempurl_info.get('expires')},
                headers={'Origin': 'http://foo.com'})
            self.assertTrue(
                'Access-Control-Allow-Origin' not in response.headers,
                'Allow-Origin header should not be returned.')
            self.assertTrue(
                'Access-Control-Expose-Headers' not in response.headers,
                'Expose-Headers should not be returned.')

            # Requests with Origin which does not match, should not return
            # CORS headers.
            response = dumb_client.request(
                'GET', tempurl_info.get('target_url'), params={
                    'temp_url_sig': tempurl_info.get('signature'),
                    'temp_url_expires': tempurl_info.get('expires')},
                headers={'Origin': 'http://example.com'})
            self.assertTrue(
                'Access-Control-Allow-Origin' not in response.headers,
                'Allow-Origin header should not be returned.')
            self.assertTrue(
                'Access-Control-Expose-Headers' not in response.headers,
                'Expose-Headers should not be returned.')
        else:
            # Early implementation of CORS.

            # Requests with Origin which matches container, should not return
            # CORS headers.
            response = dumb_client.request(
                'GET', tempurl_info.get('target_url'), params={
                    'temp_url_sig': tempurl_info.get('signature'),
                    'temp_url_expires': tempurl_info.get('expires')},
                headers={'Origin': 'http://foo.com'})
            self.assertTrue(
                'Access-Control-Allow-Origin' in response.headers,
                'Allow-Origin header should be returned.')
            self.assertTrue(
                'Access-Control-Expose-Headers' in response.headers,
                'Expose-Headers should be returned.')

            # Requests with Origin which does not match, should not return
            # CORS headers.
            response = dumb_client.request(
                'GET', tempurl_info.get('target_url'), params={
                    'temp_url_sig': tempurl_info.get('signature'),
                    'temp_url_expires': tempurl_info.get('expires')},
                headers={'Origin': 'http://example.com'})
            self.assertTrue(
                'Access-Control-Allow-Origin' in response.headers,
                'Allow-Origin header should be returned with '
                'differing origin.')
            self.assertTrue(
                'Access-Control-Expose-Headers' in response.headers,
                'Expose-Headers should be returned with '
                'differing origin.')
Exemple #7
0
class ExpiringObjectTest(ObjectStorageFixture):
    @classmethod
    def setUpClass(cls):
        super(ExpiringObjectTest, cls).setUpClass()
        cls.default_obj_name = cls.behaviors.VALID_OBJECT_NAME
        cls.default_obj_data = "Test Data"

    @data_driven_test(ObjectDatasetList())
    def ddtest_object_creation_with_x_delete_at(self, object_type,
                                                generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name

        start_time = timegm(gmtime())
        future_time = str(int(start_time + 60))
        object_headers = {'X-Delete-At': future_time}
        generate_object(container_name, object_name, headers=object_headers)

        response = self.client.get_object(container_name, object_name)

        content_length = response.headers.get('content-length')
        self.assertNotEqual(content_length, 0)

        # wait for the object to expire - future_time + 10 seconds
        sleep(70)

        response = self.client.get_object(container_name, object_name)

        self.assertEqual(response.status_code, 404)

    @data_driven_test(ObjectDatasetList())
    def ddtest_object_creation_with_x_delete_after(self, object_type,
                                                   generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        object_headers = {'X-Delete-After': '60'}
        generate_object(container_name, object_name, headers=object_headers)

        response = self.client.get_object(container_name, object_name)

        content_length = response.headers.get('content-length')
        self.assertNotEqual(content_length, 0)

        # wait for the object to expire - delete after 60 seconds + 10 seconds
        sleep(70)

        response = self.client.get_object(container_name, object_name)

        self.assertEqual(response.status_code, 404)

    @data_driven_test(ObjectDatasetList())
    def ddtest_object_creation_with_x_delete_after_with_unicode_container_name(
            self, object_type, generate_object):
        """
        Scenario:
            Create a container with a unicode name and then add
            an expiring object to it using x_delete_after

        Expected Results:
            The object should be available until the expiration time,
            then it should be deleted
        """
        delete_after = 60

        container_description = unicode(u'\u262D\u2622').encode('utf-8')
        container_name = self.create_temp_container(
            descriptor=container_description)

        object_name = self.default_obj_name
        object_headers = {'X-Delete-After': delete_after}
        generate_object(container_name, object_name, headers=object_headers)

        object_response = self.client.get_object(container_name, object_name)

        method = 'Creating Expiring Object in Unicode Container'
        expected = 200
        received = object_response.status_code

        self.assertEqual(expected,
                         received,
                         msg=STATUS_CODE_MSG.format(method=method,
                                                    expected=expected,
                                                    received=str(received)))

        # Sleep for period set as X-Delete-After(object expiration)
        sleep(delete_after)

        object_response = self.client.get_object(container_name, object_name)

        method = 'GET on expired object in Unicode Container'
        expected = 404
        received = object_response.status_code

        self.assertEqual(expected,
                         received,
                         msg=STATUS_CODE_MSG.format(method=method,
                                                    expected=expected,
                                                    received=str(received)))

    @data_driven_test(ObjectDatasetList())
    def ddtest_object_creation_with_x_delete_at_with_unicode_container_name(
            self, object_type, generate_object):
        """
        Scenario:
            Create a container with a unicode name and then add
            an expiring object to it using x_delete_at.

        Expected Results:
            The object should be available until the expiration time,
            then it should be deleted
        """
        start_time = timegm(gmtime())
        future_time = str(int(start_time + 60))

        container_description = unicode(u'\u262D\u2622').encode('utf-8')
        container_name = self.create_temp_container(
            descriptor=container_description)

        object_name = self.default_obj_name
        object_headers = {'X-Delete-At': future_time}
        generate_object(container_name, object_name, headers=object_headers)

        object_response = self.client.get_object(container_name, object_name)

        method = 'Creating Expiring Object in Unicode Container'
        expected = 200
        received = object_response.status_code

        self.assertEqual(expected,
                         received,
                         msg=STATUS_CODE_MSG.format(method=method,
                                                    expected=expected,
                                                    received=str(received)))

        # Wait for object to expire using interval from config
        sleep(self.objectstorage_api_config.object_deletion_wait_interval)

        object_response = self.client.get_object(container_name, object_name)

        method = 'GET on expired object in Unicode Container'
        expected = 404
        received = object_response.status_code

        self.assertEqual(expected,
                         received,
                         msg=STATUS_CODE_MSG.format(method=method,
                                                    expected=expected,
                                                    received=str(received)))

    @data_driven_test(ObjectDatasetList())
    def ddtest_object_deletion_with_x_delete_at(self):
        """
        Scenario:
            Create an object which has the X-Delete-At metadata.

        Expected Results:
            The object should be accessible before the 'delete at' time.
            The object should not be accessible after the 'delete at' time.
            The object should not be listed after the object expirer has had
                time to run.

        NOTE:
            This is currently a bug and has not yet been fixed.
            https://bugs.launchpad.net/swift/+bug/1257330
        """
        # this is a workaround. skips currently do not work with ddtests
        if get_value('fail') != 'true':
            sys.stderr.write('skipped: current bug ... ')
            return

        container_name = self.behaviors.generate_unique_container_name(
            self.base_container_name)

        self.behaviors.create_container(container_name)

        self.addCleanup(self.behaviors.force_delete_containers,
                        [container_name])

        delete_after = 60
        delete_at = str(int(timegm(gmtime()) + delete_after))
        headers = {
            'Content-Length': str(len(self.default_obj_data)),
            'X-Delete-At': delete_at
        }

        resp = self.client.create_object(container_name,
                                         self.default_obj_name,
                                         headers=headers,
                                         data=self.default_obj_data)

        self.assertEqual(201, resp.status_code,
                         'Object should be created with X-Delete-At header.')

        resp = self.client.get_object(container_name, self.default_obj_name)

        self.assertEqual(200, resp.status_code,
                         'Object should exist before X-Delete-At.')

        # wait for the object to be deleted.
        sleep(delete_after)

        resp = self.client.get_object(container_name, self.default_obj_name)

        self.assertEqual(404, resp.status_code,
                         'Object should be deleted after X-Delete-At.')

        sleep(self.expirer_run_interval)

        get_response = self.client.list_objects(container_name,
                                                params={'format': 'json'})

        self.assertEqual(204, get_response.status_code,
                         'No content should be returned for the request.')

        get_count = int(get_response.headers.get('x-container-object-count'))

        self.assertEqual('0', get_count,
                         'No objects should be listed in the container.')

        self.assertEqual('0', len(get_response.entity),
                         'No objects should be listed in the container.')

        head_response = self.client.get_container_metadata(container_name)

        head_count = int(head_response.headers.get('x-container-object-count'))

        self.assertEqual('0', head_count,
                         'No objects should be listed in the container.')
class ObjectSmokeTest(ObjectStorageFixture):
    @classmethod
    def setUpClass(cls):
        super(ObjectSmokeTest, cls).setUpClass()
        cls.default_obj_name = cls.behaviors.VALID_OBJECT_NAME

    @data_driven_test(ObjectDatasetList())
    def ddtest_object_retrieval_with_valid_object_name(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        generate_object(container_name, object_name)

        response = self.client.get_object(container_name, object_name)

        method = 'object creation with valid object name'
        expected = 200
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

    @data_driven_test(ObjectDatasetList(exclude=['dlo', 'slo']))
    def ddtest_object_retrieval_with_if_match(
            self, object_type, generate_object):
        """
        Bug filed for dlo/slo support of If-match Header:
        https://bugs.launchpad.net/swift/+bug/1279076
        """
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        obj_info = generate_object(container_name, object_name)

        headers = {'If-Match': obj_info.get('etag')}

        response = self.client.get_object(
            container_name,
            self.default_obj_name,
            headers=headers)

        method = 'object retrieval with if match header'
        expected = 200
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

    @data_driven_test(ObjectDatasetList(exclude=['dlo', 'slo']))
    def ddtest_object_retrieval_with_if_none_match(
            self, object_type, generate_object):
        """
        Bug filed for dlo/slo support of If-match Header:
        https://bugs.launchpad.net/swift/+bug/1279076
        """
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        object_info = generate_object(container_name, object_name)

        headers = {'If-None-Match': 'grok'}

        response = self.client.get_object(
            container_name,
            self.default_obj_name,
            headers=headers)

        method = 'object retrieval with if none match header'
        expected = 200
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

        headers = {'If-None-Match': object_info.get('etag')}

        response = self.client.get_object(
            container_name,
            self.default_obj_name,
            headers=headers)

        method = 'object should be flagged as not modified'
        expected = 304
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

    @data_driven_test(ObjectDatasetList())
    def ddtest_object_retrieval_with_if_modified_since(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        generate_object(container_name, object_name)

        headers = {'If-Modified-Since': 'Fri, 17 Aug 2001 18:44:42 GMT'}

        response = self.client.get_object(
            container_name,
            self.default_obj_name,
            headers=headers)

        method = 'object retrieval with if modified since header (past date)'
        expected = 200
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

    @data_driven_test(ObjectDatasetList())
    def ddtest_object_not_modified_with_if_modified_since(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        generate_object(container_name, object_name)

        headers = {'If-Modified-Since': 'Fri, 17 Aug 2101 18:44:42 GMT'}

        response = self.client.get_object(
            container_name,
            self.default_obj_name,
            headers=headers)

        method = 'object retrieval with if modified since header (future date)'
        expected = 304
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

    @data_driven_test(ObjectDatasetList())
    def ddtest_object_retrieval_with_if_unmodified_since(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        generate_object(container_name, object_name)

        headers = {'If-Unmodified-Since': 'Fri, 17 Aug 2101 18:44:42 GMT'}

        response = self.client.get_object(
            container_name,
            self.default_obj_name,
            headers=headers)

        method = 'object retrieval with if unmodified since header'
        expected = 200
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

    @data_driven_test(ObjectDatasetList())
    def ddtest_object_retrieval_fails_with_if_unmodified_since(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        generate_object(container_name, object_name)

        headers = {'If-Unmodified-Since': 'Fri, 17 Aug 2001 18:44:42 GMT'}

        response = self.client.get_object(
            container_name,
            self.default_obj_name,
            headers=headers)

        method = ('object retrieval precondition fail with if unmodified'
                  ' since header')
        expected = 412
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

    @data_driven_test(ObjectDatasetList())
    def ddtest_partial_object_retrieval_with_start_range(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        generate_object(container_name, object_name)

        headers = {'Range': 'bytes=5-'}

        response = self.client.get_object(
            container_name,
            self.default_obj_name,
            headers=headers)

        method = 'partial object retrieval with start range'
        expected = 206
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method, expected=expected, received=str(received)))

    @data_driven_test(ObjectDatasetList())
    def ddtest_partial_object_retrieval_with_end_range(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        generate_object(container_name, object_name)

        headers = {'Range': 'bytes=-4'}

        response = self.client.get_object(
            container_name,
            self.default_obj_name,
            headers=headers)

        method = 'partial object retrieval with end range'
        expected = 206
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

    @data_driven_test(ObjectDatasetList())
    def ddtest_partial_object_retrieval_with_range(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        generate_object(container_name, object_name)

        headers = {'Range': 'bytes=5-8'}

        response = self.client.get_object(
            container_name,
            self.default_obj_name,
            headers=headers)

        method = 'partial object retrieval with start and end range'
        expected = 206
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

    @data_driven_test(ObjectDatasetList())
    def ddtest_partial_object_retrieval_with_complete_range(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        generate_object(container_name, object_name)

        headers = {'Range': 'bytes=99-0'}

        response = self.client.get_object(
            container_name,
            self.default_obj_name,
            headers=headers)

        method = 'partial object retrieval with complete range'
        expected = 200
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

    @data_driven_test(ObjectDatasetList())
    def ddtest_object_creation_with_valid_object_name(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        object_info = generate_object(container_name, object_name)

        response = object_info.get('response')
        method = 'object creation with valid object name'
        expected = 201
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

        response = self.client.get_object(
            container_name,
            self.default_obj_name)

        method = 'object retrieval'
        expected = 200
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

        response_md5 = md5.new(response.content).hexdigest()
        self.assertEqual(
            object_info.get('md5'),
            response_md5,
            msg='should return identical object')

    @data_driven_test(ObjectDatasetList(exclude=['dlo', 'slo']))
    def ddtest_object_update_with_valid_object_name(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        generate_object(container_name, object_name)

        updated_object_data = 'Updated test file data'
        updated_content_length = str(len(updated_object_data))
        headers = {'Content-Length': updated_content_length,
                   'Content-Type': CONTENT_TYPES.get('text')}
        response = self.client.create_object(
            container_name,
            self.default_obj_name,
            headers=headers,
            data=updated_object_data)

        method = 'object update with valid object name'
        expected = 201
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

    @data_driven_test(ObjectDatasetList(exclude=['dlo', 'slo']))
    def ddtest_object_creation_with_etag(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        object_info = generate_object(container_name, object_name)

        response = object_info.get('response')
        method = 'object creation with etag header'
        expected = 201
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

        response = self.client.get_object_metadata(
            container_name,
            self.default_obj_name)

        response = self.client.get_object(
            container_name,
            self.default_obj_name)
        self.assertIn(
            'etag',
            response.headers,
            msg="Etag header was set")

        expected = object_info.get('etag')
        received = response.headers.get('etag')

        self.assertEqual(
            expected,
            received,
            msg='object created with Etag header'
                ' value expected: {0} received: {1}'.format(
                    expected,
                    received))

    @data_driven_test(ObjectDatasetList(exclude=['standard']))
    def ddtest_large_object_creation_with_etag(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        object_info = generate_object(container_name, object_name)

        response = object_info.get('response')
        method = 'object creation with etag header'
        expected = 201
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

        response = self.client.get_object_metadata(
            container_name,
            self.default_obj_name)

        response = self.client.get_object(
            container_name,
            self.default_obj_name)
        self.assertIn(
            'etag',
            response.headers,
            msg="Etag header was set")

        expected = '"{0}"'.format(object_info.get('etag'))
        received = response.headers.get('etag')

        self.assertEqual(
            expected,
            received,
            msg='object created with Etag header'
                ' value expected: {0} received: {1}'.format(
                    expected,
                    received))

    @data_driven_test(ObjectDatasetList())
    @ObjectStorageFixture.required_features('object-cors')
    def ddtest_object_creation_with_access_control_allow_credentials(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        object_headers = {'Access-Control-Allow-Credentials': 'true'}
        object_info = generate_object(container_name, object_name,
                                      headers=object_headers)

        response = object_info.get('response')
        method = 'object creation with Access-Control-Allow-Credentials header'
        expected = 201
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

        response = self.client.get_object_metadata(
            container_name,
            self.default_obj_name)

        self.assertIn(
            'Access-Control-Allow-Credentials',
            response.headers,
            msg="Access-Control-Allow-Credentials header was set")

        expected = 'true'
        received = response.headers.get('Access-Control-Allow-Credentials')

        self.assertEqual(
            expected,
            received,
            msg='object created with Access-Control-Allow-Credentials header'
                ' value expected: {0} recieved: {1}'.format(
                    expected,
                    received))

    @data_driven_test(ObjectDatasetList())
    @ObjectStorageFixture.required_features('object-cors')
    def ddtest_object_creation_with_access_control_allow_methods(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        object_headers = {
            'Access-Control-Allow-Methods': 'GET, POST, OPTIONS'}
        object_info = generate_object(container_name, object_name,
                                      headers=object_headers)

        response = object_info.get('response')
        method = 'object creation with Access-Control-Allow-Methods header'
        expected = 201
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

        response = self.client.get_object_metadata(
            container_name,
            self.default_obj_name)

        self.assertIn(
            'Access-Control-Allow-Methods',
            response.headers,
            msg="Access-Control-Allow-Methods header was set")

        expected = 'GET, POST, OPTIONS'
        received = response.headers.get('Access-Control-Allow-Methods')

        self.assertEqual(
            expected,
            received,
            msg='object created with Access-Control-Allow-Methods header'
                ' value expected: {0} recieved: {1}'.format(
                    expected,
                    received))

    @data_driven_test(ObjectDatasetList())
    @ObjectStorageFixture.required_features('object-cors')
    def ddtest_object_creation_with_access_control_allow_origin(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        object_headers = {
            'Access-Control-Allow-Origin': 'http://example.com'}
        object_info = generate_object(container_name, object_name,
                                      headers=object_headers)

        response = object_info.get('response')
        method = 'object creation with Access-Control-Allow-Origin header'
        expected = 201
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

        response = self.client.get_object_metadata(
            container_name, self.default_obj_name)

        self.assertIn(
            'Access-Control-Allow-Origin',
            response.headers,
            msg="Access-Control-Allow-Origin header was set")

        expected = 'http://example.com'
        received = response.headers.get('Access-Control-Allow-Origin')

        self.assertEqual(
            expected,
            received,
            msg='object created with Access-Control-Allow-Origin header'
                ' value expected: {0} recieved: {1}'.format(
                    expected,
                    received))

    @data_driven_test(ObjectDatasetList())
    @ObjectStorageFixture.required_features('object-cors')
    def ddtest_object_creation_with_access_control_expose_headers(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        object_headers = {'Access-Control-Expose-Headers': 'X-Foo-Header'}
        object_info = generate_object(container_name, object_name,
                                      headers=object_headers)

        response = object_info.get('response')
        method = 'object creation with Access-Control-Expose-Headers header'
        expected = 201
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

        response = self.client.get_object_metadata(
            container_name,
            self.default_obj_name)

        self.assertIn(
            'Access-Control-Expose-Headers',
            response.headers,
            msg="Access-Control-Expose-Headers header was set")

        expected = 'X-Foo-Header'
        received = response.headers.get('Access-Control-Expose-Headers')

        self.assertEqual(
            expected,
            received,
            msg='object created with Access-Control-Expose-Headers header'
                ' value expected: {0} recieved: {1}'.format(
                    expected,
                    received))

    @data_driven_test(ObjectDatasetList())
    @ObjectStorageFixture.required_features('object-cors')
    def ddtest_object_creation_with_access_controle_max_age(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        object_headers = {'Access-Control-Max-Age': '5'}
        object_info = generate_object(container_name, object_name,
                                      headers=object_headers)

        response = object_info.get('response')
        method = 'object creation with Access-Control-Max-Age header'
        expected = 201
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

        response = self.client.get_object_metadata(
            container_name,
            self.default_obj_name)

        self.assertIn(
            'Access-Control-Max-Age',
            response.headers,
            msg="Access-Control-Max-Age header was set")

        expected = '5'
        received = response.headers.get('Access-Control-Max-Age')

        self.assertEqual(
            expected,
            received,
            msg='object created with Access-Control-Max-Age header'
                ' value expected: {0} recieved: {1}'.format(
                    expected,
                    received))

    @data_driven_test(ObjectDatasetList())
    @ObjectStorageFixture.required_features('object-cors')
    def ddtest_object_creation_with_access_control_request_headers(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        object_headers = {'Access-Control-Request-Headers': 'x-requested-with'}
        object_info = generate_object(container_name, object_name,
                                      headers=object_headers)

        response = object_info.get('response')
        method = 'object creation with Access-Control-Request-Headers header'
        expected = 201
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

        response = self.client.get_object_metadata(
            container_name,
            self.default_obj_name)

        self.assertIn(
            'Access-Control-Request-Headers',
            response.headers,
            msg="Access-Control-Request-Headers header was set")

        expected = 'x-requested-with'
        received = response.headers.get('Access-Control-Request-Headers')

        self.assertEqual(
            expected,
            received,
            msg='object created with Access-Control-Request-Headers header'
                ' value expected: {0} recieved: {1}'.format(
                    expected,
                    received))

    @data_driven_test(ObjectDatasetList())
    @ObjectStorageFixture.required_features('object-cors')
    def ddtest_object_creation_with_access_control_request_method(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        object_headers = {'Access-Control-Request-Method': 'GET'}
        object_info = generate_object(container_name, object_name,
                                      headers=object_headers)

        response = object_info.get('response')
        method = 'object creation with Access-Control-Request-Method header'
        expected = 201
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

        response = self.client.get_object_metadata(
            container_name,
            self.default_obj_name)

        self.assertIn(
            'Access-Control-Request-Method',
            response.headers,
            msg="Access-Control-Request-Method header was set")

        expected = 'GET'
        received = response.headers.get('Access-Control-Request-Method')

        self.assertEqual(
            expected,
            received,
            msg='object created with Access-Control-Request-Method header'
                ' value expected: {0} recieved: {1}'.format(
                    expected,
                    received))

    @data_driven_test(ObjectDatasetList())
    @ObjectStorageFixture.required_features('object-cors')
    def ddtest_object_retrieval_with_origin(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        headers = {'access-control-allow-origin': 'http://example.com',
                   'access-control-expose-headers': 'X-Trans-Id'}
        generate_object(container_name, object_name, headers=headers)

        headers = {'Origin': 'http://example.com'}
        response = self.client.get_object_metadata(
            container_name, object_name, headers=headers)

        self.assertIn(
            'access-control-expose-headers',
            response.headers,
            msg="access-control-expose-headers header should be set")

        self.assertIn(
            'access-control-allow-origin',
            response.headers,
            msg="access-control-allow-origin header should be set")

        expected = 'http://example.com'
        received = response.headers.get('access-control-allow-origin')

        self.assertEqual(
            expected,
            received,
            msg='access-control-allow-origin header should reflect origin'
                ' expected: {0} recieved: {1}'.format(expected, received))

    @data_driven_test(ObjectDatasetList(exclude=['dlo', 'slo']))
    def ddtest_object_creation_with_file_compression(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name

        def object_data_op(data, extra_data):
            data = zlib.compress(data)
            return (data, extra_data)

        object_headers = {'Content-Encoding': 'gzip'}
        object_info = generate_object(container_name, object_name,
                                      data_op=object_data_op,
                                      headers=object_headers)

        response = object_info.get('response')
        method = 'object creation with Content-Encoding header'
        expected = 201
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

        response = self.client.get_object_metadata(
            container_name,
            self.default_obj_name)

        self.assertIn(
            'Content-Encoding',
            response.headers,
            msg="Content-Encoding header was set")

        expected = 'gzip'
        received = response.headers.get('Content-Encoding')

        self.assertEqual(
            expected,
            received,
            msg='object created with Content-Encoding header value'
                ' expected: {0} recieved: {1}'.format(expected, received))

    @data_driven_test(ObjectDatasetList())
    def ddtest_object_creation_with_content_disposition(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        object_headers = {
            'Content-Disposition': 'attachment; filename=testdata.txt'}
        object_info = generate_object(container_name, object_name,
                                      headers=object_headers)

        response = object_info.get('response')
        method = 'object creation with content disposition header'
        expected = 201
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

        response = self.client.get_object_metadata(
            container_name,
            self.default_obj_name)

        self.assertIn(
            'Content-Disposition',
            response.headers,
            msg="Content-Disposition header was set")

        expected = 'attachment; filename=testdata.txt'
        received = response.headers.get('Content-Disposition')

        self.assertEqual(
            expected,
            received,
            msg='object created with Content-Disposition header value'
                ' expected: {0} recieved: {1}'.format(expected, received))

    @data_driven_test(ObjectDatasetList())
    def ddtest_object_creation_with_x_delete_at(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name

        start_time = calendar.timegm(time.gmtime())
        future_time = str(int(start_time + 60))
        object_headers = {'X-Delete-At': future_time}
        object_info = generate_object(container_name, object_name,
                                      headers=object_headers)

        response = object_info.get('response')
        method = 'object creation with X-Delete-At header'
        expected = 201
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

        response = self.client.get_object_metadata(
            container_name,
            self.default_obj_name)

        self.assertIn(
            'X-Delete-At',
            response.headers,
            msg="X-Delete-At header was set")

        expected = future_time
        received = response.headers.get('X-Delete-At')

        self.assertEqual(
            expected,
            received,
            msg='object created with X-Delete-At header value'
                ' expected: {0} recieved: {1}'.format(expected, received))

    @data_driven_test(ObjectDatasetList())
    def ddtest_object_creation_with_delete_after(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        object_headers = {'X-Delete-After': '60'}
        object_info = generate_object(container_name, object_name,
                                      headers=object_headers)

        response = object_info.get('response')
        method = 'object creation with X-Delete-After header'
        expected = 201
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

        response = self.client.get_object_metadata(
            container_name,
            self.default_obj_name)

        self.assertIn(
            'X-Delete-At',
            response.headers,
            msg="X-Delete-At header was set")

    @data_driven_test(ObjectDatasetList())
    @ObjectStorageFixture.required_features('object_versioning')
    def ddtest_versioned_container_creation_with_valid_data(
            self, object_type, generate_object):
        object_history_container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR, headers={
                'X-Versions-Location': object_history_container_name})

        # list objects in non-current container
        response = self.client.list_objects(
            object_history_container_name)

        method = 'list on empty versioned container'
        expected = 204
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

        # Create an object (version 1)
        object_name = self.default_obj_name
        ver1_info = generate_object(container_name, object_name)

        response = ver1_info.get('response')
        method = 'object version one creation'
        expected = 201
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

        # Update an object (version 2)
        object_name = self.default_obj_name
        ver2_info = generate_object(container_name, object_name)

        response = ver2_info.get('response')
        method = 'update version one object'
        expected = 201
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

        response = self.client.list_objects(object_history_container_name)
        method = 'list on versioned container'
        expected = 200
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

    @data_driven_test(ObjectDatasetList())
    def ddtest_put_copy_object(self, object_type, generate_object):
        src_container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        dest_container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)

        src_object_name = '{0}_source'.format(self.default_obj_name)
        generate_object(src_container_name, src_object_name)

        dest_obj_name = '{0}_destination'.format(self.default_obj_name)
        source = '/{0}/{1}'.format(src_container_name, src_object_name)
        hdrs = {'X-Copy-From': source, 'Content-Length': '0'}

        response = self.client.copy_object(
            dest_container_name,
            dest_obj_name,
            headers=hdrs)

        method = 'put copy object'
        expected = 201
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

        response = self.client.get_object(
            dest_container_name,
            dest_obj_name)

        method = 'copied object retrieval'
        expected = 200
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

    @data_driven_test(ObjectDatasetList())
    def ddtest_copy_object(self, object_type, generate_object):
        src_container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        dest_container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)

        src_object_name = '{0}_source'.format(self.default_obj_name)
        generate_object(src_container_name, src_object_name)

        dest_object_name = '{0}_destination'.format(self.default_obj_name)
        dest = '/{0}/{1}'.format(dest_container_name, dest_object_name)
        headers = {'Destination': dest}

        response = self.client.copy_object(
            src_container_name,
            src_object_name,
            headers=headers)

        method = 'copy object'
        expected = 201
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

        response = self.client.get_object(
            dest_container_name,
            dest_object_name)

        method = 'copied object retrieval'
        expected = 200
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

    @data_driven_test(ObjectDatasetList())
    def ddtest_object_deletion_with_valid_object(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        generate_object(container_name, object_name)

        response = self.client.delete_object(
            container_name,
            object_name)

        method = 'delete object'
        expected = 204
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

        response = self.client.get_object(
            container_name,
            self.default_obj_name)

        method = 'object retrieval'
        expected = 404
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

    @data_driven_test(ObjectDatasetList())
    def ddtest_obj_metadata_update_with_object_possessing_metadata(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        generate_object(container_name, object_name,
                        headers={'X-Object-Meta-Grok': 'Drok'})
        response = self.client.get_object_metadata(
            container_name, object_name)

        self.assertIn(
            'X-Object-Meta-Grok',
            response.headers,
            msg="object not created with X-Object-Meta-Grok header")

        expected = 'Drok'
        received = response.headers.get('X-Object-Meta-Grok')

        self.assertEqual(
            expected,
            received,
            msg='object created with X-Object-Meta-Grok header value'
                ' expected: {0} recieved: {1}'.format(expected, received))

        headers = {'X-Object-Meta-Foo': 'Bar'}

        response = self.client.set_object_metadata(
            container_name,
            self.default_obj_name,
            headers=headers)

        method = 'set object metadata'
        expected = 202
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

        response = self.client.get_object_metadata(
            container_name,
            self.default_obj_name)

        self.assertIn(
            'X-Object-Meta-Foo',
            response.headers,
            msg="object updated with X-Object-Meta-Foo header")

        expected = 'Bar'
        received = response.headers.get('X-Object-Meta-Foo')

        self.assertEqual(
            expected,
            received,
            msg='object X-Object-Meta-Foo header value expected: {0}'
                ' recieved: {1}'.format(expected, received))

    @data_driven_test(ObjectDatasetList())
    def ddtest_obj_metadata_update(self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object_name = self.default_obj_name
        generate_object(container_name, object_name)

        headers = {'X-Object-Meta-Grok': 'Drok'}
        response = self.client.set_object_metadata(
            container_name, object_name, headers=headers)

        method = 'set object metadata X-Object-Meta-Grok: Drok'
        expected = 202
        received = response.status_code

        self.assertEqual(
            expected,
            received,
            msg=STATUS_CODE_MSG.format(
                method=method,
                expected=expected,
                received=str(received)))

        response = self.client.get_object_metadata(
            container_name,
            self.default_obj_name)

        self.assertIn(
            'X-Object-Meta-Grok',
            response.headers,
            msg="object updated with X-Object-Meta-Grok header")

        expected = 'Drok'
        received = response.headers.get('X-Object-Meta-Grok')

        self.assertEqual(
            expected,
            received,
            msg='object X-Object-Meta-Grok header value expected: {0}'
                ' recieved: {1}'.format(expected, received))

    @data_driven_test(ObjectDatasetList())
    def ddtest_content_type_not_detected_without_detect_content_type_header(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object1_name = 'object1.txt'
        object1_headers = {'Content-Type': 'application/x-www-form-urlencoded'}
        generate_object(container_name, object1_name, headers=object1_headers)

        object2_name = 'object2.txt'
        object2_headers = {'X-Detect-Content-Type': False,
                           'Content-Type': 'application/x-www-form-urlencoded'}
        generate_object(container_name, object2_name, headers=object2_headers)

        response = self.client.get_object(
            container_name, object1_name)

        expected = 'application/x-www-form-urlencoded'
        received = response.headers.get('content-type')

        self.assertEqual(
            expected,
            received,
            msg='object created should have content type: {0}'
                ' recieved: {1}'.format(expected, received))

        response = self.client.get_object(
            container_name, object2_name)

        self.assertEqual(
            expected,
            received,
            msg='object created should have content type: {0}'
                ' recieved: {1}'.format(expected, received))

    @data_driven_test(ObjectDatasetList())
    def ddtest_content_type_detected_with_detect_content_type(
            self, object_type, generate_object):
        container_name = self.create_temp_container(
            descriptor=CONTAINER_DESCRIPTOR)
        object1_name = 'object1.txt'
        object1_headers = {'X-Detect-Content-Type': True,
                           'Content-Type': 'application/x-www-form-urlencoded'}
        generate_object(container_name, object1_name, headers=object1_headers)

        response = self.client.get_object(
            container_name, object1_name)

        expected = 'text/plain'
        received = response.headers.get('content-type')

        self.assertEqual(
            expected,
            received,
            msg='object created should have content type: {0}'
                ' recieved: {1}'.format(expected, received))

        object2_name = 'object2.txt'
        object2_headers = {'X-Detect-Content-Type': True}
        generate_object(container_name, object2_name, headers=object2_headers)

        response = self.client.get_object(
            container_name, object2_name)

        expected = 'text/plain'
        received = response.headers.get('content-type')

        self.assertEqual(
            expected,
            received,
            msg='object created should have content type: {0}'
                ' recieved: {1}'.format(expected, received))