From 0c6a6dc380bc5b37ea02b9003857968b2c4eacdd Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Fri, 8 Jan 2016 00:40:06 -0800 Subject: [PATCH] http: Enable Transfer-Encoding chunked transfer Fixes #1020 --- api-headers.go | 18 +++++++++--------- api-response.go | 18 ++++++++++++------ appveyor.yml | 3 --- bucket-handlers.go | 44 ++++++++++++++++++++++---------------------- object-handlers.go | 24 ++++++++++++------------ 5 files changed, 55 insertions(+), 52 deletions(-) diff --git a/api-headers.go b/api-headers.go index 295a49b85..032158063 100644 --- a/api-headers.go +++ b/api-headers.go @@ -32,7 +32,7 @@ import ( // Static alphaNumeric table used for generating unique request ids var alphaNumericTable = []byte("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") -// generateRequestID generate request id +// generateRequestID - Generate request id func generateRequestID() []byte { alpha := make([]byte, 16) rand.Read(alpha) @@ -43,14 +43,11 @@ func generateRequestID() []byte { } // Write http common headers -func setCommonHeaders(w http.ResponseWriter, contentLength int) { - // set unique request ID for each reply +func setCommonHeaders(w http.ResponseWriter) { + // Set unique request ID for each reply. w.Header().Set("X-Amz-Request-Id", string(generateRequestID())) w.Header().Set("Server", ("Minio/" + minioReleaseTag + " (" + runtime.GOOS + "; " + runtime.GOARCH + ")")) w.Header().Set("Accept-Ranges", "bytes") - w.Header().Set("Connection", "close") - // should be set to '0' by default - w.Header().Set("Content-Length", strconv.Itoa(contentLength)) } // Write error response headers @@ -68,12 +65,15 @@ func setObjectHeaders(w http.ResponseWriter, metadata fs.ObjectMetadata, content // set common headers if contentRange != nil { if contentRange.length > 0 { - setCommonHeaders(w, int(contentRange.length)) + w.Header().Set("Content-Length", strconv.FormatInt(contentRange.length, 10)) + setCommonHeaders(w) } else { - setCommonHeaders(w, int(metadata.Size)) + w.Header().Set("Content-Length", strconv.FormatInt(metadata.Size, 10)) + setCommonHeaders(w) } } else { - setCommonHeaders(w, int(metadata.Size)) + w.Header().Set("Content-Length", strconv.FormatInt(metadata.Size, 10)) + setCommonHeaders(w) } // set object headers lastModified := metadata.Created.Format(http.TimeFormat) diff --git a/api-response.go b/api-response.go index 0b371626d..d013d168a 100644 --- a/api-response.go +++ b/api-response.go @@ -206,15 +206,20 @@ func generateListMultipartUploadsResponse(bucket string, metadata fs.BucketMulti return listMultipartUploadsResponse } -// writeSuccessResponse write success headers -func writeSuccessResponse(w http.ResponseWriter) { - setCommonHeaders(w, 0) - w.WriteHeader(http.StatusOK) +// writeSuccessResponse write success headers and response if any. +func writeSuccessResponse(w http.ResponseWriter, response []byte) { + setCommonHeaders(w) + if response == nil { + w.WriteHeader(http.StatusOK) + return + } + w.Write(response) + w.(http.Flusher).Flush() } // writeSuccessNoContent write success headers with http status 204 func writeSuccessNoContent(w http.ResponseWriter) { - setCommonHeaders(w, 0) + setCommonHeaders(w) w.WriteHeader(http.StatusNoContent) } @@ -225,12 +230,13 @@ func writeErrorResponse(w http.ResponseWriter, req *http.Request, errorType int, errorResponse := getErrorResponse(error, resource) encodedErrorResponse := encodeErrorResponse(errorResponse) // set common headers - setCommonHeaders(w, len(encodedErrorResponse)) + setCommonHeaders(w) // write Header w.WriteHeader(error.HTTPStatusCode) // HEAD should have no body, do not attempt to write to it if req.Method != "HEAD" { // write error body w.Write(encodedErrorResponse) + w.(http.Flusher).Flush() } } diff --git a/appveyor.yml b/appveyor.yml index 6195aef44..b2a775a96 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,9 +14,6 @@ environment: # scripts that run after cloning repository install: - set PATH=%GOPATH%\bin;c:\go\bin;%PATH% - - rd C:\Go /s /q - - appveyor DownloadFile https://storage.googleapis.com/golang/go1.5.1.windows-amd64.zip - - 7z x go1.5.1.windows-amd64.zip -oC:\ >nul - go version - go env diff --git a/bucket-handlers.go b/bucket-handlers.go index 14c929ef7..275a3ab76 100644 --- a/bucket-handlers.go +++ b/bucket-handlers.go @@ -58,8 +58,8 @@ func (api CloudStorageAPI) GetBucketLocationHandler(w http.ResponseWriter, req * // we bring in a mechanism of configurable regions. For the time being // default region is empty i.e 'us-east-1'. encodedSuccessResponse := encodeSuccessResponse(LocationResponse{}) // generate response - setCommonHeaders(w, len(encodedSuccessResponse)) // write headers - w.Write(encodedSuccessResponse) // write body + setCommonHeaders(w) // write headers + writeSuccessResponse(w, encodedSuccessResponse) } // ListMultipartUploadsHandler - GET Bucket (List Multipart uploads) @@ -104,10 +104,10 @@ func (api CloudStorageAPI) ListMultipartUploadsHandler(w http.ResponseWriter, re // generate response response := generateListMultipartUploadsResponse(bucket, resources) encodedSuccessResponse := encodeSuccessResponse(response) - // write headers - setCommonHeaders(w, len(encodedSuccessResponse)) - // write body - w.Write(encodedSuccessResponse) + // write headers. + setCommonHeaders(w) + // write success response. + writeSuccessResponse(w, encodedSuccessResponse) } // ListObjectsHandler - GET Bucket (List Objects) @@ -139,13 +139,13 @@ func (api CloudStorageAPI) ListObjectsHandler(w http.ResponseWriter, req *http.R objects, resources, err := api.Filesystem.ListObjects(bucket, resources) if err == nil { - // generate response + // Generate response response := generateListObjectsResponse(bucket, objects, resources) encodedSuccessResponse := encodeSuccessResponse(response) - // write headers - setCommonHeaders(w, len(encodedSuccessResponse)) - // write body - w.Write(encodedSuccessResponse) + // Write headers + setCommonHeaders(w) + // Write success response. + writeSuccessResponse(w, encodedSuccessResponse) return } switch err.ToGoError().(type) { @@ -180,9 +180,9 @@ func (api CloudStorageAPI) ListBucketsHandler(w http.ResponseWriter, req *http.R response := generateListBucketsResponse(buckets) encodedSuccessResponse := encodeSuccessResponse(response) // write headers - setCommonHeaders(w, len(encodedSuccessResponse)) + setCommonHeaders(w) // write response - w.Write(encodedSuccessResponse) + writeSuccessResponse(w, encodedSuccessResponse) return } errorIf(err.Trace(), "ListBuckets failed.", nil) @@ -265,7 +265,7 @@ func (api CloudStorageAPI) PutBucketHandler(w http.ResponseWriter, req *http.Req } // Make sure to add Location information here only for bucket w.Header().Set("Location", "/"+bucket) - writeSuccessResponse(w) + writeSuccessResponse(w, nil) } // PostPolicyBucketHandler - POST policy @@ -348,7 +348,7 @@ func (api CloudStorageAPI) PostPolicyBucketHandler(w http.ResponseWriter, req *h return } w.Header().Set("ETag", "\""+metadata.Md5+"\"") - writeSuccessResponse(w) + writeSuccessResponse(w, nil) } // PutBucketACLHandler - PUT Bucket ACL @@ -384,7 +384,7 @@ func (api CloudStorageAPI) PutBucketACLHandler(w http.ResponseWriter, req *http. } return } - writeSuccessResponse(w) + writeSuccessResponse(w, nil) } // GetBucketACLHandler - GET ACL on a Bucket @@ -417,13 +417,13 @@ func (api CloudStorageAPI) GetBucketACLHandler(w http.ResponseWriter, req *http. } return } - // generate response + // Generate response response := generateAccessControlPolicyResponse(bucketMetadata.ACL) encodedSuccessResponse := encodeSuccessResponse(response) - // write headers - setCommonHeaders(w, len(encodedSuccessResponse)) - // write body - w.Write(encodedSuccessResponse) + // Write headers + setCommonHeaders(w) + // Write success response. + writeSuccessResponse(w, encodedSuccessResponse) } // HeadBucketHandler - HEAD Bucket @@ -458,7 +458,7 @@ func (api CloudStorageAPI) HeadBucketHandler(w http.ResponseWriter, req *http.Re } return } - writeSuccessResponse(w) + writeSuccessResponse(w, nil) } // DeleteBucketHandler - Delete bucket diff --git a/object-handlers.go b/object-handlers.go index 45f4893c2..52111941a 100644 --- a/object-handlers.go +++ b/object-handlers.go @@ -194,7 +194,7 @@ func (api CloudStorageAPI) PutObjectHandler(w http.ResponseWriter, req *http.Req return } w.Header().Set("ETag", "\""+metadata.Md5+"\"") - writeSuccessResponse(w) + writeSuccessResponse(w, nil) } /// Multipart CloudStorageAPI @@ -237,9 +237,9 @@ func (api CloudStorageAPI) NewMultipartUploadHandler(w http.ResponseWriter, req response := generateInitiateMultipartUploadResponse(bucket, object, uploadID) encodedSuccessResponse := encodeSuccessResponse(response) // write headers - setCommonHeaders(w, len(encodedSuccessResponse)) - // write body - w.Write(encodedSuccessResponse) + setCommonHeaders(w) + // write success response. + writeSuccessResponse(w, encodedSuccessResponse) } // PutObjectPartHandler - Upload part @@ -326,7 +326,7 @@ func (api CloudStorageAPI) PutObjectPartHandler(w http.ResponseWriter, req *http return } w.Header().Set("ETag", "\""+calculatedMD5+"\"") - writeSuccessResponse(w) + writeSuccessResponse(w, nil) } // AbortMultipartUploadHandler - Abort multipart upload @@ -412,10 +412,10 @@ func (api CloudStorageAPI) ListObjectPartsHandler(w http.ResponseWriter, req *ht } response := generateListPartsResponse(objectResourcesMetadata) encodedSuccessResponse := encodeSuccessResponse(response) - // write headers - setCommonHeaders(w, len(encodedSuccessResponse)) - // write body - w.Write(encodedSuccessResponse) + // write headers. + setCommonHeaders(w) + // write success response. + writeSuccessResponse(w, encodedSuccessResponse) } // CompleteMultipartUploadHandler - Complete multipart upload @@ -478,9 +478,9 @@ func (api CloudStorageAPI) CompleteMultipartUploadHandler(w http.ResponseWriter, response := generateCompleteMultpartUploadResponse(bucket, object, req.URL.String(), metadata.Md5) encodedSuccessResponse := encodeSuccessResponse(response) // write headers - setCommonHeaders(w, len(encodedSuccessResponse)) - // write body - w.Write(encodedSuccessResponse) + setCommonHeaders(w) + // write success response. + writeSuccessResponse(w, encodedSuccessResponse) } /// Delete CloudStorageAPI