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