From afde340c9e2e24af578e6ecd28d4779218e6be6a Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Sat, 2 May 2020 09:15:28 +0100 Subject: [PATCH] gcs: fix --header-upload - #59 Before this code we were settig the headers on the PUT request. However this isn't where GCS needs them. After this fix we set the headers in the object upload request itself. This means that we only support a limited range of headers - Cache-Control - Content-Disposition - Content-Encoding - Content-Language - Content-Type - X-Goog-Meta- Note for the last of those are for setting custom metadata in the form "X-Goog-Meta-Key: value". --- .../googlecloudstorage/googlecloudstorage.go | 28 ++++++++++++++++++- docs/content/googlecloudstorage.md | 18 ++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/backend/googlecloudstorage/googlecloudstorage.go b/backend/googlecloudstorage/googlecloudstorage.go index d0afe9244..acafc955a 100644 --- a/backend/googlecloudstorage/googlecloudstorage.go +++ b/backend/googlecloudstorage/googlecloudstorage.go @@ -1066,13 +1066,39 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op ContentType: fs.MimeType(ctx, src), Metadata: metadataFromModTime(modTime), } + // Apply upload options + for _, option := range options { + key, value := option.Header() + lowerKey := strings.ToLower(key) + switch lowerKey { + case "": + // ignore + case "cache-control": + object.CacheControl = value + case "content-disposition": + object.ContentDisposition = value + case "content-encoding": + object.ContentEncoding = value + case "content-language": + object.ContentLanguage = value + case "content-type": + object.ContentType = value + default: + const googMetaPrefix = "x-goog-meta-" + if strings.HasPrefix(lowerKey, googMetaPrefix) { + metaKey := lowerKey[len(googMetaPrefix):] + object.Metadata[metaKey] = value + } else { + fs.Errorf(o, "Don't know how to set key %q on upload", key) + } + } + } var newObject *storage.Object err = o.fs.pacer.CallNoRetry(func() (bool, error) { insertObject := o.fs.svc.Objects.Insert(bucket, &object).Media(in, googleapi.ContentType("")).Name(object.Name) if !o.fs.opt.BucketPolicyOnly { insertObject.PredefinedAcl(o.fs.opt.ObjectACL) } - fs.OpenOptionAddHTTPHeaders(insertObject.Header(), options) newObject, err = insertObject.Context(ctx).Do() return shouldRetry(err) }) diff --git a/docs/content/googlecloudstorage.md b/docs/content/googlecloudstorage.md index ea58ead93..4f04e5a59 100644 --- a/docs/content/googlecloudstorage.md +++ b/docs/content/googlecloudstorage.md @@ -215,6 +215,24 @@ This remote supports `--fast-list` which allows you to use fewer transactions in exchange for more memory. See the [rclone docs](/docs/#fast-list) for more details. +### Custom upload headers ### + +You can set custom upload headers with the `--header-upload` +flag. Google Cloud Storage supports the headers as described in the +[working with metadata documentation](https://cloud.google.com/storage/docs/gsutil/addlhelp/WorkingWithObjectMetadata) + +- Cache-Control +- Content-Disposition +- Content-Encoding +- Content-Language +- Content-Type +- X-Goog-Meta- + +Eg `--header-upload "Content-Type text/potato"` + +Note that the last of these is for setting custom metadata in the form +`--header-upload "x-goog-meta-key: value"` + ### Modified time ### Google google cloud storage stores md5sums natively and rclone stores