From e3c9073a8b43f1dd4aa871639b61cb974a1f110e Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 23 May 2022 21:52:56 -0400 Subject: [PATCH] base64-encode binary responses (#5048) * base64-encode binary responses - closes #4174 * tweak comments --- .changeset/lovely-flies-care.md | 5 ++++ packages/adapter-netlify/src/serverless.js | 33 ++++++++++++++++----- packages/kit/src/runtime/server/endpoint.js | 2 +- 3 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 .changeset/lovely-flies-care.md diff --git a/.changeset/lovely-flies-care.md b/.changeset/lovely-flies-care.md new file mode 100644 index 000000000000..34b909c7ba64 --- /dev/null +++ b/.changeset/lovely-flies-care.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/adapter-netlify': patch +--- + +Encode binary responses as base64 diff --git a/packages/adapter-netlify/src/serverless.js b/packages/adapter-netlify/src/serverless.js index 7d0c0b0135e4..8c4bcff5d945 100644 --- a/packages/adapter-netlify/src/serverless.js +++ b/packages/adapter-netlify/src/serverless.js @@ -10,7 +10,7 @@ export function init(manifest) { const server = new Server(manifest); return async (event, context) => { - const rendered = await server.respond(to_request(event), { + const response = await server.respond(to_request(event), { platform: { context }, getClientAddress() { return event.headers['x-nf-client-connection-ip']; @@ -18,25 +18,24 @@ export function init(manifest) { }); const partial_response = { - statusCode: rendered.status, - ...split_headers(rendered.headers) + statusCode: response.status, + ...split_headers(response.headers) }; - // TODO this is probably wrong now? - if (rendered.body instanceof Uint8Array) { + if (!is_text(response.headers.get('content-type'))) { // Function responses should be strings (or undefined), and responses with binary // content should be base64 encoded and set isBase64Encoded to true. // https://github.com/netlify/functions/blob/main/src/function/response.ts return { ...partial_response, isBase64Encoded: true, - body: Buffer.from(rendered.body).toString('base64') + body: Buffer.from(await response.arrayBuffer()).toString('base64') }; } return { ...partial_response, - body: await rendered.text() + body: await response.text() }; }; } @@ -61,3 +60,23 @@ function to_request(event) { return new Request(rawUrl, init); } + +const text_types = new Set([ + 'application/xml', + 'application/json', + 'application/x-www-form-urlencoded', + 'multipart/form-data' +]); + +/** + * Decides how the body should be parsed based on its mime type + * + * @param {string | undefined | null} content_type The `content-type` header of a request/response. + * @returns {boolean} + */ +function is_text(content_type) { + if (!content_type) return true; // defaults to json + const type = content_type.split(';')[0].toLowerCase(); // get the mime type + + return type.startsWith('text/') || type.endsWith('+xml') || text_types.has(type); +} diff --git a/packages/kit/src/runtime/server/endpoint.js b/packages/kit/src/runtime/server/endpoint.js index d29003cbc4de..739111b6d7c2 100644 --- a/packages/kit/src/runtime/server/endpoint.js +++ b/packages/kit/src/runtime/server/endpoint.js @@ -22,7 +22,7 @@ const text_types = new Set([ ]); /** - * Decides how the body should be parsed based on its mime type. Should match what's in parse_body + * Decides how the body should be parsed based on its mime type * * @param {string | undefined | null} content_type The `content-type` header of a request/response. * @returns {boolean}