storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/server_test.go (about)

     1  /*
     2   * MinIO Cloud Storage, (C) 2015, 2016, 2017, 2018 MinIO, Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package cmd
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/xml"
    22  	"fmt"
    23  	"io"
    24  	"io/ioutil"
    25  	"math/rand"
    26  	"net/http"
    27  	"net/url"
    28  	"reflect"
    29  	"strings"
    30  	"sync"
    31  	"testing"
    32  	"time"
    33  
    34  	humanize "github.com/dustin/go-humanize"
    35  	"github.com/minio/minio-go/v7/pkg/set"
    36  
    37  	xhttp "storj.io/minio/cmd/http"
    38  	"storj.io/minio/pkg/bucket/policy"
    39  )
    40  
    41  // API suite container common to both FS and Erasure.
    42  type TestSuiteCommon struct {
    43  	serverType string
    44  	testServer TestServer
    45  	endPoint   string
    46  	accessKey  string
    47  	secretKey  string
    48  	signer     signerType
    49  	secure     bool
    50  	client     *http.Client
    51  }
    52  
    53  type check struct {
    54  	*testing.T
    55  	testType string
    56  }
    57  
    58  // Assert - checks if gotValue is same as expectedValue, if not fails the test.
    59  func (c *check) Assert(gotValue interface{}, expectedValue interface{}) {
    60  	if !reflect.DeepEqual(gotValue, expectedValue) {
    61  		c.Fatalf("Test %s:%s expected %v, got %v", getSource(2), c.testType, expectedValue, gotValue)
    62  	}
    63  }
    64  
    65  func verifyError(c *check, response *http.Response, code, description string, statusCode int) {
    66  	data, err := ioutil.ReadAll(response.Body)
    67  	c.Assert(err, nil)
    68  	errorResponse := APIErrorResponse{}
    69  	err = xml.Unmarshal(data, &errorResponse)
    70  	c.Assert(err, nil)
    71  	c.Assert(errorResponse.Code, code)
    72  	c.Assert(errorResponse.Message, description)
    73  	c.Assert(response.StatusCode, statusCode)
    74  }
    75  
    76  func runAllTests(suite *TestSuiteCommon, c *check) {
    77  	suite.SetUpSuite(c)
    78  	suite.TestCors(c)
    79  	suite.TestObjectDir(c)
    80  	suite.TestBucketPolicy(c)
    81  	suite.TestDeleteBucket(c)
    82  	suite.TestDeleteBucketNotEmpty(c)
    83  	suite.TestDeleteMultipleObjects(c)
    84  	suite.TestDeleteObject(c)
    85  	suite.TestNonExistentBucket(c)
    86  	suite.TestEmptyObject(c)
    87  	suite.TestBucket(c)
    88  	suite.TestObjectGetAnonymous(c)
    89  	suite.TestMultipleObjects(c)
    90  	suite.TestHeader(c)
    91  	suite.TestPutBucket(c)
    92  	suite.TestCopyObject(c)
    93  	suite.TestPutObject(c)
    94  	suite.TestListBuckets(c)
    95  	suite.TestValidateSignature(c)
    96  	suite.TestSHA256Mismatch(c)
    97  	suite.TestPutObjectLongName(c)
    98  	suite.TestNotBeAbleToCreateObjectInNonexistentBucket(c)
    99  	suite.TestHeadOnObjectLastModified(c)
   100  	suite.TestHeadOnBucket(c)
   101  	suite.TestContentTypePersists(c)
   102  	suite.TestPartialContent(c)
   103  	suite.TestListObjectsHandler(c)
   104  	suite.TestListObjectsHandlerErrors(c)
   105  	suite.TestPutBucketErrors(c)
   106  	suite.TestGetObjectLarge10MiB(c)
   107  	suite.TestGetObjectLarge11MiB(c)
   108  	suite.TestGetPartialObjectMisAligned(c)
   109  	suite.TestGetPartialObjectLarge11MiB(c)
   110  	suite.TestGetPartialObjectLarge10MiB(c)
   111  	suite.TestGetObjectErrors(c)
   112  	suite.TestGetObjectRangeErrors(c)
   113  	suite.TestObjectMultipartAbort(c)
   114  	suite.TestBucketMultipartList(c)
   115  	suite.TestValidateObjectMultipartUploadID(c)
   116  	suite.TestObjectMultipartListError(c)
   117  	suite.TestObjectValidMD5(c)
   118  	suite.TestObjectMultipart(c)
   119  	suite.TearDownSuite(c)
   120  }
   121  
   122  func TestServerSuite(t *testing.T) {
   123  	testCases := []*TestSuiteCommon{
   124  		// Init and run test on FS backend with signature v4.
   125  		{serverType: "FS", signer: signerV4},
   126  		// Init and run test on FS backend with signature v2.
   127  		{serverType: "FS", signer: signerV2},
   128  		// Init and run test on FS backend, with tls enabled.
   129  		{serverType: "FS", signer: signerV4, secure: true},
   130  		// Init and run test on Erasure backend.
   131  		{serverType: "Erasure", signer: signerV4},
   132  		// Init and run test on ErasureSet backend.
   133  		{serverType: "ErasureSet", signer: signerV4},
   134  	}
   135  	GlobalCLIContext.StrictS3Compat = true
   136  	for i, testCase := range testCases {
   137  		t.Run(fmt.Sprintf("Test: %d, ServerType: %s", i+1, testCase.serverType), func(t *testing.T) {
   138  			runAllTests(testCase, &check{t, testCase.serverType})
   139  		})
   140  	}
   141  }
   142  
   143  // Setting up the test suite.
   144  // Starting the Test server with temporary FS backend.
   145  func (s *TestSuiteCommon) SetUpSuite(c *check) {
   146  	if s.secure {
   147  		cert, key, err := generateTLSCertKey("127.0.0.1")
   148  		c.Assert(err, nil)
   149  
   150  		s.testServer = StartTestTLSServer(c, s.serverType, cert, key)
   151  	} else {
   152  		s.testServer = StartTestServer(c, s.serverType)
   153  	}
   154  
   155  	s.client = s.testServer.Server.Client()
   156  	s.endPoint = s.testServer.Server.URL
   157  	s.accessKey = s.testServer.AccessKey
   158  	s.secretKey = s.testServer.SecretKey
   159  }
   160  
   161  // Called implicitly by "gopkg.in/check.v1" after all tests are run.
   162  func (s *TestSuiteCommon) TearDownSuite(c *check) {
   163  	s.testServer.Stop()
   164  }
   165  
   166  func (s *TestSuiteCommon) TestBucketSQSNotificationWebHook(c *check) {
   167  	// Sample bucket notification.
   168  	bucketNotificationBuf := `<NotificationConfiguration><QueueConfiguration><Event>s3:ObjectCreated:Put</Event><Filter><S3Key><FilterRule><Name>prefix</Name><Value>images/</Value></FilterRule></S3Key></Filter><Id>1</Id><Queue>arn:minio:sqs:us-east-1:444455556666:webhook</Queue></QueueConfiguration></NotificationConfiguration>`
   169  	// generate a random bucket Name.
   170  	bucketName := getRandomBucketName()
   171  	// HTTP request to create the bucket.
   172  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
   173  		0, nil, s.accessKey, s.secretKey, s.signer)
   174  	c.Assert(err, nil)
   175  
   176  	// execute the request.
   177  	response, err := s.client.Do(request)
   178  	c.Assert(err, nil)
   179  
   180  	// assert the http response status code.
   181  	c.Assert(response.StatusCode, http.StatusOK)
   182  
   183  	request, err = newTestSignedRequest(http.MethodPut, getPutNotificationURL(s.endPoint, bucketName),
   184  		int64(len(bucketNotificationBuf)), bytes.NewReader([]byte(bucketNotificationBuf)), s.accessKey, s.secretKey, s.signer)
   185  	c.Assert(err, nil)
   186  
   187  	// execute the HTTP request.
   188  	response, err = s.client.Do(request)
   189  
   190  	c.Assert(err, nil)
   191  	verifyError(c, response, "InvalidArgument", "A specified destination ARN does not exist or is not well-formed. Verify the destination ARN.", http.StatusBadRequest)
   192  }
   193  
   194  func (s *TestSuiteCommon) TestCors(c *check) {
   195  	expectedMap := http.Header{}
   196  	expectedMap.Set("Access-Control-Allow-Credentials", "true")
   197  	expectedMap.Set("Access-Control-Allow-Origin", "http://foobar.com")
   198  	expectedMap["Access-Control-Expose-Headers"] = []string{
   199  		"Date",
   200  		"Etag",
   201  		"Server",
   202  		"Connection",
   203  		"Accept-Ranges",
   204  		"Content-Range",
   205  		"Content-Encoding",
   206  		"Content-Length",
   207  		"Content-Type",
   208  		"Content-Disposition",
   209  		"Last-Modified",
   210  		"Content-Language",
   211  		"Cache-Control",
   212  		"Retry-After",
   213  		"X-Amz-Bucket-Region",
   214  		"Expires",
   215  		"X-Amz*",
   216  		"X-Amz*",
   217  		"*",
   218  	}
   219  	expectedMap.Set("Vary", "Origin")
   220  
   221  	req, _ := http.NewRequest(http.MethodOptions, s.endPoint, nil)
   222  	req.Header.Set("Origin", "http://foobar.com")
   223  	res, err := s.client.Do(req)
   224  	if err != nil {
   225  		c.Fatal(err)
   226  	}
   227  
   228  	for k := range expectedMap {
   229  		if v, ok := res.Header[k]; !ok {
   230  			c.Errorf("Expected key %s missing from %v", k, res.Header)
   231  		} else {
   232  			expectedSet := set.CreateStringSet(expectedMap[k]...)
   233  			gotSet := set.CreateStringSet(strings.Split(v[0], ", ")...)
   234  			if !expectedSet.Equals(gotSet) {
   235  				c.Errorf("Expected value %v, got %v", strings.Join(expectedMap[k], ", "), v)
   236  			}
   237  		}
   238  	}
   239  
   240  }
   241  
   242  func (s *TestSuiteCommon) TestObjectDir(c *check) {
   243  	bucketName := getRandomBucketName()
   244  	// HTTP request to create the bucket.
   245  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
   246  		0, nil, s.accessKey, s.secretKey, s.signer)
   247  	c.Assert(err, nil)
   248  
   249  	// execute the request.
   250  	response, err := s.client.Do(request)
   251  	c.Assert(err, nil)
   252  
   253  	// assert the http response status code.
   254  	c.Assert(response.StatusCode, http.StatusOK)
   255  
   256  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, "my-object-directory/"),
   257  		0, nil, s.accessKey, s.secretKey, s.signer)
   258  	c.Assert(err, nil)
   259  
   260  	// execute the HTTP request.
   261  	response, err = s.client.Do(request)
   262  
   263  	c.Assert(err, nil)
   264  	// assert the http response status code.
   265  	c.Assert(response.StatusCode, http.StatusOK)
   266  
   267  	request, err = newTestSignedRequest(http.MethodHead, getHeadObjectURL(s.endPoint, bucketName, "my-object-directory/"),
   268  		0, nil, s.accessKey, s.secretKey, s.signer)
   269  	c.Assert(err, nil)
   270  
   271  	// execute the HTTP request.
   272  	response, err = s.client.Do(request)
   273  
   274  	c.Assert(err, nil)
   275  	c.Assert(response.StatusCode, http.StatusOK)
   276  
   277  	request, err = newTestSignedRequest(http.MethodGet, getGetObjectURL(s.endPoint, bucketName, "my-object-directory/"),
   278  		0, nil, s.accessKey, s.secretKey, s.signer)
   279  	c.Assert(err, nil)
   280  
   281  	// execute the HTTP request.
   282  	response, err = s.client.Do(request)
   283  
   284  	c.Assert(err, nil)
   285  	c.Assert(response.StatusCode, http.StatusOK)
   286  
   287  	request, err = newTestSignedRequest(http.MethodDelete, getDeleteObjectURL(s.endPoint, bucketName, "my-object-directory/"),
   288  		0, nil, s.accessKey, s.secretKey, s.signer)
   289  	c.Assert(err, nil)
   290  
   291  	// execute the HTTP request.
   292  	response, err = s.client.Do(request)
   293  
   294  	c.Assert(err, nil)
   295  	c.Assert(response.StatusCode, http.StatusNoContent)
   296  }
   297  
   298  func (s *TestSuiteCommon) TestBucketSQSNotificationAMQP(c *check) {
   299  	// Sample bucket notification.
   300  	bucketNotificationBuf := `<NotificationConfiguration><QueueConfiguration><Event>s3:ObjectCreated:Put</Event><Filter><S3Key><FilterRule><Name>prefix</Name><Value>images/</Value></FilterRule></S3Key></Filter><Id>1</Id><Queue>arn:minio:sqs:us-east-1:444455556666:amqp</Queue></QueueConfiguration></NotificationConfiguration>`
   301  	// generate a random bucket Name.
   302  	bucketName := getRandomBucketName()
   303  	// HTTP request to create the bucket.
   304  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
   305  		0, nil, s.accessKey, s.secretKey, s.signer)
   306  	c.Assert(err, nil)
   307  
   308  	// execute the request.
   309  	response, err := s.client.Do(request)
   310  	c.Assert(err, nil)
   311  
   312  	// assert the http response status code.
   313  	c.Assert(response.StatusCode, http.StatusOK)
   314  
   315  	request, err = newTestSignedRequest(http.MethodPut, getPutNotificationURL(s.endPoint, bucketName),
   316  		int64(len(bucketNotificationBuf)), bytes.NewReader([]byte(bucketNotificationBuf)), s.accessKey, s.secretKey, s.signer)
   317  	c.Assert(err, nil)
   318  
   319  	// execute the HTTP request.
   320  	response, err = s.client.Do(request)
   321  
   322  	c.Assert(err, nil)
   323  	verifyError(c, response, "InvalidArgument", "A specified destination ARN does not exist or is not well-formed. Verify the destination ARN.", http.StatusBadRequest)
   324  }
   325  
   326  // TestBucketPolicy - Inserts the bucket policy and verifies it by fetching the policy back.
   327  // Deletes the policy and verifies the deletion by fetching it back.
   328  func (s *TestSuiteCommon) TestBucketPolicy(c *check) {
   329  	// Sample bucket policy.
   330  	bucketPolicyBuf := `{"Version":"2012-10-17","Statement":[{"Action":["s3:GetBucketLocation","s3:ListBucket"],"Effect":"Allow","Principal":{"AWS":["*"]},"Resource":["arn:aws:s3:::%s"]},{"Action":["s3:GetObject"],"Effect":"Allow","Principal":{"AWS":["*"]},"Resource":["arn:aws:s3:::%s/this*"]}]}`
   331  
   332  	// generate a random bucket Name.
   333  	bucketName := getRandomBucketName()
   334  	// create the policy statement string with the randomly generated bucket name.
   335  	bucketPolicyStr := fmt.Sprintf(bucketPolicyBuf, bucketName, bucketName)
   336  	// HTTP request to create the bucket.
   337  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
   338  		0, nil, s.accessKey, s.secretKey, s.signer)
   339  	c.Assert(err, nil)
   340  
   341  	// execute the request.
   342  	response, err := s.client.Do(request)
   343  	c.Assert(err, nil)
   344  	// assert the http response status code.
   345  	c.Assert(response.StatusCode, http.StatusOK)
   346  
   347  	/// Put a new bucket policy.
   348  	request, err = newTestSignedRequest(http.MethodPut, getPutPolicyURL(s.endPoint, bucketName),
   349  		int64(len(bucketPolicyStr)), bytes.NewReader([]byte(bucketPolicyStr)), s.accessKey, s.secretKey, s.signer)
   350  	c.Assert(err, nil)
   351  
   352  	// execute the HTTP request to create bucket.
   353  	response, err = s.client.Do(request)
   354  	c.Assert(err, nil)
   355  	c.Assert(response.StatusCode, http.StatusNoContent)
   356  
   357  	// Fetch the uploaded policy.
   358  	request, err = newTestSignedRequest(http.MethodGet, getGetPolicyURL(s.endPoint, bucketName), 0, nil,
   359  		s.accessKey, s.secretKey, s.signer)
   360  	c.Assert(err, nil)
   361  
   362  	response, err = s.client.Do(request)
   363  	c.Assert(err, nil)
   364  	c.Assert(response.StatusCode, http.StatusOK)
   365  
   366  	bucketPolicyReadBuf, err := ioutil.ReadAll(response.Body)
   367  	c.Assert(err, nil)
   368  	// Verify if downloaded policy matches with previously uploaded.
   369  	expectedPolicy, err := policy.ParseConfig(strings.NewReader(bucketPolicyStr), bucketName)
   370  	c.Assert(err, nil)
   371  	gotPolicy, err := policy.ParseConfig(bytes.NewReader(bucketPolicyReadBuf), bucketName)
   372  	c.Assert(err, nil)
   373  	c.Assert(reflect.DeepEqual(expectedPolicy, gotPolicy), true)
   374  
   375  	// Delete policy.
   376  	request, err = newTestSignedRequest(http.MethodDelete, getDeletePolicyURL(s.endPoint, bucketName), 0, nil,
   377  		s.accessKey, s.secretKey, s.signer)
   378  	c.Assert(err, nil)
   379  
   380  	response, err = s.client.Do(request)
   381  	c.Assert(err, nil)
   382  	c.Assert(response.StatusCode, http.StatusNoContent)
   383  
   384  	// Verify if the policy was indeed deleted.
   385  	request, err = newTestSignedRequest(http.MethodGet, getGetPolicyURL(s.endPoint, bucketName),
   386  		0, nil, s.accessKey, s.secretKey, s.signer)
   387  	c.Assert(err, nil)
   388  
   389  	response, err = s.client.Do(request)
   390  	c.Assert(err, nil)
   391  	c.Assert(response.StatusCode, http.StatusNotFound)
   392  }
   393  
   394  // TestDeleteBucket - validates DELETE bucket operation.
   395  func (s *TestSuiteCommon) TestDeleteBucket(c *check) {
   396  	bucketName := getRandomBucketName()
   397  
   398  	// HTTP request to create the bucket.
   399  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
   400  		0, nil, s.accessKey, s.secretKey, s.signer)
   401  	c.Assert(err, nil)
   402  
   403  	response, err := s.client.Do(request)
   404  	c.Assert(err, nil)
   405  	// assert the response status code.
   406  	c.Assert(response.StatusCode, http.StatusOK)
   407  
   408  	// construct request to delete the bucket.
   409  	request, err = newTestSignedRequest(http.MethodDelete, getDeleteBucketURL(s.endPoint, bucketName),
   410  		0, nil, s.accessKey, s.secretKey, s.signer)
   411  	c.Assert(err, nil)
   412  
   413  	response, err = s.client.Do(request)
   414  	c.Assert(err, nil)
   415  	// Assert the response status code.
   416  	c.Assert(response.StatusCode, http.StatusNoContent)
   417  }
   418  
   419  // TestDeleteBucketNotEmpty - Validates the operation during an attempt to delete a non-empty bucket.
   420  func (s *TestSuiteCommon) TestDeleteBucketNotEmpty(c *check) {
   421  	// generate a random bucket name.
   422  	bucketName := getRandomBucketName()
   423  
   424  	// HTTP request to create the bucket.
   425  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
   426  		0, nil, s.accessKey, s.secretKey, s.signer)
   427  	c.Assert(err, nil)
   428  
   429  	// execute the request.
   430  	response, err := s.client.Do(request)
   431  	c.Assert(err, nil)
   432  	// assert the response status code.
   433  	c.Assert(response.StatusCode, http.StatusOK)
   434  
   435  	// generate http request for an object upload.
   436  	// "test-object" is the object name.
   437  	objectName := "test-object"
   438  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objectName),
   439  		0, nil, s.accessKey, s.secretKey, s.signer)
   440  	c.Assert(err, nil)
   441  
   442  	// execute the request to complete object upload.
   443  	response, err = s.client.Do(request)
   444  	c.Assert(err, nil)
   445  	// assert the status code of the response.
   446  	c.Assert(response.StatusCode, http.StatusOK)
   447  
   448  	// constructing http request to delete the bucket.
   449  	// making an attempt to delete an non-empty bucket.
   450  	// expected to fail.
   451  	request, err = newTestSignedRequest(http.MethodDelete, getDeleteBucketURL(s.endPoint, bucketName),
   452  		0, nil, s.accessKey, s.secretKey, s.signer)
   453  	c.Assert(err, nil)
   454  
   455  	response, err = s.client.Do(request)
   456  	c.Assert(err, nil)
   457  	c.Assert(response.StatusCode, http.StatusConflict)
   458  
   459  }
   460  
   461  func (s *TestSuiteCommon) TestListenNotificationHandler(c *check) {
   462  	// generate a random bucket name.
   463  	bucketName := getRandomBucketName()
   464  	// HTTP request to create the bucket.
   465  	req, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
   466  		0, nil, s.accessKey, s.secretKey, s.signer)
   467  	c.Assert(err, nil)
   468  
   469  	// execute the request.
   470  	response, err := s.client.Do(req)
   471  	c.Assert(err, nil)
   472  	// assert the http response status code.
   473  	c.Assert(response.StatusCode, http.StatusOK)
   474  
   475  	invalidBucket := "Invalid\\Bucket"
   476  	tooByte := bytes.Repeat([]byte("a"), 1025)
   477  	tooBigPrefix := string(tooByte)
   478  	validEvents := []string{"s3:ObjectCreated:*", "s3:ObjectRemoved:*"}
   479  	invalidEvents := []string{"invalidEvent"}
   480  
   481  	req, err = newTestSignedRequest(http.MethodGet,
   482  		getListenNotificationURL(s.endPoint, invalidBucket, []string{}, []string{}, []string{}),
   483  		0, nil, s.accessKey, s.secretKey, s.signer)
   484  	c.Assert(err, nil)
   485  
   486  	// execute the request.
   487  	response, err = s.client.Do(req)
   488  	c.Assert(err, nil)
   489  	verifyError(c, response, "InvalidBucketName", "The specified bucket is not valid.", http.StatusBadRequest)
   490  
   491  	req, err = newTestSignedRequest(http.MethodGet,
   492  		getListenNotificationURL(s.endPoint, bucketName, []string{}, []string{}, invalidEvents),
   493  		0, nil, s.accessKey, s.secretKey, s.signer)
   494  	c.Assert(err, nil)
   495  
   496  	// execute the request.
   497  	response, err = s.client.Do(req)
   498  	c.Assert(err, nil)
   499  	verifyError(c, response, "InvalidArgument", "A specified event is not supported for notifications.", http.StatusBadRequest)
   500  
   501  	req, err = newTestSignedRequest(http.MethodGet,
   502  		getListenNotificationURL(s.endPoint, bucketName, []string{tooBigPrefix}, []string{}, validEvents),
   503  		0, nil, s.accessKey, s.secretKey, s.signer)
   504  	c.Assert(err, nil)
   505  
   506  	// execute the request.
   507  	response, err = s.client.Do(req)
   508  	c.Assert(err, nil)
   509  	verifyError(c, response, "InvalidArgument", "Size of filter rule value cannot exceed 1024 bytes in UTF-8 representation", http.StatusBadRequest)
   510  
   511  	req, err = newTestSignedBadSHARequest(http.MethodGet,
   512  		getListenNotificationURL(s.endPoint, bucketName, []string{}, []string{}, validEvents),
   513  		0, nil, s.accessKey, s.secretKey, s.signer)
   514  	c.Assert(err, nil)
   515  
   516  	// execute the request.
   517  	response, err = s.client.Do(req)
   518  	c.Assert(err, nil)
   519  	if s.signer == signerV4 {
   520  		verifyError(c, response, "XAmzContentSHA256Mismatch", "The provided 'x-amz-content-sha256' header does not match what was computed.", http.StatusBadRequest)
   521  	}
   522  }
   523  
   524  // Test deletes multiple objects and verifies server response.
   525  func (s *TestSuiteCommon) TestDeleteMultipleObjects(c *check) {
   526  	// generate a random bucket name.
   527  	bucketName := getRandomBucketName()
   528  	// HTTP request to create the bucket.
   529  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
   530  		0, nil, s.accessKey, s.secretKey, s.signer)
   531  	c.Assert(err, nil)
   532  
   533  	// execute the request.
   534  	response, err := s.client.Do(request)
   535  	c.Assert(err, nil)
   536  	// assert the http response status code.
   537  	c.Assert(response.StatusCode, http.StatusOK)
   538  
   539  	objectName := "prefix/myobject"
   540  	delObjReq := DeleteObjectsRequest{
   541  		Quiet: false,
   542  	}
   543  	for i := 0; i < 10; i++ {
   544  		// Obtain http request to upload object.
   545  		// object Name contains a prefix.
   546  		objName := fmt.Sprintf("%d/%s", i, objectName)
   547  		request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objName),
   548  			0, nil, s.accessKey, s.secretKey, s.signer)
   549  		c.Assert(err, nil)
   550  
   551  		// execute the http request.
   552  		response, err = s.client.Do(request)
   553  		c.Assert(err, nil)
   554  		// assert the status of http response.
   555  		c.Assert(response.StatusCode, http.StatusOK)
   556  		// Append all objects.
   557  		delObjReq.Objects = append(delObjReq.Objects, ObjectToDelete{
   558  			ObjectName: objName,
   559  		})
   560  	}
   561  	// Marshal delete request.
   562  	deleteReqBytes, err := xml.Marshal(delObjReq)
   563  	c.Assert(err, nil)
   564  
   565  	// Delete list of objects.
   566  	request, err = newTestSignedRequest(http.MethodPost, getMultiDeleteObjectURL(s.endPoint, bucketName),
   567  		int64(len(deleteReqBytes)), bytes.NewReader(deleteReqBytes), s.accessKey, s.secretKey, s.signer)
   568  	c.Assert(err, nil)
   569  	response, err = s.client.Do(request)
   570  	c.Assert(err, nil)
   571  	c.Assert(response.StatusCode, http.StatusOK)
   572  
   573  	var deleteResp = DeleteObjectsResponse{}
   574  	delRespBytes, err := ioutil.ReadAll(response.Body)
   575  	c.Assert(err, nil)
   576  	err = xml.Unmarshal(delRespBytes, &deleteResp)
   577  	c.Assert(err, nil)
   578  	for i := 0; i < 10; i++ {
   579  		// All the objects should be under deleted list (including non-existent object)
   580  		c.Assert(deleteResp.DeletedObjects[i], DeletedObject{
   581  			ObjectName: delObjReq.Objects[i].ObjectName,
   582  			VersionID:  delObjReq.Objects[i].VersionID,
   583  		})
   584  	}
   585  	c.Assert(len(deleteResp.Errors), 0)
   586  
   587  	// Attempt second time results should be same, NoSuchKey for objects not found
   588  	// shouldn't be set.
   589  	request, err = newTestSignedRequest(http.MethodPost, getMultiDeleteObjectURL(s.endPoint, bucketName),
   590  		int64(len(deleteReqBytes)), bytes.NewReader(deleteReqBytes), s.accessKey, s.secretKey, s.signer)
   591  	c.Assert(err, nil)
   592  	response, err = s.client.Do(request)
   593  	c.Assert(err, nil)
   594  	c.Assert(response.StatusCode, http.StatusOK)
   595  
   596  	deleteResp = DeleteObjectsResponse{}
   597  	delRespBytes, err = ioutil.ReadAll(response.Body)
   598  	c.Assert(err, nil)
   599  	err = xml.Unmarshal(delRespBytes, &deleteResp)
   600  	c.Assert(err, nil)
   601  	c.Assert(len(deleteResp.DeletedObjects), len(delObjReq.Objects))
   602  	for i := 0; i < 10; i++ {
   603  		c.Assert(deleteResp.DeletedObjects[i], DeletedObject{
   604  			ObjectName: delObjReq.Objects[i].ObjectName,
   605  			VersionID:  delObjReq.Objects[i].VersionID,
   606  		})
   607  	}
   608  	c.Assert(len(deleteResp.Errors), 0)
   609  }
   610  
   611  // Tests delete object responses and success.
   612  func (s *TestSuiteCommon) TestDeleteObject(c *check) {
   613  	// generate a random bucket name.
   614  	bucketName := getRandomBucketName()
   615  	// HTTP request to create the bucket.
   616  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
   617  		0, nil, s.accessKey, s.secretKey, s.signer)
   618  	c.Assert(err, nil)
   619  
   620  	// execute the request.
   621  	response, err := s.client.Do(request)
   622  	c.Assert(err, nil)
   623  	// assert the http response status code.
   624  	c.Assert(response.StatusCode, http.StatusOK)
   625  
   626  	objectName := "prefix/myobject"
   627  	// obtain http request to upload object.
   628  	// object Name contains a prefix.
   629  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objectName),
   630  		0, nil, s.accessKey, s.secretKey, s.signer)
   631  	c.Assert(err, nil)
   632  
   633  	// execute the http request.
   634  	response, err = s.client.Do(request)
   635  	c.Assert(err, nil)
   636  	// assert the status of http response.
   637  	c.Assert(response.StatusCode, http.StatusOK)
   638  
   639  	// object name was "prefix/myobject", an attempt to delete "prefix"
   640  	// Should not delete "prefix/myobject"
   641  	request, err = newTestSignedRequest(http.MethodDelete, getDeleteObjectURL(s.endPoint, bucketName, "prefix"),
   642  		0, nil, s.accessKey, s.secretKey, s.signer)
   643  	c.Assert(err, nil)
   644  	response, err = s.client.Do(request)
   645  	c.Assert(err, nil)
   646  	c.Assert(response.StatusCode, http.StatusNoContent)
   647  
   648  	// create http request to HEAD on the object.
   649  	// this helps to validate the existence of the bucket.
   650  	request, err = newTestSignedRequest(http.MethodHead, getHeadObjectURL(s.endPoint, bucketName, objectName),
   651  		0, nil, s.accessKey, s.secretKey, s.signer)
   652  	c.Assert(err, nil)
   653  
   654  	response, err = s.client.Do(request)
   655  	c.Assert(err, nil)
   656  	// Assert the HTTP response status code.
   657  	c.Assert(response.StatusCode, http.StatusOK)
   658  
   659  	// create HTTP request to delete the object.
   660  	request, err = newTestSignedRequest(http.MethodDelete, getDeleteObjectURL(s.endPoint, bucketName, objectName),
   661  		0, nil, s.accessKey, s.secretKey, s.signer)
   662  	c.Assert(err, nil)
   663  	// execute the http request.
   664  	response, err = s.client.Do(request)
   665  	c.Assert(err, nil)
   666  	// assert the http response status code.
   667  	c.Assert(response.StatusCode, http.StatusNoContent)
   668  
   669  	// Delete of non-existent data should return success.
   670  	request, err = newTestSignedRequest(http.MethodDelete, getDeleteObjectURL(s.endPoint, bucketName, "prefix/myobject1"),
   671  		0, nil, s.accessKey, s.secretKey, s.signer)
   672  	c.Assert(err, nil)
   673  	// execute the http request.
   674  	response, err = s.client.Do(request)
   675  	c.Assert(err, nil)
   676  	// assert the http response status.
   677  	c.Assert(response.StatusCode, http.StatusNoContent)
   678  }
   679  
   680  // TestNonExistentBucket - Asserts response for HEAD on non-existent bucket.
   681  func (s *TestSuiteCommon) TestNonExistentBucket(c *check) {
   682  	// generate a random bucket name.
   683  	bucketName := getRandomBucketName()
   684  	// create request to HEAD on the bucket.
   685  	// HEAD on an bucket helps validate the existence of the bucket.
   686  	request, err := newTestSignedRequest(http.MethodHead, getHEADBucketURL(s.endPoint, bucketName),
   687  		0, nil, s.accessKey, s.secretKey, s.signer)
   688  	c.Assert(err, nil)
   689  
   690  	// execute the http request.
   691  	response, err := s.client.Do(request)
   692  	c.Assert(err, nil)
   693  	// Assert the response.
   694  	c.Assert(response.StatusCode, http.StatusNotFound)
   695  }
   696  
   697  // TestEmptyObject - Asserts the response for operation on a 0 byte object.
   698  func (s *TestSuiteCommon) TestEmptyObject(c *check) {
   699  	// generate a random bucket name.
   700  	bucketName := getRandomBucketName()
   701  	// HTTP request to create the bucket.
   702  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
   703  		0, nil, s.accessKey, s.secretKey, s.signer)
   704  	c.Assert(err, nil)
   705  
   706  	// execute the http request.
   707  	response, err := s.client.Do(request)
   708  	c.Assert(err, nil)
   709  	// assert the http response status code.
   710  	c.Assert(response.StatusCode, http.StatusOK)
   711  
   712  	objectName := "test-object"
   713  	// construct http request for uploading the object.
   714  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objectName),
   715  		0, nil, s.accessKey, s.secretKey, s.signer)
   716  	c.Assert(err, nil)
   717  
   718  	// execute the upload request.
   719  	response, err = s.client.Do(request)
   720  	c.Assert(err, nil)
   721  	// assert the http response.
   722  	c.Assert(response.StatusCode, http.StatusOK)
   723  
   724  	// make HTTP request to fetch the object.
   725  	request, err = newTestSignedRequest(http.MethodGet, getGetObjectURL(s.endPoint, bucketName, objectName),
   726  		0, nil, s.accessKey, s.secretKey, s.signer)
   727  	c.Assert(err, nil)
   728  
   729  	// execute the http request to fetch object.
   730  	response, err = s.client.Do(request)
   731  	c.Assert(err, nil)
   732  	// assert the http response status code.
   733  	c.Assert(response.StatusCode, http.StatusOK)
   734  
   735  	var buffer bytes.Buffer
   736  	// extract the body of the response.
   737  	responseBody, err := ioutil.ReadAll(response.Body)
   738  	c.Assert(err, nil)
   739  	// assert the http response body content.
   740  	c.Assert(true, bytes.Equal(responseBody, buffer.Bytes()))
   741  }
   742  
   743  func (s *TestSuiteCommon) TestBucket(c *check) {
   744  	// generate a random bucket name.
   745  	bucketName := getRandomBucketName()
   746  
   747  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
   748  		0, nil, s.accessKey, s.secretKey, s.signer)
   749  	c.Assert(err, nil)
   750  
   751  	response, err := s.client.Do(request)
   752  	c.Assert(err, nil)
   753  	c.Assert(response.StatusCode, http.StatusOK)
   754  
   755  	request, err = newTestSignedRequest(http.MethodHead, getMakeBucketURL(s.endPoint, bucketName),
   756  		0, nil, s.accessKey, s.secretKey, s.signer)
   757  	c.Assert(err, nil)
   758  
   759  	response, err = s.client.Do(request)
   760  	c.Assert(err, nil)
   761  	c.Assert(response.StatusCode, http.StatusOK)
   762  }
   763  
   764  // Tests get anonymous object.
   765  func (s *TestSuiteCommon) TestObjectGetAnonymous(c *check) {
   766  	// generate a random bucket name.
   767  	bucketName := getRandomBucketName()
   768  	buffer := bytes.NewReader([]byte("hello world"))
   769  	// HTTP request to create the bucket.
   770  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
   771  		0, nil, s.accessKey, s.secretKey, s.signer)
   772  	c.Assert(err, nil)
   773  
   774  	// execute the make bucket http request.
   775  	response, err := s.client.Do(request)
   776  	c.Assert(err, nil)
   777  	// assert the response http status code.
   778  	c.Assert(response.StatusCode, http.StatusOK)
   779  
   780  	objectName := "testObject"
   781  	// create HTTP request to upload the object.
   782  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objectName),
   783  		int64(buffer.Len()), buffer, s.accessKey, s.secretKey, s.signer)
   784  	c.Assert(err, nil)
   785  
   786  	// execute the HTTP request to upload the object.
   787  	response, err = s.client.Do(request)
   788  	c.Assert(err, nil)
   789  	// assert the HTTP response status code.
   790  	c.Assert(response.StatusCode, http.StatusOK)
   791  
   792  	// initiate anonymous HTTP request to fetch the object which does not exist. We need to return AccessDenied.
   793  	response, err = s.client.Get(getGetObjectURL(s.endPoint, bucketName, objectName+".1"))
   794  	c.Assert(err, nil)
   795  	// assert the http response status code.
   796  	verifyError(c, response, "AccessDenied", "Access Denied.", http.StatusForbidden)
   797  
   798  	// initiate anonymous HTTP request to fetch the object which does exist. We need to return AccessDenied.
   799  	response, err = s.client.Get(getGetObjectURL(s.endPoint, bucketName, objectName))
   800  	c.Assert(err, nil)
   801  	// assert the http response status code.
   802  	verifyError(c, response, "AccessDenied", "Access Denied.", http.StatusForbidden)
   803  }
   804  
   805  // TestMultipleObjects - Validates upload and fetching of multiple object into the bucket.
   806  func (s *TestSuiteCommon) TestMultipleObjects(c *check) {
   807  	// generate a random bucket name.
   808  	bucketName := getRandomBucketName()
   809  	// HTTP request to create the bucket.
   810  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
   811  		0, nil, s.accessKey, s.secretKey, s.signer)
   812  	c.Assert(err, nil)
   813  
   814  	// execute the HTTP request to create the bucket.
   815  	response, err := s.client.Do(request)
   816  	c.Assert(err, nil)
   817  	c.Assert(response.StatusCode, http.StatusOK)
   818  
   819  	// constructing HTTP request to fetch a non-existent object.
   820  	// expected to fail, error response asserted for expected error values later.
   821  	objectName := "testObject"
   822  	request, err = newTestSignedRequest(http.MethodGet, getGetObjectURL(s.endPoint, bucketName, objectName),
   823  		0, nil, s.accessKey, s.secretKey, s.signer)
   824  	c.Assert(err, nil)
   825  
   826  	// execute the HTTP request.
   827  	response, err = s.client.Do(request)
   828  	c.Assert(err, nil)
   829  	// Asserting the error response with the expected values.
   830  	verifyError(c, response, "NoSuchKey", "The specified key does not exist.", http.StatusNotFound)
   831  
   832  	objectName = "testObject1"
   833  	// content for the object to be uploaded.
   834  	buffer1 := bytes.NewReader([]byte("hello one"))
   835  	// create HTTP request for the object upload.
   836  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objectName),
   837  		int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey, s.signer)
   838  	c.Assert(err, nil)
   839  
   840  	// execute the HTTP request for object upload.
   841  	response, err = s.client.Do(request)
   842  	c.Assert(err, nil)
   843  	// assert the returned values.
   844  	c.Assert(response.StatusCode, http.StatusOK)
   845  
   846  	// create HTTP request to fetch the object which was uploaded above.
   847  	request, err = newTestSignedRequest(http.MethodGet, getGetObjectURL(s.endPoint, bucketName, objectName),
   848  		0, nil, s.accessKey, s.secretKey, s.signer)
   849  	c.Assert(err, nil)
   850  
   851  	// execute the HTTP request.
   852  	response, err = s.client.Do(request)
   853  	c.Assert(err, nil)
   854  	// assert whether 200 OK response status is obtained.
   855  	c.Assert(response.StatusCode, http.StatusOK)
   856  
   857  	// extract the response body.
   858  	responseBody, err := ioutil.ReadAll(response.Body)
   859  	c.Assert(err, nil)
   860  	// assert the content body for the expected object data.
   861  	c.Assert(true, bytes.Equal(responseBody, []byte("hello one")))
   862  
   863  	// data for new object to be uploaded.
   864  	buffer2 := bytes.NewReader([]byte("hello two"))
   865  	objectName = "testObject2"
   866  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objectName),
   867  		int64(buffer2.Len()), buffer2, s.accessKey, s.secretKey, s.signer)
   868  	c.Assert(err, nil)
   869  
   870  	// execute the HTTP request for object upload.
   871  	response, err = s.client.Do(request)
   872  	c.Assert(err, nil)
   873  	// assert the response status code for expected value 200 OK.
   874  	c.Assert(response.StatusCode, http.StatusOK)
   875  	// fetch the object which was uploaded above.
   876  	request, err = newTestSignedRequest(http.MethodGet, getGetObjectURL(s.endPoint, bucketName, objectName),
   877  		0, nil, s.accessKey, s.secretKey, s.signer)
   878  	c.Assert(err, nil)
   879  
   880  	// execute the HTTP request to fetch the object.
   881  	response, err = s.client.Do(request)
   882  	c.Assert(err, nil)
   883  	// assert the response status code for expected value 200 OK.
   884  	c.Assert(response.StatusCode, http.StatusOK)
   885  
   886  	// verify response data
   887  	responseBody, err = ioutil.ReadAll(response.Body)
   888  	c.Assert(err, nil)
   889  	c.Assert(true, bytes.Equal(responseBody, []byte("hello two")))
   890  
   891  	// data for new object to be uploaded.
   892  	buffer3 := bytes.NewReader([]byte("hello three"))
   893  	objectName = "testObject3"
   894  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objectName),
   895  		int64(buffer3.Len()), buffer3, s.accessKey, s.secretKey, s.signer)
   896  	c.Assert(err, nil)
   897  
   898  	// execute HTTP request.
   899  	response, err = s.client.Do(request)
   900  	c.Assert(err, nil)
   901  	// verify the response code with the expected value of 200 OK.
   902  	c.Assert(response.StatusCode, http.StatusOK)
   903  
   904  	// fetch the object which was uploaded above.
   905  	request, err = newTestSignedRequest(http.MethodGet, getPutObjectURL(s.endPoint, bucketName, objectName),
   906  		0, nil, s.accessKey, s.secretKey, s.signer)
   907  	c.Assert(err, nil)
   908  
   909  	response, err = s.client.Do(request)
   910  	c.Assert(err, nil)
   911  	c.Assert(response.StatusCode, http.StatusOK)
   912  
   913  	// verify object.
   914  	responseBody, err = ioutil.ReadAll(response.Body)
   915  	c.Assert(err, nil)
   916  	c.Assert(true, bytes.Equal(responseBody, []byte("hello three")))
   917  }
   918  
   919  // TestHeader - Validates the error response for an attempt to fetch non-existent object.
   920  func (s *TestSuiteCommon) TestHeader(c *check) {
   921  	// generate a random bucket name.
   922  	bucketName := getRandomBucketName()
   923  	// obtain HTTP request to fetch an object from non-existent bucket/object.
   924  	request, err := newTestSignedRequest(http.MethodGet, getGetObjectURL(s.endPoint, bucketName, "testObject"),
   925  		0, nil, s.accessKey, s.secretKey, s.signer)
   926  	c.Assert(err, nil)
   927  
   928  	response, err := s.client.Do(request)
   929  	c.Assert(err, nil)
   930  	// asserting for the expected error response.
   931  	verifyError(c, response, "NoSuchBucket", "The specified bucket does not exist", http.StatusNotFound)
   932  }
   933  
   934  func (s *TestSuiteCommon) TestPutBucket(c *check) {
   935  	// generate a random bucket name.
   936  	bucketName := getRandomBucketName()
   937  	// Block 1: Testing for racy access
   938  	// The assertion is removed from this block since the purpose of this block is to find races
   939  	// The purpose this block is not to check for correctness of functionality
   940  	// Run the test with -race flag to utilize this
   941  	var wg sync.WaitGroup
   942  	for i := 0; i < testConcurrencyLevel; i++ {
   943  		wg.Add(1)
   944  		go func() {
   945  			defer wg.Done()
   946  			// HTTP request to create the bucket.
   947  			request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
   948  				0, nil, s.accessKey, s.secretKey, s.signer)
   949  			c.Assert(err, nil)
   950  
   951  			response, err := s.client.Do(request)
   952  			if err != nil {
   953  				c.Errorf("Put bucket Failed: <ERROR> %s", err)
   954  				return
   955  			}
   956  			defer response.Body.Close()
   957  		}()
   958  	}
   959  	wg.Wait()
   960  
   961  	bucketName = getRandomBucketName()
   962  	//Block 2: testing for correctness of the functionality
   963  	// HTTP request to create the bucket.
   964  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
   965  		0, nil, s.accessKey, s.secretKey, s.signer)
   966  	c.Assert(err, nil)
   967  
   968  	response, err := s.client.Do(request)
   969  	c.Assert(err, nil)
   970  	c.Assert(response.StatusCode, http.StatusOK)
   971  	response.Body.Close()
   972  }
   973  
   974  // TestCopyObject - Validates copy object.
   975  // The following is the test flow.
   976  // 1. Create bucket.
   977  // 2. Insert Object.
   978  // 3. Use "X-Amz-Copy-Source" header to copy the previously created object.
   979  // 4. Validate the content of copied object.
   980  func (s *TestSuiteCommon) TestCopyObject(c *check) {
   981  	// generate a random bucket name.
   982  	bucketName := getRandomBucketName()
   983  	// HTTP request to create the bucket.
   984  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
   985  		0, nil, s.accessKey, s.secretKey, s.signer)
   986  	c.Assert(err, nil)
   987  
   988  	// execute the HTTP request to create bucket.
   989  	response, err := s.client.Do(request)
   990  	c.Assert(err, nil)
   991  	c.Assert(response.StatusCode, http.StatusOK)
   992  
   993  	// content for the object to be created.
   994  	buffer1 := bytes.NewReader([]byte("hello world"))
   995  	objectName := "testObject"
   996  	// create HTTP request for object upload.
   997  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objectName),
   998  		int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey, s.signer)
   999  	request.Header.Set("Content-Type", "application/json")
  1000  	if s.signer == signerV2 {
  1001  		c.Assert(err, nil)
  1002  		err = signRequestV2(request, s.accessKey, s.secretKey)
  1003  	}
  1004  	c.Assert(err, nil)
  1005  	// execute the HTTP request for object upload.
  1006  	response, err = s.client.Do(request)
  1007  	c.Assert(err, nil)
  1008  	c.Assert(response.StatusCode, http.StatusOK)
  1009  
  1010  	objectName2 := "testObject2"
  1011  	// Unlike the actual PUT object request, the request to Copy Object doesn't contain request body,
  1012  	// empty body with the "X-Amz-Copy-Source" header pointing to the object to copies it in the backend.
  1013  	request, err = newTestRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objectName2), 0, nil)
  1014  	c.Assert(err, nil)
  1015  	// setting the "X-Amz-Copy-Source" to allow copying the content of previously uploaded object.
  1016  	request.Header.Set("X-Amz-Copy-Source", url.QueryEscape(SlashSeparator+bucketName+SlashSeparator+objectName))
  1017  	if s.signer == signerV4 {
  1018  		err = signRequestV4(request, s.accessKey, s.secretKey)
  1019  	} else {
  1020  		err = signRequestV2(request, s.accessKey, s.secretKey)
  1021  	}
  1022  	c.Assert(err, nil)
  1023  	// execute the HTTP request.
  1024  	// the content is expected to have the content of previous disk.
  1025  	response, err = s.client.Do(request)
  1026  	c.Assert(err, nil)
  1027  	c.Assert(response.StatusCode, http.StatusOK)
  1028  
  1029  	// creating HTTP request to fetch the previously uploaded object.
  1030  	request, err = newTestSignedRequest(http.MethodGet, getGetObjectURL(s.endPoint, bucketName, objectName2),
  1031  		0, nil, s.accessKey, s.secretKey, s.signer)
  1032  	c.Assert(err, nil)
  1033  	// executing the HTTP request.
  1034  	response, err = s.client.Do(request)
  1035  	c.Assert(err, nil)
  1036  	// validating the response status code.
  1037  	c.Assert(response.StatusCode, http.StatusOK)
  1038  	// reading the response body.
  1039  	// response body is expected to have the copied content of the first uploaded object.
  1040  	object, err := ioutil.ReadAll(response.Body)
  1041  	c.Assert(err, nil)
  1042  	c.Assert(string(object), "hello world")
  1043  }
  1044  
  1045  // TestPutObject -  Tests successful put object request.
  1046  func (s *TestSuiteCommon) TestPutObject(c *check) {
  1047  	// generate a random bucket name.
  1048  	bucketName := getRandomBucketName()
  1049  	// HTTP request to create the bucket.
  1050  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
  1051  		0, nil, s.accessKey, s.secretKey, s.signer)
  1052  	c.Assert(err, nil)
  1053  
  1054  	// execute the HTTP request to create bucket.
  1055  	response, err := s.client.Do(request)
  1056  	c.Assert(err, nil)
  1057  	c.Assert(response.StatusCode, http.StatusOK)
  1058  
  1059  	// content for new object upload.
  1060  	buffer1 := bytes.NewReader([]byte("hello world"))
  1061  	objectName := "testObject"
  1062  	// creating HTTP request for object upload.
  1063  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objectName),
  1064  		int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey, s.signer)
  1065  	c.Assert(err, nil)
  1066  	// execute the HTTP request for object upload.
  1067  	response, err = s.client.Do(request)
  1068  	c.Assert(err, nil)
  1069  	c.Assert(response.StatusCode, http.StatusOK)
  1070  
  1071  	// fetch the object back and verify its contents.
  1072  	request, err = newTestSignedRequest(http.MethodGet, getGetObjectURL(s.endPoint, bucketName, objectName),
  1073  		0, nil, s.accessKey, s.secretKey, s.signer)
  1074  	c.Assert(err, nil)
  1075  	// execute the HTTP request to fetch the object.
  1076  	response, err = s.client.Do(request)
  1077  	c.Assert(err, nil)
  1078  	c.Assert(response.StatusCode, http.StatusOK)
  1079  	c.Assert(response.ContentLength, int64(len([]byte("hello world"))))
  1080  	var buffer2 bytes.Buffer
  1081  	// retrieve the contents of response body.
  1082  	n, err := io.Copy(&buffer2, response.Body)
  1083  	c.Assert(err, nil)
  1084  	c.Assert(n, int64(len([]byte("hello world"))))
  1085  	// asserted the contents of the fetched object with the expected result.
  1086  	c.Assert(true, bytes.Equal(buffer2.Bytes(), []byte("hello world")))
  1087  
  1088  	// Test the response when object name ends with a slash.
  1089  	// This is a special case with size as '0' and object ends with
  1090  	// a slash separator, we treat it like a valid operation and
  1091  	// return success.
  1092  	// The response Etag headers should contain Md5Sum of empty string.
  1093  	objectName = "objectwith/"
  1094  	// create HTTP request for object upload.
  1095  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objectName),
  1096  		0, nil, s.accessKey, s.secretKey, s.signer)
  1097  	if s.signer == signerV2 {
  1098  		c.Assert(err, nil)
  1099  		err = signRequestV2(request, s.accessKey, s.secretKey)
  1100  	}
  1101  	c.Assert(err, nil)
  1102  	// execute the HTTP request for object upload.
  1103  	response, err = s.client.Do(request)
  1104  	c.Assert(err, nil)
  1105  	c.Assert(response.StatusCode, http.StatusOK)
  1106  	// The response Etag header should contain Md5sum of an empty string.
  1107  	c.Assert(response.Header.Get(xhttp.ETag), "\""+emptyETag+"\"")
  1108  }
  1109  
  1110  // TestListBuckets - Make request for listing of all buckets.
  1111  // XML response is parsed.
  1112  // Its success verifies the format of the response.
  1113  func (s *TestSuiteCommon) TestListBuckets(c *check) {
  1114  	// generate a random bucket name.
  1115  	bucketName := getRandomBucketName()
  1116  	// HTTP request to create the bucket.
  1117  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
  1118  		0, nil, s.accessKey, s.secretKey, s.signer)
  1119  	c.Assert(err, nil)
  1120  	// execute the HTTP request to list buckets.
  1121  	response, err := s.client.Do(request)
  1122  	c.Assert(err, nil)
  1123  	c.Assert(response.StatusCode, http.StatusOK)
  1124  
  1125  	// create HTTP request for listing buckets.
  1126  	request, err = newTestSignedRequest(http.MethodGet, getListBucketURL(s.endPoint),
  1127  		0, nil, s.accessKey, s.secretKey, s.signer)
  1128  	c.Assert(err, nil)
  1129  
  1130  	// execute the HTTP request to list buckets.
  1131  	response, err = s.client.Do(request)
  1132  	c.Assert(err, nil)
  1133  	c.Assert(response.StatusCode, http.StatusOK)
  1134  
  1135  	var results ListBucketsResponse
  1136  	// parse the list bucket response.
  1137  	decoder := xml.NewDecoder(response.Body)
  1138  	err = decoder.Decode(&results)
  1139  	// validating that the xml-decoding/parsing was successful.
  1140  	c.Assert(err, nil)
  1141  
  1142  	// Fetch the bucket created above
  1143  	var createdBucket Bucket
  1144  	for _, b := range results.Buckets.Buckets {
  1145  		if b.Name == bucketName {
  1146  			createdBucket = b
  1147  		}
  1148  	}
  1149  	c.Assert(createdBucket.Name != "", true)
  1150  
  1151  	// Parse the bucket modtime
  1152  	creationTime, err := time.Parse(iso8601TimeFormat, createdBucket.CreationDate)
  1153  	c.Assert(err, nil)
  1154  
  1155  	// Check if bucket modtime is consistent (not less than current time and not late more than 5 minutes)
  1156  	timeNow := time.Now().UTC()
  1157  	c.Assert(creationTime.Before(timeNow), true)
  1158  	c.Assert(timeNow.Sub(creationTime) < time.Minute*5, true)
  1159  }
  1160  
  1161  // This tests validate if PUT handler can successfully detect signature mismatch.
  1162  func (s *TestSuiteCommon) TestValidateSignature(c *check) {
  1163  	// generate a random bucket name.
  1164  	bucketName := getRandomBucketName()
  1165  	// HTTP request to create the bucket.
  1166  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
  1167  		0, nil, s.accessKey, s.secretKey, s.signer)
  1168  	c.Assert(err, nil)
  1169  
  1170  	// Execute the HTTP request to create bucket.
  1171  	response, err := s.client.Do(request)
  1172  	c.Assert(err, nil)
  1173  	c.Assert(response.StatusCode, http.StatusOK)
  1174  
  1175  	objName := "test-object"
  1176  
  1177  	// Body is on purpose set to nil so that we get payload generated for empty bytes.
  1178  
  1179  	// Create new HTTP request with incorrect secretKey to generate an incorrect signature.
  1180  	secretKey := s.secretKey + "a"
  1181  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objName), 0, nil, s.accessKey, secretKey, s.signer)
  1182  	c.Assert(err, nil)
  1183  	response, err = s.client.Do(request)
  1184  	c.Assert(err, nil)
  1185  	verifyError(c, response, "SignatureDoesNotMatch", "The request signature we calculated does not match the signature you provided. Check your key and signing method.", http.StatusForbidden)
  1186  }
  1187  
  1188  // This tests validate if PUT handler can successfully detect SHA256 mismatch.
  1189  func (s *TestSuiteCommon) TestSHA256Mismatch(c *check) {
  1190  	// generate a random bucket name.
  1191  	bucketName := getRandomBucketName()
  1192  	// HTTP request to create the bucket.
  1193  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
  1194  		0, nil, s.accessKey, s.secretKey, s.signer)
  1195  	c.Assert(err, nil)
  1196  
  1197  	// Execute the HTTP request to create bucket.
  1198  	response, err := s.client.Do(request)
  1199  	c.Assert(err, nil)
  1200  	c.Assert(response.StatusCode, http.StatusOK)
  1201  
  1202  	objName := "test-object"
  1203  
  1204  	// Body is on purpose set to nil so that we get payload generated for empty bytes.
  1205  
  1206  	// Create new HTTP request with incorrect secretKey to generate an incorrect signature.
  1207  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objName), 0, nil, s.accessKey, s.secretKey, s.signer)
  1208  	if s.signer == signerV4 {
  1209  		c.Assert(request.Header.Get("x-amz-content-sha256"), "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
  1210  	}
  1211  	// Set the body to generate signature mismatch.
  1212  	helloReader := bytes.NewReader([]byte("Hello, World"))
  1213  	request.ContentLength = helloReader.Size()
  1214  	request.Body = ioutil.NopCloser(helloReader)
  1215  	c.Assert(err, nil)
  1216  
  1217  	// execute the HTTP request.
  1218  	response, err = s.client.Do(request)
  1219  	c.Assert(err, nil)
  1220  	if s.signer == signerV4 {
  1221  		verifyError(c, response, "XAmzContentSHA256Mismatch", "The provided 'x-amz-content-sha256' header does not match what was computed.", http.StatusBadRequest)
  1222  	}
  1223  }
  1224  
  1225  // TestPutObjectLongName - Validates the error response
  1226  // on an attempt to upload an object with long name.
  1227  func (s *TestSuiteCommon) TestPutObjectLongName(c *check) {
  1228  	// generate a random bucket name.
  1229  	bucketName := getRandomBucketName()
  1230  	// HTTP request to create the bucket.
  1231  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
  1232  		0, nil, s.accessKey, s.secretKey, s.signer)
  1233  	c.Assert(err, nil)
  1234  
  1235  	// Execute the HTTP request to create bucket.
  1236  	response, err := s.client.Do(request)
  1237  	c.Assert(err, nil)
  1238  	c.Assert(response.StatusCode, http.StatusOK)
  1239  	// Content for the object to be uploaded.
  1240  	buffer := bytes.NewReader([]byte("hello world"))
  1241  	// make long object name.
  1242  	longObjName := fmt.Sprintf("%0255d/%0255d/%0255d", 1, 1, 1)
  1243  	if IsDocker() || IsKubernetes() {
  1244  		longObjName = fmt.Sprintf("%0242d/%0242d/%0242d", 1, 1, 1)
  1245  	}
  1246  	// create new HTTP request to insert the object.
  1247  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, longObjName),
  1248  		int64(buffer.Len()), buffer, s.accessKey, s.secretKey, s.signer)
  1249  	c.Assert(err, nil)
  1250  	// execute the HTTP request.
  1251  	response, err = s.client.Do(request)
  1252  	c.Assert(err, nil)
  1253  	c.Assert(response.StatusCode, http.StatusOK)
  1254  
  1255  	//make long object name.
  1256  	longObjName = fmt.Sprintf("%0255d/%0255d/%0255d/%0255d/%0255d", 1, 1, 1, 1, 1)
  1257  	if IsDocker() || IsKubernetes() {
  1258  		longObjName = fmt.Sprintf("%0242d/%0242d/%0242d/%0242d/%0242d", 1, 1, 1, 1, 1)
  1259  	}
  1260  	// create new HTTP request to insert the object.
  1261  	buffer = bytes.NewReader([]byte("hello world"))
  1262  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, longObjName),
  1263  		int64(buffer.Len()), buffer, s.accessKey, s.secretKey, s.signer)
  1264  	c.Assert(err, nil)
  1265  	// execute the HTTP request.
  1266  	response, err = s.client.Do(request)
  1267  	c.Assert(err, nil)
  1268  	c.Assert(response.StatusCode, http.StatusBadRequest)
  1269  	verifyError(c, response, "KeyTooLongError", "Your key is too long", http.StatusBadRequest)
  1270  
  1271  	// make object name as unsupported
  1272  	longObjName = fmt.Sprintf("%0256d", 1)
  1273  	buffer = bytes.NewReader([]byte("hello world"))
  1274  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, longObjName),
  1275  		int64(buffer.Len()), buffer, s.accessKey, s.secretKey, s.signer)
  1276  	c.Assert(err, nil)
  1277  
  1278  	response, err = s.client.Do(request)
  1279  	c.Assert(err, nil)
  1280  	verifyError(c, response, "XMinioInvalidObjectName", "Object name contains unsupported characters.", http.StatusBadRequest)
  1281  }
  1282  
  1283  // TestNotBeAbleToCreateObjectInNonexistentBucket - Validates the error response
  1284  // on an attempt to upload an object into a non-existent bucket.
  1285  func (s *TestSuiteCommon) TestNotBeAbleToCreateObjectInNonexistentBucket(c *check) {
  1286  	// generate a random bucket name.
  1287  	bucketName := getRandomBucketName()
  1288  	// content of the object to be uploaded.
  1289  	buffer1 := bytes.NewReader([]byte("hello world"))
  1290  
  1291  	// preparing for upload by generating the upload URL.
  1292  	objectName := "test-object"
  1293  	request, err := newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objectName),
  1294  		int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey, s.signer)
  1295  	c.Assert(err, nil)
  1296  
  1297  	// Execute the HTTP request.
  1298  	response, err := s.client.Do(request)
  1299  	c.Assert(err, nil)
  1300  	// Assert the response error message.
  1301  	verifyError(c, response, "NoSuchBucket", "The specified bucket does not exist", http.StatusNotFound)
  1302  }
  1303  
  1304  // TestHeadOnObjectLastModified - Asserts response for HEAD on an object.
  1305  // HEAD requests on an object validates the existence of the object.
  1306  // The responses for fetching the object when If-Modified-Since
  1307  // and If-Unmodified-Since headers set are validated.
  1308  // If-Modified-Since - Return the object only if it has been modified since the specified time, else return a 304 (not modified).
  1309  // If-Unmodified-Since - Return the object only if it has not been modified since the specified time, else return a 412 (precondition failed).
  1310  func (s *TestSuiteCommon) TestHeadOnObjectLastModified(c *check) {
  1311  	// generate a random bucket name.
  1312  	bucketName := getRandomBucketName()
  1313  	// HTTP request to create the bucket.
  1314  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
  1315  		0, nil, s.accessKey, s.secretKey, s.signer)
  1316  	c.Assert(err, nil)
  1317  
  1318  	// execute the HTTP request to create bucket.
  1319  	response, err := s.client.Do(request)
  1320  	c.Assert(err, nil)
  1321  	c.Assert(response.StatusCode, http.StatusOK)
  1322  
  1323  	// preparing for object upload.
  1324  	objectName := "test-object"
  1325  	// content for the object to be uploaded.
  1326  	buffer1 := bytes.NewReader([]byte("hello world"))
  1327  	// obtaining URL for uploading the object.
  1328  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objectName),
  1329  		int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey, s.signer)
  1330  	c.Assert(err, nil)
  1331  
  1332  	// executing the HTTP request to download the object.
  1333  	response, err = s.client.Do(request)
  1334  	c.Assert(err, nil)
  1335  	c.Assert(response.StatusCode, http.StatusOK)
  1336  	// make HTTP request to obtain object info.
  1337  	request, err = newTestSignedRequest(http.MethodHead, getHeadObjectURL(s.endPoint, bucketName, objectName),
  1338  		0, nil, s.accessKey, s.secretKey, s.signer)
  1339  	c.Assert(err, nil)
  1340  	// execute the HTTP request.
  1341  	response, err = s.client.Do(request)
  1342  	c.Assert(err, nil)
  1343  	// verify the status of the HTTP response.
  1344  	c.Assert(response.StatusCode, http.StatusOK)
  1345  
  1346  	// retrieve the info of last modification time of the object from the response header.
  1347  	lastModified := response.Header.Get("Last-Modified")
  1348  	// Parse it into time.Time structure.
  1349  	t, err := time.Parse(http.TimeFormat, lastModified)
  1350  	c.Assert(err, nil)
  1351  
  1352  	// make HTTP request to obtain object info.
  1353  	// But this time set the "If-Modified-Since" header to be 10 minute more than the actual
  1354  	// last modified time of the object.
  1355  	request, err = newTestSignedRequest(http.MethodHead, getHeadObjectURL(s.endPoint, bucketName, objectName),
  1356  		0, nil, s.accessKey, s.secretKey, s.signer)
  1357  	c.Assert(err, nil)
  1358  	request.Header.Set("If-Modified-Since", t.Add(10*time.Minute).UTC().Format(http.TimeFormat))
  1359  	response, err = s.client.Do(request)
  1360  	c.Assert(err, nil)
  1361  	// Since the "If-Modified-Since" header was ahead in time compared to the actual
  1362  	// modified time of the object expecting the response status to be http.StatusNotModified.
  1363  	c.Assert(response.StatusCode, http.StatusNotModified)
  1364  
  1365  	// Again, obtain the object info.
  1366  	// This time setting "If-Unmodified-Since" to a time after the object is modified.
  1367  	// As documented above, expecting http.StatusPreconditionFailed.
  1368  	request, err = newTestSignedRequest(http.MethodHead, getHeadObjectURL(s.endPoint, bucketName, objectName),
  1369  		0, nil, s.accessKey, s.secretKey, s.signer)
  1370  	c.Assert(err, nil)
  1371  	request.Header.Set("If-Unmodified-Since", t.Add(-10*time.Minute).UTC().Format(http.TimeFormat))
  1372  	response, err = s.client.Do(request)
  1373  	c.Assert(err, nil)
  1374  	c.Assert(response.StatusCode, http.StatusPreconditionFailed)
  1375  
  1376  	// make HTTP request to obtain object info.
  1377  	// But this time set a date with unrecognized format to the "If-Modified-Since" header
  1378  	request, err = newTestSignedRequest(http.MethodHead, getHeadObjectURL(s.endPoint, bucketName, objectName),
  1379  		0, nil, s.accessKey, s.secretKey, s.signer)
  1380  	c.Assert(err, nil)
  1381  	request.Header.Set("If-Unmodified-Since", "Mon, 02 Jan 2006 15:04:05 +00:00")
  1382  	response, err = s.client.Do(request)
  1383  	c.Assert(err, nil)
  1384  	// Since the "If-Modified-Since" header was ahead in time compared to the actual
  1385  	// modified time of the object expecting the response status to be http.StatusNotModified.
  1386  	c.Assert(response.StatusCode, http.StatusOK)
  1387  
  1388  }
  1389  
  1390  // TestHeadOnBucket - Validates response for HEAD on the bucket.
  1391  // HEAD request on the bucket validates the existence of the bucket.
  1392  func (s *TestSuiteCommon) TestHeadOnBucket(c *check) {
  1393  	// generate a random bucket name.
  1394  	bucketName := getRandomBucketName()
  1395  	// HTTP request to create the bucket.
  1396  	request, err := newTestSignedRequest(http.MethodPut, getHEADBucketURL(s.endPoint, bucketName),
  1397  		0, nil, s.accessKey, s.secretKey, s.signer)
  1398  	c.Assert(err, nil)
  1399  
  1400  	// execute the HTTP request to create bucket.
  1401  	response, err := s.client.Do(request)
  1402  	c.Assert(err, nil)
  1403  	c.Assert(response.StatusCode, http.StatusOK)
  1404  	// make HEAD request on the bucket.
  1405  	request, err = newTestSignedRequest(http.MethodHead, getHEADBucketURL(s.endPoint, bucketName),
  1406  		0, nil, s.accessKey, s.secretKey, s.signer)
  1407  	c.Assert(err, nil)
  1408  	// execute the HTTP request.
  1409  	response, err = s.client.Do(request)
  1410  	c.Assert(err, nil)
  1411  	// Asserting the response status for expected value of http.StatusOK.
  1412  	c.Assert(response.StatusCode, http.StatusOK)
  1413  }
  1414  
  1415  // TestContentTypePersists - Object upload with different Content-type is first done.
  1416  // And then a HEAD and GET request on these objects are done to validate if the same Content-Type set during upload persists.
  1417  func (s *TestSuiteCommon) TestContentTypePersists(c *check) {
  1418  	// generate a random bucket name.
  1419  	bucketName := getRandomBucketName()
  1420  	// HTTP request to create the bucket.
  1421  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
  1422  		0, nil, s.accessKey, s.secretKey, s.signer)
  1423  	c.Assert(err, nil)
  1424  
  1425  	// execute the HTTP request to create bucket.
  1426  	response, err := s.client.Do(request)
  1427  	c.Assert(err, nil)
  1428  	c.Assert(response.StatusCode, http.StatusOK)
  1429  
  1430  	// Uploading a new object with Content-Type "image/png".
  1431  	// content for the object to be uploaded.
  1432  	buffer1 := bytes.NewReader([]byte("hello world"))
  1433  	objectName := "test-object.png"
  1434  	// constructing HTTP request for object upload.
  1435  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objectName),
  1436  		int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey, s.signer)
  1437  	c.Assert(err, nil)
  1438  	request.Header.Set("Content-Type", "image/png")
  1439  	if s.signer == signerV2 {
  1440  		err = signRequestV2(request, s.accessKey, s.secretKey)
  1441  		c.Assert(err, nil)
  1442  	}
  1443  
  1444  	// execute the HTTP request for object upload.
  1445  	response, err = s.client.Do(request)
  1446  	c.Assert(err, nil)
  1447  	c.Assert(response.StatusCode, http.StatusOK)
  1448  
  1449  	// Fetching the object info using HEAD request for the object which was uploaded above.
  1450  	request, err = newTestSignedRequest(http.MethodHead, getHeadObjectURL(s.endPoint, bucketName, objectName),
  1451  		0, nil, s.accessKey, s.secretKey, s.signer)
  1452  	c.Assert(err, nil)
  1453  
  1454  	// Execute the HTTP request.
  1455  	response, err = s.client.Do(request)
  1456  	c.Assert(err, nil)
  1457  	// Verify if the Content-Type header is set during the object persists.
  1458  	c.Assert(response.Header.Get("Content-Type"), "image/png")
  1459  
  1460  	// Fetching the object itself and then verify the Content-Type header.
  1461  	request, err = newTestSignedRequest(http.MethodGet, getGetObjectURL(s.endPoint, bucketName, objectName),
  1462  		0, nil, s.accessKey, s.secretKey, s.signer)
  1463  	c.Assert(err, nil)
  1464  
  1465  	// Execute the HTTP to fetch the object.
  1466  	response, err = s.client.Do(request)
  1467  	c.Assert(err, nil)
  1468  	c.Assert(response.StatusCode, http.StatusOK)
  1469  	// Verify if the Content-Type header is set during the object persists.
  1470  	c.Assert(response.Header.Get("Content-Type"), "image/png")
  1471  
  1472  	// Uploading a new object with Content-Type  "application/json".
  1473  	objectName = "test-object.json"
  1474  	buffer2 := bytes.NewReader([]byte("hello world"))
  1475  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objectName),
  1476  		int64(buffer2.Len()), buffer2, s.accessKey, s.secretKey, s.signer)
  1477  	c.Assert(err, nil)
  1478  	// setting the request header to be application/json.
  1479  	request.Header.Set("Content-Type", "application/json")
  1480  	if s.signer == signerV2 {
  1481  		err = signRequestV2(request, s.accessKey, s.secretKey)
  1482  		c.Assert(err, nil)
  1483  	}
  1484  
  1485  	// Execute the HTTP request to upload the object.
  1486  	response, err = s.client.Do(request)
  1487  	c.Assert(err, nil)
  1488  	c.Assert(response.StatusCode, http.StatusOK)
  1489  
  1490  	// Obtain the info of the object which was uploaded above using HEAD request.
  1491  	request, err = newTestSignedRequest(http.MethodHead, getHeadObjectURL(s.endPoint, bucketName, objectName),
  1492  		0, nil, s.accessKey, s.secretKey, s.signer)
  1493  	c.Assert(err, nil)
  1494  	// Execute the HTTP request.
  1495  	response, err = s.client.Do(request)
  1496  	c.Assert(err, nil)
  1497  	// Assert if the content-type header set during the object upload persists.
  1498  	c.Assert(response.Header.Get("Content-Type"), "application/json")
  1499  
  1500  	// Fetch the object and assert whether the Content-Type header persists.
  1501  	request, err = newTestSignedRequest(http.MethodGet, getGetObjectURL(s.endPoint, bucketName, objectName),
  1502  		0, nil, s.accessKey, s.secretKey, s.signer)
  1503  	c.Assert(err, nil)
  1504  
  1505  	// Execute the HTTP request.
  1506  	response, err = s.client.Do(request)
  1507  	c.Assert(err, nil)
  1508  	// Assert if the content-type header set during the object upload persists.
  1509  	c.Assert(response.Header.Get("Content-Type"), "application/json")
  1510  }
  1511  
  1512  // TestPartialContent - Validating for GetObject with partial content request.
  1513  // By setting the Range header, A request to send specific bytes range of data from an
  1514  // already uploaded object can be done.
  1515  func (s *TestSuiteCommon) TestPartialContent(c *check) {
  1516  	bucketName := getRandomBucketName()
  1517  
  1518  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
  1519  		0, nil, s.accessKey, s.secretKey, s.signer)
  1520  	c.Assert(err, nil)
  1521  
  1522  	response, err := s.client.Do(request)
  1523  	c.Assert(err, nil)
  1524  	c.Assert(response.StatusCode, http.StatusOK)
  1525  
  1526  	buffer1 := bytes.NewReader([]byte("Hello World"))
  1527  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, "bar"),
  1528  		int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey, s.signer)
  1529  	c.Assert(err, nil)
  1530  
  1531  	response, err = s.client.Do(request)
  1532  	c.Assert(err, nil)
  1533  	c.Assert(response.StatusCode, http.StatusOK)
  1534  
  1535  	// Prepare request
  1536  	request, err = newTestSignedRequest(http.MethodGet, getGetObjectURL(s.endPoint, bucketName, "bar"),
  1537  		0, nil, s.accessKey, s.secretKey, s.signer)
  1538  	c.Assert(err, nil)
  1539  	request.Header.Set("Range", "bytes=6-7")
  1540  
  1541  	response, err = s.client.Do(request)
  1542  	c.Assert(err, nil)
  1543  	c.Assert(response.StatusCode, http.StatusPartialContent)
  1544  	partialObject, err := ioutil.ReadAll(response.Body)
  1545  	c.Assert(err, nil)
  1546  
  1547  	c.Assert(string(partialObject), "Wo")
  1548  }
  1549  
  1550  // TestListObjectsHandler - Setting valid parameters to List Objects
  1551  // and then asserting the response with the expected one.
  1552  func (s *TestSuiteCommon) TestListObjectsHandler(c *check) {
  1553  	// generate a random bucket name.
  1554  	bucketName := getRandomBucketName()
  1555  	// HTTP request to create the bucket.
  1556  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
  1557  		0, nil, s.accessKey, s.secretKey, s.signer)
  1558  	c.Assert(err, nil)
  1559  
  1560  	// execute the HTTP request to create bucket.
  1561  	response, err := s.client.Do(request)
  1562  	c.Assert(err, nil)
  1563  	c.Assert(response.StatusCode, http.StatusOK)
  1564  
  1565  	for _, objectName := range []string{"foo bar 1", "foo bar 2"} {
  1566  		buffer := bytes.NewReader([]byte("Hello World"))
  1567  		request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objectName),
  1568  			int64(buffer.Len()), buffer, s.accessKey, s.secretKey, s.signer)
  1569  		c.Assert(err, nil)
  1570  
  1571  		response, err = s.client.Do(request)
  1572  		c.Assert(err, nil)
  1573  		c.Assert(response.StatusCode, http.StatusOK)
  1574  	}
  1575  
  1576  	var testCases = []struct {
  1577  		getURL          string
  1578  		expectedStrings []string
  1579  	}{
  1580  		{getListObjectsV1URL(s.endPoint, bucketName, "", "1000", ""), []string{"<Key>foo bar 1</Key>", "<Key>foo bar 2</Key>"}},
  1581  		{getListObjectsV1URL(s.endPoint, bucketName, "", "1000", "url"), []string{"<Key>foo+bar+1</Key>", "<Key>foo+bar+2</Key>"}},
  1582  		{getListObjectsV2URL(s.endPoint, bucketName, "", "1000", "", ""),
  1583  			[]string{
  1584  				"<Key>foo bar 1</Key>",
  1585  				"<Key>foo bar 2</Key>",
  1586  				fmt.Sprintf("<Owner><ID>%s</ID><DisplayName>minio</DisplayName></Owner>", GlobalMinioDefaultOwnerID),
  1587  			},
  1588  		},
  1589  		{getListObjectsV2URL(s.endPoint, bucketName, "", "1000", "true", ""),
  1590  			[]string{
  1591  				"<Key>foo bar 1</Key>",
  1592  				"<Key>foo bar 2</Key>",
  1593  				fmt.Sprintf("<Owner><ID>%s</ID><DisplayName>minio</DisplayName></Owner>", GlobalMinioDefaultOwnerID),
  1594  			},
  1595  		},
  1596  		{getListObjectsV2URL(s.endPoint, bucketName, "", "1000", "", "url"), []string{"<Key>foo+bar+1</Key>", "<Key>foo+bar+2</Key>"}},
  1597  	}
  1598  
  1599  	for _, testCase := range testCases {
  1600  		// create listObjectsV1 request with valid parameters
  1601  		request, err = newTestSignedRequest(http.MethodGet, testCase.getURL, 0, nil, s.accessKey, s.secretKey, s.signer)
  1602  		c.Assert(err, nil)
  1603  		// execute the HTTP request.
  1604  		response, err = s.client.Do(request)
  1605  		c.Assert(err, nil)
  1606  		c.Assert(response.StatusCode, http.StatusOK)
  1607  
  1608  		getContent, err := ioutil.ReadAll(response.Body)
  1609  		c.Assert(err, nil)
  1610  
  1611  		for _, expectedStr := range testCase.expectedStrings {
  1612  			c.Assert(strings.Contains(string(getContent), expectedStr), true)
  1613  		}
  1614  	}
  1615  }
  1616  
  1617  // TestListObjectsHandlerErrors - Setting invalid parameters to List Objects
  1618  // and then asserting the error response with the expected one.
  1619  func (s *TestSuiteCommon) TestListObjectsHandlerErrors(c *check) {
  1620  	// generate a random bucket name.
  1621  	bucketName := getRandomBucketName()
  1622  	// HTTP request to create the bucket.
  1623  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
  1624  		0, nil, s.accessKey, s.secretKey, s.signer)
  1625  	c.Assert(err, nil)
  1626  
  1627  	// execute the HTTP request to create bucket.
  1628  	response, err := s.client.Do(request)
  1629  	c.Assert(err, nil)
  1630  	c.Assert(response.StatusCode, http.StatusOK)
  1631  
  1632  	// create listObjectsV1 request with invalid value of max-keys parameter. max-keys is set to -2.
  1633  	request, err = newTestSignedRequest(http.MethodGet, getListObjectsV1URL(s.endPoint, bucketName, "", "-2", ""),
  1634  		0, nil, s.accessKey, s.secretKey, s.signer)
  1635  	c.Assert(err, nil)
  1636  	// execute the HTTP request.
  1637  	response, err = s.client.Do(request)
  1638  	c.Assert(err, nil)
  1639  	// validating the error response.
  1640  	verifyError(c, response, "InvalidArgument", "Argument maxKeys must be an integer between 0 and 2147483647", http.StatusBadRequest)
  1641  
  1642  	// create listObjectsV2 request with invalid value of max-keys parameter. max-keys is set to -2.
  1643  	request, err = newTestSignedRequest(http.MethodGet, getListObjectsV2URL(s.endPoint, bucketName, "", "-2", "", ""),
  1644  		0, nil, s.accessKey, s.secretKey, s.signer)
  1645  	c.Assert(err, nil)
  1646  	// execute the HTTP request.
  1647  	response, err = s.client.Do(request)
  1648  	c.Assert(err, nil)
  1649  	// validating the error response.
  1650  	verifyError(c, response, "InvalidArgument", "Argument maxKeys must be an integer between 0 and 2147483647", http.StatusBadRequest)
  1651  
  1652  }
  1653  
  1654  // TestPutBucketErrors - request for non valid bucket operation
  1655  // and validate it with expected error result.
  1656  func (s *TestSuiteCommon) TestPutBucketErrors(c *check) {
  1657  	// generate a random bucket name.
  1658  	bucketName := getRandomBucketName()
  1659  	// generating a HTTP request to create bucket.
  1660  	// using invalid bucket name.
  1661  	request, err := newTestSignedRequest(http.MethodPut, s.endPoint+"/putbucket-.",
  1662  		0, nil, s.accessKey, s.secretKey, s.signer)
  1663  	c.Assert(err, nil)
  1664  
  1665  	response, err := s.client.Do(request)
  1666  	c.Assert(err, nil)
  1667  	// expected to fail with error message "InvalidBucketName".
  1668  	verifyError(c, response, "InvalidBucketName", "The specified bucket is not valid.", http.StatusBadRequest)
  1669  	// HTTP request to create the bucket.
  1670  	request, err = newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
  1671  		0, nil, s.accessKey, s.secretKey, s.signer)
  1672  	c.Assert(err, nil)
  1673  
  1674  	// execute the HTTP request to create bucket.
  1675  	response, err = s.client.Do(request)
  1676  	c.Assert(err, nil)
  1677  	c.Assert(response.StatusCode, http.StatusOK)
  1678  	// make HTTP request to create the same bucket again.
  1679  	// expected to fail with error message "BucketAlreadyOwnedByYou".
  1680  	request, err = newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
  1681  		0, nil, s.accessKey, s.secretKey, s.signer)
  1682  	c.Assert(err, nil)
  1683  
  1684  	response, err = s.client.Do(request)
  1685  	c.Assert(err, nil)
  1686  	verifyError(c, response, "BucketAlreadyOwnedByYou", "Your previous request to create the named bucket succeeded and you already own it.",
  1687  		http.StatusConflict)
  1688  }
  1689  
  1690  func (s *TestSuiteCommon) TestGetObjectLarge10MiB(c *check) {
  1691  	// generate a random bucket name.
  1692  	bucketName := getRandomBucketName()
  1693  	// form HTTP request to create the bucket.
  1694  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
  1695  		0, nil, s.accessKey, s.secretKey, s.signer)
  1696  	c.Assert(err, nil)
  1697  
  1698  	// execute the HTTP request to create the bucket.
  1699  	response, err := s.client.Do(request)
  1700  	c.Assert(err, nil)
  1701  	c.Assert(response.StatusCode, http.StatusOK)
  1702  
  1703  	var buffer bytes.Buffer
  1704  	line := `1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1705  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1706  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1707  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1708  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1709  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1710  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1711  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1712  	1234567890,1234567890,1234567890,1234567890,1234567890,123"`
  1713  	// Create 10MiB content where each line contains 1024 characters.
  1714  	for i := 0; i < 10*1024; i++ {
  1715  		buffer.WriteString(fmt.Sprintf("[%05d] %s\n", i, line))
  1716  	}
  1717  	putContent := buffer.String()
  1718  
  1719  	buf := bytes.NewReader([]byte(putContent))
  1720  
  1721  	objectName := "test-big-object"
  1722  	// create HTTP request for object upload.
  1723  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objectName),
  1724  		int64(buf.Len()), buf, s.accessKey, s.secretKey, s.signer)
  1725  	c.Assert(err, nil)
  1726  
  1727  	// execute the HTTP request.
  1728  	response, err = s.client.Do(request)
  1729  	c.Assert(err, nil)
  1730  	// Assert the status code to verify successful upload.
  1731  	c.Assert(response.StatusCode, http.StatusOK)
  1732  
  1733  	// prepare HTTP requests to download the object.
  1734  	request, err = newTestSignedRequest(http.MethodGet, getPutObjectURL(s.endPoint, bucketName, objectName),
  1735  		0, nil, s.accessKey, s.secretKey, s.signer)
  1736  	c.Assert(err, nil)
  1737  
  1738  	// execute the HTTP request to download the object.
  1739  	response, err = s.client.Do(request)
  1740  	c.Assert(err, nil)
  1741  	c.Assert(response.StatusCode, http.StatusOK)
  1742  	// extract the content from response body.
  1743  	getContent, err := ioutil.ReadAll(response.Body)
  1744  	c.Assert(err, nil)
  1745  
  1746  	// Compare putContent and getContent.
  1747  	c.Assert(string(getContent), putContent)
  1748  }
  1749  
  1750  // TestGetObjectLarge11MiB - Tests validate fetching of an object of size 11MB.
  1751  func (s *TestSuiteCommon) TestGetObjectLarge11MiB(c *check) {
  1752  	// generate a random bucket name.
  1753  	bucketName := getRandomBucketName()
  1754  	// HTTP request to create the bucket.
  1755  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
  1756  		0, nil, s.accessKey, s.secretKey, s.signer)
  1757  	c.Assert(err, nil)
  1758  
  1759  	// execute the HTTP request.
  1760  	response, err := s.client.Do(request)
  1761  	c.Assert(err, nil)
  1762  	c.Assert(response.StatusCode, http.StatusOK)
  1763  
  1764  	var buffer bytes.Buffer
  1765  	line := `1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1766  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1767  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1768  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1769  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1770  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1771  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1772  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1773  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1774  	1234567890,1234567890,1234567890,123`
  1775  	// Create 11MiB content where each line contains 1024 characters.
  1776  	for i := 0; i < 11*1024; i++ {
  1777  		buffer.WriteString(fmt.Sprintf("[%05d] %s\n", i, line))
  1778  	}
  1779  	putMD5 := getMD5Hash(buffer.Bytes())
  1780  
  1781  	objectName := "test-11Mb-object"
  1782  	// Put object
  1783  	buf := bytes.NewReader(buffer.Bytes())
  1784  	// create HTTP request foe object upload.
  1785  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objectName),
  1786  		int64(buf.Len()), buf, s.accessKey, s.secretKey, s.signer)
  1787  	c.Assert(err, nil)
  1788  
  1789  	// execute the HTTP request for object upload.
  1790  	response, err = s.client.Do(request)
  1791  	c.Assert(err, nil)
  1792  	c.Assert(response.StatusCode, http.StatusOK)
  1793  
  1794  	// create HTTP request to download the object.
  1795  	request, err = newTestSignedRequest(http.MethodGet, getGetObjectURL(s.endPoint, bucketName, objectName),
  1796  		0, nil, s.accessKey, s.secretKey, s.signer)
  1797  	c.Assert(err, nil)
  1798  
  1799  	// execute the HTTP request.
  1800  	response, err = s.client.Do(request)
  1801  	c.Assert(err, nil)
  1802  	c.Assert(response.StatusCode, http.StatusOK)
  1803  	// fetch the content from response body.
  1804  	getContent, err := ioutil.ReadAll(response.Body)
  1805  	c.Assert(err, nil)
  1806  
  1807  	// Get etag of the response content.
  1808  	getMD5 := getMD5Hash(getContent)
  1809  
  1810  	// Compare putContent and getContent.
  1811  	c.Assert(putMD5, getMD5)
  1812  }
  1813  
  1814  // TestGetPartialObjectMisAligned - tests get object partially mis-aligned.
  1815  // create a large buffer of mis-aligned data and upload it.
  1816  // then make partial range requests to while fetching it back and assert the response content.
  1817  func (s *TestSuiteCommon) TestGetPartialObjectMisAligned(c *check) {
  1818  	// generate a random bucket name.
  1819  	bucketName := getRandomBucketName()
  1820  	// HTTP request to create the bucket.
  1821  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
  1822  		0, nil, s.accessKey, s.secretKey, s.signer)
  1823  	c.Assert(err, nil)
  1824  
  1825  	// execute the HTTP request to create the bucket.
  1826  	response, err := s.client.Do(request)
  1827  	c.Assert(err, nil)
  1828  	c.Assert(response.StatusCode, http.StatusOK)
  1829  
  1830  	var buffer bytes.Buffer
  1831  	// data to be written into buffer.
  1832  	data := "1234567890"
  1833  	// seed the random number generator once.
  1834  	rand.Seed(3)
  1835  	// generate a random number between 13 and 200.
  1836  	randInt := getRandomRange(13, 200, -1)
  1837  	// write into buffer till length of the buffer is greater than the generated random number.
  1838  	for i := 0; i <= randInt; i += 10 {
  1839  		buffer.WriteString(data)
  1840  	}
  1841  	// String content which is used for put object range test.
  1842  	putBytes := buffer.Bytes()
  1843  	putBytes = putBytes[:randInt]
  1844  	// randomize the order of bytes in the byte array and create a reader.
  1845  	putBytes = randomizeBytes(putBytes, -1)
  1846  	buf := bytes.NewReader(putBytes)
  1847  	putContent := string(putBytes)
  1848  	objectName := "test-big-file"
  1849  	// HTTP request to upload the object.
  1850  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objectName),
  1851  		int64(buf.Len()), buf, s.accessKey, s.secretKey, s.signer)
  1852  	c.Assert(err, nil)
  1853  
  1854  	// execute the HTTP request to upload the object.
  1855  	response, err = s.client.Do(request)
  1856  	c.Assert(err, nil)
  1857  	c.Assert(response.StatusCode, http.StatusOK)
  1858  
  1859  	// test Cases containing data to make partial range requests.
  1860  	// also has expected response data.
  1861  	var testCases = []struct {
  1862  		byteRange      string
  1863  		expectedString string
  1864  	}{
  1865  		// request for byte range 10-11.
  1866  		// expecting the result to contain only putContent[10:12] bytes.
  1867  		{"10-11", putContent[10:12]},
  1868  		// request for object data after the first byte.
  1869  		{"1-", putContent[1:]},
  1870  		// request for object data after the first byte.
  1871  		{"6-", putContent[6:]},
  1872  		// request for last 2 bytes of the object.
  1873  		{"-2", putContent[len(putContent)-2:]},
  1874  		// request for last 7 bytes of the object.
  1875  		{"-7", putContent[len(putContent)-7:]},
  1876  	}
  1877  
  1878  	for _, t := range testCases {
  1879  		// HTTP request to download the object.
  1880  		request, err = newTestSignedRequest(http.MethodGet, getGetObjectURL(s.endPoint, bucketName, objectName),
  1881  			0, nil, s.accessKey, s.secretKey, s.signer)
  1882  		c.Assert(err, nil)
  1883  		// Get partial content based on the byte range set.
  1884  		request.Header.Set("Range", "bytes="+t.byteRange)
  1885  
  1886  		// execute the HTTP request.
  1887  		response, err = s.client.Do(request)
  1888  		c.Assert(err, nil)
  1889  		// Since only part of the object is requested, expecting response status to be http.StatusPartialContent .
  1890  		c.Assert(response.StatusCode, http.StatusPartialContent)
  1891  		// parse the HTTP response body.
  1892  		getContent, err := ioutil.ReadAll(response.Body)
  1893  		c.Assert(err, nil)
  1894  
  1895  		// Compare putContent and getContent.
  1896  		c.Assert(string(getContent), t.expectedString)
  1897  	}
  1898  }
  1899  
  1900  // TestGetPartialObjectLarge11MiB - Test validates partial content request for a 11MiB object.
  1901  func (s *TestSuiteCommon) TestGetPartialObjectLarge11MiB(c *check) {
  1902  	// generate a random bucket name.
  1903  	bucketName := getRandomBucketName()
  1904  	// HTTP request to create the bucket.
  1905  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
  1906  		0, nil, s.accessKey, s.secretKey, s.signer)
  1907  	c.Assert(err, nil)
  1908  
  1909  	// execute the HTTP request to create the bucket.
  1910  	response, err := s.client.Do(request)
  1911  	c.Assert(err, nil)
  1912  	c.Assert(response.StatusCode, http.StatusOK)
  1913  
  1914  	var buffer bytes.Buffer
  1915  	line := `234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1916  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1917  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1918  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1919  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1920  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1921  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1922  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1923  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1924  	1234567890,1234567890,1234567890,123`
  1925  	// Create 11MiB content where each line contains 1024
  1926  	// characters.
  1927  	for i := 0; i < 11*1024; i++ {
  1928  		buffer.WriteString(fmt.Sprintf("[%05d] %s\n", i, line))
  1929  	}
  1930  	putContent := buffer.String()
  1931  
  1932  	objectName := "test-large-11Mb-object"
  1933  
  1934  	buf := bytes.NewReader([]byte(putContent))
  1935  	// HTTP request to upload the object.
  1936  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objectName),
  1937  		int64(buf.Len()), buf, s.accessKey, s.secretKey, s.signer)
  1938  	c.Assert(err, nil)
  1939  
  1940  	// execute the HTTP request to upload the object.
  1941  	response, err = s.client.Do(request)
  1942  	c.Assert(err, nil)
  1943  	c.Assert(response.StatusCode, http.StatusOK)
  1944  
  1945  	// HTTP request to download the object.
  1946  	request, err = newTestSignedRequest(http.MethodGet, getGetObjectURL(s.endPoint, bucketName, objectName),
  1947  		0, nil, s.accessKey, s.secretKey, s.signer)
  1948  	c.Assert(err, nil)
  1949  	// This range spans into first two blocks.
  1950  	request.Header.Set("Range", "bytes=10485750-10485769")
  1951  
  1952  	// execute the HTTP request.
  1953  	response, err = s.client.Do(request)
  1954  	c.Assert(err, nil)
  1955  	// Since only part of the object is requested, expecting response status to be http.StatusPartialContent .
  1956  	c.Assert(response.StatusCode, http.StatusPartialContent)
  1957  	// read the downloaded content from the response body.
  1958  	getContent, err := ioutil.ReadAll(response.Body)
  1959  	c.Assert(err, nil)
  1960  
  1961  	// Compare putContent and getContent.
  1962  	c.Assert(string(getContent), putContent[10485750:10485770])
  1963  }
  1964  
  1965  // TestGetPartialObjectLarge11MiB - Test validates partial content request for a 10MiB object.
  1966  func (s *TestSuiteCommon) TestGetPartialObjectLarge10MiB(c *check) {
  1967  	// generate a random bucket name.
  1968  	bucketName := getRandomBucketName()
  1969  	// HTTP request to create the bucket.
  1970  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
  1971  		0, nil, s.accessKey, s.secretKey, s.signer)
  1972  	c.Assert(err, nil)
  1973  
  1974  	// execute the HTTP request to create bucket.
  1975  	response, err := s.client.Do(request)
  1976  	// expecting the error to be nil.
  1977  	c.Assert(err, nil)
  1978  	// expecting the HTTP response status code to 200 OK.
  1979  	c.Assert(response.StatusCode, http.StatusOK)
  1980  
  1981  	var buffer bytes.Buffer
  1982  	line := `1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1983  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1984  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1985  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1986  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1987  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1988  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1989  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1990  	1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
  1991  	1234567890,1234567890,1234567890,123`
  1992  	// Create 10MiB content where each line contains 1024 characters.
  1993  	for i := 0; i < 10*1024; i++ {
  1994  		buffer.WriteString(fmt.Sprintf("[%05d] %s\n", i, line))
  1995  	}
  1996  
  1997  	putContent := buffer.String()
  1998  	buf := bytes.NewReader([]byte(putContent))
  1999  
  2000  	objectName := "test-big-10Mb-file"
  2001  	// HTTP request to upload the object.
  2002  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objectName),
  2003  		int64(buf.Len()), buf, s.accessKey, s.secretKey, s.signer)
  2004  	c.Assert(err, nil)
  2005  
  2006  	// execute the HTTP request to upload the object.
  2007  	response, err = s.client.Do(request)
  2008  	c.Assert(err, nil)
  2009  	// verify whether upload was successful.
  2010  	c.Assert(response.StatusCode, http.StatusOK)
  2011  
  2012  	// HTTP request to download the object.
  2013  	request, err = newTestSignedRequest(http.MethodGet, getGetObjectURL(s.endPoint, bucketName, objectName),
  2014  		0, nil, s.accessKey, s.secretKey, s.signer)
  2015  	c.Assert(err, nil)
  2016  	// Get partial content based on the byte range set.
  2017  	request.Header.Set("Range", "bytes=2048-2058")
  2018  
  2019  	// execute the HTTP request to download the partial content.
  2020  	response, err = s.client.Do(request)
  2021  	c.Assert(err, nil)
  2022  	// Since only part of the object is requested, expecting response status to be http.StatusPartialContent .
  2023  	c.Assert(response.StatusCode, http.StatusPartialContent)
  2024  	// read the downloaded content from the response body.
  2025  	getContent, err := ioutil.ReadAll(response.Body)
  2026  	c.Assert(err, nil)
  2027  
  2028  	// Compare putContent and getContent.
  2029  	c.Assert(string(getContent), putContent[2048:2059])
  2030  }
  2031  
  2032  // TestGetObjectErrors - Tests validate error response for invalid object operations.
  2033  func (s *TestSuiteCommon) TestGetObjectErrors(c *check) {
  2034  	// generate a random bucket name.
  2035  	bucketName := getRandomBucketName()
  2036  
  2037  	// HTTP request to create the bucket.
  2038  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
  2039  		0, nil, s.accessKey, s.secretKey, s.signer)
  2040  	c.Assert(err, nil)
  2041  
  2042  	// execute the HTTP request to create bucket.
  2043  	response, err := s.client.Do(request)
  2044  	c.Assert(err, nil)
  2045  	c.Assert(response.StatusCode, http.StatusOK)
  2046  
  2047  	objectName := "test-non-exitent-object"
  2048  	// HTTP request to download the object.
  2049  	// Since the specified object doesn't exist in the given bucket,
  2050  	// expected to fail with error message "NoSuchKey"
  2051  	request, err = newTestSignedRequest(http.MethodGet, getGetObjectURL(s.endPoint, bucketName, objectName),
  2052  		0, nil, s.accessKey, s.secretKey, s.signer)
  2053  	c.Assert(err, nil)
  2054  
  2055  	response, err = s.client.Do(request)
  2056  	c.Assert(err, nil)
  2057  	verifyError(c, response, "NoSuchKey", "The specified key does not exist.", http.StatusNotFound)
  2058  
  2059  	// request to download an object, but an invalid bucket name is set.
  2060  	request, err = newTestSignedRequest(http.MethodGet, getGetObjectURL(s.endPoint, "getobjecterrors-.", objectName),
  2061  		0, nil, s.accessKey, s.secretKey, s.signer)
  2062  	c.Assert(err, nil)
  2063  
  2064  	// execute the HTTP request.
  2065  	response, err = s.client.Do(request)
  2066  	c.Assert(err, nil)
  2067  	// expected to fail with "InvalidBucketName".
  2068  	verifyError(c, response, "InvalidBucketName", "The specified bucket is not valid.", http.StatusBadRequest)
  2069  }
  2070  
  2071  // TestGetObjectRangeErrors - Validate error response when object is fetched with incorrect byte range value.
  2072  func (s *TestSuiteCommon) TestGetObjectRangeErrors(c *check) {
  2073  	// generate a random bucket name.
  2074  	bucketName := getRandomBucketName()
  2075  	// HTTP request to create the bucket.
  2076  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
  2077  		0, nil, s.accessKey, s.secretKey, s.signer)
  2078  	c.Assert(err, nil)
  2079  
  2080  	// execute the HTTP request to create bucket.
  2081  	response, err := s.client.Do(request)
  2082  	c.Assert(err, nil)
  2083  	c.Assert(response.StatusCode, http.StatusOK)
  2084  
  2085  	// content for the object to be uploaded.
  2086  	buffer1 := bytes.NewReader([]byte("Hello World"))
  2087  
  2088  	objectName := "test-object"
  2089  	// HTTP request to upload the object.
  2090  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objectName),
  2091  		int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey, s.signer)
  2092  	c.Assert(err, nil)
  2093  
  2094  	// execute the HTTP request to upload the object.
  2095  	response, err = s.client.Do(request)
  2096  	c.Assert(err, nil)
  2097  	// verify whether upload was successful.
  2098  	c.Assert(response.StatusCode, http.StatusOK)
  2099  
  2100  	// HTTP request to download the object.
  2101  	request, err = newTestSignedRequest(http.MethodGet, getGetObjectURL(s.endPoint, bucketName, objectName),
  2102  		0, nil, s.accessKey, s.secretKey, s.signer)
  2103  	// Invalid byte range set.
  2104  	request.Header.Set("Range", "bytes=-0")
  2105  	c.Assert(err, nil)
  2106  
  2107  	// execute the HTTP request.
  2108  	response, err = s.client.Do(request)
  2109  	c.Assert(err, nil)
  2110  	// expected to fail with "InvalidRange" error message.
  2111  	verifyError(c, response, "InvalidRange", "The requested range is not satisfiable", http.StatusRequestedRangeNotSatisfiable)
  2112  }
  2113  
  2114  // TestObjectMultipartAbort - Test validates abortion of a multipart upload after uploading 2 parts.
  2115  func (s *TestSuiteCommon) TestObjectMultipartAbort(c *check) {
  2116  	// generate a random bucket name.
  2117  	bucketName := getRandomBucketName()
  2118  	// HTTP request to create the bucket.
  2119  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
  2120  		0, nil, s.accessKey, s.secretKey, s.signer)
  2121  	c.Assert(err, nil)
  2122  
  2123  	// execute the HTTP request to create bucket.
  2124  	response, err := s.client.Do(request)
  2125  	c.Assert(err, nil)
  2126  	c.Assert(response.StatusCode, http.StatusOK)
  2127  
  2128  	objectName := "test-multipart-object"
  2129  
  2130  	// 1. Initiate 2 uploads for the same object
  2131  	// 2. Upload 2 parts for the second upload
  2132  	// 3. Abort the second upload.
  2133  	// 4. Abort the first upload.
  2134  	// This will test abort upload when there are more than one upload IDs
  2135  	// and the case where there is only one upload ID.
  2136  
  2137  	// construct HTTP request to initiate a NewMultipart upload.
  2138  	request, err = newTestSignedRequest(http.MethodPost, getNewMultipartURL(s.endPoint, bucketName, objectName),
  2139  		0, nil, s.accessKey, s.secretKey, s.signer)
  2140  	c.Assert(err, nil)
  2141  
  2142  	// execute the HTTP request initiating the new multipart upload.
  2143  	response, err = s.client.Do(request)
  2144  	c.Assert(err, nil)
  2145  	c.Assert(response.StatusCode, http.StatusOK)
  2146  
  2147  	// parse the response body and obtain the new upload ID.
  2148  	decoder := xml.NewDecoder(response.Body)
  2149  	newResponse := &InitiateMultipartUploadResponse{}
  2150  
  2151  	err = decoder.Decode(newResponse)
  2152  	c.Assert(err, nil)
  2153  	c.Assert(len(newResponse.UploadID) > 0, true)
  2154  
  2155  	// construct HTTP request to initiate a NewMultipart upload.
  2156  	request, err = newTestSignedRequest(http.MethodPost, getNewMultipartURL(s.endPoint, bucketName, objectName),
  2157  		0, nil, s.accessKey, s.secretKey, s.signer)
  2158  	c.Assert(err, nil)
  2159  
  2160  	// execute the HTTP request initiating the new multipart upload.
  2161  	response, err = s.client.Do(request)
  2162  	c.Assert(err, nil)
  2163  	c.Assert(response.StatusCode, http.StatusOK)
  2164  
  2165  	// parse the response body and obtain the new upload ID.
  2166  	decoder = xml.NewDecoder(response.Body)
  2167  	newResponse = &InitiateMultipartUploadResponse{}
  2168  
  2169  	err = decoder.Decode(newResponse)
  2170  	c.Assert(err, nil)
  2171  	c.Assert(len(newResponse.UploadID) > 0, true)
  2172  	// uploadID to be used for rest of the multipart operations on the object.
  2173  	uploadID := newResponse.UploadID
  2174  
  2175  	// content for the part to be uploaded.
  2176  	buffer1 := bytes.NewReader([]byte("hello world"))
  2177  	// HTTP request for the part to be uploaded.
  2178  	request, err = newTestSignedRequest(http.MethodPut, getPartUploadURL(s.endPoint, bucketName, objectName, uploadID, "1"),
  2179  		int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey, s.signer)
  2180  	c.Assert(err, nil)
  2181  	// execute the HTTP request to upload the first part.
  2182  	response1, err := s.client.Do(request)
  2183  	c.Assert(err, nil)
  2184  	c.Assert(response1.StatusCode, http.StatusOK)
  2185  
  2186  	// content for the second part to be uploaded.
  2187  	buffer2 := bytes.NewReader([]byte("hello world"))
  2188  	// HTTP request for the second part to be uploaded.
  2189  	request, err = newTestSignedRequest(http.MethodPut, getPartUploadURL(s.endPoint, bucketName, objectName, uploadID, "2"),
  2190  		int64(buffer2.Len()), buffer2, s.accessKey, s.secretKey, s.signer)
  2191  	c.Assert(err, nil)
  2192  	// execute the HTTP request to upload the second part.
  2193  	response2, err := s.client.Do(request)
  2194  	c.Assert(err, nil)
  2195  	c.Assert(response2.StatusCode, http.StatusOK)
  2196  	// HTTP request for aborting the multipart upload.
  2197  	request, err = newTestSignedRequest(http.MethodDelete, getAbortMultipartUploadURL(s.endPoint, bucketName, objectName, uploadID),
  2198  		0, nil, s.accessKey, s.secretKey, s.signer)
  2199  	c.Assert(err, nil)
  2200  	// execute the HTTP request to abort the multipart upload.
  2201  	response3, err := s.client.Do(request)
  2202  	c.Assert(err, nil)
  2203  	// expecting the response status code to be http.StatusNoContent.
  2204  	// The assertion validates the success of Abort Multipart operation.
  2205  	c.Assert(response3.StatusCode, http.StatusNoContent)
  2206  }
  2207  
  2208  // TestBucketMultipartList - Initiates a NewMultipart upload, uploads parts and validates listing of the parts.
  2209  func (s *TestSuiteCommon) TestBucketMultipartList(c *check) {
  2210  	// generate a random bucket name.
  2211  	bucketName := getRandomBucketName()
  2212  	// HTTP request to create the bucket.
  2213  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName), 0,
  2214  		nil, s.accessKey, s.secretKey, s.signer)
  2215  	c.Assert(err, nil)
  2216  
  2217  	// execute the HTTP request to create bucket.
  2218  	response, err := s.client.Do(request)
  2219  	c.Assert(err, nil)
  2220  	c.Assert(response.StatusCode, 200)
  2221  
  2222  	objectName := "test-multipart-object"
  2223  	// construct HTTP request to initiate a NewMultipart upload.
  2224  	request, err = newTestSignedRequest(http.MethodPost, getNewMultipartURL(s.endPoint, bucketName, objectName),
  2225  		0, nil, s.accessKey, s.secretKey, s.signer)
  2226  	c.Assert(err, nil)
  2227  	// execute the HTTP request initiating the new multipart upload.
  2228  	response, err = s.client.Do(request)
  2229  	c.Assert(err, nil)
  2230  	// expecting the response status code to be http.StatusOK(200 OK) .
  2231  	c.Assert(response.StatusCode, http.StatusOK)
  2232  
  2233  	// parse the response body and obtain the new upload ID.
  2234  	decoder := xml.NewDecoder(response.Body)
  2235  	newResponse := &InitiateMultipartUploadResponse{}
  2236  
  2237  	err = decoder.Decode(newResponse)
  2238  	c.Assert(err, nil)
  2239  	c.Assert(len(newResponse.UploadID) > 0, true)
  2240  	// uploadID to be used for rest of the multipart operations on the object.
  2241  	uploadID := newResponse.UploadID
  2242  
  2243  	// content for the part to be uploaded.
  2244  	buffer1 := bytes.NewReader([]byte("hello world"))
  2245  	// HTTP request for the part to be uploaded.
  2246  	request, err = newTestSignedRequest(http.MethodPut, getPartUploadURL(s.endPoint, bucketName, objectName, uploadID, "1"),
  2247  		int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey, s.signer)
  2248  	c.Assert(err, nil)
  2249  	// execute the HTTP request to upload the first part.
  2250  	response1, err := s.client.Do(request)
  2251  	c.Assert(err, nil)
  2252  	c.Assert(response1.StatusCode, http.StatusOK)
  2253  
  2254  	// content for the second part to be uploaded.
  2255  	buffer2 := bytes.NewReader([]byte("hello world"))
  2256  	// HTTP request for the second part to be uploaded.
  2257  	request, err = newTestSignedRequest(http.MethodPut, getPartUploadURL(s.endPoint, bucketName, objectName, uploadID, "2"),
  2258  		int64(buffer2.Len()), buffer2, s.accessKey, s.secretKey, s.signer)
  2259  	c.Assert(err, nil)
  2260  	// execute the HTTP request to upload the second part.
  2261  	response2, err := s.client.Do(request)
  2262  	c.Assert(err, nil)
  2263  	c.Assert(response2.StatusCode, http.StatusOK)
  2264  
  2265  	// HTTP request to ListMultipart Uploads.
  2266  	request, err = newTestSignedRequest(http.MethodGet, getListMultipartURL(s.endPoint, bucketName),
  2267  		0, nil, s.accessKey, s.secretKey, s.signer)
  2268  	c.Assert(err, nil)
  2269  	// execute the HTTP request.
  2270  	response3, err := s.client.Do(request)
  2271  	c.Assert(err, nil)
  2272  	c.Assert(response3.StatusCode, http.StatusOK)
  2273  
  2274  	// The reason to duplicate this structure here is to verify if the
  2275  	// unmarshalling works from a client perspective, specifically
  2276  	// while unmarshalling time.Time type for 'Initiated' field.
  2277  	// time.Time does not honor xml marshaller, it means that we need
  2278  	// to encode/format it before giving it to xml marshaling.
  2279  
  2280  	// This below check adds client side verification to see if its
  2281  	// truly parsable.
  2282  
  2283  	// listMultipartUploadsResponse - format for list multipart uploads response.
  2284  	type listMultipartUploadsResponse struct {
  2285  		XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListMultipartUploadsResult" json:"-"`
  2286  
  2287  		Bucket             string
  2288  		KeyMarker          string
  2289  		UploadIDMarker     string `xml:"UploadIdMarker"`
  2290  		NextKeyMarker      string
  2291  		NextUploadIDMarker string `xml:"NextUploadIdMarker"`
  2292  		EncodingType       string
  2293  		MaxUploads         int
  2294  		IsTruncated        bool
  2295  		// All the in progress multipart uploads.
  2296  		Uploads []struct {
  2297  			Key          string
  2298  			UploadID     string `xml:"UploadId"`
  2299  			Initiator    Initiator
  2300  			Owner        Owner
  2301  			StorageClass string
  2302  			Initiated    time.Time // Keep this native to be able to parse properly.
  2303  		}
  2304  		Prefix         string
  2305  		Delimiter      string
  2306  		CommonPrefixes []CommonPrefix
  2307  	}
  2308  
  2309  	// parse the response body.
  2310  	decoder = xml.NewDecoder(response3.Body)
  2311  	newResponse3 := &listMultipartUploadsResponse{}
  2312  	err = decoder.Decode(newResponse3)
  2313  	c.Assert(err, nil)
  2314  	// Assert the bucket name in the response with the expected bucketName.
  2315  	c.Assert(newResponse3.Bucket, bucketName)
  2316  	// Assert the bucket name in the response with the expected bucketName.
  2317  	c.Assert(newResponse3.IsTruncated, false)
  2318  }
  2319  
  2320  // TestValidateObjectMultipartUploadID - Test Initiates a new multipart upload and validates the uploadID.
  2321  func (s *TestSuiteCommon) TestValidateObjectMultipartUploadID(c *check) {
  2322  	// generate a random bucket name.
  2323  	bucketName := getRandomBucketName()
  2324  	// HTTP request to create the bucket.
  2325  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
  2326  		0, nil, s.accessKey, s.secretKey, s.signer)
  2327  	c.Assert(err, nil)
  2328  
  2329  	// execute the HTTP request to create bucket.
  2330  	response, err := s.client.Do(request)
  2331  	c.Assert(err, nil)
  2332  	c.Assert(response.StatusCode, 200)
  2333  
  2334  	objectName := "directory1/directory2/object"
  2335  	// construct HTTP request to initiate a NewMultipart upload.
  2336  	request, err = newTestSignedRequest(http.MethodPost, getNewMultipartURL(s.endPoint, bucketName, objectName),
  2337  		0, nil, s.accessKey, s.secretKey, s.signer)
  2338  	c.Assert(err, nil)
  2339  	// execute the HTTP request initiating the new multipart upload.
  2340  	response, err = s.client.Do(request)
  2341  	c.Assert(err, nil)
  2342  	c.Assert(response.StatusCode, http.StatusOK)
  2343  
  2344  	// parse the response body and obtain the new upload ID.
  2345  	decoder := xml.NewDecoder(response.Body)
  2346  	newResponse := &InitiateMultipartUploadResponse{}
  2347  	err = decoder.Decode(newResponse)
  2348  	// expecting the decoding error to be nil.
  2349  	c.Assert(err, nil)
  2350  	// Verifying for Upload ID value to be greater than 0.
  2351  	c.Assert(len(newResponse.UploadID) > 0, true)
  2352  }
  2353  
  2354  // TestObjectMultipartListError - Initiates a NewMultipart upload, uploads parts and validates
  2355  // error response for an incorrect max-parts parameter .
  2356  func (s *TestSuiteCommon) TestObjectMultipartListError(c *check) {
  2357  	// generate a random bucket name.
  2358  	bucketName := getRandomBucketName()
  2359  	// HTTP request to create the bucket.
  2360  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
  2361  		0, nil, s.accessKey, s.secretKey, s.signer)
  2362  	c.Assert(err, nil)
  2363  
  2364  	// execute the HTTP request to create bucket.
  2365  	response, err := s.client.Do(request)
  2366  	c.Assert(err, nil)
  2367  	c.Assert(response.StatusCode, 200)
  2368  
  2369  	objectName := "test-multipart-object"
  2370  	// construct HTTP request to initiate a NewMultipart upload.
  2371  	request, err = newTestSignedRequest(http.MethodPost, getNewMultipartURL(s.endPoint, bucketName, objectName),
  2372  		0, nil, s.accessKey, s.secretKey, s.signer)
  2373  	c.Assert(err, nil)
  2374  	// execute the HTTP request initiating the new multipart upload.
  2375  	response, err = s.client.Do(request)
  2376  	c.Assert(err, nil)
  2377  	c.Assert(response.StatusCode, http.StatusOK)
  2378  	// parse the response body and obtain the new upload ID.
  2379  	decoder := xml.NewDecoder(response.Body)
  2380  	newResponse := &InitiateMultipartUploadResponse{}
  2381  
  2382  	err = decoder.Decode(newResponse)
  2383  	c.Assert(err, nil)
  2384  	c.Assert(len(newResponse.UploadID) > 0, true)
  2385  	// uploadID to be used for rest of the multipart operations on the object.
  2386  	uploadID := newResponse.UploadID
  2387  
  2388  	// content for the part to be uploaded.
  2389  	buffer1 := bytes.NewReader([]byte("hello world"))
  2390  	// HTTP request for the part to be uploaded.
  2391  	request, err = newTestSignedRequest(http.MethodPut, getPartUploadURL(s.endPoint, bucketName, objectName, uploadID, "1"),
  2392  		int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey, s.signer)
  2393  	c.Assert(err, nil)
  2394  	// execute the HTTP request to upload the first part.
  2395  	response1, err := s.client.Do(request)
  2396  	c.Assert(err, nil)
  2397  	c.Assert(response1.StatusCode, http.StatusOK)
  2398  
  2399  	// content for the second part to be uploaded.
  2400  	buffer2 := bytes.NewReader([]byte("hello world"))
  2401  	// HTTP request for the second part to be uploaded.
  2402  	request, err = newTestSignedRequest(http.MethodPut, getPartUploadURL(s.endPoint, bucketName, objectName, uploadID, "2"),
  2403  		int64(buffer2.Len()), buffer2, s.accessKey, s.secretKey, s.signer)
  2404  	c.Assert(err, nil)
  2405  
  2406  	// execute the HTTP request to upload the second part.
  2407  	response2, err := s.client.Do(request)
  2408  	c.Assert(err, nil)
  2409  	c.Assert(response2.StatusCode, http.StatusOK)
  2410  
  2411  	// HTTP request to ListMultipart Uploads.
  2412  	// max-keys is set to valid value of 1
  2413  	request, err = newTestSignedRequest(http.MethodGet, getListMultipartURLWithParams(s.endPoint, bucketName, objectName, uploadID, "1", "", ""),
  2414  		0, nil, s.accessKey, s.secretKey, s.signer)
  2415  	c.Assert(err, nil)
  2416  	// execute the HTTP request.
  2417  	response3, err := s.client.Do(request)
  2418  	c.Assert(err, nil)
  2419  	c.Assert(response3.StatusCode, http.StatusOK)
  2420  
  2421  	// HTTP request to ListMultipart Uploads.
  2422  	// max-keys is set to invalid value of -2.
  2423  	request, err = newTestSignedRequest(http.MethodGet, getListMultipartURLWithParams(s.endPoint, bucketName, objectName, uploadID, "-2", "", ""),
  2424  		0, nil, s.accessKey, s.secretKey, s.signer)
  2425  	c.Assert(err, nil)
  2426  	// execute the HTTP request.
  2427  	response4, err := s.client.Do(request)
  2428  	c.Assert(err, nil)
  2429  	// Since max-keys parameter in the ListMultipart request set to invalid value of -2,
  2430  	// its expected to fail with error message "InvalidArgument".
  2431  	verifyError(c, response4, "InvalidArgument", "Argument max-parts must be an integer between 0 and 2147483647", http.StatusBadRequest)
  2432  }
  2433  
  2434  // TestObjectValidMD5 - First uploads an object with a valid Content-Md5 header and verifies the status,
  2435  // then upload an object in a wrong Content-Md5 and validate the error response.
  2436  func (s *TestSuiteCommon) TestObjectValidMD5(c *check) {
  2437  	// generate a random bucket name.
  2438  	bucketName := getRandomBucketName()
  2439  	// HTTP request to create the bucket.
  2440  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
  2441  		0, nil, s.accessKey, s.secretKey, s.signer)
  2442  	c.Assert(err, nil)
  2443  
  2444  	// execute the HTTP request to create bucket.
  2445  	response, err := s.client.Do(request)
  2446  	c.Assert(err, nil)
  2447  	c.Assert(response.StatusCode, 200)
  2448  
  2449  	// Create a byte array of 5MB.
  2450  	// content for the object to be uploaded.
  2451  	data := bytes.Repeat([]byte("0123456789abcdef"), 5*humanize.MiByte/16)
  2452  	// calculate etag of the data.
  2453  	etagBase64 := getMD5HashBase64(data)
  2454  
  2455  	buffer1 := bytes.NewReader(data)
  2456  	objectName := "test-1-object"
  2457  	// HTTP request for the object to be uploaded.
  2458  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objectName),
  2459  		int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey, s.signer)
  2460  	c.Assert(err, nil)
  2461  	// set the Content-Md5 to be the hash to content.
  2462  	request.Header.Set("Content-Md5", etagBase64)
  2463  	response, err = s.client.Do(request)
  2464  	c.Assert(err, nil)
  2465  	// expecting a successful upload.
  2466  	c.Assert(response.StatusCode, http.StatusOK)
  2467  	objectName = "test-2-object"
  2468  	buffer1 = bytes.NewReader(data)
  2469  	// HTTP request for the object to be uploaded.
  2470  	request, err = newTestSignedRequest(http.MethodPut, getPutObjectURL(s.endPoint, bucketName, objectName),
  2471  		int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey, s.signer)
  2472  	c.Assert(err, nil)
  2473  	// set Content-Md5 to invalid value.
  2474  	request.Header.Set("Content-Md5", "kvLTlMrX9NpYDQlEIFlnDA==")
  2475  	// expecting a failure during upload.
  2476  	response, err = s.client.Do(request)
  2477  	c.Assert(err, nil)
  2478  	// Since Content-Md5 header was wrong, expecting to fail with "SignatureDoesNotMatch" error.
  2479  	verifyError(c, response, "SignatureDoesNotMatch", "The request signature we calculated does not match the signature you provided. Check your key and signing method.", http.StatusForbidden)
  2480  }
  2481  
  2482  // TestObjectMultipart - Initiates a NewMultipart upload, uploads 2 parts,
  2483  // completes the multipart upload and validates the status of the operation.
  2484  func (s *TestSuiteCommon) TestObjectMultipart(c *check) {
  2485  	// generate a random bucket name.
  2486  	bucketName := getRandomBucketName()
  2487  	// HTTP request to create the bucket.
  2488  	request, err := newTestSignedRequest(http.MethodPut, getMakeBucketURL(s.endPoint, bucketName),
  2489  		0, nil, s.accessKey, s.secretKey, s.signer)
  2490  	c.Assert(err, nil)
  2491  
  2492  	// execute the HTTP request to create bucket.
  2493  	response, err := s.client.Do(request)
  2494  	c.Assert(err, nil)
  2495  	c.Assert(response.StatusCode, 200)
  2496  
  2497  	objectName := "test-multipart-object"
  2498  	// construct HTTP request to initiate a NewMultipart upload.
  2499  	request, err = newTestSignedRequest(http.MethodPost, getNewMultipartURL(s.endPoint, bucketName, objectName),
  2500  		0, nil, s.accessKey, s.secretKey, s.signer)
  2501  	c.Assert(err, nil)
  2502  
  2503  	// execute the HTTP request initiating the new multipart upload.
  2504  	response, err = s.client.Do(request)
  2505  	c.Assert(err, nil)
  2506  	// expecting the response status code to be http.StatusOK(200 OK).
  2507  	c.Assert(response.StatusCode, http.StatusOK)
  2508  	// parse the response body and obtain the new upload ID.
  2509  	decoder := xml.NewDecoder(response.Body)
  2510  	newResponse := &InitiateMultipartUploadResponse{}
  2511  
  2512  	err = decoder.Decode(newResponse)
  2513  	c.Assert(err, nil)
  2514  	c.Assert(len(newResponse.UploadID) > 0, true)
  2515  	// uploadID to be used for rest of the multipart operations on the object.
  2516  	uploadID := newResponse.UploadID
  2517  
  2518  	// content for the part to be uploaded.
  2519  	// Create a byte array of 5MB.
  2520  	data := bytes.Repeat([]byte("0123456789abcdef"), 5*humanize.MiByte/16)
  2521  	// calculate etag of the data.
  2522  	md5SumBase64 := getMD5HashBase64(data)
  2523  
  2524  	buffer1 := bytes.NewReader(data)
  2525  	// HTTP request for the part to be uploaded.
  2526  	request, err = newTestSignedRequest(http.MethodPut, getPartUploadURL(s.endPoint, bucketName, objectName, uploadID, "1"),
  2527  		int64(buffer1.Len()), buffer1, s.accessKey, s.secretKey, s.signer)
  2528  	// set the Content-Md5 header to the base64 encoding the etag of the content.
  2529  	request.Header.Set("Content-Md5", md5SumBase64)
  2530  	c.Assert(err, nil)
  2531  
  2532  	// execute the HTTP request to upload the first part.
  2533  	response1, err := s.client.Do(request)
  2534  	c.Assert(err, nil)
  2535  	c.Assert(response1.StatusCode, http.StatusOK)
  2536  
  2537  	// content for the second part to be uploaded.
  2538  	// Create a byte array of 1 byte.
  2539  	data = []byte("0")
  2540  
  2541  	// calculate etag of the data.
  2542  	md5SumBase64 = getMD5HashBase64(data)
  2543  
  2544  	buffer2 := bytes.NewReader(data)
  2545  	// HTTP request for the second part to be uploaded.
  2546  	request, err = newTestSignedRequest(http.MethodPut, getPartUploadURL(s.endPoint, bucketName, objectName, uploadID, "2"),
  2547  		int64(buffer2.Len()), buffer2, s.accessKey, s.secretKey, s.signer)
  2548  	// set the Content-Md5 header to the base64 encoding the etag of the content.
  2549  	request.Header.Set("Content-Md5", md5SumBase64)
  2550  	c.Assert(err, nil)
  2551  
  2552  	// execute the HTTP request to upload the second part.
  2553  	response2, err := s.client.Do(request)
  2554  	c.Assert(err, nil)
  2555  	c.Assert(response2.StatusCode, http.StatusOK)
  2556  
  2557  	// Complete multipart upload
  2558  	completeUploads := &CompleteMultipartUpload{
  2559  		Parts: []CompletePart{
  2560  			{
  2561  				PartNumber: 1,
  2562  				ETag:       response1.Header.Get("ETag"),
  2563  			},
  2564  			{
  2565  				PartNumber: 2,
  2566  				ETag:       response2.Header.Get("ETag"),
  2567  			},
  2568  		},
  2569  	}
  2570  
  2571  	completeBytes, err := xml.Marshal(completeUploads)
  2572  	c.Assert(err, nil)
  2573  	// Indicating that all parts are uploaded and initiating CompleteMultipartUpload.
  2574  	request, err = newTestSignedRequest(http.MethodPost, getCompleteMultipartUploadURL(s.endPoint, bucketName, objectName, uploadID),
  2575  		int64(len(completeBytes)), bytes.NewReader(completeBytes), s.accessKey, s.secretKey, s.signer)
  2576  	c.Assert(err, nil)
  2577  	// Execute the complete multipart request.
  2578  	response, err = s.client.Do(request)
  2579  	c.Assert(err, nil)
  2580  	// verify whether complete multipart was successful.
  2581  	c.Assert(response.StatusCode, http.StatusOK)
  2582  	var parts []CompletePart
  2583  	for _, part := range completeUploads.Parts {
  2584  		part.ETag = canonicalizeETag(part.ETag)
  2585  		parts = append(parts, part)
  2586  	}
  2587  	etag := getCompleteMultipartMD5(parts)
  2588  	c.Assert(canonicalizeETag(response.Header.Get(xhttp.ETag)), etag)
  2589  }