mirror of
				https://github.com/minio/minio.git
				synced 2025-10-29 15:55:00 -04:00 
			
		
		
		
	fix size accounting for encrypted/compressed objects (#9690)
size calculation in crawler was using the real size of the object instead of its actual size i.e either a decrypted or uncompressed size. this is needed to make sure all other accounting such as bucket quota and mcs UI to display the correct values.
This commit is contained in:
		
							parent
							
								
									bc285cf0dd
								
							
						
					
					
						commit
						0c71ce3398
					
				| @ -120,20 +120,9 @@ func setObjectHeaders(w http.ResponseWriter, objInfo ObjectInfo, rs *HTTPRangeSp | ||||
| 		w.Header().Set(k, v) | ||||
| 	} | ||||
| 
 | ||||
| 	var totalObjectSize int64 | ||||
| 	switch { | ||||
| 	case crypto.IsEncrypted(objInfo.UserDefined): | ||||
| 		totalObjectSize, err = objInfo.DecryptedSize() | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	case objInfo.IsCompressed(): | ||||
| 		totalObjectSize = objInfo.GetActualSize() | ||||
| 		if totalObjectSize < 0 { | ||||
| 			return errInvalidDecompressedSize | ||||
| 		} | ||||
| 	default: | ||||
| 		totalObjectSize = objInfo.Size | ||||
| 	totalObjectSize, err := objInfo.GetActualSize() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	// for providing ranged content | ||||
|  | ||||
| @ -99,24 +99,13 @@ func (api objectAPIHandlers) ListBucketObjectVersionsHandler(w http.ResponseWrit | ||||
| 	} | ||||
| 
 | ||||
| 	for i := range listObjectsInfo.Objects { | ||||
| 		var actualSize int64 | ||||
| 		if listObjectsInfo.Objects[i].IsCompressed() { | ||||
| 			// Read the decompressed size from the meta.json. | ||||
| 			actualSize = listObjectsInfo.Objects[i].GetActualSize() | ||||
| 			if actualSize < 0 { | ||||
| 				writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrInvalidDecompressedSize), | ||||
| 					r.URL, guessIsBrowserReq(r)) | ||||
| 				return | ||||
| 			} | ||||
| 			// Set the info.Size to the actualSize. | ||||
| 			listObjectsInfo.Objects[i].Size = actualSize | ||||
| 		} else if crypto.IsEncrypted(listObjectsInfo.Objects[i].UserDefined) { | ||||
| 		if crypto.IsEncrypted(listObjectsInfo.Objects[i].UserDefined) { | ||||
| 			listObjectsInfo.Objects[i].ETag = getDecryptedETag(r.Header, listObjectsInfo.Objects[i], false) | ||||
| 			listObjectsInfo.Objects[i].Size, err = listObjectsInfo.Objects[i].DecryptedSize() | ||||
| 			if err != nil { | ||||
| 				writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 		listObjectsInfo.Objects[i].Size, err = listObjectsInfo.Objects[i].GetActualSize() | ||||
| 		if err != nil { | ||||
| 			writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -181,23 +170,13 @@ func (api objectAPIHandlers) ListObjectsV2MHandler(w http.ResponseWriter, r *htt | ||||
| 	} | ||||
| 
 | ||||
| 	for i := range listObjectsV2Info.Objects { | ||||
| 		var actualSize int64 | ||||
| 		if listObjectsV2Info.Objects[i].IsCompressed() { | ||||
| 			// Read the decompressed size from the meta.json. | ||||
| 			actualSize = listObjectsV2Info.Objects[i].GetActualSize() | ||||
| 			if actualSize < 0 { | ||||
| 				writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrInvalidDecompressedSize), r.URL, guessIsBrowserReq(r)) | ||||
| 				return | ||||
| 			} | ||||
| 			// Set the info.Size to the actualSize. | ||||
| 			listObjectsV2Info.Objects[i].Size = actualSize | ||||
| 		} else if crypto.IsEncrypted(listObjectsV2Info.Objects[i].UserDefined) { | ||||
| 		if crypto.IsEncrypted(listObjectsV2Info.Objects[i].UserDefined) { | ||||
| 			listObjectsV2Info.Objects[i].ETag = getDecryptedETag(r.Header, listObjectsV2Info.Objects[i], false) | ||||
| 			listObjectsV2Info.Objects[i].Size, err = listObjectsV2Info.Objects[i].DecryptedSize() | ||||
| 			if err != nil { | ||||
| 				writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 		listObjectsV2Info.Objects[i].Size, err = listObjectsV2Info.Objects[i].GetActualSize() | ||||
| 		if err != nil { | ||||
| 			writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -265,23 +244,13 @@ func (api objectAPIHandlers) ListObjectsV2Handler(w http.ResponseWriter, r *http | ||||
| 	} | ||||
| 
 | ||||
| 	for i := range listObjectsV2Info.Objects { | ||||
| 		var actualSize int64 | ||||
| 		if listObjectsV2Info.Objects[i].IsCompressed() { | ||||
| 			// Read the decompressed size from the meta.json. | ||||
| 			actualSize = listObjectsV2Info.Objects[i].GetActualSize() | ||||
| 			if actualSize < 0 { | ||||
| 				writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrInvalidDecompressedSize), r.URL, guessIsBrowserReq(r)) | ||||
| 				return | ||||
| 			} | ||||
| 			// Set the info.Size to the actualSize. | ||||
| 			listObjectsV2Info.Objects[i].Size = actualSize | ||||
| 		} else if crypto.IsEncrypted(listObjectsV2Info.Objects[i].UserDefined) { | ||||
| 		if crypto.IsEncrypted(listObjectsV2Info.Objects[i].UserDefined) { | ||||
| 			listObjectsV2Info.Objects[i].ETag = getDecryptedETag(r.Header, listObjectsV2Info.Objects[i], false) | ||||
| 			listObjectsV2Info.Objects[i].Size, err = listObjectsV2Info.Objects[i].DecryptedSize() | ||||
| 			if err != nil { | ||||
| 				writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 		listObjectsV2Info.Objects[i].Size, err = listObjectsV2Info.Objects[i].GetActualSize() | ||||
| 		if err != nil { | ||||
| 			writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -344,25 +313,16 @@ func (api objectAPIHandlers) ListObjectsV1Handler(w http.ResponseWriter, r *http | ||||
| 	} | ||||
| 
 | ||||
| 	for i := range listObjectsInfo.Objects { | ||||
| 		var actualSize int64 | ||||
| 		if listObjectsInfo.Objects[i].IsCompressed() { | ||||
| 			// Read the decompressed size from the meta.json. | ||||
| 			actualSize = listObjectsInfo.Objects[i].GetActualSize() | ||||
| 			if actualSize < 0 { | ||||
| 				writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrInvalidDecompressedSize), r.URL, guessIsBrowserReq(r)) | ||||
| 				return | ||||
| 			} | ||||
| 			// Set the info.Size to the actualSize. | ||||
| 			listObjectsInfo.Objects[i].Size = actualSize | ||||
| 		} else if crypto.IsEncrypted(listObjectsInfo.Objects[i].UserDefined) { | ||||
| 		if crypto.IsEncrypted(listObjectsInfo.Objects[i].UserDefined) { | ||||
| 			listObjectsInfo.Objects[i].ETag = getDecryptedETag(r.Header, listObjectsInfo.Objects[i], false) | ||||
| 			listObjectsInfo.Objects[i].Size, err = listObjectsInfo.Objects[i].DecryptedSize() | ||||
| 			if err != nil { | ||||
| 				writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 		listObjectsInfo.Objects[i].Size, err = listObjectsInfo.Objects[i].GetActualSize() | ||||
| 		if err != nil { | ||||
| 			writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	response := generateListObjectsV1Response(bucket, prefix, marker, delimiter, encodingType, maxKeys, listObjectsInfo) | ||||
| 
 | ||||
| 	// Write success response. | ||||
|  | ||||
| @ -1260,9 +1260,6 @@ func (args eventArgs) ToEvent(escape bool) event.Event { | ||||
| 	if args.EventName != event.ObjectRemovedDelete { | ||||
| 		newEvent.S3.Object.ETag = args.Object.ETag | ||||
| 		newEvent.S3.Object.Size = args.Object.Size | ||||
| 		if args.Object.IsCompressed() { | ||||
| 			newEvent.S3.Object.Size = args.Object.GetActualSize() | ||||
| 		} | ||||
| 		newEvent.S3.Object.ContentType = args.Object.ContentType | ||||
| 		newEvent.S3.Object.UserMetadata = args.Object.UserDefined | ||||
| 	} | ||||
| @ -1271,16 +1268,9 @@ func (args eventArgs) ToEvent(escape bool) event.Event { | ||||
| } | ||||
| 
 | ||||
| func sendEvent(args eventArgs) { | ||||
| 	// remove sensitive encryption entries in metadata. | ||||
| 	switch { | ||||
| 	case crypto.IsEncrypted(args.Object.UserDefined): | ||||
| 		if totalObjectSize, err := args.Object.DecryptedSize(); err == nil { | ||||
| 			args.Object.Size = totalObjectSize | ||||
| 		} | ||||
| 	case args.Object.IsCompressed(): | ||||
| 		args.Object.Size = args.Object.GetActualSize() | ||||
| 	} | ||||
| 	args.Object.Size, _ = args.Object.GetActualSize() | ||||
| 
 | ||||
| 	// remove sensitive encryption entries in metadata. | ||||
| 	crypto.RemoveSensitiveEntries(args.Object.UserDefined) | ||||
| 	crypto.RemoveInternalEntries(args.Object.UserDefined) | ||||
| 
 | ||||
|  | ||||
| @ -372,17 +372,23 @@ func (o ObjectInfo) IsCompressedOK() (bool, error) { | ||||
| 	return true, fmt.Errorf("unknown compression scheme: %s", scheme) | ||||
| } | ||||
| 
 | ||||
| // GetActualSize - read the decompressed size from the meta json. | ||||
| func (o ObjectInfo) GetActualSize() int64 { | ||||
| 	metadata := o.UserDefined | ||||
| 	sizeStr, ok := metadata[ReservedMetadataPrefix+"actual-size"] | ||||
| 	if ok { | ||||
| 		size, err := strconv.ParseInt(sizeStr, 10, 64) | ||||
| 		if err == nil { | ||||
| 			return size | ||||
| 		} | ||||
| // GetActualSize - returns the actual size of the stored object | ||||
| func (o ObjectInfo) GetActualSize() (int64, error) { | ||||
| 	if crypto.IsEncrypted(o.UserDefined) { | ||||
| 		return o.DecryptedSize() | ||||
| 	} | ||||
| 	return -1 | ||||
| 	if o.IsCompressed() { | ||||
| 		sizeStr, ok := o.UserDefined[ReservedMetadataPrefix+"actual-size"] | ||||
| 		if !ok { | ||||
| 			return -1, errInvalidDecompressedSize | ||||
| 		} | ||||
| 		size, err := strconv.ParseInt(sizeStr, 10, 64) | ||||
| 		if err != nil { | ||||
| 			return -1, errInvalidDecompressedSize | ||||
| 		} | ||||
| 		return size, nil | ||||
| 	} | ||||
| 	return o.Size, nil | ||||
| } | ||||
| 
 | ||||
| // Disabling compression for encrypted enabled requests. | ||||
| @ -608,9 +614,9 @@ func NewGetObjectReader(rs *HTTPRangeSpec, oi ObjectInfo, opts ObjectOptions, cl | ||||
| 		} | ||||
| 	case isCompressed: | ||||
| 		// Read the decompressed size from the meta.json. | ||||
| 		actualSize := oi.GetActualSize() | ||||
| 		if actualSize < 0 { | ||||
| 			return nil, 0, 0, errInvalidDecompressedSize | ||||
| 		actualSize, err := oi.GetActualSize() | ||||
| 		if err != nil { | ||||
| 			return nil, 0, 0, err | ||||
| 		} | ||||
| 		off, length = int64(0), oi.Size | ||||
| 		decOff, decLength := int64(0), actualSize | ||||
|  | ||||
| @ -521,7 +521,7 @@ func TestGetActualSize(t *testing.T) { | ||||
| 		}, | ||||
| 	} | ||||
| 	for i, test := range testCases { | ||||
| 		got := test.objInfo.GetActualSize() | ||||
| 		got, _ := test.objInfo.GetActualSize() | ||||
| 		if got != test.result { | ||||
| 			t.Errorf("Test %d - expected %d but received %d", | ||||
| 				i+1, test.result, got) | ||||
|  | ||||
| @ -1188,10 +1188,6 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re | ||||
| 	// Write success response. | ||||
| 	writeSuccessResponseXML(w, encodedSuccessResponse) | ||||
| 
 | ||||
| 	if objInfo.IsCompressed() { | ||||
| 		objInfo.Size = actualSize | ||||
| 	} | ||||
| 
 | ||||
| 	// Notify object created event. | ||||
| 	sendEvent(eventArgs{ | ||||
| 		EventName:    event.ObjectCreatedCopy, | ||||
| @ -1508,6 +1504,9 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req | ||||
| 
 | ||||
| 	writeSuccessResponseHeadersOnly(w) | ||||
| 
 | ||||
| 	// Set the etag sent to the client as part of the event. | ||||
| 	objInfo.ETag = etag | ||||
| 
 | ||||
| 	// Notify object created event. | ||||
| 	sendEvent(eventArgs{ | ||||
| 		EventName:    event.ObjectCreatedPut, | ||||
|  | ||||
							
								
								
									
										10
									
								
								cmd/posix.go
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								cmd/posix.go
									
									
									
									
									
								
							| @ -383,7 +383,15 @@ func (s *posix) CrawlAndGetDataUsage(ctx context.Context, cache dataUsageCache) | ||||
| 			return 0, nil | ||||
| 		} | ||||
| 
 | ||||
| 		return meta.Stat.Size, nil | ||||
| 		// we don't necessarily care about the names | ||||
| 		// of bucket and object, only interested in size. | ||||
| 		// so use some dummy names. | ||||
| 		size, err := meta.ToObjectInfo("dummy", "dummy").GetActualSize() | ||||
| 		if err != nil { | ||||
| 			return 0, errSkipFile | ||||
| 		} | ||||
| 		return size, nil | ||||
| 
 | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return dataUsageInfo, err | ||||
|  | ||||
| @ -529,17 +529,9 @@ func (web *webAPIHandlers) ListObjects(r *http.Request, args *ListObjectsArgs, r | ||||
| 			return &json2.Error{Message: err.Error()} | ||||
| 		} | ||||
| 		for i := range lo.Objects { | ||||
| 			if crypto.IsEncrypted(lo.Objects[i].UserDefined) { | ||||
| 				lo.Objects[i].Size, err = lo.Objects[i].DecryptedSize() | ||||
| 				if err != nil { | ||||
| 					return toJSONError(ctx, err) | ||||
| 				} | ||||
| 			} else if lo.Objects[i].IsCompressed() { | ||||
| 				actualSize := lo.Objects[i].GetActualSize() | ||||
| 				if actualSize < 0 { | ||||
| 					return toJSONError(ctx, errInvalidDecompressedSize) | ||||
| 				} | ||||
| 				lo.Objects[i].Size = actualSize | ||||
| 			lo.Objects[i].Size, err = lo.Objects[i].GetActualSize() | ||||
| 			if err != nil { | ||||
| 				return toJSONError(ctx, err) | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| @ -1505,10 +1497,10 @@ func (web *webAPIHandlers) DownloadZip(w http.ResponseWriter, r *http.Request) { | ||||
| 			info := gr.ObjInfo | ||||
| 			// filter object lock metadata if permission does not permit | ||||
| 			info.UserDefined = objectlock.FilterObjectLockMetadata(info.UserDefined, getRetPerms[i] != ErrNone, legalHoldPerms[i] != ErrNone) | ||||
| 
 | ||||
| 			if info.IsCompressed() { | ||||
| 				// For reporting, set the file size to the uncompressed size. | ||||
| 				info.Size = info.GetActualSize() | ||||
| 			// For reporting, set the file size to the uncompressed size. | ||||
| 			info.Size, err = info.GetActualSize() | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			header := &zip.FileHeader{ | ||||
| 				Name:     strings.TrimPrefix(objectName, args.Prefix), | ||||
|  | ||||
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							| @ -106,7 +106,7 @@ require ( | ||||
| 	github.com/stretchr/testify v1.5.1 // indirect | ||||
| 	github.com/tinylib/msgp v1.1.1 | ||||
| 	github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 // indirect | ||||
| 	github.com/ugorji/go/codec v1.1.5-pre // indirect | ||||
| 	github.com/ugorji/go v1.1.5-pre // indirect | ||||
| 	github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a | ||||
| 	github.com/willf/bitset v1.1.10 // indirect | ||||
| 	github.com/willf/bloom v2.0.3+incompatible | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user