Revision control

Copy as Markdown

Other Tools

"use strict";
define(function (require) {
var headerparser = require("jsmime").headerparser;
var assert = require("assert");
function smartDeepEqual(actual, expected) {
assert.deepEqual(actual, expected);
// XXX: instanceof Map don't work for actual. Unclear why.
if ("entries" in actual && "entries" in expected) {
assert.deepEqual(
Array.from(actual.entries()),
Array.from(expected.entries())
);
}
}
function arrayTest(data, fn) {
fn.toString = function () {
let text = Function.prototype.toString.call(this);
text = text.replace(/data\[([0-9]*)\]/g, function (m, p) {
return JSON.stringify(data[p]);
});
return text;
};
return test(data[0], fn);
}
suite("headerparser", function () {
suite("parseParameterHeader", function () {
const header_tests = [
["multipart/related", ["multipart/related", {}]],
["a ; b=v", ["a", { b: "v" }]],
["a ; b='v'", ["a", { b: "'v'" }]],
['a; b = "v"', ["a", { b: "v" }]],
["a;b=1;b=2", ["a", { b: "1" }]],
["a;b=2;b=1", ["a", { b: "2" }]],
['a;b="a;b"', ["a", { b: "a;b" }]],
['a;b="\\\\"', ["a", { b: "\\" }]],
['a;b="a\\b\\c"', ["a", { b: "abc" }]],
["a;b=1;c=2", ["a", { b: "1", c: "2" }]],
['a;b="a\\', ["a", { b: "a" }]],
["a;b", ["a", {}]],
['a;b=";";c=d', ["a", { b: ";", c: "d" }]],
];
header_tests.forEach(function (data) {
arrayTest(data, function () {
const testMap = new Map();
for (const key in data[1][1]) {
testMap.set(key, data[1][1][key]);
}
testMap.preSemi = data[1][0];
assert.deepEqual(
headerparser.parseParameterHeader(data[0], false, false),
testMap
);
});
});
});
suite("parseParameterHeader (2231/2047 support)", function () {
const header_tests = [
// Copied from test_MIME_params.js and adapted
["attachment;", ["attachment", {}]],
["attachment; filename=basic", ["attachment", { filename: "basic" }]],
['attachment; filename="\\""', ["attachment", { filename: '"' }]],
['attachment; filename="\\x"', ["attachment", { filename: "x" }]],
['attachment; filename=""', ["attachment", { filename: "" }]],
["attachment; filename=", ["attachment", { filename: "" }]],
["attachment; filename X", ["attachment", {}]],
[
"attachment; filename = foo-A.html",
["attachment", { filename: "foo-A.html" }],
],
['attachment; filename="', ["attachment", { filename: "" }]],
[
"attachment; filename=foo; trouble",
["attachment", { filename: "foo" }],
],
[
"attachment; filename=foo; trouble ",
["attachment", { filename: "foo" }],
],
["attachment", ["attachment", {}]],
["attachment; filename=foo", ["attachment", { filename: "foo" }]],
['attachment; filename="foo"', ["attachment", { filename: "foo" }]],
["attachment; filename='foo'", ["attachment", { filename: "'foo'" }]],
[
'attachment; filename="=?UTF-8?Q?foo?="',
["attachment", { filename: "foo" }],
],
[
"attachment; filename==?UTF-8?Q?foo?=",
["attachment", { filename: "foo" }],
],
// 2231/5987 tests from test_MIME_params.js
[
"attachment; filename*=UTF-8''extended",
["attachment", { filename: "extended" }],
],
[
"attachment; filename=basic; filename*=UTF-8''extended",
["attachment", { filename: "extended" }],
],
[
"attachment; filename*=UTF-8''extended; filename=basic",
["attachment", { filename: "extended" }],
],
[
"attachment; filename*0=foo; filename*1=bar",
["attachment", { filename: "foobar" }],
],
[
"attachment; filename*0=first; filename*0=wrong; filename=basic",
["attachment", { filename: "first" }],
], // or basic?
[
"attachment; filename*0=first; filename*1=second; filename*0=wrong",
["attachment", { filename: "firstsecond" }],
], // or nothing?
[
"attachment; filename=basic; filename*0=foo; filename*1=bar",
["attachment", { filename: "foobar" }],
],
[
"attachment; filename=basic; filename*0=first; filename*0=wrong; " +
"filename*=UTF-8''extended",
["attachment", { filename: "extended" }],
],
[
"attachment; filename=basic; filename*=UTF-8''extended; filename*0=foo" +
"; filename*1=bar",
["attachment", { filename: "extended" }],
],
[
"attachment; filename*0=foo; filename*2=bar",
["attachment", { filename: "foo" }],
],
[
"attachment; filename*0=foo; filename*01=bar",
["attachment", { filename: "foo" }],
],
[
"attachment; filename=basic; filename*0*=UTF-8''multi; filename*1=line" +
"; filename*2*=%20extended",
["attachment", { filename: "multiline extended" }],
],
[
"attachment; filename=basic; filename*0*=UTF-8''multi; filename*1=line" +
"; filename*3*=%20extended",
["attachment", { filename: "multiline" }],
],
[
"attachment; filename=basic; filename*0*=UTF-8''multi; filename*1=line" +
"; filename*0*=UTF-8''wrong; filename*1=bad; filename*2=evil",
["attachment", { filename: "multiline" }],
],
[
"attachment; filename=basic; filename*0=UTF-8''multi; filename*=UTF-8'" +
"'extended; filename*1=line; filename*2*=%20extended",
["attachment", { filename: "extended" }],
],
[
"attachment; filename*0=UTF-8''unescaped; filename*1*=%20so%20includes" +
"%20UTF-8''%20in%20value",
[
"attachment",
{ filename: "UTF-8''unescaped so includes UTF-8'' in value" },
],
],
[
"attachment; filename=basic; filename*0*=UTF-8''multi; filename*1=line" +
"; filename*0*=UTF-8''wrong; filename*1=bad; filename*2=evil",
["attachment", { filename: "multiline" }],
],
[
"attachment; filename=basic; filename*1=foo; filename*2=bar",
["attachment", { filename: "basic" }],
],
[
"attachment; filename=basic; filename*0*=UTF-8''0; filename*1=1; filen" +
"ame*2=2;filename*3=3;filename*4=4;filename*5=5;filename*6=6;filename" +
"*7=7;filename*8=8;filename*9=9;filename*10=a;filename*11=b;filename*" +
"12=c;filename*13=d;filename*14=e;filename*15=f",
["attachment", { filename: "0123456789abcdef" }],
],
[
"attachment; filename=basic; filename*0*=UTF-8''0; filename*1=1; filen" +
"ame*2=2;filename*3=3;filename*4=4;filename*5=5;filename*6=6;filename" +
"*7=7;filename*8=8;filename*9=9;filename*10=a;filename*11=b;filename*" +
"12=c;filename*14=e",
["attachment", { filename: "0123456789abc" }],
],
[
"attachment; filename*1=multi; filename*2=line; filename*3*=%20extended",
["attachment", {}],
],
[
"attachment; filename=basic; filename*0*=UTF-8''0; filename*1=1; filen" +
"ame*2=2;filename*3=3;filename*4=4;filename*5=5;filename*6=6;filename" +
"*7=7;filename*8=8;filename*9=9;filename*10=a;filename*11=b;filename*" +
"12=c;filename*13=d;filename*15=f;filename*14=e",
["attachment", { filename: "0123456789abcdef" }],
],
[
"attachment; filename=basic; filename*0*=UTF-8''0; filename*1a=1",
["attachment", { filename: "0" }],
],
[
"attachment; filename=basic; filename*0*=UTF-8''0; filename*1111111111" +
"1111111111111111111111111=1",
["attachment", { filename: "0" }],
],
[
"attachment; filename=basic; filename*0*=UTF-8''0; filename*-1=1",
["attachment", { filename: "0" }],
],
[
'attachment; filename=basic; filename*0="0"; filename*1=1; filename*' +
"2*=%32",
["attachment", { filename: "012" }],
],
[
"attachment; filename=basic; filename**=UTF-8''0;",
["attachment", { filename: "basic" }],
],
[
"attachment; filename=IT839\x04\xB5(m8)2.pdf;",
["attachment", { filename: "IT839\u00b5(m8)2.pdf" }],
],
["attachment; filename*=utf-8''%41", ["attachment", { filename: "A" }]],
// See bug 651185 and bug 703015
[
"attachment; filename*=\"utf-8''%41\"",
["attachment", { filename: "A" }],
],
["attachment; filename *=utf-8''foo-%41", ["attachment", {}]],
["attachment; filename*=''foo", ["attachment", {}]],
["attachment; filename*=a''foo", ["attachment", {}]],
// Bug 692574: we should ignore this one...
[
"attachment; filename*=UTF-8'foo-%41",
["attachment", { filename: "foo-A" }],
],
["attachment; filename*=foo-%41", ["attachment", {}]],
[
"attachment; filename*=UTF-8'foo-%41; filename=bar",
["attachment", { filename: "foo-A" }],
],
[
"attachment; filename*=ISO-8859-1''%c3%a4",
["attachment", { filename: "\u00c3\u00a4" }],
],
[
"attachment; filename*=ISO-8859-1''%e2%82%ac",
["attachment", { filename: "\u00e2\u201a\u00ac" }],
],
["attachment; filename*=UTF-8''A%e4B", ["attachment", {}]],
[
"attachment; filename*=UTF-8''A%e4B; filename=fallback",
["attachment", { filename: "fallback" }],
],
[
"attachment; filename*0*=UTF-8''A%e4B; filename=fallback",
["attachment", { filename: "fallback" }],
],
[
"attachment; filename*0*=ISO-8859-15''euro-sign%3d%a4; filename*=ISO-8" +
"859-1''currency-sign%3d%a4",
["attachment", { filename: "currency-sign=\u00a4" }],
],
[
"attachment; filename*=ISO-8859-1''currency-sign%3d%a4; filename*0*=IS" +
"O-8859-15''euro-sign%3d%a4",
["attachment", { filename: "currency-sign=\u00a4" }],
],
[
'attachment; filename=basic; filename*0="foo"; filename*1="\\b\\a\\' +
'r"',
["attachment", { filename: "foobar" }],
],
[
'attachment; filename=basic; filename*0="foo"; filename*1="\\b\\a\\',
["attachment", { filename: "fooba" }],
],
['attachment; filename="\\b\\a\\', ["attachment", { filename: "ba" }]],
// According to comments and bugs, this works in necko, but it doesn't
// appear that it ought to. See bug 732369 for more info.
[
"attachment; extension=bla filename=foo",
["attachment", { extension: "bla" }],
],
[
"attachment; filename==?ISO-8859-1?Q?foo-=E4.html?=",
["attachment", { filename: "foo-\u00e4.html" }],
],
[
'attachment; filename="=?ISO-8859-1?Q?foo-=E4.html?="',
["attachment", { filename: "foo-\u00e4.html" }],
],
[
'attachment; filename="=?ISO-8859-1?Q?foo-=E4.html?="; filename*=UTF' +
"-8''5987",
["attachment", { filename: "5987" }],
],
// ABC\u202Etxt.zip dir switch char in middle.
[
"attachment; filename*=UTF-8''%41%42%43%E2%80%AE%2E%74%78%74%2E%7A%69%70",
["attachment", { filename: "ABC .txt.zip" }],
],
];
header_tests.forEach(function (data) {
arrayTest(data, function () {
const testMap = new Map();
for (const key in data[1][1]) {
testMap.set(key, data[1][1][key]);
}
testMap.preSemi = data[1][0];
smartDeepEqual(
headerparser.parseParameterHeader(data[0], true, true),
testMap
);
});
});
});
suite("parseAddressingHeader", function () {
const header_tests = [
["", []],
[
"Joe Schmoe <jschmoe@invalid.invalid>",
[{ name: "Joe Schmoe", email: "jschmoe@invalid.invalid" }],
],
[
"user@tinderbox.invalid",
[{ name: "", email: "user@tinderbox.invalid" }],
],
[
"Hello Kitty <a@b.c>, No Kitty <b@b.c>",
[
{ name: "Hello Kitty", email: "a@b.c" },
{ name: "No Kitty", email: "b@b.c" },
],
],
[
"undisclosed-recipients:;",
[{ name: "undisclosed-recipients", group: [] }],
],
["me@[127.0.0.1]", [{ name: "", email: "me@[127.0.0.1]" }]],
['"me"@a.com', [{ name: "", email: "me@a.com" }]],
['"!"@a.com', [{ name: "", email: '"!"@a.com' }]],
['"\\!"@a.com', [{ name: "", email: '"!"@a.com' }]],
['"\\\\!"@a.com', [{ name: "", email: '"\\\\!"@a.com' }]],
[
"Coward (not@email) <real@email.com>",
[{ name: "Coward (not@email)", email: "real@email.com" }],
],
[
'"y@example.com" <xx@example.com>',
[{ name: "y@example.com", email: "xx@example.com" }],
],
["@@@", [{ name: "", email: '"@@"@' }]],
[
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
[{ name: "", email: '"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"@' }],
],
[
"Nat Ex <{admin@example.com|stocks@example.com|stockmarket@example.com|trades@example.com|money@example.com|broker@example.com|deals@example.com|offers@example.com|news@example.com|binary@example.com|forex@example.com|marketing@example.com|mail@example.com|inboxdeals@example.com|packages@example.com>",
[
{
name: "Nat Ex",
email:
'"{admin@example.com|stocks@example.com|stockmarket@example.com|trades@example.com|money@example.com|broker@example.com|deals@example.com|offers@example.com|news@example.com|binary@example.com|forex@example.com|marketing@example.com|mail@example.com|inboxdeals@example.com|packages"@example.com',
},
],
],
[
"Group: a@b.com, b@c.com;",
[
{
name: "Group",
group: [
{ name: "", email: "a@b.com" },
{ name: "", email: "b@c.com" },
],
},
],
],
[
"a@invalid.invalid, Group: a@b.com;",
[
{ name: "", email: "a@invalid.invalid" },
{ name: "Group", group: [{ name: "", email: "a@b.com" }] },
],
],
[
"Group A: a@b.com;, Group B: b@b.com;",
[
{ name: "Group A", group: [{ name: "", email: "a@b.com" }] },
{ name: "Group B", group: [{ name: "", email: "b@b.com" }] },
],
],
[
'Crazy (<Stupid "name") <simple@a.email>',
[{ name: "Crazy (<Stupid name)", email: "simple@a.email" }],
],
[
"Group: Real <a@b.com>, Fake <a@b.com>",
[
{
name: "Group",
group: [
{ name: "Real", email: "a@b.com" },
{ name: "Fake", email: "a@b.com" },
],
},
],
],
[
'"Joe Q. Public" <john.q.public@example.com>,' +
'Test <"abc!x.yz"@foo.invalid>, Test <test@[xyz!]>,' +
'"Giant; \\"Big\\" Box" <sysservices@example.net>',
[
{ name: "Joe Q. Public", email: "john.q.public@example.com" },
{ name: "Test", email: '"abc!x.yz"@foo.invalid' },
{ name: "Test", email: "test@[xyz!]" },
{ name: 'Giant; "Big" Box', email: "sysservices@example.net" },
],
],
[
"Unfortunate breaking < so . many . spaces @ here . invalid >",
[
{
name: "Unfortunate breaking",
email: "so.many.spaces@here.invalid",
},
],
],
[
"so . many . spaces @ here . invalid",
[{ name: "", email: "so.many.spaces@here.invalid" }],
],
["abc@foo.invalid", [{ name: "", email: "abc@foo.invalid" }]],
["foo <ghj@foo.invalid>", [{ name: "foo", email: "ghj@foo.invalid" }]],
[
"abc@foo.invalid, foo <ghj@foo.invalid>",
[
{ name: "", email: "abc@foo.invalid" },
{ name: "foo", email: "ghj@foo.invalid" },
],
],
[
"foo bar <foo@bar.invalid>",
[{ name: "foo bar", email: "foo@bar.invalid" }],
],
[
"foo bar <foo@bar.invalid>, abc@foo.invalid, foo <ghj@foo.invalid>",
[
{ name: "foo bar", email: "foo@bar.invalid" },
{ name: "", email: "abc@foo.invalid" },
{ name: "foo", email: "ghj@foo.invalid" },
],
],
[
"foo\u00D0 bar <foo@bar.invalid>, \u00F6foo <ghj@foo.invalid>",
[
{ name: "foo\u00D0 bar", email: "foo@bar.invalid" },
{ name: "\u00F6foo", email: "ghj@foo.invalid" },
],
],
[
"Undisclosed recipients:;",
[{ name: "Undisclosed recipients", group: [] }],
],
[
'" "@a a;b',
[
{ name: "", email: '" "@a a' },
{ name: "b", email: "" },
],
],
[
"Undisclosed recipients:;\0:; foo <ghj@veryveryveryverylongveryveryver" +
"yveryinvalidaddress.invalid>",
[
{ name: "Undisclosed recipients", group: [] },
{
name: "foo",
email:
"ghj@veryveryveryverylongveryveryveryveryinvali" +
"daddress.invalid",
},
],
],
// XXX: test_nsIMsgHeaderParser2 has an empty one here...
[
"<a;a@invalid",
[
{ name: "", email: "a" },
{ name: "", email: "a@invalid" },
],
],
["me@foo.invalid", [{ name: "", email: "me@foo.invalid" }]],
[
"me@foo.invalid, me2@foo.invalid",
[
{ name: "", email: "me@foo.invalid" },
{ name: "", email: "me2@foo.invalid" },
],
],
[
'"foo bar" <me@foo.invalid>',
[{ name: "foo bar", email: "me@foo.invalid" }],
],
[
'"foo bar" <me@foo.invalid>, "bar foo" <me2@foo.invalid>',
[
{ name: "foo bar", email: "me@foo.invalid" },
{ name: "bar foo", email: "me2@foo.invalid" },
],
],
[
"A Group:Ed Jones <c@a.invalid>,joe@where.invalid,John <jdoe@one.invalid>;",
[
{
name: "A Group",
group: [
{ name: "Ed Jones", email: "c@a.invalid" },
{ name: "", email: "joe@where.invalid" },
{ name: "John", email: "jdoe@one.invalid" },
],
},
],
],
[
"mygroup:;, empty:;, foo@foo.invalid, othergroup:bar@foo.invalid, bar2" +
"@foo.invalid;, y@y.invalid, empty:;",
[
{ name: "mygroup", group: [] },
{ name: "empty", group: [] },
{ name: "", email: "foo@foo.invalid" },
{
name: "othergroup",
group: [
{ name: "", email: "bar@foo.invalid" },
{ name: "", email: "bar2@foo.invalid" },
],
},
{ name: "", email: "y@y.invalid" },
{ name: "empty", group: [] },
],
],
[
"Undisclosed recipients:;;;;;;;;;;;;;;;;,,,,,,,,,,,,,,,,",
[{ name: "Undisclosed recipients", group: [] }],
],
[
"a@xxx.invalid; b@xxx.invalid",
[
{ name: "", email: "a@xxx.invalid" },
{ name: "", email: "b@xxx.invalid" },
],
],
[
"a@xxx.invalid; B <b@xxx.invalid>",
[
{ name: "", email: "a@xxx.invalid" },
{ name: "B", email: "b@xxx.invalid" },
],
],
[
'"A " <a@xxx.invalid>; b@xxx.invalid',
[
{ name: "A", email: "a@xxx.invalid" },
{ name: "", email: "b@xxx.invalid" },
],
],
[
"A <a@xxx.invalid>; B <b@xxx.invalid>",
[
{ name: "A", email: "a@xxx.invalid" },
{ name: "B", email: "b@xxx.invalid" },
],
],
[
"A (this: is, a comment;) <a.invalid>; g: (this: is, <a> comment;) C" +
"<c.invalid>, d.invalid;",
[
{ name: "A (this: is, a comment;)", email: "a.invalid" },
{
name: "g",
group: [
{ name: "(this: is, <a> comment;) C", email: "c.invalid" },
{ name: "d.invalid", email: "" },
],
},
],
],
[
"Mary Smith <mary@x.invalid>, extra:;, group:jdoe@example.invalid; Who" +
'? <one@y.invalid>; <boss@nil.invalid>, "Giant; \\"Big\\" Box" <sysse' +
"rvices@example.invalid>, ",
[
{ name: "Mary Smith", email: "mary@x.invalid" },
{ name: "extra", group: [] },
{
name: "group",
group: [{ name: "", email: "jdoe@example.invalid" }],
},
{ name: "Who?", email: "one@y.invalid" },
{ name: "", email: "boss@nil.invalid" },
{ name: 'Giant; "Big" Box', email: "sysservices@example.invalid" },
],
],
[
"Undisclosed recipients: a@foo.invalid ;;extra:;",
[
{
name: "Undisclosed recipients",
group: [{ name: "", email: "a@foo.invalid" }],
},
{ name: "extra", group: [] },
],
],
[
"Undisclosed recipients:;;extra:a@foo.invalid;",
[
{ name: "Undisclosed recipients", group: [] },
{ name: "extra", group: [{ name: "", email: "a@foo.invalid" }] },
],
],
["a < <a@b.c>", [{ name: "a", email: "a@b.c" }]],
[
"Name <incomplete@email",
[{ name: "Name", email: "incomplete@email" }],
],
[
"Name <space here@email.invalid>",
[{ name: "Name", email: '"space here"@email.invalid' }],
],
["Name <not an email>", [{ name: "Name", email: "not an email" }]],
[
"=?UTF-8?Q?Simple?= <a@b.c>",
[{ name: "=?UTF-8?Q?Simple?=", email: "a@b.c" }],
],
["No email address", [{ name: "No email address", email: "" }]],
// Thought we were parsing an address, but it was a name.
[
"name@example.com <receiver@example.com>",
[{ name: "name@example.com", email: "receiver@example.com" }],
],
[
"name@huhu.com <receiver@example.com>",
[{ name: "name@huhu.com", email: "receiver@example.com" }],
],
// Some names with quotes.
[
'"name@huhu.com" <receiver@example.com>',
[{ name: "name@huhu.com", email: "receiver@example.com" }],
],
[
'"Chaplin, Charlie" <receiver@example.com>',
[{ name: "Chaplin, Charlie", email: "receiver@example.com" }],
],
[
'"name@huhu.com and name@haha.com" <receiver@example.com>',
[
{
name: "name@huhu.com and name@haha.com",
email: "receiver@example.com",
},
],
],
// Handling of comments and legacy display-names as per RFC 5322 §3.4
[
"(c1)n(c2) <(c3)a(c4)@(c5)b(c6).(c7)d(c8)> (c9(c10)c11)",
[{ name: "(c1) n (c2) (c9(c10)c11)", email: "a@b.d" }],
],
[
"<(c3)a(c4)@(c5)b(c6).(c7)d(c8)> (c9(c10)c11)",
[{ name: "(c9(c10)c11)", email: "a@b.d" }],
],
[
"(c3)a(c4)@(c5)b(c6).(c7)d(c8)(c9(c10)c11)",
[{ name: "c9(c10)c11", email: "a@b.d" }],
],
[
"(c1)n(c2) <(c3)a(c4)@(c5)b(c6).(c7)d(c8)> (c9(c10)c11)(c12)",
[{ name: "(c1) n (c2) (c9(c10)c11) (c12)", email: "a@b.d" }],
],
[
"<(c3)a(c4)@(c5)b(c6).(c7)d(c8)> (c9(c10)c11)(c12)",
[{ name: "(c9(c10)c11) (c12)", email: "a@b.d" }],
],
[
"(c3)a(c4)@(c5)b(c6).(c7)d(c8)(c9(c10)c11)(c12)",
[{ name: "c12", email: "a@b.d" }],
],
// Collapse extraneous whitespace and make sure unexpected characters aren't there.
[
'Friend "<friend@huhu.com>" \t \t \u00A0\u00A0\u2003 \u00AD \x20\u200B\x20\u200B\x20 \t \u034F \u2028 \uDB40\uDD01 \u2800 \t <ws@example.com>',
[{ name: "Friend <friend@huhu.com>", email: "ws@example.com" }],
],
// Collapse multiple "special" spaces like NBSP (\u00A0), EM space (\u2003), etc.
[
"Foe \u00A0\u00A0\u2003 A <foe@example.com>",
[{ name: "Foe A", email: "foe@example.com" }],
],
// Remove tabs.
[
"Tabby \t \t A\t\tB <tab@example.com>",
[{ name: "Tabby A B", email: "tab@example.com" }],
],
// Ensure it's the address in angles that is parsed as address.
[
"<attacker@example.com>friend@example.com\t, bystander@example.com,Someone (some@invalid) <someone@example.com>,",
[
{ name: "", email: "attacker@example.com" },
{ name: "", email: "bystander@example.com" },
{ name: "Someone (some@invalid)", email: "someone@example.com" },
],
],
[
"me (via foo@example.com) <attacker2@example.com>friend2@example.com ",
[
{
name: "me (via foo@example.com)",
email: "attacker2@example.com",
},
],
],
[
"<attacker@example.com> <friend@example.com>,friend2@example.com<attacker2@example.com>",
[
{
name: "",
email: "attacker@example.com",
},
{
name: "friend2@example.com",
email: "attacker2@example.com",
},
],
],
[
'My "XX ><<friend2@example.com>" YY <attacker@example.com> <friend@example.com> ("mr ><x")',
[
{
name: "My XX ><<friend2@example.com> YY (mr ><x)",
email: "attacker@example.com",
},
],
],
];
header_tests.forEach(function (data) {
arrayTest(data, function () {
assert.deepEqual(
headerparser.parseAddressingHeader(data[0], false),
data[1]
);
});
});
});
suite("parseAddressingHeader (RFC 2047 support)", function () {
const header_tests = [
["Simple <a@b.c>", [{ name: "Simple", email: "a@b.c" }]],
["=?UTF-8?Q?Simple?= <a@b.c>", [{ name: "Simple", email: "a@b.c" }]],
["=?UTF-8?Q?=3C@b.c?= <a@b.c>", [{ name: "<@b.c", email: "a@b.c" }]],
// RFC 2047 tokens should not interfere with lexical processing
["=?UTF-8?Q?a@b.c,?= <b@b.c>", [{ name: "a@b.c,", email: "b@b.c" }]],
["=?UTF-8?Q?a@b.c=2C?= <b@b.c>", [{ name: "a@b.c,", email: "b@b.c" }]],
["=?UTF-8?Q?<?= <a@b.c>", [{ name: "<", email: "a@b.c" }]],
[
"Simple =?UTF-8?Q?<?= a@b.c>",
[{ name: "", email: '"Simple < a"@b.c' }],
],
["Tag <=?UTF-8?Q?email?=@b.c>", [{ name: "Tag", email: "email@b.c" }]],
// handling of comments and legacy display-names as per RFC 5322 §3.4
[
"jl1@b.c (=?ISO-8859-1?Q?Joe_L=F6we?=)",
[{ name: "Joe Löwe", email: "jl1@b.c" }],
],
[
"(=?ISO-8859-1?Q?Joe_L=F6we?=) jl2@b.c",
[{ name: "Joe Löwe", email: "jl2@b.c" }],
],
[
"(=?ISO-8859-1?Q?Joe_L=F6we?=) jl3@b.c (c2)",
[{ name: "c2", email: "jl3@b.c" }],
],
[
"=?ISO-8859-1?Q?Joe_L=F6we?= <jl3@b.c> (c2)",
[{ name: "Joe Löwe (c2)", email: "jl3@b.c" }],
],
[
"(=?ISO-8859-1?Q?Joe_L=F6we?=) <jl3@b.c> (c2)",
[{ name: "(Joe Löwe) (c2)", email: "jl3@b.c" }],
],
// Bug 1141446: Malformed From addresses with erroneous quotes,
// note: acute accents: a \u00E1, e \u00E9, i \u00ED, o \u00F3, u \u00FA.
[
'"=?UTF-8?Q?Jazzy_Fern=C3=A1ndez_Nunoz?= jazzy.f.nunoz@example.com ' +
'[BCN-FC]" <Barcelona-Freecycle-noreply@yahoogroups.com>',
[
{
name: "Jazzy Fern\u00E1ndez Nunoz jazzy.f.nunoz@example.com [BCN-FC]",
email: "Barcelona-Freecycle-noreply@yahoogroups.com",
},
],
],
[
'"=?UTF-8?B?TWlyaWFtIEJlcm5hYsOpIFBlcmVsbMOz?= miriam@example.com ' +
'[BCN-FC]" <Barcelona-Freecycle-noreply@yahoogroups.com>',
[
{
name: "Miriam Bernab\u00E9 Perell\u00F3 miriam@example.com [BCN-FC]",
email: "Barcelona-Freecycle-noreply@yahoogroups.com",
},
],
],
[
'"=?iso-8859-1?Q?First_Mar=EDa_Furi=F3_Gancho?= mail@yahoo.es ' +
'[BCN-FC]" <Barcelona-Freecycle-noreply@yahoogroups.com>',
[
{
name: "First Mar\u00EDa Furi\u00F3 Gancho mail@yahoo.es [BCN-FC]",
email: "Barcelona-Freecycle-noreply@yahoogroups.com",
},
],
],
[
'"=?iso-8859-1?B?U29maWEgQ2FzdGVsbPMgUm9tZXJv?= sonia@example.com ' +
'[BCN-FC]" <Barcelona-Freecycle-noreply@yahoogroups.com>',
[
{
name: "Sofia Castell\u00F3 Romero sonia@example.com [BCN-FC]",
email: "Barcelona-Freecycle-noreply@yahoogroups.com",
},
],
],
[
"=?iso-8859-1?Q?Klaus_Eisschl=E4ger_=28k=2Eeisschlaeger=40t-onli?=" +
"=?iso-8859-1?Q?ne=2Ede=29?= <k.eisschlaeger@t-online.de>",
[
{
name: "Klaus Eisschläger (k.eisschlaeger@t-online.de)",
email: "k.eisschlaeger@t-online.de",
},
],
],
[
'"=?UTF-8?Q?=22Claudia_R=C3=B6hschicht=22?= Claudia_Roehschicht@web.de [freecycle-berlin]" ' +
"<freecycle-berlin-noreply@yahoogroups.de>",
[
{
name: '"Claudia Röhschicht" Claudia_Roehschicht@web.de [freecycle-berlin]',
email: "freecycle-berlin-noreply@yahoogroups.de",
},
],
],
// Collapse multiple consecutive "special" spaces, like zero width space
// etc.
// \u00AD is soft hyphen. \u200B is zero width space.
[
`invisiblespaceA@friend.example.com B \u200B\u00AD \u200B \u200B A. <foeA@example.com>`,
[
{
name: "invisiblespaceA@friend.example.com B A.",
email: "foeA@example.com",
},
],
],
// Collapse multiple consecutive "special" spaces, like zero width space
// etc. also when encoded.
// \u00AD is soft hyphen. \u200B is zero width space.
// unescape(encodeURIComponent(source)) encodes the JavaScript UTF-16 representation
// of the string into UTF-8. Example: encodeURIComponent("ö") returns "%C3%B6",
// unescape("%C3%B6") returns the bytes 0xC3B6 which is the UTF-8 encoding of "ö".
// See bug 1551746 for other ways.
[
//"=?UTF-8?B?IMKgIGJsw7YgPGludmlzaWJsZXNwYWNlQGZyaWVuZC5leGFtcGxlLmNvbT4g4oCLIOKAiyDigIsu=?= <foe@example.com>"
`=?UTF-8?B?${btoa(
unescape(
encodeURIComponent(
" \u00AD blö <invisiblespace@friend.example.com> \u200B \u200B \u200B."
)
)
)}?= <foe@example.com>`,
[
{
name: "blö <invisiblespace@friend.example.com> .",
email: "foe@example.com",
},
],
],
];
header_tests.forEach(function (data) {
arrayTest(data, function () {
assert.deepEqual(
headerparser.parseAddressingHeader(data[0], true),
data[1]
);
});
});
});
suite("parseDateHeader", function () {
const header_tests = [
// Some basic tests, derived from searching for Date headers in a mailing
// list archive.
["Thu, 06 Sep 2012 08:08:21 -0700", "2012-09-06T08:08:21-0700"],
["Thu, 6 Sep 2012 14:49:05 -0400", "2012-09-06T14:49:05-0400"],
["Fri, 07 Sep 2012 07:30:11 -0700 (PDT)", "2012-09-07T07:30:11-0700"],
["9 Sep 2012 21:03:59 -0000", "2012-09-09T21:03:59Z"],
["Sun, 09 Sep 2012 19:10:59 -0400", "2012-09-09T19:10:59-0400"],
["Wed, 17 Jun 2009 10:12:25 +0530", "2009-06-17T10:12:25+0530"],
// Exercise all the months.
["Mon, 28 Jan 2013 13:35:05 -0500", "2013-01-28T13:35:05-0500"],
["Wed, 29 Feb 2012 23:43:26 +0000", "2012-02-29T23:43:26+0000"],
["Sat, 09 Mar 2013 18:24:47 -0500", "2013-03-09T18:24:47-0500"],
["Sat, 27 Apr 2013 12:51:48 -0400", "2013-04-27T12:51:48-0400"],
["Tue, 28 May 2013 17:21:13 +0800", "2013-05-28T17:21:13+0800"],
["Mon, 17 Jun 2013 22:15:41 +0200", "2013-06-17T22:15:41+0200"],
["Wed, 18 Jul 2012 13:50:47 +0900", "2012-07-18T13:50:47+0900"],
["Mon, 13 Aug 2012 13:55:16 +0200", "2012-08-13T13:55:16+0200"],
["Thu, 06 Sep 2012 19:49:47 -0400", "2012-09-06T19:49:47-0400"],
["Mon, 22 Oct 2012 02:27:23 -0700", "2012-10-22T02:27:23-0700"],
["Thu, 22 Nov 2012 09:04:24 +0800", "2012-11-22T09:04:24+0800"],
["Sun, 25 Dec 2011 12:27:13 +0000", "2011-12-25T12:27:13+0000"],
// Try out less common timezone offsets.
["Sun, 25 Dec 2011 12:27:13 +1337", "2011-12-25T12:27:13+1337"],
["Sun, 25 Dec 2011 12:27:13 -1337", "2011-12-25T12:27:13-1337"],
// Leap seconds! Except that since dates in JS don't believe they exist,
// they get shoved to the next second.
["30 Jun 2012 23:59:60 +0000", "2012-07-01T00:00:00Z"],
["31 Dec 2008 23:59:60 +0000", "2009-01-01T00:00:00Z"],
// This one doesn't exist (they are added only as needed on an irregular
// basis), but it's plausible...
["30 Jun 2030 23:59:60 +0000", "2030-07-01T00:00:00Z"],
// ... and this one isn't.
["10 Jun 2030 13:39:60 +0000", "2030-06-10T13:40:00Z"],
// How about leap seconds in other timezones?
["30 Jun 2012 18:59:60 -0500", "2012-07-01T00:00:00Z"],
// RFC 5322 obsolete date productions
["Sun, 26 Jan 14 17:14:22 -0600", "2014-01-26T17:14:22-0600"],
["Tue, 26 Jan 49 17:14:22 -0600", "2049-01-26T17:14:22-0600"],
["Thu, 26 Jan 50 17:14:22 -0600", "1950-01-26T17:14:22-0600"],
["Sun, 26 Jan 2014 17:14:22 EST", "2014-01-26T17:14:22-0500"],
["Sun, 26 Jan 2014 17:14:22 CST", "2014-01-26T17:14:22-0600"],
["Sun, 26 Jan 2014 17:14:22 MST", "2014-01-26T17:14:22-0700"],
["Sun, 26 Jan 2014 17:14:22 PST", "2014-01-26T17:14:22-0800"],
["Sun, 26 Jan 2014 17:14:22 AST", "2014-01-26T17:14:22-0400"],
["Sun, 26 Jan 2014 17:14:22 NST", "2014-01-26T17:14:22-0330"],
["Sun, 26 Jan 2014 17:14:22 MET", "2014-01-26T17:14:22+0100"],
["Sun, 26 Jan 2014 17:14:22 EET", "2014-01-26T17:14:22+0200"],
["Sun, 26 Jan 2014 17:14:22 JST", "2014-01-26T17:14:22+0900"],
["Sun, 26 Jan 2014 17:14:22 GMT", "2014-01-26T17:14:22+0000"],
["Sun, 26 Jan 2014 17:14:22 UT", "2014-01-26T17:14:22+0000"],
// Daylight savings timezones, even though these aren't actually during
// daylight savings time for the relevant jurisdictions.
["Sun, 26 Jan 2014 17:14:22 EDT", "2014-01-26T17:14:22-0400"],
["Sun, 26 Jan 2014 17:14:22 CDT", "2014-01-26T17:14:22-0500"],
["Sun, 26 Jan 2014 17:14:22 MDT", "2014-01-26T17:14:22-0600"],
["Sun, 26 Jan 2014 17:14:22 PDT", "2014-01-26T17:14:22-0700"],
["Sun, 26 Jan 2014 17:14:22 BST", "2014-01-26T17:14:22+0100"],
// Unknown time zone--assume UTC
["Sun, 26 Jan 2014 17:14:22 QMT", "2014-01-26T17:14:22+0000"],
// The following days of the week are incorrect.
["Tue, 28 Jan 2013 13:35:05 -0500", "2013-01-28T13:35:05-0500"],
["Thu, 26 Jan 14 17:14:22 -0600", "2014-01-26T17:14:22-0600"],
["Fri, 26 Jan 49 17:14:22 -0600", "2049-01-26T17:14:22-0600"],
["Mon, 26 Jan 50 17:14:22 -0600", "1950-01-26T17:14:22-0600"],
// And for these 2 digit years, they are correct for the other century.
["Mon, 26 Jan 14 17:14:22 -0600", "2014-01-26T17:14:22-0600"],
["Wed, 26 Jan 49 17:14:22 -0600", "2049-01-26T17:14:22-0600"],
["Wed, 26 Jan 50 17:14:22 -0600", "1950-01-26T17:14:22-0600"],
// Try with some illegal names for days of the week or months of the year.
["Sam, 05 Apr 2014 15:04:13 -0500", "2014-04-05T15:04:13-0500"],
["Lun, 01 Apr 2014 15:04:13 -0500", "2014-04-01T15:04:13-0500"],
["Mar, 02 Apr 2014 15:04:13 -0500", "2014-04-02T15:04:13-0500"],
["Mar, 02 April 2014 15:04:13 -0500", "2014-04-02T15:04:13-0500"],
["Mar, 02 Avr 2014 15:04:13 -0500", NaN],
["Tue, 02 A 2014 15:04:13 -0500", NaN],
// A truly invalid date
["Coincident with the rapture", NaN],
];
header_tests.forEach(function (data) {
arrayTest(data, function () {
assert.equal(
headerparser.parseDateHeader(data[0]).toString(),
new Date(data[1]).toString()
);
});
});
});
suite("decodeRFC2047Words", function () {
const header_tests = [
// Some basic sanity tests for the test process
["Test", "Test"],
["Test 2", "Test 2"],
["Basic words", "Basic words"],
["Not a =? word", "Not a =? word"],
// Simple 2047 decodings
["=?UTF-8?Q?Encoded?=", "Encoded"],
["=?UTF-8?q?Encoded?=", "Encoded"],
["=?ISO-8859-1?Q?oxyg=e8ne?=", "oxyg\u00e8ne"],
["=?UTF-8?B?QmFzZTY0?=", "Base64"],
["=?UTF-8?b?QmFzZTY0?=", "Base64"],
["=?UTF-8?Q?A_space?=", "A space"],
["=?UTF-8?Q?A space?=", "A space"],
["A =?UTF-8?Q?B?= C", "A B C"],
["=?UTF-8?Q?A?= =?UTF-8?Q?B?=", "AB"],
["=?UTF-8?Q?oxyg=c3=a8ne?=", "oxyg\u00e8ne"],
["=?utf-8?Q?oxyg=C3=A8ne?=", "oxyg\u00e8ne"],
["=?UTF-8?B?b3h5Z8OobmU=?=", "oxyg\u00e8ne"],
["=?UTF-8*fr?B?b3h5Z8OobmU=?=", "oxyg\u00e8ne"],
[
"=?BIG5?Q?=B9=CF=AE=D1=C0]SSCI=A4=CEJCR=B8=EA=AE=C6=AEw=C1=BF=B2=DF=A1A=A8" +
"=F3=A7U=B1z=A1u=B4=A3=A4=C9=AC=E3=A8s=AF=C0=BD=E8=BBP=AE=C4=B2v=A5H=A4=CE" +
"=A7=EB=BDZ=B5=A6=B2=A4=AA=BA=B9B=A5=CE=A1v=A1A=C5w=AA=EF=B3=F8=A6W=B0=D1" +
"=A5[=A1C?=",
"\u5716\u66F8\u9928SSCI\u53CAJCR\u8CC7\u6599\u5EAB\u8B1B" +
"\u7FD2\uFF0C\u5354\u52A9\u60A8\u300C\u63D0\u5347\u7814\u7A76\u7D20\u8CEA" +
"\u8207\u6548\u7387\u4EE5\u53CA\u6295\u7A3F\u7B56\u7565\u7684\u904B\u7528" +
"\u300D\uFF0C\u6B61\u8FCE\u5831\u540D\u53C3\u52A0\u3002",
],
// Invalid decodings
["=?UTF-8?Q?=f0ab?=", "\ufffdab"],
["=?UTF-8?Q?=f0?= ab", "\ufffd ab"],
[
"=?UTF-8?Q?=ed=a0=bd=ed=b2=a9?=",
"\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd",
],
["=?NoSuchCharset?Q?ab?=", "=?NoSuchCharset?Q?ab?="],
["=?UTF-8?U?Encoded?=", "=?UTF-8?U?Encoded?="],
["=?UTF-8?Q?Almost", "=?UTF-8?Q?Almost"],
// Try some non-BMP characters in various charsets
["=?UTF-8?B?8J+SqQ==?=", "\ud83d\udca9"],
// The goal for the next one is to be a non-BMP in a non-full-Unicode
// charset. The only category where this exists is a small set of
// characters in Big5, which were previously mapped to a PUA in an older
// version but then reassigned to Plane 1. However, Big5 is really a set
// of slightly different, slightly incompatible charsets.
// TODO: This requires future investigation. Bug 912470 discusses the
// changes to Big5 proposed within Mozilla.
// ["=?Big5?Q?=87E?=", "\ud85c\ude67"],
["=?GB18030?B?lDnaMw==?=", "\ud83d\udca9"],
// How to handle breaks in multi-byte encoding
["=?UTF-8?Q?=f0=9f?= =?UTF-8?Q?=92=a9?=", "\ud83d\udca9"],
["=?UTF-8?B?8J+S?= =?UTF-8?B?qQ==?=", "\ud83d\udca9"],
["=?UTF-8?B?8J+S?= =?UTF-8?Q?=a9?=", "\ud83d\udca9"],
["=?UTF-8?B?8J+S?= =?ISO-8859-1?B?qQ==?=", "\ufffd\u00a9"],
["=?UTF-8?Q?=f0?= =?UTF-8?Q?ab?=", "\ufffdab"],
// This is a split non-BMP character.
[
"=?UTF-8?B?YfCfkqnwn5Kp8J+SqfCfkqnwn5Kp8J+SqfCfkqnvv70=?= =?UTF-8?B?77+9?=",
"a\uD83D\uDCA9\uD83D\uDCA9\uD83D\uDCA9\uD83D\uDCA9\uD83D\uDCA9\uD83D" +
"\uDCA9\uD83D\uDCA9\uFFFD\uFFFD",
],
// Spaces in RFC 2047 tokens
["=?UTF-8?Q?Invalid token?=", "Invalid token"],
// More tests from bug 493544
[
"AAA =?UTF-8?Q?bbb?= CCC =?UTF-8?Q?ddd?= EEE =?UTF-8?Q?fff?= GGG",
"AAA bbb CCC ddd EEE fff GGG",
],
[
"=?UTF-8?B?4oiAICDiiIEgIOKIgiAg4oiDICDiiIQgIOKIhSAg4oiGICDiiIcgIOKIiC" +
"Ag?=\n =?UTF-8?B?4oiJICDiiIogIOKIiyAg4oiMICDiiI0gIOKIjiAg4oiP?=",
"\u2200 \u2201 \u2202 \u2203 \u2204 \u2205 \u2206 \u2207 " +
"\u2208 \u2209 \u220a \u220b \u220c \u220d \u220e \u220f",
],
[
"=?utf-8?Q?=E2=88=80__=E2=88=81__=E2=88=82__=E2=88=83__=E2=88=84__=E2" +
"?=\n =?utf-8?Q?=88=85__=E2=88=86__=E2=88=87__=E2=88=88__=E2=88=89__" +
"=E2=88?=\n =?utf-8?Q?=8A__=E2=88=8B__=E2=88=8C__=E2=88=8D__=E2=88=8" +
"E__=E2=88=8F?=",
"\u2200 \u2201 \u2202 \u2203 \u2204 \u2205 \u2206 \u2207 " +
"\u2208 \u2209 \u220a \u220b \u220c \u220d \u220e \u220f",
],
[
"=?UTF-8?B?4oiAICDiiIEgIOKIgiAg4oiDICDiiIQgIOKIhSAg4oiGICDiiIcgIOKIiA" +
"==?=\n =?UTF-8?B?ICDiiIkgIOKIiiAg4oiLICDiiIwgIOKIjSAg4oiOICDiiI8=?=",
"\u2200 \u2201 \u2202 \u2203 \u2204 \u2205 \u2206 \u2207 " +
"\u2208 \u2209 \u220a \u220b \u220c \u220d \u220e \u220f",
],
[
"=?UTF-8?b?4oiAICDiiIEgIOKIgiAg4oiDICDiiIQgIOKIhSAg4oiGICDiiIcgIOKIiA" +
"==?=\n =?UTF-8?b?ICDiiIkgIOKIiiAg4oiLICDiiIwgIOKIjSAg4oiOICDiiI8=?=",
"\u2200 \u2201 \u2202 \u2203 \u2204 \u2205 \u2206 \u2207 " +
"\u2208 \u2209 \u220a \u220b \u220c \u220d \u220e \u220f",
],
[
"=?utf-8?Q?=E2=88=80__=E2=88=81__=E2=88=82__=E2=88=83__=E2=88=84__?=\n" +
" =?utf-8?Q?=E2=88=85__=E2=88=86__=E2=88=87__=E2=88=88__=E2=88=89__?=\n" +
" =?utf-8?Q?=E2=88=8A__=E2=88=8B__=E2=88=8C__=E2=88=8D__=E2=88=8E__?=\n" +
" =?utf-8?Q?=E2=88=8F?=",
"\u2200 \u2201 \u2202 \u2203 \u2204 \u2205 \u2206 \u2207 " +
"\u2208 \u2209 \u220a \u220b \u220c \u220d \u220e \u220f",
],
[
"=?utf-8?q?=E2=88=80__=E2=88=81__=E2=88=82__=E2=88=83__=E2=88=84__?=\n" +
" =?utf-8?q?=E2=88=85__=E2=88=86__=E2=88=87__=E2=88=88__=E2=88=89__?=\n" +
" =?utf-8?q?=E2=88=8A__=E2=88=8B__=E2=88=8C__=E2=88=8D__=E2=88=8E__?=\n" +
" =?utf-8?q?=E2=88=8F?=",
"\u2200 \u2201 \u2202 \u2203 \u2204 \u2205 \u2206 \u2207 " +
"\u2208 \u2209 \u220a \u220b \u220c \u220d \u220e \u220f",
],
[
"=?UTF-8?B?4oiAICDiiIEgIOKIgiAg4oiDICDiiIQgIOKIhSAg4oiGICDiiIcgIOKIiA=" +
"==?=\n =?UTF-8?B?ICDiiIkgIOKIiiAg4oiLICDiiIwgIOKIjSAg4oiOICDiiI8=?=",
"\u2200 \u2201 \u2202 \u2203 \u2204 \u2205 \u2206 \u2207 " +
"\u2208 \u2209 \u220a \u220b \u220c \u220d \u220e \u220f",
],
// Some interesting headers found in the wild:
// Bug 1498795: Tolerate spaces in base64-encoded RFC 2047 tokens.
[
"=?UTF-8?B?Q29uc2lndW Ug dG9kbyBlbCBmw7p0Ym9sIA==?= =?iso-8859-1?" +
"B?Y2 9uI EZVU0nTTiBjb24g?= =?windows-1252?B?ZX N 0ZSBvZmVydPNu?=",
"Consigue todo el f\u00fatbol con FUSI\u00d3N con este ofert\u00f3n",
],
["=?us-ascii?Q?=09Edward_Rosten?=", "\tEdward Rosten"],
[
"=?us-ascii?Q?=3D=3FUTF-8=3FQ=3Ff=3DC3=3DBCr=3F=3D?=",
"=?UTF-8?Q?f=C3=BCr?=",
],
// We don't decode unrecognized charsets (This one is actually UTF-8).
["=??B?Sy4gSC4gdm9uIFLDvGRlbg==?=", "=??B?Sy4gSC4gdm9uIFLDvGRlbg==?="],
// Test for bug 1374149 with ISO-2022-JP where we shouldn't stream
// if the first token ends in ESC(B.
// GyRCJCIbKEI= is the base64 encoding of ESC$B$"ESC(B.
[
"=?ISO-2022-JP?B?GyRCJCIbKEI=?==?ISO-2022-JP?B?GyRCJCIbKEI=?=",
"ああ",
],
// Tolerate invalid split of character, € = 0xE2 0x82 0xAC in UTF-8.
[
"Split =?UTF-8?Q?=E2?= =?UTF-8?Q?=82=AC?= after first byte",
"Split € after first byte",
],
[
"Split =?UTF-8?Q?=E2=82?= =?UTF-8?Q?=AC?= after second byte",
"Split € after second byte",
],
["Byte missing =?UTF-8?Q?=E2=82?=", "Byte missing \ufffd"], // Replacement character for invalid input.
// Test for bug 1301989: Tolerate invalid base64 encoding.
["=?us-ascii?B?YWJjZA==?=", "abcd"], // correct
["=?us-ascii?B?YWJjZA=?=", "abc"], // not a multiple of 4
["=?us-ascii?B?Y=WJjZA==?=", "abcd"], // invalid =
["=?us-ascii?B?Y=WJj==ZA==?=", "abcd"], // invalid =
["=?us-ascii?B?YWJjZA===?=", "abcd"], // excess = at the end, see bug 227290.
// Test for bug 1437282: Tolerate extra = padding at the end.
["=?us-ascii?B?VGVzdA==?=", "Test"], // This is correct.
["=?us-ascii?B?VGVzdA===?=", "Test"],
["=?us-ascii?B?VGVzdA====?=", "Test"],
["=?us-ascii?B?VGVzdA=====?=", "Test"],
["=?us-ascii?B?VGVzdA======?=", "Test"],
["=?us-ascii?B?VGVzdA========?=", "Test"],
["=?us-ascii?B?VGVzdA=========?=", "Test"],
["=?us-ascii?B?VGVzdA==========?=", "Test"],
["=?us-ascii?B?VGVzdA===========?=", "Test"],
];
header_tests.forEach(function (data) {
arrayTest(data, function () {
assert.deepEqual(headerparser.decodeRFC2047Words(data[0]), data[1]);
});
});
});
suite("8-bit header processing", function () {
const header_tests = [
// Non-ASCII header values
["oxyg\xc3\xa8ne", "oxyg\u00e8ne", "UTF-8"],
["oxyg\xc3\xa8ne", "oxyg\u00e8ne", "ISO-8859-1"], // UTF-8 overrides
["oxyg\xc3\xa8ne", "oxyg\u00e8ne"], // default to UTF-8 if no charset
["oxyg\xe8ne", "oxyg\ufffdne", "UTF-8"],
["oxyg\xe8ne", "oxyg\u00e8ne", "ISO-8859-1"],
["\xc3\xa8\xe8", "\u00e8\ufffd", "UTF-8"],
["\xc3\xa8\xe8", "\u00c3\u00a8\u00e8", "ISO-8859-1"],
// Don't fallback to UTF-16 or UTF-32
["\xe8S!0", "\ufffdS!0", "UTF-16"],
["\xe8S!0", "\ufffdS!0", "UTF-16be"],
["\xe8S!0", "\ufffdS!0", "UTF-32"],
["\xe8S!0", "\ufffdS!0", "utf-32"],
// Don't combine encoded-word and header charset decoding
["=?UTF-8?Q?=c3?= \xa8", "\ufffd \ufffd", "UTF-8"],
["=?UTF-8?Q?=c3?= \xa8", "\ufffd \u00a8", "ISO-8859-1"],
["\xc3 =?UTF-8?Q?=a8?=", "\ufffd \ufffd", "UTF-8"],
["\xc3 =?UTF-8?Q?=a8?=", "\u00c3 \ufffd", "ISO-8859-1"],
];
header_tests.forEach(function (data) {
arrayTest(data, function () {
assert.deepEqual(
headerparser.decodeRFC2047Words(
headerparser.convert8BitHeader(
data[0],
data.length > 2 ? data[2] : null
)
),
data[1]
);
});
});
});
});
});