Home | History | Annotate | Download | only in 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 	"os"
     11 	"regexp"
     12 	"strings"
     13 	"testing"
     14 )
     15 
     16 func TestReadForm(t *testing.T) {
     17 	testBody := regexp.MustCompile("\n").ReplaceAllString(message, "\r\n")
     18 	b := strings.NewReader(testBody)
     19 	r := NewReader(b, boundary)
     20 	f, err := r.ReadForm(25)
     21 	if err != nil {
     22 		t.Fatal("ReadForm:", err)
     23 	}
     24 	defer f.RemoveAll()
     25 	if g, e := f.Value["texta"][0], textaValue; g != e {
     26 		t.Errorf("texta value = %q, want %q", g, e)
     27 	}
     28 	if g, e := f.Value["textb"][0], textbValue; g != e {
     29 		t.Errorf("texta value = %q, want %q", g, e)
     30 	}
     31 	fd := testFile(t, f.File["filea"][0], "filea.txt", fileaContents)
     32 	if _, ok := fd.(*os.File); ok {
     33 		t.Error("file is *os.File, should not be")
     34 	}
     35 	fd.Close()
     36 	fd = testFile(t, f.File["fileb"][0], "fileb.txt", filebContents)
     37 	if _, ok := fd.(*os.File); !ok {
     38 		t.Errorf("file has unexpected underlying type %T", fd)
     39 	}
     40 	fd.Close()
     41 }
     42 
     43 func testFile(t *testing.T, fh *FileHeader, efn, econtent string) File {
     44 	if fh.Filename != efn {
     45 		t.Errorf("filename = %q, want %q", fh.Filename, efn)
     46 	}
     47 	f, err := fh.Open()
     48 	if err != nil {
     49 		t.Fatal("opening file:", err)
     50 	}
     51 	b := new(bytes.Buffer)
     52 	_, err = io.Copy(b, f)
     53 	if err != nil {
     54 		t.Fatal("copying contents:", err)
     55 	}
     56 	if g := b.String(); g != econtent {
     57 		t.Errorf("contents = %q, want %q", g, econtent)
     58 	}
     59 	return f
     60 }
     61 
     62 const (
     63 	fileaContents = "This is a test file."
     64 	filebContents = "Another test file."
     65 	textaValue    = "foo"
     66 	textbValue    = "bar"
     67 	boundary      = `MyBoundary`
     68 )
     69 
     70 const message = `
     71 --MyBoundary
     72 Content-Disposition: form-data; name="filea"; filename="filea.txt"
     73 Content-Type: text/plain
     74 
     75 ` + fileaContents + `
     76 --MyBoundary
     77 Content-Disposition: form-data; name="fileb"; filename="fileb.txt"
     78 Content-Type: text/plain
     79 
     80 ` + filebContents + `
     81 --MyBoundary
     82 Content-Disposition: form-data; name="texta"
     83 
     84 ` + textaValue + `
     85 --MyBoundary
     86 Content-Disposition: form-data; name="textb"
     87 
     88 ` + textbValue + `
     89 --MyBoundary--
     90 `
     91 
     92 func TestReadForm_NoReadAfterEOF(t *testing.T) {
     93 	maxMemory := int64(32) << 20
     94 	boundary := `---------------------------8d345eef0d38dc9`
     95 	body := `
     96 -----------------------------8d345eef0d38dc9
     97 Content-Disposition: form-data; name="version"
     98 
     99 171
    100 -----------------------------8d345eef0d38dc9--`
    101 
    102 	mr := NewReader(&failOnReadAfterErrorReader{t: t, r: strings.NewReader(body)}, boundary)
    103 
    104 	f, err := mr.ReadForm(maxMemory)
    105 	if err != nil {
    106 		t.Fatal(err)
    107 	}
    108 	t.Logf("Got: %#v", f)
    109 }
    110 
    111 // failOnReadAfterErrorReader is an io.Reader wrapping r.
    112 // It fails t if any Read is called after a failing Read.
    113 type failOnReadAfterErrorReader struct {
    114 	t      *testing.T
    115 	r      io.Reader
    116 	sawErr error
    117 }
    118 
    119 func (r *failOnReadAfterErrorReader) Read(p []byte) (n int, err error) {
    120 	if r.sawErr != nil {
    121 		r.t.Fatalf("unexpected Read on Reader after previous read saw error %v", r.sawErr)
    122 	}
    123 	n, err = r.r.Read(p)
    124 	r.sawErr = err
    125 	return
    126 }
    127