| 
									
										
										
										
											2015-02-15 16:48:15 +08:00
										 |  |  | /* | 
					
						
							| 
									
										
										
										
											2017-03-19 02:28:41 +08:00
										 |  |  |  * Minio Cloud Storage, (C) 2015, 2016, 2017 Minio, Inc. | 
					
						
							| 
									
										
										
										
											2015-02-15 16:48:15 +08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  |  * you may not use this file except in compliance with the License. | 
					
						
							|  |  |  |  * You may obtain a copy of the License at | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *     http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  |  * distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  |  * See the License for the specific language governing permissions and | 
					
						
							|  |  |  |  * limitations under the License. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 07:23:42 +08:00
										 |  |  | package cmd | 
					
						
							| 
									
										
										
										
											2015-02-11 19:23:15 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2018-01-23 06:54:55 +08:00
										 |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2015-02-11 19:23:15 +08:00
										 |  |  | 	"encoding/xml" | 
					
						
							| 
									
										
										
										
											2017-01-11 08:43:48 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2015-02-11 19:23:15 +08:00
										 |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"strconv" | 
					
						
							| 
									
										
										
										
											2017-01-11 08:43:48 +08:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2018-09-21 10:22:09 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/minio/minio/cmd/crypto" | 
					
						
							| 
									
										
										
										
											2015-02-11 19:23:15 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-11 08:43:48 +08:00
										 |  |  | // Returns a hexadecimal representation of time at the
 | 
					
						
							|  |  |  | // time response is sent to the client.
 | 
					
						
							|  |  |  | func mustGetRequestID(t time.Time) string { | 
					
						
							|  |  |  | 	return fmt.Sprintf("%X", t.UnixNano()) | 
					
						
							| 
									
										
										
										
											2015-07-15 05:29:56 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-24 08:46:48 +08:00
										 |  |  | // Write http common headers
 | 
					
						
							| 
									
										
										
										
											2016-01-08 16:40:06 +08:00
										 |  |  | func setCommonHeaders(w http.ResponseWriter) { | 
					
						
							| 
									
										
										
										
											2017-01-10 06:22:10 +08:00
										 |  |  | 	w.Header().Set("Server", globalServerUserAgent) | 
					
						
							| 
									
										
										
										
											2017-06-24 07:05:40 +08:00
										 |  |  | 	// Set `x-amz-bucket-region` only if region is set on the server
 | 
					
						
							|  |  |  | 	// by default minio uses an empty region.
 | 
					
						
							| 
									
										
										
										
											2017-11-30 05:12:47 +08:00
										 |  |  | 	if region := globalServerConfig.GetRegion(); region != "" { | 
					
						
							| 
									
										
										
										
											2017-06-24 07:05:40 +08:00
										 |  |  | 		w.Header().Set("X-Amz-Bucket-Region", region) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-11 16:01:49 +08:00
										 |  |  | 	w.Header().Set("Accept-Ranges", "bytes") | 
					
						
							| 
									
										
										
										
											2018-09-26 03:39:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Remove sensitive information
 | 
					
						
							|  |  |  | 	crypto.RemoveSensitiveHeaders(w.Header()) | 
					
						
							| 
									
										
										
										
											2015-02-11 19:23:15 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-07 04:16:22 +08:00
										 |  |  | // Encodes the response headers into XML format.
 | 
					
						
							|  |  |  | func encodeResponse(response interface{}) []byte { | 
					
						
							| 
									
										
										
										
											2015-02-11 19:23:15 +08:00
										 |  |  | 	var bytesBuffer bytes.Buffer | 
					
						
							| 
									
										
										
										
											2015-12-10 07:38:40 +08:00
										 |  |  | 	bytesBuffer.WriteString(xml.Header) | 
					
						
							| 
									
										
										
										
											2015-10-04 15:27:49 +08:00
										 |  |  | 	e := xml.NewEncoder(&bytesBuffer) | 
					
						
							| 
									
										
										
										
											2015-09-10 06:11:37 +08:00
										 |  |  | 	e.Encode(response) | 
					
						
							| 
									
										
										
										
											2015-02-11 19:23:15 +08:00
										 |  |  | 	return bytesBuffer.Bytes() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-23 06:54:55 +08:00
										 |  |  | // Encodes the response headers into JSON format.
 | 
					
						
							|  |  |  | func encodeResponseJSON(response interface{}) []byte { | 
					
						
							|  |  |  | 	var bytesBuffer bytes.Buffer | 
					
						
							|  |  |  | 	e := json.NewEncoder(&bytesBuffer) | 
					
						
							|  |  |  | 	e.Encode(response) | 
					
						
							|  |  |  | 	return bytesBuffer.Bytes() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-24 08:46:48 +08:00
										 |  |  | // Write object header
 | 
					
						
							| 
									
										
										
										
											2018-09-21 10:22:09 +08:00
										 |  |  | func setObjectHeaders(w http.ResponseWriter, objInfo ObjectInfo, rs *HTTPRangeSpec) (err error) { | 
					
						
							| 
									
										
										
										
											2015-07-29 10:33:56 +08:00
										 |  |  | 	// set common headers
 | 
					
						
							| 
									
										
										
										
											2016-03-07 04:16:22 +08:00
										 |  |  | 	setCommonHeaders(w) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-23 11:31:45 +08:00
										 |  |  | 	// Set last modified time.
 | 
					
						
							| 
									
										
										
										
											2016-04-09 01:37:38 +08:00
										 |  |  | 	lastModified := objInfo.ModTime.UTC().Format(http.TimeFormat) | 
					
						
							| 
									
										
										
										
											2016-03-07 04:16:22 +08:00
										 |  |  | 	w.Header().Set("Last-Modified", lastModified) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-23 11:31:45 +08:00
										 |  |  | 	// Set Etag if available.
 | 
					
						
							| 
									
										
										
										
											2017-05-15 03:05:51 +08:00
										 |  |  | 	if objInfo.ETag != "" { | 
					
						
							|  |  |  | 		w.Header().Set("ETag", "\""+objInfo.ETag+"\"") | 
					
						
							| 
									
										
										
										
											2016-01-29 11:57:23 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-07-23 11:31:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-13 18:56:16 +08:00
										 |  |  | 	if objInfo.ContentType != "" { | 
					
						
							|  |  |  | 		w.Header().Set("Content-Type", objInfo.ContentType) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if objInfo.ContentEncoding != "" { | 
					
						
							|  |  |  | 		w.Header().Set("Content-Encoding", objInfo.ContentEncoding) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-23 11:31:45 +08:00
										 |  |  | 	// Set all other user defined metadata.
 | 
					
						
							| 
									
										
										
										
											2016-07-13 03:45:17 +08:00
										 |  |  | 	for k, v := range objInfo.UserDefined { | 
					
						
							| 
									
										
										
										
											2018-03-02 08:15:53 +08:00
										 |  |  | 		if hasPrefix(k, ReservedMetadataPrefix) { | 
					
						
							|  |  |  | 			// Do not need to send any internal metadata
 | 
					
						
							|  |  |  | 			// values to client.
 | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-07-21 03:40:20 +08:00
										 |  |  | 		w.Header().Set(k, v) | 
					
						
							| 
									
										
										
										
											2016-07-13 03:45:17 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-03-07 04:16:22 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-21 10:22:09 +08:00
										 |  |  | 	var totalObjectSize int64 | 
					
						
							|  |  |  | 	switch { | 
					
						
							|  |  |  | 	case crypto.IsEncrypted(objInfo.UserDefined): | 
					
						
							|  |  |  | 		totalObjectSize, err = objInfo.DecryptedSize() | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-09-28 11:36:17 +08:00
										 |  |  | 	case objInfo.IsCompressed(): | 
					
						
							|  |  |  | 		totalObjectSize = objInfo.GetActualSize() | 
					
						
							|  |  |  | 		if totalObjectSize < 0 { | 
					
						
							|  |  |  | 			return errInvalidDecompressedSize | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-09-21 10:22:09 +08:00
										 |  |  | 	default: | 
					
						
							|  |  |  | 		totalObjectSize = objInfo.Size | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-07 04:16:22 +08:00
										 |  |  | 	// for providing ranged content
 | 
					
						
							| 
									
										
										
										
											2018-09-21 10:22:09 +08:00
										 |  |  | 	start, rangeLen, err := rs.GetOffsetLength(totalObjectSize) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2015-07-29 10:33:56 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-09-21 10:22:09 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Set content length.
 | 
					
						
							|  |  |  | 	w.Header().Set("Content-Length", strconv.FormatInt(rangeLen, 10)) | 
					
						
							|  |  |  | 	if rs != nil { | 
					
						
							|  |  |  | 		contentRange := fmt.Sprintf("bytes %d-%d/%d", start, start+rangeLen-1, totalObjectSize) | 
					
						
							|  |  |  | 		w.Header().Set("Content-Range", contentRange) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2015-03-11 16:01:49 +08:00
										 |  |  | } |