From f06d48f2b2b59f3c5c27a35843bd705cb4753595 Mon Sep 17 00:00:00 2001 From: HemangChothani Date: Tue, 25 Feb 2020 11:19:01 +0530 Subject: [PATCH 1/7] feat(storage): add cname support for v4 signature --- google/cloud/storage/_signing.py | 3 ++- google/cloud/storage/blob.py | 13 +++++++++++++ google/cloud/storage/bucket.py | 13 +++++++++++++ tests/unit/test_blob.py | 10 ++++++++++ tests/unit/test_bucket.py | 10 ++++++++++ 5 files changed, 48 insertions(+), 1 deletion(-) diff --git a/google/cloud/storage/_signing.py b/google/cloud/storage/_signing.py index 0da075ddb..5d229a923 100644 --- a/google/cloud/storage/_signing.py +++ b/google/cloud/storage/_signing.py @@ -553,7 +553,8 @@ def generate_signed_url_v4( header_names = [key.lower() for key in headers] if "host" not in header_names: - headers["Host"] = "storage.googleapis.com" + host_name = six.moves.urllib.parse.urlparse(api_access_endpoint) + headers["Host"] = host_name.netloc if method.upper() == "RESUMABLE": method = "POST" diff --git a/google/cloud/storage/blob.py b/google/cloud/storage/blob.py index 0d412447b..0db05a3a4 100644 --- a/google/cloud/storage/blob.py +++ b/google/cloud/storage/blob.py @@ -362,6 +362,7 @@ def generate_signed_url( service_account_email=None, access_token=None, virtual_hosted_style=False, + use_cname=None, ): """Generates a signed URL for this blob. @@ -384,6 +385,8 @@ def generate_signed_url( accessible blobs, but don't want to require users to explicitly log in. + If ``cname`` is set as an argument of :attr:`api_access_endpoint`, ``https`` works only if using a ``CDN``. + :type expiration: Union[Integer, datetime.datetime, datetime.timedelta] :param expiration: Point in time when the signed URL should expire. @@ -460,6 +463,13 @@ def generate_signed_url( (Optional) If true, then construct the URL relative the bucket's virtual hostname, e.g., '.storage.googleapis.com'. + :type use_cname: bool + :param use_cname: + (Optional) If true, then construct the URL relative the bucket-bound hostname , + pass ``bucket-bound hostname`` value as argument of ``api_access_endpoint``, + e.g., 'api_access_endpoint = '. See: + https://cloud.google.com/storage/docs/request-endpoints#cname + :raises: :exc:`ValueError` when version is invalid. :raises: :exc:`TypeError` when expiration is not a valid type. :raises: :exc:`AttributeError` if credentials is not an instance @@ -486,6 +496,9 @@ def generate_signed_url( bucket_name=self.bucket.name, quoted_name=quoted_name ) + if use_cname: + resource = "/{quoted_name}".format(quoted_name=quoted_name) + if credentials is None: client = self._require_client(client) credentials = client._credentials diff --git a/google/cloud/storage/bucket.py b/google/cloud/storage/bucket.py index e71b3cbb9..ae888fd6b 100644 --- a/google/cloud/storage/bucket.py +++ b/google/cloud/storage/bucket.py @@ -2355,6 +2355,7 @@ def generate_signed_url( credentials=None, version=None, virtual_hosted_style=False, + use_cname=None, ): """Generates a signed URL for this bucket. @@ -2373,6 +2374,8 @@ def generate_signed_url( amount of time, you can use this method to generate a URL that is only valid within a certain time period. + If ``cname`` is set as an argument of :attr:`api_access_endpoint`, ``https`` works only if using a ``CDN``. + This is particularly useful if you don't want publicly accessible buckets, but don't want to require users to explicitly log in. @@ -2422,6 +2425,13 @@ def generate_signed_url( (Optional) If true, then construct the URL relative the bucket's virtual hostname, e.g., '.storage.googleapis.com'. + :type use_cname: bool + :param use_cname: + (Optional) If true, then construct the URL relative the bucket-bound hostname , + pass ``bucket-bound hostname`` value as argument of ``api_access_endpoint``, + e.g., 'api_access_endpoint = '. See: + https://cloud.google.com/storage/docs/request-endpoints#cname + :raises: :exc:`ValueError` when version is invalid. :raises: :exc:`TypeError` when expiration is not a valid type. :raises: :exc:`AttributeError` if credentials is not an instance @@ -2444,6 +2454,9 @@ def generate_signed_url( else: resource = "/{bucket_name}".format(bucket_name=self.name) + if use_cname: + resource = "/" + if credentials is None: client = self._require_client(client) credentials = client._credentials diff --git a/tests/unit/test_blob.py b/tests/unit/test_blob.py index 856aa712e..20d4b2be9 100644 --- a/tests/unit/test_blob.py +++ b/tests/unit/test_blob.py @@ -400,6 +400,7 @@ def _generate_signed_url_helper( access_token=None, service_account_email=None, virtual_hosted_style=False, + use_cname=None, ): from six.moves.urllib import parse from google.cloud._helpers import UTC @@ -444,6 +445,7 @@ def _generate_signed_url_helper( access_token=access_token, service_account_email=service_account_email, virtual_hosted_style=virtual_hosted_style, + use_cname=use_cname, ) self.assertEqual(signed_uri, signer.return_value) @@ -465,6 +467,9 @@ def _generate_signed_url_helper( expected_api_access_endpoint = api_access_endpoint expected_resource = "/{}/{}".format(bucket.name, quoted_name) + if use_cname: + expected_resource = "/{}".format(quoted_name) + if encryption_key is not None: expected_headers = headers or {} if effective_version == "v2": @@ -619,6 +624,11 @@ def test_generate_signed_url_v4_w_csek_and_headers(self): def test_generate_signed_url_v4_w_virtual_hostname(self): self._generate_signed_url_v4_helper(virtual_hosted_style=True) + def test_generate_signed_url_v4_w_bucket_bound_hostname(self): + self._generate_signed_url_v4_helper( + api_access_endpoint="https://cdn.example.com", use_cname=True + ) + def test_generate_signed_url_v4_w_credentials(self): credentials = object() self._generate_signed_url_v4_helper(credentials=credentials) diff --git a/tests/unit/test_bucket.py b/tests/unit/test_bucket.py index 684d1d486..0f1d45dc7 100644 --- a/tests/unit/test_bucket.py +++ b/tests/unit/test_bucket.py @@ -2740,6 +2740,7 @@ def _generate_signed_url_helper( credentials=None, expiration=None, virtual_hosted_style=False, + use_cname=None, ): from six.moves.urllib import parse from google.cloud._helpers import UTC @@ -2775,6 +2776,7 @@ def _generate_signed_url_helper( query_parameters=query_parameters, version=version, virtual_hosted_style=virtual_hosted_style, + use_cname=use_cname, ) self.assertEqual(signed_uri, signer.return_value) @@ -2793,6 +2795,9 @@ def _generate_signed_url_helper( expected_api_access_endpoint = api_access_endpoint expected_resource = "/{}".format(parse.quote(bucket_name)) + if use_cname: + expected_resource = "/" + expected_kwargs = { "resource": expected_resource, "expiration": expiration, @@ -2928,6 +2933,11 @@ def test_generate_signed_url_v4_w_credentials(self): def test_generate_signed_url_v4_w_virtual_hostname(self): self._generate_signed_url_v4_helper(virtual_hosted_style=True) + def test_generate_signed_url_v4_w_bucket_bound_hostname(self): + self._generate_signed_url_v4_helper( + api_access_endpoint="https://cdn.example.com", use_cname=True + ) + class _Connection(object): _delete_bucket = False From ad1afc9686700da245575ed705ce20e4677c59af Mon Sep 17 00:00:00 2001 From: HemangChothani Date: Wed, 26 Feb 2020 16:04:03 +0530 Subject: [PATCH 2/7] docs(storage): comment changes --- google/cloud/storage/_signing.py | 3 +-- google/cloud/storage/blob.py | 5 ++--- google/cloud/storage/bucket.py | 4 ++-- tests/unit/test_blob.py | 3 +-- tests/unit/test_bucket.py | 3 +-- 5 files changed, 7 insertions(+), 11 deletions(-) diff --git a/google/cloud/storage/_signing.py b/google/cloud/storage/_signing.py index 5d229a923..8f3059f5f 100644 --- a/google/cloud/storage/_signing.py +++ b/google/cloud/storage/_signing.py @@ -553,8 +553,7 @@ def generate_signed_url_v4( header_names = [key.lower() for key in headers] if "host" not in header_names: - host_name = six.moves.urllib.parse.urlparse(api_access_endpoint) - headers["Host"] = host_name.netloc + headers["Host"] = six.moves.urllib.parse.urlparse(api_access_endpoint).netloc if method.upper() == "RESUMABLE": method = "POST" diff --git a/google/cloud/storage/blob.py b/google/cloud/storage/blob.py index 0db05a3a4..388c15db8 100644 --- a/google/cloud/storage/blob.py +++ b/google/cloud/storage/blob.py @@ -465,7 +465,7 @@ def generate_signed_url( :type use_cname: bool :param use_cname: - (Optional) If true, then construct the URL relative the bucket-bound hostname , + (Optional) If true, then construct the URL relative the bucket-bound hostname, pass ``bucket-bound hostname`` value as argument of ``api_access_endpoint``, e.g., 'api_access_endpoint = '. See: https://cloud.google.com/storage/docs/request-endpoints#cname @@ -490,13 +490,12 @@ def generate_signed_url( api_access_endpoint = "https://{bucket_name}.storage.googleapis.com".format( bucket_name=self.bucket.name ) - resource = "/{quoted_name}".format(quoted_name=quoted_name) else: resource = "/{bucket_name}/{quoted_name}".format( bucket_name=self.bucket.name, quoted_name=quoted_name ) - if use_cname: + if virtual_hosted_style or use_cname: resource = "/{quoted_name}".format(quoted_name=quoted_name) if credentials is None: diff --git a/google/cloud/storage/bucket.py b/google/cloud/storage/bucket.py index ae888fd6b..d7ceb2dbd 100644 --- a/google/cloud/storage/bucket.py +++ b/google/cloud/storage/bucket.py @@ -2450,11 +2450,11 @@ def generate_signed_url( api_access_endpoint = "https://{bucket_name}.storage.googleapis.com".format( bucket_name=self.name ) - resource = "/" + else: resource = "/{bucket_name}".format(bucket_name=self.name) - if use_cname: + if virtual_hosted_style or use_cname: resource = "/" if credentials is None: diff --git a/tests/unit/test_blob.py b/tests/unit/test_blob.py index 20d4b2be9..0e88a0055 100644 --- a/tests/unit/test_blob.py +++ b/tests/unit/test_blob.py @@ -462,12 +462,11 @@ def _generate_signed_url_helper( expected_api_access_endpoint = "https://{}.storage.googleapis.com".format( bucket.name ) - expected_resource = "/{}".format(quoted_name) else: expected_api_access_endpoint = api_access_endpoint expected_resource = "/{}/{}".format(bucket.name, quoted_name) - if use_cname: + if virtual_hosted_style or use_cname: expected_resource = "/{}".format(quoted_name) if encryption_key is not None: diff --git a/tests/unit/test_bucket.py b/tests/unit/test_bucket.py index 0f1d45dc7..f3ef70577 100644 --- a/tests/unit/test_bucket.py +++ b/tests/unit/test_bucket.py @@ -2790,12 +2790,11 @@ def _generate_signed_url_helper( expected_api_access_endpoint = "https://{}.storage.googleapis.com".format( bucket_name ) - expected_resource = "/" else: expected_api_access_endpoint = api_access_endpoint expected_resource = "/{}".format(parse.quote(bucket_name)) - if use_cname: + if virtual_hosted_style or use_cname: expected_resource = "/" expected_kwargs = { From 273f7704cd5035952fea29f2ea6d8d120cde62ca Mon Sep 17 00:00:00 2001 From: HemangChothani Date: Thu, 27 Feb 2020 12:34:05 +0530 Subject: [PATCH 3/7] feat(storage): address comment --- google/cloud/storage/blob.py | 31 +++++++++++++++++++++---------- google/cloud/storage/bucket.py | 30 +++++++++++++++++++++--------- tests/unit/test_blob.py | 21 ++++++++++++++++----- tests/unit/test_bucket.py | 21 ++++++++++++++++----- 4 files changed, 74 insertions(+), 29 deletions(-) diff --git a/google/cloud/storage/blob.py b/google/cloud/storage/blob.py index 388c15db8..9d32c80be 100644 --- a/google/cloud/storage/blob.py +++ b/google/cloud/storage/blob.py @@ -362,7 +362,8 @@ def generate_signed_url( service_account_email=None, access_token=None, virtual_hosted_style=False, - use_cname=None, + bucket_bound_host_name=None, + host_name_scheme="http", ): """Generates a signed URL for this blob. @@ -385,8 +386,6 @@ def generate_signed_url( accessible blobs, but don't want to require users to explicitly log in. - If ``cname`` is set as an argument of :attr:`api_access_endpoint`, ``https`` works only if using a ``CDN``. - :type expiration: Union[Integer, datetime.datetime, datetime.timedelta] :param expiration: Point in time when the signed URL should expire. @@ -463,12 +462,17 @@ def generate_signed_url( (Optional) If true, then construct the URL relative the bucket's virtual hostname, e.g., '.storage.googleapis.com'. - :type use_cname: bool - :param use_cname: - (Optional) If true, then construct the URL relative the bucket-bound hostname, - pass ``bucket-bound hostname`` value as argument of ``api_access_endpoint``, - e.g., 'api_access_endpoint = '. See: - https://cloud.google.com/storage/docs/request-endpoints#cname + :type bucket_bound_host_name: str + :param bucket_bound_host_name: + (Optional) If pass, then construct the URL relative to the bucket-bound hostname + as a CNAME. Value cane be a bare or with scheme, e.g., 'example.com ' or http://example.com. + See: https://cloud.google.com/storage/docs/request-endpoints#cname + + type host_name_scheme: str + :param host_name_scheme: + (Optional) If ``bucket_bound_host_name`` is passed as a bare hostname, use + this value as the scheme. ``https`` will work only when using a CDN. + Defaults to ``"http"``. :raises: :exc:`ValueError` when version is invalid. :raises: :exc:`TypeError` when expiration is not a valid type. @@ -490,12 +494,19 @@ def generate_signed_url( api_access_endpoint = "https://{bucket_name}.storage.googleapis.com".format( bucket_name=self.bucket.name ) + elif bucket_bound_host_name: + if ":" in bucket_bound_host_name: + api_access_endpoint = bucket_bound_host_name + else: + api_access_endpoint = "{scheme}://{cname}".format( + scheme=host_name_scheme, cname=bucket_bound_host_name + ) else: resource = "/{bucket_name}/{quoted_name}".format( bucket_name=self.bucket.name, quoted_name=quoted_name ) - if virtual_hosted_style or use_cname: + if virtual_hosted_style or bucket_bound_host_name: resource = "/{quoted_name}".format(quoted_name=quoted_name) if credentials is None: diff --git a/google/cloud/storage/bucket.py b/google/cloud/storage/bucket.py index d7ceb2dbd..30b37f87e 100644 --- a/google/cloud/storage/bucket.py +++ b/google/cloud/storage/bucket.py @@ -2355,7 +2355,8 @@ def generate_signed_url( credentials=None, version=None, virtual_hosted_style=False, - use_cname=None, + bucket_bound_host_name=None, + host_name_scheme="http", ): """Generates a signed URL for this bucket. @@ -2425,12 +2426,17 @@ def generate_signed_url( (Optional) If true, then construct the URL relative the bucket's virtual hostname, e.g., '.storage.googleapis.com'. - :type use_cname: bool - :param use_cname: - (Optional) If true, then construct the URL relative the bucket-bound hostname , - pass ``bucket-bound hostname`` value as argument of ``api_access_endpoint``, - e.g., 'api_access_endpoint = '. See: - https://cloud.google.com/storage/docs/request-endpoints#cname + :type bucket_bound_host_name: str + :param bucket_bound_host_name: + (Optional) If pass, then construct the URL relative to the bucket-bound hostname + as a CNAME. Value cane be a bare or with scheme, e.g., 'example.com ' or http://example.com. + See: https://cloud.google.com/storage/docs/request-endpoints#cname + + type host_name_scheme: str + :param host_name_scheme: + (Optional) If ``bucket_bound_host_name`` is passed as a bare hostname, use + this value as the scheme. ``https`` will work only when using a CDN. + Defaults to ``"http"``. :raises: :exc:`ValueError` when version is invalid. :raises: :exc:`TypeError` when expiration is not a valid type. @@ -2450,11 +2456,17 @@ def generate_signed_url( api_access_endpoint = "https://{bucket_name}.storage.googleapis.com".format( bucket_name=self.name ) - + elif bucket_bound_host_name: + if ":" in bucket_bound_host_name: + api_access_endpoint = bucket_bound_host_name + else: + api_access_endpoint = "{scheme}://{cname}".format( + scheme=host_name_scheme, cname=bucket_bound_host_name + ) else: resource = "/{bucket_name}".format(bucket_name=self.name) - if virtual_hosted_style or use_cname: + if virtual_hosted_style or bucket_bound_host_name: resource = "/" if credentials is None: diff --git a/tests/unit/test_blob.py b/tests/unit/test_blob.py index 0e88a0055..3079b0eb3 100644 --- a/tests/unit/test_blob.py +++ b/tests/unit/test_blob.py @@ -400,7 +400,8 @@ def _generate_signed_url_helper( access_token=None, service_account_email=None, virtual_hosted_style=False, - use_cname=None, + bucket_bound_host_name=None, + host_name_scheme="http", ): from six.moves.urllib import parse from google.cloud._helpers import UTC @@ -445,7 +446,7 @@ def _generate_signed_url_helper( access_token=access_token, service_account_email=service_account_email, virtual_hosted_style=virtual_hosted_style, - use_cname=use_cname, + bucket_bound_host_name=bucket_bound_host_name, ) self.assertEqual(signed_uri, signer.return_value) @@ -462,11 +463,18 @@ def _generate_signed_url_helper( expected_api_access_endpoint = "https://{}.storage.googleapis.com".format( bucket.name ) + elif bucket_bound_host_name: + if ":" in bucket_bound_host_name: + expected_api_access_endpoint = bucket_bound_host_name + else: + expected_api_access_endpoint = "{scheme}://{cname}".format( + scheme=host_name_scheme, cname=bucket_bound_host_name + ) else: expected_api_access_endpoint = api_access_endpoint expected_resource = "/{}/{}".format(bucket.name, quoted_name) - if virtual_hosted_style or use_cname: + if virtual_hosted_style or bucket_bound_host_name: expected_resource = "/{}".format(quoted_name) if encryption_key is not None: @@ -623,11 +631,14 @@ def test_generate_signed_url_v4_w_csek_and_headers(self): def test_generate_signed_url_v4_w_virtual_hostname(self): self._generate_signed_url_v4_helper(virtual_hosted_style=True) - def test_generate_signed_url_v4_w_bucket_bound_hostname(self): + def test_generate_signed_url_v4_w_bucket_bound_hostname_w_scheme(self): self._generate_signed_url_v4_helper( - api_access_endpoint="https://cdn.example.com", use_cname=True + bucket_bound_host_name="http://cdn.example.com" ) + def test_generate_signed_url_v4_w_bucket_bound_hostname_w_bare_hostname(self): + self._generate_signed_url_v4_helper(bucket_bound_host_name="cdn.example.com") + def test_generate_signed_url_v4_w_credentials(self): credentials = object() self._generate_signed_url_v4_helper(credentials=credentials) diff --git a/tests/unit/test_bucket.py b/tests/unit/test_bucket.py index f3ef70577..3d726da4b 100644 --- a/tests/unit/test_bucket.py +++ b/tests/unit/test_bucket.py @@ -2740,7 +2740,8 @@ def _generate_signed_url_helper( credentials=None, expiration=None, virtual_hosted_style=False, - use_cname=None, + bucket_bound_host_name=None, + host_name_scheme="http", ): from six.moves.urllib import parse from google.cloud._helpers import UTC @@ -2776,7 +2777,7 @@ def _generate_signed_url_helper( query_parameters=query_parameters, version=version, virtual_hosted_style=virtual_hosted_style, - use_cname=use_cname, + bucket_bound_host_name=bucket_bound_host_name, ) self.assertEqual(signed_uri, signer.return_value) @@ -2790,11 +2791,18 @@ def _generate_signed_url_helper( expected_api_access_endpoint = "https://{}.storage.googleapis.com".format( bucket_name ) + elif bucket_bound_host_name: + if ":" in bucket_bound_host_name: + expected_api_access_endpoint = bucket_bound_host_name + else: + expected_api_access_endpoint = "{scheme}://{cname}".format( + scheme=host_name_scheme, cname=bucket_bound_host_name + ) else: expected_api_access_endpoint = api_access_endpoint expected_resource = "/{}".format(parse.quote(bucket_name)) - if virtual_hosted_style or use_cname: + if virtual_hosted_style or bucket_bound_host_name: expected_resource = "/" expected_kwargs = { @@ -2932,11 +2940,14 @@ def test_generate_signed_url_v4_w_credentials(self): def test_generate_signed_url_v4_w_virtual_hostname(self): self._generate_signed_url_v4_helper(virtual_hosted_style=True) - def test_generate_signed_url_v4_w_bucket_bound_hostname(self): + def test_generate_signed_url_v4_w_bucket_bound_hostname_w_scheme(self): self._generate_signed_url_v4_helper( - api_access_endpoint="https://cdn.example.com", use_cname=True + bucket_bound_host_name="http://cdn.example.com" ) + def test_generate_signed_url_v4_w_bucket_bound_hostname_w_bare_hostname(self): + self._generate_signed_url_v4_helper(bucket_bound_host_name="cdn.example.com") + class _Connection(object): _delete_bucket = False From 4057ae7daba4509533dd57328f8304a81098df81 Mon Sep 17 00:00:00 2001 From: HemangChothani Date: Thu, 27 Feb 2020 15:16:24 +0530 Subject: [PATCH 4/7] feat(storage): doc fix --- google/cloud/storage/blob.py | 2 +- google/cloud/storage/bucket.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/google/cloud/storage/blob.py b/google/cloud/storage/blob.py index 9d32c80be..4c8c6ccee 100644 --- a/google/cloud/storage/blob.py +++ b/google/cloud/storage/blob.py @@ -468,7 +468,7 @@ def generate_signed_url( as a CNAME. Value cane be a bare or with scheme, e.g., 'example.com ' or http://example.com. See: https://cloud.google.com/storage/docs/request-endpoints#cname - type host_name_scheme: str + :type host_name_scheme: str :param host_name_scheme: (Optional) If ``bucket_bound_host_name`` is passed as a bare hostname, use this value as the scheme. ``https`` will work only when using a CDN. diff --git a/google/cloud/storage/bucket.py b/google/cloud/storage/bucket.py index 30b37f87e..75b2e6205 100644 --- a/google/cloud/storage/bucket.py +++ b/google/cloud/storage/bucket.py @@ -2432,7 +2432,7 @@ def generate_signed_url( as a CNAME. Value cane be a bare or with scheme, e.g., 'example.com ' or http://example.com. See: https://cloud.google.com/storage/docs/request-endpoints#cname - type host_name_scheme: str + :type host_name_scheme: str :param host_name_scheme: (Optional) If ``bucket_bound_host_name`` is passed as a bare hostname, use this value as the scheme. ``https`` will work only when using a CDN. From 3b96e62481cf472269f49cbbf2ab3f1a348edb59 Mon Sep 17 00:00:00 2001 From: HemangChothani Date: Fri, 6 Mar 2020 14:48:35 +0530 Subject: [PATCH 5/7] feat(storage): nit addressed --- google/cloud/storage/blob.py | 45 ++++++++++++++++++++++------------ google/cloud/storage/bucket.py | 44 +++++++++++++++++++++------------ tests/unit/test_blob.py | 22 ++++++++--------- tests/unit/test_bucket.py | 22 ++++++++--------- 4 files changed, 80 insertions(+), 53 deletions(-) diff --git a/google/cloud/storage/blob.py b/google/cloud/storage/blob.py index 4c8c6ccee..dc706f09b 100644 --- a/google/cloud/storage/blob.py +++ b/google/cloud/storage/blob.py @@ -362,8 +362,8 @@ def generate_signed_url( service_account_email=None, access_token=None, virtual_hosted_style=False, - bucket_bound_host_name=None, - host_name_scheme="http", + bucket_bound_hostname=None, + scheme="http", ): """Generates a signed URL for this blob. @@ -382,6 +382,21 @@ def generate_signed_url( amount of time, you can use this method to generate a URL that is only valid within a certain time period. + If ``bucket_bound_hostname`` is set as an argument of :attr:`api_access_endpoint`, + ``https`` works only if using a ``CDN``. + + Example: + Generates a signed URL for this blob using bucket_bound_hostname and scheme. + + >>> from google.cloud import storage + >>> client = storage.Client() + >>> bucket = client.get_bucket('my-bucket-name') + >>> blob = client.get_blob('my-blob-name') + >>> url = blob.generate_signed_url(expiration='url-expiration-time', bucket_bound_hostname='mydomain.tld', + >>> version='v4') + >>> url = blob.generate_signed_url(expiration='url-expiration-time', bucket_bound_hostname='mydomain.tld', + >>> version='v4',scheme='https') # If using ``CDN`` + This is particularly useful if you don't want publicly accessible blobs, but don't want to require users to explicitly log in. @@ -462,15 +477,15 @@ def generate_signed_url( (Optional) If true, then construct the URL relative the bucket's virtual hostname, e.g., '.storage.googleapis.com'. - :type bucket_bound_host_name: str - :param bucket_bound_host_name: - (Optional) If pass, then construct the URL relative to the bucket-bound hostname - as a CNAME. Value cane be a bare or with scheme, e.g., 'example.com ' or http://example.com. + :type bucket_bound_hostname: str + :param bucket_bound_hostname: + (Optional) If pass, then construct the URL relative to the bucket-bound hostname. + Value cane be a bare or with scheme, e.g., 'example.com' or 'http://example.com'. See: https://cloud.google.com/storage/docs/request-endpoints#cname - :type host_name_scheme: str - :param host_name_scheme: - (Optional) If ``bucket_bound_host_name`` is passed as a bare hostname, use + :type scheme: str + :param scheme: + (Optional) If ``bucket_bound_hostname`` is passed as a bare hostname, use this value as the scheme. ``https`` will work only when using a CDN. Defaults to ``"http"``. @@ -494,19 +509,19 @@ def generate_signed_url( api_access_endpoint = "https://{bucket_name}.storage.googleapis.com".format( bucket_name=self.bucket.name ) - elif bucket_bound_host_name: - if ":" in bucket_bound_host_name: - api_access_endpoint = bucket_bound_host_name + elif bucket_bound_hostname: + if ":" in bucket_bound_hostname: + api_access_endpoint = bucket_bound_hostname else: - api_access_endpoint = "{scheme}://{cname}".format( - scheme=host_name_scheme, cname=bucket_bound_host_name + api_access_endpoint = "{scheme}://{bucket_bound_hostname}".format( + scheme=scheme, bucket_bound_hostname=bucket_bound_hostname ) else: resource = "/{bucket_name}/{quoted_name}".format( bucket_name=self.bucket.name, quoted_name=quoted_name ) - if virtual_hosted_style or bucket_bound_host_name: + if virtual_hosted_style or bucket_bound_hostname: resource = "/{quoted_name}".format(quoted_name=quoted_name) if credentials is None: diff --git a/google/cloud/storage/bucket.py b/google/cloud/storage/bucket.py index 5d4dafb05..4a96313d4 100644 --- a/google/cloud/storage/bucket.py +++ b/google/cloud/storage/bucket.py @@ -2395,8 +2395,8 @@ def generate_signed_url( credentials=None, version=None, virtual_hosted_style=False, - bucket_bound_host_name=None, - host_name_scheme="http", + bucket_bound_hostname=None, + scheme="http", ): """Generates a signed URL for this bucket. @@ -2415,7 +2415,19 @@ def generate_signed_url( amount of time, you can use this method to generate a URL that is only valid within a certain time period. - If ``cname`` is set as an argument of :attr:`api_access_endpoint`, ``https`` works only if using a ``CDN``. + If ``bucket_bound_hostname`` is set as an argument of :attr:`api_access_endpoint`, + ``https`` works only if using a ``CDN``. + + Example: + Generates a signed URL for this bucket using bucket_bound_hostname and scheme. + + >>> from google.cloud import storage + >>> client = storage.Client() + >>> bucket = client.get_bucket('my-bucket-name') + >>> url = bucket.generate_signed_url(expiration='url-expiration-time', bucket_bound_hostname='mydomain.tld', + >>> version='v4') + >>> url = bucket.generate_signed_url(expiration='url-expiration-time', bucket_bound_hostname='mydomain.tld', + >>> version='v4',scheme='https') # If using ``CDN`` This is particularly useful if you don't want publicly accessible buckets, but don't want to require users to explicitly @@ -2466,15 +2478,15 @@ def generate_signed_url( (Optional) If true, then construct the URL relative the bucket's virtual hostname, e.g., '.storage.googleapis.com'. - :type bucket_bound_host_name: str - :param bucket_bound_host_name: - (Optional) If pass, then construct the URL relative to the bucket-bound hostname - as a CNAME. Value cane be a bare or with scheme, e.g., 'example.com ' or http://example.com. + :type bucket_bound_hostname: str + :param bucket_bound_hostname: + (Optional) If pass, then construct the URL relative to the bucket-bound hostname. + Value cane be a bare or with scheme, e.g., 'example.com' or 'http://example.com'. See: https://cloud.google.com/storage/docs/request-endpoints#cname - :type host_name_scheme: str - :param host_name_scheme: - (Optional) If ``bucket_bound_host_name`` is passed as a bare hostname, use + :type scheme: str + :param scheme: + (Optional) If ``bucket_bound_hostname`` is passed as a bare hostname, use this value as the scheme. ``https`` will work only when using a CDN. Defaults to ``"http"``. @@ -2496,17 +2508,17 @@ def generate_signed_url( api_access_endpoint = "https://{bucket_name}.storage.googleapis.com".format( bucket_name=self.name ) - elif bucket_bound_host_name: - if ":" in bucket_bound_host_name: - api_access_endpoint = bucket_bound_host_name + elif bucket_bound_hostname: + if ":" in bucket_bound_hostname: + api_access_endpoint = bucket_bound_hostname else: - api_access_endpoint = "{scheme}://{cname}".format( - scheme=host_name_scheme, cname=bucket_bound_host_name + api_access_endpoint = "{scheme}://{bucket_bound_hostname}".format( + scheme=scheme, bucket_bound_hostname=bucket_bound_hostname ) else: resource = "/{bucket_name}".format(bucket_name=self.name) - if virtual_hosted_style or bucket_bound_host_name: + if virtual_hosted_style or bucket_bound_hostname: resource = "/" if credentials is None: diff --git a/tests/unit/test_blob.py b/tests/unit/test_blob.py index 3079b0eb3..f656e6441 100644 --- a/tests/unit/test_blob.py +++ b/tests/unit/test_blob.py @@ -400,8 +400,8 @@ def _generate_signed_url_helper( access_token=None, service_account_email=None, virtual_hosted_style=False, - bucket_bound_host_name=None, - host_name_scheme="http", + bucket_bound_hostname=None, + scheme="http", ): from six.moves.urllib import parse from google.cloud._helpers import UTC @@ -446,7 +446,7 @@ def _generate_signed_url_helper( access_token=access_token, service_account_email=service_account_email, virtual_hosted_style=virtual_hosted_style, - bucket_bound_host_name=bucket_bound_host_name, + bucket_bound_hostname=bucket_bound_hostname, ) self.assertEqual(signed_uri, signer.return_value) @@ -463,18 +463,18 @@ def _generate_signed_url_helper( expected_api_access_endpoint = "https://{}.storage.googleapis.com".format( bucket.name ) - elif bucket_bound_host_name: - if ":" in bucket_bound_host_name: - expected_api_access_endpoint = bucket_bound_host_name + elif bucket_bound_hostname: + if ":" in bucket_bound_hostname: + expected_api_access_endpoint = bucket_bound_hostname else: - expected_api_access_endpoint = "{scheme}://{cname}".format( - scheme=host_name_scheme, cname=bucket_bound_host_name + expected_api_access_endpoint = "{scheme}://{bucket_bound_hostname}".format( + scheme=scheme, bucket_bound_hostname=bucket_bound_hostname ) else: expected_api_access_endpoint = api_access_endpoint expected_resource = "/{}/{}".format(bucket.name, quoted_name) - if virtual_hosted_style or bucket_bound_host_name: + if virtual_hosted_style or bucket_bound_hostname: expected_resource = "/{}".format(quoted_name) if encryption_key is not None: @@ -633,11 +633,11 @@ def test_generate_signed_url_v4_w_virtual_hostname(self): def test_generate_signed_url_v4_w_bucket_bound_hostname_w_scheme(self): self._generate_signed_url_v4_helper( - bucket_bound_host_name="http://cdn.example.com" + bucket_bound_hostname="http://cdn.example.com" ) def test_generate_signed_url_v4_w_bucket_bound_hostname_w_bare_hostname(self): - self._generate_signed_url_v4_helper(bucket_bound_host_name="cdn.example.com") + self._generate_signed_url_v4_helper(bucket_bound_hostname="cdn.example.com") def test_generate_signed_url_v4_w_credentials(self): credentials = object() diff --git a/tests/unit/test_bucket.py b/tests/unit/test_bucket.py index 18e194711..365e1f0e1 100644 --- a/tests/unit/test_bucket.py +++ b/tests/unit/test_bucket.py @@ -2779,8 +2779,8 @@ def _generate_signed_url_helper( credentials=None, expiration=None, virtual_hosted_style=False, - bucket_bound_host_name=None, - host_name_scheme="http", + bucket_bound_hostname=None, + scheme="http", ): from six.moves.urllib import parse from google.cloud._helpers import UTC @@ -2816,7 +2816,7 @@ def _generate_signed_url_helper( query_parameters=query_parameters, version=version, virtual_hosted_style=virtual_hosted_style, - bucket_bound_host_name=bucket_bound_host_name, + bucket_bound_hostname=bucket_bound_hostname, ) self.assertEqual(signed_uri, signer.return_value) @@ -2830,18 +2830,18 @@ def _generate_signed_url_helper( expected_api_access_endpoint = "https://{}.storage.googleapis.com".format( bucket_name ) - elif bucket_bound_host_name: - if ":" in bucket_bound_host_name: - expected_api_access_endpoint = bucket_bound_host_name + elif bucket_bound_hostname: + if ":" in bucket_bound_hostname: + expected_api_access_endpoint = bucket_bound_hostname else: - expected_api_access_endpoint = "{scheme}://{cname}".format( - scheme=host_name_scheme, cname=bucket_bound_host_name + expected_api_access_endpoint = "{scheme}://{bucket_bound_hostname}".format( + scheme=scheme, bucket_bound_hostname=bucket_bound_hostname ) else: expected_api_access_endpoint = api_access_endpoint expected_resource = "/{}".format(parse.quote(bucket_name)) - if virtual_hosted_style or bucket_bound_host_name: + if virtual_hosted_style or bucket_bound_hostname: expected_resource = "/" expected_kwargs = { @@ -2981,11 +2981,11 @@ def test_generate_signed_url_v4_w_virtual_hostname(self): def test_generate_signed_url_v4_w_bucket_bound_hostname_w_scheme(self): self._generate_signed_url_v4_helper( - bucket_bound_host_name="http://cdn.example.com" + bucket_bound_hostname="http://cdn.example.com" ) def test_generate_signed_url_v4_w_bucket_bound_hostname_w_bare_hostname(self): - self._generate_signed_url_v4_helper(bucket_bound_host_name="cdn.example.com") + self._generate_signed_url_v4_helper(bucket_bound_hostname="cdn.example.com") class _Connection(object): From 3f01a04add34739b090bd839b76c07d8d200dada Mon Sep 17 00:00:00 2001 From: HemangChothani Date: Mon, 9 Mar 2020 12:31:20 +0530 Subject: [PATCH 6/7] feat(storage): add conformance tests --- tests/unit/test__signing.py | 31 ++++++++++++--- tests/unit/url_signer_v4_test_data.json | 50 +++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/tests/unit/test__signing.py b/tests/unit/test__signing.py index c7231b56b..e40055122 100644 --- a/tests/unit/test__signing.py +++ b/tests/unit/test__signing.py @@ -721,13 +721,15 @@ def dummy_service_account(): return _DUMMY_SERVICE_ACCOUNT -def _run_conformance_test(resource, test_data): +def _run_conformance_test( + resource, test_data, api_access_endpoint="https://storage.googleapis.com" +): credentials = dummy_service_account() - url = Test_generate_signed_url_v4._call_fut( credentials, resource, expiration=test_data["expiration"], + api_access_endpoint=api_access_endpoint, method=test_data["method"], _request_timestamp=test_data["timestamp"], headers=test_data.get("headers"), @@ -744,14 +746,31 @@ def test_conformance_client(test_data): @pytest.mark.parametrize("test_data", _BUCKET_TESTS) def test_conformance_bucket(test_data): - resource = "/{}".format(test_data["bucket"]) - _run_conformance_test(resource, test_data) + if "urlStyle" in test_data and test_data["urlStyle"] == "BUCKET_BOUND_DOMAIN": + api_access_endpoint = "{scheme}://{bucket_bound_hostname}".format( + scheme=test_data["scheme"], + bucket_bound_hostname=test_data["bucketBoundDomain"], + ) + resource = "/" + _run_conformance_test(resource, test_data, api_access_endpoint) + else: + resource = "/{}".format(test_data["bucket"]) + _run_conformance_test(resource, test_data) @pytest.mark.parametrize("test_data", _BLOB_TESTS) def test_conformance_blob(test_data): - resource = "/{}/{}".format(test_data["bucket"], test_data["object"]) - _run_conformance_test(resource, test_data) + if "urlStyle" in test_data and test_data["urlStyle"] == "BUCKET_BOUND_DOMAIN": + api_access_endpoint = "{scheme}://{bucket_bound_hostname}".format( + scheme=test_data["scheme"], + bucket_bound_hostname=test_data["bucketBoundDomain"], + ) + resource = "/{}".format(test_data["object"]) + _run_conformance_test(resource, test_data, api_access_endpoint) + else: + + resource = "/{}/{}".format(test_data["bucket"], test_data["object"]) + _run_conformance_test(resource, test_data) def _make_credentials(signer_email=None): diff --git a/tests/unit/url_signer_v4_test_data.json b/tests/unit/url_signer_v4_test_data.json index 807f6cf49..16d15625e 100644 --- a/tests/unit/url_signer_v4_test_data.json +++ b/tests/unit/url_signer_v4_test_data.json @@ -118,5 +118,55 @@ "expiration": 10, "timestamp": "20190201T090000Z", "expectedUrl": "https://storage.googleapis.com/test-bucket?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host&X-Goog-Signature=6dbe94f8e52b2b8a9a476b1c857efa474e09944e2b52b925800316e094a7169d8dbe0df9c0ac08dabb22ac7e827470ceccd65f5a3eadba2a4fb9beebfe37f0d9bb1e552b851fa31a25045bdf019e507f5feb44f061551ef1aeb18dcec0e38ba2e2f77d560a46eaace9c56ed9aa642281301a9d848b0eb30749e34bc7f73a3d596240533466ff9b5f289cd0d4c845c7d96b82a35a5abd0c3aff83e4440ee6873e796087f43545544dc8c01afe1d79c726696b6f555371e491980e7ec145cca0803cf562c38f3fa1d724242f5dea25aac91d74ec9ddd739ff65523627763eaef25cd1f95ad985aaf0079b7c74eb5bcb2870a9b137a7b2c8e41fbe838c95872f75b" + }, + + { + "description": "HTTP Bucket Bound Domain Support", + "bucket": "test-bucket", + "object": "test-object", + "method": "GET", + "expiration": 10, + "timestamp": "20190201T090000Z", + "expectedUrl": "http://mydomain.tld/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host&X-Goog-Signature=7115a77f8c7ed1a8b74bca8b520904fca7f3bab90d69ea052687a94efd9b3a4e2a7fb7135d40e295e0a21958194c55da7e106227957c22ed6edc9d8b3d2a8133bc8af84fc9695dda8081d53f0db5ea9f28e5bfc225d78f873e9f571fd287bb7a95330e726aebd8eb4623cdb0b1a7ceb210b2ce1351b6be0191c2ad7b38f7ceb6c5ce2f98dbfb5a5a649050585e46e97f72f1f5407de657a56e34a3fdc80cdaa0598bd47f3e8af5ff22d0916b19b106890bff8c3f6587f1d3b076b16cd0ba0508607a672be33b9c75d537e15258450b43d22a21c4d528090acbb8e5bae7b31fc394e61394106ef1d6a8ed43074ab05bcec65674cd8113fb3de388da4d97e62f56", + "scheme": "http", + "urlStyle": "BUCKET_BOUND_DOMAIN", + "bucketBoundDomain": "mydomain.tld" + }, + + { + "description": "HTTPS Bucket Bound Domain Support", + "bucket": "test-bucket", + "object": "test-object", + "method": "GET", + "expiration": 10, + "timestamp": "20190201T090000Z", + "expectedUrl": "https://mydomain.tld/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host&X-Goog-Signature=7115a77f8c7ed1a8b74bca8b520904fca7f3bab90d69ea052687a94efd9b3a4e2a7fb7135d40e295e0a21958194c55da7e106227957c22ed6edc9d8b3d2a8133bc8af84fc9695dda8081d53f0db5ea9f28e5bfc225d78f873e9f571fd287bb7a95330e726aebd8eb4623cdb0b1a7ceb210b2ce1351b6be0191c2ad7b38f7ceb6c5ce2f98dbfb5a5a649050585e46e97f72f1f5407de657a56e34a3fdc80cdaa0598bd47f3e8af5ff22d0916b19b106890bff8c3f6587f1d3b076b16cd0ba0508607a672be33b9c75d537e15258450b43d22a21c4d528090acbb8e5bae7b31fc394e61394106ef1d6a8ed43074ab05bcec65674cd8113fb3de388da4d97e62f56", + "scheme": "https", + "urlStyle": "BUCKET_BOUND_DOMAIN", + "bucketBoundDomain": "mydomain.tld" + }, + + { + "description": "HTTP Bucket Bound Domain Support", + "bucket": "test-bucket", + "method": "GET", + "expiration": 10, + "timestamp": "20190201T090000Z", + "expectedUrl": "http://mydomain.tld/?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host&X-Goog-Signature=7a629a5632f16dba78961250b17c1f0d2ac0d2a28dbd7cbf79088fd6cd0b7f3ec66285cdeccca024f7b8134376f5cdcf0d60f399c6df1f19fcf5cf3be9d7f905d72cb6c0b5600f83dd6a7c8df607510c0e12e36216530a7b832eab87920363c5368a7e610d44005c73324f6ca4b435e8687672f46cc1342419ec4a5264549cb4b77bdc73f4f461edf39fbdd8fda99db440b077e906ef48d2c6b854c11ded58096f293d664650c123c6ec2a0379affd05bf5696ba11d3474623e039d5e05d3dc331b86ff4f7afb9262cf9750ff5944e661e70cc443b28f7e150796dde831d70e205c7e848c19b8281510f1d195e5819176e4868713266d0e0db7a3354857187cf", + "scheme": "http", + "urlStyle": "BUCKET_BOUND_DOMAIN", + "bucketBoundDomain": "mydomain.tld" + }, + + { + "description": "HTTPS Bucket Bound Domain Support", + "bucket": "test-bucket", + "method": "GET", + "expiration": 10, + "timestamp": "20190201T090000Z", + "expectedUrl": "https://mydomain.tld/?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host&X-Goog-Signature=7a629a5632f16dba78961250b17c1f0d2ac0d2a28dbd7cbf79088fd6cd0b7f3ec66285cdeccca024f7b8134376f5cdcf0d60f399c6df1f19fcf5cf3be9d7f905d72cb6c0b5600f83dd6a7c8df607510c0e12e36216530a7b832eab87920363c5368a7e610d44005c73324f6ca4b435e8687672f46cc1342419ec4a5264549cb4b77bdc73f4f461edf39fbdd8fda99db440b077e906ef48d2c6b854c11ded58096f293d664650c123c6ec2a0379affd05bf5696ba11d3474623e039d5e05d3dc331b86ff4f7afb9262cf9750ff5944e661e70cc443b28f7e150796dde831d70e205c7e848c19b8281510f1d195e5819176e4868713266d0e0db7a3354857187cf", + "scheme": "https", + "urlStyle": "BUCKET_BOUND_DOMAIN", + "bucketBoundDomain": "mydomain.tld" } ] From 6af0085afd002a78f9f08a9e7b32186b3408c7b7 Mon Sep 17 00:00:00 2001 From: HemangChothani Date: Wed, 11 Mar 2020 10:27:49 +0530 Subject: [PATCH 7/7] feat(storage): nit --- tests/unit/test__signing.py | 8 ++++---- tests/unit/url_signer_v4_test_data.json | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/unit/test__signing.py b/tests/unit/test__signing.py index d1a47b8a9..c3b911f1d 100644 --- a/tests/unit/test__signing.py +++ b/tests/unit/test__signing.py @@ -804,10 +804,10 @@ def test_conformance_client(test_data): @pytest.mark.parametrize("test_data", _BUCKET_TESTS) def test_conformance_bucket(test_data): - if "urlStyle" in test_data and test_data["urlStyle"] == "BUCKET_BOUND_DOMAIN": + if "urlStyle" in test_data and test_data["urlStyle"] == "BUCKET_BOUND_HOSTNAME": api_access_endpoint = "{scheme}://{bucket_bound_hostname}".format( scheme=test_data["scheme"], - bucket_bound_hostname=test_data["bucketBoundDomain"], + bucket_bound_hostname=test_data["bucketBoundHostname"], ) resource = "/" _run_conformance_test(resource, test_data, api_access_endpoint) @@ -818,10 +818,10 @@ def test_conformance_bucket(test_data): @pytest.mark.parametrize("test_data", _BLOB_TESTS) def test_conformance_blob(test_data): - if "urlStyle" in test_data and test_data["urlStyle"] == "BUCKET_BOUND_DOMAIN": + if "urlStyle" in test_data and test_data["urlStyle"] == "BUCKET_BOUND_HOSTNAME": api_access_endpoint = "{scheme}://{bucket_bound_hostname}".format( scheme=test_data["scheme"], - bucket_bound_hostname=test_data["bucketBoundDomain"], + bucket_bound_hostname=test_data["bucketBoundHostname"], ) resource = "/{}".format(test_data["object"]) _run_conformance_test(resource, test_data, api_access_endpoint) diff --git a/tests/unit/url_signer_v4_test_data.json b/tests/unit/url_signer_v4_test_data.json index 16d15625e..a43fc5cd5 100644 --- a/tests/unit/url_signer_v4_test_data.json +++ b/tests/unit/url_signer_v4_test_data.json @@ -121,7 +121,7 @@ }, { - "description": "HTTP Bucket Bound Domain Support", + "description": "HTTP Bucket Bound Hostname Support", "bucket": "test-bucket", "object": "test-object", "method": "GET", @@ -129,12 +129,12 @@ "timestamp": "20190201T090000Z", "expectedUrl": "http://mydomain.tld/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host&X-Goog-Signature=7115a77f8c7ed1a8b74bca8b520904fca7f3bab90d69ea052687a94efd9b3a4e2a7fb7135d40e295e0a21958194c55da7e106227957c22ed6edc9d8b3d2a8133bc8af84fc9695dda8081d53f0db5ea9f28e5bfc225d78f873e9f571fd287bb7a95330e726aebd8eb4623cdb0b1a7ceb210b2ce1351b6be0191c2ad7b38f7ceb6c5ce2f98dbfb5a5a649050585e46e97f72f1f5407de657a56e34a3fdc80cdaa0598bd47f3e8af5ff22d0916b19b106890bff8c3f6587f1d3b076b16cd0ba0508607a672be33b9c75d537e15258450b43d22a21c4d528090acbb8e5bae7b31fc394e61394106ef1d6a8ed43074ab05bcec65674cd8113fb3de388da4d97e62f56", "scheme": "http", - "urlStyle": "BUCKET_BOUND_DOMAIN", - "bucketBoundDomain": "mydomain.tld" + "urlStyle": "BUCKET_BOUND_HOSTNAME", + "bucketBoundHostname": "mydomain.tld" }, { - "description": "HTTPS Bucket Bound Domain Support", + "description": "HTTPS Bucket Bound Hostname Support", "bucket": "test-bucket", "object": "test-object", "method": "GET", @@ -142,31 +142,31 @@ "timestamp": "20190201T090000Z", "expectedUrl": "https://mydomain.tld/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host&X-Goog-Signature=7115a77f8c7ed1a8b74bca8b520904fca7f3bab90d69ea052687a94efd9b3a4e2a7fb7135d40e295e0a21958194c55da7e106227957c22ed6edc9d8b3d2a8133bc8af84fc9695dda8081d53f0db5ea9f28e5bfc225d78f873e9f571fd287bb7a95330e726aebd8eb4623cdb0b1a7ceb210b2ce1351b6be0191c2ad7b38f7ceb6c5ce2f98dbfb5a5a649050585e46e97f72f1f5407de657a56e34a3fdc80cdaa0598bd47f3e8af5ff22d0916b19b106890bff8c3f6587f1d3b076b16cd0ba0508607a672be33b9c75d537e15258450b43d22a21c4d528090acbb8e5bae7b31fc394e61394106ef1d6a8ed43074ab05bcec65674cd8113fb3de388da4d97e62f56", "scheme": "https", - "urlStyle": "BUCKET_BOUND_DOMAIN", - "bucketBoundDomain": "mydomain.tld" + "urlStyle": "BUCKET_BOUND_HOSTNAME", + "bucketBoundHostname": "mydomain.tld" }, { - "description": "HTTP Bucket Bound Domain Support", + "description": "HTTP Bucket Bound Hostname Support", "bucket": "test-bucket", "method": "GET", "expiration": 10, "timestamp": "20190201T090000Z", "expectedUrl": "http://mydomain.tld/?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host&X-Goog-Signature=7a629a5632f16dba78961250b17c1f0d2ac0d2a28dbd7cbf79088fd6cd0b7f3ec66285cdeccca024f7b8134376f5cdcf0d60f399c6df1f19fcf5cf3be9d7f905d72cb6c0b5600f83dd6a7c8df607510c0e12e36216530a7b832eab87920363c5368a7e610d44005c73324f6ca4b435e8687672f46cc1342419ec4a5264549cb4b77bdc73f4f461edf39fbdd8fda99db440b077e906ef48d2c6b854c11ded58096f293d664650c123c6ec2a0379affd05bf5696ba11d3474623e039d5e05d3dc331b86ff4f7afb9262cf9750ff5944e661e70cc443b28f7e150796dde831d70e205c7e848c19b8281510f1d195e5819176e4868713266d0e0db7a3354857187cf", "scheme": "http", - "urlStyle": "BUCKET_BOUND_DOMAIN", - "bucketBoundDomain": "mydomain.tld" + "urlStyle": "BUCKET_BOUND_HOSTNAME", + "bucketBoundHostname": "mydomain.tld" }, { - "description": "HTTPS Bucket Bound Domain Support", + "description": "HTTPS Bucket Bound Hostname Support", "bucket": "test-bucket", "method": "GET", "expiration": 10, "timestamp": "20190201T090000Z", "expectedUrl": "https://mydomain.tld/?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host&X-Goog-Signature=7a629a5632f16dba78961250b17c1f0d2ac0d2a28dbd7cbf79088fd6cd0b7f3ec66285cdeccca024f7b8134376f5cdcf0d60f399c6df1f19fcf5cf3be9d7f905d72cb6c0b5600f83dd6a7c8df607510c0e12e36216530a7b832eab87920363c5368a7e610d44005c73324f6ca4b435e8687672f46cc1342419ec4a5264549cb4b77bdc73f4f461edf39fbdd8fda99db440b077e906ef48d2c6b854c11ded58096f293d664650c123c6ec2a0379affd05bf5696ba11d3474623e039d5e05d3dc331b86ff4f7afb9262cf9750ff5944e661e70cc443b28f7e150796dde831d70e205c7e848c19b8281510f1d195e5819176e4868713266d0e0db7a3354857187cf", "scheme": "https", - "urlStyle": "BUCKET_BOUND_DOMAIN", - "bucketBoundDomain": "mydomain.tld" + "urlStyle": "BUCKET_BOUND_HOSTNAME", + "bucketBoundHostname": "mydomain.tld" } ]