mirror of
				https://github.com/minio/minio.git
				synced 2025-10-31 00:01:27 +01:00 
			
		
		
		
	Golang HTTP client automatically detects content-type but for S3 clients this content-type might be incorrect or might misbehave. For example: ``` Content-Type: text/xml; charset=utf-8 ``` Should be ``` Content-Type: application/xml ``` Allow this to be set properly.
		
			
				
	
	
		
			216 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			216 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
|  * Minio Cloud Storage, (C) 2016 Minio, Inc.
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  */
 | |
| 
 | |
| package cmd
 | |
| 
 | |
| import (
 | |
| 	"encoding/json"
 | |
| 	"net/http"
 | |
| 	"net/url"
 | |
| 	"time"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	minioAdminOpHeader = "X-Minio-Operation"
 | |
| )
 | |
| 
 | |
| // ServiceStatusHandler - GET /?service
 | |
| // HTTP header x-minio-operation: status
 | |
| // ----------
 | |
| // Fetches server status information like total disk space available
 | |
| // to use, online disks, offline disks and quorum threshold.
 | |
| func (adminAPI adminAPIHandlers) ServiceStatusHandler(w http.ResponseWriter, r *http.Request) {
 | |
| 	adminAPIErr := checkRequestAuthType(r, "", "", "")
 | |
| 	if adminAPIErr != ErrNone {
 | |
| 		writeErrorResponse(w, adminAPIErr, r.URL)
 | |
| 		return
 | |
| 	}
 | |
| 	storageInfo := newObjectLayerFn().StorageInfo()
 | |
| 	jsonBytes, err := json.Marshal(storageInfo)
 | |
| 	if err != nil {
 | |
| 		writeErrorResponse(w, ErrInternalError, r.URL)
 | |
| 		errorIf(err, "Failed to marshal storage info into json.")
 | |
| 		return
 | |
| 	}
 | |
| 	// Reply with storage information (across nodes in a
 | |
| 	// distributed setup) as json.
 | |
| 	writeSuccessResponseJSON(w, jsonBytes)
 | |
| }
 | |
| 
 | |
| // ServiceStopHandler - POST /?service
 | |
| // HTTP header x-minio-operation: stop
 | |
| // ----------
 | |
| // Stops minio server gracefully. In a distributed setup, stops all the
 | |
| // servers in the cluster.
 | |
