mirror of https://github.com/minio/minio.git
				
				
				
			
		
			
				
	
	
		
			243 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			243 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			Go
		
	
	
	
| /*
 | |
|  * Minio Cloud Storage, (C) 2015 Minio, Inc.
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  */
 | |
| 
 | |
| package main
 | |
| 
 | |
| import (
 | |
| 	"net/http"
 | |
| 
 | |
| 	"github.com/minio/minio/pkg/fs"
 | |
| )
 | |
| 
 | |
| // Reply date format
 | |
| const (
 | |
| 	rfcFormat = "2006-01-02T15:04:05.000Z"
 | |
| )
 | |
| 
 | |
| // takes an array of Bucketmetadata information for serialization
 | |
| // input:
 | |
| // array of bucket metadata
 | |
| //
 | |
| // output:
 | |
| // populated struct that can be serialized to match xml and json api spec output
 | |
| func generateListBucketsResponse(buckets []fs.BucketMetadata) ListBucketsResponse {
 | |
| 	var listbuckets []*Bucket
 | |
| 	var data = ListBucketsResponse{}
 | |
| 	var owner = Owner{}
 | |
| 
 | |
| 	owner.ID = "minio"
 | |
| 	owner.DisplayName = "minio"
 | |
| 
 | |
| 	for _, bucket := range buckets {
 | |
| 		var listbucket = &Bucket{}
 | |
| 		listbucket.Name = bucket.Name
 | |
| 		listbucket.CreationDate = bucket.Created.Format(rfcFormat)
 | |
| 		listbuckets = append(listbuckets, listbucket)
 | |
| 	}
 | |
| 
 | |
| 	data.Owner = owner
 | |
| 	data.Buckets.Bucket = listbuckets
 | |
| 
 | |
| 	return data
 | |
| }
 | |
| 
 | |
| // generates an AccessControlPolicy response for the said ACL.
 | |
| func generateAccessControlPolicyResponse(acl fs.BucketACL) AccessControlPolicyResponse {
 | |
| 	accessCtrlPolicyResponse := AccessControlPolicyResponse{}
 | |
| 	accessCtrlPolicyResponse.Owner = Owner{
 | |
| 		ID:          "minio",
 | |
| 		DisplayName: "minio",
 | |
| 	}
 | |
| 	defaultGrant := Grant{}
 | |
| 	defaultGrant.Grantee.ID = "minio"
 | |
| 	defaultGrant.Grantee.DisplayName = "minio"
 | |
| 	defaultGrant.Permission = "FULL_CONTROL"
 | |
| 	accessCtrlPolicyResponse.AccessControlList.Grant = append(accessCtrlPolicyResponse.AccessControlList.Grant, defaultGrant)
 | |
| 	switch {
 | |
| 	case acl.IsPublicRead():
 | |
| 		publicReadGrant := Grant{}
 | |
| 		publicReadGrant.Grantee.ID = "minio"
 | |
| 		publicReadGrant.Grantee.DisplayName = "minio"
 | |
| 		publicReadGrant.Grantee.URI = "http://acs.amazonaws.com/groups/global/AllUsers"
 | |
| 		publicReadGrant.Permission = "READ"
 | |
| 		accessCtrlPolicyResponse.AccessControlList.Grant = append(accessCtrlPolicyResponse.AccessControlList.Grant, publicReadGrant)
 | |
| 	case acl.IsPublicReadWrite():
 | |
| 		publicReadGrant := Grant{}
 | |
| 		publicReadGrant.Grantee.ID = "minio"
 | |
| 		publicReadGrant.Grantee.DisplayName = "minio"
 | |
| 		publicReadGrant.Grantee.URI = "http://acs.amazonaws.com/groups/global/AllUsers"
 | |
| 		publicReadGrant.Permission = "READ"
 | |
| 		publicReadWriteGrant := Grant{}
 | |
| 		publicReadWriteGrant.Grantee.ID = "minio"
 | |
| 		publicReadWriteGrant.Grantee.DisplayName = "minio"
 | |
| 		publicReadWriteGrant.Grantee.URI = "http://acs.amazonaws.com/groups/global/AllUsers"
 | |
| 		publicReadWriteGrant.Permission = "WRITE"
 | |
| 		accessCtrlPolicyResponse.AccessControlList.Grant = append(accessCtrlPolicyResponse.AccessControlList.Grant, publicReadGrant)
 | |
| 		accessCtrlPolicyResponse.AccessControlList.Grant = append(accessCtrlPolicyResponse.AccessControlList.Grant, publicReadWriteGrant)
 | |
| 	}
 | |
| 	return accessCtrlPolicyResponse
 | |
| }
 | |
