diff options
Diffstat (limited to 'comm/mailnews/mime/test/unit/test_attachment_size.js')
-rw-r--r-- | comm/mailnews/mime/test/unit/test_attachment_size.js | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/comm/mailnews/mime/test/unit/test_attachment_size.js b/comm/mailnews/mime/test/unit/test_attachment_size.js new file mode 100644 index 0000000000..cf6e68f0bf --- /dev/null +++ b/comm/mailnews/mime/test/unit/test_attachment_size.js @@ -0,0 +1,322 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * This test creates some messages with attachments of different types and + * checks that libmime reports the expected size for each of them. + */ + +var { + MessageGenerator, + SyntheticPartLeaf, + SyntheticPartMultiMixed, + SyntheticMessageSet, +} = ChromeUtils.import( + "resource://testing-common/mailnews/MessageGenerator.jsm" +); +var { MessageInjection } = ChromeUtils.import( + "resource://testing-common/mailnews/MessageInjection.jsm" +); +var { PromiseTestUtils } = ChromeUtils.import( + "resource://testing-common/mailnews/PromiseTestUtils.jsm" +); + +// Somehow we hit the blocklist service, and that needs appInfo defined +const { updateAppInfo } = ChromeUtils.importESModule( + "resource://testing-common/AppInfo.sys.mjs" +); +updateAppInfo(); + +var messenger = Cc["@mozilla.org/messenger;1"].createInstance(Ci.nsIMessenger); + +// Create a message generator +var msgGen = new MessageGenerator(); +var messageInjection = new MessageInjection({ mode: "local" }); +var inbox = messageInjection.getInboxFolder(); + +/* Today's gory details (thanks to Jonathan Protzenko): libmime somehow + * counts the trailing newline for an attachment MIME part. Most of the time, + * assuming attachment has N bytes (no matter what's inside, newlines or + * not), libmime will return N + 1 bytes. On Linux and Mac, this always + * holds. However, on Windows, if the attachment is not encoded (that is, is + * inline text), libmime will return N + 2 bytes. + */ +const EPSILON = "@mozilla.org/windows-registry-key;1" in Cc ? 4 : 2; + +const TEXT_ATTACHMENT = + "Can't make the frug contest, Helen; stomach's upset. I'll fix you, " + + "Ubik! Ubik drops you back in the thick of things fast. Taken as " + + "directed, Ubik speeds relief to head and stomach. Remember: Ubik is " + + "only seconds away. Avoid prolonged use."; + +const BINARY_ATTACHMENT = TEXT_ATTACHMENT; + +const IMAGE_ATTACHMENT = + "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAABHNCSVQICAgIfAhkiAAAAAlwS" + + "FlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAA" + + "A5SURBVCiRY/z//z8DKYCJJNXkaGBgYGD4D8NQ5zUgiTVAxeBqSLaBkVRPM0KtIhrQ3km0jwe" + + "SNQAAlmAY+71EgFoAAAAASUVORK5CYII="; +const IMAGE_SIZE = 188; + +const UU_ATTACHMENT = + "begin 644 /home/jvporter/Desktop/out.txt\n" + + 'M0V%N)W0@;6%K92!T:&4@9G)U9R!C;VYT97-T+"!(96QE;CL@<W1O;6%C:"=S\n' + + "M('5P<V5T+B!))VQL(&9I>\"!Y;W4L(%5B:6LA(%5B:6L@9')O<',@>6]U(&)A\n" + + "M8VL@:6X@=&AE('1H:6-K(&]F('1H:6YG<R!F87-T+B!486ME;B!A<R!D:7)E\n" + + "M8W1E9\"P@56)I:R!S<&5E9',@<F5L:65F('1O(&AE860@86YD('-T;VUA8V@N\n" + + "M(%)E;65M8F5R.B!58FEK(&ES(&]N;'D@<V5C;VYD<R!A=V%Y+B!!=F]I9\"!P\n" + + ".<F]L;VYG960@=7-E+@H`\n" + + "`\n" + + "end"; + +const YENC_TEXT = + "Hello there --\n" + + "=ybegin line=128 size=174 name=jane\n" + + "\x76\x99\x98\x91\x9e\x8f\x97\x9a\x9d\x56\x4a\x94\x8f\x4a\x97\x8f" + + "\x4a\x9d\x9f\x93\x9d\x4a\x8d\x99\x9f\x8d\x92\xed\xd3\x4a\x8e\x8f" + + "\x4a\x8c\x99\x98\x98\x8f\x4a\x92\x8f\x9f\x9c\x8f\x58\x4a\x7a\x8b" + + "\x9c\x90\x99\x93\x9d\x56\x4a\xed\xca\x4a\x9a\x8f\x93\x98\x8f\x4a" + + "\x97\x8b\x4a\x8c\x99\x9f\x91\x93\x8f\x4a\xed\xd3\x9e\x8f\x93\x98" + + "\x9e\x8f\x56\x4a\x97\x8f\x9d\x4a\xa3\x8f\x9f\xa2\x4a\x9d\x8f\x4a" + + "\x90\x8f\x9c\x97\x8b\x93\x8f\x98\x9e\x4a\x9d\x93\x4a\xa0\x93\x9e" + + "\x8f\x4a\x9b\x9f\x8f\x4a\x94\x8f\x4a\x98\x51\x8b\xa0\x8b\x93\x9d" + + "\x0d\x0a\x4a\x9a\x8b\x9d\x4a\x96\x8f\x4a\x9e\x8f\x97\x9a\x9d\x4a" + + "\x8e\x8f\x4a\x97\x8f\x4a\x8e\x93\x9c\x8f\x4a\x64\x4a\xec\xd5\x4a" + + "\x74\x8f\x4a\x97\x51\x8f\x98\x8e\x99\x9c\x9d\x58\x4a\xec\xe5\x34" + + "\x0d\x0a" + + "=yend size=174 crc32=7efccd8e\n"; +const YENC_SIZE = 174; + +const PART_HTML = new SyntheticPartLeaf( + "<html><head></head><body>I am HTML! Woo! </body></html>", + { + contentType: "text/html", + } +); + +var attachedMessage1 = msgGen.makeMessage({ body: { body: TEXT_ATTACHMENT } }); +var attachedMessage2 = msgGen.makeMessage({ + body: { body: TEXT_ATTACHMENT }, + attachments: [ + { + body: IMAGE_ATTACHMENT, + contentType: "application/x-ubik", + filename: "ubik", + encoding: "base64", + format: "", + }, + ], +}); + +add_task(async function test_text_attachment() { + await test_message_attachments({ + attachments: [ + { + body: TEXT_ATTACHMENT, + filename: "ubik.txt", + format: "", + }, + ], + size: TEXT_ATTACHMENT.length, + }); +}); + +// (inline) image attachment +add_task(async function test_inline_image_attachment() { + await test_message_attachments({ + attachments: [ + { + body: IMAGE_ATTACHMENT, + contentType: "image/png", + filename: "lines.png", + encoding: "base64", + format: "", + }, + ], + size: IMAGE_SIZE, + }); +}); + +// binary attachment, no encoding +add_task(async function test_binary_attachment_no_encoding() { + await test_message_attachments({ + attachments: [ + { + body: BINARY_ATTACHMENT, + contentType: "application/x-ubik", + filename: "ubik", + format: "", + }, + ], + size: BINARY_ATTACHMENT.length, + }); +}); + +// binary attachment, b64 encoding +add_task(async function test_binary_attachment_b64_encoding() { + await test_message_attachments({ + attachments: [ + { + body: IMAGE_ATTACHMENT, + contentType: "application/x-ubik", + filename: "ubik", + encoding: "base64", + format: "", + }, + ], + size: IMAGE_SIZE, + }); +}); + +// uuencoded attachment +add_task(async function test_uuencoded_attachment() { + await test_message_attachments({ + attachments: [ + { + body: UU_ATTACHMENT, + contentType: "application/x-uuencode", + filename: "ubik", + format: "", + encoding: "uuencode", + }, + ], + size: TEXT_ATTACHMENT.length, + }); +}); + +// yencoded attachment +add_task(async function test_yencoded_attachment() { + await test_message_attachments({ + bodyPart: new SyntheticPartLeaf("I am text! Woo!\n\n" + YENC_TEXT, { + contentType: "", + }), + subject: 'yEnc-Prefix: "jane" 174 yEnc bytes - yEnc test (1)', + size: YENC_SIZE, + }); +}); + +// an attached eml that used to return a size that's -1 +add_task(async function test_incorrect_attached_eml() { + await test_message_attachments({ + bodyPart: new SyntheticPartMultiMixed([PART_HTML, attachedMessage1]), + size: get_message_size(attachedMessage1), + }); +}); + +// this is an attached message that itself has an attachment +add_task(async function test_recursive_attachment() { + await test_message_attachments({ + bodyPart: new SyntheticPartMultiMixed([PART_HTML, attachedMessage2]), + size: get_message_size(attachedMessage2), + }); +}); + +// an "attachment" that's really the body of the message +add_task(async function test_body_attachment() { + await test_message_attachments({ + body: { + body: TEXT_ATTACHMENT, + contentType: "application/x-ubik; name=attachment.ubik", + }, + size: TEXT_ATTACHMENT.length, + }); +}); + +// a message/rfc822 "attachment" that's really the body of the message +add_task(async function test_rfc822_attachment() { + await test_message_attachments({ + bodyPart: attachedMessage1, + size: get_message_size(attachedMessage1), + }); +}); + +// an external http link attachment (as constructed for feed enclosures) - no 'size' parm. +add_task(async function test_external_http_link_without_size() { + await test_message_attachments({ + attachments: [ + { + body: "This MIME attachment is stored separately from the message.", + contentType: 'application/unknown; name="somefile"', + extraHeaders: { + "X-Mozilla-External-Attachment-URL": "http://myblog.com/somefile", + }, + disposition: 'attachment; filename="somefile"', + }, + ], + size: -1, + }); +}); + +// an external http link attachment (as constructed for feed enclosures) - file with 'size' parm. +add_task(async function test_external_http_link_wit_file_size() { + await test_message_attachments({ + attachments: [ + { + body: "This MIME attachment is stored separately from the message.", + contentType: 'audio/mpeg; name="file.mp3"; size=123456789', + extraHeaders: { + "X-Mozilla-External-Attachment-URL": "https://myblog.com/file.mp3", + }, + disposition: 'attachment; name="file.mp3"', + }, + ], + size: 123456789, + }); +}); + +add_task(function endTest() { + messageInjection.teardownMessageInjection(); +}); + +async function test_message_attachments(info) { + let synMsg = msgGen.makeMessage(info); + let synSet = new SyntheticMessageSet([synMsg]); + await messageInjection.addSetsToFolders([inbox], [synSet]); + + let msgURI = synSet.getMsgURI(0); + let msgService = MailServices.messageServiceFromURI(msgURI); + await PromiseTestUtils.promiseDelay(200); + let streamListener = new PromiseTestUtils.PromiseStreamListener({ + onStopRequest(request) { + request.QueryInterface(Ci.nsIMailChannel); + for (let attachment of request.attachments) { + let attachmentSize = parseInt(attachment.get("X-Mozilla-PartSize")); + dump( + "*** Size is " + attachmentSize + " (expecting " + info.size + ")\n" + ); + Assert.ok(Math.abs(attachmentSize - info.size) <= EPSILON); + break; + } + }, + }); + msgService.streamMessage( + msgURI, + streamListener, + null, + null, + true, // have them create the converter + // additional uri payload, note that "header=" is prepended automatically + "filter", + false + ); + + await streamListener.promise; +} + +/** + * Return the size of a synthetic message. Much like the above comment, libmime + * counts bytes differently on Windows, where it counts newlines (\r\n) as 2 + * bytes. Mac and Linux treats them as 1 byte. + * + * @param message a synthetic message from makeMessage() + * @returns the message's size in bytes + */ +function get_message_size(message) { + let messageString = message.toMessageString(); + if (EPSILON == 4) { + // Windows + return messageString.length; + } + return messageString.replace(/\r\n/g, "\n").length; +} |