| func (adminAPI adminAPIHandlers) ServiceStopHandler(w http.ResponseWriter, r *http.Request) {
 | |
| 	adminAPIErr := checkRequestAuthType(r, "", "", "")
 | |
| 	if adminAPIErr != ErrNone {
 | |
| 		writeErrorResponse(w, adminAPIErr, r.URL)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// Reply to the client before stopping minio server.
 | |
| 	w.WriteHeader(http.StatusOK)
 | |
| 
 | |
| 	sendServiceCmd(globalAdminPeers, serviceStop)
 | |
| }
 | |
| 
 | |
| // ServiceRestartHandler - POST /?service
 | |
| // HTTP header x-minio-operation: restart
 | |
| // ----------
 | |
| // Restarts minio server gracefully. In a distributed setup,  restarts
 | |
| // all the servers in the cluster.
 | |
| func (adminAPI adminAPIHandlers) ServiceRestartHandler(w http.ResponseWriter, r *http.Request) {
 | |
| 	adminAPIErr := checkRequestAuthType(r, "", "", "")
 | |
| 	if adminAPIErr != ErrNone {
 | |
| 		writeErrorResponse(w, adminAPIErr, r.URL)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// Reply to the client before restarting minio server.
 | |
| 	w.WriteHeader(http.StatusOK)
 | |
| 
 | |
| 	sendServiceCmd(globalAdminPeers, serviceRestart)
 | |
| }
 | |
| 
 | |
| // Type-safe lock query params.
 | |
| type lockQueryKey string
 | |
| 
 | |
| // Only valid query params for list/clear locks management APIs.
 | |
| const (
 | |
| 	lockBucket    lockQueryKey = "bucket"
 | |
| 	lockPrefix    lockQueryKey = "prefix"
 | |
| 	lockOlderThan lockQueryKey = "older-than"
 | |
| )
 | |
| 
 | |
| // validateLockQueryParams - Validates query params for list/clear locks management APIs.
 | |
| func validateLockQueryParams(vars url.Values) (string, string, time.Duration, APIErrorCode) {
 | |
| 	bucket := vars.Get(string(lockBucket))
 | |
| 	prefix := vars.Get(string(lockPrefix))
 | |
| 	relTimeStr := vars.Get(string(lockOlderThan))
 | |
| 
 | |
| 	// N B empty bucket name is invalid
 | |
| 	if !IsValidBucketName(bucket) {
 | |
| 		return "", "", time.Duration(0), ErrInvalidBucketName
 | |
| 	}
 | |
| 
 | |
| 	// empty prefix is valid.
 | |
| 	if !IsValidObjectPrefix(prefix) {
 | |
| 		return "", "", time.Duration(0), ErrInvalidObjectName
 | |
| 	}
 | |
| 
 | |
| 	// If older-than parameter was empty then set it to 0s to list
 | |
| 	// all locks older than now.
 | |
| 	if relTimeStr == "" {
 | |
| 		relTimeStr = "0s"
 | |
| 	}
 | |
| 	relTime, err := time.ParseDuration(relTimeStr)
 | |
| 	if err != nil {
 | |
| 		errorIf(err, "Failed to parse duration passed as query value.")
 | |
| 		return "", "", time.Duration(0), ErrInvalidDuration
 | |
| 	}
 | |
| 
 | |
| 	return bucket, prefix, relTime, ErrNone
 | |
| }
 | |
| 
 | |
| // ListLocksHandler - GET /?lock&bucket=mybucket&prefix=myprefix&older-than=rel_time
 | |
| // - bucket is a mandatory query parameter
 | |
| // - prefix and older-than are optional query parameters
 | |
| // HTTP header x-minio-operation: list
 | |
| // ---------
 | |
| // Lists locks held on a given bucket, prefix and relative time.
 | |
| func (adminAPI adminAPIHandlers) ListLocksHandler(w http.ResponseWriter, r *http.Request) {
 | |
| 	adminAPIErr := checkRequestAuthType(r, "", "", "")
 | |
| 	if adminAPIErr != ErrNone {
 | |
| 		writeErrorResponse(w, adminAPIErr, r.URL)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	vars := r.URL.Query()
 | |
| 	bucket, prefix, relTime, adminAPIErr := validateLockQueryParams(vars)
 | |
| 	if adminAPIErr != ErrNone {
 | |
| 		writeErrorResponse(w, adminAPIErr, r.URL)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// Fetch lock information of locks matching bucket/prefix that
 | |
| 	// are available since relTime.
 | |
| 	volLocks, err := listPeerLocksInfo(globalAdminPeers, bucket, prefix, relTime)
 | |
| 	if err != nil {
 | |
| 		writeErrorResponse(w, ErrInternalError, r.URL)
 | |
| 		errorIf(err, "Failed to fetch lock information from remote nodes.")
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// Marshal list of locks as json.
 | |
| 	jsonBytes, err := json.Marshal(volLocks)
 | |
| 	if err != nil {
 | |
| 		writeErrorResponse(w, ErrInternalError, r.URL)
 | |
| 		errorIf(err, "Failed to marshal lock information into json.")
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// Reply with list of locks held on bucket, matching prefix
 | |
| 	// older than relTime supplied, as json.
 | |
| 	writeSuccessResponseJSON(w, jsonBytes)
 | |
| }
 | |
| 
 | |
| // ClearLocksHandler - POST /?lock&bucket=mybucket&prefix=myprefix&older-than=relTime
 | |
| // - bucket is a mandatory query parameter
 | |
| // - prefix and older-than are optional query parameters
 | |
| // HTTP header x-minio-operation: clear
 | |
| // ---------
 | |
| // Clear locks held on a given bucket, prefix and relative time.
 | |
| func (adminAPI adminAPIHandlers) ClearLocksHandler(w http.ResponseWriter, r *http.Request) {
 | |
| 	adminAPIErr := checkRequestAuthType(r, "", "", "")
 | |
| 	if adminAPIErr != ErrNone {
 | |
| 		writeErrorResponse(w, adminAPIErr, r.URL)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	vars := r.URL.Query()
 | |
| 	bucket, prefix, relTime, adminAPIErr := validateLockQueryParams(vars)
 | |
| 	if adminAPIErr != ErrNone {
 | |
| 		writeErrorResponse(w, adminAPIErr, r.URL)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// Fetch lock information of locks matching bucket/prefix that
 | |
| 	// are available since relTime.
 | |
| 	volLocks, err := listPeerLocksInfo(globalAdminPeers, bucket, prefix, relTime)
 | |
| 	if err != nil {
 | |
| 		writeErrorResponse(w, ErrInternalError, r.URL)
 | |
| 		errorIf(err, "Failed to fetch lock information from remote nodes.")
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// Marshal list of locks as json.
 | |
| 	jsonBytes, err := json.Marshal(volLocks)
 | |
| 	if err != nil {
 | |
| 		writeErrorResponse(w, ErrInternalError, r.URL)
 | |
| 		errorIf(err, "Failed to marshal lock information into json.")
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// Remove lock matching bucket/prefix older than relTime.
 | |
| 	for _, volLock := range volLocks {
 | |
| 		globalNSMutex.ForceUnlock(volLock.Bucket, volLock.Object)
 | |
| 	}
 | |
| 
 | |
| 	// Reply with list of locks cleared, as json.
 | |
| 	writeSuccessResponseJSON(w, jsonBytes)
 | |
| }
 |