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  }