Initial commit
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"mime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Content-Disposition is the header that keeps an uploaded file from being
|
||||
// rendered, so it has to survive whatever a filename throws at it.
|
||||
func TestContentDisposition(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
wantASCII string
|
||||
wantExt bool // expect an RFC 5987 filename* parameter too
|
||||
}{
|
||||
{"MyGame.zip", "MyGame.zip", false},
|
||||
{"notes (draft).txt", "notes (draft).txt", false},
|
||||
{`quo"te.txt`, "quo_te.txt", true},
|
||||
{`back\slash.txt`, "back_slash.txt", true},
|
||||
{"naïve.txt", "na_ve.txt", true},
|
||||
{"日本語.bin", "___.bin", true},
|
||||
{"🙂.png", "_.png", true},
|
||||
}
|
||||
for _, c := range cases {
|
||||
got := contentDisposition(c.name)
|
||||
|
||||
// It must always parse, and always be an attachment.
|
||||
disp, params, err := mime.ParseMediaType(got)
|
||||
if err != nil {
|
||||
t.Errorf("contentDisposition(%q) = %q: does not parse: %v", c.name, got, err)
|
||||
continue
|
||||
}
|
||||
if disp != "attachment" {
|
||||
t.Errorf("contentDisposition(%q): disposition = %q", c.name, disp)
|
||||
}
|
||||
// Whatever the encoding, the decoded filename must be the real one when
|
||||
// an extended parameter is present.
|
||||
if c.wantExt {
|
||||
if !strings.Contains(got, "filename*=UTF-8''") {
|
||||
t.Errorf("contentDisposition(%q) = %q: no RFC 5987 parameter", c.name, got)
|
||||
}
|
||||
if params["filename"] != c.name {
|
||||
t.Errorf("contentDisposition(%q): decoded filename = %q", c.name, params["filename"])
|
||||
}
|
||||
} else if params["filename"] != c.wantASCII {
|
||||
t.Errorf("contentDisposition(%q): filename = %q, want %q", c.name, params["filename"], c.wantASCII)
|
||||
}
|
||||
|
||||
// Nothing may break out of the header, in any spelling.
|
||||
if strings.ContainsAny(got, "\r\n") {
|
||||
t.Errorf("contentDisposition(%q) = %q: contains a line break", c.name, got)
|
||||
}
|
||||
if i := strings.Index(got, `filename="`); i >= 0 {
|
||||
quoted := got[i+len(`filename="`):]
|
||||
quoted = quoted[:strings.Index(quoted, `"`)]
|
||||
if strings.ContainsAny(quoted, `"\`) {
|
||||
t.Errorf("contentDisposition(%q): unescaped quoting in %q", c.name, quoted)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestASCIIFilenameNeverEmpty(t *testing.T) {
|
||||
for _, in := range []string{"", "...", "___", " ", "🙂"} {
|
||||
if got := asciiFilename(in); strings.Trim(got, "_. ") == "" {
|
||||
t.Errorf("asciiFilename(%q) = %q, which names nothing", in, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeRFC5987(t *testing.T) {
|
||||
cases := map[string]string{
|
||||
"plain.txt": "plain.txt",
|
||||
"a b.txt": "a%20b.txt",
|
||||
"naïve": "na%C3%AFve",
|
||||
`q"x`: "q%22x",
|
||||
}
|
||||
for in, want := range cases {
|
||||
if got := encodeRFC5987(in); got != want {
|
||||
t.Errorf("encodeRFC5987(%q) = %q, want %q", in, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user