| 
 | |
| // generates an ListObjects response for the said bucket with other enumerated options.
 | |
| func generateListObjectsResponse(bucket string, objects []fs.ObjectMetadata, bucketResources fs.BucketResourcesMetadata) ListObjectsResponse {
 | |
| 	var contents []*Object
 | |
| 	var prefixes []*CommonPrefix
 | |
| 	var owner = Owner{}
 | |
| 	var data = ListObjectsResponse{}
 | |
| 
 | |
| 	owner.ID = "minio"
 | |
| 	owner.DisplayName = "minio"
 | |
| 
 | |
| 	for _, object := range objects {
 | |
| 		var content = &Object{}
 | |
| 		if object.Object == "" {
 | |
| 			continue
 | |
| 		}
 | |
| 		content.Key = object.Object
 | |
| 		content.LastModified = object.Created.Format(rfcFormat)
 | |
| 		content.ETag = "\"" + object.Md5 + "\""
 | |
| 		content.Size = object.Size
 | |
| 		content.StorageClass = "STANDARD"
 | |
| 		content.Owner = owner
 | |
| 		contents = append(contents, content)
 | |
| 	}
 | |
| 	// TODO - support EncodingType in xml decoding
 | |
| 	data.Name = bucket
 | |
| 	data.Contents = contents
 | |
| 	data.MaxKeys = bucketResources.Maxkeys
 | |
| 	data.Prefix = bucketResources.Prefix
 | |
| 	data.Delimiter = bucketResources.Delimiter
 | |
| 	data.Marker = bucketResources.Marker
 | |
| 	data.NextMarker = bucketResources.NextMarker
 | |
| 	data.IsTruncated = bucketResources.IsTruncated
 | |
| 	for _, prefix := range bucketResources.CommonPrefixes {
 | |
| 		var prefixItem = &CommonPrefix{}
 | |
| 		prefixItem.Prefix = prefix
 | |
| 		prefixes = append(prefixes, prefixItem)
 | |
| 	}
 | |
| 	data.CommonPrefixes = prefixes
 | |
| 	return data
 | |
| }
 | |
| 
 | |
| // generateInitiateMultipartUploadResponse
 | |
