From 0793237d9435c35e39ad26923ff908814595dbd2 Mon Sep 17 00:00:00 2001 From: Bala FA Date: Sun, 10 Jul 2016 23:40:59 +0530 Subject: [PATCH] tests: Move signature calculation in separate function. (#2160) Previously newTestRequest() creates request object and returns signature v4 signed request. In TestCopyObject(), its required to add headers later to the request and sign the request. This patch introduces two new functions * signRequest(): signs request using given access/secret keys. * newTestSignedRequest(): returns new request object signed with given access/secret keys. Fixes #2097 --- bucket-policy-handlers_test.go | 10 +- server_test.go | 247 +++++++++++++++++---------------- signature-v4-utils.go | 4 +- signature-v4.go | 2 - test-utils_test.go | 165 +++++++++++++--------- 5 files changed, 233 insertions(+), 195 deletions(-) diff --git a/bucket-policy-handlers_test.go b/bucket-policy-handlers_test.go index d50c4ca5f..7dd94110d 100644 --- a/bucket-policy-handlers_test.go +++ b/bucket-policy-handlers_test.go @@ -390,7 +390,7 @@ func testPutBucketPolicyHandler(obj ObjectLayer, instanceType string, t TestErrH // initialize HTTP NewRecorder, this records any mutations to response writer inside the handler. rec := httptest.NewRecorder() // construct HTTP request for PUT bucket policy endpoint. - req, err := newTestRequest("PUT", getPutPolicyURL("", testCase.bucketName), + req, err := newTestSignedRequest("PUT", getPutPolicyURL("", testCase.bucketName), int64(len(bucketPolicyStr)), bytes.NewReader([]byte(bucketPolicyStr)), testCase.accessKey, testCase.secretKey) if err != nil { t.Fatalf("Test %d: Failed to create HTTP request for PutBucketPolicyHandler: %v", i+1, err) @@ -487,7 +487,7 @@ func testGetBucketPolicyHandler(obj ObjectLayer, instanceType string, t TestErrH // initialize HTTP NewRecorder, this records any mutations to response writer inside the handler. rec := httptest.NewRecorder() // construct HTTP request for PUT bucket policy endpoint. - req, err := newTestRequest("PUT", getPutPolicyURL("", testPolicy.bucketName), + req, err := newTestSignedRequest("PUT", getPutPolicyURL("", testPolicy.bucketName), int64(len(bucketPolicyStr)), bytes.NewReader([]byte(bucketPolicyStr)), testPolicy.accessKey, testPolicy.secretKey) if err != nil { t.Fatalf("Test %d: Failed to create HTTP request for PutBucketPolicyHandler: %v", i+1, err) @@ -518,7 +518,7 @@ func testGetBucketPolicyHandler(obj ObjectLayer, instanceType string, t TestErrH // initialize HTTP NewRecorder, this records any mutations to response writer inside the handler. rec := httptest.NewRecorder() // construct HTTP request for PUT bucket policy endpoint. - req, err := newTestRequest("GET", getGetPolicyURL("", testCase.bucketName), + req, err := newTestSignedRequest("GET", getGetPolicyURL("", testCase.bucketName), 0, nil, testCase.accessKey, testCase.secretKey) if err != nil { @@ -626,7 +626,7 @@ func testDeleteBucketPolicyHandler(obj ObjectLayer, instanceType string, t TestE // initialize HTTP NewRecorder, this records any mutations to response writer inside the handler. rec := httptest.NewRecorder() // construct HTTP request for PUT bucket policy endpoint. - req, err := newTestRequest("PUT", getPutPolicyURL("", testPolicy.bucketName), + req, err := newTestSignedRequest("PUT", getPutPolicyURL("", testPolicy.bucketName), int64(len(bucketPolicyStr)), bytes.NewReader([]byte(bucketPolicyStr)), testPolicy.accessKey, testPolicy.secretKey) if err != nil { t.Fatalf("Test %d: Failed to create HTTP request for PutBucketPolicyHandler: %v", i+1, err) @@ -653,7 +653,7 @@ func testDeleteBucketPolicyHandler(obj ObjectLayer, instanceType string, t TestE // initialize HTTP NewRecorder, this records any mutations to response writer inside the handler. rec := httptest.NewRecorder() // construct HTTP request for Delete bucket policy endpoint. - req, err := newTestRequest("DELETE", getDeletePolicyURL("", testCase.bucketName), + req, err := newTestSignedRequest("DELETE", getDeletePolicyURL("", testCase.bucketName), 0, nil, testCase.accessKey, testCase.secretKey) if err != nil { diff --git a/server_test.go b/server_test.go index e4b3f5068..fb1ab3e48 100644 --- a/server_test.go +++ b/server_test.go @@ -118,7 +118,7 @@ func (s *TestSuiteCommon) TestBucketPolicy(c *C) { // create the policy statement string with the randomly generated bucket name. bucketPolicyStr := fmt.Sprintf(bucketPolicyBuf, bucketName, bucketName) // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -130,7 +130,7 @@ func (s *TestSuiteCommon) TestBucketPolicy(c *C) { c.Assert(response.StatusCode, Equals, http.StatusOK) /// Put a new bucket policy. - request, err = newTestRequest("PUT", getPutPolicyURL(s.endPoint, bucketName), + request, err = newTestSignedRequest("PUT", getPutPolicyURL(s.endPoint, bucketName), int64(len(bucketPolicyStr)), bytes.NewReader([]byte(bucketPolicyStr)), s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -141,7 +141,7 @@ func (s *TestSuiteCommon) TestBucketPolicy(c *C) { c.Assert(response.StatusCode, Equals, http.StatusNoContent) // Fetch the uploaded policy. - request, err = newTestRequest("GET", getGetPolicyURL(s.endPoint, bucketName), 0, nil, + request, err = newTestSignedRequest("GET", getGetPolicyURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -156,7 +156,7 @@ func (s *TestSuiteCommon) TestBucketPolicy(c *C) { c.Assert(bytes.Equal([]byte(bucketPolicyStr), bucketPolicyReadBuf), Equals, true) // Delete policy. - request, err = newTestRequest("DELETE", getDeletePolicyURL(s.endPoint, bucketName), 0, nil, + request, err = newTestSignedRequest("DELETE", getDeletePolicyURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -166,7 +166,7 @@ func (s *TestSuiteCommon) TestBucketPolicy(c *C) { c.Assert(response.StatusCode, Equals, http.StatusNoContent) // Verify if the policy was indeed deleted. - request, err = newTestRequest("GET", getGetPolicyURL(s.endPoint, bucketName), + request, err = newTestSignedRequest("GET", getGetPolicyURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -181,7 +181,7 @@ func (s *TestSuiteCommon) TestDeleteBucket(c *C) { bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -192,7 +192,7 @@ func (s *TestSuiteCommon) TestDeleteBucket(c *C) { c.Assert(response.StatusCode, Equals, http.StatusOK) // construct request to delete the bucket. - request, err = newTestRequest("DELETE", getDeleteBucketURL(s.endPoint, bucketName), + request, err = newTestSignedRequest("DELETE", getDeleteBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -209,7 +209,7 @@ func (s *TestSuiteCommon) TestDeleteBucketNotEmpty(c *C) { bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -223,7 +223,7 @@ func (s *TestSuiteCommon) TestDeleteBucketNotEmpty(c *C) { // generate http request for an object upload. // "test-object" is the object name. objectName := "test-object" - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -237,7 +237,7 @@ func (s *TestSuiteCommon) TestDeleteBucketNotEmpty(c *C) { // constructing http request to delete the bucket. // making an attempt to delete an non-empty bucket. // expected to fail. - request, err = newTestRequest("DELETE", getDeleteBucketURL(s.endPoint, bucketName), + request, err = newTestSignedRequest("DELETE", getDeleteBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -253,7 +253,7 @@ func (s *TestSuiteCommon) TestDeleteObject(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -267,7 +267,7 @@ func (s *TestSuiteCommon) TestDeleteObject(c *C) { objectName := "prefix/myobject" // obtain http request to upload object. // object Name contains a prefix. - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -280,7 +280,7 @@ func (s *TestSuiteCommon) TestDeleteObject(c *C) { // object name was "prefix/myobject", an attempt to delelte "prefix" // Should not delete "prefix/myobject" - request, err = newTestRequest("DELETE", getDeleteObjectURL(s.endPoint, bucketName, "prefix"), + request, err = newTestSignedRequest("DELETE", getDeleteObjectURL(s.endPoint, bucketName, "prefix"), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) client = http.Client{} @@ -290,7 +290,7 @@ func (s *TestSuiteCommon) TestDeleteObject(c *C) { // create http request to HEAD on the object. // this helps to validate the existence of the bucket. - request, err = newTestRequest("HEAD", getHeadObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("HEAD", getHeadObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -301,7 +301,7 @@ func (s *TestSuiteCommon) TestDeleteObject(c *C) { c.Assert(response.StatusCode, Equals, http.StatusOK) // create HTTP request to delete the object. - request, err = newTestRequest("DELETE", getDeleteObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("DELETE", getDeleteObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) client = http.Client{} @@ -312,7 +312,7 @@ func (s *TestSuiteCommon) TestDeleteObject(c *C) { c.Assert(response.StatusCode, Equals, http.StatusNoContent) // Delete of non-existent data should return success. - request, err = newTestRequest("DELETE", getDeleteObjectURL(s.endPoint, bucketName, "prefix/myobject1"), + request, err = newTestSignedRequest("DELETE", getDeleteObjectURL(s.endPoint, bucketName, "prefix/myobject1"), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) client = http.Client{} @@ -329,7 +329,7 @@ func (s *TestSuiteCommon) TestNonExistentBucket(c *C) { bucketName := getRandomBucketName() // create request to HEAD on the bucket. // HEAD on an bucket helps validate the existence of the bucket. - request, err := newTestRequest("HEAD", getHEADBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("HEAD", getHEADBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -346,7 +346,7 @@ func (s *TestSuiteCommon) TestEmptyObject(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -359,7 +359,7 @@ func (s *TestSuiteCommon) TestEmptyObject(c *C) { objectName := "test-object" // construct http request for uploading the object. - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -371,7 +371,7 @@ func (s *TestSuiteCommon) TestEmptyObject(c *C) { c.Assert(response.StatusCode, Equals, http.StatusOK) // make HTTP request to fetch the object. - request, err = newTestRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -394,7 +394,7 @@ func (s *TestSuiteCommon) TestBucket(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -403,7 +403,7 @@ func (s *TestSuiteCommon) TestBucket(c *C) { c.Assert(err, IsNil) c.Assert(response.StatusCode, Equals, http.StatusOK) - request, err = newTestRequest("HEAD", getMakeBucketURL(s.endPoint, bucketName), + request, err = newTestSignedRequest("HEAD", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -419,7 +419,7 @@ func (s *TestSuiteCommon) TestObjectGet(c *C) { bucketName := getRandomBucketName() buffer := bytes.NewReader([]byte("hello world")) // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -432,7 +432,7 @@ func (s *TestSuiteCommon) TestObjectGet(c *C) { objectName := "testObject" // create HTTP request to upload the object. - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), int64(buffer.Len()), buffer, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -444,7 +444,7 @@ func (s *TestSuiteCommon) TestObjectGet(c *C) { c.Assert(response.StatusCode, Equals, http.StatusOK) // create HTTP request to fetch the object. - request, err = newTestRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -467,7 +467,7 @@ func (s *TestSuiteCommon) TestMultipleObjects(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -480,7 +480,7 @@ func (s *TestSuiteCommon) TestMultipleObjects(c *C) { // constructing HTTP request to fetch a non-existent object. // expected to fail, error response asserted for expected error values later. objectName := "testObject" - request, err = newTestRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -495,7 +495,7 @@ func (s *TestSuiteCommon) TestMultipleObjects(c *C) { // content for the object to be uploaded. buffer1 := bytes.NewReader([]byte("hello one")) // create HTTP request for the object upload. - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -507,7 +507,7 @@ func (s *TestSuiteCommon) TestMultipleObjects(c *C) { c.Assert(response.StatusCode, Equals, http.StatusOK) // create HTTP request to fetch the object which was uploaded above. - request, err = newTestRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -527,7 +527,7 @@ func (s *TestSuiteCommon) TestMultipleObjects(c *C) { // data for new object to be uploaded. buffer2 := bytes.NewReader([]byte("hello two")) objectName = "testObject2" - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), int64(buffer2.Len()), buffer2, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -538,7 +538,7 @@ func (s *TestSuiteCommon) TestMultipleObjects(c *C) { // assert the response status code for expected value 200 OK. c.Assert(response.StatusCode, Equals, http.StatusOK) // fetch the object which was uploaded above. - request, err = newTestRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -557,7 +557,7 @@ func (s *TestSuiteCommon) TestMultipleObjects(c *C) { // data for new object to be uploaded. buffer3 := bytes.NewReader([]byte("hello three")) objectName = "testObject3" - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), int64(buffer3.Len()), buffer3, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -569,7 +569,7 @@ func (s *TestSuiteCommon) TestMultipleObjects(c *C) { c.Assert(response.StatusCode, Equals, http.StatusOK) // fetch the object which was uploaded above. - request, err = newTestRequest("GET", getPutObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("GET", getPutObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -588,7 +588,7 @@ func (s *TestSuiteCommon) TestMultipleObjects(c *C) { func (s *TestSuiteCommon) TestNotImplemented(c *C) { // Generate a random bucket name. bucketName := getRandomBucketName() - request, err := newTestRequest("GET", s.endPoint+"/"+bucketName+"/object?policy", + request, err := newTestSignedRequest("GET", s.endPoint+"/"+bucketName+"/object?policy", 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -603,7 +603,7 @@ func (s *TestSuiteCommon) TestHeader(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() // obtain HTTP request to fetch an object from non-existent bucket/object. - request, err := newTestRequest("GET", getGetObjectURL(s.endPoint, bucketName, "testObject"), + request, err := newTestSignedRequest("GET", getGetObjectURL(s.endPoint, bucketName, "testObject"), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -627,7 +627,7 @@ func (s *TestSuiteCommon) TestPutBucket(c *C) { go func() { defer wg.Done() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -641,7 +641,7 @@ func (s *TestSuiteCommon) TestPutBucket(c *C) { bucketName = getRandomBucketName() //Block 2: testing for correctness of the functionality // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -662,7 +662,7 @@ func (s *TestSuiteCommon) TestCopyObject(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -676,7 +676,7 @@ func (s *TestSuiteCommon) TestCopyObject(c *C) { buffer1 := bytes.NewReader([]byte("hello world")) objectName := "testObject" // create HTTP request for object upload. - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey) request.Header.Set("Content-Type", "application/json") c.Assert(err, IsNil) @@ -687,10 +687,11 @@ func (s *TestSuiteCommon) TestCopyObject(c *C) { objectName2 := "testObject2" // creating HTTP request for uploading the object. - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName2), - 0, nil, s.accessKey, s.secretKey) + request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName2), 0, nil) + c.Assert(err, IsNil) // setting the "X-Amz-Copy-Source" to allow copying the content of previously uploaded object. request.Header.Set("X-Amz-Copy-Source", url.QueryEscape("/"+bucketName+"/"+objectName)) + err = signRequest(request, s.accessKey, s.secretKey) c.Assert(err, IsNil) // execute the HTTP request. // the content is expected to have the content of previous disk. @@ -699,7 +700,7 @@ func (s *TestSuiteCommon) TestCopyObject(c *C) { c.Assert(response.StatusCode, Equals, http.StatusOK) // creating HTTP request to fetch the previously uploaded object. - request, err = newTestRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName2), + request, err = newTestSignedRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName2), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) // executing the HTTP request. @@ -719,7 +720,7 @@ func (s *TestSuiteCommon) TestPutObject(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -733,7 +734,7 @@ func (s *TestSuiteCommon) TestPutObject(c *C) { buffer1 := bytes.NewReader([]byte("hello world")) objectName := "testObject" // creating HTTP request for object upload. - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey) c.Assert(err, IsNil) // execute the HTTP request for object upload. @@ -742,7 +743,7 @@ func (s *TestSuiteCommon) TestPutObject(c *C) { c.Assert(response.StatusCode, Equals, http.StatusOK) // fetch the object back and verify its contents. - request, err = newTestRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) // execute the HTTP request to fetch the object. @@ -764,7 +765,7 @@ func (s *TestSuiteCommon) TestPutObject(c *C) { // Its success verifies the format of the response. func (s *TestSuiteCommon) TestListBuckets(c *C) { // create HTTP request for listing buckets. - request, err := newTestRequest("GET", getListBucketURL(s.endPoint), + request, err := newTestSignedRequest("GET", getListBucketURL(s.endPoint), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -787,7 +788,7 @@ func (s *TestSuiteCommon) TestValidateSignature(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -803,7 +804,7 @@ func (s *TestSuiteCommon) TestValidateSignature(c *C) { // Create new HTTP request with incorrect secretKey to generate an incorrect signature. secretKey := s.secretKey + "a" - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objName), 0, nil, s.accessKey, secretKey) + request, err = newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objName), 0, nil, s.accessKey, secretKey) c.Assert(err, IsNil) response, err = client.Do(request) c.Assert(err, IsNil) @@ -815,7 +816,7 @@ func (s *TestSuiteCommon) TestSHA256Mismatch(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -831,7 +832,7 @@ func (s *TestSuiteCommon) TestSHA256Mismatch(c *C) { // Create new HTTP request with incorrect secretKey to generate an incorrect signature. secretKey := s.secretKey + "a" - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objName), 0, nil, s.accessKey, secretKey) + request, err = newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objName), 0, nil, s.accessKey, secretKey) c.Assert(request.Header.Get("x-amz-content-sha256"), Equals, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") // Set the body to generate signature mismatch. request.Body = ioutil.NopCloser(bytes.NewReader([]byte("Hello, World"))) @@ -848,7 +849,7 @@ func (s *TestSuiteCommon) TestPutObjectLongName(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -862,7 +863,7 @@ func (s *TestSuiteCommon) TestPutObjectLongName(c *C) { // make long object name. longObjName := fmt.Sprintf("%0255d/%0255d/%0255d", 1, 1, 1) // create new HTTP request to insert the object. - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, longObjName), + request, err = newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, longObjName), int64(buffer.Len()), buffer, s.accessKey, s.secretKey) c.Assert(err, IsNil) // execute the HTTP request. @@ -872,7 +873,7 @@ func (s *TestSuiteCommon) TestPutObjectLongName(c *C) { // make long object name. longObjName = fmt.Sprintf("%0256d", 1) buffer = bytes.NewReader([]byte("hello world")) - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, longObjName), + request, err = newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, longObjName), int64(buffer.Len()), buffer, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -891,7 +892,7 @@ func (s *TestSuiteCommon) TestNotBeAbleToCreateObjectInNonexistentBucket(c *C) { // preparing for upload by generating the upload URL. objectName := "test-object" - request, err := newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), + request, err := newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -913,7 +914,7 @@ func (s *TestSuiteCommon) TestHeadOnObjectLastModified(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -928,7 +929,7 @@ func (s *TestSuiteCommon) TestHeadOnObjectLastModified(c *C) { // content for the object to be uploaded. buffer1 := bytes.NewReader([]byte("hello world")) // obtaining URL for uploading the object. - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -937,7 +938,7 @@ func (s *TestSuiteCommon) TestHeadOnObjectLastModified(c *C) { c.Assert(err, IsNil) c.Assert(response.StatusCode, Equals, http.StatusOK) // make HTTP request to obtain object info. - request, err = newTestRequest("HEAD", getHeadObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("HEAD", getHeadObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) // execute the HTTP request. @@ -955,7 +956,7 @@ func (s *TestSuiteCommon) TestHeadOnObjectLastModified(c *C) { // make HTTP request to obtain object info. // But this time set the "If-Modified-Since" header to be 10 minute more than the actual // last modified time of the object. - request, err = newTestRequest("HEAD", getHeadObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("HEAD", getHeadObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) request.Header.Set("If-Modified-Since", t.Add(10*time.Minute).UTC().Format(http.TimeFormat)) @@ -968,7 +969,7 @@ func (s *TestSuiteCommon) TestHeadOnObjectLastModified(c *C) { // Again, obtain the object info. // This time setting "If-Unmodified-Since" to a time after the object is modified. // As documented above, expecting http.StatusPreconditionFailed. - request, err = newTestRequest("HEAD", getHeadObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("HEAD", getHeadObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) request.Header.Set("If-Unmodified-Since", t.Add(-10*time.Minute).UTC().Format(http.TimeFormat)) @@ -983,7 +984,7 @@ func (s *TestSuiteCommon) TestHeadOnBucket(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getHEADBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getHEADBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -993,7 +994,7 @@ func (s *TestSuiteCommon) TestHeadOnBucket(c *C) { c.Assert(err, IsNil) c.Assert(response.StatusCode, Equals, http.StatusOK) // make HEAD request on the bucket. - request, err = newTestRequest("HEAD", getHEADBucketURL(s.endPoint, bucketName), + request, err = newTestSignedRequest("HEAD", getHEADBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) // execute the HTTP request. @@ -1009,7 +1010,7 @@ func (s *TestSuiteCommon) TestContentTypePersists(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1024,7 +1025,7 @@ func (s *TestSuiteCommon) TestContentTypePersists(c *C) { buffer1 := bytes.NewReader([]byte("hello world")) objectName := "test-object.png" // constructing HTTP request for object upload. - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey) c.Assert(err, IsNil) request.Header.Set("Content-Type", "image/png") @@ -1036,7 +1037,7 @@ func (s *TestSuiteCommon) TestContentTypePersists(c *C) { c.Assert(response.StatusCode, Equals, http.StatusOK) // Fetching the object info using HEAD request for the object which was uploaded above. - request, err = newTestRequest("HEAD", getHeadObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("HEAD", getHeadObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1047,7 +1048,7 @@ func (s *TestSuiteCommon) TestContentTypePersists(c *C) { c.Assert(response.Header.Get("Content-Type"), Equals, "image/png") // Fetching the object itself and then verify the Content-Type header. - request, err = newTestRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1062,7 +1063,7 @@ func (s *TestSuiteCommon) TestContentTypePersists(c *C) { // Uploading a new object with Content-Type "application/json". objectName = "test-object.json" buffer2 := bytes.NewReader([]byte("hello world")) - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), int64(buffer2.Len()), buffer2, s.accessKey, s.secretKey) c.Assert(err, IsNil) // setting the request header to be application/json. @@ -1074,7 +1075,7 @@ func (s *TestSuiteCommon) TestContentTypePersists(c *C) { c.Assert(response.StatusCode, Equals, http.StatusOK) // Obtain the info of the object which was uploaded above using HEAD request. - request, err = newTestRequest("HEAD", getHeadObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("HEAD", getHeadObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) // Execute the HTTP request. @@ -1084,7 +1085,7 @@ func (s *TestSuiteCommon) TestContentTypePersists(c *C) { c.Assert(response.Header.Get("Content-Type"), Equals, "application/json") // Fetch the object and assert whether the Content-Type header persists. - request, err = newTestRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1101,7 +1102,7 @@ func (s *TestSuiteCommon) TestContentTypePersists(c *C) { func (s *TestSuiteCommon) TestPartialContent(c *C) { bucketName := getRandomBucketName() - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1111,7 +1112,7 @@ func (s *TestSuiteCommon) TestPartialContent(c *C) { c.Assert(response.StatusCode, Equals, http.StatusOK) buffer1 := bytes.NewReader([]byte("Hello World")) - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, "bar"), + request, err = newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, "bar"), int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1121,7 +1122,7 @@ func (s *TestSuiteCommon) TestPartialContent(c *C) { c.Assert(response.StatusCode, Equals, http.StatusOK) // Prepare request - request, err = newTestRequest("GET", getGetObjectURL(s.endPoint, bucketName, "bar"), + request, err = newTestSignedRequest("GET", getGetObjectURL(s.endPoint, bucketName, "bar"), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) request.Header.Add("Range", "bytes=6-7") @@ -1142,7 +1143,7 @@ func (s *TestSuiteCommon) TestListObjectsHandlerErrors(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1154,7 +1155,7 @@ func (s *TestSuiteCommon) TestListObjectsHandlerErrors(c *C) { // create HTTP request with invalid value of max-keys parameter. // max-keys is set to -2. - request, err = newTestRequest("GET", getListObjectsURL(s.endPoint, bucketName, "-2"), + request, err = newTestSignedRequest("GET", getListObjectsURL(s.endPoint, bucketName, "-2"), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) client = http.Client{} @@ -1172,7 +1173,7 @@ func (s *TestSuiteCommon) TestPutBucketErrors(c *C) { bucketName := getRandomBucketName() // generating a HTTP request to create bucket. // using invalid bucket name. - request, err := newTestRequest("PUT", s.endPoint+"/putbucket-.", + request, err := newTestSignedRequest("PUT", s.endPoint+"/putbucket-.", 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1182,7 +1183,7 @@ func (s *TestSuiteCommon) TestPutBucketErrors(c *C) { // expected to fail with error message "InvalidBucketName". verifyError(c, response, "InvalidBucketName", "The specified bucket is not valid.", http.StatusBadRequest) // HTTP request to create the bucket. - request, err = newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err = newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1193,7 +1194,7 @@ func (s *TestSuiteCommon) TestPutBucketErrors(c *C) { c.Assert(response.StatusCode, Equals, http.StatusOK) // make HTTP request to create the same bucket again. // expected to fail with error message "BucketAlreadyOwnedByYou". - request, err = newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err = newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1204,7 +1205,7 @@ func (s *TestSuiteCommon) TestPutBucketErrors(c *C) { // request for ACL. // Since Minio server doesn't support ACL's the request is expected to fail with "NotImplemented" error message. - request, err = newTestRequest("PUT", s.endPoint+"/"+bucketName+"?acl", + request, err = newTestSignedRequest("PUT", s.endPoint+"/"+bucketName+"?acl", 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1217,7 +1218,7 @@ func (s *TestSuiteCommon) TestGetObjectLarge10MiB(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() // form HTTP reqest to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1247,7 +1248,7 @@ func (s *TestSuiteCommon) TestGetObjectLarge10MiB(c *C) { objectName := "test-big-object" // create HTTP request for object upload. - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), int64(buf.Len()), buf, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1259,7 +1260,7 @@ func (s *TestSuiteCommon) TestGetObjectLarge10MiB(c *C) { c.Assert(response.StatusCode, Equals, http.StatusOK) // prepare HTTP requests to download the object. - request, err = newTestRequest("GET", getPutObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("GET", getPutObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1281,7 +1282,7 @@ func (s *TestSuiteCommon) TestGetObjectLarge11MiB(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1312,7 +1313,7 @@ func (s *TestSuiteCommon) TestGetObjectLarge11MiB(c *C) { // Put object buf := bytes.NewReader(buffer.Bytes()) // create HTTP request foe object upload. - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), int64(buf.Len()), buf, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1323,7 +1324,7 @@ func (s *TestSuiteCommon) TestGetObjectLarge11MiB(c *C) { c.Assert(response.StatusCode, Equals, http.StatusOK) // create HTTP request to download the object. - request, err = newTestRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1350,7 +1351,7 @@ func (s *TestSuiteCommon) TestGetPartialObjectMisAligned(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1382,7 +1383,7 @@ func (s *TestSuiteCommon) TestGetPartialObjectMisAligned(c *C) { objectName := "test-big-file" // HTTP request to upload the object. - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), int64(buf.Len()), buf, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1412,7 +1413,7 @@ func (s *TestSuiteCommon) TestGetPartialObjectMisAligned(c *C) { } for _, t := range testCases { // HTTP request to download the object. - request, err = newTestRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) // Get partial content based on the byte range set. @@ -1438,7 +1439,7 @@ func (s *TestSuiteCommon) TestGetPartialObjectLarge11MiB(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1470,7 +1471,7 @@ func (s *TestSuiteCommon) TestGetPartialObjectLarge11MiB(c *C) { buf := bytes.NewReader([]byte(putContent)) // HTTP request to upload the object. - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), int64(buf.Len()), buf, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1481,7 +1482,7 @@ func (s *TestSuiteCommon) TestGetPartialObjectLarge11MiB(c *C) { c.Assert(response.StatusCode, Equals, http.StatusOK) // HTTP request to download the object. - request, err = newTestRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) // This range spans into first two blocks. @@ -1506,7 +1507,7 @@ func (s *TestSuiteCommon) TestGetPartialObjectLarge10MiB(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1539,7 +1540,7 @@ func (s *TestSuiteCommon) TestGetPartialObjectLarge10MiB(c *C) { objectName := "test-big-10Mb-file" // HTTP request to upload the object. - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), int64(buf.Len()), buf, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1551,7 +1552,7 @@ func (s *TestSuiteCommon) TestGetPartialObjectLarge10MiB(c *C) { c.Assert(response.StatusCode, Equals, http.StatusOK) // HTTP request to download the object. - request, err = newTestRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) // Get partial content based on the byte range set. @@ -1577,7 +1578,7 @@ func (s *TestSuiteCommon) TestGetObjectErrors(c *C) { bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1591,7 +1592,7 @@ func (s *TestSuiteCommon) TestGetObjectErrors(c *C) { // HTTP request to download the object. // Since the specified object doesn't exist in the given bucket, // expected to fail with error message "NoSuchKey" - request, err = newTestRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1601,7 +1602,7 @@ func (s *TestSuiteCommon) TestGetObjectErrors(c *C) { verifyError(c, response, "NoSuchKey", "The specified key does not exist.", http.StatusNotFound) // request to download an object, but an invalid bucket name is set. - request, err = newTestRequest("GET", getGetObjectURL(s.endPoint, "/getobjecterrors-.", objectName), + request, err = newTestSignedRequest("GET", getGetObjectURL(s.endPoint, "/getobjecterrors-.", objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1617,7 +1618,7 @@ func (s *TestSuiteCommon) TestGetObjectRangeErrors(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1632,7 +1633,7 @@ func (s *TestSuiteCommon) TestGetObjectRangeErrors(c *C) { objectName := "test-object" // HTTP request to upload the object. - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1644,7 +1645,7 @@ func (s *TestSuiteCommon) TestGetObjectRangeErrors(c *C) { c.Assert(response.StatusCode, Equals, http.StatusOK) // HTTP request to download the object. - request, err = newTestRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("GET", getGetObjectURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) // Invalid byte range set. request.Header.Add("Range", "bytes=-0") @@ -1663,7 +1664,7 @@ func (s *TestSuiteCommon) TestObjectMultipartAbort(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1675,7 +1676,7 @@ func (s *TestSuiteCommon) TestObjectMultipartAbort(c *C) { objectName := "test-multipart-object" // construct HTTP request to initiate a NewMultipart upload. - request, err = newTestRequest("POST", getNewMultipartURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("POST", getNewMultipartURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1696,7 +1697,7 @@ func (s *TestSuiteCommon) TestObjectMultipartAbort(c *C) { // content for the part to be uploaded. buffer1 := bytes.NewReader([]byte("hello world")) // HTTP request for the part to be uploaded. - request, err = newTestRequest("PUT", getPartUploadURL(s.endPoint, bucketName, objectName, uploadID, "1"), + request, err = newTestSignedRequest("PUT", getPartUploadURL(s.endPoint, bucketName, objectName, uploadID, "1"), int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey) c.Assert(err, IsNil) // execute the HTTP request to upload the first part. @@ -1707,7 +1708,7 @@ func (s *TestSuiteCommon) TestObjectMultipartAbort(c *C) { // content for the second part to be uploaded. buffer2 := bytes.NewReader([]byte("hello world")) // HTTP request for the second part to be uploaded. - request, err = newTestRequest("PUT", getPartUploadURL(s.endPoint, bucketName, objectName, uploadID, "2"), + request, err = newTestSignedRequest("PUT", getPartUploadURL(s.endPoint, bucketName, objectName, uploadID, "2"), int64(buffer2.Len()), buffer2, s.accessKey, s.secretKey) c.Assert(err, IsNil) // execute the HTTP request to upload the second part. @@ -1715,7 +1716,7 @@ func (s *TestSuiteCommon) TestObjectMultipartAbort(c *C) { c.Assert(err, IsNil) c.Assert(response2.StatusCode, Equals, http.StatusOK) // HTTP request for aborting the multipart upload. - request, err = newTestRequest("DELETE", getAbortMultipartUploadURL(s.endPoint, bucketName, objectName, uploadID), + request, err = newTestSignedRequest("DELETE", getAbortMultipartUploadURL(s.endPoint, bucketName, objectName, uploadID), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) // execute the HTTP request to abort the multipart upload. @@ -1731,7 +1732,7 @@ func (s *TestSuiteCommon) TestBucketMultipartList(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1743,7 +1744,7 @@ func (s *TestSuiteCommon) TestBucketMultipartList(c *C) { objectName := "test-multipart-object" // construct HTTP request to initiate a NewMultipart upload. - request, err = newTestRequest("POST", getNewMultipartURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("POST", getNewMultipartURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) // execute the HTTP request initiating the new multipart upload. @@ -1765,7 +1766,7 @@ func (s *TestSuiteCommon) TestBucketMultipartList(c *C) { // content for the part to be uploaded. buffer1 := bytes.NewReader([]byte("hello world")) // HTTP request for the part to be uploaded. - request, err = newTestRequest("PUT", getPartUploadURL(s.endPoint, bucketName, objectName, uploadID, "1"), + request, err = newTestSignedRequest("PUT", getPartUploadURL(s.endPoint, bucketName, objectName, uploadID, "1"), int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey) c.Assert(err, IsNil) // execute the HTTP request to upload the first part. @@ -1776,7 +1777,7 @@ func (s *TestSuiteCommon) TestBucketMultipartList(c *C) { // content for the second part to be uploaded. buffer2 := bytes.NewReader([]byte("hello world")) // HTTP request for the second part to be uploaded. - request, err = newTestRequest("PUT", getPartUploadURL(s.endPoint, bucketName, objectName, uploadID, "2"), + request, err = newTestSignedRequest("PUT", getPartUploadURL(s.endPoint, bucketName, objectName, uploadID, "2"), int64(buffer2.Len()), buffer2, s.accessKey, s.secretKey) c.Assert(err, IsNil) // execute the HTTP request to upload the second part. @@ -1785,7 +1786,7 @@ func (s *TestSuiteCommon) TestBucketMultipartList(c *C) { c.Assert(response2.StatusCode, Equals, http.StatusOK) // HTTP request to ListMultipart Uploads. - request, err = newTestRequest("GET", getListMultipartURL(s.endPoint, bucketName), + request, err = newTestSignedRequest("GET", getListMultipartURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) // execute the HTTP request. @@ -1844,7 +1845,7 @@ func (s *TestSuiteCommon) TestValidateObjectMultipartUploadID(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1856,7 +1857,7 @@ func (s *TestSuiteCommon) TestValidateObjectMultipartUploadID(c *C) { objectName := "directory1/directory2/object" // construct HTTP request to initiate a NewMultipart upload. - request, err = newTestRequest("POST", getNewMultipartURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("POST", getNewMultipartURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) // execute the HTTP request initiating the new multipart upload. @@ -1880,7 +1881,7 @@ func (s *TestSuiteCommon) TestObjectMultipartListError(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1892,7 +1893,7 @@ func (s *TestSuiteCommon) TestObjectMultipartListError(c *C) { objectName := "test-multipart-object" // construct HTTP request to initiate a NewMultipart upload. - request, err = newTestRequest("POST", getNewMultipartURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("POST", getNewMultipartURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) // execute the HTTP request initiating the new multipart upload. @@ -1911,7 +1912,7 @@ func (s *TestSuiteCommon) TestObjectMultipartListError(c *C) { // content for the part to be uploaded. buffer1 := bytes.NewReader([]byte("hello world")) // HTTP request for the part to be uploaded. - request, err = newTestRequest("PUT", getPartUploadURL(s.endPoint, bucketName, objectName, uploadID, "1"), + request, err = newTestSignedRequest("PUT", getPartUploadURL(s.endPoint, bucketName, objectName, uploadID, "1"), int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey) c.Assert(err, IsNil) // execute the HTTP request to upload the first part. @@ -1922,7 +1923,7 @@ func (s *TestSuiteCommon) TestObjectMultipartListError(c *C) { // content for the second part to be uploaded. buffer2 := bytes.NewReader([]byte("hello world")) // HTTP request for the second part to be uploaded. - request, err = newTestRequest("PUT", getPartUploadURL(s.endPoint, bucketName, objectName, uploadID, "2"), + request, err = newTestSignedRequest("PUT", getPartUploadURL(s.endPoint, bucketName, objectName, uploadID, "2"), int64(buffer2.Len()), buffer2, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1932,7 +1933,7 @@ func (s *TestSuiteCommon) TestObjectMultipartListError(c *C) { c.Assert(response2.StatusCode, Equals, http.StatusOK) // HTTP request to ListMultipart Uploads. // max-keys is set to invalid value of -2. - request, err = newTestRequest("GET", getListMultipartURLWithParams(s.endPoint, bucketName, objectName, uploadID, "-2"), + request, err = newTestSignedRequest("GET", getListMultipartURLWithParams(s.endPoint, bucketName, objectName, uploadID, "-2"), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) // execute the HTTP request. @@ -1949,7 +1950,7 @@ func (s *TestSuiteCommon) TestObjectValidMD5(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -1970,7 +1971,7 @@ func (s *TestSuiteCommon) TestObjectValidMD5(c *C) { buffer1 := bytes.NewReader(data) objectName := "test-1-object" // HTTP request for the object to be uploaded. - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey) c.Assert(err, IsNil) // set the Content-Md5 to be the hash to content. @@ -1983,7 +1984,7 @@ func (s *TestSuiteCommon) TestObjectValidMD5(c *C) { objectName = "test-2-object" buffer1 = bytes.NewReader(data) // HTTP request for the object to be uploaded. - request, err = newTestRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("PUT", getPutObjectURL(s.endPoint, bucketName, objectName), int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey) c.Assert(err, IsNil) // set Content-Md5 to invalid value. @@ -2002,7 +2003,7 @@ func (s *TestSuiteCommon) TestObjectMultipart(c *C) { // generate a random bucket name. bucketName := getRandomBucketName() // HTTP request to create the bucket. - request, err := newTestRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), + request, err := newTestSignedRequest("PUT", getMakeBucketURL(s.endPoint, bucketName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -2014,7 +2015,7 @@ func (s *TestSuiteCommon) TestObjectMultipart(c *C) { objectName := "test-multipart-object" // construct HTTP request to initiate a NewMultipart upload. - request, err = newTestRequest("POST", getNewMultipartURL(s.endPoint, bucketName, objectName), + request, err = newTestSignedRequest("POST", getNewMultipartURL(s.endPoint, bucketName, objectName), 0, nil, s.accessKey, s.secretKey) c.Assert(err, IsNil) @@ -2044,7 +2045,7 @@ func (s *TestSuiteCommon) TestObjectMultipart(c *C) { buffer1 := bytes.NewReader(data) // HTTP request for the part to be uploaded. - request, err = newTestRequest("PUT", getPartUploadURL(s.endPoint, bucketName, objectName, uploadID, "1"), + request, err = newTestSignedRequest("PUT", getPartUploadURL(s.endPoint, bucketName, objectName, uploadID, "1"), int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey) // set the Content-Md5 header to the base64 encoding the md5Sum of the content. request.Header.Set("Content-Md5", base64.StdEncoding.EncodeToString(md5Sum)) @@ -2067,7 +2068,7 @@ func (s *TestSuiteCommon) TestObjectMultipart(c *C) { buffer2 := bytes.NewReader(data) // HTTP request for the second part to be uploaded. - request, err = newTestRequest("PUT", getPartUploadURL(s.endPoint, bucketName, objectName, uploadID, "2"), + request, err = newTestSignedRequest("PUT", getPartUploadURL(s.endPoint, bucketName, objectName, uploadID, "2"), int64(buffer2.Len()), buffer2, s.accessKey, s.secretKey) // set the Content-Md5 header to the base64 encoding the md5Sum of the content. request.Header.Set("Content-Md5", base64.StdEncoding.EncodeToString(md5Sum)) @@ -2096,7 +2097,7 @@ func (s *TestSuiteCommon) TestObjectMultipart(c *C) { completeBytes, err := xml.Marshal(completeUploads) c.Assert(err, IsNil) // Indicating that all parts are uploaded and initiating completeMultipartUpload. - request, err = newTestRequest("POST", getCompleteMultipartUploadURL(s.endPoint, bucketName, objectName, uploadID), + request, err = newTestSignedRequest("POST", getCompleteMultipartUploadURL(s.endPoint, bucketName, objectName, uploadID), int64(len(completeBytes)), bytes.NewReader(completeBytes), s.accessKey, s.secretKey) c.Assert(err, IsNil) // Execute the complete multipart request. diff --git a/signature-v4-utils.go b/signature-v4-utils.go index a20e07fd3..4bcd89a9e 100644 --- a/signature-v4-utils.go +++ b/signature-v4-utils.go @@ -58,6 +58,9 @@ func sumHMAC(key []byte, data []byte) []byte { return hash.Sum(nil) } +// Reserved string regexp. +var reservedNames = regexp.MustCompile("^[a-zA-Z0-9-_.~/]+$") + // getURLEncodedName encode the strings from UTF-8 byte representations to HTML hex escape sequences // // This is necessary since regular url.Parse() and url.Encode() functions do not support UTF-8 @@ -67,7 +70,6 @@ func sumHMAC(key []byte, data []byte) []byte { // pretty much every UTF-8 character. func getURLEncodedName(name string) string { // if object matches reserved string, no need to encode them - reservedNames := regexp.MustCompile("^[a-zA-Z0-9-_.~/]+$") if reservedNames.MatchString(name) { return name } diff --git a/signature-v4.go b/signature-v4.go index 7fe9c4216..dae1f9589 100644 --- a/signature-v4.go +++ b/signature-v4.go @@ -99,8 +99,6 @@ func getSignedHeaders(signedHeaders http.Header) string { func getCanonicalRequest(extractedSignedHeaders http.Header, payload, queryStr, urlPath, method, host string) string { rawQuery := strings.Replace(queryStr, "+", "%20", -1) encodedPath := getURLEncodedName(urlPath) - // Convert any space strings back to "+". - encodedPath = strings.Replace(encodedPath, "+", "%20", -1) canonicalRequest := strings.Join([]string{ method, encodedPath, diff --git a/test-utils_test.go b/test-utils_test.go index b7bf25041..dc12ba5ac 100644 --- a/test-utils_test.go +++ b/test-utils_test.go @@ -165,90 +165,66 @@ func (testServer TestServer) Stop() { testServer.Server.Close() } -// used to formulate HTTP v4 signed HTTP request. -func newTestRequest(method, urlStr string, contentLength int64, body io.ReadSeeker, accessKey, secretKey string) (*http.Request, error) { - if method == "" { - method = "POST" - } - t := time.Now().UTC() - - req, err := http.NewRequest(method, urlStr, nil) - if err != nil { - return nil, err +// Sign given request using Signature V4. +func signRequest(req *http.Request, accessKey, secretKey string) error { + // Get hashed payload. + hashedPayload := req.Header.Get("x-amz-content-sha256") + if hashedPayload == "" { + return fmt.Errorf("Invalid hashed payload.") } - req.Header.Set("x-amz-date", t.Format(iso8601Format)) + currTime := time.Now().UTC() - // Add Content-Length - req.ContentLength = contentLength + // Set x-amz-date. + req.Header.Set("x-amz-date", currTime.Format(iso8601Format)) - // Save for subsequent use - var hashedPayload string - switch { - case body == nil: - hashedPayload = hex.EncodeToString(sum256([]byte{})) - default: - payloadBytes, e := ioutil.ReadAll(body) - if e != nil { - return nil, e + // Get header map. + headerMap := make(map[string][]string) + for k, vv := range req.Header { + // If request header key is not in ignored headers, then add it. + if _, ok := ignoredHeaders[http.CanonicalHeaderKey(k)]; !ok { + headerMap[strings.ToLower(k)] = vv } - hashedPayload = hex.EncodeToString(sum256(payloadBytes)) - md5Base64 := base64.StdEncoding.EncodeToString(sumMD5(payloadBytes)) - req.Header.Set("Content-Md5", md5Base64) } - req.Header.Set("x-amz-content-sha256", hashedPayload) - // Seek back to beginning. - if body != nil { - body.Seek(0, 0) - // Add body - req.Body = ioutil.NopCloser(body) - } else { - // this is added to avoid panic during ioutil.ReadAll(req.Body). - // th stack trace can be found here https://github.com/minio/minio/pull/2074 . - // This is very similar to https://github.com/golang/go/issues/7527. - req.Body = ioutil.NopCloser(bytes.NewReader([]byte(""))) + // Get header keys. + headers := []string{"host"} + for k := range headerMap { + headers = append(headers, k) } - - var headers []string - vals := make(map[string][]string) - for k, vv := range req.Header { - if _, ok := ignoredHeaders[http.CanonicalHeaderKey(k)]; ok { - continue // ignored header - } - headers = append(headers, strings.ToLower(k)) - vals[strings.ToLower(k)] = vv - } - headers = append(headers, "host") sort.Strings(headers) - var canonicalHeaders bytes.Buffer + // Get canonical headers. + var buf bytes.Buffer for _, k := range headers { - canonicalHeaders.WriteString(k) - canonicalHeaders.WriteByte(':') + buf.WriteString(k) + buf.WriteByte(':') switch { case k == "host": - canonicalHeaders.WriteString(req.URL.Host) + buf.WriteString(req.URL.Host) fallthrough default: - for idx, v := range vals[k] { + for idx, v := range headerMap[k] { if idx > 0 { - canonicalHeaders.WriteByte(',') + buf.WriteByte(',') } - canonicalHeaders.WriteString(v) + buf.WriteString(v) } - canonicalHeaders.WriteByte('\n') + buf.WriteByte('\n') } } + canonicalHeaders := buf.String() + // Get signed headers. signedHeaders := strings.Join(headers, ";") + // Get canonical query string. req.URL.RawQuery = strings.Replace(req.URL.Query().Encode(), "+", "%20", -1) - encodedPath := getURLEncodedName(req.URL.Path) - // convert any space strings back to "+" - encodedPath = strings.Replace(encodedPath, "+", "%20", -1) - // + // Get canonical URI. + canonicalURI := getURLEncodedName(req.URL.Path) + + // Get canonical request. // canonicalRequest = // \n // \n @@ -259,25 +235,26 @@ func newTestRequest(method, urlStr string, contentLength int64, body io.ReadSeek // canonicalRequest := strings.Join([]string{ req.Method, - encodedPath, + canonicalURI, req.URL.RawQuery, - canonicalHeaders.String(), + canonicalHeaders, signedHeaders, hashedPayload, }, "\n") + // Get scope. scope := strings.Join([]string{ - t.Format(yyyymmdd), + currTime.Format(yyyymmdd), "us-east-1", "s3", "aws4_request", }, "/") - stringToSign := "AWS4-HMAC-SHA256" + "\n" + t.Format(iso8601Format) + "\n" + stringToSign := "AWS4-HMAC-SHA256" + "\n" + currTime.Format(iso8601Format) + "\n" stringToSign = stringToSign + scope + "\n" stringToSign = stringToSign + hex.EncodeToString(sum256([]byte(canonicalRequest))) - date := sumHMAC([]byte("AWS4"+secretKey), []byte(t.Format(yyyymmdd))) + date := sumHMAC([]byte("AWS4"+secretKey), []byte(currTime.Format(yyyymmdd))) region := sumHMAC(date, []byte("us-east-1")) service := sumHMAC(region, []byte("s3")) signingKey := sumHMAC(service, []byte("aws4_request")) @@ -293,6 +270,66 @@ func newTestRequest(method, urlStr string, contentLength int64, body io.ReadSeek auth := strings.Join(parts, ", ") req.Header.Set("Authorization", auth) + return nil +} + +// Returns new HTTP request object. +func newTestRequest(method, urlStr string, contentLength int64, body io.ReadSeeker) (*http.Request, error) { + if method == "" { + method = "POST" + } + + req, err := http.NewRequest(method, urlStr, nil) + if err != nil { + return nil, err + } + + // Add Content-Length + req.ContentLength = contentLength + + // Save for subsequent use + var hashedPayload string + switch { + case body == nil: + hashedPayload = hex.EncodeToString(sum256([]byte{})) + default: + payloadBytes, e := ioutil.ReadAll(body) + if e != nil { + return nil, e + } + hashedPayload = hex.EncodeToString(sum256(payloadBytes)) + md5Base64 := base64.StdEncoding.EncodeToString(sumMD5(payloadBytes)) + req.Header.Set("Content-Md5", md5Base64) + } + req.Header.Set("x-amz-content-sha256", hashedPayload) + + // Seek back to beginning. + if body != nil { + body.Seek(0, 0) + // Add body + req.Body = ioutil.NopCloser(body) + } else { + // this is added to avoid panic during ioutil.ReadAll(req.Body). + // th stack trace can be found here https://github.com/minio/minio/pull/2074 . + // This is very similar to https://github.com/golang/go/issues/7527. + req.Body = ioutil.NopCloser(bytes.NewReader([]byte(""))) + } + + return req, nil +} + +// Returns new HTTP request object signed with signature v4. +func newTestSignedRequest(method, urlStr string, contentLength int64, body io.ReadSeeker, accessKey, secretKey string) (*http.Request, error) { + req, err := newTestRequest(method, urlStr, contentLength, body) + if err != nil { + return nil, err + } + + err = signRequest(req, accessKey, secretKey) + if err != nil { + return nil, err + } + return req, nil }