| 
									
										
										
										
											2015-02-24 08:46:48 +08:00
										 |  |  | /* | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  |  * Minio Cloud Storage, (C) 2015, 2016 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. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 07:23:42 +08:00
										 |  |  | package cmd | 
					
						
							| 
									
										
										
										
											2015-02-16 09:03:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | 	"encoding/xml" | 
					
						
							| 
									
										
										
										
											2015-04-23 07:28:13 +08:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2016-06-21 14:25:18 +08:00
										 |  |  | 	"path" | 
					
						
							| 
									
										
										
										
											2016-02-27 19:04:52 +08:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2015-02-16 09:03:27 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-24 08:46:48 +08:00
										 |  |  | const ( | 
					
						
							| 
									
										
										
										
											2016-09-07 08:22:55 +08:00
										 |  |  | 	timeFormatAMZ  = "2006-01-02T15:04:05Z" // Reply date format
 | 
					
						
							|  |  |  | 	maxObjectList  = 1000                   // Limit number of objects in a listObjectsResponse.
 | 
					
						
							|  |  |  | 	maxUploadsList = 1000                   // Limit number of uploads in a listUploadsResponse.
 | 
					
						
							|  |  |  | 	maxPartsList   = 1000                   // Limit number of parts in a listPartsResponse.
 | 
					
						
							| 
									
										
										
										
											2015-02-24 08:46:48 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | // LocationResponse - format for location response.
 | 
					
						
							|  |  |  | type LocationResponse struct { | 
					
						
							|  |  |  | 	XMLName  xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ LocationConstraint" json:"-"` | 
					
						
							|  |  |  | 	Location string   `xml:",chardata"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ListObjectsResponse - format for list objects response.
 | 
					
						
							|  |  |  | type ListObjectsResponse struct { | 
					
						
							|  |  |  | 	XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListBucketResult" json:"-"` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	CommonPrefixes []CommonPrefix | 
					
						
							|  |  |  | 	Contents       []Object | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Delimiter string | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Encoding type used to encode object keys in the response.
 | 
					
						
							|  |  |  | 	EncodingType string | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// A flag that indicates whether or not ListObjects returned all of the results
 | 
					
						
							|  |  |  | 	// that satisfied the search criteria.
 | 
					
						
							|  |  |  | 	IsTruncated bool | 
					
						
							|  |  |  | 	Marker      string | 
					
						
							|  |  |  | 	MaxKeys     int | 
					
						
							|  |  |  | 	Name        string | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// When response is truncated (the IsTruncated element value in the response
 | 
					
						
							|  |  |  | 	// is true), you can use the key name in this field as marker in the subsequent
 | 
					
						
							|  |  |  | 	// request to get next set of objects. Server lists objects in alphabetical
 | 
					
						
							|  |  |  | 	// order Note: This element is returned only if you have delimiter request parameter
 | 
					
						
							|  |  |  | 	// specified. If response does not include the NextMaker and it is truncated,
 | 
					
						
							|  |  |  | 	// you can use the value of the last Key in the response as the marker in the
 | 
					
						
							|  |  |  | 	// subsequent request to get the next set of object keys.
 | 
					
						
							|  |  |  | 	NextMarker string | 
					
						
							|  |  |  | 	Prefix     string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 13:10:55 +08:00
										 |  |  | // ListObjectsV2Response - format for list objects response.
 | 
					
						
							|  |  |  | type ListObjectsV2Response struct { | 
					
						
							|  |  |  | 	XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListBucketResult" json:"-"` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	CommonPrefixes []CommonPrefix | 
					
						
							|  |  |  | 	Contents       []Object | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Delimiter string | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Encoding type used to encode object keys in the response.
 | 
					
						
							|  |  |  | 	EncodingType string | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// A flag that indicates whether or not ListObjects returned all of the results
 | 
					
						
							|  |  |  | 	// that satisfied the search criteria.
 | 
					
						
							|  |  |  | 	IsTruncated bool | 
					
						
							|  |  |  | 	StartAfter  string | 
					
						
							|  |  |  | 	MaxKeys     int | 
					
						
							|  |  |  | 	Name        string | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// When response is truncated (the IsTruncated element value in the response
 | 
					
						
							|  |  |  | 	// is true), you can use the key name in this field as marker in the subsequent
 | 
					
						
							|  |  |  | 	// request to get next set of objects. Server lists objects in alphabetical
 | 
					
						
							|  |  |  | 	// order Note: This element is returned only if you have delimiter request parameter
 | 
					
						
							|  |  |  | 	// specified. If response does not include the NextMaker and it is truncated,
 | 
					
						
							|  |  |  | 	// you can use the value of the last Key in the response as the marker in the
 | 
					
						
							|  |  |  | 	// subsequent request to get the next set of object keys.
 | 
					
						
							|  |  |  | 	ContinuationToken     string | 
					
						
							|  |  |  | 	NextContinuationToken string | 
					
						
							|  |  |  | 	Prefix                string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | // Part container for part metadata.
 | 
					
						
							|  |  |  | type Part struct { | 
					
						
							|  |  |  | 	PartNumber   int | 
					
						
							|  |  |  | 	ETag         string | 
					
						
							|  |  |  | 	LastModified string | 
					
						
							|  |  |  | 	Size         int64 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ListPartsResponse - format for list parts response.
 | 
					
						
							|  |  |  | type ListPartsResponse struct { | 
					
						
							|  |  |  | 	XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListPartsResult" json:"-"` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Bucket   string | 
					
						
							|  |  |  | 	Key      string | 
					
						
							|  |  |  | 	UploadID string `xml:"UploadId"` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Initiator Initiator | 
					
						
							|  |  |  | 	Owner     Owner | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// The class of storage used to store the object.
 | 
					
						
							|  |  |  | 	StorageClass string | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	PartNumberMarker     int | 
					
						
							|  |  |  | 	NextPartNumberMarker int | 
					
						
							|  |  |  | 	MaxParts             int | 
					
						
							|  |  |  | 	IsTruncated          bool | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// List of parts.
 | 
					
						
							|  |  |  | 	Parts []Part `xml:"Part"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ListMultipartUploadsResponse - format for list multipart uploads response.
 | 
					
						
							|  |  |  | type ListMultipartUploadsResponse struct { | 
					
						
							|  |  |  | 	XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/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 | 
					
						
							|  |  |  | 	Uploads            []Upload `xml:"Upload"` | 
					
						
							|  |  |  | 	Prefix             string | 
					
						
							|  |  |  | 	Delimiter          string | 
					
						
							|  |  |  | 	CommonPrefixes     []CommonPrefix | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ListBucketsResponse - format for list buckets response
 | 
					
						
							|  |  |  | type ListBucketsResponse struct { | 
					
						
							|  |  |  | 	XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListAllMyBucketsResult" json:"-"` | 
					
						
							|  |  |  | 	// Container for one or more buckets.
 | 
					
						
							|  |  |  | 	Buckets struct { | 
					
						
							|  |  |  | 		Buckets []Bucket `xml:"Bucket"` | 
					
						
							|  |  |  | 	} // Buckets are nested
 | 
					
						
							|  |  |  | 	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 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Bucket container for bucket metadata
 | 
					
						
							|  |  |  | type Bucket struct { | 
					
						
							|  |  |  | 	Name         string | 
					
						
							|  |  |  | 	CreationDate string // time string of format "2006-01-02T15:04:05.000Z"
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Object container for object metadata
 | 
					
						
							|  |  |  | type Object struct { | 
					
						
							|  |  |  | 	ETag         string | 
					
						
							|  |  |  | 	Key          string | 
					
						
							|  |  |  | 	LastModified string // time string of format "2006-01-02T15:04:05.000Z"
 | 
					
						
							|  |  |  | 	Size         int64 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Owner Owner | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// The class of storage used to store the object.
 | 
					
						
							|  |  |  | 	StorageClass string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-27 19:04:52 +08:00
										 |  |  | // CopyObjectResponse container returns ETag and LastModified of the
 | 
					
						
							|  |  |  | // successfully copied object
 | 
					
						
							|  |  |  | type CopyObjectResponse struct { | 
					
						
							|  |  |  | 	XMLName      xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ CopyObjectResult" json:"-"` | 
					
						
							|  |  |  | 	ETag         string | 
					
						
							|  |  |  | 	LastModified string // time string of format "2006-01-02T15:04:05.000Z"
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | // Initiator inherit from Owner struct, fields are same
 | 
					
						
							|  |  |  | type Initiator Owner | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Owner - bucket owner/principal
 | 
					
						
							|  |  |  | type Owner struct { | 
					
						
							|  |  |  | 	ID          string | 
					
						
							|  |  |  | 	DisplayName string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // InitiateMultipartUploadResponse container for InitiateMultiPartUpload response, provides uploadID to start MultiPart upload
 | 
					
						
							|  |  |  | type InitiateMultipartUploadResponse struct { | 
					
						
							|  |  |  | 	XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ InitiateMultipartUploadResult" json:"-"` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Bucket   string | 
					
						
							|  |  |  | 	Key      string | 
					
						
							|  |  |  | 	UploadID string `xml:"UploadId"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // CompleteMultipartUploadResponse container for completed multipart upload response
 | 
					
						
							|  |  |  | type CompleteMultipartUploadResponse struct { | 
					
						
							|  |  |  | 	XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ CompleteMultipartUploadResult" json:"-"` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Location string | 
					
						
							|  |  |  | 	Bucket   string | 
					
						
							| 
									
										
										
										
											2016-05-05 06:24:10 +08:00
										 |  |  | 	Key      string | 
					
						
							|  |  |  | 	ETag     string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-06 08:43:48 +08:00
										 |  |  | // DeleteError structure.
 | 
					
						
							|  |  |  | type DeleteError struct { | 
					
						
							|  |  |  | 	Code    string | 
					
						
							|  |  |  | 	Message string | 
					
						
							|  |  |  | 	Key     string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // DeleteObjectsResponse container for multiple object deletes.
 | 
					
						
							|  |  |  | type DeleteObjectsResponse struct { | 
					
						
							|  |  |  | 	XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ DeleteResult" json:"-"` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Collection of all deleted objects
 | 
					
						
							|  |  |  | 	DeletedObjects []ObjectIdentifier `xml:"Deleted,omitempty"` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Collection of errors deleting certain objects.
 | 
					
						
							|  |  |  | 	Errors []DeleteError `xml:"Error,omitempty"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-02 12:01:40 +08:00
										 |  |  | // getLocation get URL location.
 | 
					
						
							|  |  |  | func getLocation(r *http.Request) string { | 
					
						
							| 
									
										
										
										
											2016-06-21 14:25:18 +08:00
										 |  |  | 	return path.Clean(r.URL.Path) // Clean any trailing slashes.
 | 
					
						
							| 
									
										
										
										
											2016-03-02 12:01:40 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-05 06:24:10 +08:00
										 |  |  | // getObjectLocation gets the relative URL for an object
 | 
					
						
							|  |  |  | func getObjectLocation(bucketName string, key string) string { | 
					
						
							|  |  |  | 	return "/" + bucketName + "/" + key | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
 | 
					
						
							| 
									
										
											  
											
												fs: Break fs package to top-level and introduce ObjectAPI interface.
ObjectAPI interface brings in changes needed for XL ObjectAPI layer.
The new interface for any ObjectAPI layer is as below
```
// ObjectAPI interface.
type ObjectAPI interface {
        // Bucket resource API.
        DeleteBucket(bucket string) *probe.Error
        ListBuckets() ([]BucketInfo, *probe.Error)
        MakeBucket(bucket string) *probe.Error
        GetBucketInfo(bucket string) (BucketInfo, *probe.Error)
        // Bucket query API.
        ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsResult, *probe.Error)
        ListMultipartUploads(bucket string, resources BucketMultipartResourcesMetadata) (BucketMultipartResourcesMetadata, *probe.Error)
        // Object resource API.
        GetObject(bucket, object string, startOffset int64) (io.ReadCloser, *probe.Error)
        GetObjectInfo(bucket, object string) (ObjectInfo, *probe.Error)
        PutObject(bucket string, object string, size int64, data io.Reader, metadata map[string]string) (ObjectInfo, *probe.Error)
        DeleteObject(bucket, object string) *probe.Error
        // Object query API.
        NewMultipartUpload(bucket, object string) (string, *probe.Error)
        PutObjectPart(bucket, object, uploadID string, partID int, size int64, data io.Reader, md5Hex string) (string, *probe.Error)
        ListObjectParts(bucket, object string, resources ObjectResourcesMetadata) (ObjectResourcesMetadata, *probe.Error)
        CompleteMultipartUpload(bucket string, object string, uploadID string, parts []CompletePart) (ObjectInfo, *probe.Error)
        AbortMultipartUpload(bucket, object, uploadID string) *probe.Error
}
```
											
										 
											2016-03-31 07:15:28 +08:00
										 |  |  | func generateListBucketsResponse(buckets []BucketInfo) ListBucketsResponse { | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +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 { | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | 		var listbucket = Bucket{} | 
					
						
							| 
									
										
										
										
											2015-02-16 09:03:27 +08:00
										 |  |  | 		listbucket.Name = bucket.Name | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | 		listbucket.CreationDate = bucket.Created.Format(timeFormatAMZ) | 
					
						
							| 
									
										
										
										
											2015-02-16 09:03:27 +08:00
										 |  |  | 		listbuckets = append(listbuckets, listbucket) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	data.Owner = owner | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | 	data.Buckets.Buckets = listbuckets | 
					
						
							| 
									
										
										
										
											2015-02-16 09:03:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return data | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-18 03:32:05 +08:00
										 |  |  | // generates an ListObjectsV1 response for the said bucket with other enumerated options.
 | 
					
						
							|  |  |  | func generateListObjectsV1Response(bucket, prefix, marker, delimiter string, maxKeys int, resp ListObjectsInfo) ListObjectsResponse { | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +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" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 	for _, object := range resp.Objects { | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | 		var content = Object{} | 
					
						
							| 
									
										
										
										
											2016-03-12 08:31:24 +08:00
										 |  |  | 		if object.Name == "" { | 
					
						
							| 
									
										
										
										
											2015-03-01 06:44:26 +08:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-03-12 08:31:24 +08:00
										 |  |  | 		content.Key = object.Name | 
					
						
							| 
									
										
										
										
											2016-04-09 01:37:38 +08:00
										 |  |  | 		content.LastModified = object.ModTime.UTC().Format(timeFormatAMZ) | 
					
						
							| 
									
										
										
										
											2016-03-12 08:31:24 +08:00
										 |  |  | 		if object.MD5Sum != "" { | 
					
						
							|  |  |  | 			content.ETag = "\"" + object.MD5Sum + "\"" | 
					
						
							| 
									
										
										
										
											2016-02-02 04:19:54 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-02-16 09:03:27 +08:00
										 |  |  | 		content.Size = object.Size | 
					
						
							|  |  |  | 		content.StorageClass = "STANDARD" | 
					
						
							|  |  |  | 		content.Owner = owner | 
					
						
							|  |  |  | 		contents = append(contents, content) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											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-11-10 19:10:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 	data.Prefix = prefix | 
					
						
							|  |  |  | 	data.Marker = marker | 
					
						
							|  |  |  | 	data.Delimiter = delimiter | 
					
						
							|  |  |  | 	data.MaxKeys = maxKeys | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	data.NextMarker = resp.NextMarker | 
					
						
							|  |  |  | 	data.IsTruncated = resp.IsTruncated | 
					
						
							| 
									
										
										
										
											2016-06-01 13:10:55 +08:00
										 |  |  | 	for _, prefix := range resp.Prefixes { | 
					
						
							|  |  |  | 		var prefixItem = CommonPrefix{} | 
					
						
							|  |  |  | 		prefixItem.Prefix = prefix | 
					
						
							|  |  |  | 		prefixes = append(prefixes, prefixItem) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	data.CommonPrefixes = prefixes | 
					
						
							|  |  |  | 	return data | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-18 03:32:05 +08:00
										 |  |  | // generates an ListObjectsV2 response for the said bucket with other enumerated options.
 | 
					
						
							| 
									
										
										
										
											2016-09-11 01:44:38 +08:00
										 |  |  | func generateListObjectsV2Response(bucket, prefix, token, startAfter, delimiter string, fetchOwner bool, maxKeys int, resp ListObjectsInfo) ListObjectsV2Response { | 
					
						
							| 
									
										
										
										
											2016-06-01 13:10:55 +08:00
										 |  |  | 	var contents []Object | 
					
						
							|  |  |  | 	var prefixes []CommonPrefix | 
					
						
							|  |  |  | 	var owner = Owner{} | 
					
						
							|  |  |  | 	var data = ListObjectsV2Response{} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-11 01:44:38 +08:00
										 |  |  | 	if fetchOwner { | 
					
						
							|  |  |  | 		owner.ID = "minio" | 
					
						
							|  |  |  | 		owner.DisplayName = "minio" | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-06-01 13:10:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for _, object := range resp.Objects { | 
					
						
							|  |  |  | 		var content = Object{} | 
					
						
							|  |  |  | 		if object.Name == "" { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		content.Key = object.Name | 
					
						
							|  |  |  | 		content.LastModified = object.ModTime.UTC().Format(timeFormatAMZ) | 
					
						
							|  |  |  | 		if object.MD5Sum != "" { | 
					
						
							|  |  |  | 			content.ETag = "\"" + object.MD5Sum + "\"" | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		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.StartAfter = startAfter | 
					
						
							|  |  |  | 	data.Delimiter = delimiter | 
					
						
							|  |  |  | 	data.Prefix = prefix | 
					
						
							|  |  |  | 	data.MaxKeys = maxKeys | 
					
						
							|  |  |  | 	data.ContinuationToken = token | 
					
						
							|  |  |  | 	data.NextContinuationToken = resp.NextMarker | 
					
						
							|  |  |  | 	data.IsTruncated = resp.IsTruncated | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 	for _, prefix := range resp.Prefixes { | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-27 19:04:52 +08:00
										 |  |  | // generateCopyObjectResponse
 | 
					
						
							|  |  |  | func generateCopyObjectResponse(etag string, lastModified time.Time) CopyObjectResponse { | 
					
						
							|  |  |  | 	return CopyObjectResponse{ | 
					
						
							|  |  |  | 		ETag:         "\"" + etag + "\"", | 
					
						
							| 
									
										
										
										
											2016-02-29 10:10:37 +08:00
										 |  |  | 		LastModified: lastModified.UTC().Format(timeFormatAMZ), | 
					
						
							| 
									
										
										
										
											2016-02-27 19:04:52 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-10 10:01:15 +08:00
										 |  |  | // generateInitiateMultipartUploadResponse
 | 
					
						
							|  |  |  | func generateInitiateMultipartUploadResponse(bucket, key, uploadID string) InitiateMultipartUploadResponse { | 
					
						
							|  |  |  | 	return InitiateMultipartUploadResponse{ | 
					
						
							| 
									
										
										
										
											2015-05-08 10:55:30 +08:00
										 |  |  | 		Bucket:   bucket, | 
					
						
							|  |  |  | 		Key:      key, | 
					
						
							|  |  |  | 		UploadID: uploadID, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-10 10:01:15 +08:00
										 |  |  | // generateCompleteMultipartUploadResponse
 | 
					
						
							|  |  |  | func generateCompleteMultpartUploadResponse(bucket, key, location, etag string) CompleteMultipartUploadResponse { | 
					
						
							|  |  |  | 	return CompleteMultipartUploadResponse{ | 
					
						
							| 
									
										
										
										
											2015-05-08 13:43:19 +08:00
										 |  |  | 		Location: location, | 
					
						
							|  |  |  | 		Bucket:   bucket, | 
					
						
							|  |  |  | 		Key:      key, | 
					
						
							|  |  |  | 		ETag:     etag, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-10 02:41:26 +08:00
										 |  |  | // generateListPartsResult
 | 
					
						
							| 
									
										
										
											
												objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
											
										 
											2016-04-03 16:34:20 +08:00
										 |  |  | func generateListPartsResponse(partsInfo ListPartsInfo) ListPartsResponse { | 
					
						
							| 
									
										
										
										
											2015-05-10 02:41:26 +08:00
										 |  |  | 	// TODO - support EncodingType in xml decoding
 | 
					
						
							|  |  |  | 	listPartsResponse := ListPartsResponse{} | 
					
						
							| 
									
										
										
											
												objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
											
										 
											2016-04-03 16:34:20 +08:00
										 |  |  | 	listPartsResponse.Bucket = partsInfo.Bucket | 
					
						
							|  |  |  | 	listPartsResponse.Key = partsInfo.Object | 
					
						
							|  |  |  | 	listPartsResponse.UploadID = partsInfo.UploadID | 
					
						
							| 
									
										
										
										
											2015-05-10 02:41:26 +08:00
										 |  |  | 	listPartsResponse.StorageClass = "STANDARD" | 
					
						
							|  |  |  | 	listPartsResponse.Initiator.ID = "minio" | 
					
						
							|  |  |  | 	listPartsResponse.Initiator.DisplayName = "minio" | 
					
						
							|  |  |  | 	listPartsResponse.Owner.ID = "minio" | 
					
						
							|  |  |  | 	listPartsResponse.Owner.DisplayName = "minio" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
											
												objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
											
										 
											2016-04-03 16:34:20 +08:00
										 |  |  | 	listPartsResponse.MaxParts = partsInfo.MaxParts | 
					
						
							|  |  |  | 	listPartsResponse.PartNumberMarker = partsInfo.PartNumberMarker | 
					
						
							|  |  |  | 	listPartsResponse.IsTruncated = partsInfo.IsTruncated | 
					
						
							|  |  |  | 	listPartsResponse.NextPartNumberMarker = partsInfo.NextPartNumberMarker | 
					
						
							| 
									
										
										
										
											2015-05-10 02:41:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
											
												objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
											
										 
											2016-04-03 16:34:20 +08:00
										 |  |  | 	listPartsResponse.Parts = make([]Part, len(partsInfo.Parts)) | 
					
						
							|  |  |  | 	for index, part := range partsInfo.Parts { | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | 		newPart := Part{} | 
					
						
							| 
									
										
										
										
											2015-05-10 02:41:26 +08:00
										 |  |  | 		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 | 
					
						
							| 
									
										
										
										
											2016-02-29 10:10:37 +08:00
										 |  |  | 		newPart.LastModified = part.LastModified.UTC().Format(timeFormatAMZ) | 
					
						
							| 
									
										
										
										
											2016-03-20 14:44:43 +08:00
										 |  |  | 		listPartsResponse.Parts[index] = newPart | 
					
						
							| 
									
										
										
										
											2015-05-10 02:41:26 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return listPartsResponse | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-10 10:01:15 +08:00
										 |  |  | // generateListMultipartUploadsResponse
 | 
					
						
							| 
									
										
										
											
												objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
											
										 
											2016-04-03 16:34:20 +08:00
										 |  |  | func generateListMultipartUploadsResponse(bucket string, multipartsInfo ListMultipartsInfo) ListMultipartUploadsResponse { | 
					
						
							| 
									
										
										
										
											2015-05-15 05:36:41 +08:00
										 |  |  | 	listMultipartUploadsResponse := ListMultipartUploadsResponse{} | 
					
						
							|  |  |  | 	listMultipartUploadsResponse.Bucket = bucket | 
					
						
							| 
									
										
										
											
												objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
											
										 
											2016-04-03 16:34:20 +08:00
										 |  |  | 	listMultipartUploadsResponse.Delimiter = multipartsInfo.Delimiter | 
					
						
							|  |  |  | 	listMultipartUploadsResponse.IsTruncated = multipartsInfo.IsTruncated | 
					
						
							|  |  |  | 	listMultipartUploadsResponse.EncodingType = multipartsInfo.EncodingType | 
					
						
							|  |  |  | 	listMultipartUploadsResponse.Prefix = multipartsInfo.Prefix | 
					
						
							|  |  |  | 	listMultipartUploadsResponse.KeyMarker = multipartsInfo.KeyMarker | 
					
						
							|  |  |  | 	listMultipartUploadsResponse.NextKeyMarker = multipartsInfo.NextKeyMarker | 
					
						
							|  |  |  | 	listMultipartUploadsResponse.MaxUploads = multipartsInfo.MaxUploads | 
					
						
							|  |  |  | 	listMultipartUploadsResponse.NextUploadIDMarker = multipartsInfo.NextUploadIDMarker | 
					
						
							|  |  |  | 	listMultipartUploadsResponse.UploadIDMarker = multipartsInfo.UploadIDMarker | 
					
						
							| 
									
										
										
										
											2016-04-06 06:08:59 +08:00
										 |  |  | 	listMultipartUploadsResponse.CommonPrefixes = make([]CommonPrefix, len(multipartsInfo.CommonPrefixes)) | 
					
						
							|  |  |  | 	for index, commonPrefix := range multipartsInfo.CommonPrefixes { | 
					
						
							|  |  |  | 		listMultipartUploadsResponse.CommonPrefixes[index] = CommonPrefix{ | 
					
						
							|  |  |  | 			Prefix: commonPrefix, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
											
												objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
											
										 
											2016-04-03 16:34:20 +08:00
										 |  |  | 	listMultipartUploadsResponse.Uploads = make([]Upload, len(multipartsInfo.Uploads)) | 
					
						
							|  |  |  | 	for index, upload := range multipartsInfo.Uploads { | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | 		newUpload := Upload{} | 
					
						
							| 
									
										
										
										
											2015-05-15 05:36:41 +08:00
										 |  |  | 		newUpload.UploadID = upload.UploadID | 
					
						
							| 
									
										
										
										
											2015-10-17 02:26:01 +08:00
										 |  |  | 		newUpload.Key = upload.Object | 
					
						
							| 
									
										
										
										
											2016-03-20 14:44:43 +08:00
										 |  |  | 		newUpload.Initiated = upload.Initiated.UTC().Format(timeFormatAMZ) | 
					
						
							|  |  |  | 		listMultipartUploadsResponse.Uploads[index] = newUpload | 
					
						
							| 
									
										
										
										
											2015-05-15 05:36:41 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return listMultipartUploadsResponse | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-06 08:43:48 +08:00
										 |  |  | // generate multi objects delete response.
 | 
					
						
							|  |  |  | func generateMultiDeleteResponse(quiet bool, deletedObjects []ObjectIdentifier, errs []DeleteError) DeleteObjectsResponse { | 
					
						
							|  |  |  | 	deleteResp := DeleteObjectsResponse{} | 
					
						
							|  |  |  | 	if !quiet { | 
					
						
							|  |  |  | 		deleteResp.DeletedObjects = deletedObjects | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	deleteResp.Errors = errs | 
					
						
							|  |  |  | 	return deleteResp | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 16:40:06 +08:00
										 |  |  | // 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() | 
					
						
							| 
									
										
										
										
											2015-04-30 01:51:59 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-17 11:02:37 +08:00
										 |  |  | // writeSuccessNoContent write success headers with http status 204
 | 
					
						
							|  |  |  | func writeSuccessNoContent(w http.ResponseWriter) { | 
					
						
							| 
									
										
										
										
											2016-01-08 16:40:06 +08:00
										 |  |  | 	setCommonHeaders(w) | 
					
						
							| 
									
										
										
										
											2015-10-17 11:02:37 +08:00
										 |  |  | 	w.WriteHeader(http.StatusNoContent) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-10 02:41:26 +08:00
										 |  |  | // writeErrorRespone write error headers
 | 
					
						
							| 
									
										
										
										
											2016-03-10 18:24:52 +08:00
										 |  |  | func writeErrorResponse(w http.ResponseWriter, req *http.Request, errorCode APIErrorCode, resource string) { | 
					
						
							|  |  |  | 	error := getAPIError(errorCode) | 
					
						
							| 
									
										
										
										
											2015-04-30 06:28:04 +08:00
										 |  |  | 	// set common headers
 | 
					
						
							| 
									
										
										
										
											2016-01-08 16:40:06 +08:00
										 |  |  | 	setCommonHeaders(w) | 
					
						
							| 
									
										
										
										
											2015-05-16 11:44:42 +08:00
										 |  |  | 	// write Header
 | 
					
						
							| 
									
										
										
										
											2015-04-23 07:28:13 +08:00
										 |  |  | 	w.WriteHeader(error.HTTPStatusCode) | 
					
						
							| 
									
										
										
										
											2016-07-01 09:48:50 +08:00
										 |  |  | 	writeErrorResponseNoHeader(w, req, errorCode, resource) | 
					
						
							| 
									
										
										
										
											2016-06-16 11:31:06 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-01 09:48:50 +08:00
										 |  |  | func writeErrorResponseNoHeader(w http.ResponseWriter, req *http.Request, errorCode APIErrorCode, resource string) { | 
					
						
							|  |  |  | 	error := getAPIError(errorCode) | 
					
						
							| 
									
										
										
										
											2016-06-29 05:51:49 +08:00
										 |  |  | 	// Generate error response.
 | 
					
						
							| 
									
										
										
										
											2016-06-16 11:31:06 +08:00
										 |  |  | 	errorResponse := getAPIErrorResponse(error, resource) | 
					
						
							|  |  |  | 	encodedErrorResponse := encodeResponse(errorResponse) | 
					
						
							| 
									
										
										
										
											2015-09-19 17:36:50 +08:00
										 |  |  | 	// HEAD should have no body, do not attempt to write to it
 | 
					
						
							| 
									
										
										
										
											2015-07-11 12:06:43 +08:00
										 |  |  | 	if req.Method != "HEAD" { | 
					
						
							|  |  |  | 		// write error body
 | 
					
						
							|  |  |  | 		w.Write(encodedErrorResponse) | 
					
						
							| 
									
										
										
										
											2016-01-08 16:40:06 +08:00
										 |  |  | 		w.(http.Flusher).Flush() | 
					
						
							| 
									
										
										
										
											2015-07-11 12:06:43 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-23 07:28:13 +08:00
										 |  |  | } |