...

Source file src/mime/multipart/formdata_test.go

Documentation: mime/multipart

		 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  }
	 237  

View as plain text