Skip to content

Commit e175c86

Browse files
committed
s3: split the GCS quirks into -s3-use-x-id and -s3-sign-accept-encoding rclone#8373
Before this we applied both these quirks if provider == "GCS". Splitting them like this makes them applicable for other providers such as ActiveScale.
1 parent 64cd8ae commit e175c86

File tree

1 file changed

+81
-25
lines changed

1 file changed

+81
-25
lines changed

backend/s3/s3.go

Lines changed: 81 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2680,6 +2680,34 @@ knows about - please make a bug report if not.
26802680
You can change this if you want to disable the use of multipart uploads.
26812681
This shouldn't be necessary in normal operation.
26822682
2683+
This should be automatically set correctly for all providers rclone
2684+
knows about - please make a bug report if not.
2685+
`,
2686+
Default: fs.Tristate{},
2687+
Advanced: true,
2688+
}, {
2689+
Name: "use_x_id",
2690+
Help: `Set if rclone should add x-id URL parameters.
2691+
2692+
You can change this if you want to disable the AWS SDK from
2693+
adding x-id URL parameters.
2694+
2695+
This shouldn't be necessary in normal operation.
2696+
2697+
This should be automatically set correctly for all providers rclone
2698+
knows about - please make a bug report if not.
2699+
`,
2700+
Default: fs.Tristate{},
2701+
Advanced: true,
2702+
}, {
2703+
Name: "sign_accept_encoding",
2704+
Help: `Set if rclone should include Accept-Encoding as part of the signature.
2705+
2706+
You can change this if you want to stop rclone including
2707+
Accept-Encoding as part of the signature.
2708+
2709+
This shouldn't be necessary in normal operation.
2710+
26832711
This should be automatically set correctly for all providers rclone
26842712
knows about - please make a bug report if not.
26852713
`,
@@ -2901,6 +2929,8 @@ type Options struct {
29012929
DirectoryBucket bool `config:"directory_bucket"`
29022930
IBMAPIKey string `config:"ibm_api_key"`
29032931
IBMInstanceID string `config:"ibm_resource_instance_id"`
2932+
UseXID fs.Tristate `config:"use_x_id"`
2933+
SignAcceptEncoding fs.Tristate `config:"sign_accept_encoding"`
29042934
}
29052935

29062936
// Fs represents a remote s3 server
@@ -3085,59 +3115,67 @@ func getClient(ctx context.Context, opt *Options) *http.Client {
30853115
}
30863116
}
30873117

3118+
// Fixup the request if needed.
3119+
//
30883120
// Google Cloud Storage alters the Accept-Encoding header, which
3089-
// breaks the v2 request signature
3121+
// breaks the v2 request signature. This is set with opt.SignAcceptEncoding.
30903122
//
30913123
// It also doesn't like the x-id URL parameter SDKv2 puts in so we
3092-
// remove that too.
3124+
// remove that too. This is set with opt.UseXID.Value.
30933125
//
30943126
// See https://github.com/aws/aws-sdk-go-v2/issues/1816.
30953127
// Adapted from: https://github.com/aws/aws-sdk-go-v2/issues/1816#issuecomment-1927281540
3096-
func fixupGCS(o *s3.Options) {
3128+
func fixupRequest(o *s3.Options, opt *Options) {
30973129
type ignoredHeadersKey struct{}
30983130
headers := []string{"Accept-Encoding"}
30993131

31003132
fixup := middleware.FinalizeMiddlewareFunc(
3101-
"FixupGCS",
3133+
"FixupRequest",
31023134
func(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) (out middleware.FinalizeOutput, metadata middleware.Metadata, err error) {
31033135
req, ok := in.Request.(*smithyhttp.Request)
31043136
if !ok {
3105-
return out, metadata, fmt.Errorf("fixupGCS: unexpected request middleware type %T", in.Request)
3137+
return out, metadata, fmt.Errorf("fixupRequest: unexpected request middleware type %T", in.Request)
31063138
}
31073139

3108-
// Delete headers from being signed - will restore later
3109-
ignored := make(map[string]string, len(headers))
3110-
for _, h := range headers {
3111-
ignored[h] = req.Header.Get(h)
3112-
req.Header.Del(h)
3113-
}
3140+
if !opt.SignAcceptEncoding.Value {
3141+
// Delete headers from being signed - will restore later
3142+
ignored := make(map[string]string, len(headers))
3143+
for _, h := range headers {
3144+
ignored[h] = req.Header.Get(h)
3145+
req.Header.Del(h)
3146+
}
31143147

3115-
// Remove x-id because Google doesn't like them
3116-
if query := req.URL.Query(); query.Has("x-id") {
3117-
query.Del("x-id")
3118-
req.URL.RawQuery = query.Encode()
3148+
// Store ignored on context
3149+
ctx = middleware.WithStackValue(ctx, ignoredHeadersKey{}, ignored)
31193150
}
31203151

3121-
// Store ignored on context
3122-
ctx = middleware.WithStackValue(ctx, ignoredHeadersKey{}, ignored)
3152+
if !opt.UseXID.Value {
3153+
// Remove x-id
3154+
if query := req.URL.Query(); query.Has("x-id") {
3155+
query.Del("x-id")
3156+
req.URL.RawQuery = query.Encode()
3157+
}
3158+
}
31233159

31243160
return next.HandleFinalize(ctx, in)
31253161
},
31263162
)
31273163

31283164
// Restore headers if necessary
31293165
restore := middleware.FinalizeMiddlewareFunc(
3130-
"FixupGCSRestoreHeaders",
3166+
"FixupRequestRestoreHeaders",
31313167
func(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) (out middleware.FinalizeOutput, metadata middleware.Metadata, err error) {
31323168
req, ok := in.Request.(*smithyhttp.Request)
31333169
if !ok {
3134-
return out, metadata, fmt.Errorf("fixupGCS: unexpected request middleware type %T", in.Request)
3170+
return out, metadata, fmt.Errorf("fixupRequest: unexpected request middleware type %T", in.Request)
31353171
}
31363172

3137-
// Restore ignored from ctx
3138-
ignored, _ := middleware.GetStackValue(ctx, ignoredHeadersKey{}).(map[string]string)
3139-
for k, v := range ignored {
3140-
req.Header.Set(k, v)
3173+
if !opt.SignAcceptEncoding.Value {
3174+
// Restore ignored from ctx
3175+
ignored, _ := middleware.GetStackValue(ctx, ignoredHeadersKey{}).(map[string]string)
3176+
for k, v := range ignored {
3177+
req.Header.Set(k, v)
3178+
}
31413179
}
31423180

31433181
return next.HandleFinalize(ctx, in)
@@ -3267,9 +3305,10 @@ func s3Connection(ctx context.Context, opt *Options, client *http.Client) (s3Cli
32673305
}
32683306
}
32693307

3270-
if opt.Provider == "GCS" {
3308+
// Fixup the request if needed
3309+
if !opt.UseXID.Value || !opt.SignAcceptEncoding.Value {
32713310
options = append(options, func(o *s3.Options) {
3272-
fixupGCS(o)
3311+
fixupRequest(o, opt)
32733312
})
32743313
}
32753314

@@ -3384,6 +3423,8 @@ func setQuirks(opt *Options) {
33843423
useAlreadyExists = true // Set if provider returns AlreadyOwnedByYou or no error if you try to remake your own bucket
33853424
useMultipartUploads = true // Set if provider supports multipart uploads
33863425
useUnsignedPayload = true // Do we need to use unsigned payloads to avoid seeking in PutObject
3426+
useXID = true // Add x-id URL parameter into requests
3427+
signAcceptEncoding = true // If we should include AcceptEncoding in the signature
33873428
)
33883429
switch opt.Provider {
33893430
case "AWS":
@@ -3528,11 +3569,14 @@ func setQuirks(opt *Options) {
35283569
// Google break request Signature by mutating accept-encoding HTTP header
35293570
// https://github.com/rclone/rclone/issues/6670
35303571
useAcceptEncodingGzip = false
3572+
signAcceptEncoding = false
35313573
useAlreadyExists = true // returns BucketNameUnavailable instead of BucketAlreadyExists but good enough!
35323574
// GCS S3 doesn't support multi-part server side copy:
35333575
// See: https://issuetracker.google.com/issues/323465186
35343576
// So make cutoff very large which it does seem to support
35353577
opt.CopyCutoff = math.MaxInt64
3578+
// GCS doesn't like the x-id URL parameter the SDKv2 inserts
3579+
useXID = false
35363580
default: //nolint:gocritic // Don't include gocritic when running golangci-lint to avoid defaultCaseOrder: consider to make `default` case as first or as last case
35373581
fs.Logf("s3", "s3 provider %q not known - please set correctly", opt.Provider)
35383582
fallthrough
@@ -3602,6 +3646,18 @@ func setQuirks(opt *Options) {
36023646
opt.UseUnsignedPayload.Valid = true
36033647
opt.UseUnsignedPayload.Value = useUnsignedPayload
36043648
}
3649+
3650+
// Set the correct use UseXID if not manually set
3651+
if !opt.UseXID.Valid {
3652+
opt.UseXID.Valid = true
3653+
opt.UseXID.Value = useXID
3654+
}
3655+
3656+
// Set the correct SignAcceptEncoding if not manually set
3657+
if !opt.SignAcceptEncoding.Valid {
3658+
opt.SignAcceptEncoding.Valid = true
3659+
opt.SignAcceptEncoding.Value = signAcceptEncoding
3660+
}
36053661
}
36063662

36073663
// setRoot changes the root of the Fs

0 commit comments

Comments
 (0)