| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | /* | 
					
						
							|  |  |  |  * Minio Cloud Storage, (C) 2017 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 cmd | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"encoding/xml" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"io" | 
					
						
							|  |  |  | 	"io/ioutil" | 
					
						
							|  |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"net/url" | 
					
						
							|  |  |  | 	"strconv" | 
					
						
							| 
									
										
										
										
											2017-09-29 06:23:46 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/Azure/azure-sdk-for-go/storage" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-29 06:23:46 +08:00
										 |  |  | // Copied from github.com/Azure/azure-sdk-for-go/storage/container.go
 | 
					
						
							|  |  |  | func azureListBlobsGetParameters(p storage.ListBlobsParameters) url.Values { | 
					
						
							|  |  |  | 	out := url.Values{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if p.Prefix != "" { | 
					
						
							|  |  |  | 		out.Set("prefix", p.Prefix) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if p.Delimiter != "" { | 
					
						
							|  |  |  | 		out.Set("delimiter", p.Delimiter) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if p.Marker != "" { | 
					
						
							|  |  |  | 		out.Set("marker", p.Marker) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if p.Include != nil { | 
					
						
							|  |  |  | 		addString := func(datasets []string, include bool, text string) []string { | 
					
						
							|  |  |  | 			if include { | 
					
						
							|  |  |  | 				datasets = append(datasets, text) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return datasets | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		include := []string{} | 
					
						
							|  |  |  | 		include = addString(include, p.Include.Snapshots, "snapshots") | 
					
						
							|  |  |  | 		include = addString(include, p.Include.Metadata, "metadata") | 
					
						
							|  |  |  | 		include = addString(include, p.Include.UncommittedBlobs, "uncommittedblobs") | 
					
						
							|  |  |  | 		include = addString(include, p.Include.Copy, "copy") | 
					
						
							|  |  |  | 		fullInclude := strings.Join(include, ",") | 
					
						
							|  |  |  | 		out.Set("include", fullInclude) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if p.MaxResults != 0 { | 
					
						
							|  |  |  | 		out.Set("maxresults", fmt.Sprintf("%v", p.MaxResults)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if p.Timeout != 0 { | 
					
						
							|  |  |  | 		out.Set("timeout", fmt.Sprintf("%v", p.Timeout)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return out | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-24 13:07:46 +08:00
										 |  |  | // Make anonymous HTTP request to azure endpoint.
 | 
					
						
							|  |  |  | func azureAnonRequest(verb, urlStr string, header http.Header) (*http.Response, error) { | 
					
						
							|  |  |  | 	req, err := http.NewRequest(verb, urlStr, nil) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if header != nil { | 
					
						
							|  |  |  | 		req.Header = header | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	resp, err := http.DefaultClient.Do(req) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 4XX and 5XX are error HTTP codes.
 | 
					
						
							|  |  |  | 	if resp.StatusCode >= 400 && resp.StatusCode <= 511 { | 
					
						
							|  |  |  | 		defer resp.Body.Close() | 
					
						
							|  |  |  | 		respBody, err := ioutil.ReadAll(resp.Body) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if len(respBody) == 0 { | 
					
						
							|  |  |  | 			// no error in response body, might happen in HEAD requests
 | 
					
						
							|  |  |  | 			return nil, storage.AzureStorageServiceError{ | 
					
						
							|  |  |  | 				StatusCode: resp.StatusCode, | 
					
						
							|  |  |  | 				Code:       resp.Status, | 
					
						
							|  |  |  | 				Message:    "no response body was available for error status code", | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Response contains Azure storage service error object.
 | 
					
						
							|  |  |  | 		var storageErr storage.AzureStorageServiceError | 
					
						
							|  |  |  | 		if err := xml.Unmarshal(respBody, &storageErr); err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		storageErr.StatusCode = resp.StatusCode | 
					
						
							|  |  |  | 		return nil, storageErr | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return resp, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | // AnonGetBucketInfo - Get bucket metadata from azure anonymously.
 | 
					
						
							| 
									
										
										
										
											2017-05-15 15:52:33 +08:00
										 |  |  | func (a *azureObjects) AnonGetBucketInfo(bucket string) (bucketInfo BucketInfo, err error) { | 
					
						
							| 
									
										
										
										
											2017-09-29 06:23:46 +08:00
										 |  |  | 	blobURL := a.client.GetContainerReference(bucket).GetBlobReference("").GetURL() | 
					
						
							|  |  |  | 	url, err := url.Parse(blobURL) | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return bucketInfo, azureToObjectError(traceError(err)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	url.RawQuery = "restype=container" | 
					
						
							| 
									
										
										
										
											2017-06-24 13:07:46 +08:00
										 |  |  | 	resp, err := azureAnonRequest(httpHEAD, url.String(), nil) | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return bucketInfo, azureToObjectError(traceError(err), bucket) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-24 13:07:46 +08:00
										 |  |  | 	defer resp.Body.Close() | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if resp.StatusCode != http.StatusOK { | 
					
						
							|  |  |  | 		return bucketInfo, azureToObjectError(traceError(anonErrToObjectErr(resp.StatusCode, bucket)), bucket) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t, err := time.Parse(time.RFC1123, resp.Header.Get("Last-Modified")) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return bucketInfo, traceError(err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-09-29 10:37:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	bucketInfo = BucketInfo{ | 
					
						
							|  |  |  | 		Name:    bucket, | 
					
						
							|  |  |  | 		Created: t, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-09-29 10:37:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	return bucketInfo, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // AnonGetObject - SendGET request without authentication.
 | 
					
						
							|  |  |  | // This is needed when clients send GET requests on objects that can be downloaded without auth.
 | 
					
						
							| 
									
										
										
										
											2017-05-15 15:52:33 +08:00
										 |  |  | func (a *azureObjects) AnonGetObject(bucket, object string, startOffset int64, length int64, writer io.Writer) (err error) { | 
					
						
							| 
									
										
										
										
											2017-06-24 13:07:46 +08:00
										 |  |  | 	h := make(http.Header) | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	if length > 0 && startOffset > 0 { | 
					
						
							| 
									
										
										
										
											2017-06-24 13:07:46 +08:00
										 |  |  | 		h.Add("Range", fmt.Sprintf("bytes=%d-%d", startOffset, startOffset+length-1)) | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	} else if startOffset > 0 { | 
					
						
							| 
									
										
										
										
											2017-06-24 13:07:46 +08:00
										 |  |  | 		h.Add("Range", fmt.Sprintf("bytes=%d-", startOffset)) | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-29 06:23:46 +08:00
										 |  |  | 	blobURL := a.client.GetContainerReference(bucket).GetBlobReference(object).GetURL() | 
					
						
							|  |  |  | 	resp, err := azureAnonRequest(httpGET, blobURL, h) | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return azureToObjectError(traceError(err), bucket, object) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer resp.Body.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if resp.StatusCode != http.StatusPartialContent && resp.StatusCode != http.StatusOK { | 
					
						
							|  |  |  | 		return azureToObjectError(traceError(anonErrToObjectErr(resp.StatusCode, bucket, object)), bucket, object) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_, err = io.Copy(writer, resp.Body) | 
					
						
							|  |  |  | 	return traceError(err) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // AnonGetObjectInfo - Send HEAD request without authentication and convert the
 | 
					
						
							|  |  |  | // result to ObjectInfo.
 | 
					
						
							| 
									
										
										
										
											2017-05-15 15:52:33 +08:00
										 |  |  | func (a *azureObjects) AnonGetObjectInfo(bucket, object string) (objInfo ObjectInfo, err error) { | 
					
						
							| 
									
										
										
										
											2017-09-29 06:23:46 +08:00
										 |  |  | 	blobURL := a.client.GetContainerReference(bucket).GetBlobReference(object).GetURL() | 
					
						
							|  |  |  | 	resp, err := azureAnonRequest(httpHEAD, blobURL, nil) | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return objInfo, azureToObjectError(traceError(err), bucket, object) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-24 13:07:46 +08:00
										 |  |  | 	defer resp.Body.Close() | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if resp.StatusCode != http.StatusOK { | 
					
						
							|  |  |  | 		return objInfo, azureToObjectError(traceError(anonErrToObjectErr(resp.StatusCode, bucket, object)), bucket, object) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var contentLength int64 | 
					
						
							|  |  |  | 	contentLengthStr := resp.Header.Get("Content-Length") | 
					
						
							|  |  |  | 	if contentLengthStr != "" { | 
					
						
							|  |  |  | 		contentLength, err = strconv.ParseInt(contentLengthStr, 0, 64) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return objInfo, azureToObjectError(traceError(errUnexpected), bucket, object) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t, err := time.Parse(time.RFC1123, resp.Header.Get("Last-Modified")) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return objInfo, traceError(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	objInfo.ModTime = t | 
					
						
							|  |  |  | 	objInfo.Bucket = bucket | 
					
						
							|  |  |  | 	objInfo.UserDefined = make(map[string]string) | 
					
						
							|  |  |  | 	if resp.Header.Get("Content-Encoding") != "" { | 
					
						
							|  |  |  | 		objInfo.UserDefined["Content-Encoding"] = resp.Header.Get("Content-Encoding") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	objInfo.UserDefined["Content-Type"] = resp.Header.Get("Content-Type") | 
					
						
							| 
									
										
										
										
											2017-05-15 03:05:51 +08:00
										 |  |  | 	objInfo.ETag = resp.Header.Get("Etag") | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	objInfo.ModTime = t | 
					
						
							|  |  |  | 	objInfo.Name = object | 
					
						
							|  |  |  | 	objInfo.Size = contentLength | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // AnonListObjects - Use Azure equivalent ListBlobs.
 | 
					
						
							| 
									
										
										
										
											2017-05-15 15:52:33 +08:00
										 |  |  | func (a *azureObjects) AnonListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (result ListObjectsInfo, err error) { | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	params := storage.ListBlobsParameters{ | 
					
						
							|  |  |  | 		Prefix:     prefix, | 
					
						
							|  |  |  | 		Marker:     marker, | 
					
						
							|  |  |  | 		Delimiter:  delimiter, | 
					
						
							|  |  |  | 		MaxResults: uint(maxKeys), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	q := azureListBlobsGetParameters(params) | 
					
						
							|  |  |  | 	q.Set("restype", "container") | 
					
						
							|  |  |  | 	q.Set("comp", "list") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-29 06:23:46 +08:00
										 |  |  | 	blobURL := a.client.GetContainerReference(bucket).GetBlobReference("").GetURL() | 
					
						
							|  |  |  | 	url, err := url.Parse(blobURL) | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return result, azureToObjectError(traceError(err)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	url.RawQuery = q.Encode() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-24 13:07:46 +08:00
										 |  |  | 	resp, err := azureAnonRequest(httpGET, url.String(), nil) | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return result, azureToObjectError(traceError(err)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer resp.Body.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var listResp storage.BlobListResponse | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	data, err := ioutil.ReadAll(resp.Body) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return result, azureToObjectError(traceError(err)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	err = xml.Unmarshal(data, &listResp) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return result, azureToObjectError(traceError(err)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	result.IsTruncated = listResp.NextMarker != "" | 
					
						
							|  |  |  | 	result.NextMarker = listResp.NextMarker | 
					
						
							|  |  |  | 	for _, object := range listResp.Blobs { | 
					
						
							|  |  |  | 		result.Objects = append(result.Objects, ObjectInfo{ | 
					
						
							|  |  |  | 			Bucket:          bucket, | 
					
						
							|  |  |  | 			Name:            object.Name, | 
					
						
							| 
									
										
										
										
											2017-09-29 06:23:46 +08:00
										 |  |  | 			ModTime:         time.Time(object.Properties.LastModified), | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 			Size:            object.Properties.ContentLength, | 
					
						
							| 
									
										
										
										
											2017-05-15 03:05:51 +08:00
										 |  |  | 			ETag:            object.Properties.Etag, | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 			ContentType:     object.Properties.ContentType, | 
					
						
							|  |  |  | 			ContentEncoding: object.Properties.ContentEncoding, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	result.Prefixes = listResp.BlobPrefixes | 
					
						
							|  |  |  | 	return result, nil | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-06-17 13:17:00 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // AnonListObjectsV2 - List objects in V2 mode, anonymously
 | 
					
						
							| 
									
										
										
										
											2017-09-30 03:08:23 +08:00
										 |  |  | func (a *azureObjects) AnonListObjectsV2(bucket, prefix, continuationToken, delimiter string, maxKeys int, fetchOwner bool, startAfter string) (result ListObjectsV2Info, err error) { | 
					
						
							| 
									
										
										
										
											2017-06-17 13:17:00 +08:00
										 |  |  | 	params := storage.ListBlobsParameters{ | 
					
						
							|  |  |  | 		Prefix:     prefix, | 
					
						
							|  |  |  | 		Marker:     continuationToken, | 
					
						
							|  |  |  | 		Delimiter:  delimiter, | 
					
						
							|  |  |  | 		MaxResults: uint(maxKeys), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	q := azureListBlobsGetParameters(params) | 
					
						
							|  |  |  | 	q.Set("restype", "container") | 
					
						
							|  |  |  | 	q.Set("comp", "list") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-29 06:23:46 +08:00
										 |  |  | 	blobURL := a.client.GetContainerReference(bucket).GetBlobReference("").GetURL() | 
					
						
							|  |  |  | 	url, err := url.Parse(blobURL) | 
					
						
							| 
									
										
										
										
											2017-06-17 13:17:00 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return result, azureToObjectError(traceError(err)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	url.RawQuery = q.Encode() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	resp, err := http.Get(url.String()) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return result, azureToObjectError(traceError(err)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer resp.Body.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var listResp storage.BlobListResponse | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	data, err := ioutil.ReadAll(resp.Body) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return result, azureToObjectError(traceError(err)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	err = xml.Unmarshal(data, &listResp) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return result, azureToObjectError(traceError(err)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If NextMarker is not empty, this means response is truncated and NextContinuationToken should be set
 | 
					
						
							|  |  |  | 	if listResp.NextMarker != "" { | 
					
						
							|  |  |  | 		result.IsTruncated = true | 
					
						
							|  |  |  | 		result.NextContinuationToken = listResp.NextMarker | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, object := range listResp.Blobs { | 
					
						
							|  |  |  | 		result.Objects = append(result.Objects, ObjectInfo{ | 
					
						
							|  |  |  | 			Bucket:          bucket, | 
					
						
							|  |  |  | 			Name:            object.Name, | 
					
						
							| 
									
										
										
										
											2017-09-29 06:23:46 +08:00
										 |  |  | 			ModTime:         time.Time(object.Properties.LastModified), | 
					
						
							| 
									
										
										
										
											2017-06-17 13:17:00 +08:00
										 |  |  | 			Size:            object.Properties.ContentLength, | 
					
						
							|  |  |  | 			ETag:            canonicalizeETag(object.Properties.Etag), | 
					
						
							|  |  |  | 			ContentType:     object.Properties.ContentType, | 
					
						
							|  |  |  | 			ContentEncoding: object.Properties.ContentEncoding, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	result.Prefixes = listResp.BlobPrefixes | 
					
						
							|  |  |  | 	return result, nil | 
					
						
							|  |  |  | } |