851 lines · 28.8 KB · Go
RawDownload
// Copyright (c) 2015-2021 MinIO, Inc.//// This file is part of MinIO Object Storage stack//// This program is free software: you can redistribute it and/or modify// it under the terms of the GNU Affero General Public License as published by// the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the// GNU Affero General Public License for more details.//// You should have received a copy of the GNU Affero General Public License// along with this program.  If not, see <http://www.gnu.org/licenses/>. package cmd import (	"context"	"encoding/base64"	"encoding/xml"	"fmt"	"net/http"	"net/url"	"path"	"strconv"	"strings"	"time" 	"github.com/minio/minio/internal/crypto"	"github.com/minio/minio/internal/handlers"	xhttp "github.com/minio/minio/internal/http"	"github.com/minio/minio/internal/logger") const (	// RFC3339 a subset of the ISO8601 timestamp format. e.g 2014-04-29T18:30:38Z	iso8601TimeFormat = "2006-01-02T15:04:05.000Z" // Reply date format with nanosecond precision.	maxObjectList     = 1000                       // Limit number of objects in a listObjectsResponse/listObjectsVersionsResponse.	maxDeleteList     = 1000                       // Limit number of objects deleted in a delete call.	maxUploadsList    = 10000                      // Limit number of uploads in a listUploadsResponse.	maxPartsList      = 10000                      // Limit number of parts in a listPartsResponse.) // 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"`} // PolicyStatus captures information returned by GetBucketPolicyStatusHandlertype PolicyStatus struct {	XMLName  xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ PolicyStatus" json:"-"`	IsPublic string} // ListVersionsResponse - format for list bucket versions response.type ListVersionsResponse struct {	XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListVersionsResult" json:"-"` 	Name      string	Prefix    string	KeyMarker 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.	NextKeyMarker string `xml:"NextKeyMarker,omitempty"` 	// When the number of responses exceeds the value of MaxKeys,	// NextVersionIdMarker specifies the first object version not	// returned that satisfies the search criteria. Use this value	// for the version-id-marker request parameter in a subsequent request.	NextVersionIDMarker string `xml:"NextVersionIdMarker"` 	// Marks the last version of the Key returned in a truncated response.	VersionIDMarker string `xml:"VersionIdMarker"` 	MaxKeys   int	Delimiter string	// A flag that indicates whether or not ListObjects returned all of the results	// that satisfied the search criteria.	IsTruncated bool 	CommonPrefixes []CommonPrefix	Versions       []ObjectVersion 	// Encoding type used to encode object keys in the response.	EncodingType string `xml:"EncodingType,omitempty"`} // ListObjectsResponse - format for list objects response.type ListObjectsResponse struct {	XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListBucketResult" json:"-"` 	Name   string	Prefix string	Marker 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 `xml:"NextMarker,omitempty"` 	MaxKeys   int	Delimiter string	// A flag that indicates whether or not ListObjects returned all of the results	// that satisfied the search criteria.	IsTruncated bool 	Contents       []Object	CommonPrefixes []CommonPrefix 	// Encoding type used to encode object keys in the response.	EncodingType string `xml:"EncodingType,omitempty"`} // ListObjectsV2Response - format for list objects response.type ListObjectsV2Response struct {	XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListBucketResult" json:"-"` 	Name       string	Prefix     string	StartAfter string `xml:"StartAfter,omitempty"`	// 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 `xml:"ContinuationToken,omitempty"`	NextContinuationToken string `xml:"NextContinuationToken,omitempty"` 	KeyCount  int	MaxKeys   int	Delimiter string	// A flag that indicates whether or not ListObjects returned all of the results	// that satisfied the search criteria.	IsTruncated bool 	Contents       []Object	CommonPrefixes []CommonPrefix 	// Encoding type used to encode object keys in the response.	EncodingType string `xml:"EncodingType,omitempty"`} // Part container for part metadata.type Part struct {	PartNumber   int	LastModified string	ETag         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"`	Delimiter          string	Prefix             string	EncodingType       string `xml:"EncodingType,omitempty"`	MaxUploads         int	IsTruncated        bool 	// List of pending uploads.	Uploads []Upload `xml:"Upload"` 	// Delimed common prefixes.	CommonPrefixes []CommonPrefix} // ListBucketsResponse - format for list buckets responsetype ListBucketsResponse struct {	XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListAllMyBucketsResult" json:"-"` 	Owner Owner 	// Container for one or more buckets.	Buckets struct {		Buckets []Bucket `xml:"Bucket"`	} // Buckets are nested} // Upload container for in progress multipart uploadtype Upload struct {	Key          string	UploadID     string `xml:"UploadId"`	Initiator    Initiator	Owner        Owner	StorageClass string	Initiated    string} // CommonPrefix container for prefix response in ListObjectsResponsetype CommonPrefix struct {	Prefix string} // Bucket container for bucket metadatatype Bucket struct {	Name         string	CreationDate string // time string of format "2006-01-02T15:04:05.000Z"} // ObjectVersion container for object version metadatatype ObjectVersion struct {	Object	IsLatest  bool	VersionID string `xml:"VersionId"` 	isDeleteMarker bool} // MarshalXML - marshal ObjectVersionfunc (o ObjectVersion) MarshalXML(e *xml.Encoder, start xml.StartElement) error {	if o.isDeleteMarker {		start.Name.Local = "DeleteMarker"	} else {		start.Name.Local = "Version"	} 	type objectVersionWrapper ObjectVersion	return e.EncodeElement(objectVersionWrapper(o), start)} // StringMap is a map[string]stringtype StringMap map[string]string // MarshalXML - StringMap marshals into XML.func (s StringMap) MarshalXML(e *xml.Encoder, start xml.StartElement) error {	tokens := []xml.Token{start} 	for key, value := range s {		t := xml.StartElement{}		t.Name = xml.Name{			Space: "",			Local: key,		}		tokens = append(tokens, t, xml.CharData(value), xml.EndElement{Name: t.Name})	} 	tokens = append(tokens, xml.EndElement{		Name: start.Name,	}) 	for _, t := range tokens {		if err := e.EncodeToken(t); err != nil {			return err		}	} 	// flush to ensure tokens are written	return e.Flush()} // Object container for object metadatatype Object struct {	Key          string	LastModified string // time string of format "2006-01-02T15:04:05.000Z"	ETag         string	Size         int64 	// Owner of the object.	Owner Owner 	// The class of storage used to store the object.	StorageClass string 	// UserMetadata user-defined metadata	UserMetadata StringMap `xml:"UserMetadata,omitempty"`} // CopyObjectResponse container returns ETag and LastModified of the successfully copied objecttype CopyObjectResponse struct {	XMLName      xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ CopyObjectResult" json:"-"`	LastModified string   // time string of format "2006-01-02T15:04:05.000Z"	ETag         string   // md5sum of the copied object.} // CopyObjectPartResponse container returns ETag and LastModified of the successfully copied objecttype CopyObjectPartResponse struct {	XMLName      xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ CopyPartResult" json:"-"`	LastModified string   // time string of format "2006-01-02T15:04:05.000Z"	ETag         string   // md5sum of the copied object part.} // Initiator inherit from Owner struct, fields are sametype Initiator Owner // Owner - bucket owner/principaltype Owner struct {	ID          string	DisplayName string} // InitiateMultipartUploadResponse container for InitiateMultiPartUpload response, provides uploadID to start MultiPart uploadtype 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 responsetype CompleteMultipartUploadResponse struct {	XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ CompleteMultipartUploadResult" json:"-"` 	Location string	Bucket   string	Key      string	ETag     string} // DeleteError structure.type DeleteError struct {	Code      string	Message   string	Key       string	VersionID string `xml:"VersionId"`} // 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 []DeletedObject `xml:"Deleted,omitempty"` 	// Collection of errors deleting certain objects.	Errors []DeleteError `xml:"Error,omitempty"`} // PostResponse container for POST object request when success_action_status is set to 201type PostResponse struct {	Bucket   string	Key      string	ETag     string	Location string} // returns "https" if the tls boolean is true, "http" otherwise.func getURLScheme(tls bool) string {	if tls {		return httpsScheme	}	return httpScheme} // getObjectLocation gets the fully qualified URL of an object.func getObjectLocation(r *http.Request, domains []string, bucket, object string) string {	// unit tests do not have host set.	if r.Host == "" {		return path.Clean(r.URL.Path)	}	proto := handlers.GetSourceScheme(r)	if proto == "" {		proto = getURLScheme(globalIsTLS)	}	u := &url.URL{		Host:   r.Host,		Path:   path.Join(SlashSeparator, bucket, object),		Scheme: proto,	}	// If domain is set then we need to use bucket DNS style.	for _, domain := range domains {		if strings.HasPrefix(r.Host, bucket+"."+domain) {			u.Path = path.Join(SlashSeparator, object)			break		}	}	return u.String()} // generates ListBucketsResponse from array of BucketInfo which can be// serialized to match XML and JSON API spec output.func generateListBucketsResponse(buckets []BucketInfo) ListBucketsResponse {	listbuckets := make([]Bucket, 0, len(buckets))	data := ListBucketsResponse{}	owner := Owner{		ID:          globalMinioDefaultOwnerID,		DisplayName: "minio",	} 	for _, bucket := range buckets {		listbuckets = append(listbuckets, Bucket{			Name:         bucket.Name,			CreationDate: bucket.Created.UTC().Format(iso8601TimeFormat),		})	} 	data.Owner = owner	data.Buckets.Buckets = listbuckets 	return data} // generates an ListBucketVersions response for the said bucket with other enumerated options.func generateListVersionsResponse(bucket, prefix, marker, versionIDMarker, delimiter, encodingType string, maxKeys int, resp ListObjectVersionsInfo) ListVersionsResponse {	versions := make([]ObjectVersion, 0, len(resp.Objects))	owner := Owner{		ID:          globalMinioDefaultOwnerID,		DisplayName: "minio",	}	data := ListVersionsResponse{} 	for _, object := range resp.Objects {		content := ObjectVersion{}		if object.Name == "" {			continue		}		content.Key = s3EncodeName(object.Name, encodingType)		content.LastModified = object.ModTime.UTC().Format(iso8601TimeFormat)		if object.ETag != "" {			content.ETag = "\"" + object.ETag + "\""		}		content.Size = object.Size		if object.StorageClass != "" {			content.StorageClass = object.StorageClass		} else {			content.StorageClass = globalMinioDefaultStorageClass		}		content.Owner = owner		content.VersionID = object.VersionID		if content.VersionID == "" {			content.VersionID = nullVersionID		}		content.IsLatest = object.IsLatest		content.isDeleteMarker = object.DeleteMarker		versions = append(versions, content)	} 	data.Name = bucket	data.Versions = versions	data.EncodingType = encodingType	data.Prefix = s3EncodeName(prefix, encodingType)	data.KeyMarker = s3EncodeName(marker, encodingType)	data.Delimiter = s3EncodeName(delimiter, encodingType)	data.MaxKeys = maxKeys 	data.NextKeyMarker = s3EncodeName(resp.NextMarker, encodingType)	data.NextVersionIDMarker = resp.NextVersionIDMarker	data.VersionIDMarker = versionIDMarker	data.IsTruncated = resp.IsTruncated 	prefixes := make([]CommonPrefix, 0, len(resp.Prefixes))	for _, prefix := range resp.Prefixes {		prefixItem := CommonPrefix{}		prefixItem.Prefix = s3EncodeName(prefix, encodingType)		prefixes = append(prefixes, prefixItem)	}	data.CommonPrefixes = prefixes	return data} // generates an ListObjectsV1 response for the said bucket with other enumerated options.func generateListObjectsV1Response(bucket, prefix, marker, delimiter, encodingType string, maxKeys int, resp ListObjectsInfo) ListObjectsResponse {	contents := make([]Object, 0, len(resp.Objects))	owner := Owner{		ID:          globalMinioDefaultOwnerID,

Lines 1–500 of 851.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t