| 
									
										
										
										
											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/>.
 | 
					
						
							| 
									
										
										
										
											2016-04-29 11:01:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 07:23:42 +08:00
										 |  |  | package cmd | 
					
						
							| 
									
										
										
										
											2016-04-29 11:01:11 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2016-04-29 11:01:11 +08:00
										 |  |  | 	"encoding/xml" | 
					
						
							| 
									
										
										
										
											2022-09-20 02:05:16 +08:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2016-04-29 11:01:11 +08:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2021-02-04 12:41:33 +08:00
										 |  |  | 	"net/textproto" | 
					
						
							| 
									
										
										
										
											2017-08-13 10:25:43 +08:00
										 |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2016-07-23 11:31:45 +08:00
										 |  |  | 	"reflect" | 
					
						
							| 
									
										
										
										
											2016-04-29 11:01:11 +08:00
										 |  |  | 	"testing" | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-02 05:59:40 +08:00
										 |  |  | 	"github.com/minio/minio/internal/config" | 
					
						
							| 
									
										
										
										
											2016-04-29 11:01:11 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Tests validate bucket LocationConstraint.
 | 
					
						
							| 
									
										
										
										
											2024-02-22 14:26:06 +08:00
										 |  |  | func TestIsValidLocationConstraint(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2022-10-14 18:08:40 +08:00
										 |  |  | 	ctx, cancel := context.WithCancel(context.Background()) | 
					
						
							|  |  |  | 	defer cancel() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	obj, fsDir, err := prepareFS(ctx) | 
					
						
							| 
									
										
										
										
											2016-07-19 12:20:17 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer os.RemoveAll(fsDir) | 
					
						
							|  |  |  | 	if err = newTestConfig(globalMinioDefaultRegion, obj); err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							| 
									
										
										
										
											2016-07-19 12:20:17 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 23:19:09 +08:00
										 |  |  | 	// Corrupted XML
 | 
					
						
							| 
									
										
										
										
											2016-09-21 01:40:46 +08:00
										 |  |  | 	malformedReq := &http.Request{ | 
					
						
							| 
									
										
										
										
											2022-09-20 02:05:16 +08:00
										 |  |  | 		Body:          io.NopCloser(bytes.NewReader([]byte("<>"))), | 
					
						
							| 
									
										
										
										
											2016-09-21 01:40:46 +08:00
										 |  |  | 		ContentLength: int64(len("<>")), | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-01-31 23:19:09 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Not an XML
 | 
					
						
							|  |  |  | 	badRequest := &http.Request{ | 
					
						
							| 
									
										
										
										
											2022-09-20 02:05:16 +08:00
										 |  |  | 		Body:          io.NopCloser(bytes.NewReader([]byte("garbage"))), | 
					
						
							| 
									
										
										
										
											2019-01-31 23:19:09 +08:00
										 |  |  | 		ContentLength: int64(len("garbage")), | 
					
						
							| 
									
										
										
										
											2016-09-21 01:40:46 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-29 11:01:11 +08:00
										 |  |  | 	// generates the input request with XML bucket configuration set to the request body.
 | 
					
						
							| 
									
										
										
										
											2019-01-31 23:19:09 +08:00
										 |  |  | 	createExpectedRequest := func(req *http.Request, location string) *http.Request { | 
					
						
							| 
									
										
										
										
											2016-04-29 11:01:11 +08:00
										 |  |  | 		createBucketConfig := createBucketLocationConfiguration{} | 
					
						
							|  |  |  | 		createBucketConfig.Location = location | 
					
						
							| 
									
										
										
										
											2019-01-31 23:19:09 +08:00
										 |  |  | 		createBucketConfigBytes, _ := xml.Marshal(createBucketConfig) | 
					
						
							| 
									
										
										
										
											2020-12-27 14:58:06 +08:00
										 |  |  | 		createBucketConfigBuffer := bytes.NewReader(createBucketConfigBytes) | 
					
						
							| 
									
										
										
										
											2022-09-20 02:05:16 +08:00
										 |  |  | 		req.Body = io.NopCloser(createBucketConfigBuffer) | 
					
						
							| 
									
										
										
										
											2016-07-19 12:20:17 +08:00
										 |  |  | 		req.ContentLength = int64(createBucketConfigBuffer.Len()) | 
					
						
							| 
									
										
										
										
											2019-01-31 23:19:09 +08:00
										 |  |  | 		return req | 
					
						
							| 
									
										
										
										
											2016-04-29 11:01:11 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	testCases := []struct { | 
					
						
							| 
									
										
										
										
											2019-01-31 23:19:09 +08:00
										 |  |  | 		request            *http.Request | 
					
						
							|  |  |  | 		serverConfigRegion string | 
					
						
							|  |  |  | 		expectedCode       APIErrorCode | 
					
						
							| 
									
										
										
										
											2016-04-29 11:01:11 +08:00
										 |  |  | 	}{ | 
					
						
							|  |  |  | 		// Test case - 1.
 | 
					
						
							| 
									
										
										
										
											2019-01-31 23:19:09 +08:00
										 |  |  | 		{createExpectedRequest(&http.Request{}, "eu-central-1"), globalMinioDefaultRegion, ErrNone}, | 
					
						
							| 
									
										
										
										
											2016-04-29 11:01:11 +08:00
										 |  |  | 		// Test case - 2.
 | 
					
						
							|  |  |  | 		// In case of empty request body ErrNone is returned.
 | 
					
						
							| 
									
										
										
										
											2019-01-31 23:19:09 +08:00
										 |  |  | 		{createExpectedRequest(&http.Request{}, ""), globalMinioDefaultRegion, ErrNone}, | 
					
						
							|  |  |  | 		// Test case - 3
 | 
					
						
							|  |  |  | 		// In case of garbage request body ErrMalformedXML is returned.
 | 
					
						
							|  |  |  | 		{badRequest, globalMinioDefaultRegion, ErrMalformedXML}, | 
					
						
							|  |  |  | 		// Test case - 4
 | 
					
						
							|  |  |  | 		// In case of invalid XML request body ErrMalformedXML is returned.
 | 
					
						
							|  |  |  | 		{malformedReq, globalMinioDefaultRegion, ErrMalformedXML}, | 
					
						
							| 
									
										
										
										
											2016-04-29 11:01:11 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-01-31 23:19:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-29 11:01:11 +08:00
										 |  |  | 	for i, testCase := range testCases { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 		config.SetRegion(globalServerConfig, testCase.serverConfigRegion) | 
					
						
							| 
									
										
										
										
											2019-01-31 23:19:09 +08:00
										 |  |  | 		_, actualCode := parseLocationConstraint(testCase.request) | 
					
						
							| 
									
										
										
										
											2016-04-29 11:01:11 +08:00
										 |  |  | 		if testCase.expectedCode != actualCode { | 
					
						
							|  |  |  | 			t.Errorf("Test %d: Expected the APIErrCode to be %d, but instead found %d", i+1, testCase.expectedCode, actualCode) | 
					
						
							| 
									
										
										
										
											2017-03-14 05:41:13 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-23 11:31:45 +08:00
										 |  |  | // Tests validate metadata extraction from http headers.
 | 
					
						
							|  |  |  | func TestExtractMetadataHeaders(t *testing.T) { | 
					
						
							|  |  |  | 	testCases := []struct { | 
					
						
							| 
									
										
										
										
											2017-07-06 07:56:10 +08:00
										 |  |  | 		header     http.Header | 
					
						
							|  |  |  | 		metadata   map[string]string | 
					
						
							|  |  |  | 		shouldFail bool | 
					
						
							| 
									
										
										
										
											2016-07-23 11:31:45 +08:00
										 |  |  | 	}{ | 
					
						
							|  |  |  | 		// Validate if there a known 'content-type'.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			header: http.Header{ | 
					
						
							|  |  |  | 				"Content-Type": []string{"image/png"}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			metadata: map[string]string{ | 
					
						
							|  |  |  | 				"content-type": "image/png", | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2017-07-06 07:56:10 +08:00
										 |  |  | 			shouldFail: false, | 
					
						
							| 
									
										
										
										
											2016-07-23 11:31:45 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		// Validate if there are no keys to extract.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			header: http.Header{ | 
					
						
							| 
									
										
										
										
											2017-07-06 07:56:10 +08:00
										 |  |  | 				"Test-1": []string{"123"}, | 
					
						
							| 
									
										
										
										
											2016-07-23 11:31:45 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2017-07-06 07:56:10 +08:00
										 |  |  | 			metadata:   map[string]string{}, | 
					
						
							|  |  |  | 			shouldFail: false, | 
					
						
							| 
									
										
										
										
											2016-07-23 11:31:45 +08:00
										 |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2017-07-06 07:56:10 +08:00
										 |  |  | 		// Validate that there are all headers extracted
 | 
					
						
							| 
									
										
										
										
											2016-09-21 01:40:46 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			header: http.Header{ | 
					
						
							|  |  |  | 				"X-Amz-Meta-Appid":   []string{"amz-meta"}, | 
					
						
							|  |  |  | 				"X-Minio-Meta-Appid": []string{"minio-meta"}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			metadata: map[string]string{ | 
					
						
							|  |  |  | 				"X-Amz-Meta-Appid":   "amz-meta", | 
					
						
							| 
									
										
										
										
											2017-07-06 07:56:10 +08:00
										 |  |  | 				"X-Minio-Meta-Appid": "minio-meta", | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			shouldFail: false, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// Fail if header key is not in canonicalized form
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			header: http.Header{ | 
					
						
							|  |  |  | 				"x-amz-meta-appid": []string{"amz-meta"}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			metadata: map[string]string{ | 
					
						
							| 
									
										
										
										
											2018-07-11 11:27:10 +08:00
										 |  |  | 				"x-amz-meta-appid": "amz-meta", | 
					
						
							| 
									
										
										
										
											2017-07-06 07:56:10 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2018-07-11 11:27:10 +08:00
										 |  |  | 			shouldFail: false, | 
					
						
							| 
									
										
										
										
											2016-09-21 01:40:46 +08:00
										 |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2018-11-03 02:32:18 +08:00
										 |  |  | 		// Support multiple values
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			header: http.Header{ | 
					
						
							|  |  |  | 				"x-amz-meta-key": []string{"amz-meta1", "amz-meta2"}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			metadata: map[string]string{ | 
					
						
							|  |  |  | 				"x-amz-meta-key": "amz-meta1,amz-meta2", | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			shouldFail: false, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2017-03-14 05:41:13 +08:00
										 |  |  | 		// Empty header input returns empty metadata.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2017-07-06 07:56:10 +08:00
										 |  |  | 			header:     nil, | 
					
						
							|  |  |  | 			metadata:   nil, | 
					
						
							|  |  |  | 			shouldFail: true, | 
					
						
							| 
									
										
										
										
											2017-03-14 05:41:13 +08:00
										 |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2016-07-23 11:31:45 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Validate if the extracting headers.
 | 
					
						
							|  |  |  | 	for i, testCase := range testCases { | 
					
						
							| 
									
										
										
										
											2018-07-11 11:27:10 +08:00
										 |  |  | 		metadata := make(map[string]string) | 
					
						
							| 
									
										
										
										
											2021-02-04 12:41:33 +08:00
										 |  |  | 		err := extractMetadataFromMime(context.Background(), textproto.MIMEHeader(testCase.header), metadata) | 
					
						
							| 
									
										
										
										
											2017-07-06 07:56:10 +08:00
										 |  |  | 		if err != nil && !testCase.shouldFail { | 
					
						
							|  |  |  | 			t.Fatalf("Test %d failed to extract metadata: %v", i+1, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if err == nil && testCase.shouldFail { | 
					
						
							|  |  |  | 			t.Fatalf("Test %d should fail, but it passed", i+1) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if err == nil && !reflect.DeepEqual(metadata, testCase.metadata) { | 
					
						
							| 
									
										
										
										
											2016-07-23 11:31:45 +08:00
										 |  |  | 			t.Fatalf("Test %d failed: Expected \"%#v\", got \"%#v\"", i+1, testCase.metadata, metadata) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-11-15 08:56:24 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Test getResource()
 | 
					
						
							|  |  |  | func TestGetResource(t *testing.T) { | 
					
						
							|  |  |  | 	testCases := []struct { | 
					
						
							|  |  |  | 		p                string | 
					
						
							|  |  |  | 		host             string | 
					
						
							| 
									
										
										
										
											2019-02-23 11:18:01 +08:00
										 |  |  | 		domains          []string | 
					
						
							| 
									
										
										
										
											2017-11-15 08:56:24 +08:00
										 |  |  | 		expectedResource string | 
					
						
							|  |  |  | 	}{ | 
					
						
							| 
									
										
										
										
											2019-02-23 11:18:01 +08:00
										 |  |  | 		{"/a/b/c", "test.mydomain.com", []string{"mydomain.com"}, "/test/a/b/c"}, | 
					
						
							| 
									
										
											  
											
												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-02 04:45:45 +08:00
										 |  |  | 		{"/a/b/c", "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:17000", []string{"mydomain.com"}, "/a/b/c"}, | 
					
						
							|  |  |  | 		{"/a/b/c", "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]", []string{"mydomain.com"}, "/a/b/c"}, | 
					
						
							|  |  |  | 		{"/a/b/c", "192.168.1.1:9000", []string{"mydomain.com"}, "/a/b/c"}, | 
					
						
							| 
									
										
										
										
											2019-02-23 11:18:01 +08:00
										 |  |  | 		{"/a/b/c", "test.mydomain.com", []string{"notmydomain.com"}, "/a/b/c"}, | 
					
						
							|  |  |  | 		{"/a/b/c", "test.mydomain.com", nil, "/a/b/c"}, | 
					
						
							| 
									
										
										
										
											2017-11-15 08:56:24 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for i, test := range testCases { | 
					
						
							| 
									
										
										
										
											2019-02-23 11:18:01 +08:00
										 |  |  | 		gotResource, err := getResource(test.p, test.host, test.domains) | 
					
						
							| 
									
										
										
										
											2017-11-15 08:56:24 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatal(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if gotResource != test.expectedResource { | 
					
						
							|  |  |  | 			t.Fatalf("test %d: expected %s got %s", i+1, test.expectedResource, gotResource) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |