From 278f52b1d072d4657ce38f6f11488e1f4c6f22c1 Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Fri, 16 Jun 2017 01:34:04 -0700 Subject: [PATCH] For GCS the size limit of S3 is not useful. This change allows for the GCS server to reject if needed. For size == -1 we just use `Transfer-Encoding: chunked` For size >= 0 we just use regular upload operation. Related to https://github.com/restic/restic/issues/996 --- api-put-object-file.go | 11 +---------- api-put-object-progress.go | 14 +------------- api-put-object.go | 15 +++++---------- api.go | 8 +++++--- 4 files changed, 12 insertions(+), 36 deletions(-) diff --git a/api-put-object-file.go b/api-put-object-file.go index fc475c9a3..eafa302fc 100644 --- a/api-put-object-file.go +++ b/api-put-object-file.go @@ -77,17 +77,8 @@ func (c Client) FPutObject(bucketName, objectName, filePath, contentType string) objMetadata["Content-Type"] = []string{contentType} // NOTE: Google Cloud Storage multipart Put is not compatible with Amazon S3 APIs. - // Current implementation will only upload a maximum of 5GiB to Google Cloud Storage servers. if s3utils.IsGoogleEndpoint(c.endpointURL) { - if fileSize > int64(maxSinglePutObjectSize) { - return 0, ErrorResponse{ - Code: "NotImplemented", - Message: fmt.Sprintf("Invalid Content-Length %d for file uploads to Google Cloud Storage.", fileSize), - Key: objectName, - BucketName: bucketName, - } - } - // Do not compute MD5 for Google Cloud Storage. Uploads up to 5GiB in size. + // Do not compute MD5 for Google Cloud Storage. return c.putObjectNoChecksum(bucketName, objectName, fileReader, fileSize, objMetadata, nil) } diff --git a/api-put-object-progress.go b/api-put-object-progress.go index e5b24ad2a..abf5b75d5 100644 --- a/api-put-object-progress.go +++ b/api-put-object-progress.go @@ -83,20 +83,8 @@ func (c Client) PutObjectWithMetadata(bucketName, objectName string, reader io.R } // NOTE: Google Cloud Storage does not implement Amazon S3 Compatible multipart PUT. - // So we fall back to single PUT operation with the maximum limit of 5GiB. if s3utils.IsGoogleEndpoint(c.endpointURL) { - if size <= -1 { - return 0, ErrorResponse{ - Code: "NotImplemented", - Message: "Content-Length cannot be negative for file uploads to Google Cloud Storage.", - Key: objectName, - BucketName: bucketName, - } - } - if size > maxSinglePutObjectSize { - return 0, ErrEntityTooLarge(size, maxSinglePutObjectSize, bucketName, objectName) - } - // Do not compute MD5 for Google Cloud Storage. Uploads up to 5GiB in size. + // Do not compute MD5 for Google Cloud Storage. return c.putObjectNoChecksum(bucketName, objectName, reader, size, metaData, progress) } diff --git a/api-put-object.go b/api-put-object.go index e61f305cb..1668768e1 100644 --- a/api-put-object.go +++ b/api-put-object.go @@ -166,8 +166,11 @@ func (c Client) putObjectNoChecksum(bucketName, objectName string, reader io.Rea if err := isValidObjectName(objectName); err != nil { return 0, err } - if size > maxSinglePutObjectSize { - return 0, ErrEntityTooLarge(size, maxSinglePutObjectSize, bucketName, objectName) + if size > 0 { + readerAt, ok := reader.(io.ReaderAt) + if ok { + reader = io.NewSectionReader(readerAt, 0, size) + } } // Update progress reader appropriately to the latest offset as we @@ -260,14 +263,6 @@ func (c Client) putObjectDo(bucketName, objectName string, reader io.Reader, md5 return ObjectInfo{}, err } - if size <= -1 { - return ObjectInfo{}, ErrEntityTooSmall(size, bucketName, objectName) - } - - if size > maxSinglePutObjectSize { - return ObjectInfo{}, ErrEntityTooLarge(size, maxSinglePutObjectSize, bucketName, objectName) - } - // Set headers. customHeader := make(http.Header) diff --git a/api.go b/api.go index 0e89cfa55..f9bfe7ccc 100644 --- a/api.go +++ b/api.go @@ -632,9 +632,11 @@ func (c Client) newRequest(method string, metadata requestMetadata) (req *http.R req.Header.Set(k, v[0]) } - // set incoming content-length. - if metadata.contentLength > 0 { - req.ContentLength = metadata.contentLength + // Set incoming content-length. + req.ContentLength = metadata.contentLength + if req.ContentLength <= -1 { + // For unknown content length, we upload using transfer-encoding: chunked. + req.TransferEncoding = []string{"chunked"} } // set md5Sum for content protection.