diff --git a/cmd/bucket-handlers.go b/cmd/bucket-handlers.go index e2f292f32..29a39a724 100644 --- a/cmd/bucket-handlers.go +++ b/cmd/bucket-handlers.go @@ -983,7 +983,7 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h } var b bytes.Buffer - if fileName == "" { + if name != "file" { if http.CanonicalHeaderKey(name) == http.CanonicalHeaderKey("x-minio-fanout-list") { dec := json.NewDecoder(part) diff --git a/cmd/post-policy_test.go b/cmd/post-policy_test.go index 5f956d80f..c2bcd0ed4 100644 --- a/cmd/post-policy_test.go +++ b/cmd/post-policy_test.go @@ -314,6 +314,7 @@ func testPostPolicyBucketHandler(obj ObjectLayer, instanceType string, t TestErr secretKey string dates []interface{} policy string + noFilename bool corruptedBase64 bool corruptedMultipart bool }{ @@ -327,6 +328,17 @@ func testPostPolicyBucketHandler(obj ObjectLayer, instanceType string, t TestErr dates: []interface{}{curTimePlus5Min.Format(iso8601TimeFormat), curTime.Format(iso8601DateFormat), curTime.Format(yyyymmdd)}, policy: `{"expiration": "%s","conditions":[["eq", "$bucket", "` + bucketName + `"], ["starts-with", "$key", "test/"], ["eq", "$x-amz-algorithm", "AWS4-HMAC-SHA256"], ["eq", "$x-amz-date", "%s"], ["eq", "$x-amz-credential", "` + credentials.AccessKey + `/%s/us-east-1/s3/aws4_request"],["eq", "$x-amz-meta-uuid", "1234"]]}`, }, + // Success case, no multipart filename. + { + objectName: "test", + data: []byte("Hello, World"), + expectedRespStatus: http.StatusNoContent, + accessKey: credentials.AccessKey, + secretKey: credentials.SecretKey, + dates: []interface{}{curTimePlus5Min.Format(iso8601TimeFormat), curTime.Format(iso8601DateFormat), curTime.Format(yyyymmdd)}, + policy: `{"expiration": "%s","conditions":[["eq", "$bucket", "` + bucketName + `"], ["starts-with", "$key", "test/"], ["eq", "$x-amz-algorithm", "AWS4-HMAC-SHA256"], ["eq", "$x-amz-date", "%s"], ["eq", "$x-amz-credential", "` + credentials.AccessKey + `/%s/us-east-1/s3/aws4_request"],["eq", "$x-amz-meta-uuid", "1234"]]}`, + noFilename: true, + }, // Success case, big body. { objectName: "test", @@ -399,7 +411,7 @@ func testPostPolicyBucketHandler(obj ObjectLayer, instanceType string, t TestErr testCase.policy = fmt.Sprintf(testCase.policy, testCase.dates...) req, perr := newPostRequestV4Generic("", bucketName, testCase.objectName, testCase.data, testCase.accessKey, - testCase.secretKey, region, curTime, []byte(testCase.policy), nil, testCase.corruptedBase64, testCase.corruptedMultipart) + testCase.secretKey, region, curTime, []byte(testCase.policy), nil, testCase.noFilename, testCase.corruptedBase64, testCase.corruptedMultipart) if perr != nil { t.Fatalf("Test %d: %s: Failed to create HTTP request for PostPolicyHandler: %v", i+1, instanceType, perr) } @@ -539,7 +551,7 @@ func testPostPolicyBucketHandlerRedirect(obj ObjectLayer, instanceType string, t // Create a new POST request with success_action_redirect field specified req, perr := newPostRequestV4Generic("", bucketName, keyName, []byte("objData"), credentials.AccessKey, credentials.SecretKey, region, curTime, - []byte(policy), map[string]string{"success_action_redirect": redirectURL.String()}, false, false) + []byte(policy), map[string]string{"success_action_redirect": redirectURL.String()}, false, false, false) if perr != nil { t.Fatalf("%s: Failed to create HTTP request for PostPolicyHandler: %v", instanceType, perr) @@ -647,7 +659,7 @@ func buildGenericPolicy(t time.Time, accessKey, region, bucketName, objectName s } func newPostRequestV4Generic(endPoint, bucketName, objectName string, objData []byte, accessKey, secretKey string, region string, - t time.Time, policy []byte, addFormData map[string]string, corruptedB64 bool, corruptedMultipart bool, + t time.Time, policy []byte, addFormData map[string]string, noFilename bool, corruptedB64 bool, corruptedMultipart bool, ) (*http.Request, error) { // Get the user credential. credStr := getCredentialString(accessKey, region, t) @@ -662,9 +674,17 @@ func newPostRequestV4Generic(endPoint, bucketName, objectName string, objData [] // Presign with V4 signature based on the policy. signature := postPresignSignatureV4(encodedPolicy, t, secretKey, region) + // If there is no filename on multipart, get the filename from the key. + key := objectName + if noFilename { + key += "/upload.txt" + } else { + key += "/${filename}" + } + formData := map[string]string{ "bucket": bucketName, - "key": objectName + "/${filename}", + "key": key, "x-amz-credential": credStr, "policy": encodedPolicy, "x-amz-signature": signature, @@ -689,7 +709,13 @@ func newPostRequestV4Generic(endPoint, bucketName, objectName string, objData [] } // Set the File formData but don't if we want send an incomplete multipart request if !corruptedMultipart { - writer, err := w.CreateFormFile("file", "upload.txt") + var writer io.Writer + var err error + if noFilename { + writer, err = w.CreateFormField("file") + } else { + writer, err = w.CreateFormFile("file", "upload.txt") + } if err != nil { // return nil, err return nil, err @@ -716,12 +742,12 @@ func newPostRequestV4WithContentLength(endPoint, bucketName, objectName string, t := UTCNow() region := "us-east-1" policy := buildGenericPolicy(t, accessKey, region, bucketName, objectName, true) - return newPostRequestV4Generic(endPoint, bucketName, objectName, objData, accessKey, secretKey, region, t, policy, nil, false, false) + return newPostRequestV4Generic(endPoint, bucketName, objectName, objData, accessKey, secretKey, region, t, policy, nil, false, false, false) } func newPostRequestV4(endPoint, bucketName, objectName string, objData []byte, accessKey, secretKey string) (*http.Request, error) { t := UTCNow() region := "us-east-1" policy := buildGenericPolicy(t, accessKey, region, bucketName, objectName, false) - return newPostRequestV4Generic(endPoint, bucketName, objectName, objData, accessKey, secretKey, region, t, policy, nil, false, false) + return newPostRequestV4Generic(endPoint, bucketName, objectName, objData, accessKey, secretKey, region, t, policy, nil, false, false, false) }