Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit b4b6816

Browse filesBrowse files
authored
feat(storage): Add snippets for v4 signed URLs (GoogleCloudPlatform#2142)
* feat(storage): Add snippets for v4 signed URLs * lint * fix .format() * add v4 command to switch statement * fix region tag * change if => elif to try to make func less complex * move main to a function
1 parent b50ebac commit b4b6816
Copy full SHA for b4b6816

File tree

Expand file treeCollapse file tree

3 files changed

+103
-7
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+103
-7
lines changed

‎storage/cloud-client/requirements.txt

Copy file name to clipboard
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
google-cloud-pubsub==0.39.1
2-
google-cloud-storage==1.14.0
2+
google-cloud-storage==1.15.0

‎storage/cloud-client/snippets.py

Copy file name to clipboardExpand all lines: storage/cloud-client/snippets.py
+78-6Lines changed: 78 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ def make_blob_public(bucket_name, blob_name):
249249

250250

251251
def generate_signed_url(bucket_name, blob_name):
252-
"""Generates a signed URL for a blob.
252+
"""Generates a v2 signed URL for downloading a blob.
253253
254254
Note that this method requires a service account key file. You can not use
255255
this if you are using Application Default Credentials from Google Compute
@@ -269,6 +269,62 @@ def generate_signed_url(bucket_name, blob_name):
269269
return url
270270

271271

272+
# [START storage_generate_signed_url_v4]
273+
def generate_download_signed_url_v4(bucket_name, blob_name):
274+
"""Generates a v4 signed URL for downloading a blob.
275+
276+
Note that this method requires a service account key file. You can not use
277+
this if you are using Application Default Credentials from Google Compute
278+
Engine or from the Google Cloud SDK.
279+
"""
280+
storage_client = storage.Client()
281+
bucket = storage_client.get_bucket(bucket_name)
282+
blob = bucket.blob(blob_name)
283+
284+
url = blob.generate_signed_url(
285+
version='v4',
286+
# This URL is valid for 15 minutes
287+
expiration=datetime.timedelta(minutes=15),
288+
# Allow GET requests using this URL.
289+
method='GET')
290+
291+
print('Generated GET signed URL:')
292+
print(url)
293+
print('You can use this URL with any user agent, for example:')
294+
print('curl \'{}\''.format(url))
295+
return url
296+
# [END storage_generate_signed_url_v4]
297+
298+
299+
# [START storage_generate_upload_signed_url_v4]
300+
def generate_upload_signed_url_v4(bucket_name, blob_name):
301+
"""Generates a v4 signed URL for uploading a blob using HTTP PUT.
302+
303+
Note that this method requires a service account key file. You can not use
304+
this if you are using Application Default Credentials from Google Compute
305+
Engine or from the Google Cloud SDK.
306+
"""
307+
storage_client = storage.Client()
308+
bucket = storage_client.get_bucket(bucket_name)
309+
blob = bucket.blob(blob_name)
310+
311+
url = blob.generate_signed_url(
312+
version='v4',
313+
# This URL is valid for 15 minutes
314+
expiration=datetime.timedelta(minutes=15),
315+
# Allow GET requests using this URL.
316+
method='PUT',
317+
content_type='application/octet-stream')
318+
319+
print('Generated PUT signed URL:')
320+
print(url)
321+
print('You can use this URL with any user agent, for example:')
322+
print("curl -X PUT -H 'Content-Type: application/octet-stream' "
323+
"--upload-file my-file '{}'".format(url))
324+
return url
325+
# [END storage_generate_upload_signed_url_v4]
326+
327+
272328
def rename_blob(bucket_name, blob_name, new_name):
273329
"""Renames a blob."""
274330
storage_client = storage.Client()
@@ -296,7 +352,7 @@ def copy_blob(bucket_name, blob_name, new_bucket_name, new_blob_name):
296352
destination_bucket.name))
297353

298354

299-
if __name__ == '__main__':
355+
def main():
300356
parser = argparse.ArgumentParser(
301357
description=__doc__,
302358
formatter_class=argparse.RawDescriptionHelpFormatter)
@@ -350,6 +406,14 @@ def copy_blob(bucket_name, blob_name, new_bucket_name, new_blob_name):
350406
'signed-url', help=generate_signed_url.__doc__)
351407
signed_url_parser.add_argument('blob_name')
352408

