Skip to content

Commit

Permalink
Strip default MIME type and charset in data URLs (#100)
Browse files Browse the repository at this point in the history
  • Loading branch information
fisker authored and sindresorhus committed Sep 29, 2019
1 parent 065330e commit 308909b
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 10 deletions.
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

0 comments on commit 308909b

Please sign in to comment.