diff --git a/cmd/admin-bucket-handlers.go b/cmd/admin-bucket-handlers.go index 5ebc5d5ef..b6327b414 100644 --- a/cmd/admin-bucket-handlers.go +++ b/cmd/admin-bucket-handlers.go @@ -122,7 +122,7 @@ func (a adminAPIHandlers) SetRemoteTargetHandler(w http.ResponseWriter, r *http. defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r)) vars := mux.Vars(r) bucket := pathClean(vars["bucket"]) - update := r.URL.Query().Get("update") == "true" + update := r.Form.Get("update") == "true" if !globalIsErasure { writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL) @@ -169,7 +169,7 @@ func (a adminAPIHandlers) SetRemoteTargetHandler(w http.ResponseWriter, r *http. target.SourceBucket = bucket var ops []madmin.TargetUpdateType if update { - ops = madmin.GetTargetUpdateOps(r.URL.Query()) + ops = madmin.GetTargetUpdateOps(r.Form) } else { target.Arn = globalBucketTargetSys.getRemoteARN(bucket, &target) } diff --git a/cmd/admin-handlers-config-kv.go b/cmd/admin-handlers-config-kv.go index 3b9a2a48c..1a34e6324 100644 --- a/cmd/admin-handlers-config-kv.go +++ b/cmd/admin-handlers-config-kv.go @@ -337,7 +337,7 @@ func (a adminAPIHandlers) HelpConfigKVHandler(w http.ResponseWriter, r *http.Req subSys := vars["subSys"] key := vars["key"] - _, envOnly := r.URL.Query()["env"] + _, envOnly := r.Form["env"] rd, err := GetHelp(subSys, key, envOnly) if err != nil { diff --git a/cmd/admin-handlers-users.go b/cmd/admin-handlers-users.go index 5e3046c2e..04665ceca 100644 --- a/cmd/admin-handlers-users.go +++ b/cmd/admin-handlers-users.go @@ -851,7 +851,7 @@ func (a adminAPIHandlers) ListServiceAccounts(w http.ResponseWriter, r *http.Req var targetAccount string - user := r.URL.Query().Get("user") + user := r.Form.Get("user") if user != "" { if !globalIAMSys.IsAllowed(iampolicy.Args{ AccountName: cred.AccessKey, @@ -997,7 +997,7 @@ func (a adminAPIHandlers) AccountInfoHandler(w http.ResponseWriter, r *http.Requ r.Header.Set("delimiter", SlashSeparator) // Check if we are asked to return prefix usage - enablePrefixUsage := r.URL.Query().Get("prefix-usage") == "true" + enablePrefixUsage := r.Form.Get("prefix-usage") == "true" isAllowedAccess := func(bucketName string) (rd, wr bool) { if globalIAMSys.IsAllowed(iampolicy.Args{ diff --git a/cmd/admin-handlers.go b/cmd/admin-handlers.go index bc2d7a0ee..b86cd18fe 100644 --- a/cmd/admin-handlers.go +++ b/cmd/admin-handlers.go @@ -450,7 +450,7 @@ func (a adminAPIHandlers) TopLocksHandler(w http.ResponseWriter, r *http.Request } count := 10 // by default list only top 10 entries - if countStr := r.URL.Query().Get("count"); countStr != "" { + if countStr := r.Form.Get("count"); countStr != "" { var err error count, err = strconv.Atoi(countStr) if err != nil { @@ -458,7 +458,7 @@ func (a adminAPIHandlers) TopLocksHandler(w http.ResponseWriter, r *http.Request return } } - stale := r.URL.Query().Get("stale") == "true" // list also stale locks + stale := r.Form.Get("stale") == "true" // list also stale locks peerLocks := globalNotificationSys.GetLocks(ctx, r) @@ -713,7 +713,7 @@ func (a adminAPIHandlers) HealHandler(w http.ResponseWriter, r *http.Request) { return } - hip, errCode := extractHealInitParams(mux.Vars(r), r.URL.Query(), r.Body) + hip, errCode := extractHealInitParams(mux.Vars(r), r.Form, r.Body) if errCode != ErrNone { writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(errCode), r.URL) return @@ -926,9 +926,9 @@ func (a adminAPIHandlers) SpeedtestHandler(w http.ResponseWriter, r *http.Reques return } - sizeStr := r.URL.Query().Get(peerRESTSize) - durationStr := r.URL.Query().Get(peerRESTDuration) - concurrentStr := r.URL.Query().Get(peerRESTConcurrent) + sizeStr := r.Form.Get(peerRESTSize) + durationStr := r.Form.Get(peerRESTDuration) + concurrentStr := r.Form.Get(peerRESTConcurrent) size, err := strconv.Atoi(sizeStr) if err != nil { @@ -1157,7 +1157,7 @@ func mustTrace(entry interface{}, opts madmin.ServiceTraceOpts) (shouldTrace boo } func extractTraceOptions(r *http.Request) (opts madmin.ServiceTraceOpts, err error) { - q := r.URL.Query() + q := r.Form opts.OnlyErrors = q.Get("err") == "true" opts.S3 = q.Get("s3") == "true" @@ -1259,15 +1259,15 @@ func (a adminAPIHandlers) ConsoleLogHandler(w http.ResponseWriter, r *http.Reque if objectAPI == nil { return } - node := r.URL.Query().Get("node") + node := r.Form.Get("node") // limit buffered console entries if client requested it. - limitStr := r.URL.Query().Get("limit") + limitStr := r.Form.Get("limit") limitLines, err := strconv.Atoi(limitStr) if err != nil { limitLines = 10 } - logKind := r.URL.Query().Get("logType") + logKind := r.Form.Get("logType") if logKind == "" { logKind = string(logger.All) } @@ -1342,7 +1342,7 @@ func (a adminAPIHandlers) KMSCreateKeyHandler(w http.ResponseWriter, r *http.Req return } - if err := GlobalKMS.CreateKey(r.URL.Query().Get("key-id")); err != nil { + if err := GlobalKMS.CreateKey(r.Form.Get("key-id")); err != nil { writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) return } @@ -1409,7 +1409,7 @@ func (a adminAPIHandlers) KMSKeyStatusHandler(w http.ResponseWriter, r *http.Req return } - keyID := r.URL.Query().Get("key-id") + keyID := r.Form.Get("key-id") if keyID == "" { keyID = stat.DefaultKey } @@ -1576,7 +1576,7 @@ func (a adminAPIHandlers) HealthInfoHandler(w http.ResponseWriter, r *http.Reque return } - query := r.URL.Query() + query := r.Form healthInfo := madmin.HealthInfo{Version: madmin.HealthInfoVersion} healthInfoCh := make(chan madmin.HealthInfo) @@ -1600,7 +1600,7 @@ func (a adminAPIHandlers) HealthInfoHandler(w http.ResponseWriter, r *http.Reque } deadline := 1 * time.Hour - if dstr := r.URL.Query().Get("deadline"); dstr != "" { + if dstr := r.Form.Get("deadline"); dstr != "" { var err error deadline, err = time.ParseDuration(dstr) if err != nil { @@ -1975,7 +1975,7 @@ func (a adminAPIHandlers) BandwidthMonitorHandler(w http.ResponseWriter, r *http reportCh := make(chan madmin.BucketBandwidthReport) keepAliveTicker := time.NewTicker(500 * time.Millisecond) defer keepAliveTicker.Stop() - bucketsRequestedString := r.URL.Query().Get("buckets") + bucketsRequestedString := r.Form.Get("buckets") bucketsRequested := strings.Split(bucketsRequestedString, ",") go func() { defer close(reportCh) @@ -2233,8 +2233,8 @@ func (a adminAPIHandlers) InspectDataHandler(w http.ResponseWriter, r *http.Requ return } - volume := r.URL.Query().Get("volume") - file := r.URL.Query().Get("file") + volume := r.Form.Get("volume") + file := r.Form.Get("file") if len(volume) == 0 { writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidBucketName), r.URL) return diff --git a/cmd/auth-handler.go b/cmd/auth-handler.go index 1e94b211b..f08873052 100644 --- a/cmd/auth-handler.go +++ b/cmd/auth-handler.go @@ -27,6 +27,7 @@ import ( "io" "io/ioutil" "net/http" + "net/url" "strconv" "strings" "sync/atomic" @@ -61,13 +62,13 @@ func isRequestSignatureV2(r *http.Request) bool { // Verify if request has AWS PreSign Version '4'. func isRequestPresignedSignatureV4(r *http.Request) bool { - _, ok := r.URL.Query()[xhttp.AmzCredential] + _, ok := r.Form[xhttp.AmzCredential] return ok } // Verify request has AWS PreSign Version '2'. func isRequestPresignedSignatureV2(r *http.Request) bool { - _, ok := r.URL.Query()[xhttp.AmzAccessKeyID] + _, ok := r.Form[xhttp.AmzAccessKeyID] return ok } @@ -102,6 +103,14 @@ const ( // Get request authentication type. func getRequestAuthType(r *http.Request) authType { + if r.URL != nil { + var err error + r.Form, err = url.ParseQuery(r.URL.RawQuery) + if err != nil { + logger.LogIf(r.Context(), err) + return authTypeUnknown + } + } if isRequestSignatureV2(r) { return authTypeSignedV2 } else if isRequestPresignedSignatureV2(r) { @@ -116,7 +125,7 @@ func getRequestAuthType(r *http.Request) authType { return authTypeJWT } else if isRequestPostPolicySignatureV4(r) { return authTypePostPolicy - } else if _, ok := r.URL.Query()[xhttp.Action]; ok { + } else if _, ok := r.Form[xhttp.Action]; ok { return authTypeSTS } else if _, ok := r.Header[xhttp.Authorization]; !ok { return authTypeAnonymous @@ -183,7 +192,7 @@ func getSessionToken(r *http.Request) (token string) { if token != "" { return token } - return r.URL.Query().Get(xhttp.AmzSecurityToken) + return r.Form.Get(xhttp.AmzSecurityToken) } // Fetch claims in the security token returned by the client, doesn't return @@ -444,7 +453,7 @@ func isReqAuthenticated(ctx context.Context, r *http.Request, region string, sty // Do not verify 'X-Amz-Content-Sha256' if skipSHA256. var contentSHA256 []byte if skipSHA256 := skipContentSha256Cksum(r); !skipSHA256 && isRequestPresignedSignatureV4(r) { - if sha256Sum, ok := r.URL.Query()[xhttp.AmzContentSha256]; ok && len(sha256Sum) > 0 { + if sha256Sum, ok := r.Form[xhttp.AmzContentSha256]; ok && len(sha256Sum) > 0 { contentSHA256, err = hex.DecodeString(sha256Sum[0]) if err != nil { return ErrContentSHA256Mismatch diff --git a/cmd/auth-handler_test.go b/cmd/auth-handler_test.go index 499047279..35478e40e 100644 --- a/cmd/auth-handler_test.go +++ b/cmd/auth-handler_test.go @@ -38,6 +38,7 @@ func TestGetRequestAuthType(t *testing.T) { req *http.Request authT authType } + nopCloser := ioutil.NopCloser(io.LimitReader(&nullReader{}, 1024)) testCases := []testCase{ // Test case - 1 // Check for generic signature v4 header. @@ -54,6 +55,7 @@ func TestGetRequestAuthType(t *testing.T) { "Content-Encoding": []string{streamingContentEncoding}, }, Method: http.MethodPut, + Body: nopCloser, }, authT: authTypeStreamingSigned, }, @@ -113,6 +115,7 @@ func TestGetRequestAuthType(t *testing.T) { "Content-Type": []string{"multipart/form-data"}, }, Method: http.MethodPost, + Body: nopCloser, }, authT: authTypePostPolicy, }, @@ -220,6 +223,7 @@ func TestIsRequestPresignedSignatureV2(t *testing.T) { q := inputReq.URL.Query() q.Add(testCase.inputQueryKey, testCase.inputQueryValue) inputReq.URL.RawQuery = q.Encode() + inputReq.ParseForm() actualResult := isRequestPresignedSignatureV2(inputReq) if testCase.expectedResult != actualResult { @@ -254,6 +258,7 @@ func TestIsRequestPresignedSignatureV4(t *testing.T) { q := inputReq.URL.Query() q.Add(testCase.inputQueryKey, testCase.inputQueryValue) inputReq.URL.RawQuery = q.Encode() + inputReq.ParseForm() actualResult := isRequestPresignedSignatureV4(inputReq) if testCase.expectedResult != actualResult { diff --git a/cmd/bucket-handlers.go b/cmd/bucket-handlers.go index 7f1756ba5..e6c3dc4f1 100644 --- a/cmd/bucket-handlers.go +++ b/cmd/bucket-handlers.go @@ -246,7 +246,7 @@ func (api objectAPIHandlers) ListMultipartUploadsHandler(w http.ResponseWriter, return } - prefix, keyMarker, uploadIDMarker, delimiter, maxUploads, encodingType, errCode := getBucketMultipartResources(r.URL.Query()) + prefix, keyMarker, uploadIDMarker, delimiter, maxUploads, encodingType, errCode := getBucketMultipartResources(r.Form) if errCode != ErrNone { writeErrorResponse(ctx, w, errorCodes.ToAPIErr(errCode), r.URL) return @@ -1699,7 +1699,7 @@ func (api objectAPIHandlers) ResetBucketReplicationStateHandler(w http.ResponseW vars := mux.Vars(r) bucket := vars["bucket"] - durationStr := r.URL.Query().Get("older-than") + durationStr := r.Form.Get("older-than") var ( days time.Duration err error diff --git a/cmd/bucket-lifecycle.go b/cmd/bucket-lifecycle.go index fd3b991db..511e5d38e 100644 --- a/cmd/bucket-lifecycle.go +++ b/cmd/bucket-lifecycle.go @@ -458,7 +458,7 @@ func (r *RestoreObjectRequest) validate(ctx context.Context, objAPI ObjectLayer) func postRestoreOpts(ctx context.Context, r *http.Request, bucket, object string) (opts ObjectOptions, err error) { versioned := globalBucketVersioningSys.Enabled(bucket) versionSuspended := globalBucketVersioningSys.Suspended(bucket) - vid := strings.TrimSpace(r.URL.Query().Get(xhttp.VersionID)) + vid := strings.TrimSpace(r.Form.Get(xhttp.VersionID)) if vid != "" && vid != nullVersionID { _, err := uuid.Parse(vid) if err != nil { diff --git a/cmd/bucket-listobjects-handlers.go b/cmd/bucket-listobjects-handlers.go index 4c7be8198..5fa687dd4 100644 --- a/cmd/bucket-listobjects-handlers.go +++ b/cmd/bucket-listobjects-handlers.go @@ -92,7 +92,7 @@ func (api objectAPIHandlers) ListObjectVersionsHandler(w http.ResponseWriter, r return } - urlValues := r.URL.Query() + urlValues := r.Form // Extract all the listBucketVersions query params to their native values. prefix, marker, delimiter, maxkeys, encodingType, versionIDMarker, errCode := getListBucketObjectVersionsArgs(urlValues) @@ -153,7 +153,7 @@ func (api objectAPIHandlers) ListObjectsV2MHandler(w http.ResponseWriter, r *htt return } - urlValues := r.URL.Query() + urlValues := r.Form // Extract all the listObjectsV2 query params to their native values. prefix, token, startAfter, delimiter, fetchOwner, maxKeys, encodingType, errCode := getListObjectsV2Args(urlValues) @@ -220,7 +220,7 @@ func (api objectAPIHandlers) ListObjectsV2Handler(w http.ResponseWriter, r *http return } - urlValues := r.URL.Query() + urlValues := r.Form // Extract all the listObjectsV2 query params to their native values. prefix, token, startAfter, delimiter, fetchOwner, maxKeys, encodingType, errCode := getListObjectsV2Args(urlValues) @@ -329,7 +329,7 @@ func (api objectAPIHandlers) ListObjectsV1Handler(w http.ResponseWriter, r *http } // Extract all the litsObjectsV1 query params to their native values. - prefix, marker, delimiter, maxKeys, encodingType, s3Error := getListObjectsV1Args(r.URL.Query()) + prefix, marker, delimiter, maxKeys, encodingType, s3Error := getListObjectsV1Args(r.Form) if s3Error != ErrNone { writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL) return diff --git a/cmd/bucket-policy.go b/cmd/bucket-policy.go index 2d6436897..e8db0ac17 100644 --- a/cmd/bucket-policy.go +++ b/cmd/bucket-policy.go @@ -77,10 +77,10 @@ func getConditionValues(r *http.Request, lc string, username string, claims map[ } } - vid := r.URL.Query().Get("versionId") + vid := r.Form.Get(xhttp.VersionID) if vid == "" { if u, err := url.Parse(r.Header.Get(xhttp.AmzCopySource)); err == nil { - vid = u.Query().Get("versionId") + vid = u.Query().Get(xhttp.VersionID) } } @@ -143,8 +143,8 @@ func getConditionValues(r *http.Request, lc string, username string, claims map[ } } - var cloneURLValues = url.Values{} - for k, v := range r.URL.Query() { + cloneURLValues := make(url.Values, len(r.Form)) + for k, v := range r.Form { cloneURLValues[k] = v } diff --git a/cmd/crossdomain-xml-handler_test.go b/cmd/crossdomain-xml-handler_test.go index 51e047993..6158fd2fd 100644 --- a/cmd/crossdomain-xml-handler_test.go +++ b/cmd/crossdomain-xml-handler_test.go @@ -28,7 +28,7 @@ import ( // Test cross domain xml handler. func TestCrossXMLHandler(t *testing.T) { // Server initialization. - router := mux.NewRouter().SkipClean(true) + router := mux.NewRouter().SkipClean(true).UseEncodedPath() handler := setCrossDomainPolicy(router) srv := httptest.NewServer(handler) diff --git a/cmd/generic-handlers.go b/cmd/generic-handlers.go index fae367b24..9496ba606 100644 --- a/cmd/generic-handlers.go +++ b/cmd/generic-handlers.go @@ -406,7 +406,7 @@ func setRequestValidityHandler(h http.Handler) http.Handler { return } // Check for bad components in URL query values. - for _, vv := range r.URL.Query() { + for _, vv := range r.Form { for _, v := range vv { if hasBadPathComponent(v) { writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrInvalidResourceName), r.URL) @@ -436,55 +436,6 @@ func setBucketForwardingHandler(h http.Handler) http.Handler { return } - // For browser requests, when federation is setup we need to - // specifically handle download and upload for browser requests. - if guessIsBrowserReq(r) { - var bucket, _ string - switch r.Method { - case http.MethodPut: - if getRequestAuthType(r) == authTypeJWT { - bucket, _ = path2BucketObjectWithBasePath(minioReservedBucketPath+"/upload", r.URL.Path) - } - case http.MethodGet: - if t := r.URL.Query().Get("token"); t != "" { - bucket, _ = path2BucketObjectWithBasePath(minioReservedBucketPath+"/download", r.URL.Path) - } else if getRequestAuthType(r) != authTypeJWT && !strings.HasPrefix(r.URL.Path, minioReservedBucketPath) { - bucket, _ = request2BucketObjectName(r) - } - } - if bucket == "" { - h.ServeHTTP(w, r) - return - } - sr, err := globalDNSConfig.Get(bucket) - if err != nil { - if err == dns.ErrNoEntriesFound { - writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrNoSuchBucket), - r.URL) - } else { - writeErrorResponse(r.Context(), w, toAPIError(r.Context(), err), - r.URL) - } - return - } - if globalDomainIPs.Intersection(set.CreateStringSet(getHostsSlice(sr)...)).IsEmpty() { - r.URL.Scheme = "http" - if globalIsTLS { - r.URL.Scheme = "https" - } - r.URL.Host = getHostFromSrv(sr) - // Make sure we remove any existing headers before - // proxying the request to another node. - for k := range w.Header() { - w.Header().Del(k) - } - globalForwarder.ServeHTTP(w, r) - return - } - h.ServeHTTP(w, r) - return - } - bucket, object := request2BucketObjectName(r) // Requests in federated setups for STS type calls which are diff --git a/cmd/handler-utils.go b/cmd/handler-utils.go index 68a00f268..e1678c0be 100644 --- a/cmd/handler-utils.go +++ b/cmd/handler-utils.go @@ -112,7 +112,7 @@ var userMetadataKeyPrefixes = []string{ // extractMetadata extracts metadata from HTTP header and HTTP queryString. func extractMetadata(ctx context.Context, r *http.Request) (metadata map[string]string, err error) { - query := r.URL.Query() + query := r.Form header := r.Header metadata = make(map[string]string) // Extract all query values. diff --git a/cmd/healthcheck-handler.go b/cmd/healthcheck-handler.go index 821e6446b..221e2368b 100644 --- a/cmd/healthcheck-handler.go +++ b/cmd/healthcheck-handler.go @@ -42,7 +42,7 @@ func ClusterCheckHandler(w http.ResponseWriter, r *http.Request) { ctx, cancel := context.WithTimeout(ctx, globalAPIConfig.getClusterDeadline()) defer cancel() - opts := HealthOptions{Maintenance: r.URL.Query().Get("maintenance") == "true"} + opts := HealthOptions{Maintenance: r.Form.Get("maintenance") == "true"} result := objLayer.Health(ctx, opts) if result.WriteQuorum > 0 { w.Header().Set(xhttp.MinIOWriteQuorum, strconv.Itoa(result.WriteQuorum)) diff --git a/cmd/listen-notification-handlers.go b/cmd/listen-notification-handlers.go index 2da032166..3850bba18 100644 --- a/cmd/listen-notification-handlers.go +++ b/cmd/listen-notification-handlers.go @@ -65,7 +65,7 @@ func (api objectAPIHandlers) ListenNotificationHandler(w http.ResponseWriter, r } } - values := r.URL.Query() + values := r.Form var prefix string if len(values[peerRESTListenPrefix]) > 1 { diff --git a/cmd/lock-rest-server.go b/cmd/lock-rest-server.go index 1d6506d42..bebd00ca4 100644 --- a/cmd/lock-rest-server.go +++ b/cmd/lock-rest-server.go @@ -63,15 +63,16 @@ func (l *lockRESTServer) IsValid(w http.ResponseWriter, r *http.Request) bool { } func getLockArgs(r *http.Request) (args dsync.LockArgs, err error) { - quorum, err := strconv.Atoi(r.URL.Query().Get(lockRESTQuorum)) + values := r.Form + quorum, err := strconv.Atoi(values.Get(lockRESTQuorum)) if err != nil { return args, err } args = dsync.LockArgs{ - Owner: r.URL.Query().Get(lockRESTOwner), - UID: r.URL.Query().Get(lockRESTUID), - Source: r.URL.Query().Get(lockRESTSource), + Owner: values.Get(lockRESTOwner), + UID: values.Get(lockRESTUID), + Source: values.Get(lockRESTSource), Quorum: quorum, } diff --git a/cmd/metacache-walk.go b/cmd/metacache-walk.go index 78af572a4..572dd0eb2 100644 --- a/cmd/metacache-walk.go +++ b/cmd/metacache-walk.go @@ -332,8 +332,8 @@ func (s *storageRESTServer) WalkDirHandler(w http.ResponseWriter, r *http.Reques } } - prefix := r.URL.Query().Get(storageRESTPrefixFilter) - forward := r.URL.Query().Get(storageRESTForwardFilter) + prefix := r.Form.Get(storageRESTPrefixFilter) + forward := r.Form.Get(storageRESTForwardFilter) writer := streamHTTPResponse(w) writer.CloseWithError(s.storage.WalkDir(r.Context(), WalkDirOptions{ Bucket: volume, diff --git a/cmd/object-api-options.go b/cmd/object-api-options.go index c2e90f291..3f71f0156 100644 --- a/cmd/object-api-options.go +++ b/cmd/object-api-options.go @@ -83,7 +83,7 @@ func getOpts(ctx context.Context, r *http.Request, bucket, object string) (Objec var partNumber int var err error - if pn := r.URL.Query().Get(xhttp.PartNumber); pn != "" { + if pn := r.Form.Get(xhttp.PartNumber); pn != "" { partNumber, err = strconv.Atoi(pn) if err != nil { return opts, err @@ -93,7 +93,7 @@ func getOpts(ctx context.Context, r *http.Request, bucket, object string) (Objec } } - vid := strings.TrimSpace(r.URL.Query().Get(xhttp.VersionID)) + vid := strings.TrimSpace(r.Form.Get(xhttp.VersionID)) if vid != "" && vid != nullVersionID { _, err := uuid.Parse(vid) if err != nil { @@ -219,7 +219,7 @@ func delOpts(ctx context.Context, r *http.Request, bucket, object string) (opts // get ObjectOptions for PUT calls from encryption headers and metadata func putOpts(ctx context.Context, r *http.Request, bucket, object string, metadata map[string]string) (opts ObjectOptions, err error) { versioned := globalBucketVersioningSys.Enabled(bucket) - vid := strings.TrimSpace(r.URL.Query().Get(xhttp.VersionID)) + vid := strings.TrimSpace(r.Form.Get(xhttp.VersionID)) if vid != "" && vid != nullVersionID { _, err := uuid.Parse(vid) if err != nil { diff --git a/cmd/object-handlers.go b/cmd/object-handlers.go index 8f4c596bd..b64e64c95 100644 --- a/cmd/object-handlers.go +++ b/cmd/object-handlers.go @@ -491,7 +491,7 @@ func (api objectAPIHandlers) getObjectHandler(ctx context.Context, objectAPI Obj setPartsCountHeaders(w, objInfo) } - setHeadGetRespHeaders(w, r.URL.Query()) + setHeadGetRespHeaders(w, r.Form) statusCodeWritten := false httpWriter := ioutil.WriteOnClose(w) @@ -739,7 +739,7 @@ func (api objectAPIHandlers) headObjectHandler(ctx context.Context, objectAPI Ob } // Set any additional requested response headers. - setHeadGetRespHeaders(w, r.URL.Query()) + setHeadGetRespHeaders(w, r.Form) // Successful response. if rs != nil || opts.PartNumber > 0 { @@ -806,7 +806,7 @@ func getCpObjMetadataFromHeader(ctx context.Context, r *http.Request, userMeta m // to the destination metadata. sc := r.Header.Get(xhttp.AmzStorageClass) if sc == "" { - sc = r.URL.Query().Get(xhttp.AmzStorageClass) + sc = r.Form.Get(xhttp.AmzStorageClass) } // if x-amz-metadata-directive says REPLACE then @@ -2264,8 +2264,8 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt return } - uploadID := r.URL.Query().Get(xhttp.UploadID) - partIDString := r.URL.Query().Get(xhttp.PartNumber) + uploadID := r.Form.Get(xhttp.UploadID) + partIDString := r.Form.Get(xhttp.PartNumber) partID, err := strconv.Atoi(partIDString) if err != nil { @@ -2591,8 +2591,8 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http return } - uploadID := r.URL.Query().Get(xhttp.UploadID) - partIDString := r.URL.Query().Get(xhttp.PartNumber) + uploadID := r.Form.Get(xhttp.UploadID) + partIDString := r.Form.Get(xhttp.PartNumber) partID, err := strconv.Atoi(partIDString) if err != nil { @@ -2812,7 +2812,7 @@ func (api objectAPIHandlers) AbortMultipartUploadHandler(w http.ResponseWriter, return } - uploadID, _, _, _, s3Error := getObjectResources(r.URL.Query()) + uploadID, _, _, _, s3Error := getObjectResources(r.Form) if s3Error != ErrNone { writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL) return @@ -2851,7 +2851,7 @@ func (api objectAPIHandlers) ListObjectPartsHandler(w http.ResponseWriter, r *ht return } - uploadID, partNumberMarker, maxParts, encodingType, s3Error := getObjectResources(r.URL.Query()) + uploadID, partNumberMarker, maxParts, encodingType, s3Error := getObjectResources(r.Form) if s3Error != ErrNone { writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL) return @@ -2997,7 +2997,7 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite } // Get upload id. - uploadID, _, _, _, s3Error := getObjectResources(r.URL.Query()) + uploadID, _, _, _, s3Error := getObjectResources(r.Form) if s3Error != ErrNone { writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL) return diff --git a/cmd/object-handlers_test.go b/cmd/object-handlers_test.go index 158fbebbb..9499d50a2 100644 --- a/cmd/object-handlers_test.go +++ b/cmd/object-handlers_test.go @@ -26,6 +26,7 @@ import ( "encoding/xml" "fmt" "io" + "path" "runtime" "strings" @@ -557,12 +558,8 @@ func testAPIGetObjectHandler(obj ObjectLayer, instanceType, bucketName string, a t.Fatalf("Test %d: %s: Failed parsing response body: %v", i+1, instanceType, err) } - if actualError.BucketName != testCase.bucketName { - t.Fatalf("Test %d: %s: Unexpected bucket name, expected %s, got %s", i+1, instanceType, testCase.bucketName, actualError.BucketName) - } - - if actualError.Key != testCase.objectName { - t.Fatalf("Test %d: %s: Unexpected object name, expected %s, got %s", i+1, instanceType, testCase.objectName, actualError.Key) + if path.Clean(actualError.Resource) != pathJoin(SlashSeparator, testCase.bucketName, testCase.objectName) { + t.Fatalf("Test %d: %s: Unexpected resource, expected %s, got %s", i+1, instanceType, pathJoin(SlashSeparator, testCase.bucketName, testCase.objectName), actualError.Resource) } // Verify response of the V2 signed HTTP request. @@ -606,12 +603,8 @@ func testAPIGetObjectHandler(obj ObjectLayer, instanceType, bucketName string, a t.Fatalf("Test %d: %s: Failed parsing response body: %v", i+1, instanceType, err) } - if actualError.BucketName != testCase.bucketName { - t.Fatalf("Test %d: %s: Unexpected bucket name, expected %s, got %s", i+1, instanceType, testCase.bucketName, actualError.BucketName) - } - - if actualError.Key != testCase.objectName { - t.Fatalf("Test %d: %s: Unexpected object name, expected %s, got %s", i+1, instanceType, testCase.objectName, actualError.Key) + if path.Clean(actualError.Resource) != pathJoin(SlashSeparator, testCase.bucketName, testCase.objectName) { + t.Fatalf("Test %d: %s: Unexpected resource, expected %s, got %s", i+1, instanceType, pathJoin(SlashSeparator, testCase.bucketName, testCase.objectName), actualError.Resource) } } @@ -918,7 +911,6 @@ func testAPIGetObjectWithPartNumberHandler(obj ObjectLayer, instanceType, bucket mkGetReqWithPartNumber := func(oindex int, oi ObjectInput, partNumber int) { object := oi.objectName - rec := httptest.NewRecorder() queries := url.Values{} queries.Add("partNumber", strconv.Itoa(partNumber)) @@ -930,6 +922,7 @@ func testAPIGetObjectWithPartNumberHandler(obj ObjectLayer, instanceType, bucket object, oindex, partNumber, err) } + rec := httptest.NewRecorder() apiRouter.ServeHTTP(rec, req) // Check response code (we make only valid requests in this test) diff --git a/cmd/peer-rest-server.go b/cmd/peer-rest-server.go index 32300b261..3ba27f89c 100644 --- a/cmd/peer-rest-server.go +++ b/cmd/peer-rest-server.go @@ -136,7 +136,7 @@ func (s *peerRESTServer) LoadPolicyMappingHandler(w http.ResponseWriter, r *http return } - _, isGroup := r.URL.Query()[peerRESTIsGroup] + _, isGroup := r.Form[peerRESTIsGroup] if err := globalIAMSys.LoadPolicyMapping(objAPI, userOrGroup, isGroup); err != nil { s.writeErrorResponse(w, err) return @@ -841,7 +841,7 @@ func (s *peerRESTServer) ListenHandler(w http.ResponseWriter, r *http.Request) { return } - values := r.URL.Query() + values := r.Form var prefix string if len(values[peerRESTListenPrefix]) > 1 { @@ -932,15 +932,13 @@ func (s *peerRESTServer) ListenHandler(w http.ResponseWriter, r *http.Request) { } func extractTraceOptsFromPeerRequest(r *http.Request) (opts madmin.ServiceTraceOpts, err error) { + opts.S3 = r.Form.Get(peerRESTTraceS3) == "true" + opts.OS = r.Form.Get(peerRESTTraceOS) == "true" + opts.Storage = r.Form.Get(peerRESTTraceStorage) == "true" + opts.Internal = r.Form.Get(peerRESTTraceInternal) == "true" + opts.OnlyErrors = r.Form.Get(peerRESTTraceErr) == "true" - q := r.URL.Query() - opts.OnlyErrors = q.Get(peerRESTTraceErr) == "true" - opts.Storage = q.Get(peerRESTTraceStorage) == "true" - opts.Internal = q.Get(peerRESTTraceInternal) == "true" - opts.S3 = q.Get(peerRESTTraceS3) == "true" - opts.OS = q.Get(peerRESTTraceOS) == "true" - - if t := q.Get(peerRESTTraceThreshold); t != "" { + if t := r.Form.Get(peerRESTTraceThreshold); t != "" { d, err := time.ParseDuration(t) if err != nil { return opts, err @@ -1078,7 +1076,8 @@ func (s *peerRESTServer) GetBandwidth(w http.ResponseWriter, r *http.Request) { s.writeErrorResponse(w, errors.New("invalid request")) return } - bucketsString := r.URL.Query().Get("buckets") + + bucketsString := r.Form.Get("buckets") w.WriteHeader(http.StatusOK) w.(http.Flusher).Flush() @@ -1259,9 +1258,9 @@ func (s *peerRESTServer) SpeedtestHandler(w http.ResponseWriter, r *http.Request return } - sizeStr := r.URL.Query().Get(peerRESTSize) - durationStr := r.URL.Query().Get(peerRESTDuration) - concurrentStr := r.URL.Query().Get(peerRESTConcurrent) + sizeStr := r.Form.Get(peerRESTSize) + durationStr := r.Form.Get(peerRESTDuration) + concurrentStr := r.Form.Get(peerRESTConcurrent) size, err := strconv.Atoi(sizeStr) if err != nil { diff --git a/cmd/s3-zip-handlers.go b/cmd/s3-zip-handlers.go index 9cb8ea848..b36bea866 100644 --- a/cmd/s3-zip-handlers.go +++ b/cmd/s3-zip-handlers.go @@ -196,7 +196,7 @@ func (api objectAPIHandlers) getObjectInArchiveFileHandler(ctx context.Context, return } - setHeadGetRespHeaders(w, r.URL.Query()) + setHeadGetRespHeaders(w, r.Form) httpWriter := ioutil.WriteOnClose(w) @@ -467,7 +467,7 @@ func (api objectAPIHandlers) headObjectInArchiveFileHandler(ctx context.Context, } // Set any additional requested response headers. - setHeadGetRespHeaders(w, r.URL.Query()) + setHeadGetRespHeaders(w, r.Form) // Successful response. if rs != nil { diff --git a/cmd/signature-v2.go b/cmd/signature-v2.go index 7aee99a3b..dd56e095f 100644 --- a/cmd/signature-v2.go +++ b/cmd/signature-v2.go @@ -183,7 +183,7 @@ func doesPresignV2SignatureMatch(r *http.Request) APIErrorCode { } func getReqAccessKeyV2(r *http.Request) (auth.Credentials, bool, APIErrorCode) { - if accessKey := r.URL.Query().Get(xhttp.AmzAccessKeyID); accessKey != "" { + if accessKey := r.Form.Get(xhttp.AmzAccessKeyID); accessKey != "" { return checkKeyValid(accessKey) } diff --git a/cmd/signature-v4-parser.go b/cmd/signature-v4-parser.go index 0e8b05ce8..f40696833 100644 --- a/cmd/signature-v4-parser.go +++ b/cmd/signature-v4-parser.go @@ -50,7 +50,7 @@ func (c credentialHeader) getScope() string { } func getReqAccessKeyV4(r *http.Request, region string, stype serviceType) (auth.Credentials, bool, APIErrorCode) { - ch, s3Err := parseCredentialHeader("Credential="+r.URL.Query().Get(xhttp.AmzCredential), region, stype) + ch, s3Err := parseCredentialHeader("Credential="+r.Form.Get(xhttp.AmzCredential), region, stype) if s3Err != ErrNone { // Strip off the Algorithm prefix. v4Auth := strings.TrimPrefix(r.Header.Get("Authorization"), signV4Algorithm) diff --git a/cmd/signature-v4-utils.go b/cmd/signature-v4-utils.go index c2f749f56..856d36abb 100644 --- a/cmd/signature-v4-utils.go +++ b/cmd/signature-v4-utils.go @@ -46,7 +46,7 @@ func skipContentSha256Cksum(r *http.Request) bool { ) if isRequestPresignedSignatureV4(r) { - v, ok = r.URL.Query()[xhttp.AmzContentSha256] + v, ok = r.Form[xhttp.AmzContentSha256] if !ok { v, ok = r.Header[xhttp.AmzContentSha256] } @@ -82,7 +82,7 @@ func getContentSha256Cksum(r *http.Request, stype serviceType) string { // X-Amz-Content-Sha256, if not set in presigned requests, checksum // will default to 'UNSIGNED-PAYLOAD'. defaultSha256Cksum = unsignedPayload - v, ok = r.URL.Query()[xhttp.AmzContentSha256] + v, ok = r.Form[xhttp.AmzContentSha256] if !ok { v, ok = r.Header[xhttp.AmzContentSha256] } @@ -151,7 +151,7 @@ func sumHMAC(key []byte, data []byte) []byte { // extractSignedHeaders extract signed headers from Authorization header func extractSignedHeaders(signedHeaders []string, r *http.Request) (http.Header, APIErrorCode) { reqHeaders := r.Header - reqQueries := r.URL.Query() + reqQueries := r.Form // find whether "host" is part of list of signed headers. // if not return ErrUnsignedHeaders. "host" is mandatory. if !contains(signedHeaders, "host") { diff --git a/cmd/signature-v4-utils_test.go b/cmd/signature-v4-utils_test.go index 1784a7d7c..d56a20e70 100644 --- a/cmd/signature-v4-utils_test.go +++ b/cmd/signature-v4-utils_test.go @@ -89,6 +89,7 @@ func TestSkipContentSha256Cksum(t *testing.T) { inputReq.Header.Set(testCase.inputHeaderKey, testCase.inputHeaderValue) } } + inputReq.ParseForm() actualResult := skipContentSha256Cksum(inputReq) if testCase.expectedResult != actualResult { @@ -163,6 +164,7 @@ func TestExtractSignedHeaders(t *testing.T) { // set headers value through Get parameter inputQuery.Add("x-amz-server-side-encryption", xhttp.AmzEncryptionAES) r.URL.RawQuery = inputQuery.Encode() + r.ParseForm() _, errCode = extractSignedHeaders(signedHeaders, r) if errCode != ErrNone { t.Fatalf("Expected the APIErrorCode to be %d, but got %d", ErrNone, errCode) @@ -267,6 +269,7 @@ func TestGetContentSha256Cksum(t *testing.T) { if testCase.h != "" { r.Header.Set("x-amz-content-sha256", testCase.h) } + r.ParseForm() got := getContentSha256Cksum(r, serviceS3) if got != testCase.expected { t.Errorf("Test %d: got:%s expected:%s", i+1, got, testCase.expected) diff --git a/cmd/signature-v4.go b/cmd/signature-v4.go index b6b70e33a..9da2a16b1 100644 --- a/cmd/signature-v4.go +++ b/cmd/signature-v4.go @@ -209,7 +209,7 @@ func doesPresignedSignatureMatch(hashedPayload string, r *http.Request, region s req := *r // Parse request query string. - pSignValues, err := parsePreSignV4(req.URL.Query(), region, stype) + pSignValues, err := parsePreSignV4(req.Form, region, stype) if err != ErrNone { return err } @@ -241,12 +241,12 @@ func doesPresignedSignatureMatch(hashedPayload string, r *http.Request, region s // Construct new query. query := make(url.Values) - clntHashedPayload := req.URL.Query().Get(xhttp.AmzContentSha256) + clntHashedPayload := req.Form.Get(xhttp.AmzContentSha256) if clntHashedPayload != "" { query.Set(xhttp.AmzContentSha256, hashedPayload) } - token := req.URL.Query().Get(xhttp.AmzSecurityToken) + token := req.Form.Get(xhttp.AmzSecurityToken) if token != "" { query.Set(xhttp.AmzSecurityToken, cred.SessionToken) } @@ -271,7 +271,7 @@ func doesPresignedSignatureMatch(hashedPayload string, r *http.Request, region s ) // Add missing query parameters if any provided in the request URL - for k, v := range req.URL.Query() { + for k, v := range req.Form { if !defaultSigParams.Contains(k) { query[k] = v } @@ -281,19 +281,19 @@ func doesPresignedSignatureMatch(hashedPayload string, r *http.Request, region s encodedQuery := query.Encode() // Verify if date query is same. - if req.URL.Query().Get(xhttp.AmzDate) != query.Get(xhttp.AmzDate) { + if req.Form.Get(xhttp.AmzDate) != query.Get(xhttp.AmzDate) { return ErrSignatureDoesNotMatch } // Verify if expires query is same. - if req.URL.Query().Get(xhttp.AmzExpires) != query.Get(xhttp.AmzExpires) { + if req.Form.Get(xhttp.AmzExpires) != query.Get(xhttp.AmzExpires) { return ErrSignatureDoesNotMatch } // Verify if signed headers query is same. - if req.URL.Query().Get(xhttp.AmzSignedHeaders) != query.Get(xhttp.AmzSignedHeaders) { + if req.Form.Get(xhttp.AmzSignedHeaders) != query.Get(xhttp.AmzSignedHeaders) { return ErrSignatureDoesNotMatch } // Verify if credential query is same. - if req.URL.Query().Get(xhttp.AmzCredential) != query.Get(xhttp.AmzCredential) { + if req.Form.Get(xhttp.AmzCredential) != query.Get(xhttp.AmzCredential) { return ErrSignatureDoesNotMatch } // Verify if sha256 payload query is same. @@ -321,7 +321,7 @@ func doesPresignedSignatureMatch(hashedPayload string, r *http.Request, region s newSignature := getSignature(presignedSigningKey, presignedStringToSign) // Verify signature. - if !compareSignatureV4(req.URL.Query().Get(xhttp.AmzSignature), newSignature) { + if !compareSignatureV4(req.Form.Get(xhttp.AmzSignature), newSignature) { return ErrSignatureDoesNotMatch } return ErrNone @@ -369,7 +369,7 @@ func doesSignatureMatch(hashedPayload string, r *http.Request, region string, st } // Query string. - queryStr := req.URL.Query().Encode() + queryStr := req.Form.Encode() // Get canonical request. canonicalRequest := getCanonicalRequest(extractedSignedHeaders, hashedPayload, queryStr, req.URL.Path, req.Method) diff --git a/cmd/signature-v4_test.go b/cmd/signature-v4_test.go index 16601d08a..0652e7bde 100644 --- a/cmd/signature-v4_test.go +++ b/cmd/signature-v4_test.go @@ -293,6 +293,9 @@ func TestDoesPresignedSignatureMatch(t *testing.T) { req.Header.Set(key, value) } + // parse form. + req.ParseForm() + // Check if it matches! err := doesPresignedSignatureMatch(payloadSHA256, req, testCase.region, serviceS3) if err != testCase.expected { diff --git a/cmd/storage-rest-server.go b/cmd/storage-rest-server.go index c47f044ab..50b9a9ff1 100644 --- a/cmd/storage-rest-server.go +++ b/cmd/storage-rest-server.go @@ -119,7 +119,7 @@ func (s *storageRESTServer) IsValid(w http.ResponseWriter, r *http.Request) bool return false } - diskID := r.URL.Query().Get(storageRESTDiskID) + diskID := r.Form.Get(storageRESTDiskID) if diskID == "" { // Request sent empty disk-id, we allow the request // as the peer might be coming up and trying to read format.json @@ -282,7 +282,7 @@ func (s *storageRESTServer) DeleteVolHandler(w http.ResponseWriter, r *http.Requ } vars := mux.Vars(r) volume := vars[storageRESTVolume] - forceDelete := r.URL.Query().Get(storageRESTForceDelete) == "true" + forceDelete := r.Form.Get(storageRESTForceDelete) == "true" err := s.storage.DeleteVol(r.Context(), volume, forceDelete) if err != nil { s.writeErrorResponse(w, err) @@ -641,10 +641,8 @@ func (s *storageRESTServer) DeleteVersionsHandler(w http.ResponseWriter, r *http return } - vars := r.URL.Query() - volume := vars.Get(storageRESTVolume) - - totalVersions, err := strconv.Atoi(vars.Get(storageRESTTotalVersions)) + volume := r.Form.Get(storageRESTVolume) + totalVersions, err := strconv.Atoi(r.Form.Get(storageRESTTotalVersions)) if err != nil { s.writeErrorResponse(w, err) return diff --git a/cmd/streaming-signature-v4.go b/cmd/streaming-signature-v4.go index 16be98964..accfb4c26 100644 --- a/cmd/streaming-signature-v4.go +++ b/cmd/streaming-signature-v4.go @@ -117,7 +117,7 @@ func calculateSeedSignature(r *http.Request) (cred auth.Credentials, signature s } // Query string. - queryStr := req.URL.Query().Encode() + queryStr := req.Form.Encode() // Get canonical request. canonicalRequest := getCanonicalRequest(extractedSignedHeaders, payload, queryStr, req.URL.Path, req.Method) diff --git a/cmd/sts-handlers.go b/cmd/sts-handlers.go index 147d49858..3eb477da7 100644 --- a/cmd/sts-handlers.go +++ b/cmd/sts-handlers.go @@ -95,14 +95,14 @@ func registerSTSRouter(router *mux.Router) { stsRouter.Methods(http.MethodPost).MatcherFunc(func(r *http.Request, rm *mux.RouteMatch) bool { ctypeOk := wildcard.MatchSimple("application/x-www-form-urlencoded*", r.Header.Get(xhttp.ContentType)) authOk := wildcard.MatchSimple(signV4Algorithm+"*", r.Header.Get(xhttp.Authorization)) - noQueries := len(r.URL.Query()) == 0 + noQueries := len(r.URL.RawQuery) == 0 return ctypeOk && authOk && noQueries }).HandlerFunc(httpTraceAll(sts.AssumeRole)) // Assume roles with JWT handler, handles both ClientGrants and WebIdentity. stsRouter.Methods(http.MethodPost).MatcherFunc(func(r *http.Request, rm *mux.RouteMatch) bool { ctypeOk := wildcard.MatchSimple("application/x-www-form-urlencoded*", r.Header.Get(xhttp.ContentType)) - noQueries := len(r.URL.Query()) == 0 + noQueries := len(r.URL.RawQuery) == 0 return ctypeOk && noQueries }).HandlerFunc(httpTraceAll(sts.AssumeRoleWithSSO)) @@ -155,6 +155,18 @@ func checkAssumeRoleAuth(ctx context.Context, r *http.Request) (user auth.Creden return user, true, ErrSTSNone } +func parseForm(r *http.Request) error { + if err := r.ParseForm(); err != nil { + return err + } + for k, v := range r.PostForm { + if _, ok := r.Form[k]; !ok { + r.Form[k] = v + } + } + return nil +} + // AssumeRole - implementation of AWS STS API AssumeRole to get temporary // credentials for regular users on Minio. // https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html @@ -167,7 +179,7 @@ func (sts *stsAPIHandlers) AssumeRole(w http.ResponseWriter, r *http.Request) { return } - if err := r.ParseForm(); err != nil { + if err := parseForm(r); err != nil { writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err) return } @@ -275,7 +287,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithSSO(w http.ResponseWriter, r *http.Requ ctx := newContext(r, w, "AssumeRoleSSOCommon") // Parse the incoming form data. - if err := r.ParseForm(); err != nil { + if err := parseForm(r); err != nil { writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err) return } @@ -514,7 +526,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithLDAPIdentity(w http.ResponseWriter, r * defer logger.AuditLog(ctx, w, r, nil, stsLDAPPassword) // Parse the incoming form data. - if err := r.ParseForm(); err != nil { + if err := parseForm(r); err != nil { writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue, err) return } diff --git a/cmd/test-utils_test.go b/cmd/test-utils_test.go index c0d113a79..5920159b3 100644 --- a/cmd/test-utils_test.go +++ b/cmd/test-utils_test.go @@ -45,6 +45,7 @@ import ( "net/http/httptest" "net/url" "os" + "path" "reflect" "sort" "strconv" @@ -1648,12 +1649,8 @@ func ExecObjectLayerAPIAnonTest(t *testing.T, obj ObjectLayer, testName, bucketN t.Fatal(failTestStr(unknownSignTestStr, "error response failed to parse error XML")) } - if actualError.BucketName != bucketName { - t.Fatal(failTestStr(unknownSignTestStr, "error response bucket name differs from expected value")) - } - - if actualError.Key != objectName { - t.Fatal(failTestStr(unknownSignTestStr, "error response object name differs from expected value")) + if path.Clean(actualError.Resource) != pathJoin(SlashSeparator, bucketName, SlashSeparator, objectName) { + t.Fatal(failTestStr(unknownSignTestStr, "error response resource differs from expected value")) } } @@ -2035,13 +2032,15 @@ func registerAPIFunctions(muxRouter *mux.Router, objLayer ObjectLayer, apiFuncti func initTestAPIEndPoints(objLayer ObjectLayer, apiFunctions []string) http.Handler { // initialize a new mux router. // goriilla/mux is the library used to register all the routes and handle them. - muxRouter := mux.NewRouter().SkipClean(true) + muxRouter := mux.NewRouter().SkipClean(true).UseEncodedPath() if len(apiFunctions) > 0 { // Iterate the list of API functions requested for and register them in mux HTTP handler. registerAPIFunctions(muxRouter, objLayer, apiFunctions...) + muxRouter.Use(globalHandlers...) return muxRouter } registerAPIRouter(muxRouter) + muxRouter.Use(globalHandlers...) return muxRouter } diff --git a/cmd/url_test.go b/cmd/url_test.go new file mode 100644 index 000000000..6e1efc7ef --- /dev/null +++ b/cmd/url_test.go @@ -0,0 +1,70 @@ +// Copyright (c) 2015-2021 MinIO, Inc. +// +// This file is part of MinIO Object Storage stack +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package cmd + +import ( + "net/http" + "testing" +) + +func BenchmarkURLQueryForm(b *testing.B) { + req, err := http.NewRequest(http.MethodGet, "http://localhost:9000/bucket/name?uploadId=upload&partNumber=1", nil) + if err != nil { + b.Fatal(err) + } + + // benchmark utility which helps obtain number of allocations and bytes allocated per ops. + b.ReportAllocs() + // the actual benchmark for PutObject starts here. Reset the benchmark timer. + b.ResetTimer() + + if err := req.ParseForm(); err != nil { + b.Fatal(err) + } + + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + req.Form.Get("uploadId") + } + }) + + // Benchmark ends here. Stop timer. + b.StopTimer() +} + +// BenchmarkURLQuery - benchmark URL memory allocations +func BenchmarkURLQuery(b *testing.B) { + req, err := http.NewRequest(http.MethodGet, "http://localhost:9000/bucket/name?uploadId=upload&partNumber=1", nil) + if err != nil { + b.Fatal(err) + } + + // benchmark utility which helps obtain number of allocations and bytes allocated per ops. + b.ReportAllocs() + // the actual benchmark for PutObject starts here. Reset the benchmark timer. + b.ResetTimer() + + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + req.URL.Query().Get("uploadId") + } + }) + + // Benchmark ends here. Stop timer. + b.StopTimer() +}