Skip to content

Commit

Permalink
[fix] Expand list of allowed mime types for binary bodies (#1687)
Browse files Browse the repository at this point in the history
  • Loading branch information
JeanJPNM authored Jul 12, 2021
1 parent fe68e13 commit 7faf52f
Show file tree
Hide file tree
Showing 8 changed files with 45 additions and 8 deletions.
7 changes: 7 additions & 0 deletions .changeset/great-guests-visit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@sveltejs/adapter-cloudflare-workers': patch
'@sveltejs/adapter-netlify': patch
'@sveltejs/kit': patch
---

Update and consolidate checks for binary body types
3 changes: 2 additions & 1 deletion packages/adapter-cloudflare-workers/files/entry.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// TODO hardcoding the relative location makes this brittle
import { init, render } from '../output/server/app.js'; // eslint-disable-line import/no-unresolved
import { getAssetFromKV, NotFoundError } from '@cloudflare/kv-asset-handler'; // eslint-disable-line import/no-unresolved
import { isContentTypeBinary } from '@sveltejs/kit/adapter-utils'; // eslint-disable-line import/no-unresolved

init();

Expand Down Expand Up @@ -57,7 +58,7 @@ async function handle(event) {
/** @param {Request} request */
async function read(request) {
const type = request.headers.get('content-type') || '';
if (type.includes('application/octet-stream')) {
if (isContentTypeBinary(type)) {
return new Uint8Array(await request.arrayBuffer());
}

Expand Down
4 changes: 3 additions & 1 deletion packages/adapter-netlify/files/entry.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// TODO hardcoding the relative location makes this brittle
import { init, render } from '../output/server/app.js'; // eslint-disable-line import/no-unresolved
import { isContentTypeBinary } from '@sveltejs/kit/adapter-utils'; // eslint-disable-line import/no-unresolved

init();

Expand All @@ -8,8 +9,9 @@ export async function handler(event) {

const query = new URLSearchParams(rawQuery);

const type = headers['content-type'];
const rawBody =
headers['content-type'] === 'application/octet-stream'
type && isContentTypeBinary(type)
? new TextEncoder('base64').encode(body)
: isBase64Encoded
? Buffer.from(body, 'base64').toString()
Expand Down
3 changes: 3 additions & 0 deletions packages/kit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@
"./install-fetch": {
"import": "./dist/install-fetch.js"
},
"./adapter-utils": {
"import": "./dist/adapter-utils.js"
},
"./types": "./types/index.d.ts"
},
"types": "types/index.d.ts",
Expand Down
3 changes: 2 additions & 1 deletion packages/kit/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ export default [
cli: 'src/cli.js',
ssr: 'src/runtime/server/index.js',
node: 'src/core/node/index.js',
'install-fetch': 'src/install-fetch.js'
'install-fetch': 'src/install-fetch.js',
'adapter-utils': 'src/core/adapter-utils.js'
},
output: {
dir: 'dist',
Expand Down
16 changes: 16 additions & 0 deletions packages/kit/src/core/adapter-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Decides how the body should be parsed based on its mime type.
*
* This is intended to be used with both requests and responses, to have a consistent body parsing across adapters.
*
* @param {string} content_type The `content-type` header of a request/response.
* @returns {boolean}
*/
export function isContentTypeBinary(content_type) {
return (
content_type.startsWith('image/') ||
content_type.startsWith('audio/') ||
content_type.startsWith('video/') ||
content_type.startsWith('application/octet-stream')
);
}
4 changes: 3 additions & 1 deletion packages/kit/src/core/node/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { isContentTypeBinary } from '../adapter-utils.js';

/**
* @param {import('http').IncomingMessage} req
* @returns {Promise<import('types/hooks').StrictBody>}
Expand Down Expand Up @@ -48,7 +50,7 @@ export function getRawBody(req) {
req.on('end', () => {
const [type] = h['content-type'].split(/;\s*/);

if (type === 'application/octet-stream') {
if (isContentTypeBinary(type)) {
return fulfil(data);
}

Expand Down
13 changes: 9 additions & 4 deletions packages/kit/src/runtime/server/endpoint.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { isContentTypeBinary } from '../../core/adapter-utils.js';
import { lowercase_keys } from './utils.js';

/** @param {string} body */
Expand Down Expand Up @@ -37,24 +38,28 @@ export default async function render_route(request, route) {
headers = lowercase_keys(headers);
const type = headers['content-type'];

const is_type_binary = type && isContentTypeBinary(type);

// validation
if (type === 'application/octet-stream' && !(body instanceof Uint8Array)) {
if (is_type_binary && !(body instanceof Uint8Array)) {
return error(
`${preface}: body must be an instance of Uint8Array if content type is application/octet-stream`
`${preface}: body must be an instance of Uint8Array if content type is image/*, audio/*, video/* or application/octet-stream`
);
}

if (body instanceof Uint8Array && type !== 'application/octet-stream') {
if (body instanceof Uint8Array && !is_type_binary) {
return error(
`${preface}: Uint8Array body must be accompanied by content-type: application/octet-stream header`
`${preface}: Uint8Array body must have content-type header of image/*, audio/*, video/* or application/octet-stream`
);
}

/** @type {import('types/hooks').StrictBody} */
let normalized_body;

// ensure the body is an object
if (
(typeof body === 'object' || typeof body === 'undefined') &&
!(body instanceof Uint8Array) &&
(!type || type.startsWith('application/json'))
) {
headers = { ...headers, 'content-type': 'application/json; charset=utf-8' };
Expand Down

0 comments on commit 7faf52f

Please sign in to comment.