Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strip default MIME type and charset in data URLs #100

Merged
merged 2 commits into from Sep 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 11 additions & 3 deletions index.js
Expand Up @@ -2,6 +2,10 @@
// TODO: Use the `URL` global when targeting Node.js 10
const URLParser = typeof URL === 'undefined' ? require('url').URL : URL;

// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs
const DATA_URL_DEFAULT_MIME_TYPE = 'text/plain';
const DATA_URL_DEFAULT_CHARSET = 'us-ascii';

const testParameter = (name, filters) => {
return filters.some(filter => filter instanceof RegExp ? filter.test(name) : filter === name);
};
Expand All @@ -27,17 +31,21 @@ const normalizeDataURL = (urlString, {stripHash}) => {
// Lowercase MIME type
const mimeType = (mediaType.shift() || '').toLowerCase();
const attributes = mediaType
.filter(Boolean)
.map(attribute => {
let [key, value = ''] = attribute.split('=').map(string => string.trim());

// Lowercase `charset`
if (key === 'charset') {
value = value.toLowerCase();

if (value === DATA_URL_DEFAULT_CHARSET) {
return '';
}
}

return `${key}${value ? `=${value}` : ''}`;
});
})
.filter(Boolean);

const normalizedMediaType = [
...attributes
Expand All @@ -47,7 +55,7 @@ const normalizeDataURL = (urlString, {stripHash}) => {
normalizedMediaType.push('base64');
}

if (normalizedMediaType.length !== 0 || mimeType) {
if (normalizedMediaType.length !== 0 || (mimeType && mimeType !== DATA_URL_DEFAULT_MIME_TYPE)) {
normalizedMediaType.unshift(mimeType);
}

Expand Down
19 changes: 12 additions & 7 deletions test.js
Expand Up @@ -216,8 +216,14 @@ test('data URL', t => {
// Invalid URL.
t.throws(() => normalizeUrl('data:'), 'Invalid URL: data:');

// Strip default MIME type
t.is(normalizeUrl('data:text/plain,foo'), 'data:,foo');

// Strip default charset
t.is(normalizeUrl('data:;charset=us-ascii,foo'), 'data:,foo');

// Normalize away trailing semicolon.
t.is(normalizeUrl('data:text/plain;charset=UTF-8;,foo'), 'data:text/plain;charset=utf-8,foo');
t.is(normalizeUrl('data:;charset=UTF-8;,foo'), 'data:;charset=utf-8,foo');

// Empty MIME type.
t.is(normalizeUrl('data:,'), 'data:,');
Expand All @@ -226,23 +232,22 @@ test('data URL', t => {
t.is(normalizeUrl('data:;charset=utf-8,foo'), 'data:;charset=utf-8,foo');

// Lowercase the MIME type.
t.is(normalizeUrl('data:TEXT/plain,foo'), 'data:text/plain,foo');
t.is(normalizeUrl('data:TEXT/HTML,foo'), 'data:text/html,foo');

// Strip empty hash.
t.is(normalizeUrl('data:,foo# '), 'data:,foo');

// Key only mediaType attribute.
t.is(normalizeUrl('data:text/plain;foo=,'), 'data:text/plain;foo,');
t.is(normalizeUrl('data:text/plain; foo,'), 'data:text/plain;foo,');
t.is(normalizeUrl('data:;foo=;bar,'), 'data:;foo;bar,');

// Lowercase the charset.
t.is(normalizeUrl('data:text/plain;charset=UTF-8,foo'), 'data:text/plain;charset=utf-8,foo');
t.is(normalizeUrl('data:;charset=UTF-8,foo'), 'data:;charset=utf-8,foo');

// Remove spaces after the comma when it's base64.
t.is(normalizeUrl('data:image/gif;base64, R0lGODlhAQABAAAAACw= #foo #bar'), 'data:image/gif;base64,R0lGODlhAQABAAAAACw=#foo #bar');
t.is(normalizeUrl('data:;base64, Zm9v #foo #bar'), 'data:;base64,Zm9v#foo #bar');

// Keep spaces when it's not base64.
t.is(normalizeUrl('data:text/plain;charset=utf-8, foo #bar'), 'data:text/plain;charset=utf-8, foo #bar');
t.is(normalizeUrl('data:, foo #bar'), 'data:, foo #bar');

// Options.
const options = {
Expand Down