github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/mime/multipart/formdata_test.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package multipart 6 7 import ( 8 "bytes" 9 "io" 10 "math" 11 "os" 12 "strings" 13 "testing" 14 ) 15 16 func TestReadForm(t *testing.T) { 17 b := strings.NewReader(strings.ReplaceAll(message, "\n", "\r\n")) 18 r := NewReader(b, boundary) 19 f, err := r.ReadForm(25) 20 if err != nil { 21 t.Fatal("ReadForm:", err) 22 } 23 defer f.RemoveAll() 24 if g, e := f.Value["texta"][0], textaValue; g != e { 25 t.Errorf("texta value = %q, want %q", g, e) 26 } 27 if g, e := f.Value["textb"][0], textbValue; g != e { 28 t.Errorf("texta value = %q, want %q", g, e) 29 } 30 fd := testFile(t, f.File["filea"][0], "filea.txt", fileaContents) 31 if _, ok := fd.(*os.File); ok { 32 t.Error("file is *os.File, should not be") 33 } 34 fd.Close() 35 fd = testFile(t, f.File["fileb"][0], "fileb.txt", filebContents) 36 if _, ok := fd.(*os.File); !ok { 37 t.Errorf("file has unexpected underlying type %T", fd) 38 } 39 fd.Close() 40 } 41 42 func TestReadFormWithNamelessFile(t *testing.T) { 43 b := strings.NewReader(strings.ReplaceAll(messageWithFileWithoutName, "\n", "\r\n")) 44 r := NewReader(b, boundary) 45 f, err := r.ReadForm(25) 46 if err != nil { 47 t.Fatal("ReadForm:", err) 48 } 49 defer f.RemoveAll() 50 51 if g, e := f.Value["hiddenfile"][0], filebContents; g != e { 52 t.Errorf("hiddenfile value = %q, want %q", g, e) 53 } 54 } 55 56 // Issue 40430: Handle ReadForm(math.MaxInt64) 57 func TestReadFormMaxMemoryOverflow(t *testing.T) { 58 b := strings.NewReader(strings.ReplaceAll(messageWithTextContentType, "\n", "\r\n")) 59 r := NewReader(b, boundary) 60 f, err := r.ReadForm(math.MaxInt64) 61 if err != nil { 62 t.Fatalf("ReadForm(MaxInt64): %v", err) 63 } 64 if f == nil { 65 t.Fatal("ReadForm(MaxInt64): missing form") 66 } 67 } 68 69 func TestReadFormWithTextContentType(t *testing.T) { 70 // From https://github.com/golang/go/issues/24041 71 b := strings.NewReader(strings.ReplaceAll(messageWithTextContentType, "\n", "\r\n")) 72 r := NewReader(b, boundary) 73 f, err := r.ReadForm(25) 74 if err != nil { 75 t.Fatal("ReadForm:", err) 76 } 77 defer f.RemoveAll() 78 79 if g, e := f.Value["texta"][0], textaValue; g != e { 80 t.Errorf("texta value = %q, want %q", g, e) 81 } 82 } 83 84 func testFile(t *testing.T, fh *FileHeader, efn, econtent string) File { 85 if fh.Filename != efn { 86 t.Errorf("filename = %q, want %q", fh.Filename, efn) 87 } 88 if fh.Size != int64(len(econtent)) { 89 t.Errorf("size = %d, want %d", fh.Size, len(econtent)) 90 } 91 f, err := fh.Open() 92 if err != nil { 93 t.Fatal("opening file:", err) 94 } 95 b := new(bytes.Buffer) 96 _, err = io.Copy(b, f) 97 if err != nil { 98 t.Fatal("copying contents:", err) 99 } 100 if g := b.String(); g != econtent { 101 t.Errorf("contents = %q, want %q", g, econtent) 102 } 103 return f 104 } 105 106 const ( 107 fileaContents = "This is a test file." 108 filebContents = "Another test file." 109 textaValue = "foo" 110 textbValue = "bar" 111 boundary = `MyBoundary` 112 ) 113 114 const messageWithFileWithoutName = ` 115 --MyBoundary 116 Content-Disposition: form-data; name="hiddenfile"; filename="" 117 Content-Type: text/plain 118 119 ` + filebContents + ` 120 --MyBoundary-- 121 ` 122 123 const messageWithTextContentType = ` 124 --MyBoundary 125 Content-Disposition: form-data; name="texta" 126 Content-Type: text/plain 127 128 ` + textaValue + ` 129 --MyBoundary 130 ` 131 132 const message = ` 133 --MyBoundary 134 Content-Disposition: form-data; name="filea"; filename="filea.txt" 135 Content-Type: text/plain 136 137 ` + fileaContents + ` 138 --MyBoundary 139 Content-Disposition: form-data; name="fileb"; filename="fileb.txt" 140 Content-Type: text/plain 141 142 ` + filebContents + ` 143 --MyBoundary 144 Content-Disposition: form-data; name="texta" 145 146 ` + textaValue + ` 147 --MyBoundary 148 Content-Disposition: form-data; name="textb" 149 150 ` + textbValue + ` 151 --MyBoundary-- 152 ` 153 154 func TestReadForm_NoReadAfterEOF(t *testing.T) { 155 maxMemory := int64(32) << 20 156 boundary := `---------------------------8d345eef0d38dc9` 157 body := ` 158 -----------------------------8d345eef0d38dc9 159 Content-Disposition: form-data; name="version" 160 161 171 162 -----------------------------8d345eef0d38dc9--` 163 164 mr := NewReader(&failOnReadAfterErrorReader{t: t, r: strings.NewReader(body)}, boundary) 165 166 f, err := mr.ReadForm(maxMemory) 167 if err != nil { 168 t.Fatal(err) 169 } 170 t.Logf("Got: %#v", f) 171 } 172 173 // failOnReadAfterErrorReader is an io.Reader wrapping r. 174 // It fails t if any Read is called after a failing Read. 175 type failOnReadAfterErrorReader struct { 176 t *testing.T 177 r io.Reader 178 sawErr error 179 } 180 181 func (r *failOnReadAfterErrorReader) Read(p []byte) (n int, err error) { 182 if r.sawErr != nil { 183 r.t.Fatalf("unexpected Read on Reader after previous read saw error %v", r.sawErr) 184 } 185 n, err = r.r.Read(p) 186 r.sawErr = err 187 return 188 } 189 190 // TestReadForm_NonFileMaxMemory asserts that the ReadForm maxMemory limit is applied 191 // while processing non-file form data as well as file form data. 192 func TestReadForm_NonFileMaxMemory(t *testing.T) { 193 n := 10<<20 + 25 194 if testing.Short() { 195 n = 10<<10 + 25 196 } 197 largeTextValue := strings.Repeat("1", n) 198 message := `--MyBoundary 199 Content-Disposition: form-data; name="largetext" 200 201 ` + largeTextValue + ` 202 --MyBoundary-- 203 ` 204 205 testBody := strings.ReplaceAll(message, "\n", "\r\n") 206 testCases := []struct { 207 name string 208 maxMemory int64 209 err error 210 }{ 211 {"smaller", 50, nil}, 212 {"exact-fit", 25, nil}, 213 {"too-large", 0, ErrMessageTooLarge}, 214 } 215 for _, tc := range testCases { 216 t.Run(tc.name, func(t *testing.T) { 217 if tc.maxMemory == 0 && testing.Short() { 218 t.Skip("skipping in -short mode") 219 } 220 b := strings.NewReader(testBody) 221 r := NewReader(b, boundary) 222 f, err := r.ReadForm(tc.maxMemory) 223 if err == nil { 224 defer f.RemoveAll() 225 } 226 if tc.err != err { 227 t.Fatalf("ReadForm error - got: %v; expected: %v", tc.err, err) 228 } 229 if err == nil { 230 if g := f.Value["largetext"][0]; g != largeTextValue { 231 t.Errorf("largetext mismatch: got size: %v, expected size: %v", len(g), len(largeTextValue)) 232 } 233 } 234 }) 235 } 236 }