| 
									
										
										
										
											2021-04-19 03:41:13 +08:00
										 |  |  | // 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/>.
 | 
					
						
							| 
									
										
										
										
											2015-02-24 08:46:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 07:23:42 +08:00
										 |  |  | package cmd | 
					
						
							| 
									
										
										
										
											2015-02-16 09:03:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2019-02-14 08:07:21 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2019-10-02 04:09:29 +08:00
										 |  |  | 	"encoding/base64" | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | 	"encoding/xml" | 
					
						
							| 
									
										
										
										
											2020-08-24 13:06:22 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2015-04-23 07:28:13 +08:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2017-01-06 16:37:00 +08:00
										 |  |  | 	"net/url" | 
					
						
							| 
									
										
										
										
											2016-06-21 14:25:18 +08:00
										 |  |  | 	"path" | 
					
						
							| 
									
										
										
										
											2019-06-12 12:04:52 +08:00
										 |  |  | 	"strconv" | 
					
						
							| 
									
										
										
										
											2018-05-16 09:20:22 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2016-02-27 19:04:52 +08:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2018-03-03 07:23:04 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-13 02:28:30 +08:00
										 |  |  | 	"github.com/minio/minio/internal/amztime" | 
					
						
							| 
									
										
										
										
											2021-09-01 08:18:13 +08:00
										 |  |  | 	"github.com/minio/minio/internal/crypto" | 
					
						
							| 
									
										
										
										
											2021-06-02 05:59:40 +08:00
										 |  |  | 	"github.com/minio/minio/internal/handlers" | 
					
						
							| 
									
										
										
										
											2022-08-30 07:57:16 +08:00
										 |  |  | 	"github.com/minio/minio/internal/hash" | 
					
						
							| 
									
										
										
										
											2021-06-02 05:59:40 +08:00
										 |  |  | 	xhttp "github.com/minio/minio/internal/http" | 
					
						
							|  |  |  | 	"github.com/minio/minio/internal/logger" | 
					
						
							| 
									
										
										
										
											2024-05-25 07:05:23 +08:00
										 |  |  | 	"github.com/minio/pkg/v3/policy" | 
					
						
							| 
									
										
										
										
											2022-10-08 07:12:36 +08:00
										 |  |  | 	xxml "github.com/minio/xxml" | 
					
						
							| 
									
										
										
										
											2015-02-16 09:03:27 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-24 08:46:48 +08:00
										 |  |  | const ( | 
					
						
							| 
									
										
										
										
											2022-12-13 02:28:30 +08:00
										 |  |  | 	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.
 | 
					
						
							| 
									
										
										
										
											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"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-02 15:10:33 +08:00
										 |  |  | // PolicyStatus captures information returned by GetBucketPolicyStatusHandler
 | 
					
						
							|  |  |  | type PolicyStatus struct { | 
					
						
							|  |  |  | 	XMLName  xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ PolicyStatus" json:"-"` | 
					
						
							|  |  |  | 	IsPublic string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-20 05:02:54 +08:00
										 |  |  | // 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 | 
					
						
							| 
									
										
										
										
											2023-06-07 12:31:47 +08:00
										 |  |  | 	Delimiter string `xml:"Delimiter,omitempty"` | 
					
						
							| 
									
										
										
										
											2019-08-20 05:02:54 +08:00
										 |  |  | 	// A flag that indicates whether or not ListObjects returned all of the results
 | 
					
						
							|  |  |  | 	// that satisfied the search criteria.
 | 
					
						
							|  |  |  | 	IsTruncated bool | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	CommonPrefixes []CommonPrefix | 
					
						
							| 
									
										
										
										
											2022-10-08 07:12:36 +08:00
										 |  |  | 	Versions       []ObjectVersion | 
					
						
							| 
									
										
										
										
											2019-08-20 05:02:54 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Encoding type used to encode object keys in the response.
 | 
					
						
							|  |  |  | 	EncodingType string `xml:"EncodingType,omitempty"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | // ListObjectsResponse - format for list objects response.
 | 
					
						
							|  |  |  | type ListObjectsResponse struct { | 
					
						
							|  |  |  | 	XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListBucketResult" json:"-"` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 11:12:47 +08:00
										 |  |  | 	Name   string | 
					
						
							|  |  |  | 	Prefix string | 
					
						
							|  |  |  | 	Marker string | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// 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.
 | 
					
						
							| 
									
										
										
										
											2016-10-06 11:12:47 +08:00
										 |  |  | 	NextMarker string `xml:"NextMarker,omitempty"` | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 11:12:47 +08:00
										 |  |  | 	MaxKeys   int | 
					
						
							| 
									
										
										
										
											2023-06-07 12:31:47 +08:00
										 |  |  | 	Delimiter string `xml:"Delimiter,omitempty"` | 
					
						
							| 
									
										
										
										
											2016-10-06 11:12:47 +08:00
										 |  |  | 	// A flag that indicates whether or not ListObjects returned all of the results
 | 
					
						
							|  |  |  | 	// that satisfied the search criteria.
 | 
					
						
							|  |  |  | 	IsTruncated bool | 
					
						
							| 
									
										
										
										
											2016-06-01 13:10:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	Contents       []Object | 
					
						
							| 
									
										
										
										
											2016-10-06 11:12:47 +08:00
										 |  |  | 	CommonPrefixes []CommonPrefix | 
					
						
							| 
									
										
										
										
											2016-06-01 13:10:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Encoding type used to encode object keys in the response.
 | 
					
						
							| 
									
										
										
										
											2016-10-06 11:12:47 +08:00
										 |  |  | 	EncodingType string `xml:"EncodingType,omitempty"` | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-06-01 13:10:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 11:12:47 +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:"-"` | 
					
						
							| 
									
										
										
										
											2016-06-01 13:10:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 11:12:47 +08:00
										 |  |  | 	Name       string | 
					
						
							|  |  |  | 	Prefix     string | 
					
						
							|  |  |  | 	StartAfter string `xml:"StartAfter,omitempty"` | 
					
						
							| 
									
										
										
										
											2016-06-01 13:10:55 +08:00
										 |  |  | 	// 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.
 | 
					
						
							| 
									
										
										
										
											2016-10-06 11:12:47 +08:00
										 |  |  | 	ContinuationToken     string `xml:"ContinuationToken,omitempty"` | 
					
						
							|  |  |  | 	NextContinuationToken string `xml:"NextContinuationToken,omitempty"` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	KeyCount  int | 
					
						
							|  |  |  | 	MaxKeys   int | 
					
						
							| 
									
										
										
										
											2023-06-07 12:31:47 +08:00
										 |  |  | 	Delimiter string `xml:"Delimiter,omitempty"` | 
					
						
							| 
									
										
										
										
											2016-10-06 11:12:47 +08:00
										 |  |  | 	// 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"` | 
					
						
							| 
									
										
										
										
											2016-06-01 13:10:55 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | // Part container for part metadata.
 | 
					
						
							|  |  |  | type Part struct { | 
					
						
							|  |  |  | 	PartNumber   int | 
					
						
							|  |  |  | 	LastModified string | 
					
						
							| 
									
										
										
										
											2016-10-06 11:12:47 +08:00
										 |  |  | 	ETag         string | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | 	Size         int64 | 
					
						
							| 
									
										
										
										
											2022-08-30 07:57:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Checksum values
 | 
					
						
							| 
									
										
										
										
											2022-10-13 15:49:46 +08:00
										 |  |  | 	ChecksumCRC32  string `xml:"ChecksumCRC32,omitempty"` | 
					
						
							|  |  |  | 	ChecksumCRC32C string `xml:"ChecksumCRC32C,omitempty"` | 
					
						
							|  |  |  | 	ChecksumSHA1   string `xml:"ChecksumSHA1,omitempty"` | 
					
						
							|  |  |  | 	ChecksumSHA256 string `xml:"ChecksumSHA256,omitempty"` | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-30 07:57:16 +08:00
										 |  |  | 	ChecksumAlgorithm string | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | 	// 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"` | 
					
						
							| 
									
										
										
										
											2023-06-07 12:31:47 +08:00
										 |  |  | 	Delimiter          string `xml:"Delimiter,omitempty"` | 
					
						
							| 
									
										
										
										
											2016-10-06 11:12:47 +08:00
										 |  |  | 	Prefix             string | 
					
						
							|  |  |  | 	EncodingType       string `xml:"EncodingType,omitempty"` | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | 	MaxUploads         int | 
					
						
							|  |  |  | 	IsTruncated        bool | 
					
						
							| 
									
										
										
										
											2016-10-06 11:12:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// List of pending uploads.
 | 
					
						
							|  |  |  | 	Uploads []Upload `xml:"Upload"` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Delimed common prefixes.
 | 
					
						
							|  |  |  | 	CommonPrefixes []CommonPrefix | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ListBucketsResponse - format for list buckets response
 | 
					
						
							|  |  |  | type ListBucketsResponse struct { | 
					
						
							|  |  |  | 	XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListAllMyBucketsResult" json:"-"` | 
					
						
							| 
									
										
										
										
											2016-10-06 11:12:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	Owner Owner | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | 	// Container for one or more buckets.
 | 
					
						
							|  |  |  | 	Buckets struct { | 
					
						
							|  |  |  | 		Buckets []Bucket `xml:"Bucket"` | 
					
						
							|  |  |  | 	} // Buckets are nested
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Upload container for in progress multipart upload
 | 
					
						
							|  |  |  | type Upload struct { | 
					
						
							| 
									
										
										
										
											2018-01-23 06:54:55 +08:00
										 |  |  | 	Key          string | 
					
						
							|  |  |  | 	UploadID     string `xml:"UploadId"` | 
					
						
							|  |  |  | 	Initiator    Initiator | 
					
						
							|  |  |  | 	Owner        Owner | 
					
						
							|  |  |  | 	StorageClass string | 
					
						
							|  |  |  | 	Initiated    string | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // CommonPrefix container for prefix response in ListObjectsResponse
 | 
					
						
							|  |  |  | type CommonPrefix struct { | 
					
						
							|  |  |  | 	Prefix string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Bucket container for bucket metadata
 | 
					
						
							|  |  |  | type Bucket struct { | 
					
						
							| 
									
										
										
										
											2018-01-23 06:54:55 +08:00
										 |  |  | 	Name         string | 
					
						
							|  |  |  | 	CreationDate string // time string of format "2006-01-02T15:04:05.000Z"
 | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-20 05:02:54 +08:00
										 |  |  | // ObjectVersion container for object version metadata
 | 
					
						
							|  |  |  | type ObjectVersion struct { | 
					
						
							|  |  |  | 	Object | 
					
						
							|  |  |  | 	IsLatest  bool | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	VersionID string `xml:"VersionId"` | 
					
						
							| 
									
										
										
										
											2022-10-08 07:12:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	isDeleteMarker bool | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // MarshalXML - marshal ObjectVersion
 | 
					
						
							|  |  |  | func (o ObjectVersion) MarshalXML(e *xxml.Encoder, start xxml.StartElement) error { | 
					
						
							|  |  |  | 	if o.isDeleteMarker { | 
					
						
							|  |  |  | 		start.Name.Local = "DeleteMarker" | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		start.Name.Local = "Version" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	type objectVersionWrapper ObjectVersion | 
					
						
							|  |  |  | 	return e.EncodeElement(objectVersionWrapper(o), start) | 
					
						
							| 
									
										
										
										
											2022-08-24 08:04:11 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // DeleteMarkerVersion container for delete marker metadata
 | 
					
						
							|  |  |  | type DeleteMarkerVersion struct { | 
					
						
							|  |  |  | 	Key          string | 
					
						
							|  |  |  | 	LastModified string // time string of format "2006-01-02T15:04:05.000Z"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Owner of the object.
 | 
					
						
							|  |  |  | 	Owner Owner | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-24 08:04:11 +08:00
										 |  |  | 	IsLatest  bool | 
					
						
							|  |  |  | 	VersionID string `xml:"VersionId"` | 
					
						
							| 
									
										
										
										
											2020-07-04 00:15:44 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-24 08:04:11 +08:00
										 |  |  | // Metadata metadata items implemented to ensure XML marshaling works.
 | 
					
						
							|  |  |  | type Metadata struct { | 
					
						
							|  |  |  | 	Items []struct { | 
					
						
							|  |  |  | 		Key   string | 
					
						
							|  |  |  | 		Value string | 
					
						
							| 
									
										
										
										
											2020-07-04 00:15:44 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-08-24 08:04:11 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-24 08:04:11 +08:00
										 |  |  | // Set add items, duplicate items get replaced.
 | 
					
						
							|  |  |  | func (s *Metadata) Set(k, v string) { | 
					
						
							|  |  |  | 	for i, item := range s.Items { | 
					
						
							|  |  |  | 		if item.Key == k { | 
					
						
							|  |  |  | 			s.Items[i] = struct { | 
					
						
							|  |  |  | 				Key   string | 
					
						
							|  |  |  | 				Value string | 
					
						
							|  |  |  | 			}{ | 
					
						
							|  |  |  | 				Key:   k, | 
					
						
							|  |  |  | 				Value: v, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	s.Items = append(s.Items, struct { | 
					
						
							|  |  |  | 		Key   string | 
					
						
							|  |  |  | 		Value string | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		Key:   k, | 
					
						
							|  |  |  | 		Value: v, | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2019-08-20 05:02:54 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-24 08:04:11 +08:00
										 |  |  | type xmlKeyEntry struct { | 
					
						
							| 
									
										
										
										
											2023-01-17 07:38:33 +08:00
										 |  |  | 	XMLName xxml.Name | 
					
						
							| 
									
										
										
										
											2022-08-24 08:04:11 +08:00
										 |  |  | 	Value   string `xml:",chardata"` | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-11-21 17:54:49 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // MarshalXML - StringMap marshals into XML.
 | 
					
						
							| 
									
										
										
										
											2023-01-17 07:38:33 +08:00
										 |  |  | func (s *Metadata) MarshalXML(e *xxml.Encoder, start xxml.StartElement) error { | 
					
						
							| 
									
										
										
										
											2022-08-24 08:04:11 +08:00
										 |  |  | 	if s == nil { | 
					
						
							|  |  |  | 		return nil | 
					
						
							| 
									
										
										
										
											2019-11-21 17:54:49 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-24 08:04:11 +08:00
										 |  |  | 	if len(s.Items) == 0 { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-11-21 17:54:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-24 08:04:11 +08:00
										 |  |  | 	if err := e.EncodeToken(start); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, item := range s.Items { | 
					
						
							|  |  |  | 		if err := e.Encode(xmlKeyEntry{ | 
					
						
							| 
									
										
										
										
											2023-01-17 07:38:33 +08:00
										 |  |  | 			XMLName: xxml.Name{Local: item.Key}, | 
					
						
							| 
									
										
										
										
											2022-08-24 08:04:11 +08:00
										 |  |  | 			Value:   item.Value, | 
					
						
							|  |  |  | 		}); err != nil { | 
					
						
							| 
									
										
										
										
											2019-11-21 17:54:49 +08:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-24 08:04:11 +08:00
										 |  |  | 	return e.EncodeToken(start.End()) | 
					
						
							| 
									
										
										
										
											2019-11-21 17:54:49 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-20 00:42:45 +08:00
										 |  |  | // ObjectInternalInfo contains some internal information about a given
 | 
					
						
							|  |  |  | // object, it will printed in listing calls with enabled metadata.
 | 
					
						
							|  |  |  | type ObjectInternalInfo struct { | 
					
						
							|  |  |  | 	K int // Data blocks
 | 
					
						
							|  |  |  | 	M int // Parity blocks
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | // Object container for object metadata
 | 
					
						
							|  |  |  | type Object struct { | 
					
						
							|  |  |  | 	Key          string | 
					
						
							|  |  |  | 	LastModified string // time string of format "2006-01-02T15:04:05.000Z"
 | 
					
						
							| 
									
										
										
										
											2016-10-06 11:12:47 +08:00
										 |  |  | 	ETag         string | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | 	Size         int64 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 11:12:47 +08:00
										 |  |  | 	// Owner of the object.
 | 
					
						
							| 
									
										
										
										
											2023-06-07 12:31:47 +08:00
										 |  |  | 	Owner *Owner `xml:"Owner,omitempty"` | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// The class of storage used to store the object.
 | 
					
						
							| 
									
										
										
										
											2018-01-23 06:54:55 +08:00
										 |  |  | 	StorageClass string | 
					
						
							| 
									
										
										
										
											2019-11-21 17:54:49 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// UserMetadata user-defined metadata
 | 
					
						
							| 
									
										
										
										
											2022-08-24 08:04:11 +08:00
										 |  |  | 	UserMetadata *Metadata `xml:"UserMetadata,omitempty"` | 
					
						
							| 
									
										
										
										
											2023-03-24 01:27:19 +08:00
										 |  |  | 	UserTags     string    `xml:"UserTags,omitempty"` | 
					
						
							| 
									
										
										
										
											2023-05-20 00:42:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	Internal *ObjectInternalInfo `xml:"Internal,omitempty"` | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 11:12:47 +08:00
										 |  |  | // CopyObjectResponse container returns ETag and LastModified of the successfully copied object
 | 
					
						
							| 
									
										
										
										
											2016-02-27 19:04:52 +08:00
										 |  |  | type CopyObjectResponse struct { | 
					
						
							|  |  |  | 	XMLName      xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ CopyObjectResult" json:"-"` | 
					
						
							| 
									
										
										
										
											2016-10-06 11:12:47 +08:00
										 |  |  | 	LastModified string   // time string of format "2006-01-02T15:04:05.000Z"
 | 
					
						
							|  |  |  | 	ETag         string   // md5sum of the copied object.
 | 
					
						
							| 
									
										
										
										
											2016-02-27 19:04:52 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-01 01:38:34 +08:00
										 |  |  | // CopyObjectPartResponse container returns ETag and LastModified of the successfully copied object
 | 
					
						
							|  |  |  | type 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.
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2022-08-30 07:57:16 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-13 15:49:46 +08:00
										 |  |  | 	ChecksumCRC32  string `xml:"ChecksumCRC32,omitempty"` | 
					
						
							|  |  |  | 	ChecksumCRC32C string `xml:"ChecksumCRC32C,omitempty"` | 
					
						
							|  |  |  | 	ChecksumSHA1   string `xml:"ChecksumSHA1,omitempty"` | 
					
						
							|  |  |  | 	ChecksumSHA256 string `xml:"ChecksumSHA256,omitempty"` | 
					
						
							| 
									
										
										
										
											2016-05-05 06:24:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-06 08:43:48 +08:00
										 |  |  | // DeleteError structure.
 | 
					
						
							|  |  |  | type DeleteError struct { | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	Code      string | 
					
						
							|  |  |  | 	Message   string | 
					
						
							|  |  |  | 	Key       string | 
					
						
							|  |  |  | 	VersionID string `xml:"VersionId"` | 
					
						
							| 
									
										
										
										
											2016-03-06 08:43:48 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	DeletedObjects []DeletedObject `xml:"Deleted,omitempty"` | 
					
						
							| 
									
										
										
										
											2016-03-06 08:43:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Collection of errors deleting certain objects.
 | 
					
						
							|  |  |  | 	Errors []DeleteError `xml:"Error,omitempty"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-19 05:39:56 +08:00
										 |  |  | // PostResponse container for POST object request when success_action_status is set to 201
 | 
					
						
							|  |  |  | type PostResponse struct { | 
					
						
							|  |  |  | 	Bucket   string | 
					
						
							|  |  |  | 	Key      string | 
					
						
							|  |  |  | 	ETag     string | 
					
						
							|  |  |  | 	Location string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-25 07:43:21 +08:00
										 |  |  | // 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.
 | 
					
						
							| 
									
										
										
										
											2019-02-23 11:18:01 +08:00
										 |  |  | func getObjectLocation(r *http.Request, domains []string, bucket, object string) string { | 
					
						
							| 
									
										
										
										
											2018-03-24 04:46:57 +08:00
										 |  |  | 	// unit tests do not have host set.
 | 
					
						
							|  |  |  | 	if r.Host == "" { | 
					
						
							|  |  |  | 		return path.Clean(r.URL.Path) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-03 07:23:04 +08:00
										 |  |  | 	proto := handlers.GetSourceScheme(r) | 
					
						
							| 
									
										
										
										
											2017-09-25 07:43:21 +08:00
										 |  |  | 	if proto == "" { | 
					
						
							| 
									
										
										
										
											2020-12-22 13:42:38 +08:00
										 |  |  | 		proto = getURLScheme(globalIsTLS) | 
					
						
							| 
									
										
										
										
											2017-09-25 07:43:21 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-03 07:23:04 +08:00
										 |  |  | 	u := &url.URL{ | 
					
						
							|  |  |  | 		Host:   r.Host, | 
					
						
							| 
									
										
										
										
											2019-08-07 03:08:58 +08:00
										 |  |  | 		Path:   path.Join(SlashSeparator, bucket, object), | 
					
						
							| 
									
										
										
										
											2017-09-25 07:43:21 +08:00
										 |  |  | 		Scheme: proto, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-03 07:23:04 +08:00
										 |  |  | 	// If domain is set then we need to use bucket DNS style.
 | 
					
						
							| 
									
										
										
										
											2019-02-23 11:18:01 +08:00
										 |  |  | 	for _, domain := range domains { | 
					
						
							| 
									
										
										
										
											2020-07-17 04:28:29 +08:00
										 |  |  | 		if strings.HasPrefix(r.Host, bucket+"."+domain) { | 
					
						
							| 
									
										
										
										
											2019-08-07 03:08:58 +08:00
										 |  |  | 			u.Path = path.Join(SlashSeparator, object) | 
					
						
							| 
									
										
										
										
											2019-02-23 11:18:01 +08:00
										 |  |  | 			break | 
					
						
							| 
									
										
										
										
											2018-05-16 09:20:22 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-03-03 07:23:04 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-09-25 07:43:21 +08:00
										 |  |  | 	return u.String() | 
					
						
							| 
									
										
										
										
											2016-05-05 06:24:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-22 05:51:05 +08:00
										 |  |  | // generates ListBucketsResponse from array of BucketInfo which 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 { | 
					
						
							| 
									
										
										
										
											2020-09-15 11:44:18 +08:00
										 |  |  | 	listbuckets := make([]Bucket, 0, len(buckets)) | 
					
						
							| 
									
										
										
										
											2022-01-03 01:15:06 +08:00
										 |  |  | 	data := ListBucketsResponse{} | 
					
						
							|  |  |  | 	owner := Owner{ | 
					
						
							| 
									
										
										
										
											2021-03-10 04:58:22 +08:00
										 |  |  | 		ID:          globalMinioDefaultOwnerID, | 
					
						
							|  |  |  | 		DisplayName: "minio", | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-16 09:03:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for _, bucket := range buckets { | 
					
						
							| 
									
										
										
										
											2021-09-17 00:52:41 +08:00
										 |  |  | 		listbuckets = append(listbuckets, Bucket{ | 
					
						
							|  |  |  | 			Name:         bucket.Name, | 
					
						
							| 
									
										
										
										
											2022-12-13 02:28:30 +08:00
										 |  |  | 			CreationDate: amztime.ISO8601Format(bucket.Created.UTC()), | 
					
						
							| 
									
										
										
										
											2021-09-17 00:52:41 +08:00
										 |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2015-02-16 09:03:27 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-23 05:46:17 +08:00
										 |  |  | func cleanReservedKeys(metadata map[string]string) map[string]string { | 
					
						
							|  |  |  | 	m := cloneMSS(metadata) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch kind, _ := crypto.IsEncrypted(metadata); kind { | 
					
						
							|  |  |  | 	case crypto.S3: | 
					
						
							|  |  |  | 		m[xhttp.AmzServerSideEncryption] = xhttp.AmzEncryptionAES | 
					
						
							|  |  |  | 	case crypto.S3KMS: | 
					
						
							|  |  |  | 		m[xhttp.AmzServerSideEncryption] = xhttp.AmzEncryptionKMS | 
					
						
							|  |  |  | 		m[xhttp.AmzServerSideEncryptionKmsID] = kmsKeyIDFromMetadata(metadata) | 
					
						
							|  |  |  | 		if kmsCtx, ok := metadata[crypto.MetaContext]; ok { | 
					
						
							|  |  |  | 			m[xhttp.AmzServerSideEncryptionKmsContext] = kmsCtx | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case crypto.SSEC: | 
					
						
							|  |  |  | 		m[xhttp.AmzServerSideEncryptionCustomerAlgorithm] = xhttp.AmzEncryptionAES | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var toRemove []string | 
					
						
							|  |  |  | 	for k := range cleanMinioInternalMetadataKeys(m) { | 
					
						
							|  |  |  | 		if stringsHasPrefixFold(k, ReservedMetadataPrefixLower) { | 
					
						
							|  |  |  | 			// Do not need to send any internal metadata
 | 
					
						
							|  |  |  | 			// values to client.
 | 
					
						
							|  |  |  | 			toRemove = append(toRemove, k) | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// https://github.com/google/security-research/security/advisories/GHSA-76wf-9vgp-pj7w
 | 
					
						
							|  |  |  | 		if equals(k, xhttp.AmzMetaUnencryptedContentLength, xhttp.AmzMetaUnencryptedContentMD5) { | 
					
						
							|  |  |  | 			toRemove = append(toRemove, k) | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, k := range toRemove { | 
					
						
							|  |  |  | 		delete(m, k) | 
					
						
							|  |  |  | 		delete(m, strings.ToLower(k)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return m | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-20 05:02:54 +08:00
										 |  |  | // generates an ListBucketVersions response for the said bucket with other enumerated options.
 | 
					
						
							| 
									
										
										
										
											2024-05-16 02:04:16 +08:00
										 |  |  | func generateListVersionsResponse(ctx context.Context, bucket, prefix, marker, versionIDMarker, delimiter, encodingType string, maxKeys int, resp ListObjectVersionsInfo, metadata metaCheckFn) ListVersionsResponse { | 
					
						
							| 
									
										
										
										
											2020-09-15 11:44:18 +08:00
										 |  |  | 	versions := make([]ObjectVersion, 0, len(resp.Objects)) | 
					
						
							| 
									
										
										
										
											2022-08-24 08:04:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-07 12:31:47 +08:00
										 |  |  | 	owner := &Owner{ | 
					
						
							| 
									
										
										
										
											2021-03-10 04:58:22 +08:00
										 |  |  | 		ID:          globalMinioDefaultOwnerID, | 
					
						
							|  |  |  | 		DisplayName: "minio", | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-01-03 01:15:06 +08:00
										 |  |  | 	data := ListVersionsResponse{} | 
					
						
							| 
									
										
										
										
											2023-04-06 22:52:35 +08:00
										 |  |  | 	var lastObjMetaName string | 
					
						
							|  |  |  | 	var tagErr, metaErr APIErrorCode = -1, -1 | 
					
						
							| 
									
										
										
										
											2019-08-20 05:02:54 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for _, object := range resp.Objects { | 
					
						
							|  |  |  | 		if object.Name == "" { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-04-06 22:52:35 +08:00
										 |  |  | 		// Cache checks for the same object
 | 
					
						
							|  |  |  | 		if metadata != nil && lastObjMetaName != object.Name { | 
					
						
							|  |  |  | 			tagErr = metadata(object.Name, policy.GetObjectTaggingAction) | 
					
						
							|  |  |  | 			metaErr = metadata(object.Name, policy.GetObjectAction) | 
					
						
							|  |  |  | 			lastObjMetaName = object.Name | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-08-24 08:04:11 +08:00
										 |  |  | 		content := ObjectVersion{} | 
					
						
							| 
									
										
										
										
											2019-08-20 05:02:54 +08:00
										 |  |  | 		content.Key = s3EncodeName(object.Name, encodingType) | 
					
						
							| 
									
										
										
										
											2022-12-13 02:28:30 +08:00
										 |  |  | 		content.LastModified = amztime.ISO8601Format(object.ModTime.UTC()) | 
					
						
							| 
									
										
										
										
											2019-08-20 05:02:54 +08:00
										 |  |  | 		if object.ETag != "" { | 
					
						
							|  |  |  | 			content.ETag = "\"" + object.ETag + "\"" | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		content.Size = object.Size | 
					
						
							| 
									
										
										
										
											2020-04-02 15:23:09 +08:00
										 |  |  | 		if object.StorageClass != "" { | 
					
						
							| 
									
										
										
										
											2024-05-16 02:04:16 +08:00
										 |  |  | 			content.StorageClass = filterStorageClass(ctx, object.StorageClass) | 
					
						
							| 
									
										
										
										
											2020-04-02 15:23:09 +08:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			content.StorageClass = globalMinioDefaultStorageClass | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-04-06 22:52:35 +08:00
										 |  |  | 		if tagErr == ErrNone { | 
					
						
							| 
									
										
										
										
											2023-03-31 03:20:42 +08:00
										 |  |  | 			content.UserTags = object.UserTags | 
					
						
							| 
									
										
										
										
											2023-04-06 22:52:35 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if metaErr == ErrNone { | 
					
						
							| 
									
										
										
										
											2023-03-31 03:20:42 +08:00
										 |  |  | 			content.UserMetadata = &Metadata{} | 
					
						
							|  |  |  | 			switch kind, _ := crypto.IsEncrypted(object.UserDefined); kind { | 
					
						
							|  |  |  | 			case crypto.S3: | 
					
						
							|  |  |  | 				content.UserMetadata.Set(xhttp.AmzServerSideEncryption, xhttp.AmzEncryptionAES) | 
					
						
							|  |  |  | 			case crypto.S3KMS: | 
					
						
							|  |  |  | 				content.UserMetadata.Set(xhttp.AmzServerSideEncryption, xhttp.AmzEncryptionKMS) | 
					
						
							|  |  |  | 			case crypto.SSEC: | 
					
						
							|  |  |  | 				content.UserMetadata.Set(xhttp.AmzServerSideEncryptionCustomerAlgorithm, xhttp.AmzEncryptionAES) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-11-23 05:46:17 +08:00
										 |  |  | 			for k, v := range cleanReservedKeys(object.UserDefined) { | 
					
						
							| 
									
										
										
										
											2023-03-31 03:20:42 +08:00
										 |  |  | 				content.UserMetadata.Set(k, v) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-05-20 00:42:45 +08:00
										 |  |  | 			content.Internal = &ObjectInternalInfo{ | 
					
						
							|  |  |  | 				K: object.DataBlocks, | 
					
						
							|  |  |  | 				M: object.ParityBlocks, | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-03-31 03:20:42 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-08-20 05:02:54 +08:00
										 |  |  | 		content.Owner = owner | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 		content.VersionID = object.VersionID | 
					
						
							|  |  |  | 		if content.VersionID == "" { | 
					
						
							|  |  |  | 			content.VersionID = nullVersionID | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		content.IsLatest = object.IsLatest | 
					
						
							| 
									
										
										
										
											2022-10-08 07:12:36 +08:00
										 |  |  | 		content.isDeleteMarker = object.DeleteMarker | 
					
						
							| 
									
										
										
										
											2019-08-20 05:02:54 +08:00
										 |  |  | 		versions = append(versions, content) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-05-26 07:51:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-20 05:02:54 +08:00
										 |  |  | 	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) | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	data.NextVersionIDMarker = resp.NextVersionIDMarker | 
					
						
							|  |  |  | 	data.VersionIDMarker = versionIDMarker | 
					
						
							| 
									
										
										
										
											2019-08-20 05:02:54 +08:00
										 |  |  | 	data.IsTruncated = resp.IsTruncated | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-15 11:44:18 +08:00
										 |  |  | 	prefixes := make([]CommonPrefix, 0, len(resp.Prefixes)) | 
					
						
							| 
									
										
										
										
											2019-08-20 05:02:54 +08:00
										 |  |  | 	for _, prefix := range resp.Prefixes { | 
					
						
							| 
									
										
										
										
											2022-01-03 01:15:06 +08:00
										 |  |  | 		prefixItem := CommonPrefix{} | 
					
						
							| 
									
										
										
										
											2019-08-20 05:02:54 +08:00
										 |  |  | 		prefixItem.Prefix = s3EncodeName(prefix, encodingType) | 
					
						
							|  |  |  | 		prefixes = append(prefixes, prefixItem) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	data.CommonPrefixes = prefixes | 
					
						
							|  |  |  | 	return data | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-18 03:32:05 +08:00
										 |  |  | // generates an ListObjectsV1 response for the said bucket with other enumerated options.
 | 
					
						
							| 
									
										
										
										
											2024-05-16 02:04:16 +08:00
										 |  |  | func generateListObjectsV1Response(ctx context.Context, bucket, prefix, marker, delimiter, encodingType string, maxKeys int, resp ListObjectsInfo) ListObjectsResponse { | 
					
						
							| 
									
										
										
										
											2020-09-15 11:44:18 +08:00
										 |  |  | 	contents := make([]Object, 0, len(resp.Objects)) | 
					
						
							| 
									
										
										
										
											2023-06-07 12:31:47 +08:00
										 |  |  | 	owner := &Owner{ | 
					
						
							| 
									
										
										
										
											2021-03-10 04:58:22 +08:00
										 |  |  | 		ID:          globalMinioDefaultOwnerID, | 
					
						
							|  |  |  | 		DisplayName: "minio", | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-01-03 01:15:06 +08:00
										 |  |  | 	data := ListObjectsResponse{} | 
					
						
							| 
									
										
										
										
											2015-02-16 09:03:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 	for _, object := range resp.Objects { | 
					
						
							| 
									
										
										
										
											2022-01-03 01:15:06 +08:00
										 |  |  | 		content := Object{} | 
					
						
							| 
									
										
										
										
											2016-03-12 08:31:24 +08:00
										 |  |  | 		if object.Name == "" { | 
					
						
							| 
									
										
										
										
											2015-03-01 06:44:26 +08:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-02-24 14:14:24 +08:00
										 |  |  | 		content.Key = s3EncodeName(object.Name, encodingType) | 
					
						
							| 
									
										
										
										
											2022-12-13 02:28:30 +08:00
										 |  |  | 		content.LastModified = amztime.ISO8601Format(object.ModTime.UTC()) | 
					
						
							| 
									
										
										
										
											2017-05-15 03:05:51 +08:00
										 |  |  | 		if object.ETag != "" { | 
					
						
							|  |  |  | 			content.ETag = "\"" + object.ETag + "\"" | 
					
						
							| 
									
										
										
										
											2016-02-02 04:19:54 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-02-16 09:03:27 +08:00
										 |  |  | 		content.Size = object.Size | 
					
						
							| 
									
										
										
										
											2020-04-02 15:23:09 +08:00
										 |  |  | 		if object.StorageClass != "" { | 
					
						
							| 
									
										
										
										
											2024-05-16 02:04:16 +08:00
										 |  |  | 			content.StorageClass = filterStorageClass(ctx, object.StorageClass) | 
					
						
							| 
									
										
										
										
											2020-04-02 15:23:09 +08:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			content.StorageClass = globalMinioDefaultStorageClass | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-02-16 09:03:27 +08:00
										 |  |  | 		content.Owner = owner | 
					
						
							|  |  |  | 		contents = append(contents, content) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	data.Name = bucket | 
					
						
							|  |  |  | 	data.Contents = contents | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-24 14:14:24 +08:00
										 |  |  | 	data.EncodingType = encodingType | 
					
						
							|  |  |  | 	data.Prefix = s3EncodeName(prefix, encodingType) | 
					
						
							|  |  |  | 	data.Marker = s3EncodeName(marker, encodingType) | 
					
						
							|  |  |  | 	data.Delimiter = s3EncodeName(delimiter, encodingType) | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 	data.MaxKeys = maxKeys | 
					
						
							| 
									
										
										
										
											2019-02-24 14:14:24 +08:00
										 |  |  | 	data.NextMarker = s3EncodeName(resp.NextMarker, encodingType) | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 	data.IsTruncated = resp.IsTruncated | 
					
						
							| 
									
										
										
										
											2020-09-15 11:44:18 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	prefixes := make([]CommonPrefix, 0, len(resp.Prefixes)) | 
					
						
							| 
									
										
										
										
											2016-06-01 13:10:55 +08:00
										 |  |  | 	for _, prefix := range resp.Prefixes { | 
					
						
							| 
									
										
										
										
											2022-01-03 01:15:06 +08:00
										 |  |  | 		prefixItem := CommonPrefix{} | 
					
						
							| 
									
										
										
										
											2019-02-24 14:14:24 +08:00
										 |  |  | 		prefixItem.Prefix = s3EncodeName(prefix, encodingType) | 
					
						
							| 
									
										
										
										
											2016-06-01 13:10:55 +08:00
										 |  |  | 		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.
 | 
					
						
							| 
									
										
										
										
											2024-05-16 02:04:16 +08:00
										 |  |  | func generateListObjectsV2Response(ctx context.Context, bucket, prefix, token, nextToken, startAfter, delimiter, encodingType string, fetchOwner, isTruncated bool, maxKeys int, objects []ObjectInfo, prefixes []string, metadata metaCheckFn) ListObjectsV2Response { | 
					
						
							| 
									
										
										
										
											2020-09-15 11:44:18 +08:00
										 |  |  | 	contents := make([]Object, 0, len(objects)) | 
					
						
							| 
									
										
										
										
											2023-06-07 12:31:47 +08:00
										 |  |  | 	var owner *Owner | 
					
						
							|  |  |  | 	if fetchOwner { | 
					
						
							|  |  |  | 		owner = &Owner{ | 
					
						
							|  |  |  | 			ID:          globalMinioDefaultOwnerID, | 
					
						
							|  |  |  | 			DisplayName: "minio", | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-09-11 01:44:38 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-06-07 12:31:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 01:15:06 +08:00
										 |  |  | 	data := ListObjectsV2Response{} | 
					
						
							| 
									
										
										
										
											2016-06-01 13:10:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-17 13:17:00 +08:00
										 |  |  | 	for _, object := range objects { | 
					
						
							| 
									
										
										
										
											2022-01-03 01:15:06 +08:00
										 |  |  | 		content := Object{} | 
					
						
							| 
									
										
										
										
											2016-06-01 13:10:55 +08:00
										 |  |  | 		if object.Name == "" { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-02-24 14:14:24 +08:00
										 |  |  | 		content.Key = s3EncodeName(object.Name, encodingType) | 
					
						
							| 
									
										
										
										
											2022-12-13 02:28:30 +08:00
										 |  |  | 		content.LastModified = amztime.ISO8601Format(object.ModTime.UTC()) | 
					
						
							| 
									
										
										
										
											2017-05-15 03:05:51 +08:00
										 |  |  | 		if object.ETag != "" { | 
					
						
							|  |  |  | 			content.ETag = "\"" + object.ETag + "\"" | 
					
						
							| 
									
										
										
										
											2016-06-01 13:10:55 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		content.Size = object.Size | 
					
						
							| 
									
										
										
										
											2020-04-02 15:23:09 +08:00
										 |  |  | 		if object.StorageClass != "" { | 
					
						
							| 
									
										
										
										
											2024-05-16 02:04:16 +08:00
										 |  |  | 			content.StorageClass = filterStorageClass(ctx, object.StorageClass) | 
					
						
							| 
									
										
										
										
											2020-04-02 15:23:09 +08:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			content.StorageClass = globalMinioDefaultStorageClass | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-06-01 13:10:55 +08:00
										 |  |  | 		content.Owner = owner | 
					
						
							| 
									
										
										
										
											2023-04-06 22:52:35 +08:00
										 |  |  | 		if metadata != nil { | 
					
						
							|  |  |  | 			if metadata(object.Name, policy.GetObjectTaggingAction) == ErrNone { | 
					
						
							|  |  |  | 				content.UserTags = object.UserTags | 
					
						
							| 
									
										
										
										
											2021-09-01 08:18:13 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-04-06 22:52:35 +08:00
										 |  |  | 			if metadata(object.Name, policy.GetObjectAction) == ErrNone { | 
					
						
							|  |  |  | 				content.UserMetadata = &Metadata{} | 
					
						
							|  |  |  | 				switch kind, _ := crypto.IsEncrypted(object.UserDefined); kind { | 
					
						
							|  |  |  | 				case crypto.S3: | 
					
						
							|  |  |  | 					content.UserMetadata.Set(xhttp.AmzServerSideEncryption, xhttp.AmzEncryptionAES) | 
					
						
							|  |  |  | 				case crypto.S3KMS: | 
					
						
							|  |  |  | 					content.UserMetadata.Set(xhttp.AmzServerSideEncryption, xhttp.AmzEncryptionKMS) | 
					
						
							|  |  |  | 				case crypto.SSEC: | 
					
						
							|  |  |  | 					content.UserMetadata.Set(xhttp.AmzServerSideEncryptionCustomerAlgorithm, xhttp.AmzEncryptionAES) | 
					
						
							| 
									
										
										
										
											2019-11-21 17:54:49 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2023-11-23 05:46:17 +08:00
										 |  |  | 				for k, v := range cleanReservedKeys(object.UserDefined) { | 
					
						
							| 
									
										
										
										
											2023-04-06 22:52:35 +08:00
										 |  |  | 					content.UserMetadata.Set(k, v) | 
					
						
							| 
									
										
										
										
											2020-08-11 23:29:29 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2023-05-20 00:42:45 +08:00
										 |  |  | 				content.Internal = &ObjectInternalInfo{ | 
					
						
							|  |  |  | 					K: object.DataBlocks, | 
					
						
							|  |  |  | 					M: object.ParityBlocks, | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2019-11-21 17:54:49 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-06-01 13:10:55 +08:00
										 |  |  | 		contents = append(contents, content) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	data.Name = bucket | 
					
						
							|  |  |  | 	data.Contents = contents | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-24 14:14:24 +08:00
										 |  |  | 	data.EncodingType = encodingType | 
					
						
							| 
									
										
										
										
											2019-02-25 10:50:28 +08:00
										 |  |  | 	data.StartAfter = s3EncodeName(startAfter, encodingType) | 
					
						
							| 
									
										
										
										
											2019-02-24 14:14:24 +08:00
										 |  |  | 	data.Delimiter = s3EncodeName(delimiter, encodingType) | 
					
						
							|  |  |  | 	data.Prefix = s3EncodeName(prefix, encodingType) | 
					
						
							| 
									
										
										
										
											2016-06-01 13:10:55 +08:00
										 |  |  | 	data.MaxKeys = maxKeys | 
					
						
							| 
									
										
										
										
											2019-10-02 04:09:29 +08:00
										 |  |  | 	data.ContinuationToken = base64.StdEncoding.EncodeToString([]byte(token)) | 
					
						
							|  |  |  | 	data.NextContinuationToken = base64.StdEncoding.EncodeToString([]byte(nextToken)) | 
					
						
							| 
									
										
										
										
											2017-06-17 13:17:00 +08:00
										 |  |  | 	data.IsTruncated = isTruncated | 
					
						
							| 
									
										
										
										
											2020-09-15 11:44:18 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	commonPrefixes := make([]CommonPrefix, 0, len(prefixes)) | 
					
						
							| 
									
										
										
										
											2017-06-17 13:17:00 +08:00
										 |  |  | 	for _, prefix := range prefixes { | 
					
						
							| 
									
										
										
										
											2022-01-03 01:15:06 +08:00
										 |  |  | 		prefixItem := CommonPrefix{} | 
					
						
							| 
									
										
										
										
											2019-02-24 14:14:24 +08:00
										 |  |  | 		prefixItem.Prefix = s3EncodeName(prefix, encodingType) | 
					
						
							| 
									
										
										
										
											2017-06-17 13:17:00 +08:00
										 |  |  | 		commonPrefixes = append(commonPrefixes, prefixItem) | 
					
						
							| 
									
										
										
										
											2015-03-01 06:44:26 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-17 13:17:00 +08:00
										 |  |  | 	data.CommonPrefixes = commonPrefixes | 
					
						
							| 
									
										
										
										
											2016-10-06 11:12:47 +08:00
										 |  |  | 	data.KeyCount = len(data.Contents) + len(data.CommonPrefixes) | 
					
						
							| 
									
										
										
										
											2015-02-16 09:03:27 +08:00
										 |  |  | 	return data | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-04-23 07:28:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-06 22:52:35 +08:00
										 |  |  | type metaCheckFn = func(name string, action policy.Action) (s3Err APIErrorCode) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-22 05:51:05 +08:00
										 |  |  | // generates CopyObjectResponse from etag and lastModified time.
 | 
					
						
							| 
									
										
										
										
											2016-02-27 19:04:52 +08:00
										 |  |  | func generateCopyObjectResponse(etag string, lastModified time.Time) CopyObjectResponse { | 
					
						
							|  |  |  | 	return CopyObjectResponse{ | 
					
						
							| 
									
										
										
										
											2017-02-01 01:38:34 +08:00
										 |  |  | 		ETag:         "\"" + etag + "\"", | 
					
						
							| 
									
										
										
										
											2022-12-13 02:28:30 +08:00
										 |  |  | 		LastModified: amztime.ISO8601Format(lastModified.UTC()), | 
					
						
							| 
									
										
										
										
											2017-02-01 01:38:34 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // generates CopyObjectPartResponse from etag and lastModified time.
 | 
					
						
							|  |  |  | func generateCopyObjectPartResponse(etag string, lastModified time.Time) CopyObjectPartResponse { | 
					
						
							|  |  |  | 	return CopyObjectPartResponse{ | 
					
						
							| 
									
										
										
										
											2016-02-27 19:04:52 +08:00
										 |  |  | 		ETag:         "\"" + etag + "\"", | 
					
						
							| 
									
										
										
										
											2022-12-13 02:28:30 +08:00
										 |  |  | 		LastModified: amztime.ISO8601Format(lastModified.UTC()), | 
					
						
							| 
									
										
										
										
											2016-02-27 19:04:52 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-22 05:51:05 +08:00
										 |  |  | // generates InitiateMultipartUploadResponse for given bucket, key and uploadID.
 | 
					
						
							| 
									
										
										
										
											2015-07-10 10:01:15 +08:00
										 |  |  | func generateInitiateMultipartUploadResponse(bucket, key, uploadID string) InitiateMultipartUploadResponse { | 
					
						
							|  |  |  | 	return InitiateMultipartUploadResponse{ | 
					
						
							| 
									
										
										
										
											2015-05-08 10:55:30 +08:00
										 |  |  | 		Bucket:   bucket, | 
					
						
							|  |  |  | 		Key:      key, | 
					
						
							|  |  |  | 		UploadID: uploadID, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-22 05:51:05 +08:00
										 |  |  | // generates CompleteMultipartUploadResponse for given bucket, key, location and ETag.
 | 
					
						
							| 
									
										
										
										
											2024-06-10 23:31:51 +08:00
										 |  |  | func generateCompleteMultipartUploadResponse(bucket, key, location string, oi ObjectInfo, h http.Header) CompleteMultipartUploadResponse { | 
					
						
							|  |  |  | 	cs := oi.decryptChecksums(0, h) | 
					
						
							| 
									
										
										
										
											2022-08-30 07:57:16 +08:00
										 |  |  | 	c := CompleteMultipartUploadResponse{ | 
					
						
							| 
									
										
										
										
											2015-05-08 13:43:19 +08:00
										 |  |  | 		Location: location, | 
					
						
							|  |  |  | 		Bucket:   bucket, | 
					
						
							|  |  |  | 		Key:      key, | 
					
						
							| 
									
										
										
										
											2020-05-06 08:47:54 +08:00
										 |  |  | 		// AWS S3 quotes the ETag in XML, make sure we are compatible here.
 | 
					
						
							| 
									
										
										
										
											2022-08-30 07:57:16 +08:00
										 |  |  | 		ETag:           "\"" + oi.ETag + "\"", | 
					
						
							| 
									
										
										
										
											2022-08-31 23:13:23 +08:00
										 |  |  | 		ChecksumSHA1:   cs[hash.ChecksumSHA1.String()], | 
					
						
							|  |  |  | 		ChecksumSHA256: cs[hash.ChecksumSHA256.String()], | 
					
						
							|  |  |  | 		ChecksumCRC32:  cs[hash.ChecksumCRC32.String()], | 
					
						
							|  |  |  | 		ChecksumCRC32C: cs[hash.ChecksumCRC32C.String()], | 
					
						
							| 
									
										
										
										
											2015-05-08 13:43:19 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-08-30 07:57:16 +08:00
										 |  |  | 	return c | 
					
						
							| 
									
										
										
										
											2015-05-08 13:43:19 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-22 05:51:05 +08:00
										 |  |  | // generates ListPartsResponse from ListPartsInfo.
 | 
					
						
							| 
									
										
										
										
											2019-02-24 14:14:24 +08:00
										 |  |  | func generateListPartsResponse(partsInfo ListPartsInfo, encodingType string) ListPartsResponse { | 
					
						
							| 
									
										
										
										
											2015-05-10 02:41:26 +08:00
										 |  |  | 	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 | 
					
						
							| 
									
										
										
										
											2019-02-24 14:14:24 +08:00
										 |  |  | 	listPartsResponse.Key = s3EncodeName(partsInfo.Object, encodingType) | 
					
						
							| 
									
										
										
											
												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.UploadID = partsInfo.UploadID | 
					
						
							| 
									
										
										
										
											2017-01-19 04:24:34 +08:00
										 |  |  | 	listPartsResponse.StorageClass = globalMinioDefaultStorageClass | 
					
						
							| 
									
										
										
										
											2021-02-04 12:41:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Dumb values not meaningful
 | 
					
						
							|  |  |  | 	listPartsResponse.Initiator = Initiator{ | 
					
						
							|  |  |  | 		ID:          globalMinioDefaultOwnerID, | 
					
						
							|  |  |  | 		DisplayName: globalMinioDefaultOwnerID, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	listPartsResponse.Owner = Owner{ | 
					
						
							|  |  |  | 		ID:          globalMinioDefaultOwnerID, | 
					
						
							|  |  |  | 		DisplayName: globalMinioDefaultOwnerID, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											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.MaxParts = partsInfo.MaxParts | 
					
						
							|  |  |  | 	listPartsResponse.PartNumberMarker = partsInfo.PartNumberMarker | 
					
						
							|  |  |  | 	listPartsResponse.IsTruncated = partsInfo.IsTruncated | 
					
						
							|  |  |  | 	listPartsResponse.NextPartNumberMarker = partsInfo.NextPartNumberMarker | 
					
						
							| 
									
										
										
										
											2022-08-30 07:57:16 +08:00
										 |  |  | 	listPartsResponse.ChecksumAlgorithm = partsInfo.ChecksumAlgorithm | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2022-12-13 02:28:30 +08:00
										 |  |  | 		newPart.LastModified = amztime.ISO8601Format(part.LastModified.UTC()) | 
					
						
							| 
									
										
										
										
											2022-08-30 07:57:16 +08:00
										 |  |  | 		newPart.ChecksumCRC32 = part.ChecksumCRC32 | 
					
						
							|  |  |  | 		newPart.ChecksumCRC32C = part.ChecksumCRC32C | 
					
						
							|  |  |  | 		newPart.ChecksumSHA1 = part.ChecksumSHA1 | 
					
						
							|  |  |  | 		newPart.ChecksumSHA256 = part.ChecksumSHA256 | 
					
						
							| 
									
										
										
										
											2016-03-20 14:44:43 +08:00
										 |  |  | 		listPartsResponse.Parts[index] = newPart | 
					
						
							| 
									
										
										
										
											2015-05-10 02:41:26 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return listPartsResponse | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-22 05:51:05 +08:00
										 |  |  | // generates ListMultipartUploadsResponse for given bucket and ListMultipartsInfo.
 | 
					
						
							| 
									
										
										
										
											2019-02-24 14:14:24 +08:00
										 |  |  | func generateListMultipartUploadsResponse(bucket string, multipartsInfo ListMultipartsInfo, encodingType string) ListMultipartUploadsResponse { | 
					
						
							| 
									
										
										
										
											2015-05-15 05:36:41 +08:00
										 |  |  | 	listMultipartUploadsResponse := ListMultipartUploadsResponse{} | 
					
						
							|  |  |  | 	listMultipartUploadsResponse.Bucket = bucket | 
					
						
							| 
									
										
										
										
											2019-02-24 14:14:24 +08:00
										 |  |  | 	listMultipartUploadsResponse.Delimiter = s3EncodeName(multipartsInfo.Delimiter, encodingType) | 
					
						
							| 
									
										
										
											
												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.IsTruncated = multipartsInfo.IsTruncated | 
					
						
							| 
									
										
										
										
											2019-02-24 14:14:24 +08:00
										 |  |  | 	listMultipartUploadsResponse.EncodingType = encodingType | 
					
						
							|  |  |  | 	listMultipartUploadsResponse.Prefix = s3EncodeName(multipartsInfo.Prefix, encodingType) | 
					
						
							|  |  |  | 	listMultipartUploadsResponse.KeyMarker = s3EncodeName(multipartsInfo.KeyMarker, encodingType) | 
					
						
							|  |  |  | 	listMultipartUploadsResponse.NextKeyMarker = s3EncodeName(multipartsInfo.NextKeyMarker, encodingType) | 
					
						
							| 
									
										
										
											
												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.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{ | 
					
						
							| 
									
										
										
										
											2019-02-24 14:14:24 +08:00
										 |  |  | 			Prefix: s3EncodeName(commonPrefix, encodingType), | 
					
						
							| 
									
										
										
										
											2016-04-06 06:08:59 +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
										 |  |  | 	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 | 
					
						
							| 
									
										
										
										
											2019-02-24 14:14:24 +08:00
										 |  |  | 		newUpload.Key = s3EncodeName(upload.Object, encodingType) | 
					
						
							| 
									
										
										
										
											2022-12-13 02:28:30 +08:00
										 |  |  | 		newUpload.Initiated = amztime.ISO8601Format(upload.Initiated.UTC()) | 
					
						
							| 
									
										
										
										
											2016-03-20 14:44:43 +08:00
										 |  |  | 		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.
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | func generateMultiDeleteResponse(quiet bool, deletedObjects []DeletedObject, errs []DeleteError) DeleteObjectsResponse { | 
					
						
							| 
									
										
										
										
											2016-03-06 08:43:48 +08:00
										 |  |  | 	deleteResp := DeleteObjectsResponse{} | 
					
						
							|  |  |  | 	if !quiet { | 
					
						
							|  |  |  | 		deleteResp.DeletedObjects = deletedObjects | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	deleteResp.Errors = errs | 
					
						
							|  |  |  | 	return deleteResp | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-06 16:37:00 +08:00
										 |  |  | func writeResponse(w http.ResponseWriter, statusCode int, response []byte, mType mimeType) { | 
					
						
							| 
									
										
											  
											
												Check error status codes (#14850)
If an invalid status code is generated from an error we risk panicking. Even if there 
are no potential problems at the moment we should prevent this in the future.
Add safeguards against this.
Sample trace:
```
May 02 06:41:39   minio[52806]: panic: "GET /20180401230655.PDF": invalid WriteHeader code 0
May 02 06:41:39   minio[52806]: goroutine 16040430822 [running]:
May 02 06:41:39   minio[52806]: runtime/debug.Stack(0xc01fff7c20, 0x25c4b00, 0xc0490e4080)
May 02 06:41:39   minio[52806]:         runtime/debug/stack.go:24 +0x9f
May 02 06:41:39   minio[52806]: github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1(0xc022048800, 0x4f38ab0, 0xc0406e0fc0)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/cmd/generic-handlers.go:469 +0x85
May 02 06:41:39   minio[52806]: panic(0x25c4b00, 0xc0490e4080)
May 02 06:41:39   minio[52806]:         runtime/panic.go:965 +0x1b9
May 02 06:41:39   minio[52806]: net/http.checkWriteHeaderCode(...)
May 02 06:41:39   minio[52806]:         net/http/server.go:1092
May 02 06:41:39   minio[52806]: net/http.(*response).WriteHeader(0xc0406e0fc0, 0x0)
May 02 06:41:39   minio[52806]:         net/http/server.go:1126 +0x718
May 02 06:41:39   minio[52806]: github.com/minio/minio/internal/logger.(*ResponseWriter).WriteHeader(0xc032fa3ea0, 0x0)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/internal/logger/audit.go:116 +0xb1
May 02 06:41:39   minio[52806]: github.com/minio/minio/internal/logger.(*ResponseWriter).WriteHeader(0xc032fa3f40, 0x0)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/internal/logger/audit.go:116 +0xb1
May 02 06:41:39   minio[52806]: github.com/minio/minio/internal/logger.(*ResponseWriter).WriteHeader(0xc002ce8000, 0x0)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/internal/logger/audit.go:116 +0xb1
May 02 06:41:39   minio[52806]: github.com/minio/minio/cmd.writeResponse(0x4f364a0, 0xc002ce8000, 0x0, 0xc0443b86c0, 0x1cb, 0x224, 0x2a9651e, 0xf)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/cmd/api-response.go:736 +0x18d
May 02 06:41:39   minio[52806]: github.com/minio/minio/cmd.writeErrorResponse(0x4f44218, 0xc069086ae0, 0x4f364a0, 0xc002ce8000, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc00656afc0)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/cmd/api-response.go:798 +0x306
May 02 06:41:39   minio[52806]: github.com/minio/minio/cmd.objectAPIHandlers.getObjectHandler(0x4b73768, 0x4b73730, 0x4f44218, 0xc069086ae0, 0x4f82090, 0xc002d80620, 0xc040e03885, 0xe, 0xc040e03894, 0x61, ...)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/cmd/object-handlers.go:456 +0x252c
```
											
										 
											2022-05-03 01:36:29 +08:00
										 |  |  | 	if statusCode == 0 { | 
					
						
							|  |  |  | 		statusCode = 200 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Similar check to http.checkWriteHeaderCode
 | 
					
						
							|  |  |  | 	if statusCode < 100 || statusCode > 999 { | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 		bugLogIf(context.Background(), fmt.Errorf("invalid WriteHeader code %v", statusCode)) | 
					
						
							| 
									
										
											  
											
												Check error status codes (#14850)
If an invalid status code is generated from an error we risk panicking. Even if there 
are no potential problems at the moment we should prevent this in the future.
Add safeguards against this.
Sample trace:
```
May 02 06:41:39   minio[52806]: panic: "GET /20180401230655.PDF": invalid WriteHeader code 0
May 02 06:41:39   minio[52806]: goroutine 16040430822 [running]:
May 02 06:41:39   minio[52806]: runtime/debug.Stack(0xc01fff7c20, 0x25c4b00, 0xc0490e4080)
May 02 06:41:39   minio[52806]:         runtime/debug/stack.go:24 +0x9f
May 02 06:41:39   minio[52806]: github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1(0xc022048800, 0x4f38ab0, 0xc0406e0fc0)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/cmd/generic-handlers.go:469 +0x85
May 02 06:41:39   minio[52806]: panic(0x25c4b00, 0xc0490e4080)
May 02 06:41:39   minio[52806]:         runtime/panic.go:965 +0x1b9
May 02 06:41:39   minio[52806]: net/http.checkWriteHeaderCode(...)
May 02 06:41:39   minio[52806]:         net/http/server.go:1092
May 02 06:41:39   minio[52806]: net/http.(*response).WriteHeader(0xc0406e0fc0, 0x0)
May 02 06:41:39   minio[52806]:         net/http/server.go:1126 +0x718
May 02 06:41:39   minio[52806]: github.com/minio/minio/internal/logger.(*ResponseWriter).WriteHeader(0xc032fa3ea0, 0x0)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/internal/logger/audit.go:116 +0xb1
May 02 06:41:39   minio[52806]: github.com/minio/minio/internal/logger.(*ResponseWriter).WriteHeader(0xc032fa3f40, 0x0)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/internal/logger/audit.go:116 +0xb1
May 02 06:41:39   minio[52806]: github.com/minio/minio/internal/logger.(*ResponseWriter).WriteHeader(0xc002ce8000, 0x0)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/internal/logger/audit.go:116 +0xb1
May 02 06:41:39   minio[52806]: github.com/minio/minio/cmd.writeResponse(0x4f364a0, 0xc002ce8000, 0x0, 0xc0443b86c0, 0x1cb, 0x224, 0x2a9651e, 0xf)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/cmd/api-response.go:736 +0x18d
May 02 06:41:39   minio[52806]: github.com/minio/minio/cmd.writeErrorResponse(0x4f44218, 0xc069086ae0, 0x4f364a0, 0xc002ce8000, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc00656afc0)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/cmd/api-response.go:798 +0x306
May 02 06:41:39   minio[52806]: github.com/minio/minio/cmd.objectAPIHandlers.getObjectHandler(0x4b73768, 0x4b73730, 0x4f44218, 0xc069086ae0, 0x4f82090, 0xc002d80620, 0xc040e03885, 0xe, 0xc040e03894, 0x61, ...)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/cmd/object-handlers.go:456 +0x252c
```
											
										 
											2022-05-03 01:36:29 +08:00
										 |  |  | 		statusCode = http.StatusInternalServerError | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-08 16:40:06 +08:00
										 |  |  | 	setCommonHeaders(w) | 
					
						
							| 
									
										
										
										
											2017-01-06 16:37:00 +08:00
										 |  |  | 	if mType != mimeNone { | 
					
						
							| 
									
										
										
										
											2019-07-03 13:34:32 +08:00
										 |  |  | 		w.Header().Set(xhttp.ContentType, string(mType)) | 
					
						
							| 
									
										
										
										
											2017-01-06 16:37:00 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-07-03 13:34:32 +08:00
										 |  |  | 	w.Header().Set(xhttp.ContentLength, strconv.Itoa(len(response))) | 
					
						
							| 
									
										
										
										
											2016-12-19 05:39:56 +08:00
										 |  |  | 	w.WriteHeader(statusCode) | 
					
						
							| 
									
										
										
										
											2017-01-06 16:37:00 +08:00
										 |  |  | 	if response != nil { | 
					
						
							|  |  |  | 		w.Write(response) | 
					
						
							| 
									
										
										
										
											2016-01-08 16:40:06 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-30 01:51:59 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-06 16:37:00 +08:00
										 |  |  | // mimeType represents various MIME type used API responses.
 | 
					
						
							|  |  |  | type mimeType string | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	// Means no response type.
 | 
					
						
							|  |  |  | 	mimeNone mimeType = "" | 
					
						
							|  |  |  | 	// Means response type is JSON.
 | 
					
						
							|  |  |  | 	mimeJSON mimeType = "application/json" | 
					
						
							|  |  |  | 	// Means response type is XML.
 | 
					
						
							|  |  |  | 	mimeXML mimeType = "application/xml" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // writeSuccessResponseJSON writes success headers and response if any,
 | 
					
						
							|  |  |  | // with content-type set to `application/json`.
 | 
					
						
							|  |  |  | func writeSuccessResponseJSON(w http.ResponseWriter, response []byte) { | 
					
						
							|  |  |  | 	writeResponse(w, http.StatusOK, response, mimeJSON) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // writeSuccessResponseXML writes success headers and response if any,
 | 
					
						
							|  |  |  | // with content-type set to `application/xml`.
 | 
					
						
							|  |  |  | func writeSuccessResponseXML(w http.ResponseWriter, response []byte) { | 
					
						
							|  |  |  | 	writeResponse(w, http.StatusOK, response, mimeXML) | 
					
						
							| 
									
										
										
										
											2016-12-19 05:39:56 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-21 01:32:17 +08:00
										 |  |  | // writeSuccessNoContent writes success headers with http status 204
 | 
					
						
							| 
									
										
										
										
											2015-10-17 11:02:37 +08:00
										 |  |  | func writeSuccessNoContent(w http.ResponseWriter) { | 
					
						
							| 
									
										
										
										
											2017-01-06 16:37:00 +08:00
										 |  |  | 	writeResponse(w, http.StatusNoContent, nil, mimeNone) | 
					
						
							| 
									
										
										
										
											2015-10-17 11:02:37 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-21 01:32:17 +08:00
										 |  |  | // writeRedirectSeeOther writes Location header with http status 303
 | 
					
						
							|  |  |  | func writeRedirectSeeOther(w http.ResponseWriter, location string) { | 
					
						
							| 
									
										
										
										
											2019-07-03 13:34:32 +08:00
										 |  |  | 	w.Header().Set(xhttp.Location, location) | 
					
						
							| 
									
										
										
										
											2017-01-06 16:37:00 +08:00
										 |  |  | 	writeResponse(w, http.StatusSeeOther, nil, mimeNone) | 
					
						
							| 
									
										
										
										
											2016-12-21 01:32:17 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-06 16:37:00 +08:00
										 |  |  | func writeSuccessResponseHeadersOnly(w http.ResponseWriter) { | 
					
						
							|  |  |  | 	writeResponse(w, http.StatusOK, nil, mimeNone) | 
					
						
							| 
									
										
										
										
											2016-06-16 11:31:06 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-22 14:26:06 +08:00
										 |  |  | // writeErrorResponse writes error headers
 | 
					
						
							| 
									
										
										
										
											2021-06-18 11:27:04 +08:00
										 |  |  | func writeErrorResponse(ctx context.Context, w http.ResponseWriter, err APIError, reqURL *url.URL) { | 
					
						
							| 
									
										
										
										
											2024-06-26 16:32:06 +08:00
										 |  |  | 	switch err.HTTPStatusCode { | 
					
						
							| 
									
										
										
										
											2024-08-16 16:43:49 +08:00
										 |  |  | 	case http.StatusServiceUnavailable, http.StatusTooManyRequests: | 
					
						
							| 
									
										
										
										
											2024-06-26 16:32:06 +08:00
										 |  |  | 		// Set retry-after header to indicate user-agents to retry request after 60 seconds.
 | 
					
						
							| 
									
										
										
										
											2017-12-20 16:00:14 +08:00
										 |  |  | 		// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
 | 
					
						
							| 
									
										
										
										
											2024-06-26 16:32:06 +08:00
										 |  |  | 		w.Header().Set(xhttp.RetryAfter, "60") | 
					
						
							| 
									
										
										
										
											2024-02-10 05:25:16 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch err.Code { | 
					
						
							| 
									
										
										
										
											2020-08-24 13:06:22 +08:00
										 |  |  | 	case "InvalidRegion": | 
					
						
							| 
									
										
										
										
											2024-05-17 07:13:47 +08:00
										 |  |  | 		err.Description = fmt.Sprintf("Region does not match; expecting '%s'.", globalSite.Region()) | 
					
						
							| 
									
										
										
										
											2020-08-24 13:06:22 +08:00
										 |  |  | 	case "AuthorizationHeaderMalformed": | 
					
						
							| 
									
										
										
										
											2024-05-17 07:13:47 +08:00
										 |  |  | 		err.Description = fmt.Sprintf("The authorization header is malformed; the region is wrong; expecting '%s'.", globalSite.Region()) | 
					
						
							| 
									
										
										
										
											2017-12-20 16:00:14 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-11-27 04:15:12 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
											  
											
												Check error status codes (#14850)
If an invalid status code is generated from an error we risk panicking. Even if there 
are no potential problems at the moment we should prevent this in the future.
Add safeguards against this.
Sample trace:
```
May 02 06:41:39   minio[52806]: panic: "GET /20180401230655.PDF": invalid WriteHeader code 0
May 02 06:41:39   minio[52806]: goroutine 16040430822 [running]:
May 02 06:41:39   minio[52806]: runtime/debug.Stack(0xc01fff7c20, 0x25c4b00, 0xc0490e4080)
May 02 06:41:39   minio[52806]:         runtime/debug/stack.go:24 +0x9f
May 02 06:41:39   minio[52806]: github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1(0xc022048800, 0x4f38ab0, 0xc0406e0fc0)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/cmd/generic-handlers.go:469 +0x85
May 02 06:41:39   minio[52806]: panic(0x25c4b00, 0xc0490e4080)
May 02 06:41:39   minio[52806]:         runtime/panic.go:965 +0x1b9
May 02 06:41:39   minio[52806]: net/http.checkWriteHeaderCode(...)
May 02 06:41:39   minio[52806]:         net/http/server.go:1092
May 02 06:41:39   minio[52806]: net/http.(*response).WriteHeader(0xc0406e0fc0, 0x0)
May 02 06:41:39   minio[52806]:         net/http/server.go:1126 +0x718
May 02 06:41:39   minio[52806]: github.com/minio/minio/internal/logger.(*ResponseWriter).WriteHeader(0xc032fa3ea0, 0x0)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/internal/logger/audit.go:116 +0xb1
May 02 06:41:39   minio[52806]: github.com/minio/minio/internal/logger.(*ResponseWriter).WriteHeader(0xc032fa3f40, 0x0)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/internal/logger/audit.go:116 +0xb1
May 02 06:41:39   minio[52806]: github.com/minio/minio/internal/logger.(*ResponseWriter).WriteHeader(0xc002ce8000, 0x0)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/internal/logger/audit.go:116 +0xb1
May 02 06:41:39   minio[52806]: github.com/minio/minio/cmd.writeResponse(0x4f364a0, 0xc002ce8000, 0x0, 0xc0443b86c0, 0x1cb, 0x224, 0x2a9651e, 0xf)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/cmd/api-response.go:736 +0x18d
May 02 06:41:39   minio[52806]: github.com/minio/minio/cmd.writeErrorResponse(0x4f44218, 0xc069086ae0, 0x4f364a0, 0xc002ce8000, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc00656afc0)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/cmd/api-response.go:798 +0x306
May 02 06:41:39   minio[52806]: github.com/minio/minio/cmd.objectAPIHandlers.getObjectHandler(0x4b73768, 0x4b73730, 0x4f44218, 0xc069086ae0, 0x4f82090, 0xc002d80620, 0xc040e03885, 0xe, 0xc040e03894, 0x61, ...)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/cmd/object-handlers.go:456 +0x252c
```
											
										 
											2022-05-03 01:36:29 +08:00
										 |  |  | 	// Similar check to http.checkWriteHeaderCode
 | 
					
						
							|  |  |  | 	if err.HTTPStatusCode < 100 || err.HTTPStatusCode > 999 { | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 		bugLogIf(ctx, fmt.Errorf("invalid WriteHeader code %v from %v", err.HTTPStatusCode, err.Code)) | 
					
						
							| 
									
										
											  
											
												Check error status codes (#14850)
If an invalid status code is generated from an error we risk panicking. Even if there 
are no potential problems at the moment we should prevent this in the future.
Add safeguards against this.
Sample trace:
```
May 02 06:41:39   minio[52806]: panic: "GET /20180401230655.PDF": invalid WriteHeader code 0
May 02 06:41:39   minio[52806]: goroutine 16040430822 [running]:
May 02 06:41:39   minio[52806]: runtime/debug.Stack(0xc01fff7c20, 0x25c4b00, 0xc0490e4080)
May 02 06:41:39   minio[52806]:         runtime/debug/stack.go:24 +0x9f
May 02 06:41:39   minio[52806]: github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1(0xc022048800, 0x4f38ab0, 0xc0406e0fc0)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/cmd/generic-handlers.go:469 +0x85
May 02 06:41:39   minio[52806]: panic(0x25c4b00, 0xc0490e4080)
May 02 06:41:39   minio[52806]:         runtime/panic.go:965 +0x1b9
May 02 06:41:39   minio[52806]: net/http.checkWriteHeaderCode(...)
May 02 06:41:39   minio[52806]:         net/http/server.go:1092
May 02 06:41:39   minio[52806]: net/http.(*response).WriteHeader(0xc0406e0fc0, 0x0)
May 02 06:41:39   minio[52806]:         net/http/server.go:1126 +0x718
May 02 06:41:39   minio[52806]: github.com/minio/minio/internal/logger.(*ResponseWriter).WriteHeader(0xc032fa3ea0, 0x0)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/internal/logger/audit.go:116 +0xb1
May 02 06:41:39   minio[52806]: github.com/minio/minio/internal/logger.(*ResponseWriter).WriteHeader(0xc032fa3f40, 0x0)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/internal/logger/audit.go:116 +0xb1
May 02 06:41:39   minio[52806]: github.com/minio/minio/internal/logger.(*ResponseWriter).WriteHeader(0xc002ce8000, 0x0)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/internal/logger/audit.go:116 +0xb1
May 02 06:41:39   minio[52806]: github.com/minio/minio/cmd.writeResponse(0x4f364a0, 0xc002ce8000, 0x0, 0xc0443b86c0, 0x1cb, 0x224, 0x2a9651e, 0xf)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/cmd/api-response.go:736 +0x18d
May 02 06:41:39   minio[52806]: github.com/minio/minio/cmd.writeErrorResponse(0x4f44218, 0xc069086ae0, 0x4f364a0, 0xc002ce8000, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc00656afc0)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/cmd/api-response.go:798 +0x306
May 02 06:41:39   minio[52806]: github.com/minio/minio/cmd.objectAPIHandlers.getObjectHandler(0x4b73768, 0x4b73730, 0x4f44218, 0xc069086ae0, 0x4f82090, 0xc002d80620, 0xc040e03885, 0xe, 0xc040e03894, 0x61, ...)
May 02 06:41:39   minio[52806]:         github.com/minio/minio/cmd/object-handlers.go:456 +0x252c
```
											
										 
											2022-05-03 01:36:29 +08:00
										 |  |  | 		err.HTTPStatusCode = http.StatusInternalServerError | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-29 05:51:49 +08:00
										 |  |  | 	// Generate error response.
 | 
					
						
							| 
									
										
										
										
											2019-02-21 14:20:15 +08:00
										 |  |  | 	errorResponse := getAPIErrorResponse(ctx, err, reqURL.Path, | 
					
						
							| 
									
										
										
										
											2023-02-22 18:11:09 +08:00
										 |  |  | 		w.Header().Get(xhttp.AmzRequestID), w.Header().Get(xhttp.AmzRequestHostID)) | 
					
						
							| 
									
										
										
										
											2016-06-16 11:31:06 +08:00
										 |  |  | 	encodedErrorResponse := encodeResponse(errorResponse) | 
					
						
							| 
									
										
										
										
											2019-02-12 17:25:52 +08:00
										 |  |  | 	writeResponse(w, err.HTTPStatusCode, encodedErrorResponse, mimeXML) | 
					
						
							| 
									
										
										
										
											2017-01-06 16:37:00 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-12 17:25:52 +08:00
										 |  |  | func writeErrorResponseHeadersOnly(w http.ResponseWriter, err APIError) { | 
					
						
							| 
									
										
										
										
											2023-06-19 09:20:15 +08:00
										 |  |  | 	w.Header().Set(xMinIOErrCodeHeader, err.Code) | 
					
						
							|  |  |  | 	w.Header().Set(xMinIOErrDescHeader, "\""+err.Description+"\"") | 
					
						
							| 
									
										
										
										
											2019-02-12 17:25:52 +08:00
										 |  |  | 	writeResponse(w, err.HTTPStatusCode, nil, mimeNone) | 
					
						
							| 
									
										
										
										
											2015-04-23 07:28:13 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-01-23 06:54:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-05 01:30:59 +08:00
										 |  |  | func writeErrorResponseString(ctx context.Context, w http.ResponseWriter, err APIError, reqURL *url.URL) { | 
					
						
							|  |  |  | 	// Generate string error response.
 | 
					
						
							|  |  |  | 	writeResponse(w, err.HTTPStatusCode, []byte(err.Description), mimeNone) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-23 06:54:55 +08:00
										 |  |  | // writeErrorResponseJSON - writes error response in JSON format;
 | 
					
						
							|  |  |  | // useful for admin APIs.
 | 
					
						
							| 
									
										
										
										
											2019-02-14 08:07:21 +08:00
										 |  |  | func writeErrorResponseJSON(ctx context.Context, w http.ResponseWriter, err APIError, reqURL *url.URL) { | 
					
						
							| 
									
										
										
										
											2018-01-23 06:54:55 +08:00
										 |  |  | 	// Generate error response.
 | 
					
						
							| 
									
										
										
										
											2023-02-22 18:11:09 +08:00
										 |  |  | 	errorResponse := getAPIErrorResponse(ctx, err, reqURL.Path, w.Header().Get(xhttp.AmzRequestID), w.Header().Get(xhttp.AmzRequestHostID)) | 
					
						
							| 
									
										
										
										
											2018-01-23 06:54:55 +08:00
										 |  |  | 	encodedErrorResponse := encodeResponseJSON(errorResponse) | 
					
						
							| 
									
										
										
										
											2019-02-12 17:25:52 +08:00
										 |  |  | 	writeResponse(w, err.HTTPStatusCode, encodedErrorResponse, mimeJSON) | 
					
						
							| 
									
										
										
										
											2018-01-23 06:54:55 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // writeCustomErrorResponseJSON - similar to writeErrorResponseJSON,
 | 
					
						
							|  |  |  | // but accepts the error message directly (this allows messages to be
 | 
					
						
							|  |  |  | // dynamically generated.)
 | 
					
						
							| 
									
										
										
										
											2019-02-14 08:07:21 +08:00
										 |  |  | func writeCustomErrorResponseJSON(ctx context.Context, w http.ResponseWriter, err APIError, | 
					
						
							| 
									
										
										
										
											2022-01-03 01:15:06 +08:00
										 |  |  | 	errBody string, reqURL *url.URL, | 
					
						
							|  |  |  | ) { | 
					
						
							| 
									
										
										
										
											2019-02-14 08:07:21 +08:00
										 |  |  | 	reqInfo := logger.GetReqInfo(ctx) | 
					
						
							| 
									
										
										
										
											2018-01-23 06:54:55 +08:00
										 |  |  | 	errorResponse := APIErrorResponse{ | 
					
						
							| 
									
										
										
										
											2019-02-14 08:07:21 +08:00
										 |  |  | 		Code:       err.Code, | 
					
						
							|  |  |  | 		Message:    errBody, | 
					
						
							|  |  |  | 		Resource:   reqURL.Path, | 
					
						
							|  |  |  | 		BucketName: reqInfo.BucketName, | 
					
						
							|  |  |  | 		Key:        reqInfo.ObjectName, | 
					
						
							| 
									
										
										
										
											2019-07-03 13:34:32 +08:00
										 |  |  | 		RequestID:  w.Header().Get(xhttp.AmzRequestID), | 
					
						
							| 
									
										
										
										
											2023-10-18 23:06:57 +08:00
										 |  |  | 		HostID:     globalDeploymentID(), | 
					
						
							| 
									
										
										
										
											2018-01-23 06:54:55 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	encodedErrorResponse := encodeResponseJSON(errorResponse) | 
					
						
							| 
									
										
										
										
											2019-02-12 17:25:52 +08:00
										 |  |  | 	writeResponse(w, err.HTTPStatusCode, encodedErrorResponse, mimeJSON) | 
					
						
							| 
									
										
										
										
											2018-01-23 06:54:55 +08:00
										 |  |  | } |