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