| func generateInitiateMultipartUploadResponse(bucket, key, uploadID string) InitiateMultipartUploadResponse {
 | |
| 	return InitiateMultipartUploadResponse{
 | |
| 		Bucket:   bucket,
 | |
| 		Key:      key,
 | |
| 		UploadID: uploadID,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // generateCompleteMultipartUploadResponse
 | |
| func generateCompleteMultpartUploadResponse(bucket, key, location, etag string) CompleteMultipartUploadResponse {
 | |
| 	return CompleteMultipartUploadResponse{
 | |
| 		Location: location,
 | |
| 		Bucket:   bucket,
 | |
| 		Key:      key,
 | |
| 		ETag:     etag,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // generateListPartsResult
 | |
| func generateListPartsResponse(objectMetadata fs.ObjectResourcesMetadata) ListPartsResponse {
 | |
| 	// TODO - support EncodingType in xml decoding
 | |
| 	listPartsResponse := ListPartsResponse{}
 | |
| 	listPartsResponse.Bucket = objectMetadata.Bucket
 | |
| 	listPartsResponse.Key = objectMetadata.Object
 | |
| 	listPartsResponse.UploadID = objectMetadata.UploadID
 | |
| 	listPartsResponse.StorageClass = "STANDARD"
 | |
| 	listPartsResponse.Initiator.ID = "minio"
 | |
| 	listPartsResponse.Initiator.DisplayName = "minio"
 | |
| 	listPartsResponse.Owner.ID = "minio"
 | |
| 	listPartsResponse.Owner.DisplayName = "minio"
 | |
| 
 | |
| 	listPartsResponse.MaxParts = objectMetadata.MaxParts
 | |
| 	listPartsResponse.PartNumberMarker = objectMetadata.PartNumberMarker
 | |
| 	listPartsResponse.IsTruncated = objectMetadata.IsTruncated
 | |
| 	listPartsResponse.NextPartNumberMarker = objectMetadata.NextPartNumberMarker
 | |
| 
 | |
| 	listPartsResponse.Part = make([]*Part, len(objectMetadata.Part))
 | |
| 	for _, part := range objectMetadata.Part {
 | |
| 		newPart := &Part{}
 | |
| 		newPart.PartNumber = part.PartNumber
 | |
| 		newPart.ETag = "\"" + part.ETag + "\""
 | |
| 		newPart.Size = part.Size
 | |
| 		newPart.LastModified = part.LastModified.Format(rfcFormat)
 | |
| 		listPartsResponse.Part = append(listPartsResponse.Part, newPart)
 | |
| 	}
 | |
| 	return listPartsResponse
 | |
| }
 | |
| 
 | |
| // generateListMultipartUploadsResponse
 | |
| func generateListMultipartUploadsResponse(bucket string, metadata fs.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.Object
 | |
| 		newUpload.Initiated = upload.Initiated.Format(rfcFormat)
 | |
| 		listMultipartUploadsResponse.Upload = append(listMultipartUploadsResponse.Upload, newUpload)
 | |
| 	}
 | |
| 	return listMultipartUploadsResponse
 | |
| }
 | |
| 
 | |
| // writeSuccessResponse write success headers and response if any.
 | |
| func writeSuccessResponse(w http.ResponseWriter, response []byte) {
 | |
| 	setCommonHeaders(w)
 | |
| 	if response == nil {
 | |
| 		w.WriteHeader(http.StatusOK)
 | |
| 		return
 | |
| 	}
 | |
| 	w.Write(response)
 | |
| 	w.(http.Flusher).Flush()
 | |
| }
 | |
| 
 | |
| // writeSuccessNoContent write success headers with http status 204
 | |
| func writeSuccessNoContent(w http.ResponseWriter) {
 | |
| 	setCommonHeaders(w)
 | |
| 	w.WriteHeader(http.StatusNoContent)
 | |
| }
 | |
| 
 | |
| // writeErrorRespone write error headers
 | |
| func writeErrorResponse(w http.ResponseWriter, req *http.Request, errorType int, resource string) {
 | |
| 	error := getErrorCode(errorType)
 | |
| 	// generate error response
 | |
| 	errorResponse := getErrorResponse(error, resource)
 | |
| 	encodedErrorResponse := encodeErrorResponse(errorResponse)
 | |
| 	// set common headers
 | |
| 	setCommonHeaders(w)
 | |
| 	// write Header
 | |
| 	w.WriteHeader(error.HTTPStatusCode)
 | |
| 	// HEAD should have no body, do not attempt to write to it
 | |
| 	if req.Method != "HEAD" {
 | |
| 		// write error body
 | |
| 		w.Write(encodedErrorResponse)
 | |
| 		w.(http.Flusher).Flush()
 | |
| 	}
 | |
| }
 |