2021-04-18 15:41:13 -04: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/>.
2016-04-28 23:01:11 -04:00
2016-08-18 19:23:42 -04:00
package cmd
2016-04-28 23:01:11 -04:00
import (
2018-04-05 18:04:40 -04:00
"context"
2020-08-31 15:37:31 -04:00
"errors"
2019-11-04 12:30:59 -05:00
"fmt"
2016-07-19 00:20:17 -04:00
"net/http"
2021-02-03 23:41:33 -05:00
"net/textproto"
2019-11-04 12:30:59 -05:00
"regexp"
2016-07-22 23:31:45 -04:00
"strings"
2017-10-24 22:04:51 -04:00
2023-06-19 20:53:08 -04:00
"github.com/minio/madmin-go/v3"
2021-06-01 17:59:40 -04:00
"github.com/minio/minio/internal/auth"
"github.com/minio/minio/internal/handlers"
xhttp "github.com/minio/minio/internal/http"
"github.com/minio/minio/internal/logger"
2023-04-12 17:37:19 -04:00
"github.com/minio/minio/internal/mcontext"
2023-09-04 15:57:37 -04:00
xnet "github.com/minio/pkg/v2/net"
2024-03-28 13:44:56 -04:00
"golang.org/x/exp/maps"
"golang.org/x/exp/slices"
2020-01-20 11:45:59 -05:00
)
const (
copyDirective = "COPY"
replaceDirective = "REPLACE"
2023-07-22 10:19:43 -04:00
accessDirective = "ACCESS"
2016-04-28 23:01:11 -04:00
)
2017-04-03 17:50:09 -04:00
// Parses location constraint from the incoming reader.
func parseLocationConstraint ( r * http . Request ) ( location string , s3Error APIErrorCode ) {
2016-07-19 00:20:17 -04:00
// If the request has no body with content-length set to 0,
// we do not have to validate location constraint. Bucket will
// be created at default region.
locationConstraint := createBucketLocationConfiguration { }
2016-09-29 18:51:00 -04:00
err := xmlDecoder ( r . Body , & locationConstraint , r . ContentLength )
2019-01-31 10:19:09 -05:00
if err != nil && r . ContentLength != 0 {
2023-06-24 23:29:13 -04:00
logger . LogOnceIf ( GlobalContext , err , "location-constraint-xml-parsing" )
2017-04-03 17:50:09 -04:00
// Treat all other failures as XML parsing errors.
return "" , ErrMalformedXML
} // else for both err as nil or io.EOF
location = locationConstraint . Location
if location == "" {
2021-11-25 16:06:25 -05:00
location = globalSite . Region
2016-04-28 23:01:11 -04:00
}
2023-02-24 21:39:20 -05:00
if ! isValidLocation ( location ) {
return location , ErrInvalidRegion
}
2017-04-03 17:50:09 -04:00
return location , ErrNone
}
// Validates input location is same as configured region
2019-04-09 14:39:42 -04:00
// of MinIO server.
2017-04-03 17:50:09 -04:00
func isValidLocation ( location string ) bool {
2021-11-25 16:06:25 -05:00
return globalSite . Region == "" || globalSite . Region == location
2016-04-28 23:01:11 -04:00
}
2016-07-22 23:31:45 -04:00
// Supported headers that needs to be extracted.
var supportedHeaders = [ ] string {
"content-type" ,
"cache-control" ,
2018-03-14 05:57:32 -04:00
"content-language" ,
2016-07-22 23:31:45 -04:00
"content-encoding" ,
"content-disposition" ,
2021-02-03 23:41:33 -05:00
"x-amz-storage-class" ,
2019-10-07 01:50:24 -04:00
xhttp . AmzStorageClass ,
2020-01-20 11:45:59 -05:00
xhttp . AmzObjectTagging ,
2018-03-28 17:14:06 -04:00
"expires" ,
2020-07-21 20:49:56 -04:00
xhttp . AmzBucketReplicationStatus ,
2024-03-28 13:44:56 -04:00
"X-Minio-Replication-Server-Side-Encryption-Sealed-Key" ,
"X-Minio-Replication-Server-Side-Encryption-Seal-Algorithm" ,
"X-Minio-Replication-Server-Side-Encryption-Iv" ,
"X-Minio-Replication-Encrypted-Multipart" ,
"X-Minio-Replication-Actual-Object-Size" ,
// Add more supported headers here.
}
// mapping of internal headers to allowed replication headers
var validSSEReplicationHeaders = map [ string ] string {
"X-Minio-Internal-Server-Side-Encryption-Sealed-Key" : "X-Minio-Replication-Server-Side-Encryption-Sealed-Key" ,
"X-Minio-Internal-Server-Side-Encryption-Seal-Algorithm" : "X-Minio-Replication-Server-Side-Encryption-Seal-Algorithm" ,
"X-Minio-Internal-Server-Side-Encryption-Iv" : "X-Minio-Replication-Server-Side-Encryption-Iv" ,
"X-Minio-Internal-Encrypted-Multipart" : "X-Minio-Replication-Encrypted-Multipart" ,
"X-Minio-Internal-Actual-Object-Size" : "X-Minio-Replication-Actual-Object-Size" ,
// Add more supported headers here.
}
// mapping of replication headers to internal headers
var replicationToInternalHeaders = map [ string ] string {
"X-Minio-Replication-Server-Side-Encryption-Sealed-Key" : "X-Minio-Internal-Server-Side-Encryption-Sealed-Key" ,
"X-Minio-Replication-Server-Side-Encryption-Seal-Algorithm" : "X-Minio-Internal-Server-Side-Encryption-Seal-Algorithm" ,
"X-Minio-Replication-Server-Side-Encryption-Iv" : "X-Minio-Internal-Server-Side-Encryption-Iv" ,
"X-Minio-Replication-Encrypted-Multipart" : "X-Minio-Internal-Encrypted-Multipart" ,
"X-Minio-Replication-Actual-Object-Size" : "X-Minio-Internal-Actual-Object-Size" ,
2016-07-22 23:31:45 -04:00
// Add more supported headers here.
}
2020-01-20 11:45:59 -05:00
// isDirectiveValid - check if tagging-directive is valid.
func isDirectiveValid ( v string ) bool {
// Check if set metadata-directive is valid.
return isDirectiveCopy ( v ) || isDirectiveReplace ( v )
2016-12-26 19:29:26 -05:00
}
2020-01-20 11:45:59 -05:00
// Check if the directive COPY is requested.
func isDirectiveCopy ( value string ) bool {
// By default if directive is not set we
// treat it as 'COPY' this function returns true.
return value == copyDirective || value == ""
2016-12-26 19:29:26 -05:00
}
2020-01-20 11:45:59 -05:00
// Check if the directive REPLACE is requested.
func isDirectiveReplace ( value string ) bool {
return value == replaceDirective
2016-12-26 19:29:26 -05:00
}
2017-08-22 19:53:35 -04:00
// userMetadataKeyPrefixes contains the prefixes of used-defined metadata keys.
// All values stored with a key starting with one of the following prefixes
// must be extracted from the header.
var userMetadataKeyPrefixes = [ ] string {
2020-05-25 19:51:32 -04:00
"x-amz-meta-" ,
"x-minio-meta-" ,
2017-08-22 19:53:35 -04:00
}
2023-11-22 13:51:46 -05:00
// extractMetadataFromReq extracts metadata from HTTP header and HTTP queryString.
func extractMetadataFromReq ( ctx context . Context , r * http . Request ) ( metadata map [ string ] string , err error ) {
return extractMetadata ( ctx , textproto . MIMEHeader ( r . Form ) , textproto . MIMEHeader ( r . Header ) )
}
func extractMetadata ( ctx context . Context , mimesHeader ... textproto . MIMEHeader ) ( metadata map [ string ] string , err error ) {
2018-07-10 23:27:10 -04:00
metadata = make ( map [ string ] string )
2023-11-22 13:51:46 -05:00
for _ , hdr := range mimesHeader {
// Extract all query values.
err = extractMetadataFromMime ( ctx , hdr , metadata )
if err != nil {
return nil , err
}
2017-03-13 17:41:13 -04:00
}
2017-12-22 06:28:13 -05:00
2018-12-19 17:31:45 -05:00
// Set content-type to default value if it is not set.
2020-07-08 20:36:56 -04:00
if _ , ok := metadata [ strings . ToLower ( xhttp . ContentType ) ] ; ! ok {
2021-02-10 11:56:37 -05:00
metadata [ strings . ToLower ( xhttp . ContentType ) ] = "binary/octet-stream"
2018-12-19 17:31:45 -05:00
}
2020-07-08 20:36:56 -04:00
2020-08-11 11:29:29 -04:00
// https://github.com/google/security-research/security/advisories/GHSA-76wf-9vgp-pj7w
for k := range metadata {
2021-02-03 23:41:33 -05:00
if equals ( k , xhttp . AmzMetaUnencryptedContentLength , xhttp . AmzMetaUnencryptedContentMD5 ) {
2020-08-11 11:29:29 -04:00
delete ( metadata , k )
}
}
2020-07-08 20:36:56 -04:00
if contentEncoding , ok := metadata [ strings . ToLower ( xhttp . ContentEncoding ) ] ; ok {
contentEncoding = trimAwsChunkedContentEncoding ( contentEncoding )
if contentEncoding != "" {
// Make sure to trim and save the content-encoding
// parameter for a streaming signature which is set
// to a custom value for example: "aws-chunked,gzip".
metadata [ strings . ToLower ( xhttp . ContentEncoding ) ] = contentEncoding
} else {
// Trimmed content encoding is empty when the header
// value is set to "aws-chunked" only.
// Make sure to delete the content-encoding parameter
// for a streaming signature which is set to value
// for example: "aws-chunked"
delete ( metadata , strings . ToLower ( xhttp . ContentEncoding ) )
}
}
2018-07-10 23:27:10 -04:00
// Success.
return metadata , nil
}
// extractMetadata extracts metadata from map values.
2021-02-03 23:41:33 -05:00
func extractMetadataFromMime ( ctx context . Context , v textproto . MIMEHeader , m map [ string ] string ) error {
2018-07-10 23:27:10 -04:00
if v == nil {
logger . LogIf ( ctx , errInvalidArgument )
return errInvalidArgument
}
2021-02-03 23:41:33 -05:00
nv := make ( textproto . MIMEHeader , len ( v ) )
for k , kv := range v {
// Canonicalize all headers, to remove any duplicates.
nv [ http . CanonicalHeaderKey ( k ) ] = kv
}
2017-12-22 06:28:13 -05:00
// Save all supported headers.
2016-07-22 23:31:45 -04:00
for _ , supportedHeader := range supportedHeaders {
2021-02-03 23:41:33 -05:00
value , ok := nv [ http . CanonicalHeaderKey ( supportedHeader ) ]
if ok {
2024-03-28 13:44:56 -04:00
if slices . Contains ( maps . Keys ( replicationToInternalHeaders ) , supportedHeader ) {
m [ replicationToInternalHeaders [ supportedHeader ] ] = strings . Join ( value , "," )
} else {
m [ supportedHeader ] = strings . Join ( value , "," )
}
2016-07-22 23:31:45 -04:00
}
}
2021-02-03 23:41:33 -05:00
2018-07-10 23:27:10 -04:00
for key := range v {
2017-08-22 19:53:35 -04:00
for _ , prefix := range userMetadataKeyPrefixes {
2023-07-06 19:02:08 -04:00
if ! stringsHasPrefixFold ( key , prefix ) {
2018-07-10 23:27:10 -04:00
continue
}
2021-02-03 23:41:33 -05:00
value , ok := nv [ http . CanonicalHeaderKey ( key ) ]
2018-07-10 23:27:10 -04:00
if ok {
2018-07-12 12:40:14 -04:00
m [ key ] = strings . Join ( value , "," )
2017-08-22 19:53:35 -04:00
break
}
2016-07-22 23:31:45 -04:00
}
}
2018-07-10 23:27:10 -04:00
return nil
2016-12-19 19:14:04 -05:00
}
2018-11-29 20:35:11 -05:00
// Returns access credentials in the request Authorization header.
func getReqAccessCred ( r * http . Request , region string ) ( cred auth . Credentials ) {
2019-02-27 20:46:55 -05:00
cred , _ , _ = getReqAccessKeyV4 ( r , region , serviceS3 )
2018-11-07 09:40:03 -05:00
if cred . AccessKey == "" {
cred , _ , _ = getReqAccessKeyV2 ( r )
2018-11-02 21:40:08 -04:00
}
2018-11-29 20:35:11 -05:00
return cred
2018-11-02 21:40:08 -04:00
}
2024-01-18 02:03:17 -05:00
// Extract request params to be sent with event notification.
2017-03-13 17:41:13 -04:00
func extractReqParams ( r * http . Request ) map [ string ] string {
if r == nil {
return nil
2016-12-19 19:14:04 -05:00
}
2017-03-13 17:41:13 -04:00
2021-11-25 16:06:25 -05:00
region := globalSite . Region
2018-11-29 20:35:11 -05:00
cred := getReqAccessCred ( r , region )
2018-12-19 08:13:47 -05:00
2021-03-31 16:21:10 -04:00
principalID := cred . AccessKey
if cred . ParentUser != "" {
principalID = cred . ParentUser
}
2017-03-13 17:41:13 -04:00
// Success.
2021-03-03 14:13:31 -05:00
m := map [ string ] string {
2018-11-02 21:40:08 -04:00
"region" : region ,
2021-03-31 16:21:10 -04:00
"principalId" : principalID ,
2018-07-02 17:40:18 -04:00
"sourceIPAddress" : handlers . GetSourceIP ( r ) ,
2017-03-13 17:41:13 -04:00
// Add more fields here.
}
2022-05-02 13:37:26 -04:00
if rangeField := r . Header . Get ( xhttp . Range ) ; rangeField != "" {
m [ "range" ] = rangeField
}
2021-03-03 14:13:31 -05:00
if _ , ok := r . Header [ xhttp . MinIOSourceReplicationRequest ] ; ok {
m [ xhttp . MinIOSourceReplicationRequest ] = ""
}
return m
2017-03-13 17:41:13 -04:00
}
2024-01-18 02:03:17 -05:00
// Extract response elements to be sent with event notification.
2018-08-23 17:40:54 -04:00
func extractRespElements ( w http . ResponseWriter ) map [ string ] string {
2020-10-02 16:36:13 -04:00
if w == nil {
return map [ string ] string { }
}
2018-08-23 17:40:54 -04:00
return map [ string ] string {
2019-07-03 01:34:32 -04:00
"requestId" : w . Header ( ) . Get ( xhttp . AmzRequestID ) ,
2023-02-22 05:11:09 -05:00
"nodeId" : w . Header ( ) . Get ( xhttp . AmzRequestHostID ) ,
2019-07-03 01:34:32 -04:00
"content-length" : w . Header ( ) . Get ( xhttp . ContentLength ) ,
2018-08-23 17:40:54 -04:00
// Add more fields here.
}
}
2017-03-27 20:02:04 -04:00
// Trims away `aws-chunked` from the content-encoding header if present.
// Streaming signature clients can have custom content-encoding such as
// `aws-chunked,gzip` here we need to only save `gzip`.
// For more refer http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html
func trimAwsChunkedContentEncoding ( contentEnc string ) ( trimmedContentEnc string ) {
if contentEnc == "" {
return contentEnc
}
var newEncs [ ] string
for _ , enc := range strings . Split ( contentEnc , "," ) {
if enc != streamingContentEncoding {
newEncs = append ( newEncs , enc )
}
}
return strings . Join ( newEncs , "," )
}
2023-07-08 10:35:11 -04:00
func collectInternodeStats ( f http . HandlerFunc ) http . HandlerFunc {
return func ( w http . ResponseWriter , r * http . Request ) {
f . ServeHTTP ( w , r )
tc , ok := r . Context ( ) . Value ( mcontext . ContextTraceKey ) . ( * mcontext . TraceCtxt )
if ! ok || tc == nil {
return
}
globalConnStats . incInternodeInputBytes ( int64 ( tc . RequestRecorder . Size ( ) ) )
globalConnStats . incInternodeOutputBytes ( int64 ( tc . ResponseRecorder . Size ( ) ) )
}
}
2019-10-23 00:01:14 -04:00
func collectAPIStats ( api string , f http . HandlerFunc ) http . HandlerFunc {
return func ( w http . ResponseWriter , r * http . Request ) {
2023-06-21 12:41:59 -04:00
resource , err := getResource ( r . URL . Path , r . Host , globalDomainNames )
if err != nil {
defer logger . AuditLog ( r . Context ( ) , w , r , mustGetClaimsFromToken ( r ) )
apiErr := errorCodes . ToAPIErr ( ErrUnsupportedHostHeader )
apiErr . Description = fmt . Sprintf ( "%s: %v" , apiErr . Description , err )
writeErrorResponse ( r . Context ( ) , w , apiErr , r . URL )
return
}
bucket , _ := path2BucketObject ( resource )
2024-03-12 07:33:30 -04:00
meta , err := globalBucketMetadataSys . Get ( bucket ) // check if this bucket exists.
countBktStat := bucket != "" && bucket != minioReservedBucket && err == nil && ! meta . Created . IsZero ( )
2024-03-01 11:00:42 -05:00
if countBktStat {
2023-06-21 12:41:59 -04:00
globalBucketHTTPStats . updateHTTPStats ( bucket , api , nil )
}
2024-03-01 11:00:42 -05:00
globalHTTPStats . currentS3Requests . Inc ( api )
2023-03-31 12:37:29 -04:00
f . ServeHTTP ( w , r )
2024-03-01 11:00:42 -05:00
globalHTTPStats . currentS3Requests . Dec ( api )
2019-10-23 00:01:14 -04:00
2024-03-01 11:00:42 -05:00
tc , _ := r . Context ( ) . Value ( mcontext . ContextTraceKey ) . ( * mcontext . TraceCtxt )
2023-04-12 17:37:19 -04:00
if tc != nil {
globalHTTPStats . updateStats ( api , tc . ResponseRecorder )
globalConnStats . incS3InputBytes ( int64 ( tc . RequestRecorder . Size ( ) ) )
globalConnStats . incS3OutputBytes ( int64 ( tc . ResponseRecorder . Size ( ) ) )
2024-03-01 11:00:42 -05:00
if countBktStat {
2023-04-12 17:37:19 -04:00
globalBucketConnStats . incS3InputBytes ( bucket , int64 ( tc . RequestRecorder . Size ( ) ) )
globalBucketConnStats . incS3OutputBytes ( bucket , int64 ( tc . ResponseRecorder . Size ( ) ) )
2023-06-21 12:41:59 -04:00
globalBucketHTTPStats . updateHTTPStats ( bucket , api , tc . ResponseRecorder )
2023-04-12 17:37:19 -04:00
}
2023-03-31 12:37:29 -04:00
}
2019-10-23 00:01:14 -04:00
}
}
2017-11-14 19:56:24 -05:00
// Returns "/bucketName/objectName" for path-style or virtual-host-style requests.
2019-02-22 22:18:01 -05:00
func getResource ( path string , host string , domains [ ] string ) ( string , error ) {
if len ( domains ) == 0 {
2017-11-14 19:56:24 -05:00
return path , nil
}
fix: panic in browser redirect handler for unexpected r.Host (#14844)
```
panic: "GET /": invalid hostname
goroutine 148 [running]:
runtime/debug.Stack()
runtime/debug/stack.go:24 +0x65
github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1()
github.com/minio/minio/cmd/generic-handlers.go:469 +0x8e
panic({0x2201f00, 0xc001f1ddd0})
runtime/panic.go:1038 +0x215
github.com/minio/pkg/net.URL.String({{0x25aa417, 0x5}, {0x0, 0x0}, 0x0, {0xc000174380, 0xd7}, {0x0, 0x0}, {0x0, ...}, ...})
github.com/minio/pkg@v1.1.23/net/url.go:97 +0xfe
github.com/minio/minio/cmd.setBrowserRedirectHandler.func1({0x49af080, 0xc0003c20e0}, 0xc00002ea00)
github.com/minio/minio/cmd/generic-handlers.go:136 +0x118
net/http.HandlerFunc.ServeHTTP(0xc00002ea00, {0x49af080, 0xc0003c20e0}, 0xa)
net/http/server.go:2047 +0x2f
github.com/minio/minio/cmd.setAuthHandler.func1({0x49af080, 0xc0003c20e0}, 0xc00002ea00)
github.com/minio/minio/cmd/auth-handler.go:525 +0x3d8
net/http.HandlerFunc.ServeHTTP(0xc00002e900, {0x49af080, 0xc0003c20e0}, 0xc001f33701)
net/http/server.go:2047 +0x2f
github.com/gorilla/mux.(*Router).ServeHTTP(0xc0025d0780, {0x49af080, 0xc0003c20e0}, 0xc00002e800)
github.com/gorilla/mux@v1.8.0/mux.go:210 +0x1cf
github.com/rs/cors.(*Cors).Handler.func1({0x49af080, 0xc0003c20e0}, 0xc00002e800)
github.com/rs/cors@v1.7.0/cors.go:219 +0x1bd
net/http.HandlerFunc.ServeHTTP(0x0, {0x49af080, 0xc0003c20e0}, 0xc00068d9f8)
net/http/server.go:2047 +0x2f
github.com/minio/minio/cmd.setCriticalErrorHandler.func1({0x49af080, 0xc0003c20e0}, 0x4a5cd3)
github.com/minio/minio/cmd/generic-handlers.go:476 +0x83
net/http.HandlerFunc.ServeHTTP(0x72, {0x49af080, 0xc0003c20e0}, 0x0)
net/http/server.go:2047 +0x2f
github.com/minio/minio/internal/http.(*Server).Start.func1({0x49af080, 0xc0003c20e0}, 0x10000c001f1dda0)
github.com/minio/minio/internal/http/server.go:105 +0x1b6
net/http.HandlerFunc.ServeHTTP(0x0, {0x49af080, 0xc0003c20e0}, 0x46982e)
net/http/server.go:2047 +0x2f
net/http.serverHandler.ServeHTTP({0xc003dc1950}, {0x49af080, 0xc0003c20e0}, 0xc00002e800)
net/http/server.go:2879 +0x43b
net/http.(*conn).serve(0xc000514d20, {0x49cfc38, 0xc0010c0e70})
net/http/server.go:1930 +0xb08
created by net/http.(*Server).Serve
net/http/server.go:3034 +0x4e8
```
2022-05-01 16:45:45 -04:00
2017-11-14 19:56:24 -05:00
// If virtual-host-style is enabled construct the "resource" properly.
fix: panic in browser redirect handler for unexpected r.Host (#14844)
```
panic: "GET /": invalid hostname
goroutine 148 [running]:
runtime/debug.Stack()
runtime/debug/stack.go:24 +0x65
github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1()
github.com/minio/minio/cmd/generic-handlers.go:469 +0x8e
panic({0x2201f00, 0xc001f1ddd0})
runtime/panic.go:1038 +0x215
github.com/minio/pkg/net.URL.String({{0x25aa417, 0x5}, {0x0, 0x0}, 0x0, {0xc000174380, 0xd7}, {0x0, 0x0}, {0x0, ...}, ...})
github.com/minio/pkg@v1.1.23/net/url.go:97 +0xfe
github.com/minio/minio/cmd.setBrowserRedirectHandler.func1({0x49af080, 0xc0003c20e0}, 0xc00002ea00)
github.com/minio/minio/cmd/generic-handlers.go:136 +0x118
net/http.HandlerFunc.ServeHTTP(0xc00002ea00, {0x49af080, 0xc0003c20e0}, 0xa)
net/http/server.go:2047 +0x2f
github.com/minio/minio/cmd.setAuthHandler.func1({0x49af080, 0xc0003c20e0}, 0xc00002ea00)
github.com/minio/minio/cmd/auth-handler.go:525 +0x3d8
net/http.HandlerFunc.ServeHTTP(0xc00002e900, {0x49af080, 0xc0003c20e0}, 0xc001f33701)
net/http/server.go:2047 +0x2f
github.com/gorilla/mux.(*Router).ServeHTTP(0xc0025d0780, {0x49af080, 0xc0003c20e0}, 0xc00002e800)
github.com/gorilla/mux@v1.8.0/mux.go:210 +0x1cf
github.com/rs/cors.(*Cors).Handler.func1({0x49af080, 0xc0003c20e0}, 0xc00002e800)
github.com/rs/cors@v1.7.0/cors.go:219 +0x1bd
net/http.HandlerFunc.ServeHTTP(0x0, {0x49af080, 0xc0003c20e0}, 0xc00068d9f8)
net/http/server.go:2047 +0x2f
github.com/minio/minio/cmd.setCriticalErrorHandler.func1({0x49af080, 0xc0003c20e0}, 0x4a5cd3)
github.com/minio/minio/cmd/generic-handlers.go:476 +0x83
net/http.HandlerFunc.ServeHTTP(0x72, {0x49af080, 0xc0003c20e0}, 0x0)
net/http/server.go:2047 +0x2f
github.com/minio/minio/internal/http.(*Server).Start.func1({0x49af080, 0xc0003c20e0}, 0x10000c001f1dda0)
github.com/minio/minio/internal/http/server.go:105 +0x1b6
net/http.HandlerFunc.ServeHTTP(0x0, {0x49af080, 0xc0003c20e0}, 0x46982e)
net/http/server.go:2047 +0x2f
net/http.serverHandler.ServeHTTP({0xc003dc1950}, {0x49af080, 0xc0003c20e0}, 0xc00002e800)
net/http/server.go:2879 +0x43b
net/http.(*conn).serve(0xc000514d20, {0x49cfc38, 0xc0010c0e70})
net/http/server.go:1930 +0xb08
created by net/http.(*Server).Serve
net/http/server.go:3034 +0x4e8
```
2022-05-01 16:45:45 -04:00
xhost , err := xnet . ParseHost ( host )
if err != nil {
return "" , err
2017-11-14 19:56:24 -05:00
}
fix: panic in browser redirect handler for unexpected r.Host (#14844)
```
panic: "GET /": invalid hostname
goroutine 148 [running]:
runtime/debug.Stack()
runtime/debug/stack.go:24 +0x65
github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1()
github.com/minio/minio/cmd/generic-handlers.go:469 +0x8e
panic({0x2201f00, 0xc001f1ddd0})
runtime/panic.go:1038 +0x215
github.com/minio/pkg/net.URL.String({{0x25aa417, 0x5}, {0x0, 0x0}, 0x0, {0xc000174380, 0xd7}, {0x0, 0x0}, {0x0, ...}, ...})
github.com/minio/pkg@v1.1.23/net/url.go:97 +0xfe
github.com/minio/minio/cmd.setBrowserRedirectHandler.func1({0x49af080, 0xc0003c20e0}, 0xc00002ea00)
github.com/minio/minio/cmd/generic-handlers.go:136 +0x118
net/http.HandlerFunc.ServeHTTP(0xc00002ea00, {0x49af080, 0xc0003c20e0}, 0xa)
net/http/server.go:2047 +0x2f
github.com/minio/minio/cmd.setAuthHandler.func1({0x49af080, 0xc0003c20e0}, 0xc00002ea00)
github.com/minio/minio/cmd/auth-handler.go:525 +0x3d8
net/http.HandlerFunc.ServeHTTP(0xc00002e900, {0x49af080, 0xc0003c20e0}, 0xc001f33701)
net/http/server.go:2047 +0x2f
github.com/gorilla/mux.(*Router).ServeHTTP(0xc0025d0780, {0x49af080, 0xc0003c20e0}, 0xc00002e800)
github.com/gorilla/mux@v1.8.0/mux.go:210 +0x1cf
github.com/rs/cors.(*Cors).Handler.func1({0x49af080, 0xc0003c20e0}, 0xc00002e800)
github.com/rs/cors@v1.7.0/cors.go:219 +0x1bd
net/http.HandlerFunc.ServeHTTP(0x0, {0x49af080, 0xc0003c20e0}, 0xc00068d9f8)
net/http/server.go:2047 +0x2f
github.com/minio/minio/cmd.setCriticalErrorHandler.func1({0x49af080, 0xc0003c20e0}, 0x4a5cd3)
github.com/minio/minio/cmd/generic-handlers.go:476 +0x83
net/http.HandlerFunc.ServeHTTP(0x72, {0x49af080, 0xc0003c20e0}, 0x0)
net/http/server.go:2047 +0x2f
github.com/minio/minio/internal/http.(*Server).Start.func1({0x49af080, 0xc0003c20e0}, 0x10000c001f1dda0)
github.com/minio/minio/internal/http/server.go:105 +0x1b6
net/http.HandlerFunc.ServeHTTP(0x0, {0x49af080, 0xc0003c20e0}, 0x46982e)
net/http/server.go:2047 +0x2f
net/http.serverHandler.ServeHTTP({0xc003dc1950}, {0x49af080, 0xc0003c20e0}, 0xc00002e800)
net/http/server.go:2879 +0x43b
net/http.(*conn).serve(0xc000514d20, {0x49cfc38, 0xc0010c0e70})
net/http/server.go:1930 +0xb08
created by net/http.(*Server).Serve
net/http/server.go:3034 +0x4e8
```
2022-05-01 16:45:45 -04:00
2019-02-22 22:18:01 -05:00
for _ , domain := range domains {
fix: panic in browser redirect handler for unexpected r.Host (#14844)
```
panic: "GET /": invalid hostname
goroutine 148 [running]:
runtime/debug.Stack()
runtime/debug/stack.go:24 +0x65
github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1()
github.com/minio/minio/cmd/generic-handlers.go:469 +0x8e
panic({0x2201f00, 0xc001f1ddd0})
runtime/panic.go:1038 +0x215
github.com/minio/pkg/net.URL.String({{0x25aa417, 0x5}, {0x0, 0x0}, 0x0, {0xc000174380, 0xd7}, {0x0, 0x0}, {0x0, ...}, ...})
github.com/minio/pkg@v1.1.23/net/url.go:97 +0xfe
github.com/minio/minio/cmd.setBrowserRedirectHandler.func1({0x49af080, 0xc0003c20e0}, 0xc00002ea00)
github.com/minio/minio/cmd/generic-handlers.go:136 +0x118
net/http.HandlerFunc.ServeHTTP(0xc00002ea00, {0x49af080, 0xc0003c20e0}, 0xa)
net/http/server.go:2047 +0x2f
github.com/minio/minio/cmd.setAuthHandler.func1({0x49af080, 0xc0003c20e0}, 0xc00002ea00)
github.com/minio/minio/cmd/auth-handler.go:525 +0x3d8
net/http.HandlerFunc.ServeHTTP(0xc00002e900, {0x49af080, 0xc0003c20e0}, 0xc001f33701)
net/http/server.go:2047 +0x2f
github.com/gorilla/mux.(*Router).ServeHTTP(0xc0025d0780, {0x49af080, 0xc0003c20e0}, 0xc00002e800)
github.com/gorilla/mux@v1.8.0/mux.go:210 +0x1cf
github.com/rs/cors.(*Cors).Handler.func1({0x49af080, 0xc0003c20e0}, 0xc00002e800)
github.com/rs/cors@v1.7.0/cors.go:219 +0x1bd
net/http.HandlerFunc.ServeHTTP(0x0, {0x49af080, 0xc0003c20e0}, 0xc00068d9f8)
net/http/server.go:2047 +0x2f
github.com/minio/minio/cmd.setCriticalErrorHandler.func1({0x49af080, 0xc0003c20e0}, 0x4a5cd3)
github.com/minio/minio/cmd/generic-handlers.go:476 +0x83
net/http.HandlerFunc.ServeHTTP(0x72, {0x49af080, 0xc0003c20e0}, 0x0)
net/http/server.go:2047 +0x2f
github.com/minio/minio/internal/http.(*Server).Start.func1({0x49af080, 0xc0003c20e0}, 0x10000c001f1dda0)
github.com/minio/minio/internal/http/server.go:105 +0x1b6
net/http.HandlerFunc.ServeHTTP(0x0, {0x49af080, 0xc0003c20e0}, 0x46982e)
net/http/server.go:2047 +0x2f
net/http.serverHandler.ServeHTTP({0xc003dc1950}, {0x49af080, 0xc0003c20e0}, 0xc00002e800)
net/http/server.go:2879 +0x43b
net/http.(*conn).serve(0xc000514d20, {0x49cfc38, 0xc0010c0e70})
net/http/server.go:1930 +0xb08
created by net/http.(*Server).Serve
net/http/server.go:3034 +0x4e8
```
2022-05-01 16:45:45 -04:00
if xhost . Name == minioReservedBucket + "." + domain {
2020-09-09 12:57:37 -04:00
continue
}
fix: panic in browser redirect handler for unexpected r.Host (#14844)
```
panic: "GET /": invalid hostname
goroutine 148 [running]:
runtime/debug.Stack()
runtime/debug/stack.go:24 +0x65
github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1()
github.com/minio/minio/cmd/generic-handlers.go:469 +0x8e
panic({0x2201f00, 0xc001f1ddd0})
runtime/panic.go:1038 +0x215
github.com/minio/pkg/net.URL.String({{0x25aa417, 0x5}, {0x0, 0x0}, 0x0, {0xc000174380, 0xd7}, {0x0, 0x0}, {0x0, ...}, ...})
github.com/minio/pkg@v1.1.23/net/url.go:97 +0xfe
github.com/minio/minio/cmd.setBrowserRedirectHandler.func1({0x49af080, 0xc0003c20e0}, 0xc00002ea00)
github.com/minio/minio/cmd/generic-handlers.go:136 +0x118
net/http.HandlerFunc.ServeHTTP(0xc00002ea00, {0x49af080, 0xc0003c20e0}, 0xa)
net/http/server.go:2047 +0x2f
github.com/minio/minio/cmd.setAuthHandler.func1({0x49af080, 0xc0003c20e0}, 0xc00002ea00)
github.com/minio/minio/cmd/auth-handler.go:525 +0x3d8
net/http.HandlerFunc.ServeHTTP(0xc00002e900, {0x49af080, 0xc0003c20e0}, 0xc001f33701)
net/http/server.go:2047 +0x2f
github.com/gorilla/mux.(*Router).ServeHTTP(0xc0025d0780, {0x49af080, 0xc0003c20e0}, 0xc00002e800)
github.com/gorilla/mux@v1.8.0/mux.go:210 +0x1cf
github.com/rs/cors.(*Cors).Handler.func1({0x49af080, 0xc0003c20e0}, 0xc00002e800)
github.com/rs/cors@v1.7.0/cors.go:219 +0x1bd
net/http.HandlerFunc.ServeHTTP(0x0, {0x49af080, 0xc0003c20e0}, 0xc00068d9f8)
net/http/server.go:2047 +0x2f
github.com/minio/minio/cmd.setCriticalErrorHandler.func1({0x49af080, 0xc0003c20e0}, 0x4a5cd3)
github.com/minio/minio/cmd/generic-handlers.go:476 +0x83
net/http.HandlerFunc.ServeHTTP(0x72, {0x49af080, 0xc0003c20e0}, 0x0)
net/http/server.go:2047 +0x2f
github.com/minio/minio/internal/http.(*Server).Start.func1({0x49af080, 0xc0003c20e0}, 0x10000c001f1dda0)
github.com/minio/minio/internal/http/server.go:105 +0x1b6
net/http.HandlerFunc.ServeHTTP(0x0, {0x49af080, 0xc0003c20e0}, 0x46982e)
net/http/server.go:2047 +0x2f
net/http.serverHandler.ServeHTTP({0xc003dc1950}, {0x49af080, 0xc0003c20e0}, 0xc00002e800)
net/http/server.go:2879 +0x43b
net/http.(*conn).serve(0xc000514d20, {0x49cfc38, 0xc0010c0e70})
net/http/server.go:1930 +0xb08
created by net/http.(*Server).Serve
net/http/server.go:3034 +0x4e8
```
2022-05-01 16:45:45 -04:00
if ! strings . HasSuffix ( xhost . Name , "." + domain ) {
2019-02-22 22:18:01 -05:00
continue
}
fix: panic in browser redirect handler for unexpected r.Host (#14844)
```
panic: "GET /": invalid hostname
goroutine 148 [running]:
runtime/debug.Stack()
runtime/debug/stack.go:24 +0x65
github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1()
github.com/minio/minio/cmd/generic-handlers.go:469 +0x8e
panic({0x2201f00, 0xc001f1ddd0})
runtime/panic.go:1038 +0x215
github.com/minio/pkg/net.URL.String({{0x25aa417, 0x5}, {0x0, 0x0}, 0x0, {0xc000174380, 0xd7}, {0x0, 0x0}, {0x0, ...}, ...})
github.com/minio/pkg@v1.1.23/net/url.go:97 +0xfe
github.com/minio/minio/cmd.setBrowserRedirectHandler.func1({0x49af080, 0xc0003c20e0}, 0xc00002ea00)
github.com/minio/minio/cmd/generic-handlers.go:136 +0x118
net/http.HandlerFunc.ServeHTTP(0xc00002ea00, {0x49af080, 0xc0003c20e0}, 0xa)
net/http/server.go:2047 +0x2f
github.com/minio/minio/cmd.setAuthHandler.func1({0x49af080, 0xc0003c20e0}, 0xc00002ea00)
github.com/minio/minio/cmd/auth-handler.go:525 +0x3d8
net/http.HandlerFunc.ServeHTTP(0xc00002e900, {0x49af080, 0xc0003c20e0}, 0xc001f33701)
net/http/server.go:2047 +0x2f
github.com/gorilla/mux.(*Router).ServeHTTP(0xc0025d0780, {0x49af080, 0xc0003c20e0}, 0xc00002e800)
github.com/gorilla/mux@v1.8.0/mux.go:210 +0x1cf
github.com/rs/cors.(*Cors).Handler.func1({0x49af080, 0xc0003c20e0}, 0xc00002e800)
github.com/rs/cors@v1.7.0/cors.go:219 +0x1bd
net/http.HandlerFunc.ServeHTTP(0x0, {0x49af080, 0xc0003c20e0}, 0xc00068d9f8)
net/http/server.go:2047 +0x2f
github.com/minio/minio/cmd.setCriticalErrorHandler.func1({0x49af080, 0xc0003c20e0}, 0x4a5cd3)
github.com/minio/minio/cmd/generic-handlers.go:476 +0x83
net/http.HandlerFunc.ServeHTTP(0x72, {0x49af080, 0xc0003c20e0}, 0x0)
net/http/server.go:2047 +0x2f
github.com/minio/minio/internal/http.(*Server).Start.func1({0x49af080, 0xc0003c20e0}, 0x10000c001f1dda0)
github.com/minio/minio/internal/http/server.go:105 +0x1b6
net/http.HandlerFunc.ServeHTTP(0x0, {0x49af080, 0xc0003c20e0}, 0x46982e)
net/http/server.go:2047 +0x2f
net/http.serverHandler.ServeHTTP({0xc003dc1950}, {0x49af080, 0xc0003c20e0}, 0xc00002e800)
net/http/server.go:2879 +0x43b
net/http.(*conn).serve(0xc000514d20, {0x49cfc38, 0xc0010c0e70})
net/http/server.go:1930 +0xb08
created by net/http.(*Server).Serve
net/http/server.go:3034 +0x4e8
```
2022-05-01 16:45:45 -04:00
bucket := strings . TrimSuffix ( xhost . Name , "." + domain )
2019-08-06 15:08:58 -04:00
return SlashSeparator + pathJoin ( bucket , path ) , nil
2017-11-14 19:56:24 -05:00
}
2019-02-22 22:18:01 -05:00
return path , nil
2017-11-14 19:56:24 -05:00
}
2021-02-08 13:15:12 -05:00
var regexVersion = regexp . MustCompile ( ` ^/minio.*/(v\d+)/.* ` )
2019-11-04 12:30:59 -05:00
func extractAPIVersion ( r * http . Request ) string {
2021-02-08 13:15:12 -05:00
if matches := regexVersion . FindStringSubmatch ( r . URL . Path ) ; len ( matches ) > 1 {
return matches [ 1 ]
}
return "unknown"
2017-11-14 19:56:24 -05:00
}
2019-07-05 23:41:35 -04:00
2020-10-28 12:18:35 -04:00
func methodNotAllowedHandler ( api string ) func ( w http . ResponseWriter , r * http . Request ) {
2022-01-13 20:25:08 -05:00
return errorResponseHandler
2020-10-28 12:18:35 -04:00
}
2019-11-04 12:30:59 -05:00
// If none of the http routes match respond with appropriate errors
func errorResponseHandler ( w http . ResponseWriter , r * http . Request ) {
2020-07-27 12:03:38 -04:00
if r . Method == http . MethodOptions {
return
}
2022-01-13 20:25:08 -05:00
desc := "Do not upgrade one server at a time - please follow the recommended guidelines mentioned here https://github.com/minio/minio#upgrading-minio for your environment"
2019-10-03 03:08:12 -04:00
switch {
2019-11-04 12:30:59 -05:00
case strings . HasPrefix ( r . URL . Path , peerRESTPrefix ) :
writeErrorResponseString ( r . Context ( ) , w , APIError {
Code : "XMinioPeerVersionMismatch" ,
Description : desc ,
2020-06-17 17:49:26 -04:00
HTTPStatusCode : http . StatusUpgradeRequired ,
2019-11-04 12:30:59 -05:00
} , r . URL )
case strings . HasPrefix ( r . URL . Path , storageRESTPrefix ) :
writeErrorResponseString ( r . Context ( ) , w , APIError {
Code : "XMinioStorageVersionMismatch" ,
Description : desc ,
2020-06-17 17:49:26 -04:00
HTTPStatusCode : http . StatusUpgradeRequired ,
2019-11-04 12:30:59 -05:00
} , r . URL )
case strings . HasPrefix ( r . URL . Path , adminPathPrefix ) :
var desc string
2022-01-13 20:25:08 -05:00
version := extractAPIVersion ( r )
switch version {
case "v1" , madmin . AdminAPIVersionV2 :
2019-11-04 12:30:59 -05:00
desc = fmt . Sprintf ( "Server expects client requests with 'admin' API version '%s', found '%s', please upgrade the client to latest releases" , madmin . AdminAPIVersion , version )
2022-01-13 20:25:08 -05:00
case madmin . AdminAPIVersion :
2019-11-04 12:30:59 -05:00
desc = fmt . Sprintf ( "This 'admin' API is not supported by server in '%s'" , getMinioMode ( ) )
2022-01-13 20:25:08 -05:00
default :
2019-11-04 12:30:59 -05:00
desc = fmt . Sprintf ( "Unexpected client 'admin' API version found '%s', expected '%s', please downgrade the client to older releases" , version , madmin . AdminAPIVersion )
}
writeErrorResponseJSON ( r . Context ( ) , w , APIError {
Code : "XMinioAdminVersionMismatch" ,
Description : desc ,
2020-06-17 17:49:26 -04:00
HTTPStatusCode : http . StatusUpgradeRequired ,
2019-11-04 12:30:59 -05:00
} , r . URL )
2019-10-03 03:08:12 -04:00
default :
2019-11-04 12:30:59 -05:00
writeErrorResponse ( r . Context ( ) , w , APIError {
2021-03-02 02:10:33 -05:00
Code : "BadRequest" ,
Description : fmt . Sprintf ( "An error occurred when parsing the HTTP request %s at '%s'" ,
r . Method , r . URL . Path ) ,
2019-11-04 12:30:59 -05:00
HTTPStatusCode : http . StatusBadRequest ,
2021-06-17 23:27:04 -04:00
} , r . URL )
2019-10-03 03:08:12 -04:00
}
}
2019-07-05 23:41:35 -04:00
// gets host name for current node
2019-07-18 12:58:37 -04:00
func getHostName ( r * http . Request ) ( hostName string ) {
2020-06-12 23:04:01 -04:00
if globalIsDistErasure {
2021-03-26 14:37:58 -04:00
hostName = globalLocalNodeName
2019-07-18 12:58:37 -04:00
} else {
hostName = r . Host
2019-07-05 23:41:35 -04:00
}
return
}
2020-07-03 14:53:03 -04:00
// Proxy any request to an endpoint.
func proxyRequest ( ctx context . Context , w http . ResponseWriter , r * http . Request , ep ProxyEndpoint ) ( success bool ) {
success = true
2020-08-07 07:10:16 -04:00
// Make sure we remove any existing headers before
// proxying the request to another node.
for k := range w . Header ( ) {
w . Header ( ) . Del ( k )
}
2020-07-03 14:53:03 -04:00
f := handlers . NewForwarder ( & handlers . Forwarder {
PassHost : true ,
RoundTripper : ep . Transport ,
ErrorHandler : func ( w http . ResponseWriter , r * http . Request , err error ) {
success = false
2020-08-31 15:37:31 -04:00
if err != nil && ! errors . Is ( err , context . Canceled ) {
logger . LogIf ( GlobalContext , err )
}
2020-07-03 14:53:03 -04:00
} ,
} )
r . URL . Scheme = "http"
2020-12-22 00:42:38 -05:00
if globalIsTLS {
2020-07-03 14:53:03 -04:00
r . URL . Scheme = "https"
}
r . URL . Host = ep . Host
f . ServeHTTP ( w , r )
return
}