api: postPolicy cleanup. Simplify the code and re-use. (#3890)

This change is cleanup of the postPolicyHandler code
primarily to address the flow and also converting
certain critical parts into self contained functions.
This commit is contained in:
Harshavardhana 2017-03-13 14:41:13 -07:00 committed by GitHub
parent 3314501f19
commit 5f7565762e
12 changed files with 222 additions and 162 deletions

View file

@ -19,7 +19,6 @@ package cmd
import (
"encoding/base64"
"encoding/xml"
"fmt"
"io"
"net/http"
"net/url"
@ -327,9 +326,7 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter,
ObjInfo: ObjectInfo{
Name: dobj.ObjectName,
},
ReqParams: map[string]string{
"sourceIPAddress": r.RemoteAddr,
},
ReqParams: extractReqParams(r),
})
}
}
@ -439,14 +436,25 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h
defer fileBody.Close()
bucket := mux.Vars(r)["bucket"]
formValues["Bucket"] = bucket
formValues.Set("Bucket", bucket)
if fileName != "" && strings.Contains(formValues["Key"], "${filename}") {
if fileName != "" && strings.Contains(formValues.Get("Key"), "${filename}") {
// S3 feature to replace ${filename} found in Key form field
// by the filename attribute passed in multipart
formValues["Key"] = strings.Replace(formValues["Key"], "${filename}", fileName, -1)
formValues.Set("Key", strings.Replace(formValues.Get("Key"), "${filename}", fileName, -1))
}
object := formValues.Get("Key")
successRedirect := formValues.Get("success_action_redirect")
successStatus := formValues.Get("success_action_status")
var redirectURL *url.URL
if successRedirect != "" {
redirectURL, err = url.Parse(successRedirect)
if err != nil {
writeErrorResponse(w, ErrMalformedPOSTRequest, r.URL)
return
}
}
object := formValues["Key"]
// Verify policy signature.
apiErr := doesPolicySignatureMatch(formValues)
@ -455,7 +463,7 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h
return
}
policyBytes, err := base64.StdEncoding.DecodeString(formValues["Policy"])
policyBytes, err := base64.StdEncoding.DecodeString(formValues.Get("Policy"))
if err != nil {
writeErrorResponse(w, ErrMalformedPOSTRequest, r.URL)
return
@ -492,7 +500,6 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h
// Extract metadata to be saved from received Form.
metadata := extractMetadataFromForm(formValues)
sha256sum := ""
objectLock := globalNSMutex.NewNSLock(bucket, object)
@ -505,50 +512,40 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
return
}
w.Header().Set("ETag", "\""+objInfo.MD5Sum+"\"")
w.Header().Set("ETag", `"`+objInfo.MD5Sum+`"`)
w.Header().Set("Location", getObjectLocation(bucket, object))
successRedirect := formValues[http.CanonicalHeaderKey("success_action_redirect")]
successStatus := formValues[http.CanonicalHeaderKey("success_action_status")]
// Notify object created event.
defer eventNotify(eventData{
Type: ObjectCreatedPost,
Bucket: objInfo.Bucket,
ObjInfo: objInfo,
ReqParams: extractReqParams(r),
})
if successStatus == "" && successRedirect == "" {
writeSuccessNoContent(w)
} else {
if successRedirect != "" {
redirectURL := successRedirect + "?" + fmt.Sprintf("bucket=%s&key=%s&etag=%s",
bucket,
getURLEncodedName(object),
getURLEncodedName("\""+objInfo.MD5Sum+"\""))
writeRedirectSeeOther(w, redirectURL)
} else {
// Decide what http response to send depending on success_action_status parameter
switch successStatus {
case "201":
resp := encodeResponse(PostResponse{
Bucket: bucket,
Key: object,
ETag: "\"" + objInfo.MD5Sum + "\"",
Location: getObjectLocation(bucket, object),
})
writeResponse(w, http.StatusCreated, resp, "application/xml")
case "200":
writeSuccessResponseHeadersOnly(w)
default:
writeSuccessNoContent(w)
}
}
if successRedirect != "" {
// Replace raw query params..
redirectURL.RawQuery = getRedirectPostRawQuery(objInfo)
writeRedirectSeeOther(w, redirectURL.String())
return
}
// Notify object created event.
eventNotify(eventData{
Type: ObjectCreatedPost,
Bucket: bucket,
ObjInfo: objInfo,
ReqParams: map[string]string{
"sourceIPAddress": r.RemoteAddr,
},
})
// Decide what http response to send depending on success_action_status parameter
switch successStatus {
case "201":
resp := encodeResponse(PostResponse{
Bucket: objInfo.Bucket,
Key: objInfo.Name,
ETag: `"` + objInfo.MD5Sum + `"`,
Location: getObjectLocation(objInfo.Bucket, objInfo.Name),
})
writeResponse(w, http.StatusCreated, resp, "application/xml")
case "200":
writeSuccessResponseHeadersOnly(w)
default:
writeSuccessNoContent(w)
}
}
// HeadBucketHandler - HEAD Bucket

