storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/streaming-signature-v4_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 "bufio" 21 "bytes" 22 "fmt" 23 "io" 24 "strings" 25 "testing" 26 ) 27 28 // Test read chunk line. 29 func TestReadChunkLine(t *testing.T) { 30 type testCase struct { 31 reader *bufio.Reader 32 expectedErr error 33 chunkSize []byte 34 chunkSignature []byte 35 } 36 // List of readers used. 37 readers := []io.Reader{ 38 // Test - 1 39 bytes.NewReader([]byte("1000;chunk-signature=111123333333333333334444211\r\n")), 40 // Test - 2 41 bytes.NewReader([]byte("1000;")), 42 // Test - 3 43 bytes.NewReader([]byte(fmt.Sprintf("%4097d", 1))), 44 // Test - 4 45 bytes.NewReader([]byte("1000;chunk-signature=111123333333333333334444211\r\n")), 46 } 47 testCases := []testCase{ 48 // Test - 1 - small bufio reader. 49 { 50 bufio.NewReaderSize(readers[0], 16), 51 errLineTooLong, 52 nil, 53 nil, 54 }, 55 // Test - 2 - unexpected end of the reader. 56 { 57 bufio.NewReader(readers[1]), 58 io.ErrUnexpectedEOF, 59 nil, 60 nil, 61 }, 62 // Test - 3 - line too long bigger than 4k+1 63 { 64 bufio.NewReader(readers[2]), 65 errLineTooLong, 66 nil, 67 nil, 68 }, 69 // Test - 4 - parse the chunk reader properly. 70 { 71 bufio.NewReader(readers[3]), 72 nil, 73 []byte("1000"), 74 []byte("111123333333333333334444211"), 75 }, 76 } 77 // Valid test cases for each chunk line. 78 for i, tt := range testCases { 79 chunkSize, chunkSignature, err := readChunkLine(tt.reader) 80 if err != tt.expectedErr { 81 t.Errorf("Test %d: Expected %s, got %s", i+1, tt.expectedErr, err) 82 } 83 if !bytes.Equal(chunkSize, tt.chunkSize) { 84 t.Errorf("Test %d: Expected %s, got %s", i+1, string(tt.chunkSize), string(chunkSize)) 85 } 86 if !bytes.Equal(chunkSignature, tt.chunkSignature) { 87 t.Errorf("Test %d: Expected %s, got %s", i+1, string(tt.chunkSignature), string(chunkSignature)) 88 } 89 } 90 } 91 92 // Test parsing s3 chunk extension. 93 func TestParseS3ChunkExtension(t *testing.T) { 94 type testCase struct { 95 buf []byte 96 chunkSize []byte 97 chunkSign []byte 98 } 99 100 tests := []testCase{ 101 // Test - 1 valid case. 102 { 103 []byte("10000;chunk-signature=ad80c730a21e5b8d04586a2213dd63b9a0e99e0e2307b0ade35a65485a288648"), 104 []byte("10000"), 105 []byte("ad80c730a21e5b8d04586a2213dd63b9a0e99e0e2307b0ade35a65485a288648"), 106 }, 107 // Test - 2 no chunk extension, return same buffer. 108 { 109 []byte("10000;"), 110 []byte("10000;"), 111 nil, 112 }, 113 // Test - 3 no chunk size, return error. 114 { 115 []byte(";chunk-signature="), 116 nil, 117 nil, 118 }, 119 // Test - 4 removes trailing slash. 120 { 121 []byte("10000;chunk-signature=ad80c730a21e5b8d04586a2213dd63b9a0e99e0e2307b0ade35a65485a288648 \t \n"), 122 []byte("10000"), 123 []byte("ad80c730a21e5b8d04586a2213dd63b9a0e99e0e2307b0ade35a65485a288648"), 124 }, 125 } 126 // Validate chunk extension removal. 127 for i, tt := range tests { 128 // Extract chunk size and chunk signature after parsing a standard chunk-extension format. 129 hexChunkSize, hexChunkSignature := parseS3ChunkExtension(tt.buf) 130 if !bytes.Equal(hexChunkSize, tt.chunkSize) { 131 t.Errorf("Test %d: Expected %s, got %s", i+1, string(tt.chunkSize), string(hexChunkSize)) 132 } 133 if !bytes.Equal(hexChunkSignature, tt.chunkSign) { 134 t.Errorf("Test %d: Expected %s, got %s", i+1, string(tt.chunkSign), string(hexChunkSignature)) 135 } 136 } 137 } 138 139 // Test read CRLF characters on input reader. 140 func TestReadCRLF(t *testing.T) { 141 type testCase struct { 142 reader io.Reader 143 expectedErr error 144 } 145 tests := []testCase{ 146 // Test - 1 valid buffer with CRLF. 147 {bytes.NewReader([]byte("\r\n")), nil}, 148 // Test - 2 invalid buffer with no CRLF. 149 {bytes.NewReader([]byte("he")), errMalformedEncoding}, 150 // Test - 3 invalid buffer with more characters. 151 {bytes.NewReader([]byte("he\r\n")), errMalformedEncoding}, 152 // Test - 4 smaller buffer than expected. 153 {bytes.NewReader([]byte("h")), io.ErrUnexpectedEOF}, 154 } 155 for i, tt := range tests { 156 err := readCRLF(tt.reader) 157 if err != tt.expectedErr { 158 t.Errorf("Test %d: Expected %s, got %s this", i+1, tt.expectedErr, err) 159 } 160 } 161 } 162 163 // Tests parsing hex number into its uint64 decimal equivalent. 164 func TestParseHexUint(t *testing.T) { 165 type testCase struct { 166 in string 167 want uint64 168 wantErr string 169 } 170 tests := []testCase{ 171 {"x", 0, "invalid byte in chunk length"}, 172 {"0000000000000000", 0, ""}, 173 {"0000000000000001", 1, ""}, 174 {"ffffffffffffffff", 1<<64 - 1, ""}, 175 {"FFFFFFFFFFFFFFFF", 1<<64 - 1, ""}, 176 {"000000000000bogus", 0, "invalid byte in chunk length"}, 177 {"00000000000000000", 0, "http chunk length too large"}, // could accept if we wanted 178 {"10000000000000000", 0, "http chunk length too large"}, 179 {"00000000000000001", 0, "http chunk length too large"}, // could accept if we wanted 180 } 181 for i := uint64(0); i <= 1234; i++ { 182 tests = append(tests, testCase{in: fmt.Sprintf("%x", i), want: i}) 183 } 184 for _, tt := range tests { 185 got, err := parseHexUint([]byte(tt.in)) 186 if tt.wantErr != "" { 187 if err != nil && !strings.Contains(err.Error(), tt.wantErr) { 188 t.Errorf("parseHexUint(%q) = %v, %v; want error %q", tt.in, got, err, tt.wantErr) 189 } 190 } else { 191 if err != nil || got != tt.want { 192 t.Errorf("parseHexUint(%q) = %v, %v; want %v", tt.in, got, err, tt.want) 193 } 194 } 195 } 196 }