mirror of
https://github.com/pgsty/minio.git
synced 2026-07-20 20:50:22 +03:00
feat: Deprecate embedded browser and import console (#12460)
This feature also changes the default port where the browser is running, now the port has moved to 9001 and it can be configured with ``` --console-address ":9001" ```
This commit is contained in:
+44
-58
@@ -19,7 +19,9 @@ package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
@@ -64,7 +66,7 @@ const (
|
||||
func setRequestHeaderSizeLimitHandler(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if isHTTPHeaderSizeTooLarge(r.Header) {
|
||||
writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrMetadataTooLarge), r.URL, guessIsBrowserReq(r))
|
||||
writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrMetadataTooLarge), r.URL)
|
||||
atomic.AddUint64(&globalHTTPStats.rejectedRequestsHeader, 1)
|
||||
return
|
||||
}
|
||||
@@ -105,7 +107,7 @@ const (
|
||||
func filterReservedMetadata(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if containsReservedMetadata(r.Header) {
|
||||
writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrUnsupportedMetadata), r.URL, guessIsBrowserReq(r))
|
||||
writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrUnsupportedMetadata), r.URL)
|
||||
return
|
||||
}
|
||||
h.ServeHTTP(w, r)
|
||||
@@ -149,15 +151,22 @@ func setRedirectHandler(h http.Handler) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
func guessIsBrowserReq(r *http.Request) bool {
|
||||
aType := getRequestAuthType(r)
|
||||
ok := strings.Contains(r.Header.Get("User-Agent"), "Mozilla") && globalBrowserEnabled &&
|
||||
(aType == authTypeJWT || aType == authTypeAnonymous)
|
||||
return ok
|
||||
}
|
||||
|
||||
func setBrowserRedirectHandler(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Re-direction is handled specifically for browser requests.
|
||||
if globalBrowserEnabled && guessIsBrowserReq(r) {
|
||||
if guessIsBrowserReq(r) {
|
||||
// Fetch the redirect location if any.
|
||||
redirectLocation := getRedirectLocation(r.URL.Path)
|
||||
if redirectLocation != "" {
|
||||
u := getRedirectLocation(r)
|
||||
if u != nil {
|
||||
// Employ a temporary re-direct.
|
||||
http.Redirect(w, r, redirectLocation, http.StatusTemporaryRedirect)
|
||||
http.Redirect(w, r, u.String(), http.StatusTemporaryRedirect)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -174,9 +183,22 @@ func shouldProxy() bool {
|
||||
// redirectable, this is purely internal function and
|
||||
// serves only limited purpose on redirect-handler for
|
||||
// browser requests.
|
||||
func getRedirectLocation(urlPath string) (rLocation string) {
|
||||
func getRedirectLocation(r *http.Request) *url.URL {
|
||||
hostname, _, _ := net.SplitHostPort(r.Host)
|
||||
if hostname == "" {
|
||||
hostname = r.Host
|
||||
}
|
||||
var rurl = &url.URL{
|
||||
Host: net.JoinHostPort(hostname, globalMinioConsolePort),
|
||||
}
|
||||
urlPath := r.URL.Path
|
||||
scheme := "http"
|
||||
if r.TLS != nil {
|
||||
scheme = "https"
|
||||
}
|
||||
rurl.Scheme = scheme
|
||||
if urlPath == minioReservedBucketPath {
|
||||
rLocation = minioReservedBucketPath + SlashSeparator
|
||||
rurl.Path = minioReservedBucketPath + SlashSeparator
|
||||
}
|
||||
if contains([]string{
|
||||
SlashSeparator,
|
||||
@@ -186,24 +208,9 @@ func getRedirectLocation(urlPath string) (rLocation string) {
|
||||
"/favicon-32x32.png",
|
||||
"/favicon-96x96.png",
|
||||
}, urlPath) {
|
||||
rLocation = minioReservedBucketPath + urlPath
|
||||
rurl.Path = minioReservedBucketPath + urlPath
|
||||
}
|
||||
return rLocation
|
||||
}
|
||||
|
||||
// guessIsBrowserReq - returns true if the request is browser.
|
||||
// This implementation just validates user-agent and
|
||||
// looks for "Mozilla" string. This is no way certifiable
|
||||
// way to know if the request really came from a browser
|
||||
// since User-Agent's can be arbitrary. But this is just
|
||||
// a best effort function.
|
||||
func guessIsBrowserReq(req *http.Request) bool {
|
||||
if req == nil {
|
||||
return false
|
||||
}
|
||||
aType := getRequestAuthType(req)
|
||||
return strings.Contains(req.Header.Get("User-Agent"), "Mozilla") && globalBrowserEnabled &&
|
||||
(aType == authTypeJWT || aType == authTypeAnonymous)
|
||||
return rurl
|
||||
}
|
||||
|
||||
// guessIsHealthCheckReq - returns true if incoming request looks
|
||||
@@ -242,27 +249,6 @@ func guessIsRPCReq(req *http.Request) bool {
|
||||
strings.HasPrefix(req.URL.Path, minioReservedBucketPath+SlashSeparator)
|
||||
}
|
||||
|
||||
// Adds Cache-Control header
|
||||
func setBrowserCacheControlHandler(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if globalBrowserEnabled && r.Method == http.MethodGet && guessIsBrowserReq(r) {
|
||||
// For all browser requests set appropriate Cache-Control policies
|
||||
if HasPrefix(r.URL.Path, minioReservedBucketPath+SlashSeparator) {
|
||||
if HasSuffix(r.URL.Path, ".js") || r.URL.Path == minioReservedBucketPath+"/favicon.ico" {
|
||||
// For assets set cache expiry of one year. For each release, the name
|
||||
// of the asset name will change and hence it can not be served from cache.
|
||||
w.Header().Set(xhttp.CacheControl, "max-age=31536000")
|
||||
} else {
|
||||
// For non asset requests we serve index.html which will never be cached.
|
||||
w.Header().Set(xhttp.CacheControl, "no-store")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// Check to allow access to the reserved "bucket" `/minio` for Admin
|
||||
// API requests.
|
||||
func isAdminReq(r *http.Request) bool {
|
||||
@@ -276,7 +262,7 @@ func setReservedBucketHandler(h http.Handler) http.Handler {
|
||||
bucketName, _ := request2BucketObjectName(r)
|
||||
if isMinioReservedBucket(bucketName) || isMinioMetaBucket(bucketName) {
|
||||
if !guessIsRPCReq(r) && !guessIsBrowserReq(r) && !guessIsHealthCheckReq(r) && !guessIsMetricsReq(r) && !isAdminReq(r) {
|
||||
writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrAllAccessDisabled), r.URL, guessIsBrowserReq(r))
|
||||
writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrAllAccessDisabled), r.URL)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -333,7 +319,7 @@ func setTimeValidityHandler(h http.Handler) http.Handler {
|
||||
// All our internal APIs are sensitive towards Date
|
||||
// header, for all requests where Date header is not
|
||||
// present we will reject such clients.
|
||||
writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(errCode), r.URL, guessIsBrowserReq(r))
|
||||
writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(errCode), r.URL)
|
||||
atomic.AddUint64(&globalHTTPStats.rejectedRequestsTime, 1)
|
||||
return
|
||||
}
|
||||
@@ -341,7 +327,7 @@ func setTimeValidityHandler(h http.Handler) http.Handler {
|
||||
// or in the future, reject request otherwise.
|
||||
curTime := UTCNow()
|
||||
if curTime.Sub(amzDate) > globalMaxSkewTime || amzDate.Sub(curTime) > globalMaxSkewTime {
|
||||
writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrRequestTimeTooSkewed), r.URL, guessIsBrowserReq(r))
|
||||
writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrRequestTimeTooSkewed), r.URL)
|
||||
atomic.AddUint64(&globalHTTPStats.rejectedRequestsTime, 1)
|
||||
return
|
||||
}
|
||||
@@ -409,7 +395,7 @@ func setRequestValidityHandler(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Check for bad components in URL path.
|
||||
if hasBadPathComponent(r.URL.Path) {
|
||||
writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrInvalidResourceName), r.URL, guessIsBrowserReq(r))
|
||||
writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrInvalidResourceName), r.URL)
|
||||
atomic.AddUint64(&globalHTTPStats.rejectedRequestsInvalid, 1)
|
||||
return
|
||||
}
|
||||
@@ -417,14 +403,14 @@ func setRequestValidityHandler(h http.Handler) http.Handler {
|
||||
for _, vv := range r.URL.Query() {
|
||||
for _, v := range vv {
|
||||
if hasBadPathComponent(v) {
|
||||
writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrInvalidResourceName), r.URL, guessIsBrowserReq(r))
|
||||
writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrInvalidResourceName), r.URL)
|
||||
atomic.AddUint64(&globalHTTPStats.rejectedRequestsInvalid, 1)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if hasMultipleAuth(r) {
|
||||
writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL, guessIsBrowserReq(r))
|
||||
writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL)
|
||||
atomic.AddUint64(&globalHTTPStats.rejectedRequestsInvalid, 1)
|
||||
return
|
||||
}
|
||||
@@ -468,10 +454,10 @@ func setBucketForwardingHandler(h http.Handler) http.Handler {
|
||||
if err != nil {
|
||||
if err == dns.ErrNoEntriesFound {
|
||||
writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrNoSuchBucket),
|
||||
r.URL, guessIsBrowserReq(r))
|
||||
r.URL)
|
||||
} else {
|
||||
writeErrorResponse(r.Context(), w, toAPIError(r.Context(), err),
|
||||
r.URL, guessIsBrowserReq(r))
|
||||
r.URL)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -524,9 +510,9 @@ func setBucketForwardingHandler(h http.Handler) http.Handler {
|
||||
sr, err := globalDNSConfig.Get(bucket)
|
||||
if err != nil {
|
||||
if err == dns.ErrNoEntriesFound {
|
||||
writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrNoSuchBucket), r.URL, guessIsBrowserReq(r))
|
||||
writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrNoSuchBucket), r.URL)
|
||||
} else {
|
||||
writeErrorResponse(r.Context(), w, toAPIError(r.Context(), err), r.URL, guessIsBrowserReq(r))
|
||||
writeErrorResponse(r.Context(), w, toAPIError(r.Context(), err), r.URL)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -579,7 +565,7 @@ type criticalErrorHandler struct{ handler http.Handler }
|
||||
func (h criticalErrorHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
if err := recover(); err == logger.ErrCritical { // handle
|
||||
writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrInternalError), r.URL, guessIsBrowserReq(r))
|
||||
writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrInternalError), r.URL)
|
||||
return
|
||||
} else if err != nil {
|
||||
panic(err) // forward other panic calls
|
||||
@@ -596,7 +582,7 @@ func setSSETLSHandler(h http.Handler) http.Handler {
|
||||
if r.Method == http.MethodHead {
|
||||
writeErrorResponseHeadersOnly(w, errorCodes.ToAPIErr(ErrInsecureSSECustomerRequest))
|
||||
} else {
|
||||
writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrInsecureSSECustomerRequest), r.URL, guessIsBrowserReq(r))
|
||||
writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrInsecureSSECustomerRequest), r.URL)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user