View file

@ -20,6 +20,7 @@ import (
"io"
"mime/multipart"
"net/http"
"net/url"
"strings"
)
@ -105,6 +106,9 @@ func path2BucketAndObject(path string) (bucket, object string) {
// extractMetadataFromHeader extracts metadata from HTTP header.
func extractMetadataFromHeader(header http.Header) map[string]string {
if header == nil {
return nil
}
metadata := make(map[string]string)
// Save standard supported headers.
for _, supportedHeader := range supportedHeaders {
@ -126,51 +130,67 @@ func extractMetadataFromHeader(header http.Header) map[string]string {
metadata[cKey] = header.Get(key)
}
}
// Return.
// Success.
return metadata
}
// The Query string for the redirect URL the client is
// redirected on successful upload.
func getRedirectPostRawQuery(objInfo ObjectInfo) string {
redirectValues := make(url.Values)
redirectValues.Set("bucket", objInfo.Bucket)
redirectValues.Set("key", objInfo.Name)
redirectValues.Set("etag", "\""+objInfo.MD5Sum+"\"")
return redirectValues.Encode()
}
// Extract request params to be sent with event notifiation.
func extractReqParams(r *http.Request) map[string]string {
if r == nil {
return nil
}
// Success.
return map[string]string{
"sourceIPAddress": r.RemoteAddr,
// Add more fields here.
}
}
// extractMetadataFromForm extracts metadata from Post Form.
func extractMetadataFromForm(formValues map[string]string) map[string]string {
metadata := make(map[string]string)
// Save standard supported headers.
for _, supportedHeader := range supportedHeaders {
canonicalHeader := http.CanonicalHeaderKey(supportedHeader)
// Form field names are case insensitive, look for both canonical
// and non canonical entries.
if _, ok := formValues[canonicalHeader]; ok {
metadata[supportedHeader] = formValues[canonicalHeader]
} else if _, ok := formValues[supportedHeader]; ok {
metadata[supportedHeader] = formValues[canonicalHeader]
func extractMetadataFromForm(formValues http.Header) map[string]string {
return extractMetadataFromHeader(formValues)
}
// Validate form field size for s3 specification requirement.
func validateFormFieldSize(formValues http.Header) error {
// Iterate over form values
for k := range formValues {
// Check if value's field exceeds S3 limit
if int64(len(formValues.Get(k))) > maxFormFieldSize {
return traceError(errSizeUnexpected)
}
}
// Go through all other form values for any additional headers that needs to be saved.
for key := range formValues {
cKey := http.CanonicalHeaderKey(key)
if strings.HasPrefix(cKey, "X-Amz-Meta-") {
metadata[cKey] = formValues[key]
} else if strings.HasPrefix(cKey, "X-Minio-Meta-") {
metadata[cKey] = formValues[key]
}
}
return metadata
// Success.
return nil
}
// Extract form fields and file data from a HTTP POST Policy
func extractPostPolicyFormValues(form *multipart.Form) (filePart io.ReadCloser, fileName string, fileSize int64, formValues map[string]string, err error) {
func extractPostPolicyFormValues(form *multipart.Form) (filePart io.ReadCloser, fileName string, fileSize int64, formValues http.Header, err error) {
/// HTML Form values
formValues = make(map[string]string)
fileName = ""
// Iterate over form values
// Canonicalize the form values into http.Header.
formValues = make(http.Header)
for k, v := range form.Value {
canonicalFormName := http.CanonicalHeaderKey(k)
// Check if value's field exceeds S3 limit
if int64(len(v[0])) > maxFormFieldSize {
return nil, "", 0, nil, traceError(errSizeUnexpected)
}
// Set the form value
formValues[canonicalFormName] = v[0]
formValues[http.CanonicalHeaderKey(k)] = v
}
// Validate form values.
if err = validateFormFieldSize(formValues); err != nil {
return nil, "", 0, nil, err
}
// Iterator until we find a valid File field and break

View file

@ -22,6 +22,7 @@ import (
"io/ioutil"
"net/http"
"reflect"
"strings"
"testing"
)
@ -83,6 +84,44 @@ func TestIsValidLocationContraint(t *testing.T) {
}
}
// Test validate form field size.
func TestValidateFormFieldSize(t *testing.T) {
testCases := []struct {
header http.Header
err error
}{
// Empty header returns error as nil,
{
header: nil,
err: nil,
},
// Valid header returns error as nil.
{
header: http.Header{
"Content-Type": []string{"image/png"},
},
err: nil,
},
// Invalid header value > maxFormFieldSize+1
{
header: http.Header{
"Garbage": []string{strings.Repeat("a", int(maxFormFieldSize)+1)},
},
err: errSizeUnexpected,
},
}
// Run validate form field size check under all test cases.
for i, testCase := range testCases {
err := validateFormFieldSize(testCase.header)
if err != nil {
if errorCause(err).Error() != testCase.err.Error() {
t.Errorf("Test %d: Expected error %s, got %s", i+1, testCase.err, err)
}
}
}
}
// Tests validate metadata extraction from http headers.
func TestExtractMetadataHeaders(t *testing.T) {
testCases := []struct {
@ -115,6 +154,11 @@ func TestExtractMetadataHeaders(t *testing.T) {
"X-Amz-Meta-Appid": "amz-meta",
"X-Minio-Meta-Appid": "minio-meta"},
},
// Empty header input returns empty metadata.
{
header: nil,
metadata: nil,
},
}
// Validate if the extracting headers.

View file

@ -359,12 +359,10 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
// Notify object created event.
eventNotify(eventData{
Type: ObjectCreatedCopy,
Bucket: dstBucket,
ObjInfo: objInfo,
ReqParams: map[string]string{
"sourceIPAddress": r.RemoteAddr,
},
Type: ObjectCreatedCopy,
Bucket: dstBucket,
ObjInfo: objInfo,
ReqParams: extractReqParams(r),
})
}
@ -492,12 +490,10 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req
// Notify object created event.
eventNotify(eventData{
Type: ObjectCreatedPut,
Bucket: bucket,
ObjInfo: objInfo,
ReqParams: map[string]string{
"sourceIPAddress": r.RemoteAddr,
},
Type: ObjectCreatedPut,
Bucket: bucket,
ObjInfo: objInfo,
ReqParams: extractReqParams(r),
})
}
@ -922,12 +918,10 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite
// Notify object created event.
eventNotify(eventData{
Type: ObjectCreatedCompleteMultipartUpload,
Bucket: bucket,
ObjInfo: objInfo,
ReqParams: map[string]string{
"sourceIPAddress": r.RemoteAddr,
},
Type: ObjectCreatedCompleteMultipartUpload,
Bucket: bucket,
ObjInfo: objInfo,
ReqParams: extractReqParams(r),
})
}
@ -970,8 +964,6 @@ func (api objectAPIHandlers) DeleteObjectHandler(w http.ResponseWriter, r *http.
ObjInfo: ObjectInfo{
Name: object,
},
ReqParams: map[string]string{
"sourceIPAddress": r.RemoteAddr,
},
ReqParams: extractReqParams(r),
})
}

