Content-Length: 598002 | pFad | https://www.github.com/googleapis/python-storage/commit/23df542d0669852b05139023d5ef1ae14a09f4c7

392 feat: generate signed URLs for blobs/buckets using virtual hostname (… · googleapis/python-storage@23df542 · GitHub
Skip to content

Commit 23df542

Browse files
authored
feat: generate signed URLs for blobs/buckets using virtual hostname (#58)
* Add 'virtual_hosted_style' arg to 'Blob.generate_signed_url' * Add 'virtual_hosted_style arg to 'Bucket.generate_signed_url'
1 parent a834d1b commit 23df542

File tree

4 files changed

+61
-9
lines changed

4 files changed

+61
-9
lines changed

google/cloud/storage/blob.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ def generate_signed_url(
361361
version=None,
362362
service_account_email=None,
363363
access_token=None,
364+
virtual_hosted_style=False,
364365
):
365366
"""Generates a signed URL for this blob.
366367
@@ -454,6 +455,11 @@ def generate_signed_url(
454455
:type access_token: str
455456
:param access_token: (Optional) Access token for a service account.
456457
458+
:type virtual_hosted_style: bool
459+
:param virtual_hosted_style:
460+
(Optional) If true, then construct the URL relative the bucket's
461+
virtual hostname, e.g., '<bucket-name>.storage.googleapis.com'.
462+
457463
:raises: :exc:`ValueError` when version is invalid.
458464
:raises: :exc:`TypeError` when expiration is not a valid type.
459465
:raises: :exc:`AttributeError` if credentials is not an instance
@@ -469,9 +475,16 @@ def generate_signed_url(
469475
raise ValueError("'version' must be either 'v2' or 'v4'")
470476

471477
quoted_name = _quote(self.name, safe=b"/~")
472-
resource = "/{bucket_name}/{quoted_name}".format(
473-
bucket_name=self.bucket.name, quoted_name=quoted_name
474-
)
478+
479+
if virtual_hosted_style:
480+
api_access_endpoint = "https://{bucket_name}.storage.googleapis.com".format(
481+
bucket_name=self.bucket.name
482+
)
483+
resource = "/{quoted_name}".format(quoted_name=quoted_name)
484+
else:
485+
resource = "/{bucket_name}/{quoted_name}".format(
486+
bucket_name=self.bucket.name, quoted_name=quoted_name
487+
)
475488

476489
if credentials is None:
477490
client = self._require_client(client)

google/cloud/storage/bucket.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2354,6 +2354,7 @@ def generate_signed_url(
23542354
client=None,
23552355
credentials=None,
23562356
version=None,
2357+
virtual_hosted_style=False,
23572358
):
23582359
"""Generates a signed URL for this bucket.
23592360
@@ -2416,6 +2417,11 @@ def generate_signed_url(
24162417
:param version: (Optional) The version of signed credential to create.
24172418
Must be one of 'v2' | 'v4'.
24182419
2420+
:type virtual_hosted_style: bool
2421+
:param virtual_hosted_style:
2422+
(Optional) If true, then construct the URL relative the bucket's
2423+
virtual hostname, e.g., '<bucket-name>.storage.googleapis.com'.
2424+
24192425
:raises: :exc:`ValueError` when version is invalid.
24202426
:raises: :exc:`TypeError` when expiration is not a valid type.
24212427
:raises: :exc:`AttributeError` if credentials is not an instance
@@ -2430,7 +2436,13 @@ def generate_signed_url(
24302436
elif version not in ("v2", "v4"):
24312437
raise ValueError("'version' must be either 'v2' or 'v4'")
24322438

2433-
resource = "/{bucket_name}".format(bucket_name=self.name)
2439+
if virtual_hosted_style:
2440+
api_access_endpoint = "https://{bucket_name}.storage.googleapis.com".format(
2441+
bucket_name=self.name
2442+
)
2443+
resource = "/"
2444+
else:
2445+
resource = "/{bucket_name}".format(bucket_name=self.name)
24342446

24352447
if credentials is None:
24362448
client = self._require_client(client)

tests/unit/test_blob.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,7 @@ def _generate_signed_url_helper(
399399
encryption_key=None,
400400
access_token=None,
401401
service_account_email=None,
402+
virtual_hosted_style=False,
402403
):
403404
from six.moves.urllib import parse
404405
from google.cloud._helpers import UTC
@@ -442,6 +443,7 @@ def _generate_signed_url_helper(
442443
version=version,
443444
access_token=access_token,
444445
service_account_email=service_account_email,
446+
virtual_hosted_style=virtual_hosted_style,
445447
)
446448

447449
self.assertEqual(signed_uri, signer.return_value)
@@ -452,7 +454,17 @@ def _generate_signed_url_helper(
452454
expected_creds = credentials
453455

454456
encoded_name = blob_name.encode("utf-8")
455-
expected_resource = "/name/{}".format(parse.quote(encoded_name, safe=b"/~"))
457+
quoted_name = parse.quote(encoded_name, safe=b"/~")
458+
459+
if virtual_hosted_style:
460+
expected_api_access_endpoint = "https://{}.storage.googleapis.com".format(
461+
bucket.name
462+
)
463+
expected_resource = "/{}".format(quoted_name)
464+
else:
465+
expected_api_access_endpoint = api_access_endpoint
466+
expected_resource = "/{}/{}".format(bucket.name, quoted_name)
467+
456468
if encryption_key is not None:
457469
expected_headers = headers or {}
458470
if effective_version == "v2":
@@ -465,7 +477,7 @@ def _generate_signed_url_helper(
465477
expected_kwargs = {
466478
"resource": expected_resource,
467479
"expiration": expiration,
468-
"api_access_endpoint": api_access_endpoint,
480+
"api_access_endpoint": expected_api_access_endpoint,
469481
"method": method.upper(),
470482
"content_md5": content_md5,
471483
"content_type": content_type,
@@ -604,6 +616,9 @@ def test_generate_signed_url_v4_w_csek_and_headers(self):
604616
encryption_key=os.urandom(32), headers={"x-goog-foo": "bar"}
605617
)
606618

619+
def test_generate_signed_url_v4_w_virtual_hostname(self):
620+
self._generate_signed_url_v4_helper(virtual_hosted_style=True)
621+
607622
def test_generate_signed_url_v4_w_credentials(self):
608623
credentials = object()
609624
self._generate_signed_url_v4_helper(credentials=credentials)

tests/unit/test_bucket.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2739,6 +2739,7 @@ def _generate_signed_url_helper(
27392739
query_parameters=None,
27402740
credentials=None,
27412741
expiration=None,
2742+
virtual_hosted_style=False,
27422743
):
27432744
from six.moves.urllib import parse
27442745
from google.cloud._helpers import UTC
@@ -2773,6 +2774,7 @@ def _generate_signed_url_helper(
27732774
headers=headers,
27742775
query_parameters=query_parameters,
27752776
version=version,
2777+
virtual_hosted_style=virtual_hosted_style,
27762778
)
27772779

27782780
self.assertEqual(signed_uri, signer.return_value)
@@ -2782,12 +2784,19 @@ def _generate_signed_url_helper(
27822784
else:
27832785
expected_creds = credentials
27842786

2785-
encoded_name = bucket_name.encode("utf-8")
2786-
expected_resource = "/{}".format(parse.quote(encoded_name))
2787+
if virtual_hosted_style:
2788+
expected_api_access_endpoint = "https://{}.storage.googleapis.com".format(
2789+
bucket_name
2790+
)
2791+
expected_resource = "/"
2792+
else:
2793+
expected_api_access_endpoint = api_access_endpoint
2794+
expected_resource = "/{}".format(parse.quote(bucket_name))
2795+
27872796
expected_kwargs = {
27882797
"resource": expected_resource,
27892798
"expiration": expiration,
2790-
"api_access_endpoint": api_access_endpoint,
2799+
"api_access_endpoint": expected_api_access_endpoint,
27912800
"method": method.upper(),
27922801
"headers": headers,
27932802
"query_parameters": query_parameters,
@@ -2916,6 +2925,9 @@ def test_generate_signed_url_v4_w_credentials(self):
29162925
credentials = object()
29172926
self._generate_signed_url_v4_helper(credentials=credentials)
29182927

2928+
def test_generate_signed_url_v4_w_virtual_hostname(self):
2929+
self._generate_signed_url_v4_helper(virtual_hosted_style=True)
2930+
29192931

29202932
class _Connection(object):
29212933
_delete_bucket = False

0 commit comments

Comments
 (0)








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: https://www.github.com/googleapis/python-storage/commit/23df542d0669852b05139023d5ef1ae14a09f4c7

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy