github.com/riscv/riscv-go@v0.0.0-20200123204226-124ebd6fcc8e/src/mime/mediatype_test.go (about) 1 // Copyright 2010 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 mime 6 7 import ( 8 "reflect" 9 "testing" 10 ) 11 12 func TestConsumeToken(t *testing.T) { 13 tests := [...][3]string{ 14 {"foo bar", "foo", " bar"}, 15 {"bar", "bar", ""}, 16 {"", "", ""}, 17 {" foo", "", " foo"}, 18 } 19 for _, test := range tests { 20 token, rest := consumeToken(test[0]) 21 expectedToken := test[1] 22 expectedRest := test[2] 23 if token != expectedToken { 24 t.Errorf("expected to consume token '%s', not '%s' from '%s'", 25 expectedToken, token, test[0]) 26 } else if rest != expectedRest { 27 t.Errorf("expected to have left '%s', not '%s' after reading token '%s' from '%s'", 28 expectedRest, rest, token, test[0]) 29 } 30 } 31 } 32 33 func TestConsumeValue(t *testing.T) { 34 tests := [...][3]string{ 35 {"foo bar", "foo", " bar"}, 36 {"bar", "bar", ""}, 37 {" bar ", "", " bar "}, 38 {`"My value"end`, "My value", "end"}, 39 {`"My value" end`, "My value", " end"}, 40 {`"\\" rest`, "\\", " rest"}, 41 {`"My \" value"end`, "My \" value", "end"}, 42 {`"\" rest`, "", `"\" rest`}, 43 } 44 for _, test := range tests { 45 value, rest := consumeValue(test[0]) 46 expectedValue := test[1] 47 expectedRest := test[2] 48 if value != expectedValue { 49 t.Errorf("expected to consume value [%s], not [%s] from [%s]", 50 expectedValue, value, test[0]) 51 } else if rest != expectedRest { 52 t.Errorf("expected to have left [%s], not [%s] after reading value [%s] from [%s]", 53 expectedRest, rest, value, test[0]) 54 } 55 } 56 } 57 58 func TestConsumeMediaParam(t *testing.T) { 59 tests := [...][4]string{ 60 {" ; foo=bar", "foo", "bar", ""}, 61 {"; foo=bar", "foo", "bar", ""}, 62 {";foo=bar", "foo", "bar", ""}, 63 {";FOO=bar", "foo", "bar", ""}, 64 {`;foo="bar"`, "foo", "bar", ""}, 65 {`;foo="bar"; `, "foo", "bar", "; "}, 66 {`;foo="bar"; foo=baz`, "foo", "bar", "; foo=baz"}, 67 {` ; boundary=----CUT;`, "boundary", "----CUT", ";"}, 68 {` ; key=value; blah="value";name="foo" `, "key", "value", `; blah="value";name="foo" `}, 69 {`; blah="value";name="foo" `, "blah", "value", `;name="foo" `}, 70 {`;name="foo" `, "name", "foo", ` `}, 71 } 72 for _, test := range tests { 73 param, value, rest := consumeMediaParam(test[0]) 74 expectedParam := test[1] 75 expectedValue := test[2] 76 expectedRest := test[3] 77 if param != expectedParam { 78 t.Errorf("expected to consume param [%s], not [%s] from [%s]", 79 expectedParam, param, test[0]) 80 } else if value != expectedValue { 81 t.Errorf("expected to consume value [%s], not [%s] from [%s]", 82 expectedValue, value, test[0]) 83 } else if rest != expectedRest { 84 t.Errorf("expected to have left [%s], not [%s] after reading [%s/%s] from [%s]", 85 expectedRest, rest, param, value, test[0]) 86 } 87 } 88 } 89 90 type mediaTypeTest struct { 91 in string 92 t string 93 p map[string]string 94 } 95 96 func TestParseMediaType(t *testing.T) { 97 // Convenience map initializer 98 m := func(s ...string) map[string]string { 99 sm := make(map[string]string) 100 for i := 0; i < len(s); i += 2 { 101 sm[s[i]] = s[i+1] 102 } 103 return sm 104 } 105 106 nameFoo := map[string]string{"name": "foo"} 107 tests := []mediaTypeTest{ 108 {`form-data; name="foo"`, "form-data", nameFoo}, 109 {` form-data ; name=foo`, "form-data", nameFoo}, 110 {`FORM-DATA;name="foo"`, "form-data", nameFoo}, 111 {` FORM-DATA ; name="foo"`, "form-data", nameFoo}, 112 {` FORM-DATA ; name="foo"`, "form-data", nameFoo}, 113 114 {`form-data; key=value; blah="value";name="foo" `, 115 "form-data", 116 m("key", "value", "blah", "value", "name", "foo")}, 117 118 {`foo; key=val1; key=the-key-appears-again-which-is-bogus`, 119 "", m()}, 120 121 // From RFC 2231: 122 {`application/x-stuff; title*=us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A`, 123 "application/x-stuff", 124 m("title", "This is ***fun***")}, 125 126 {`message/external-body; access-type=URL; ` + 127 `URL*0="ftp://";` + 128 `URL*1="cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar"`, 129 "message/external-body", 130 m("access-type", "URL", 131 "url", "ftp://cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar")}, 132 133 {`application/x-stuff; ` + 134 `title*0*=us-ascii'en'This%20is%20even%20more%20; ` + 135 `title*1*=%2A%2A%2Afun%2A%2A%2A%20; ` + 136 `title*2="isn't it!"`, 137 "application/x-stuff", 138 m("title", "This is even more ***fun*** isn't it!")}, 139 140 // Tests from http://greenbytes.de/tech/tc2231/ 141 // Note: Backslash escape handling is a bit loose, like MSIE. 142 // TODO(bradfitz): add the rest of the tests from that site. 143 {`attachment; filename="f\oo.html"`, 144 "attachment", 145 m("filename", "f\\oo.html")}, 146 {`attachment; filename="\"quoting\" tested.html"`, 147 "attachment", 148 m("filename", `"quoting" tested.html`)}, 149 {`attachment; filename="Here's a semicolon;.html"`, 150 "attachment", 151 m("filename", "Here's a semicolon;.html")}, 152 {`attachment; foo="\"\\";filename="foo.html"`, 153 "attachment", 154 m("foo", "\"\\", "filename", "foo.html")}, 155 {`attachment; filename=foo.html`, 156 "attachment", 157 m("filename", "foo.html")}, 158 {`attachment; filename=foo.html ;`, 159 "attachment", 160 m("filename", "foo.html")}, 161 {`attachment; filename='foo.html'`, 162 "attachment", 163 m("filename", "'foo.html'")}, 164 {`attachment; filename="foo-%41.html"`, 165 "attachment", 166 m("filename", "foo-%41.html")}, 167 {`attachment; filename="foo-%\41.html"`, 168 "attachment", 169 m("filename", "foo-%\\41.html")}, 170 {`filename=foo.html`, 171 "", m()}, 172 {`x=y; filename=foo.html`, 173 "", m()}, 174 {`"foo; filename=bar;baz"; filename=qux`, 175 "", m()}, 176 {`inline; attachment; filename=foo.html`, 177 "", m()}, 178 {`attachment; filename="foo.html".txt`, 179 "", m()}, 180 {`attachment; filename="bar`, 181 "", m()}, 182 {`attachment; creation-date="Wed, 12 Feb 1997 16:29:51 -0500"`, 183 "attachment", 184 m("creation-date", "Wed, 12 Feb 1997 16:29:51 -0500")}, 185 {`foobar`, "foobar", m()}, 186 {`attachment; filename* =UTF-8''foo-%c3%a4.html`, 187 "attachment", 188 m("filename", "foo-ä.html")}, 189 {`attachment; filename*=UTF-8''A-%2541.html`, 190 "attachment", 191 m("filename", "A-%41.html")}, 192 {`attachment; filename*0="foo."; filename*1="html"`, 193 "attachment", 194 m("filename", "foo.html")}, 195 {`attachment; filename*0*=UTF-8''foo-%c3%a4; filename*1=".html"`, 196 "attachment", 197 m("filename", "foo-ä.html")}, 198 {`attachment; filename*0="foo"; filename*01="bar"`, 199 "attachment", 200 m("filename", "foo")}, 201 {`attachment; filename*0="foo"; filename*2="bar"`, 202 "attachment", 203 m("filename", "foo")}, 204 {`attachment; filename*1="foo"; filename*2="bar"`, 205 "attachment", m()}, 206 {`attachment; filename*1="bar"; filename*0="foo"`, 207 "attachment", 208 m("filename", "foobar")}, 209 {`attachment; filename="foo-ae.html"; filename*=UTF-8''foo-%c3%a4.html`, 210 "attachment", 211 m("filename", "foo-ä.html")}, 212 {`attachment; filename*=UTF-8''foo-%c3%a4.html; filename="foo-ae.html"`, 213 "attachment", 214 m("filename", "foo-ä.html")}, 215 216 // Browsers also just send UTF-8 directly without RFC 2231, 217 // at least when the source page is served with UTF-8. 218 {`form-data; firstname="Брэд"; lastname="Фицпатрик"`, 219 "form-data", 220 m("firstname", "Брэд", "lastname", "Фицпатрик")}, 221 222 // Empty string used to be mishandled. 223 {`foo; bar=""`, "foo", m("bar", "")}, 224 225 // Microsoft browers in intranet mode do not think they need to escape \ in file name. 226 {`form-data; name="file"; filename="C:\dev\go\robots.txt"`, "form-data", m("name", "file", "filename", `C:\dev\go\robots.txt`)}, 227 } 228 for _, test := range tests { 229 mt, params, err := ParseMediaType(test.in) 230 if err != nil { 231 if test.t != "" { 232 t.Errorf("for input %#q, unexpected error: %v", test.in, err) 233 continue 234 } 235 continue 236 } 237 if g, e := mt, test.t; g != e { 238 t.Errorf("for input %#q, expected type %q, got %q", 239 test.in, e, g) 240 continue 241 } 242 if len(params) == 0 && len(test.p) == 0 { 243 continue 244 } 245 if !reflect.DeepEqual(params, test.p) { 246 t.Errorf("for input %#q, wrong params.\n"+ 247 "expected: %#v\n"+ 248 " got: %#v", 249 test.in, test.p, params) 250 } 251 } 252 } 253 254 type badMediaTypeTest struct { 255 in string 256 err string 257 } 258 259 var badMediaTypeTests = []badMediaTypeTest{ 260 {"bogus ;=========", "mime: invalid media parameter"}, 261 {"bogus/<script>alert</script>", "mime: expected token after slash"}, 262 {"bogus/bogus<script>alert</script>", "mime: unexpected content after media subtype"}, 263 } 264 265 func TestParseMediaTypeBogus(t *testing.T) { 266 for _, tt := range badMediaTypeTests { 267 mt, params, err := ParseMediaType(tt.in) 268 if err == nil { 269 t.Errorf("ParseMediaType(%q) = nil error; want parse error", tt.in) 270 continue 271 } 272 if err.Error() != tt.err { 273 t.Errorf("ParseMediaType(%q) = err %q; want %q", tt.in, err.Error(), tt.err) 274 } 275 if params != nil { 276 t.Errorf("ParseMediaType(%q): got non-nil params on error", tt.in) 277 } 278 if mt != "" { 279 t.Errorf("ParseMediaType(%q): got non-empty media type string on error", tt.in) 280 } 281 } 282 } 283 284 type formatTest struct { 285 typ string 286 params map[string]string 287 want string 288 } 289 290 var formatTests = []formatTest{ 291 {"noslash", map[string]string{"X": "Y"}, "noslash; x=Y"}, // e.g. Content-Disposition values (RFC 2183); issue 11289 292 {"foo bar/baz", nil, ""}, 293 {"foo/bar baz", nil, ""}, 294 {"foo/BAR", nil, "foo/bar"}, 295 {"foo/BAR", map[string]string{"X": "Y"}, "foo/bar; x=Y"}, 296 {"foo/BAR", map[string]string{"space": "With space"}, `foo/bar; space="With space"`}, 297 {"foo/BAR", map[string]string{"quote": `With "quote`}, `foo/bar; quote="With \"quote"`}, 298 {"foo/BAR", map[string]string{"bslash": `With \backslash`}, `foo/bar; bslash="With \\backslash"`}, 299 {"foo/BAR", map[string]string{"both": `With \backslash and "quote`}, `foo/bar; both="With \\backslash and \"quote"`}, 300 {"foo/BAR", map[string]string{"": "empty attribute"}, ""}, 301 {"foo/BAR", map[string]string{"bad attribute": "baz"}, ""}, 302 {"foo/BAR", map[string]string{"nonascii": "not an ascii character: ä"}, ""}, 303 {"foo/bar", map[string]string{"a": "av", "b": "bv", "c": "cv"}, "foo/bar; a=av; b=bv; c=cv"}, 304 {"foo/bar", map[string]string{"0": "'", "9": "'"}, "foo/bar; 0='; 9='"}, 305 {"foo", map[string]string{"bar": ""}, `foo; bar=""`}, 306 } 307 308 func TestFormatMediaType(t *testing.T) { 309 for i, tt := range formatTests { 310 got := FormatMediaType(tt.typ, tt.params) 311 if got != tt.want { 312 t.Errorf("%d. FormatMediaType(%q, %v) = %q; want %q", i, tt.typ, tt.params, got, tt.want) 313 } 314 } 315 }