409+
signed_url_download_v4_parser = subparsers.add_parser(
410+
'signed-url-download-v4', help=generate_download_signed_url_v4.__doc__)
411+
signed_url_download_v4_parser.add_argument('blob_name')
412+
413+
signed_url_upload_v4_parser = subparsers.add_parser(
414+
'signed-url-upload-v4', help=generate_upload_signed_url_v4.__doc__)
415+
signed_url_upload_v4_parser.add_argument('blob_name')
416+
353417
rename_parser = subparsers.add_parser('rename', help=rename_blob.__doc__)
354418
rename_parser.add_argument('blob_name')
355419
rename_parser.add_argument('new_name')
@@ -363,15 +427,15 @@ def copy_blob(bucket_name, blob_name, new_bucket_name, new_blob_name):
363427

364428
if args.command == 'create-bucket':
365429
create_bucket(args.bucket_name)
366-
if args.command == 'enable-default-kms-key':
430+
elif args.command == 'enable-default-kms-key':
367431
enable_default_kms_key(args.bucket_name, args.kms_key_name)
368432
elif args.command == 'delete-bucket':
369433
delete_bucket(args.bucket_name)
370-
if args.command == 'get-bucket-labels':
434+
elif args.command == 'get-bucket-labels':
371435
get_bucket_labels(args.bucket_name)
372-
if args.command == 'add-bucket-label':
436+
elif args.command == 'add-bucket-label':
373437
add_bucket_label(args.bucket_name)
374-
if args.command == 'remove-bucket-label':
438+
elif args.command == 'remove-bucket-label':
375439
remove_bucket_label(args.bucket_name)
376440
elif args.command == 'list':
377441
list_blobs(args.bucket_name)
@@ -401,6 +465,10 @@ def copy_blob(bucket_name, blob_name, new_bucket_name, new_blob_name):
401465
make_blob_public(args.bucket_name, args.blob_name)
402466
elif args.command == 'signed-url':
403467
generate_signed_url(args.bucket_name, args.blob_name)
468+
elif args.command == 'signed-url-download-v4':
469+
generate_download_signed_url_v4(args.bucket_name, args.blob_name)
470+
elif args.command == 'signed-url-upload-v4':
471+
generate_upload_signed_url_v4(args.bucket_name, args.blob_name)
404472
elif args.command == 'rename':
405473
rename_blob(args.bucket_name, args.blob_name, args.new_name)
406474
elif args.command == 'copy':
@@ -409,3 +477,7 @@ def copy_blob(bucket_name, blob_name, new_bucket_name, new_blob_name):
409477
args.blob_name,
410478
args.new_bucket_name,
411479
args.new_blob_name)
480+
481+
482+
if __name__ == '__main__':
483+
main()

‎storage/cloud-client/snippets_test.py

Copy file name to clipboardExpand all lines: storage/cloud-client/snippets_test.py
+24Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,30 @@ def test_generate_signed_url(test_blob, capsys):
145145
assert r.text == 'Hello, is it me you\'re looking for?'
146146

147147

148+
def test_generate_download_signed_url_v4(test_blob, capsys):
149+
url = snippets.generate_download_signed_url_v4(
150+
BUCKET,
151+
test_blob.name)
152+
153+
r = requests.get(url)
154+
assert r.text == 'Hello, is it me you\'re looking for?'
155+
156+
157+
def test_generate_upload_signed_url_v4(capsys):
158+
blob_name = 'storage_snippets_test_upload'
159+
content = b'Uploaded via v4 signed url'
160+
url = snippets.generate_upload_signed_url_v4(
161+
BUCKET,
162+
blob_name)
163+
164+
requests.put(url, data=content, headers={
165+
'content-type': 'application/octet-stream'})
166+
167+
bucket = storage.Client().bucket(BUCKET)
168+
blob = bucket.blob(blob_name)
169+
assert blob.download_as_string() == content
170+
171+
148172
def test_rename_blob(test_blob):
149173
bucket = storage.Client().bucket(BUCKET)
150174

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.