mirror of https://github.com/minio/minio.git
				
				
				
			
		
			
	
	
		
			186 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Go
		
	
	
	
		
		
			
		
	
	
			186 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Go
		
	
	
	
|  | /* | ||
|  |  * 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" | ||
|  | 	"time" | ||
|  | 
 | ||
|  | 	"github.com/Azure/azure-sdk-for-go/storage" | ||
|  | ) | ||
|  | 
 | ||
|  | // AnonGetBucketInfo - Get bucket metadata from azure anonymously.
 | ||
|  | func (a AzureObjects) AnonGetBucketInfo(bucket string) (bucketInfo BucketInfo, err error) { | ||
|  | 	url, err := url.Parse(a.client.GetBlobURL(bucket, "")) | ||
|  | 	if err != nil { | ||
|  | 		return bucketInfo, azureToObjectError(traceError(err)) | ||
|  | 	} | ||
|  | 	url.RawQuery = "restype=container" | ||
|  | 	resp, err := http.Head(url.String()) | ||
|  | 	if err != nil { | ||
|  | 		return bucketInfo, azureToObjectError(traceError(err), bucket) | ||
|  | 	} | ||
|  | 	defer resp.Body.Close() | ||
|  | 
 | ||
|  | 	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) | ||
|  | 	} | ||
|  | 	bucketInfo = BucketInfo{ | ||
|  | 		Name:    bucket, | ||
|  | 		Created: t, | ||
|  | 	} | ||
|  | 	return bucketInfo, nil | ||
|  | } | ||
|  | 
 | ||
|  | // AnonGetObject - SendGET request without authentication.
 | ||
|  | // This is needed when clients send GET requests on objects that can be downloaded without auth.
 | ||
|  | func (a AzureObjects) AnonGetObject(bucket, object string, startOffset int64, length int64, writer io.Writer) (err error) { | ||
|  | 	u := a.client.GetBlobURL(bucket, object) | ||
|  | 	req, err := http.NewRequest("GET", u, nil) | ||
|  | 	if err != nil { | ||
|  | 		return azureToObjectError(traceError(err), bucket, object) | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if length > 0 && startOffset > 0 { | ||
|  | 		req.Header.Add("Range", fmt.Sprintf("bytes=%d-%d", startOffset, startOffset+length-1)) | ||
|  | 	} else if startOffset > 0 { | ||
|  | 		req.Header.Add("Range", fmt.Sprintf("bytes=%d-", startOffset)) | ||
|  | 	} | ||
|  | 
 | ||
|  | 	resp, err := http.DefaultClient.Do(req) | ||
|  | 	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.
 | ||
|  | func (a AzureObjects) AnonGetObjectInfo(bucket, object string) (objInfo ObjectInfo, err error) { | ||
|  | 	resp, err := http.Head(a.client.GetBlobURL(bucket, object)) | ||
|  | 	if err != nil { | ||
|  | 		return objInfo, azureToObjectError(traceError(err), bucket, object) | ||
|  | 	} | ||
|  | 	defer resp.Body.Close() | ||
|  | 
 | ||
|  | 	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") | ||
|  | 	objInfo.MD5Sum = resp.Header.Get("Etag") | ||
|  | 	objInfo.ModTime = t | ||
|  | 	objInfo.Name = object | ||
|  | 	objInfo.Size = contentLength | ||
|  | 	return | ||
|  | } | ||
|  | 
 | ||
|  | // AnonListObjects - Use Azure equivalent ListBlobs.
 | ||
|  | func (a AzureObjects) AnonListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (result ListObjectsInfo, err error) { | ||
|  | 	params := storage.ListBlobsParameters{ | ||
|  | 		Prefix:     prefix, | ||
|  | 		Marker:     marker, | ||
|  | 		Delimiter:  delimiter, | ||
|  | 		MaxResults: uint(maxKeys), | ||
|  | 	} | ||
|  | 
 | ||
|  | 	q := azureListBlobsGetParameters(params) | ||
|  | 	q.Set("restype", "container") | ||
|  | 	q.Set("comp", "list") | ||
|  | 
 | ||
|  | 	url, err := url.Parse(a.client.GetBlobURL(bucket, "")) | ||
|  | 	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)) | ||
|  | 	} | ||
|  | 
 | ||
|  | 	result.IsTruncated = listResp.NextMarker != "" | ||
|  | 	result.NextMarker = listResp.NextMarker | ||
|  | 	for _, object := range listResp.Blobs { | ||
|  | 		t, e := time.Parse(time.RFC1123, object.Properties.LastModified) | ||
|  | 		if e != nil { | ||
|  | 			continue | ||
|  | 		} | ||
|  | 		result.Objects = append(result.Objects, ObjectInfo{ | ||
|  | 			Bucket:          bucket, | ||
|  | 			Name:            object.Name, | ||
|  | 			ModTime:         t, | ||
|  | 			Size:            object.Properties.ContentLength, | ||
|  | 			MD5Sum:          object.Properties.Etag, | ||
|  | 			ContentType:     object.Properties.ContentType, | ||
|  | 			ContentEncoding: object.Properties.ContentEncoding, | ||
|  | 		}) | ||
|  | 	} | ||
|  | 	result.Prefixes = listResp.BlobPrefixes | ||
|  | 	return result, nil | ||
|  | } |