storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/generic-handlers_test.go (about) 1 /* 2 * MinIO Cloud Storage, (C) 2016 MinIO, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package cmd 18 19 import ( 20 "net/http" 21 "net/http/httptest" 22 "net/url" 23 "strconv" 24 "testing" 25 26 "storj.io/minio/cmd/crypto" 27 xhttp "storj.io/minio/cmd/http" 28 ) 29 30 // Tests getRedirectLocation function for all its criteria. 31 func TestRedirectLocation(t *testing.T) { 32 testCases := []struct { 33 urlPath string 34 location string 35 }{ 36 { 37 // 1. When urlPath is '/minio' 38 urlPath: minioReservedBucketPath, 39 location: minioReservedBucketPath + SlashSeparator, 40 }, 41 { 42 // 2. When urlPath is '/' 43 urlPath: SlashSeparator, 44 location: minioReservedBucketPath + SlashSeparator, 45 }, 46 { 47 // 3. When urlPath is '/webrpc' 48 urlPath: "/webrpc", 49 location: minioReservedBucketPath + "/webrpc", 50 }, 51 { 52 // 4. When urlPath is '/login' 53 urlPath: "/login", 54 location: minioReservedBucketPath + "/login", 55 }, 56 { 57 // 5. When urlPath is '/favicon-16x16.png' 58 urlPath: "/favicon-16x16.png", 59 location: minioReservedBucketPath + "/favicon-16x16.png", 60 }, 61 { 62 // 6. When urlPath is '/favicon-16x16.png' 63 urlPath: "/favicon-32x32.png", 64 location: minioReservedBucketPath + "/favicon-32x32.png", 65 }, 66 { 67 // 7. When urlPath is '/favicon-96x96.png' 68 urlPath: "/favicon-96x96.png", 69 location: minioReservedBucketPath + "/favicon-96x96.png", 70 }, 71 { 72 // 8. When urlPath is '/unknown' 73 urlPath: "/unknown", 74 location: "", 75 }, 76 } 77 78 // Validate all conditions. 79 for i, testCase := range testCases { 80 loc := getRedirectLocation(testCase.urlPath) 81 if testCase.location != loc { 82 t.Errorf("Test %d: Unexpected location expected %s, got %s", i+1, testCase.location, loc) 83 } 84 } 85 } 86 87 // Tests request guess function for net/rpc requests. 88 func TestGuessIsRPC(t *testing.T) { 89 if guessIsRPCReq(nil) { 90 t.Fatal("Unexpected return for nil request") 91 } 92 93 u, err := url.Parse("http://localhost:9000/minio/lock") 94 if err != nil { 95 t.Fatal(err) 96 } 97 98 r := &http.Request{ 99 Proto: "HTTP/1.0", 100 Method: http.MethodPost, 101 URL: u, 102 } 103 if !guessIsRPCReq(r) { 104 t.Fatal("Test shouldn't fail for a possible net/rpc request.") 105 } 106 r = &http.Request{ 107 Proto: "HTTP/1.1", 108 Method: http.MethodGet, 109 } 110 if guessIsRPCReq(r) { 111 t.Fatal("Test shouldn't report as net/rpc for a non net/rpc request.") 112 } 113 } 114 115 // Tests browser request guess function. 116 func TestGuessIsBrowser(t *testing.T) { 117 globalBrowserEnabled = true 118 if guessIsBrowserReq(nil) { 119 t.Fatal("Unexpected return for nil request") 120 } 121 r := &http.Request{ 122 Header: http.Header{}, 123 URL: &url.URL{}, 124 } 125 r.Header.Set("User-Agent", "Mozilla") 126 if !guessIsBrowserReq(r) { 127 t.Fatal("Test shouldn't fail for a possible browser request anonymous user") 128 } 129 r.Header.Set("Authorization", "Bearer token") 130 if !guessIsBrowserReq(r) { 131 t.Fatal("Test shouldn't fail for a possible browser request JWT user") 132 } 133 r = &http.Request{ 134 Header: http.Header{}, 135 URL: &url.URL{}, 136 } 137 r.Header.Set("User-Agent", "mc") 138 if guessIsBrowserReq(r) { 139 t.Fatal("Test shouldn't report as browser for a non browser request.") 140 } 141 } 142 143 var isHTTPHeaderSizeTooLargeTests = []struct { 144 header http.Header 145 shouldFail bool 146 }{ 147 {header: generateHeader(0, 0), shouldFail: false}, 148 {header: generateHeader(1024, 0), shouldFail: false}, 149 {header: generateHeader(2048, 0), shouldFail: false}, 150 {header: generateHeader(8*1024+1, 0), shouldFail: true}, 151 {header: generateHeader(0, 1024), shouldFail: false}, 152 {header: generateHeader(0, 2048), shouldFail: true}, 153 {header: generateHeader(0, 2048+1), shouldFail: true}, 154 } 155 156 func generateHeader(size, usersize int) http.Header { 157 header := http.Header{} 158 for i := 0; i < size; i++ { 159 header.Set(strconv.Itoa(i), "") 160 } 161 userlength := 0 162 for i := 0; userlength < usersize; i++ { 163 userlength += len(userMetadataKeyPrefixes[0] + strconv.Itoa(i)) 164 header.Set(userMetadataKeyPrefixes[0]+strconv.Itoa(i), "") 165 } 166 return header 167 } 168 169 func TestIsHTTPHeaderSizeTooLarge(t *testing.T) { 170 for i, test := range isHTTPHeaderSizeTooLargeTests { 171 if res := isHTTPHeaderSizeTooLarge(test.header); res != test.shouldFail { 172 t.Errorf("Test %d: Expected %v got %v", i, res, test.shouldFail) 173 } 174 } 175 } 176 177 var containsReservedMetadataTests = []struct { 178 header http.Header 179 shouldFail bool 180 }{ 181 { 182 header: http.Header{"X-Minio-Key": []string{"value"}}, 183 }, 184 { 185 header: http.Header{crypto.MetaIV: []string{"iv"}}, 186 shouldFail: true, 187 }, 188 { 189 header: http.Header{crypto.MetaAlgorithm: []string{crypto.InsecureSealAlgorithm}}, 190 shouldFail: true, 191 }, 192 { 193 header: http.Header{crypto.MetaSealedKeySSEC: []string{"mac"}}, 194 shouldFail: true, 195 }, 196 { 197 header: http.Header{ReservedMetadataPrefix + "Key": []string{"value"}}, 198 shouldFail: true, 199 }, 200 } 201 202 func TestContainsReservedMetadata(t *testing.T) { 203 for _, test := range containsReservedMetadataTests { 204 test := test 205 t.Run("", func(t *testing.T) { 206 contains := containsReservedMetadata(test.header) 207 if contains && !test.shouldFail { 208 t.Errorf("contains reserved header but should not fail") 209 } else if !contains && test.shouldFail { 210 t.Errorf("does not contain reserved header but failed") 211 } 212 }) 213 } 214 } 215 216 var sseTLSHandlerTests = []struct { 217 URL *url.URL 218 Header http.Header 219 IsTLS, ShouldFail bool 220 }{ 221 {URL: &url.URL{}, Header: http.Header{}, IsTLS: false, ShouldFail: false}, // 0 222 {URL: &url.URL{}, Header: http.Header{xhttp.AmzServerSideEncryptionCustomerAlgorithm: []string{"AES256"}}, IsTLS: false, ShouldFail: true}, // 1 223 {URL: &url.URL{}, Header: http.Header{xhttp.AmzServerSideEncryptionCustomerAlgorithm: []string{"AES256"}}, IsTLS: true, ShouldFail: false}, // 2 224 {URL: &url.URL{}, Header: http.Header{xhttp.AmzServerSideEncryptionCustomerKey: []string{""}}, IsTLS: true, ShouldFail: false}, // 3 225 {URL: &url.URL{}, Header: http.Header{xhttp.AmzServerSideEncryptionCopyCustomerAlgorithm: []string{""}}, IsTLS: false, ShouldFail: true}, // 4 226 } 227 228 func TestSSETLSHandler(t *testing.T) { 229 defer func(isSSL bool) { GlobalIsTLS = isSSL }(GlobalIsTLS) // reset GlobalIsTLS after test 230 231 var okHandler http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) { 232 w.WriteHeader(http.StatusOK) 233 } 234 for i, test := range sseTLSHandlerTests { 235 GlobalIsTLS = test.IsTLS 236 237 w := httptest.NewRecorder() 238 r := new(http.Request) 239 r.Header = test.Header 240 r.URL = test.URL 241 242 h := setSSETLSHandler(okHandler) 243 h.ServeHTTP(w, r) 244 245 switch { 246 case test.ShouldFail && w.Code == http.StatusOK: 247 t.Errorf("Test %d: should fail but status code is HTTP %d", i, w.Code) 248 case !test.ShouldFail && w.Code != http.StatusOK: 249 t.Errorf("Test %d: should not fail but status code is HTTP %d and not 200 OK", i, w.Code) 250 } 251 } 252 }