From 6e130ca83bafff748a3f0f8dfe21422591993209 Mon Sep 17 00:00:00 2001 From: Mike Lang Date: Sun, 28 May 2023 02:07:35 +1000 Subject: [PATCH] multipart uploads: Hack to support gsutil cp (#1182) * multipart uploads: Hack to support gsutil cp `gsutil` sends an invalid multipart boundary param, which golang's `mime.ParseMediaType` correctly rejects. However, the real GCS evidently does not reject this, so in order to make `gsutil` work we need to support it. In particular, `gsutil` sends a boundary param that is quoted using single-quotes when it should be using double-quotes. In cases where the param is definitely invalid (so we're guarenteed not to break any valid values), we replace all single-quotes with double-quotes to produce the intended meaning. Upstream bug: https://github.com/GoogleCloudPlatform/gsutil/issues/1466 * Use ` to avoid having to escape --------- Co-authored-by: fsouza <108725+fsouza@users.noreply.github.com> --- fakestorage/upload.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/fakestorage/upload.go b/fakestorage/upload.go index 4b3d8593f9..d0399a550b 100644 --- a/fakestorage/upload.go +++ b/fakestorage/upload.go @@ -306,7 +306,18 @@ func getObjectACL(predefinedACL string) []storage.ACLRule { func (s *Server) multipartUpload(bucketName string, r *http.Request) jsonResponse { defer r.Body.Close() - _, params, err := mime.ParseMediaType(r.Header.Get(contentTypeHeader)) + requestContentType := r.Header.Get(contentTypeHeader) + // gsutil is observed to submit incorrectly-quoted bounary strings + // like: boundary='===============5900997287163282353==' + // See https://github.com/GoogleCloudPlatform/gsutil/issues/1466 + // Having an "=" character in the boundary param requires the value be quoted, + // but ' is not a quote char, " is. + // If we see a string like "boundary='=", which is always invalid anyway, + // attempt to rescue the situation by converting all ' to ". + if strings.Contains(requestContentType, "boundary='=") { + requestContentType = strings.ReplaceAll(requestContentType, "'", `"`) + } + _, params, err := mime.ParseMediaType(requestContentType) if err != nil { return jsonResponse{ status: http.StatusBadRequest,