Implement proper delimiter and prefix handling

With this change Minio server now responds with, delimited
'object names' in conjunction with prefix filtering

~~~
<ListBucketResult>
  <Name>example-bucket</Name>
  <Prefix></Prefix>
  <Marker></Marker>
  <MaxKeys>1000</MaxKeys>
  <Delimiter>/</Delimiter>
  <IsTruncated>false</IsTruncated>
  <Contents>
    <Key>sample.html</Key>
    <LastModified>2011-02-26T01:56:20.000Z</LastModified>
    <ETag>example-bucket#sample.html</ETag>
    <Size>142863</Size>
    <Owner>
      <ID>minio</ID>
      <DisplayName>minio</DisplayName>
    </Owner>
    <StorageClass>STANDARD</StorageClass>
  </Contents>
  <CommonPrefixes>
    <Prefix>photos/</Prefix>
  </CommonPrefixes>
</ListBucketResult>
~~~

~~~
<ListBucketResult>
  <Name>example-bucket</Name>
  <Prefix>photos/2006/</Prefix>
  <Marker></Marker>
  <MaxKeys>1000</MaxKeys>
  <Delimiter>/</Delimiter>
  <IsTruncated>false</IsTruncated>

  <CommonPrefixes>
    <Prefix>photos/2006/feb/</Prefix>
  </CommonPrefixes>
  <CommonPrefixes>
    <Prefix>photos/2006/jan/</Prefix>
  </CommonPrefixes>
</ListBucketResult>
~~~
This commit is contained in:
Harshavardhana
2015-02-28 14:44:26 -08:00
parent acee4d16fd
commit 0c2d58bc6d
5 changed files with 84 additions and 37 deletions

View File

@@ -45,7 +45,7 @@ func (server *minioApi) listObjectsHandler(w http.ResponseWriter, req *http.Requ
switch err := err.(type) {
case nil: // success
{
response := generateObjectsListResult(bucket, objects, resources.IsTruncated)
response := generateObjectsListResult(bucket, objects, resources)
w.Write(writeObjectHeadersAndResponse(w, response, acceptsContentType))
}
case mstorage.BucketNotFound:

View File

@@ -34,10 +34,8 @@ type ObjectListResponse struct {
MaxKeys int
Delimiter string
IsTruncated bool
Contents []*Item `xml:,innerxml`
CommonPrefixes struct {
Prefix string
} `xml:,innerxml`
Contents []*Item `xml:,innerxml`
CommonPrefixes []*Prefix `xml:,innerxml`
}
// Bucket list response format
@@ -49,6 +47,10 @@ type BucketListResponse struct {
} `xml:,innerxml` // Buckets are nested
}
type Prefix struct {
Prefix string
}
// Bucket struct
type Bucket struct {
Name string

View File

@@ -68,8 +68,9 @@ func (b ItemKey) Less(i, j int) bool { return b[i].Key < b[j].Key }
//
// output:
// populated struct that can be serialized to match xml and json api spec output
func generateObjectsListResult(bucket string, objects []mstorage.ObjectMetadata, isTruncated bool) ObjectListResponse {
func generateObjectsListResult(bucket string, objects []mstorage.ObjectMetadata, bucketResources mstorage.BucketResourcesMetadata) ObjectListResponse {
var contents []*Item
var prefixes []*Prefix
var owner = Owner{}
var data = ObjectListResponse{}
@@ -78,6 +79,9 @@ func generateObjectsListResult(bucket string, objects []mstorage.ObjectMetadata,
for _, object := range objects {
var content = &Item{}
if object.Key == "" {
continue
}
content.Key = object.Key
content.LastModified = object.Created.Format(dateFormat)
content.ETag = object.ETag
@@ -89,7 +93,16 @@ func generateObjectsListResult(bucket string, objects []mstorage.ObjectMetadata,
sort.Sort(ItemKey(contents))
data.Name = bucket
data.Contents = contents
data.MaxKeys = MAX_OBJECT_LIST
data.IsTruncated = isTruncated
data.MaxKeys = bucketResources.Maxkeys
data.Prefix = bucketResources.Prefix
data.Delimiter = bucketResources.Delimiter
data.Marker = bucketResources.Marker
data.IsTruncated = bucketResources.IsTruncated
for _, prefix := range bucketResources.CommonPrefixes {
var prefixItem = &Prefix{}
prefixItem.Prefix = prefix
prefixes = append(prefixes, prefixItem)
}
data.CommonPrefixes = prefixes
return data
}