mirror of
https://github.com/minio/minio.git
synced 2025-11-20 09:56:07 -05:00
An attempt to implement ListMultipartUploads()
This commit is contained in:
@@ -61,6 +61,56 @@ func (server *minioAPI) isValidOp(w http.ResponseWriter, req *http.Request, acce
|
||||
return true
|
||||
}
|
||||
|
||||
// GET Bucket (List Multipart uploads)
|
||||
// -------------------------
|
||||
// This operation lists in-progress multipart uploads. An in-progress
|
||||
// multipart upload is a multipart upload that has been initiated,
|
||||
// using the Initiate Multipart Upload request, but has not yet been completed or aborted.
|
||||
// This operation returns at most 1,000 multipart uploads in the response.
|
||||
//
|
||||
func (server *minioAPI) listMultipartUploadsHandler(w http.ResponseWriter, req *http.Request) {
|
||||
acceptsContentType := getContentType(req)
|
||||
// verify if bucket allows this operation
|
||||
if !server.isValidOp(w, req, acceptsContentType) {
|
||||
return
|
||||
}
|
||||
|
||||
resources := getBucketMultipartResources(req.URL.Query())
|
||||
if resources.MaxUploads == 0 {
|
||||
resources.MaxUploads = maxObjectList
|
||||
}
|
||||
|
||||
vars := mux.Vars(req)
|
||||
bucket := vars["bucket"]
|
||||
|
||||
resources, err := server.driver.ListMultipartUploads(bucket, resources)
|
||||
switch err := iodine.ToError(err).(type) {
|
||||
case nil: // success
|
||||
{
|
||||
// generate response
|
||||
response := generateListMultipartUploadsResult(bucket, resources)
|
||||
encodedSuccessResponse := encodeSuccessResponse(response, acceptsContentType)
|
||||
// write headers
|
||||
setCommonHeaders(w, getContentTypeString(acceptsContentType))
|
||||
// set content-length to the size of the body
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(encodedSuccessResponse)))
|
||||
w.WriteHeader(http.StatusOK)
|
||||
// write body
|
||||
w.Write(encodedSuccessResponse)
|
||||
}
|
||||
case drivers.ObjectNotFound:
|
||||
{
|
||||
writeErrorResponse(w, req, NoSuchKey, acceptsContentType, req.URL.Path)
|
||||
}
|
||||
default:
|
||||
{
|
||||
log.Error.Println(iodine.New(err, nil))
|
||||
writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// GET Bucket (List Objects)
|
||||
// -------------------------
|
||||
// This implementation of the GET operation returns some or all (up to 1000)
|
||||
@@ -74,6 +124,11 @@ func (server *minioAPI) listObjectsHandler(w http.ResponseWriter, req *http.Requ
|
||||
return
|
||||
}
|
||||
|
||||
if isRequestUploads(req.URL.Query()) {
|
||||
server.listMultipartUploadsHandler(w, req)
|
||||
return
|
||||
}
|
||||
|
||||
resources := getBucketResources(req.URL.Query())
|
||||
if resources.Maxkeys == 0 {
|
||||
resources.Maxkeys = maxObjectList
|
||||
|
||||
@@ -16,9 +16,7 @@
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
)
|
||||
import "encoding/xml"
|
||||
|
||||
// Limit number of objects in a given response
|
||||
const (
|
||||
@@ -78,6 +76,24 @@ type ListPartsResponse struct {
|
||||
Part []*Part
|
||||
}
|
||||
|
||||
// ListMultipartUploadsResponse - format for list multipart uploads response
|
||||
type ListMultipartUploadsResponse struct {
|
||||
XMLName xml.Name `xml:"http://doc.s3.amazonaws.com/2006-03-01 ListMultipartUploadsResult" json:"-"`
|
||||
|
||||
Bucket string
|
||||
KeyMarker string
|
||||
UploadIDMarker string `xml:"UploadIdMarker"`
|
||||
NextKeyMarker string
|
||||
NextUploadIDMarker string `xml:"NextUploadIdMarker"`
|
||||
EncodingType string
|
||||
MaxUploads int
|
||||
IsTruncated bool
|
||||
Upload []*Upload
|
||||
Prefix string
|
||||
Delimiter string
|
||||
CommonPrefixes []*CommonPrefix
|
||||
}
|
||||
|
||||
// ListBucketsResponse - format for list buckets response
|
||||
type ListBucketsResponse struct {
|
||||
XMLName xml.Name `xml:"http://doc.s3.amazonaws.com/2006-03-01 ListAllMyBucketsResult" json:"-"`
|
||||
@@ -88,6 +104,16 @@ type ListBucketsResponse struct {
|
||||
Owner Owner
|
||||
}
|
||||
|
||||
// Upload container for in progress multipart upload
|
||||
type Upload struct {
|
||||
Key string
|
||||
UploadID string `xml:"UploadId"`
|
||||
Initiator Initiator
|
||||
Owner Owner
|
||||
StorageClass string
|
||||
Initiated string
|
||||
}
|
||||
|
||||
// CommonPrefix container for prefix response in ListObjectsResponse
|
||||
type CommonPrefix struct {
|
||||
Prefix string
|
||||
|
||||
@@ -131,13 +131,6 @@ func generateCompleteMultpartUploadResult(bucket, key, location, etag string) Co
|
||||
}
|
||||
}
|
||||
|
||||
// partNumber
|
||||
type partNumber []*Part
|
||||
|
||||
func (b partNumber) Len() int { return len(b) }
|
||||
func (b partNumber) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
|
||||
func (b partNumber) Less(i, j int) bool { return b[i].PartNumber < b[j].PartNumber }
|
||||
|
||||
// generateListPartsResult
|
||||
func generateListPartsResult(objectMetadata drivers.ObjectResourcesMetadata) ListPartsResponse {
|
||||
// TODO - support EncodingType in xml decoding
|
||||
@@ -168,6 +161,31 @@ func generateListPartsResult(objectMetadata drivers.ObjectResourcesMetadata) Lis
|
||||
return listPartsResponse
|
||||
}
|
||||
|
||||
// generateListMultipartUploadsResult
|
||||
func generateListMultipartUploadsResult(bucket string, metadata drivers.BucketMultipartResourcesMetadata) ListMultipartUploadsResponse {
|
||||
listMultipartUploadsResponse := ListMultipartUploadsResponse{}
|
||||
listMultipartUploadsResponse.Bucket = bucket
|
||||
listMultipartUploadsResponse.Delimiter = metadata.Delimiter
|
||||
listMultipartUploadsResponse.IsTruncated = metadata.IsTruncated
|
||||
listMultipartUploadsResponse.EncodingType = metadata.EncodingType
|
||||
listMultipartUploadsResponse.Prefix = metadata.Prefix
|
||||
listMultipartUploadsResponse.KeyMarker = metadata.KeyMarker
|
||||
listMultipartUploadsResponse.NextKeyMarker = metadata.NextKeyMarker
|
||||
listMultipartUploadsResponse.MaxUploads = metadata.MaxUploads
|
||||
listMultipartUploadsResponse.NextUploadIDMarker = metadata.NextUploadIDMarker
|
||||
listMultipartUploadsResponse.UploadIDMarker = metadata.UploadIDMarker
|
||||
|
||||
listMultipartUploadsResponse.Upload = make([]*Upload, len(metadata.Upload))
|
||||
for _, upload := range metadata.Upload {
|
||||
newUpload := &Upload{}
|
||||
newUpload.UploadID = upload.UploadID
|
||||
newUpload.Key = upload.Key
|
||||
newUpload.Initiated = upload.Initiated.Format(iso8601Format)
|
||||
listMultipartUploadsResponse.Upload = append(listMultipartUploadsResponse.Upload, newUpload)
|
||||
}
|
||||
return listMultipartUploadsResponse
|
||||
}
|
||||
|
||||
// writeSuccessResponse write success headers
|
||||
func writeSuccessResponse(w http.ResponseWriter, acceptsContentType contentType) {
|
||||
setCommonHeaders(w, getContentTypeString(acceptsContentType))
|
||||
|
||||
@@ -33,6 +33,17 @@ func getBucketResources(values url.Values) (v drivers.BucketResourcesMetadata) {
|
||||
return
|
||||
}
|
||||
|
||||
// part bucket url queries for ?uploads
|
||||
func getBucketMultipartResources(values url.Values) (v drivers.BucketMultipartResourcesMetadata) {
|
||||
v.Prefix = values.Get("prefix")
|
||||
v.KeyMarker = values.Get("key-marker")
|
||||
v.MaxUploads, _ = strconv.Atoi(values.Get("max-uploads"))
|
||||
v.Delimiter = values.Get("delimiter")
|
||||
v.EncodingType = values.Get("encoding-type")
|
||||
v.UploadIDMarker = values.Get("upload-id-marker")
|
||||
return
|
||||
}
|
||||
|
||||
// parse object url queries
|
||||
func getObjectResources(values url.Values) (v drivers.ObjectResourcesMetadata) {
|
||||
v.UploadID = values.Get("uploadId")
|
||||
@@ -42,15 +53,14 @@ func getObjectResources(values url.Values) (v drivers.ObjectResourcesMetadata) {
|
||||
return
|
||||
}
|
||||
|
||||
// check if req query values have acl
|
||||
func isRequestBucketACL(values url.Values) bool {
|
||||
for key := range values {
|
||||
switch true {
|
||||
case key == "acl":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
// check if req quere values carry uploads resource
|
||||
func isRequestUploads(values url.Values) bool {
|
||||
_, ok := values["uploads"]
|
||||
return ok
|
||||
}
|
||||
|
||||
// check if req query values carry acl resource
|
||||
func isRequestBucketACL(values url.Values) bool {
|
||||
_, ok := values["acl"]
|
||||
return ok
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user