|
|
|
@ -126,6 +126,90 @@ func (api objectAPIHandlers) ListBucketObjectVersionsHandler(w http.ResponseWrit |
|
|
|
|
writeSuccessResponseXML(w, encodeResponse(response)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ListObjectsV2MHandler - GET Bucket (List Objects) Version 2 with metadata.
|
|
|
|
|
// --------------------------
|
|
|
|
|
// This implementation of the GET operation returns some or all (up to 10000)
|
|
|
|
|
// of the objects in a bucket. You can use the request parame<ters as selection
|
|
|
|
|
// criteria to return a subset of the objects in a bucket.
|
|
|
|
|
//
|
|
|
|
|
// NOTE: It is recommended that this API to be used for application development.
|
|
|
|
|
// MinIO continues to support ListObjectsV1 and V2 for supporting legacy tools.
|
|
|
|
|
func (api objectAPIHandlers) ListObjectsV2MHandler(w http.ResponseWriter, r *http.Request) { |
|
|
|
|
ctx := newContext(r, w, "ListObjectsV2M") |
|
|
|
|
|
|
|
|
|
defer logger.AuditLog(w, r, "ListObjectsV2M", mustGetClaimsFromToken(r)) |
|
|
|
|
|
|
|
|
|
vars := mux.Vars(r) |
|
|
|
|
bucket := vars["bucket"] |
|
|
|
|
|
|
|
|
|
objectAPI := api.ObjectAPI() |
|
|
|
|
if objectAPI == nil { |
|
|
|
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if s3Error := checkRequestAuthType(ctx, r, policy.ListBucketAction, bucket, ""); s3Error != ErrNone { |
|
|
|
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
urlValues := r.URL.Query() |
|
|
|
|
|
|
|
|
|
// Extract all the listObjectsV2 query params to their native values.
|
|
|
|
|
prefix, token, startAfter, delimiter, fetchOwner, maxKeys, encodingType, errCode := getListObjectsV2Args(urlValues) |
|
|
|
|
if errCode != ErrNone { |
|
|
|
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(errCode), r.URL, guessIsBrowserReq(r)) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Validate the query params before beginning to serve the request.
|
|
|
|
|
// fetch-owner is not validated since it is a boolean
|
|
|
|
|
if s3Error := validateListObjectsArgs(token, delimiter, encodingType, maxKeys); s3Error != ErrNone { |
|
|
|
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
listObjectsV2 := objectAPI.ListObjectsV2 |
|
|
|
|
|
|
|
|
|
// Inititate a list objects operation based on the input params.
|
|
|
|
|
// On success would return back ListObjectsInfo object to be
|
|
|
|
|
// marshaled into S3 compatible XML header.
|
|
|
|
|
listObjectsV2Info, err := listObjectsV2(ctx, bucket, prefix, token, delimiter, maxKeys, fetchOwner, startAfter) |
|
|
|
|
if err != nil { |
|
|
|
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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) { |
|
|
|
|
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 |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
response := generateListObjectsV2Response(bucket, prefix, token, |
|
|
|
|
listObjectsV2Info.NextContinuationToken, startAfter, |
|
|
|
|
delimiter, encodingType, fetchOwner, listObjectsV2Info.IsTruncated, |
|
|
|
|
maxKeys, listObjectsV2Info.Objects, listObjectsV2Info.Prefixes, true) |
|
|
|
|
|
|
|
|
|
// Write success response.
|
|
|
|
|
writeSuccessResponseXML(w, encodeResponse(response)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ListObjectsV2Handler - GET Bucket (List Objects) Version 2.
|
|
|
|
|
// --------------------------
|
|
|
|
|
// This implementation of the GET operation returns some or all (up to 10000)
|
|
|
|
@ -201,8 +285,10 @@ func (api objectAPIHandlers) ListObjectsV2Handler(w http.ResponseWriter, r *http |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
response := generateListObjectsV2Response(bucket, prefix, token, listObjectsV2Info.NextContinuationToken, startAfter, |
|
|
|
|
delimiter, encodingType, fetchOwner, listObjectsV2Info.IsTruncated, maxKeys, listObjectsV2Info.Objects, listObjectsV2Info.Prefixes) |
|
|
|
|
response := generateListObjectsV2Response(bucket, prefix, token, |
|
|
|
|
listObjectsV2Info.NextContinuationToken, startAfter, |
|
|
|
|
delimiter, encodingType, fetchOwner, listObjectsV2Info.IsTruncated, |
|
|
|
|
maxKeys, listObjectsV2Info.Objects, listObjectsV2Info.Prefixes, false) |
|
|
|
|
|
|
|
|
|
// Write success response.
|
|
|
|
|
writeSuccessResponseXML(w, encodeResponse(response)) |
|
|
|
|