View file

@ -24,6 +24,7 @@ import (
"mime/multipart"
"net/http"
"net/http/httptest"
"net/url"
"testing"
"time"
@ -444,7 +445,10 @@ func testPostPolicyBucketHandlerRedirect(obj ObjectLayer, instanceType string, t
targetObj := keyName + "/upload.txt"
// The url of success_action_redirect field
redirectURL := "http://www.google.com"
redirectURL, err := url.Parse("http://www.google.com")
if err != nil {
t.Fatal(err)
}
// Register the API end points with XL/FS object layer.
apiRouter := initTestAPIEndPoints(obj, []string{"PostPolicy"})
@ -464,7 +468,7 @@ func testPostPolicyBucketHandlerRedirect(obj ObjectLayer, instanceType string, t
rec := httptest.NewRecorder()
dates := []interface{}{curTimePlus5Min.Format(expirationDateFormat), curTime.Format(iso8601DateFormat), curTime.Format(yyyymmdd)}
policy := `{"expiration": "%s","conditions":[["eq", "$bucket", "` + bucketName + `"], {"success_action_redirect":"` + redirectURL + `"},["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"]]}`
policy := `{"expiration": "%s","conditions":[["eq", "$bucket", "` + bucketName + `"], {"success_action_redirect":"` + redirectURL.String() + `"},["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"]]}`
// Generate the final policy document
policy = fmt.Sprintf(policy, dates...)
@ -472,7 +476,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, curTime,
[]byte(policy), map[string]string{"success_action_redirect": redirectURL}, false, false)
[]byte(policy), map[string]string{"success_action_redirect": redirectURL.String()}, false, false)
if perr != nil {
t.Fatalf("%s: Failed to create HTTP request for PostPolicyHandler: <ERROR> %v", instanceType, perr)
@ -492,8 +496,8 @@ func testPostPolicyBucketHandlerRedirect(obj ObjectLayer, instanceType string, t
t.Error("Unexpected error: ", err)
}
expectedLocation := fmt.Sprintf(redirectURL+"?bucket=%s&key=%s&etag=%s",
bucketName, getURLEncodedName(targetObj), getURLEncodedName("\""+info.MD5Sum+"\""))
redirectURL.RawQuery = getRedirectPostRawQuery(info)
expectedLocation := redirectURL.String()
// Check the new location url
if rec.HeaderMap.Get("Location") != expectedLocation {

View file

@ -219,7 +219,7 @@ func checkPolicyCond(op string, input1, input2 string) bool {
// checkPostPolicy - apply policy conditions and validate input values.
// (http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html)
func checkPostPolicy(formValues map[string]string, postPolicyForm PostPolicyForm) APIErrorCode {
func checkPostPolicy(formValues http.Header, postPolicyForm PostPolicyForm) APIErrorCode {
// Check if policy document expiry date is still not reached
if !postPolicyForm.Expiration.After(time.Now().UTC()) {
return ErrPolicyAlreadyExpired
@ -242,12 +242,12 @@ func checkPostPolicy(formValues map[string]string, postPolicyForm PostPolicyForm
return ErrAccessDenied
}
// Check if current policy condition is satisfied
condPassed = checkPolicyCond(op, formValues[formCanonicalName], v.Value)
condPassed = checkPolicyCond(op, formValues.Get(formCanonicalName), v.Value)
} else {
// This covers all conditions X-Amz-Meta-* and X-Amz-*
if strings.HasPrefix(cond, "$x-amz-meta-") || strings.HasPrefix(cond, "$x-amz-") {
// Check if policy condition is satisfied
condPassed = checkPolicyCond(op, formValues[formCanonicalName], v.Value)
condPassed = checkPolicyCond(op, formValues.Get(formCanonicalName), v.Value)
}
}
// Check if current policy condition is satisfied, quit immediately otherwise

View file

@ -18,12 +18,12 @@ package cmd
import (
"encoding/base64"
"net/http"
"testing"
)
// Test Post Policy parsing and checking conditions
func TestPostPolicyForm(t *testing.T) {
type testCase struct {
Bucket string
Key string
@ -60,18 +60,18 @@ func TestPostPolicyForm(t *testing.T) {
}
// Validate all the test cases.
for i, tt := range testCases {
formValues := make(map[string]string)
formValues["Bucket"] = tt.Bucket
formValues["Acl"] = tt.ACL
formValues["Key"] = tt.Key
formValues["X-Amz-Date"] = tt.XAmzDate
formValues["X-Amz-Meta-Uuid"] = tt.XAmzMetaUUID
formValues["X-Amz-Server-Side-Encryption"] = tt.XAmzServerSideEncryption
formValues["X-Amz-Algorithm"] = tt.XAmzAlgorithm
formValues["X-Amz-Credential"] = tt.XAmzCredential
formValues["Content-Type"] = tt.ContentType
formValues["Policy"] = tt.Policy
formValues["Success_action_redirect"] = tt.SuccessActionRedirect
formValues := make(http.Header)
formValues.Set("Bucket", tt.Bucket)
formValues.Set("Acl", tt.ACL)
formValues.Set("Key", tt.Key)
formValues.Set("X-Amz-Date", tt.XAmzDate)
formValues.Set("X-Amz-Meta-Uuid", tt.XAmzMetaUUID)
formValues.Set("X-Amz-Server-Side-Encryption", tt.XAmzServerSideEncryption)
formValues.Set("X-Amz-Algorithm", tt.XAmzAlgorithm)
formValues.Set("X-Amz-Credential", tt.XAmzCredential)
formValues.Set("Content-Type", tt.ContentType)
formValues.Set("Policy", tt.Policy)
formValues.Set("Success_action_redirect", tt.SuccessActionRedirect)
policyBytes, err := base64.StdEncoding.DecodeString(tt.Policy)
if err != nil {
t.Fatal(err)

View file

@ -64,14 +64,14 @@ var resourceList = []string{
"website",
}
func doesPolicySignatureV2Match(formValues map[string]string) APIErrorCode {
func doesPolicySignatureV2Match(formValues http.Header) APIErrorCode {
cred := serverConfig.GetCredential()
accessKey := formValues["Awsaccesskeyid"]
accessKey := formValues.Get("AWSAccessKeyId")
if accessKey != cred.AccessKey {
return ErrInvalidAccessKeyID
}
signature := formValues["Signature"]
policy := formValues["Policy"]
policy := formValues.Get("Policy")
signature := formValues.Get("Signature")
if signature != calculateSignatureV2(policy, cred.SecretKey) {
return ErrSignatureDoesNotMatch
}

View file

@ -208,10 +208,10 @@ func TestDoesPolicySignatureV2Match(t *testing.T) {
{creds.AccessKey, policy, calculateSignatureV2(policy, creds.SecretKey), ErrNone},
}
for i, test := range testCases {
formValues := make(map[string]string)
formValues["Awsaccesskeyid"] = test.accessKey
formValues["Signature"] = test.signature
formValues["Policy"] = test.policy
formValues := make(http.Header)
formValues.Set("Awsaccesskeyid", test.accessKey)
formValues.Set("Signature", test.signature)
formValues.Set("Policy", test.policy)
errCode := doesPolicySignatureV2Match(formValues)
if errCode != test.errCode {
t.Fatalf("(%d) expected to get %s, instead got %s", i+1, niceError(test.errCode), niceError(errCode))

View file

@ -147,9 +147,9 @@ func getSignature(signingKey []byte, stringToSign string) string {
}
// Check to see if Policy is signed correctly.
func doesPolicySignatureMatch(formValues map[string]string) APIErrorCode {
func doesPolicySignatureMatch(formValues http.Header) APIErrorCode {
// For SignV2 - Signature field will be valid
if formValues["Signature"] != "" {
if _, ok := formValues["Signature"]; ok {
return doesPolicySignatureV2Match(formValues)
}
return doesPolicySignatureV4Match(formValues)
@ -158,7 +158,7 @@ func doesPolicySignatureMatch(formValues map[string]string) APIErrorCode {
// doesPolicySignatureMatch - Verify query headers with post policy
// - http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html
// returns ErrNone if the signature matches.
func doesPolicySignatureV4Match(formValues map[string]string) APIErrorCode {
func doesPolicySignatureV4Match(formValues http.Header) APIErrorCode {
// Access credentials.
cred := serverConfig.GetCredential()
@ -166,7 +166,7 @@ func doesPolicySignatureV4Match(formValues map[string]string) APIErrorCode {
region := serverConfig.GetRegion()
// Parse credential tag.
credHeader, err := parseCredentialHeader("Credential=" + formValues["X-Amz-Credential"])
credHeader, err := parseCredentialHeader("Credential=" + formValues.Get("X-Amz-Credential"))
if err != ErrNone {
return ErrMissingFields
}
@ -186,12 +186,14 @@ func doesPolicySignatureV4Match(formValues map[string]string) APIErrorCode {
signingKey := getSigningKey(cred.SecretKey, credHeader.scope.date, region)
// Get signature.
newSignature := getSignature(signingKey, formValues["Policy"])
newSignature := getSignature(signingKey, formValues.Get("Policy"))
// Verify signature.
if newSignature != formValues["X-Amz-Signature"] {
if newSignature != formValues.Get("X-Amz-Signature") {
return ErrSignatureDoesNotMatch
}
// Success.
return ErrNone
}

View file

@ -39,45 +39,50 @@ func TestDoesPolicySignatureMatch(t *testing.T) {
accessKey := serverConfig.GetCredential().AccessKey
testCases := []struct {
form map[string]string
form http.Header
expected APIErrorCode
}{
// (0) It should fail if 'X-Amz-Credential' is missing.
{
form: map[string]string{},
form: http.Header{},
expected: ErrMissingFields,
},
// (1) It should fail if the access key is incorrect.
{
form: map[string]string{
"X-Amz-Credential": fmt.Sprintf(credentialTemplate, "EXAMPLEINVALIDEXAMPL", now.Format(yyyymmdd), globalMinioDefaultRegion),
form: http.Header{
"X-Amz-Credential": []string{fmt.Sprintf(credentialTemplate, "EXAMPLEINVALIDEXAMPL", now.Format(yyyymmdd), globalMinioDefaultRegion)},
},
expected: ErrInvalidAccessKeyID,
},
// (2) It should fail if the region is invalid.
{
form: map[string]string{
"X-Amz-Credential": fmt.Sprintf(credentialTemplate, accessKey, now.Format(yyyymmdd), "invalidregion"),
form: http.Header{
"X-Amz-Credential": []string{fmt.Sprintf(credentialTemplate, accessKey, now.Format(yyyymmdd), "invalidregion")},
},
expected: ErrInvalidRegion,
},
// (3) It should fail with a bad signature.
{
form: map[string]string{
"X-Amz-Credential": fmt.Sprintf(credentialTemplate, accessKey, now.Format(yyyymmdd), globalMinioDefaultRegion),
"X-Amz-Date": now.Format(iso8601Format),
"X-Amz-Signature": "invalidsignature",
"Policy": "policy",
form: http.Header{
"X-Amz-Credential": []string{fmt.Sprintf(credentialTemplate, accessKey, now.Format(yyyymmdd), globalMinioDefaultRegion)},
"X-Amz-Date": []string{now.Format(iso8601Format)},
"X-Amz-Signature": []string{"invalidsignature"},
"Policy": []string{"policy"},
},
expected: ErrSignatureDoesNotMatch,
},
// (4) It should succeed if everything is correct.
{
form: map[string]string{
"X-Amz-Credential": fmt.Sprintf(credentialTemplate, accessKey, now.Format(yyyymmdd), globalMinioDefaultRegion),
"X-Amz-Date": now.Format(iso8601Format),
"X-Amz-Signature": getSignature(getSigningKey(serverConfig.GetCredential().SecretKey, now, globalMinioDefaultRegion), "policy"),
"Policy": "policy",
form: http.Header{
"X-Amz-Credential": []string{
fmt.Sprintf(credentialTemplate, accessKey, now.Format(yyyymmdd), globalMinioDefaultRegion),
},
"X-Amz-Date": []string{now.Format(iso8601Format)},
"X-Amz-Signature": []string{
getSignature(getSigningKey(serverConfig.GetCredential().SecretKey, now,
globalMinioDefaultRegion), "policy"),
},
"Policy": []string{"policy"},
},
expected: ErrNone,
},

View file

@ -292,9 +292,7 @@ objectLoop:
ObjInfo: ObjectInfo{
Name: objectName,
},
ReqParams: map[string]string{
"sourceIPAddress": r.RemoteAddr,
},
ReqParams: extractReqParams(r),
})
}
return err
@ -528,12 +526,10 @@ func (web *webAPIHandlers) Upload(w http.ResponseWriter, r *http.Request) {
// Notify object created event.
eventNotify(eventData{
Type: ObjectCreatedPut,
Bucket: bucket,
ObjInfo: objInfo,
ReqParams: map[string]string{
"sourceIPAddress": r.RemoteAddr,
},
Type: ObjectCreatedPut,
Bucket: bucket,
ObjInfo: objInfo,
ReqParams: extractReqParams(r),
})
}