@mjackson/headers
Version:
A toolkit for working with HTTP headers in JavaScript
220 lines (180 loc) • 8.47 kB
text/typescript
import * as assert from 'node:assert/strict';
import { describe, it } from 'node:test';
import { ContentDisposition } from './content-disposition.ts';
describe('ContentDisposition', () => {
it('initializes with an empty string', () => {
let header = new ContentDisposition('');
assert.equal(header.type, undefined);
assert.equal(header.filename, undefined);
});
it('initializes with a string', () => {
let header = new ContentDisposition('attachment; filename="example.txt"');
assert.equal(header.type, 'attachment');
assert.equal(header.filename, 'example.txt');
});
it('initializes with an object', () => {
let header = new ContentDisposition({ type: 'attachment', filename: 'example.txt' });
assert.equal(header.type, 'attachment');
assert.equal(header.filename, 'example.txt');
});
it('initializes with another ContentDisposition', () => {
let header = new ContentDisposition(
new ContentDisposition('attachment; filename="example.txt"'),
);
assert.equal(header.type, 'attachment');
assert.equal(header.filename, 'example.txt');
});
it('handles whitespace in initial value', () => {
let header = new ContentDisposition(' inline ; filename = "document.pdf" ');
assert.equal(header.type, 'inline');
assert.equal(header.filename, 'document.pdf');
});
it('sets and gets type', () => {
let header = new ContentDisposition('attachment');
header.type = 'inline';
assert.equal(header.type, 'inline');
});
it('sets and gets filename', () => {
let header = new ContentDisposition('attachment');
header.filename = 'example.txt';
assert.equal(header.filename, 'example.txt');
});
it('sets and gets name', () => {
let header = new ContentDisposition('form-data');
header.name = 'field1';
assert.equal(header.name, 'field1');
});
it('sets and gets filenameSplat', () => {
let header = new ContentDisposition('attachment');
header.filenameSplat = "UTF-8''%E6%96%87%E4%BB%B6.txt";
assert.equal(header.filenameSplat, "UTF-8''%E6%96%87%E4%BB%B6.txt");
});
it('handles quoted attribute values', () => {
let header = new ContentDisposition('attachment; filename="file with spaces.txt"');
assert.equal(header.filename, 'file with spaces.txt');
});
it('converts to string correctly', () => {
let header = new ContentDisposition('attachment; filename="example.txt"');
assert.equal(header.toString(), 'attachment; filename=example.txt');
});
it('converts to an empty string when type is not set', () => {
let header = new ContentDisposition();
header.filename = 'example.txt';
assert.equal(header.toString(), '');
});
it('handles multiple attributes', () => {
let header = new ContentDisposition('form-data; name="field1"; filename="example.txt"');
assert.equal(header.type, 'form-data');
assert.equal(header.name, 'field1');
assert.equal(header.filename, 'example.txt');
});
it('preserves case for type', () => {
let header = new ContentDisposition('Attachment');
assert.equal(header.type, 'Attachment');
});
it('handles attribute values with special characters', () => {
let header = new ContentDisposition(
'attachment; filename="file with spaces and (parentheses).txt"',
);
assert.equal(header.filename, 'file with spaces and (parentheses).txt');
});
it('correctly quotes attribute values in toString()', () => {
let header = new ContentDisposition('attachment');
header.filename = 'file "with" quotes.txt';
assert.equal(header.toString(), 'attachment; filename="file \\"with\\" quotes.txt"');
});
it('handles empty attribute values', () => {
let header = new ContentDisposition('form-data; name=');
assert.equal(header.name, '');
});
it('ignores attributes without values', () => {
let header = new ContentDisposition('attachment; filename');
assert.equal(header.filename, undefined);
});
it('preserves order of attributes in toString()', () => {
let header = new ContentDisposition('form-data; name="field1"; filename="example.txt"');
assert.equal(header.toString(), 'form-data; name=field1; filename=example.txt');
});
it('handles filename* (RFC 5987) correctly', () => {
let header = new ContentDisposition("attachment; filename*=UTF-8''%E6%96%87%E4%BB%B6.txt");
assert.equal(header.filenameSplat, "UTF-8''%E6%96%87%E4%BB%B6.txt");
});
it('prioritizes filename* over filename when both are present', () => {
let header = new ContentDisposition(
'attachment; filename="fallback.txt"; filename*=UTF-8\'\'%E6%96%87%E4%BB%B6.txt',
);
assert.equal(header.filename, 'fallback.txt');
assert.equal(header.filenameSplat, "UTF-8''%E6%96%87%E4%BB%B6.txt");
});
it('handles form-data disposition type correctly', () => {
let header = new ContentDisposition('form-data; name="uploadedfile"; filename="example.txt"');
assert.equal(header.type, 'form-data');
assert.equal(header.name, 'uploadedfile');
assert.equal(header.filename, 'example.txt');
});
describe('preferredFilename', () => {
it('returns filename* when both filename and filename* are present', () => {
let header = new ContentDisposition(
'attachment; filename="old.txt"; filename*=UTF-8\'\'new.txt',
);
assert.equal(header.preferredFilename, 'new.txt');
});
it('returns filename when only filename is present', () => {
let header = new ContentDisposition('attachment; filename="document.pdf"');
assert.equal(header.preferredFilename, 'document.pdf');
});
it('returns filename* when only filename* is present', () => {
let header = new ContentDisposition("attachment; filename*=UTF-8''special%20file.txt");
assert.equal(header.preferredFilename, 'special file.txt');
});
it('handles UTF-8 encoded filename* with special characters', () => {
let header = new ContentDisposition("attachment; filename*=UTF-8''%E6%96%87%E4%BB%B6.txt");
assert.equal(header.preferredFilename, '文件.txt');
});
it('handles ISO-8859-1 encoded filename* with special characters', () => {
let header = new ContentDisposition("attachment; filename*=ISO-8859-1''f%F6o.txt");
assert.equal(header.preferredFilename, 'föo.txt');
});
it('handles filename* with spaces and other special characters', () => {
let header = new ContentDisposition(
"attachment; filename*=UTF-8''hello%20world%21%20%26%20goodbye.txt",
);
assert.equal(header.preferredFilename, 'hello world! & goodbye.txt');
});
it('returns undefined when no filename or filename* is present', () => {
let header = new ContentDisposition('attachment');
assert.equal(header.preferredFilename, undefined);
});
it('falls back to filename when filename* is invalid', () => {
let header = new ContentDisposition('attachment; filename="fallback.txt"; filename*=invalid');
assert.equal(header.preferredFilename, 'fallback.txt');
});
it('correctly decodes ISO-8859-1 encoded filename', () => {
let header = new ContentDisposition("attachment; filename*=ISO-8859-1''f%F6o.txt");
assert.equal(header.preferredFilename, 'föo.txt');
});
it('correctly decodes ISO-8859-15 encoded filename', () => {
let header = new ContentDisposition("attachment; filename*=ISO-8859-15''file%A4.txt");
assert.equal(header.preferredFilename, 'file€.txt');
});
it('correctly decodes windows-1252 encoded filename', () => {
let header = new ContentDisposition("attachment; filename*=windows-1252''file%80.txt");
assert.equal(header.preferredFilename, 'file\x80.txt');
});
it('handles UTF-8 encoded filename correctly', () => {
let header = new ContentDisposition("attachment; filename*=UTF-8''%E6%96%87%E4%BB%B6.txt");
assert.equal(header.preferredFilename, '文件.txt');
});
it('falls back gracefully with a warning for unknown charsets', () => {
let warn = console.warn;
let warnWasCalled = false;
console.warn = () => {
warnWasCalled = true;
};
let header = new ContentDisposition("attachment; filename*=unknown-charset''file%FF.txt");
assert.equal(header.preferredFilename, 'fileÿ.txt');
assert.ok(warnWasCalled, 'console.warn should have been called');
console.warn = warn;
});
});
});