From 2576be7740e10466a000604c86b5f4e29e0eeef0 Mon Sep 17 00:00:00 2001 From: Bogdan Chadkin Date: Sat, 6 Feb 2021 15:33:14 +0300 Subject: [PATCH 1/5] [next] replace raw-body with get-stream and bytes get-stream is small library without dependencies for resolving streams as promise. https://packagephobia.com/result?p=raw-body https://packagephobia.com/result?p=get-stream https://packagephobia.com/result?p=bytes --- packages/next/next-server/server/api-utils.ts | 8 +++++--- packages/next/package.json | 3 +++ yarn.lock | 13 ++++++++++++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/packages/next/next-server/server/api-utils.ts b/packages/next/next-server/server/api-utils.ts index 5d7c5c9d2a7682d..2acb8bda6eb8145 100644 --- a/packages/next/next-server/server/api-utils.ts +++ b/packages/next/next-server/server/api-utils.ts @@ -1,7 +1,8 @@ import { IncomingMessage, ServerResponse } from 'http' import { parse } from 'next/dist/compiled/content-type' import { CookieSerializeOptions } from 'next/dist/compiled/cookie' -import getRawBody from 'raw-body' +import getStream from 'get-stream' +import bytes from 'bytes' import { PageConfig } from 'next/types' import { Stream } from 'stream' import { isResSent, NextApiRequest, NextApiResponse } from '../lib/utils' @@ -124,7 +125,8 @@ export async function parseBody( let buffer try { - buffer = await getRawBody(req, { encoding, limit }) + const maxBuffer = bytes.parse(limit) + buffer = await getStream.buffer(req, { maxBuffer }) } catch (e) { if (e.type === 'entity.too.large') { throw new ApiError(413, `Body exceeded ${limit} limit`) @@ -133,7 +135,7 @@ export async function parseBody( } } - const body = buffer.toString() + const body = buffer.toString(encoding) if (type === 'application/json' || type === 'application/ld+json') { return parseJson(body) diff --git a/packages/next/package.json b/packages/next/package.json index f68bb659ddb23d1..50b637ca5322bc0 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -71,6 +71,7 @@ "ast-types": "0.13.2", "browserslist": "4.16.1", "buffer": "5.6.0", + "bytes": "3.1.0", "caniuse-lite": "^1.0.30001179", "chalk": "2.4.2", "chokidar": "3.5.1", @@ -78,6 +79,7 @@ "cssnano-simple": "1.2.2", "etag": "1.8.1", "find-cache-dir": "3.3.1", + "get-stream": "6.0.0", "jest-worker": "24.9.0", "native-url": "0.3.4", "node-fetch": "2.6.1", @@ -145,6 +147,7 @@ "@types/babel__generator": "7.6.2", "@types/babel__template": "7.4.0", "@types/babel__traverse": "7.11.0", + "@types/bytes": "3.1.0", "@types/ci-info": "2.0.0", "@types/comment-json": "1.1.1", "@types/compression": "0.0.36", diff --git a/yarn.lock b/yarn.lock index 1f8e90fe3fd0884..84da43e1aa11fd7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2662,6 +2662,11 @@ "@types/connect" "*" "@types/node" "*" +"@types/bytes@3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@types/bytes/-/bytes-3.1.0.tgz#835a3e4aea3b4d7604aca216a78de372bff3ecc3" + integrity sha512-5YG1AiIC8HPPXRvYAIa7ehK3YMAwd0DWiPCtpuL9sgKceWLyWsVtLRA+lT4NkoanDNF9slwQ66lPizWDpgRlWA== + "@types/cacheable-request@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.1.tgz#5d22f3dded1fd3a84c0bbeb5039a7419c2c91976" @@ -4303,6 +4308,7 @@ bytes@3.0.0: bytes@3.1.0, bytes@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== cacache@15.0.5: version "15.0.5" @@ -4511,7 +4517,7 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@1.0.30001179, caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001020, caniuse-lite@^1.0.30001093, caniuse-lite@^1.0.30001165, caniuse-lite@^1.0.30001173, caniuse-lite@^1.0.30001179: +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001020, caniuse-lite@^1.0.30001093, caniuse-lite@^1.0.30001165, caniuse-lite@^1.0.30001173, caniuse-lite@^1.0.30001179: version "1.0.30001179" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001179.tgz#b0803883b4471a6c62066fb1752756f8afc699c8" integrity sha512-blMmO0QQujuUWZKyVrD1msR4WNDAqb/UPO1Sw2WWsQ7deoM5bJiicKnWJ1Y0NS/aGINSnKPIWBMw5luX+NDUCA== @@ -7413,6 +7419,11 @@ get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" +get-stream@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.0.tgz#3e0012cb6827319da2706e601a1583e8629a6718" + integrity sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg== + get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" From 4eb3f78341a28a8627d52338d946090d7bda4ea8 Mon Sep 17 00:00:00 2001 From: Bogdan Chadkin Date: Sat, 6 Feb 2021 15:46:10 +0300 Subject: [PATCH 2/5] Fix max buffer error detection --- packages/next/next-server/server/api-utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next/next-server/server/api-utils.ts b/packages/next/next-server/server/api-utils.ts index 2acb8bda6eb8145..044b3bc32a67ec0 100644 --- a/packages/next/next-server/server/api-utils.ts +++ b/packages/next/next-server/server/api-utils.ts @@ -128,7 +128,7 @@ export async function parseBody( const maxBuffer = bytes.parse(limit) buffer = await getStream.buffer(req, { maxBuffer }) } catch (e) { - if (e.type === 'entity.too.large') { + if (e.name === 'MaxBufferError') { throw new ApiError(413, `Body exceeded ${limit} limit`) } else { throw new ApiError(400, 'Invalid body') From f9c32f924e295d20fc69e4fdef6c0666f5282d93 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Tue, 7 Dec 2021 19:58:00 +0100 Subject: [PATCH 3/5] Remove client provided encoding --- packages/next/server/api-utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next/server/api-utils.ts b/packages/next/server/api-utils.ts index 85efdc689dd60f7..6fe81d3022d3814 100644 --- a/packages/next/server/api-utils.ts +++ b/packages/next/server/api-utils.ts @@ -167,7 +167,7 @@ export async function parseBody( } } - const body = buffer.toString(encoding) + const body = buffer.toString() if (type === 'application/json' || type === 'application/ld+json') { return parseJson(body) From 5e0c3a22fa2ec49ab74b8a6995137dd2a647bc36 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Tue, 7 Dec 2021 20:43:11 +0100 Subject: [PATCH 4/5] Ensure valid encoding is passed --- packages/next/server/api-utils.ts | 44 +++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/packages/next/server/api-utils.ts b/packages/next/server/api-utils.ts index 6fe81d3022d3814..f24a66520ae432d 100644 --- a/packages/next/server/api-utils.ts +++ b/packages/next/server/api-utils.ts @@ -137,6 +137,45 @@ export async function apiResolver( } } +// Ensures that the user-provided encoding type is a valid encoding +function getValidEncoding(encoding: string): BufferEncoding | undefined { + switch (encoding) { + case 'ascii': { + return 'ascii' + } + case 'utf8': { + return 'utf8' + } + case 'utf-8': { + return 'utf-8' + } + case 'utf16le': { + return 'utf16le' + } + case 'ucs2': { + return 'ucs2' + } + case 'ucs-2': { + return 'ucs-2' + } + case 'base64': { + return 'base64' + } + case 'latin1': { + return 'latin1' + } + case 'binary': { + return 'binary' + } + case 'hex': { + return 'hex' + } + default: { + return undefined + } + } +} + /** * Parse incoming message like `json` or `urlencoded` * @param req request object @@ -152,13 +191,14 @@ export async function parseBody( contentType = parse('text/plain') } const { type, parameters } = contentType - const encoding = parameters.charset || 'utf-8' + + const encoding = getValidEncoding(parameters.charset) || 'utf-8' let buffer try { const maxBuffer = bytes.parse(limit) - buffer = await getStream.buffer(req, { maxBuffer }) + buffer = await getStream.buffer(req, { maxBuffer, encoding }) } catch (e) { if (isError(e) && e.name === 'MaxBufferError') { throw new ApiError(413, `Body exceeded ${limit} limit`) From b4b470dfa6a5a458b2ee9e63ee9eb13d175dce67 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Wed, 8 Dec 2021 10:38:48 +0100 Subject: [PATCH 5/5] Remove raw-body --- packages/next/package.json | 1 - yarn.lock | 11 +---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/packages/next/package.json b/packages/next/package.json index 55a9f3a62165ecb..508cde7042022c3 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -104,7 +104,6 @@ "postcss": "8.2.15", "process": "0.11.10", "querystring-es3": "0.2.1", - "raw-body": "2.4.1", "react-is": "17.0.2", "react-refresh": "0.8.3", "regenerator-runtime": "0.13.4", diff --git a/yarn.lock b/yarn.lock index db8af136581e82e..4bbf8fea9f7a535 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10883,7 +10883,7 @@ http-errors@1.7.2: statuses ">= 1.5.0 < 2" toidentifier "1.0.0" -http-errors@1.7.3, http-errors@~1.7.2: +http-errors@~1.7.2: version "1.7.3" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" dependencies: @@ -16500,15 +16500,6 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" -raw-body@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.1.tgz#30ac82f98bb5ae8c152e67149dac8d55153b168c" - dependencies: - bytes "3.1.0" - http-errors "1.7.3" - iconv-lite "0.4.24" - unpipe "1.0.0" - rc@^1.0.1, rc@^1.1.6, rc@^1.2.7, rc@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"