-
Notifications
You must be signed in to change notification settings - Fork 248
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use native decoding of base64 in Node.js (#269)
* Make decoding of base64 data URIs faster I saw in microsoft/vscode-js-debug#1911 that base64 decoding of a data URI was taking a bit of time. This PR feature-detects the presence of a global `Buffer` to use native decoding when running in Node.js, which is about 25x faster on a 10MB data URI than the JS implementation in the library. I have a bit of a hack in order to test both paths when running tests, happy to change it if desired :) * use conditional exports * fix test import * fix node test import, and set stringToBuffer encoding * Create few-adults-rhyme.md --------- Co-authored-by: Nathan Rajlich <n@n8.io>
- Loading branch information
1 parent
c3c405e
commit c881a18
Showing
6 changed files
with
117 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"data-uri-to-buffer": patch | ||
--- | ||
|
||
Use native Buffer decoding in Node.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
export interface ParsedDataURI { | ||
type: string; | ||
typeFull: string; | ||
charset: string; | ||
buffer: ArrayBuffer; | ||
} | ||
|
||
export interface IBufferConversions { | ||
base64ToArrayBuffer(base64: string): ArrayBuffer; | ||
stringToBuffer(str: string): ArrayBuffer; | ||
} | ||
|
||
/** | ||
* Returns a `Buffer` instance from the given data URI `uri`. | ||
* | ||
* @param {String} uri Data URI to turn into a Buffer instance | ||
*/ | ||
export const makeDataUriToBuffer = (convert: IBufferConversions) => (uri: string | URL): ParsedDataURI => { | ||
uri = String(uri); | ||
|
||
if (!/^data:/i.test(uri)) { | ||
throw new TypeError( | ||
'`uri` does not appear to be a Data URI (must begin with "data:")' | ||
); | ||
} | ||
|
||
// strip newlines | ||
uri = uri.replace(/\r?\n/g, ''); | ||
|
||
// split the URI up into the "metadata" and the "data" portions | ||
const firstComma = uri.indexOf(','); | ||
if (firstComma === -1 || firstComma <= 4) { | ||
throw new TypeError('malformed data: URI'); | ||
} | ||
|
||
// remove the "data:" scheme and parse the metadata | ||
const meta = uri.substring(5, firstComma).split(';'); | ||
|
||
let charset = ''; | ||
let base64 = false; | ||
const type = meta[0] || 'text/plain'; | ||
let typeFull = type; | ||
for (let i = 1; i < meta.length; i++) { | ||
if (meta[i] === 'base64') { | ||
base64 = true; | ||
} else if (meta[i]) { | ||
typeFull += `;${meta[i]}`; | ||
if (meta[i].indexOf('charset=') === 0) { | ||
charset = meta[i].substring(8); | ||
} | ||
} | ||
} | ||
// defaults to US-ASCII only if type is not provided | ||
if (!meta[0] && !charset.length) { | ||
typeFull += ';charset=US-ASCII'; | ||
charset = 'US-ASCII'; | ||
} | ||
|
||
// get the encoded data portion and decode URI-encoded chars | ||
const data = unescape(uri.substring(firstComma + 1)); | ||
const buffer = base64 ? convert.base64ToArrayBuffer(data) : convert.stringToBuffer(data); | ||
|
||
return { | ||
type, | ||
typeFull, | ||
charset, | ||
buffer, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { makeDataUriToBuffer } from './common'; | ||
|
||
export type { ParsedDataURI } from './common'; | ||
|
||
function nodeBuffertoArrayBuffer(nodeBuf: Buffer) { | ||
if (nodeBuf.byteLength === nodeBuf.buffer.byteLength) { | ||
return nodeBuf.buffer; // large strings may get their own memory allocation | ||
} | ||
const buffer = new ArrayBuffer(nodeBuf.byteLength); | ||
const view = new Uint8Array(buffer); | ||
view.set(nodeBuf); | ||
return buffer; | ||
} | ||
|
||
function base64ToArrayBuffer(base64: string) { | ||
return nodeBuffertoArrayBuffer(Buffer.from(base64, 'base64')); | ||
} | ||
|
||
function stringToBuffer(str: string): ArrayBuffer { | ||
return nodeBuffertoArrayBuffer(Buffer.from(str, 'ascii')); | ||
} | ||
|
||
/** | ||
* Returns a `Buffer` instance from the given data URI `uri`. | ||
* | ||
* @param {String} uri Data URI to turn into a Buffer instance | ||
*/ | ||
export const dataUriToBuffer = makeDataUriToBuffer({ stringToBuffer, base64ToArrayBuffer }); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
c881a18
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
proxy-agents – ./
proxy-agents.n8.io
proxy-agents.vercel.app
proxy-agents-git-main-tootallnate.vercel.app
proxy-agents-tootallnate.vercel.app