| 
									
										
										
										
											2015-02-24 08:46:48 +08:00
										 |  |  | /* | 
					
						
							| 
									
										
										
										
											2015-03-20 05:35:50 +08:00
										 |  |  |  * Minimalist Object Storage, (C) 2015 Minio, Inc. | 
					
						
							| 
									
										
										
										
											2015-02-24 08:46:48 +08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * 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. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-19 08:49:33 +08:00
										 |  |  | package api | 
					
						
							| 
									
										
										
										
											2015-02-16 09:03:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2015-04-23 07:28:13 +08:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2015-02-28 09:50:55 +08:00
										 |  |  | 	"sort" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-01 07:30:02 +08:00
										 |  |  | 	"github.com/minio/minio/pkg/storage/donut" | 
					
						
							| 
									
										
										
										
											2015-02-16 09:03:27 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-24 08:46:48 +08:00
										 |  |  | // Reply date format
 | 
					
						
							|  |  |  | const ( | 
					
						
							| 
									
										
										
										
											2015-03-10 16:44:55 +08:00
										 |  |  | 	iso8601Format = "2006-01-02T15:04:05.000Z" | 
					
						
							| 
									
										
										
										
											2015-02-24 08:46:48 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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
 | 
					
						
							| 
									
										
										
										
											2015-07-01 07:30:02 +08:00
										 |  |  | func generateListBucketsResponse(buckets []donut.BucketMetadata) ListBucketsResponse { | 
					
						
							| 
									
										
										
										
											2015-02-16 09:03:27 +08:00
										 |  |  | 	var listbuckets []*Bucket | 
					
						
							| 
									
										
										
										
											2015-04-30 06:28:04 +08:00
										 |  |  | 	var data = ListBucketsResponse{} | 
					
						
							| 
									
										
										
										
											2015-02-16 09:03:27 +08:00
										 |  |  | 	var owner = Owner{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	owner.ID = "minio" | 
					
						
							|  |  |  | 	owner.DisplayName = "minio" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, bucket := range buckets { | 
					
						
							|  |  |  | 		var listbucket = &Bucket{} | 
					
						
							|  |  |  | 		listbucket.Name = bucket.Name | 
					
						
							| 
									
										
										
										
											2015-03-10 16:44:55 +08:00
										 |  |  | 		listbucket.CreationDate = bucket.Created.Format(iso8601Format) | 
					
						
							| 
									
										
										
										
											2015-02-16 09:03:27 +08:00
										 |  |  | 		listbuckets = append(listbuckets, listbucket) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	data.Owner = owner | 
					
						
							|  |  |  | 	data.Buckets.Bucket = listbuckets | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return data | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-02 10:58:46 +08:00
										 |  |  | // itemKey
 | 
					
						
							| 
									
										
										
										
											2015-05-06 05:27:18 +08:00
										 |  |  | type itemKey []*Object | 
					
						
							| 
									
										
										
										
											2015-02-28 09:50:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-02 10:58:46 +08:00
										 |  |  | func (b itemKey) Len() int           { return len(b) } | 
					
						
							|  |  |  | func (b itemKey) Swap(i, j int)      { b[i], b[j] = b[j], b[i] } | 
					
						
							| 
									
										
										
										
											2015-03-06 13:07:19 +08:00
										 |  |  | func (b itemKey) Less(i, j int) bool { return b[i].Key < b[j].Key } | 
					
						
							| 
									
										
										
										
											2015-02-28 09:50:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-16 09:03:27 +08:00
										 |  |  | // takes a set of objects and prepares the objects for serialization
 | 
					
						
							|  |  |  | // input:
 | 
					
						
							|  |  |  | // bucket name
 | 
					
						
							|  |  |  | // array of object metadata
 | 
					
						
							|  |  |  | // results truncated flag
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // output:
 | 
					
						
							|  |  |  | // populated struct that can be serialized to match xml and json api spec output
 | 
					
						
							| 
									
										
										
										
											2015-07-01 07:30:02 +08:00
										 |  |  | func generateListObjectsResponse(bucket string, objects []donut.ObjectMetadata, bucketResources donut.BucketResourcesMetadata) ListObjectsResponse { | 
					
						
							| 
									
										
										
										
											2015-05-06 05:27:18 +08:00
										 |  |  | 	var contents []*Object | 
					
						
							|  |  |  | 	var prefixes []*CommonPrefix | 
					
						
							| 
									
										
										
										
											2015-02-16 09:03:27 +08:00
										 |  |  | 	var owner = Owner{} | 
					
						
							| 
									
										
										
										
											2015-04-30 06:28:04 +08:00
										 |  |  | 	var data = ListObjectsResponse{} | 
					
						
							| 
									
										
										
										
											2015-02-16 09:03:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	owner.ID = "minio" | 
					
						
							|  |  |  | 	owner.DisplayName = "minio" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, object := range objects { | 
					
						
							| 
									
										
										
										
											2015-05-06 05:27:18 +08:00
										 |  |  | 		var content = &Object{} | 
					
						
							| 
									
										
										
										
											2015-07-01 08:08:18 +08:00
										 |  |  | 		if object.Object == "" { | 
					
						
							| 
									
										
										
										
											2015-03-01 06:44:26 +08:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-07-01 08:08:18 +08:00
										 |  |  | 		content.Key = object.Object | 
					
						
							| 
									
										
										
										
											2015-03-10 16:44:55 +08:00
										 |  |  | 		content.LastModified = object.Created.Format(iso8601Format) | 
					
						
							| 
									
										
										
										
											2015-07-01 08:08:18 +08:00
										 |  |  | 		content.ETag = "\"" + object.MD5Sum + "\"" | 
					
						
							| 
									
										
										
										
											2015-02-16 09:03:27 +08:00
										 |  |  | 		content.Size = object.Size | 
					
						
							|  |  |  | 		content.StorageClass = "STANDARD" | 
					
						
							|  |  |  | 		content.Owner = owner | 
					
						
							|  |  |  | 		contents = append(contents, content) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-06 13:07:19 +08:00
										 |  |  | 	sort.Sort(itemKey(contents)) | 
					
						
							| 
									
										
										
										
											2015-05-06 05:27:18 +08:00
										 |  |  | 	// TODO - support EncodingType in xml decoding
 | 
					
						
							| 
									
										
										
										
											2015-02-16 09:03:27 +08:00
										 |  |  | 	data.Name = bucket | 
					
						
							|  |  |  | 	data.Contents = contents | 
					
						
							| 
									
										
										
										
											2015-03-01 06:44:26 +08:00
										 |  |  | 	data.MaxKeys = bucketResources.Maxkeys | 
					
						
							|  |  |  | 	data.Prefix = bucketResources.Prefix | 
					
						
							|  |  |  | 	data.Delimiter = bucketResources.Delimiter | 
					
						
							|  |  |  | 	data.Marker = bucketResources.Marker | 
					
						
							| 
									
										
										
										
											2015-05-06 05:27:18 +08:00
										 |  |  | 	data.NextMarker = bucketResources.NextMarker | 
					
						
							| 
									
										
										
										
											2015-03-01 06:44:26 +08:00
										 |  |  | 	data.IsTruncated = bucketResources.IsTruncated | 
					
						
							|  |  |  | 	for _, prefix := range bucketResources.CommonPrefixes { | 
					
						
							| 
									
										
										
										
											2015-05-06 05:27:18 +08:00
										 |  |  | 		var prefixItem = &CommonPrefix{} | 
					
						
							| 
									
										
										
										
											2015-03-01 06:44:26 +08:00
										 |  |  | 		prefixItem.Prefix = prefix | 
					
						
							|  |  |  | 		prefixes = append(prefixes, prefixItem) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	data.CommonPrefixes = prefixes | 
					
						
							| 
									
										
										
										
											2015-02-16 09:03:27 +08:00
										 |  |  | 	return data | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-04-23 07:28:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-10 02:41:26 +08:00
										 |  |  | // generateInitiateMultipartUploadResult
 | 
					
						
							| 
									
										
										
										
											2015-05-08 10:55:30 +08:00
										 |  |  | func generateInitiateMultipartUploadResult(bucket, key, uploadID string) InitiateMultipartUploadResult { | 
					
						
							|  |  |  | 	return InitiateMultipartUploadResult{ | 
					
						
							|  |  |  | 		Bucket:   bucket, | 
					
						
							|  |  |  | 		Key:      key, | 
					
						
							|  |  |  | 		UploadID: uploadID, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-10 02:41:26 +08:00
										 |  |  | // generateCompleteMultipartUploadResult
 | 
					
						
							| 
									
										
										
										
											2015-05-08 13:43:19 +08:00
										 |  |  | func generateCompleteMultpartUploadResult(bucket, key, location, etag string) CompleteMultipartUploadResult { | 
					
						
							|  |  |  | 	return CompleteMultipartUploadResult{ | 
					
						
							|  |  |  | 		Location: location, | 
					
						
							|  |  |  | 		Bucket:   bucket, | 
					
						
							|  |  |  | 		Key:      key, | 
					
						
							|  |  |  | 		ETag:     etag, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-10 02:41:26 +08:00
										 |  |  | // generateListPartsResult
 | 
					
						
							| 
									
										
										
										
											2015-07-01 07:30:02 +08:00
										 |  |  | func generateListPartsResult(objectMetadata donut.ObjectResourcesMetadata) ListPartsResponse { | 
					
						
							| 
									
										
										
										
											2015-05-10 02:41:26 +08:00
										 |  |  | 	// TODO - support EncodingType in xml decoding
 | 
					
						
							|  |  |  | 	listPartsResponse := ListPartsResponse{} | 
					
						
							|  |  |  | 	listPartsResponse.Bucket = objectMetadata.Bucket | 
					
						
							|  |  |  | 	listPartsResponse.Key = objectMetadata.Key | 
					
						
							|  |  |  | 	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 | 
					
						
							| 
									
										
										
										
											2015-06-09 16:12:32 +08:00
										 |  |  | 		newPart.ETag = "\"" + part.ETag + "\"" | 
					
						
							| 
									
										
										
										
											2015-05-10 02:41:26 +08:00
										 |  |  | 		newPart.Size = part.Size | 
					
						
							|  |  |  | 		newPart.LastModified = part.LastModified.Format(iso8601Format) | 
					
						
							|  |  |  | 		listPartsResponse.Part = append(listPartsResponse.Part, newPart) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return listPartsResponse | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-15 05:36:41 +08:00
										 |  |  | // generateListMultipartUploadsResult
 | 
					
						
							| 
									
										
										
										
											2015-07-01 07:30:02 +08:00
										 |  |  | func generateListMultipartUploadsResult(bucket string, metadata donut.BucketMultipartResourcesMetadata) ListMultipartUploadsResponse { | 
					
						
							| 
									
										
										
										
											2015-05-15 05:36:41 +08:00
										 |  |  | 	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 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-10 02:41:26 +08:00
										 |  |  | // writeSuccessResponse write success headers
 | 
					
						
							| 
									
										
										
										
											2015-04-30 06:28:04 +08:00
										 |  |  | func writeSuccessResponse(w http.ResponseWriter, acceptsContentType contentType) { | 
					
						
							| 
									
										
										
										
											2015-05-16 11:44:42 +08:00
										 |  |  | 	setCommonHeaders(w, getContentTypeString(acceptsContentType), 0) | 
					
						
							| 
									
										
										
										
											2015-04-30 01:51:59 +08:00
										 |  |  | 	w.WriteHeader(http.StatusOK) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-10 02:41:26 +08:00
										 |  |  | // writeErrorRespone write error headers
 | 
					
						
							| 
									
										
										
										
											2015-04-27 08:02:49 +08:00
										 |  |  | func writeErrorResponse(w http.ResponseWriter, req *http.Request, errorType int, acceptsContentType contentType, resource string) { | 
					
						
							| 
									
										
										
										
											2015-04-23 07:28:13 +08:00
										 |  |  | 	error := getErrorCode(errorType) | 
					
						
							| 
									
										
										
										
											2015-04-30 06:28:04 +08:00
										 |  |  | 	// generate error response
 | 
					
						
							| 
									
										
										
										
											2015-04-23 07:28:13 +08:00
										 |  |  | 	errorResponse := getErrorResponse(error, resource) | 
					
						
							| 
									
										
										
										
											2015-04-30 06:28:04 +08:00
										 |  |  | 	encodedErrorResponse := encodeErrorResponse(errorResponse, acceptsContentType) | 
					
						
							|  |  |  | 	// set common headers
 | 
					
						
							| 
									
										
										
										
											2015-05-16 11:44:42 +08:00
										 |  |  | 	setCommonHeaders(w, getContentTypeString(acceptsContentType), len(encodedErrorResponse)) | 
					
						
							|  |  |  | 	// write Header
 | 
					
						
							| 
									
										
										
										
											2015-04-23 07:28:13 +08:00
										 |  |  | 	w.WriteHeader(error.HTTPStatusCode) | 
					
						
							| 
									
										
										
										
											2015-05-16 11:44:42 +08:00
										 |  |  | 	// write error body
 | 
					
						
							| 
									
										
										
										
											2015-04-23 07:28:13 +08:00
										 |  |  | 	w.Write(encodedErrorResponse) | 
					
						
							|  |  |  | } |