Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

messy

Package Overview
Dependencies
Maintainers
1
Versions
73
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

messy - npm Package Compare versions

Comparing version 3.2.1 to 4.0.0

3

lib/headerNameSpecialCases.js

@@ -73,8 +73,9 @@ // Headers that cannot be canonicalized by naive camel casing:

'x-csa-complaints': 'x-csa-complaints',
'x-ua-compatible': 'X-UA-Compatible',
'x-originating-ip': 'X-Originating-IP',
'x-riferimento-message-id': 'X-Riferimento-Message-ID',
'x-sg-eid': 'X-SG-EID',
'x-tiporicevuta': 'X-TipoRicevuta',
'x-ua-compatible': 'X-UA-Compatible',
'x-verificasicurezza': 'X-VerificaSicurezza',
'x-xss-protection': 'X-XSS-Protection'
};
var foldHeaderLine = require('./foldHeaderLine'),
formatHeaderName = require('./formatHeaderName'),
isRegExp = require('./isRegExp');
isRegExp = require('./isRegExp'),
rfc2231 = require('rfc2231');

@@ -176,5 +177,8 @@ function Headers(obj, doNotStringify) {

Headers.prototype.set = function (headerName, valueOrValues) {
Headers.prototype.set = function (headerName, valueOrValues, valueNumber) {
var headerNameLowerCase = headerName.toLowerCase();
if (Array.isArray(valueOrValues)) {
if (typeof valueNumber !== 'undefined') {
throw new Error('Headers.set: valueNumber not supported when the values are provided as an array');
}
if (valueOrValues.length === 0) {

@@ -187,2 +191,4 @@ delete this.valuesByName[headerNameLowerCase];

}
} else if (typeof valueNumber === 'number' && Array.isArray(this.valuesByName[headerNameLowerCase]) && valueNumber < this.valuesByName[headerNameLowerCase].length) {
this.valuesByName[headerNameLowerCase][valueNumber] = this.parseHeaderValue(valueOrValues);
} else {

@@ -262,2 +268,52 @@ (this.valuesByName[headerNameLowerCase] = this.valuesByName[headerNameLowerCase] || []).push(this.parseHeaderValue(valueOrValues));

Headers.prototype.parameter = function (headerName, attributeName, attributeValue) {
var headerValue = this.get(headerName, 0),
rfc2231DisabledForThisHeader = this.isMessyHeadersWithRfc2047 && headerName.toLowerCase() === 'content-type';
if (headerValue) {
// FIXME: Will break if a quoted parameter value contains a semicolon
var tokens = headerValue.split(/\s*;\s*/),
parameters = {},
usesRfc2231 = false;
for (var i = 1 ; i < tokens.length ; i += 1) {
var matchKeyValue = tokens[i].match(/^([^=]+)=(.*)$/);
if (matchKeyValue && !(matchKeyValue[1] in parameters)) {
var parameterName = matchKeyValue[1],
value = matchKeyValue[2],
matchQuotedValue = value.match(/^"(.*)"$/);
if (matchQuotedValue) {
value = matchQuotedValue[1].replace(/\\/, '');
}
if (!usesRfc2231 && /\*$/.test(parameterName)) {
usesRfc2231 = true;
}
parameters[parameterName] = value;
}
}
if (usesRfc2231 && !rfc2231DisabledForThisHeader) {
parameters = rfc2231.unfoldAndDecodeParameters(parameters);
}
if (attributeName) {
if (attributeValue) {
parameters[attributeName] = attributeValue;
var tokensAfterUpdate = [tokens[0]];
if (!rfc2231DisabledForThisHeader) {
parameters = rfc2231.encodeAndFoldParameters(parameters);
}
Object.keys(parameters).forEach(function (parameterName) {
tokensAfterUpdate.push(parameterName + '=' + parameters[parameterName]);
});
this.set(headerName, tokensAfterUpdate.join('; '), 0);
} else {
return parameters[attributeName];
}
} else {
return parameters;
}
}
};
Headers.prototype.equals = function (other) {

@@ -264,0 +320,0 @@ if (this === other) {

@@ -11,2 +11,4 @@ var Headers = require('./Headers'),

HeadersWithRfc2047.prototype.isMessyHeadersWithRfc2047 = true;
HeadersWithRfc2047.prototype.serializeHeaderValue = function (parsedHeaderValue) {

@@ -13,0 +15,0 @@ return rfc2047.encode(parsedHeaderValue);

module.exports = {
Headers: require('./Headers'),
Message: require('./Message'),
Mail: require('./Mail'),
RequestLine: require('./RequestLine'),

@@ -5,0 +6,0 @@ HttpRequest: require('./HttpRequest'),

@@ -11,4 +11,6 @@ var Message = require('./Message'),

Mail.prototype.isMessyMail = true;
Mail.prototype.HeadersConstructor = HeadersWithRfc2047;
module.exports = Mail;
/*global unescape*/
var Headers = require('./Headers'),
isRegExp = require('./isRegExp'),
rfc2231 = require('rfc2231');
rfc2231 = require('rfc2231'),
iconvLite = require('iconv-lite'),
quotedPrintable = require('quoted-printable'),
utf8 = require('utf8');

@@ -70,30 +73,18 @@ function quoteRegExp(str) {

Message.prototype.populateMultipartBody = function () {
if (this.isMultipart && typeof this.body !== 'undefined') {
var boundary = this.boundary;
if (boundary) {
var bodyAsString;
if (typeof Buffer === 'function' && Buffer.isBuffer(this.body)) {
bodyAsString = this.body.toString('ascii');
} else {
bodyAsString = this.body;
}
var boundaryRegExp = new RegExp('(^|\r\n?|\n\r?)--' + quoteRegExp(boundary) + '(--)?(?:\r\n?|\n\r?|$)', 'g'),
startIndex = -1,
parts = [],
match;
// TODO: Basic validation of end marker etc.
while ((match = boundaryRegExp.exec(bodyAsString))) {
var index = match.index;
if (startIndex !== -1) {
parts.push(new Message(this.body.slice(startIndex, index)));
}
startIndex = index + match[0].length;
}
if (parts.length > 0) {
this.body = parts;
}
Object.defineProperty(Message.prototype, 'hasTextualContentType', {
get: function () {
var contentType = this.headers.get('Content-Type');
if (typeof contentType === 'string') {
contentType = contentType.toLowerCase().trim().replace(/\s*;.*$/, '');
return (
/^text\//.test(contentType) ||
/^application\/(json|javascript)$/.test(contentType) ||
/^application\/xml/.test(contentType) ||
/^application\/x-www-form-urlencoded\b/.test(contentType) ||
/\+xml$/.test(contentType)
);
}
return false;
}
};
});

@@ -110,7 +101,14 @@ Object.defineProperty(Message.prototype, 'isMultipart', {

get: function () {
if (this.isMultipart) {
var matchBoundary = this.headers.get('Content-Type').match(/\;\s*boundary=('|"|)(\S*?)\1(?:$|;)/);
if (matchBoundary) {
return matchBoundary[2];
}
return this.isMultipart && this.headers.parameter('Content-Type', 'boundary');
}
});
Object.defineProperty(Message.prototype, '_bodyMustBeBuffer', {
get: function () {
if (this._parts) {
return this._parts.some(function (part) {
return part._bodyMustBeBuffer;
});
} else {
return typeof Buffer === 'function' && Buffer.isBuffer(this.body);
}

@@ -120,48 +118,128 @@ }

Object.defineProperty(Message.prototype, 'fileName', {
Object.defineProperty(Message.prototype, 'body', {
enumerable: true,
get: function () {
var contentDisposition = this.headers.get('Content-Disposition');
if (contentDisposition) {
var tokens = contentDisposition.split(/\s*;\s*/),
parameters = {};
for (var i = 1 ; i < tokens.length ; i += 1) {
var matchKeyValue = tokens[i].match(/^([^=]+)=(.*)$/);
if (matchKeyValue && !(matchKeyValue[1] in parameters)) {
parameters[matchKeyValue[1]] = matchKeyValue[2];
if (this._parts) {
if (this._parts.length === 0) {
return;
} else {
if (this._bodyMustBeBuffer) {
var chunks = [];
this._parts.forEach(function (part, i) {
if (i > 0) {
chunks.push(new Buffer('\r\n'));
}
chunks.push(new Buffer('--' + this.boundary + '\r\n'));
var serializedPart = part.serialize();
if (!Buffer.isBuffer(serializedPart)) {
serializedPart = new Buffer(serializedPart);
}
chunks.push(serializedPart);
}, this);
chunks.push(new Buffer('\r\n--' + this.boundary + '--\r\n'))
return Buffer.concat(chunks);
} else {
return;
return '--' + this.boundary + '\r\n' + this._parts.join('\r\n--' + this.boundary + '\r\n') + '\r\n--' + this.boundary + '--\r\n';
}
}
var decodedParameters = rfc2231.unfoldAndDecodeParameters(parameters);
if (decodedParameters.filename) {
return decodedParameters.filename;
} else {
return this._body;
}
},
set: function (body) {
this._body = body;
this._parts = null;
}
});
Object.defineProperty(Message.prototype, 'decodedBody', {
enumerable: true,
get: function () {
var decodedBody = this.body;
if (decodedBody) {
var contentTransferEncoding = this.headers.get('Content-Transfer-Encoding'),
contentTransferEncodingIsHonored = !contentTransferEncoding;
if (contentTransferEncoding) {
contentTransferEncoding = contentTransferEncoding.trim().toLowerCase();
if (contentTransferEncoding === 'quoted-printable') {
if (typeof Buffer === 'function' && Buffer.isBuffer(decodedBody)) {
decodedBody = decodedBody.toString('ascii');
}
var qpDecodedBodyAsByteString = quotedPrintable.decode(decodedBody);
decodedBody = new Buffer(qpDecodedBodyAsByteString.length);
for (var i = 0 ; i < qpDecodedBodyAsByteString.length ; i += 1) {
decodedBody[i] = qpDecodedBodyAsByteString.charCodeAt(i);
}
contentTransferEncodingIsHonored = true;
} else if (contentTransferEncoding === 'base64') {
decodedBody = new Buffer(decodedBody, 'base64');
contentTransferEncodingIsHonored = true;
} else if (contentTransferEncoding === '8bit' || contentTransferEncoding === '7bit') {
contentTransferEncodingIsHonored = true;
}
}
if (this.hasTextualContentType && contentTransferEncodingIsHonored) {
var charset = this.headers.parameter('Content-Type', 'charset') || 'iso-8859-1';
if (iconvLite.encodingExists(charset)) {
decodedBody = iconvLite.decode(decodedBody, charset);
}
}
}
// TODO: Try falling back to the name attribute of the Content-Type header
return decodedBody;
}
});
Object.defineProperty(Message.prototype, 'parts', {
enumerable: true,
set: function (parts) {
this._parts = parts;
},
set: function (fileName) {
var contentDisposition = this.headers.get('Content-Disposition') || 'attachment';
if (contentDisposition) {
var tokens = contentDisposition.split(/\s*;\s*/),
tokensAfterUpdate = [tokens[0]];
for (var i = 1 ; i < tokens.length ; i += 1) {
var matchKeyValue = tokens[i].match(/^([^=]+)=.*$/);
if (matchKeyValue) {
if (!/^filename(?:\*\d*)$/.test(matchKeyValue[1])) {
tokensAfterUpdate.push(tokens[i]);
}
get: function () {
if (!this._parts && this.isMultipart) {
var boundary = this.boundary;
if (boundary) {
var bodyAsString;
if (typeof Buffer === 'function' && Buffer.isBuffer(this.body)) {
bodyAsString = this.body.toString('ascii');
} else {
throw new Error('Cannot set fileName due to unparseable token ' + tokens[i]);
bodyAsString = this.body;
}
var boundaryRegExp = new RegExp('(^|\r\n?|\n\r?)--' + quoteRegExp(boundary) + '(--)?(?:\r\n?|\n\r?|$)', 'g'),
startIndex = -1,
parts = [],
match;
// TODO: Basic validation of end marker etc.
while ((match = boundaryRegExp.exec(bodyAsString))) {
var index = match.index;
if (startIndex !== -1) {
parts.push(new Message(this.body.slice(startIndex, index)));
}
startIndex = index + match[0].length;
}
if (parts.length > 0) {
this._parts = parts;
}
}
var folded = rfc2231.encodeAndFoldParameters({filename: fileName});
Object.keys(folded).forEach(function (parameterName) {
tokensAfterUpdate.push(parameterName + '=' + folded[parameterName]);
});
this.headers.set('Content-Disposition', tokensAfterUpdate.join('; '));
}
// TODO: Update the name attribute of the Content-Type header
return this._parts;
}
});
Object.defineProperty(Message.prototype, 'fileName', {
get: function () {
return this.headers.parameter('Content-Disposition', 'filename') || (this.isMessyMail && this.headers.parameter('Content-Type', 'name'));
},
set: function (fileName) {
if (!this.headers.has('Content-Disposition')) {
this.headers.set('Content-Disposition', 'attachment');
}
this.headers.parameter('Content-Disposition', 'filename', fileName);
if (this.isMessyMail && this.headers.has('Content-Type')) {
this.headers.parameter('Content-Type', 'name', fileName);
}
}
});
function buffersEqual(a, b) {

@@ -192,3 +270,3 @@ if (a === b) {

Message.prototype.toString = function (maxLineLength) {
Message.prototype.serialize = function (maxLineLength, forceString) {
if (typeof maxLineLength === 'undefined') {

@@ -202,6 +280,8 @@ maxLineLength = 72;

result += JSON.stringify(this.body);
} else if (this.isMultipart && Array.isArray(this.body) && this.boundary) {
result += '--' + this.boundary + '\r\n' + this.body.join('\r\n--' + this.boundary + '\r\n') + '\r\n--' + this.boundary + '--\r\n';
} else {
result += this.body;
if (!forceString && this._bodyMustBeBuffer) {
result = Buffer.concat([new Buffer(result), this.body]);
} else {
result += this.body;
}
}

@@ -212,2 +292,6 @@ }

Message.prototype.toString = function (maxLineLength) {
return this.serialize(maxLineLength, true);
}
Message.prototype.equals = function (other) {

@@ -214,0 +298,0 @@ return this === other || (

{
"name": "messy",
"version": "3.2.1",
"version": "4.0.0",
"description": "Object model for HTTP and RFC822 messages",

@@ -35,6 +35,9 @@ "main": "lib/index.js",

"dependencies": {
"iconv-lite": "0.4.6",
"quoted-printable": "1.0.0",
"rfc2047": "1.0.1",
"rfc2231": "1.1.1",
"underscore": "^1.6.0"
"rfc2231": "1.2.0",
"underscore": "^1.6.0",
"utf8": "2.1.0"
}
}

@@ -150,2 +150,87 @@ /*global describe, it*/

});
describe('#parameter()', function () {
describe('when called with just a header name', function () {
it('should return a hash of attributes when the header has attributes', function () {
expect(new Headers('Foo: bar; quux=baz').parameter('Foo'), 'to equal', {quux: 'baz'});
});
it('should unquote quoted parameters', function () {
expect(new Headers('Foo: bar; quux="baz"').parameter('Foo'), 'to equal', {quux: 'baz'});
});
it('should return an empty hash when the header has no attributes', function () {
expect(new Headers('Foo: bar').parameter('Foo'), 'to equal', {});
});
it('should return undefined when the header does not exist', function () {
expect(new Headers('Foo: bar').parameter('Quux'), 'to equal', undefined);
});
it('should decode rfc2231-encoded attributes', function () {
expect(new Headers(
'Content-Type: text/plain;\r\n' +
' filename*0*=utf-8\'\'%72%C3%A6%61%6C%6C%79%20%73%63%72%65%77%65%64%20%75;\r\n' +
' filename*1*=%70%20%6C%6F%6E%67%20%61%74%74%61%63%68%6D%65%6E%74%20%66%69;\r\n' +
' filename*2*=%6C%65%6E%61%6D%65%20%77%69%74%68%20%73%6D%69%6C%65%79%73%E2;\r\n' +
' filename*3*=%98%BA%20%61%6E%64%20%E2%98%BA%61%6E%64%20%C2%A1%48%6F%6C%61;\r\n' +
' filename*4*=%2C%20%73%65%C3%B1%6F%72%21%20%61%6E%64%20%66%6F%72%65%69%67;\r\n' +
' filename*5*=%6E%20%77%65%69%72%64%6E%65%73%73%D7%9D%D7%95%D7%9C%D7%A9%20;\r\n' +
' filename*6*=%D7%9F%D7%91%20%D7%99%D7%9C%D7%98%D7%A4%D7%A0%20%69%6E%20%69;\r\n' +
' filename*7*=%74%2E%E2%98%BA').parameter('Content-Type'), 'to equal', {
filename: 'ræally screwed up long attachment filename with smileys☺ and ☺and ¡Hola, señor! and foreign weirdnessםולש ןב ילטפנ in it.☺'
});
});
});
describe('when called with a header name and an attribute name', function () {
it('should return the attribute value', function () {
expect(new Headers('Foo: hey').parameter('Foo'), 'to equal', {});
});
it('should return undefined when the header has no attributes', function () {
expect(new Headers('Foo: hey').parameter('Foo', 'bar'), 'to equal', undefined);
});
it('should return undefined when the header has attributes, but not the one being asked for', function () {
expect(new Headers('Foo: hey; quux=blah').parameter('Foo', 'bar'), 'to equal', undefined);
});
it('should return undefined when the header is not there', function () {
expect(new Headers('Foo: bar').parameter('Bar', 'quux'), 'to equal', undefined);
});
});
describe('when called with a header name, an attribute name, and an attribute value', function () {
it('should define the attribute if it does not exist', function () {
var headers = new Headers('Foo: hey');
headers.parameter('Foo', 'blah', 'baz')
expect(headers.toString(), 'to equal', 'Foo: hey; blah=baz\r\n');
});
it('should update the attribute if it already exists', function () {
var headers = new Headers('Foo: hey; blah=quux');
headers.parameter('Foo', 'blah', 'baz')
expect(headers.toString(), 'to equal', 'Foo: hey; blah=baz\r\n');
});
it('should transparently encode non-ASCII attribute values using rfc2231', function () {
var headers = new Headers('Content-Type: text/plain');
headers.parameter('Content-Type', 'filename', 'ræally screwed up long attachment filename with smileys☺ and ☺and ¡Hola, señor! and foreign weirdnessםולש ןב ילטפנ in it.☺');
expect(
headers.toString(),
'to equal',
'Content-Type: text/plain;\r\n' +
' filename*0*=utf-8\'\'%72%C3%A6%61%6C%6C%79%20%73%63%72%65%77%65%64%20%75;\r\n' +
' filename*1*=%70%20%6C%6F%6E%67%20%61%74%74%61%63%68%6D%65%6E%74%20%66%69;\r\n' +
' filename*2*=%6C%65%6E%61%6D%65%20%77%69%74%68%20%73%6D%69%6C%65%79%73%E2;\r\n' +
' filename*3*=%98%BA%20%61%6E%64%20%E2%98%BA%61%6E%64%20%C2%A1%48%6F%6C%61;\r\n' +
' filename*4*=%2C%20%73%65%C3%B1%6F%72%21%20%61%6E%64%20%66%6F%72%65%69%67;\r\n' +
' filename*5*=%6E%20%77%65%69%72%64%6E%65%73%73%D7%9D%D7%95%D7%9C%D7%A9%20;\r\n' +
' filename*6*=%D7%9F%D7%91%20%D7%99%D7%9C%D7%98%D7%A4%D7%A0%20%69%6E%20%69;\r\n' +
' filename*7*=%74%2E%E2%98%BA\r\n'
);
});
});
});
});

@@ -16,2 +16,38 @@ /*global describe, it*/

});
describe('#fileName', function () {
describe('when invoked as a getter', function () {
it('should fall back to the name property of the Content-Type header when the Content-Disposition header has no filename parameter', function () {
var mail = new Mail(
'Content-Transfer-Encoding: base64\r\n' +
'Content-Disposition: attachment\r\n' +
'Content-Type: image/png; name="=?iso-8859-1?Q?=E6=F8=E5.png?="'
);
expect(mail.fileName, 'to equal', 'æøå.png');
});
it('should fall back to the name property of the Content-Type header when there is no Content-Disposition header', function () {
var mail = new Mail(
'Content-Transfer-Encoding: base64\r\n' +
'Content-Type: image/png; name="=?iso-8859-1?Q?=E6=F8=E5.png?="'
);
expect(mail.fileName, 'to equal', 'æøå.png');
});
});
describe('when invoked as a setter', function () {
it('should update the name property of the Content-Type header if available', function () {
var mail = new Mail({headers: {'Content-Type': 'image/png'}});
mail.fileName = 'æøå.png';
expect(
mail.toString(),
'to equal',
// TODO: Would be better to emit 'Content-Type: image/png; name="=?iso-8859-1?Q?=E6=F8=E5.png?="\r\n' +
'Content-Type: image/png; =?iso-8859-1?Q?name==E6=F8=E5?=.png\r\n' +
'Content-Disposition: attachment;\r\n' +
" filename*=iso-8859-1''%E6%F8%E5%2E%70%6E%67\r\n"
);
});
});
});
});

@@ -223,5 +223,3 @@ /*global describe, it*/

message.populateMultipartBody();
expect(message.body, 'to equal', [
expect(message.parts, 'to equal', [
new Message(new Buffer('Content-Disposition: form-data; name="recipient"\r\n\r\nandreas@one.com', 'utf-8')),

@@ -237,5 +235,3 @@ new Message(new Buffer('Content-Disposition: form-data; name="Name "\r\n\r\nThe name', 'utf-8')),

message.populateMultipartBody();
expect(message.body, 'to equal', [
expect(message.parts, 'to equal', [
new Message('Content-Disposition: form-data; name="recipient"\r\n\r\nandreas@one.com'),

@@ -247,37 +243,195 @@ new Message('Content-Disposition: form-data; name="Name "\r\n\r\nThe name'),

});
it('#toString should serialize the (possibly mutated) decoded parts if available', function () {
var message = new Message(src);
message.parts.splice(1, 3);
message.parts[0].headers.set('Foo', 'quux');
expect(
message.toString(),
'to equal',
'Content-Type: multipart/form-data;\r\n' +
' boundary=--------------------------231099812216460892104111\r\n' +
'\r\n' +
'----------------------------231099812216460892104111\r\n' +
'Content-Disposition: form-data; name="recipient"\r\n' +
'Foo: quux\r\n' +
'\r\n' +
'andreas@one.com\r\n' +
'----------------------------231099812216460892104111--\r\n'
);
});
it('should reparse the parts if the body of the containing Message is updated', function () {
var message = new Message(src);
message.parts.splice(1, 3);
message.body = src;
expect(message.parts, 'to have length', 4);
});
it('should support updating the parts property', function () {
var message = new Message(src);
message.parts = [];
expect(message.parts, 'to equal', []);
});
it('should recompute the body if the parts are updated', function () {
var message = new Message(src);
expect(message.parts, 'to have length', 4);
message.parts.splice(1, 3);
expect(message.body, 'to equal',
'----------------------------231099812216460892104111\r\n' +
'Content-Disposition: form-data; name="recipient"\r\n' +
'\r\n' +
'andreas@one.com\r\n' +
'----------------------------231099812216460892104111--\r\n');
});
it('should recompute the body if the parts are updated, binary mode', function () {
var message = new Message(src);
expect(message.parts, 'to have length', 4);
message.parts[0].body = new Buffer([0]);
message.parts.splice(1, 3);
var body = message.body;
expect(body, 'to be a', Buffer);
expect(body.toString('utf-8'), 'to equal',
'----------------------------231099812216460892104111\r\n' +
'Content-Disposition: form-data; name="recipient"\r\n' +
'\r\n' +
'\x00\r\n' +
'----------------------------231099812216460892104111--\r\n'
);
});
});
it('should support a fileName getter which automatically rfc2231 decodes the Content-Disposition filename', function () {
var message = new Message(
'Content-Disposition: attachment;\r\n' +
' filename*0*=utf-8\'\'%72%C3%A6%61%6C%6C%79%20%73%63%72%65%77%65%64%20%75;\r\n' +
' filename*1*=%70%20%6C%6F%6E%67%20%61%74%74%61%63%68%6D%65%6E%74%20%66%69;\r\n' +
' filename*2*=%6C%65%6E%61%6D%65%20%77%69%74%68%20%73%6D%69%6C%65%79%73%E2;\r\n' +
' filename*3*=%98%BA%20%61%6E%64%20%E2%98%BA%61%6E%64%20%C2%A1%48%6F%6C%61;\r\n' +
' filename*4*=%2C%20%73%65%C3%B1%6F%72%21%20%61%6E%64%20%66%6F%72%65%69%67;\r\n' +
' filename*5*=%6E%20%77%65%69%72%64%6E%65%73%73%D7%9D%D7%95%D7%9C%D7%A9%20;\r\n' +
' filename*6*=%D7%9F%D7%91%20%D7%99%D7%9C%D7%98%D7%A4%D7%A0%20%69%6E%20%69;\r\n' +
' filename*7*=%74%2E%E2%98%BA');
expect(message.fileName, 'to equal', 'ræally screwed up long attachment filename with smileys☺ and ☺and ¡Hola, señor! and foreign weirdnessםולש ןב ילטפנ in it.☺');
describe('#decodedBody', function () {
it('should decode a base64 body to a string when the Content-Transfer-Encoding is base64 and the Content-Type is textual', function () {
expect(new Message(
'Content-Type: text/plain; charset=UTF-8\r\n' +
'Content-Transfer-Encoding: base64\r\n' +
'\r\n' +
'Zm9v\r\n'
).decodedBody, 'to equal', 'foo');
});
it('should decode a base64 body to a Buffer when the Content-Transfer-Encoding is base64 and the Content-Type is not textual', function () {
expect(new Message(
'Content-Type: image/png; charset=UTF-8\r\n' +
'Content-Transfer-Encoding: base64\r\n' +
'\r\n' +
'Zm9v\r\n'
).decodedBody, 'to equal', new Buffer('foo'));
});
it('should decode quoted-printable when the Content-Transfer-Encoding header says so', function () {
expect(new Message(
'Content-Type: text/plain; charset=UTF-8\r\n' +
'Content-Transfer-Encoding: quoted-printable\r\n' +
'\r\n' +
'Abc =C3=A6=C3=B8=C3=A5\r\n'
).decodedBody, 'to equal', 'Abc æøå\r\n');
});
it('should not break if the Content-Transfer-Encoding is unsupported', function () {
expect(new Message(
'Content-Type: image/png; charset=UTF-8\r\n' +
'Content-Transfer-Encoding: foo\r\n' +
'\r\n' +
'Zm9v\r\n'
).decodedBody, 'to equal', 'Zm9v\r\n');
});
it('should support quoted-printable with iso-8859-1', function () {
expect(new Message(
'Content-Type: text/plain; charset=iso-8859-1\r\n' +
'Content-Transfer-Encoding: quoted-printable\r\n' +
'\r\n' +
'Abc =F8\r\n'
).decodedBody, 'to equal', 'Abc ø\r\n');
});
it('should support quoted-printable with no Content-Transfer-Encoding', function () {
expect(new Message(
Buffer.concat([
new Buffer(
'Content-Type: text/plain; charset=iso-8859-1\r\n' +
'\r\n' +
'Abc '),
new Buffer([0xf8]),
new Buffer('\r\n')
])
).decodedBody, 'to equal', 'Abc ø\r\n');
});
});
it('should support a fileName setter which updates the Content-Disposition filename with the rfc2231 encoded representation', function () {
var message = new Message({body: 'bar'});
message.fileName = 'ræally screwed up long attachment filename with smileys☺ and ☺and ¡Hola, señor! and foreign weirdnessםולש ןב ילטפנ in it.☺';
expect(
message.toString(),
'to equal',
'Content-Disposition: attachment;\r\n' +
' filename*0*=utf-8\'\'%72%C3%A6%61%6C%6C%79%20%73%63%72%65%77%65%64%20%75;\r\n' +
' filename*1*=%70%20%6C%6F%6E%67%20%61%74%74%61%63%68%6D%65%6E%74%20%66%69;\r\n' +
' filename*2*=%6C%65%6E%61%6D%65%20%77%69%74%68%20%73%6D%69%6C%65%79%73%E2;\r\n' +
' filename*3*=%98%BA%20%61%6E%64%20%E2%98%BA%61%6E%64%20%C2%A1%48%6F%6C%61;\r\n' +
' filename*4*=%2C%20%73%65%C3%B1%6F%72%21%20%61%6E%64%20%66%6F%72%65%69%67;\r\n' +
' filename*5*=%6E%20%77%65%69%72%64%6E%65%73%73%D7%9D%D7%95%D7%9C%D7%A9%20;\r\n' +
' filename*6*=%D7%9F%D7%91%20%D7%99%D7%9C%D7%98%D7%A4%D7%A0%20%69%6E%20%69;\r\n' +
' filename*7*=%74%2E%E2%98%BA\r\n' +
'\r\n' +
'bar'
);
describe('#fileName', function () {
describe('when invoked as a getter', function () {
it('should decode the Content-Disposition filename', function () {
var message = new Message(
'Content-Disposition: attachment;\r\n' +
' filename*0*=utf-8\'\'%72%C3%A6%61%6C%6C%79%20%73%63%72%65%77%65%64%20%75;\r\n' +
' filename*1*=%70%20%6C%6F%6E%67%20%61%74%74%61%63%68%6D%65%6E%74%20%66%69;\r\n' +
' filename*2*=%6C%65%6E%61%6D%65%20%77%69%74%68%20%73%6D%69%6C%65%79%73%E2;\r\n' +
' filename*3*=%98%BA%20%61%6E%64%20%E2%98%BA%61%6E%64%20%C2%A1%48%6F%6C%61;\r\n' +
' filename*4*=%2C%20%73%65%C3%B1%6F%72%21%20%61%6E%64%20%66%6F%72%65%69%67;\r\n' +
' filename*5*=%6E%20%77%65%69%72%64%6E%65%73%73%D7%9D%D7%95%D7%9C%D7%A9%20;\r\n' +
' filename*6*=%D7%9F%D7%91%20%D7%99%D7%9C%D7%98%D7%A4%D7%A0%20%69%6E%20%69;\r\n' +
' filename*7*=%74%2E%E2%98%BA');
expect(message.fileName, 'to equal', 'ræally screwed up long attachment filename with smileys☺ and ☺and ¡Hola, señor! and foreign weirdnessםולש ןב ילטפנ in it.☺');
});
it('should not fall back to the name property of the Content-Type header when the Content-Disposition header has no filename parameter', function () {
var message = new Message(
'Content-Transfer-Encoding: base64\r\n' +
'Content-Disposition: attachment\r\n' +
'Content-Type: image/png; name="=?iso-8859-1?Q?=E6=F8=E5.png?="'
);
expect(message.fileName, 'to equal', undefined);
});
it('should not fall back to the name property of the Content-Type header when there is no Content-Disposition header', function () {
var message = new Message(
'Content-Transfer-Encoding: base64\r\n' +
'Content-Type: image/png; name="=?iso-8859-1?Q?=E6=F8=E5.png?="'
);
expect(message.fileName, 'to equal', undefined);
});
});
describe('when invoked as a setter', function () {
it('should support a fileName setter which updates the Content-Disposition filename with the rfc2231 encoded representation', function () {
var message = new Message({body: 'bar'});
message.fileName = 'ræally screwed up long attachment filename with smileys☺ and ☺and ¡Hola, señor! and foreign weirdnessםולש ןב ילטפנ in it.☺';
expect(
message.toString(),
'to equal',
'Content-Disposition: attachment;\r\n' +
' filename*0*=utf-8\'\'%72%C3%A6%61%6C%6C%79%20%73%63%72%65%77%65%64%20%75;\r\n' +
' filename*1*=%70%20%6C%6F%6E%67%20%61%74%74%61%63%68%6D%65%6E%74%20%66%69;\r\n' +
' filename*2*=%6C%65%6E%61%6D%65%20%77%69%74%68%20%73%6D%69%6C%65%79%73%E2;\r\n' +
' filename*3*=%98%BA%20%61%6E%64%20%E2%98%BA%61%6E%64%20%C2%A1%48%6F%6C%61;\r\n' +
' filename*4*=%2C%20%73%65%C3%B1%6F%72%21%20%61%6E%64%20%66%6F%72%65%69%67;\r\n' +
' filename*5*=%6E%20%77%65%69%72%64%6E%65%73%73%D7%9D%D7%95%D7%9C%D7%A9%20;\r\n' +
' filename*6*=%D7%9F%D7%91%20%D7%99%D7%9C%D7%98%D7%A4%D7%A0%20%69%6E%20%69;\r\n' +
' filename*7*=%74%2E%E2%98%BA\r\n' +
'\r\n' +
'bar'
);
});
it('should not update the name property of the Content-Type header, even if available', function () {
var message = new Message({headers: {'Content-Type': 'image/png'}});
message.fileName = 'æøå.png';
expect(
message.toString(),
'to equal',
'Content-Type: image/png\r\n' +
'Content-Disposition: attachment;\r\n' +
" filename*=iso-8859-1''%E6%F8%E5%2E%70%6E%67\r\n"
);
});
});
});
});

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc