mirror of https://github.com/minio/minio.git
				
				
				
			
		
			
				
	
	
		
			134 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			134 lines
		
	
	
		
			4.4 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 (
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"net/http"
 | 
						|
	"net/url"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
	"time"
 | 
						|
)
 | 
						|
 | 
						|
// mkRange converts offset, size into Range header equivalent.
 | 
						|
func mkRange(offset, size int64) string {
 | 
						|
	if offset == 0 && size == 0 {
 | 
						|
		return ""
 | 
						|
	}
 | 
						|
	if size == 0 {
 | 
						|
		return fmt.Sprintf("%s%d-", byteRangePrefix, offset)
 | 
						|
	}
 | 
						|
	return fmt.Sprintf("%s%d-%d", byteRangePrefix, offset, offset+size-1)
 | 
						|
}
 | 
						|
 | 
						|
// AnonGetObject - performs a plain http GET request on a public resource,
 | 
						|
// fails if the resource is not public.
 | 
						|
func (l *b2Objects) AnonGetObject(bucket string, object string, startOffset int64, length int64, writer io.Writer) error {
 | 
						|
	uri := fmt.Sprintf("%s/file/%s/%s", l.b2Client.DownloadURI, bucket, object)
 | 
						|
	req, err := http.NewRequest("GET", uri, nil)
 | 
						|
	if err != nil {
 | 
						|
		return b2ToObjectError(traceError(err), bucket, object)
 | 
						|
	}
 | 
						|
	rng := mkRange(startOffset, length)
 | 
						|
	if rng != "" {
 | 
						|
		req.Header.Set("Range", rng)
 | 
						|
	}
 | 
						|
	resp, err := l.anonClient.Do(req)
 | 
						|
	if err != nil {
 | 
						|
		return b2ToObjectError(traceError(err), bucket, object)
 | 
						|
	}
 | 
						|
	defer resp.Body.Close()
 | 
						|
	if resp.StatusCode != http.StatusOK {
 | 
						|
		return b2ToObjectError(traceError(errors.New(resp.Status)), bucket, object)
 | 
						|
	}
 | 
						|
	_, err = io.Copy(writer, resp.Body)
 | 
						|
	return b2ToObjectError(traceError(err), bucket, object)
 | 
						|
}
 | 
						|
 | 
						|
// Converts http Header into ObjectInfo. This function looks for all the
 | 
						|
// standard Backblaze B2 headers to convert into ObjectInfo.
 | 
						|
//
 | 
						|
// Content-Length is converted to Size.
 | 
						|
// X-Bz-Upload-Timestamp is converted to ModTime.
 | 
						|
// X-Bz-Info-<header>:<value> is converted to <header>:<value>
 | 
						|
// Content-Type is converted to ContentType.
 | 
						|
// X-Bz-Content-Sha1 is converted to ETag.
 | 
						|
func headerToObjectInfo(bucket, object string, header http.Header) (objInfo ObjectInfo, err error) {
 | 
						|
	clen, err := strconv.ParseInt(header.Get("Content-Length"), 10, 64)
 | 
						|
	if err != nil {
 | 
						|
		return objInfo, b2ToObjectError(traceError(err), bucket, object)
 | 
						|
	}
 | 
						|
 | 
						|
	// Converting upload timestamp in milliseconds to a time.Time value for ObjectInfo.ModTime.
 | 
						|
	timeStamp, err := strconv.ParseInt(header.Get("X-Bz-Upload-Timestamp"), 10, 64)
 | 
						|
	if err != nil {
 | 
						|
		return objInfo, b2ToObjectError(traceError(err), bucket, object)
 | 
						|
	}
 | 
						|
 | 
						|
	// Populate user metadata by looking for all the X-Bz-Info-<name>
 | 
						|
	// HTTP headers, ignore other headers since they have their own
 | 
						|
	// designated meaning, for more details refer B2 API documentation.
 | 
						|
	userMetadata := make(map[string]string)
 | 
						|
	for key := range header {
 | 
						|
		if strings.HasPrefix(key, "X-Bz-Info-") {
 | 
						|
			var name string
 | 
						|
			name, err = url.QueryUnescape(strings.TrimPrefix(key, "X-Bz-Info-"))
 | 
						|
			if err != nil {
 | 
						|
				return objInfo, b2ToObjectError(traceError(err), bucket, object)
 | 
						|
			}
 | 
						|
			var val string
 | 
						|
			val, err = url.QueryUnescape(header.Get(key))
 | 
						|
			if err != nil {
 | 
						|
				return objInfo, b2ToObjectError(traceError(err), bucket, object)
 | 
						|
			}
 | 
						|
			userMetadata[name] = val
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return ObjectInfo{
 | 
						|
		Bucket:      bucket,
 | 
						|
		Name:        object,
 | 
						|
		ContentType: header.Get("Content-Type"),
 | 
						|
		ModTime:     time.Unix(0, 0).Add(time.Duration(timeStamp) * time.Millisecond),
 | 
						|
		Size:        clen,
 | 
						|
		ETag:        header.Get("X-Bz-File-Id"),
 | 
						|
		UserDefined: userMetadata,
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 | 
						|
// AnonGetObjectInfo - performs a plain http HEAD request on a public resource,
 | 
						|
// fails if the resource is not public.
 | 
						|
func (l *b2Objects) AnonGetObjectInfo(bucket string, object string) (objInfo ObjectInfo, err error) {
 | 
						|
	uri := fmt.Sprintf("%s/file/%s/%s", l.b2Client.DownloadURI, bucket, object)
 | 
						|
	req, err := http.NewRequest("HEAD", uri, nil)
 | 
						|
	if err != nil {
 | 
						|
		return objInfo, b2ToObjectError(traceError(err), bucket, object)
 | 
						|
	}
 | 
						|
	resp, err := l.anonClient.Do(req)
 | 
						|
	if err != nil {
 | 
						|
		return objInfo, b2ToObjectError(traceError(err), bucket, object)
 | 
						|
	}
 | 
						|
	defer resp.Body.Close()
 | 
						|
	if resp.StatusCode != http.StatusOK {
 | 
						|
		return objInfo, b2ToObjectError(traceError(errors.New(resp.Status)), bucket, object)
 | 
						|
	}
 | 
						|
	return headerToObjectInfo(bucket, object, resp.Header)
 | 
						|
}
 |