| 
									
										
										
										
											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/>.
 | 
					
						
							| 
									
										
										
										
											2019-07-20 04:20:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | package cmd | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"encoding/xml" | 
					
						
							|  |  |  | 	"io" | 
					
						
							|  |  |  | 	"net/http" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/gorilla/mux" | 
					
						
							| 
									
										
										
										
											2020-02-16 14:07:52 +08:00
										 |  |  | 	xhttp "github.com/minio/minio/cmd/http" | 
					
						
							| 
									
										
										
										
											2019-07-20 04:20:33 +08:00
										 |  |  | 	"github.com/minio/minio/cmd/logger" | 
					
						
							| 
									
										
										
										
											2020-01-28 06:12:34 +08:00
										 |  |  | 	"github.com/minio/minio/pkg/bucket/lifecycle" | 
					
						
							|  |  |  | 	"github.com/minio/minio/pkg/bucket/policy" | 
					
						
							| 
									
										
										
										
											2019-07-20 04:20:33 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	// Lifecycle configuration file.
 | 
					
						
							|  |  |  | 	bucketLifecycleConfig = "lifecycle.xml" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // PutBucketLifecycleHandler - This HTTP handler stores given bucket lifecycle configuration as per
 | 
					
						
							|  |  |  | // https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lifecycle-mgmt.html
 | 
					
						
							|  |  |  | func (api objectAPIHandlers) PutBucketLifecycleHandler(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 	ctx := newContext(r, w, "PutBucketLifecycle") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-27 05:21:51 +08:00
										 |  |  | 	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r)) | 
					
						
							| 
									
										
										
										
											2019-07-20 04:20:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	objAPI := api.ObjectAPI() | 
					
						
							|  |  |  | 	if objAPI == nil { | 
					
						
							| 
									
										
										
										
											2021-04-28 01:52:12 +08:00
										 |  |  | 		writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL) | 
					
						
							| 
									
										
										
										
											2019-07-20 04:20:33 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vars := mux.Vars(r) | 
					
						
							|  |  |  | 	bucket := vars["bucket"] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-16 14:07:52 +08:00
										 |  |  | 	// PutBucketLifecycle always needs a Content-Md5
 | 
					
						
							|  |  |  | 	if _, ok := r.Header[xhttp.ContentMD5]; !ok { | 
					
						
							| 
									
										
										
										
											2021-04-28 01:52:12 +08:00
										 |  |  | 		writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrMissingContentMD5), r.URL) | 
					
						
							| 
									
										
										
										
											2020-02-16 14:07:52 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-10 01:02:41 +08:00
										 |  |  | 	if s3Error := checkRequestAuthType(ctx, r, policy.PutBucketLifecycleAction, bucket, ""); s3Error != ErrNone { | 
					
						
							| 
									
										
										
										
											2021-04-28 01:52:12 +08:00
										 |  |  | 		writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL) | 
					
						
							| 
									
										
										
										
											2019-07-20 04:20:33 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Check if bucket exists.
 | 
					
						
							|  |  |  | 	if _, err := objAPI.GetBucketInfo(ctx, bucket); err != nil { | 
					
						
							| 
									
										
										
										
											2021-04-28 01:52:12 +08:00
										 |  |  | 		writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL) | 
					
						
							| 
									
										
										
										
											2019-07-20 04:20:33 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bucketLifecycle, err := lifecycle.ParseLifecycleConfig(io.LimitReader(r.Body, r.ContentLength)) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-04-28 01:52:12 +08:00
										 |  |  | 		writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL) | 
					
						
							| 
									
										
										
										
											2019-07-20 04:20:33 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-18 23:33:43 +08:00
										 |  |  | 	// Validate the received bucket policy document
 | 
					
						
							|  |  |  | 	if err = bucketLifecycle.Validate(); err != nil { | 
					
						
							| 
									
										
										
										
											2021-04-28 01:52:12 +08:00
										 |  |  | 		writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL) | 
					
						
							| 
									
										
										
										
											2020-05-18 23:33:43 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-13 04:12:09 +08:00
										 |  |  | 	// Validate the transition storage ARNs
 | 
					
						
							|  |  |  | 	if err = validateLifecycleTransition(ctx, bucket, bucketLifecycle); err != nil { | 
					
						
							| 
									
										
										
										
											2021-04-28 01:52:12 +08:00
										 |  |  | 		writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL) | 
					
						
							| 
									
										
										
										
											2020-11-13 04:12:09 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-20 04:53:54 +08:00
										 |  |  | 	configData, err := xml.Marshal(bucketLifecycle) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-04-28 01:52:12 +08:00
										 |  |  | 		writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL) | 
					
						
							| 
									
										
										
										
											2019-07-20 04:20:33 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-20 04:53:54 +08:00
										 |  |  | 	if err = globalBucketMetadataSys.Update(bucket, bucketLifecycleConfig, configData); err != nil { | 
					
						
							| 
									
										
										
										
											2021-04-28 01:52:12 +08:00
										 |  |  | 		writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL) | 
					
						
							| 
									
										
										
										
											2020-05-20 04:53:54 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-07-20 04:20:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Success.
 | 
					
						
							| 
									
										
										
										
											2019-12-17 23:39:49 +08:00
										 |  |  | 	writeSuccessResponseHeadersOnly(w) | 
					
						
							| 
									
										
										
										
											2019-07-20 04:20:33 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GetBucketLifecycleHandler - This HTTP handler returns bucket policy configuration.
 | 
					
						
							|  |  |  | func (api objectAPIHandlers) GetBucketLifecycleHandler(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 	ctx := newContext(r, w, "GetBucketLifecycle") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-27 05:21:51 +08:00
										 |  |  | 	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r)) | 
					
						
							| 
									
										
										
										
											2019-07-20 04:20:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	objAPI := api.ObjectAPI() | 
					
						
							|  |  |  | 	if objAPI == nil { | 
					
						
							| 
									
										
										
										
											2021-04-28 01:52:12 +08:00
										 |  |  | 		writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL) | 
					
						
							| 
									
										
										
										
											2019-07-20 04:20:33 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vars := mux.Vars(r) | 
					
						
							|  |  |  | 	bucket := vars["bucket"] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-10 01:02:41 +08:00
										 |  |  | 	if s3Error := checkRequestAuthType(ctx, r, policy.GetBucketLifecycleAction, bucket, ""); s3Error != ErrNone { | 
					
						
							| 
									
										
										
										
											2021-04-28 01:52:12 +08:00
										 |  |  | 		writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL) | 
					
						
							| 
									
										
										
										
											2019-07-20 04:20:33 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Check if bucket exists.
 | 
					
						
							|  |  |  | 	if _, err := objAPI.GetBucketInfo(ctx, bucket); err != nil { | 
					
						
							| 
									
										
										
										
											2021-04-28 01:52:12 +08:00
										 |  |  | 		writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL) | 
					
						
							| 
									
										
										
										
											2019-07-20 04:20:33 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-21 01:18:15 +08:00
										 |  |  | 	config, err := globalBucketMetadataSys.GetLifecycleConfig(bucket) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-04-28 01:52:12 +08:00
										 |  |  | 		writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL) | 
					
						
							| 
									
										
										
										
											2020-05-21 01:18:15 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	configData, err := xml.Marshal(config) | 
					
						
							| 
									
										
										
										
											2019-07-20 04:20:33 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-04-28 01:52:12 +08:00
										 |  |  | 		writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL) | 
					
						
							| 
									
										
										
										
											2019-07-20 04:20:33 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Write lifecycle configuration to client.
 | 
					
						
							| 
									
										
										
										
											2020-05-20 04:53:54 +08:00
										 |  |  | 	writeSuccessResponseXML(w, configData) | 
					
						
							| 
									
										
										
										
											2019-07-20 04:20:33 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // DeleteBucketLifecycleHandler - This HTTP handler removes bucket lifecycle configuration.
 | 
					
						
							|  |  |  | func (api objectAPIHandlers) DeleteBucketLifecycleHandler(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 	ctx := newContext(r, w, "DeleteBucketLifecycle") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-27 05:21:51 +08:00
										 |  |  | 	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r)) | 
					
						
							| 
									
										
										
										
											2019-07-20 04:20:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	objAPI := api.ObjectAPI() | 
					
						
							|  |  |  | 	if objAPI == nil { | 
					
						
							| 
									
										
										
										
											2021-04-28 01:52:12 +08:00
										 |  |  | 		writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL) | 
					
						
							| 
									
										
										
										
											2019-07-20 04:20:33 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vars := mux.Vars(r) | 
					
						
							|  |  |  | 	bucket := vars["bucket"] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-10 01:02:41 +08:00
										 |  |  | 	if s3Error := checkRequestAuthType(ctx, r, policy.PutBucketLifecycleAction, bucket, ""); s3Error != ErrNone { | 
					
						
							| 
									
										
										
										
											2021-04-28 01:52:12 +08:00
										 |  |  | 		writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL) | 
					
						
							| 
									
										
										
										
											2019-07-20 04:20:33 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Check if bucket exists.
 | 
					
						
							|  |  |  | 	if _, err := objAPI.GetBucketInfo(ctx, bucket); err != nil { | 
					
						
							| 
									
										
										
										
											2021-04-28 01:52:12 +08:00
										 |  |  | 		writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL) | 
					
						
							| 
									
										
										
										
											2019-07-20 04:20:33 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-20 04:53:54 +08:00
										 |  |  | 	if err := globalBucketMetadataSys.Update(bucket, bucketLifecycleConfig, nil); err != nil { | 
					
						
							| 
									
										
										
										
											2021-04-28 01:52:12 +08:00
										 |  |  | 		writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL) | 
					
						
							| 
									
										
										
										
											2019-07-20 04:20:33 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Success.
 | 
					
						
							|  |  |  | 	writeSuccessNoContent(w) | 
					
						
							|  |  |  | } |