"mime"
"mime/quotedprintable"
"net/textproto"
+ "path/filepath"
"strings"
)
return p.dispositionParams["name"]
}
-// FileName returns the filename parameter of the Part's
-// Content-Disposition header.
+// FileName returns the filename parameter of the Part's Content-Disposition
+// header. If not empty, the filename is passed through filepath.Base (which is
+// platform dependent) before being returned.
func (p *Part) FileName() string {
if p.dispositionParams == nil {
p.parseContentDisposition()
}
- return p.dispositionParams["filename"]
+ filename := p.dispositionParams["filename"]
+ if filename == "" {
+ return ""
+ }
+ // RFC 7578, Section 4.2 requires that if a filename is provided, the
+ // directory path information must not be used.
+ return filepath.Base(filename)
}
func (p *Part) parseContentDisposition() {
}
}
+// Issue 45789: multipart form should not include directory path in filename
+func TestParseMultipartFormFilename(t *testing.T) {
+ postData :=
+ `--xxx
+Content-Disposition: form-data; name="file"; filename="../usr/foobar.txt/"
+Content-Type: text/plain
+
+--xxx--
+`
+ req := &Request{
+ Method: "POST",
+ Header: Header{"Content-Type": {`multipart/form-data; boundary=xxx`}},
+ Body: io.NopCloser(strings.NewReader(postData)),
+ }
+ _, hdr, err := req.FormFile("file")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if hdr.Filename != "foobar.txt" {
+ t.Errorf("expected only the last element of the path, got %q", hdr.Filename)
+ }
+}
+
// Issue #40430: Test that if maxMemory for ParseMultipartForm when combined with
// the payload size and the internal leeway buffer size of 10MiB overflows, that we
// correctly return an error.