It took some digging, but I came up with the following that does the right thing. Some official documentation on how to do this would be nice, especially because the endpoint for actually starting a renewable download is different from what the documents call. What comes from using the gsutil tool to sign requests and then to develop what is being done. The insufficiently documented additional information is that the code that POST for this URL to get the renewable session URL must include the header "x-goog-resumable: start" to start the download. From there, everything is the same as the documents for performing renewable downloads in GCS.
import base64 import datetime import time import urllib from google.appengine.api import app_identity SIGNED_URL_EXPIRATION = datetime.timedelta(days=7) def SignResumableUploadUrl(gcs_resource_path): """Generates a signed resumable upload URL. Note that documentation on this ability is sketchy. The canonical source is derived from running the gsutil program to generate a RESUMABLE URL with the "-m RESUMABLE" argument. Run "gsutil help signurl" for info and the following for an example: gsutil -m RESUMABLE -d 10m keyfile gs://bucket/file/name Note that this generates a URL different from the standard mechanism for deriving a resumable start URL and the initiator needs to add the header: x-goog-resumable:start Args: gcs_resource_path: The path of the GCS resource, including bucket name. Returns: A full signed URL. """ method = "POST" expiration = datetime.datetime.utcnow() + SIGNED_URL_EXPIRATION expiration = int(time.mktime(expiration.timetuple())) signature_string = "\n".join([ method, "", # content md5 "", # content type str(expiration), "x-goog-resumable:start", gcs_resource_path ]) _, signature_bytes = app_identity.sign_blob(signature_string) signature = base64.b64encode(signature_bytes) query_params = { "GoogleAccessId": app_identity.get_service_account_name(), "Expires": str(expiration), "Signature": signature, } return "{endpoint}{resource}?{querystring}".format( endpoint="https://storage.googleapis.com", resource=gcs_resource_path, querystring=urllib.urlencode(query_params))
source share