Skip to content

Commit b7dd447

Browse files
authored
make actionBodySizeLimit configurable (#15589)
* make actionBodySizeLimit configurable * adds a changeset
1 parent e0f1a2b commit b7dd447

File tree

9 files changed

+50
-8
lines changed

9 files changed

+50
-8
lines changed

.changeset/young-cougars-mix.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@astrojs/node': patch
3+
'astro': patch
4+
---
5+
6+
Make the body request limit a configurable

packages/astro/src/actions/runtime/server.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -323,9 +323,10 @@ export function getActionContext(context: APIContext): AstroActionContext {
323323
throw error;
324324
}
325325

326+
const bodySizeLimit = pipeline.manifest.actionBodySizeLimit;
326327
let input;
327328
try {
328-
input = await parseRequestBody(context.request);
329+
input = await parseRequestBody(context.request, bodySizeLimit);
329330
} catch (e) {
330331
if (e instanceof ActionError) {
331332
return { data: undefined, error: e };
@@ -381,24 +382,22 @@ function getCallerInfo(ctx: APIContext) {
381382
return undefined;
382383
}
383384

384-
const DEFAULT_ACTION_BODY_SIZE_LIMIT = 1024 * 1024;
385-
386-
async function parseRequestBody(request: Request) {
385+
async function parseRequestBody(request: Request, bodySizeLimit: number) {
387386
const contentType = request.headers.get('content-type');
388387
const contentLengthHeader = request.headers.get('content-length');
389388
const contentLength = contentLengthHeader ? Number.parseInt(contentLengthHeader, 10) : undefined;
390389
const hasContentLength = typeof contentLength === 'number' && Number.isFinite(contentLength);
391390

392391
if (!contentType) return undefined;
393-
if (hasContentLength && contentLength > DEFAULT_ACTION_BODY_SIZE_LIMIT) {
392+
if (hasContentLength && contentLength > bodySizeLimit) {
394393
throw new ActionError({
395394
code: 'CONTENT_TOO_LARGE',
396-
message: `Request body exceeds ${DEFAULT_ACTION_BODY_SIZE_LIMIT} bytes`,
395+
message: `Request body exceeds ${bodySizeLimit} bytes`,
397396
});
398397
}
399398
if (hasContentType(contentType, formContentTypes)) {
400399
if (!hasContentLength) {
401-
const body = await readRequestBodyWithLimit(request.clone(), DEFAULT_ACTION_BODY_SIZE_LIMIT);
400+
const body = await readRequestBodyWithLimit(request.clone(), bodySizeLimit);
402401
const formRequest = new Request(request.url, {
403402
method: request.method,
404403
headers: request.headers,
@@ -411,7 +410,7 @@ async function parseRequestBody(request: Request) {
411410
if (hasContentType(contentType, ['application/json'])) {
412411
if (contentLength === 0) return undefined;
413412
if (!hasContentLength) {
414-
const body = await readRequestBodyWithLimit(request.clone(), DEFAULT_ACTION_BODY_SIZE_LIMIT);
413+
const body = await readRequestBodyWithLimit(request.clone(), bodySizeLimit);
415414
if (body.byteLength === 0) return undefined;
416415
return JSON.parse(new TextDecoder().decode(body));
417416
}

packages/astro/src/container/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ function createManifest(
162162
i18n: manifest?.i18n,
163163
checkOrigin: false,
164164
allowedDomains: manifest?.allowedDomains ?? [],
165+
actionBodySizeLimit: 1024 * 1024,
165166
middleware: manifest?.middleware ?? middlewareInstance,
166167
key: createKey(),
167168
csp: manifest?.csp,

packages/astro/src/core/app/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ export type SSRManifest = {
8787
actions?: () => Promise<SSRActions> | SSRActions;
8888
checkOrigin: boolean;
8989
allowedDomains?: Partial<RemotePattern>[];
90+
actionBodySizeLimit: number;
9091
sessionConfig?: ResolvedSessionConfig<any>;
9192
cacheDir: string | URL;
9293
srcDir: string | URL;

packages/astro/src/core/build/generate.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,7 @@ async function createBuildManifest(
775775
actions: () => actions,
776776
checkOrigin:
777777
(settings.config.security?.checkOrigin && settings.buildOutput === 'server') ?? false,
778+
actionBodySizeLimit: settings.config.security.actionBodySizeLimit,
778779
key,
779780
csp,
780781
};

packages/astro/src/core/build/plugins/plugin-manifest.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ async function buildManifest(
388388
checkOrigin:
389389
(settings.config.security?.checkOrigin && settings.buildOutput === 'server') ?? false,
390390
allowedDomains: settings.config.security?.allowedDomains,
391+
actionBodySizeLimit: settings.config.security.actionBodySizeLimit,
391392
serverIslandNameMap: Array.from(settings.serverIslandNameMap),
392393
key: encodedKey,
393394
sessionConfig: settings.config.session,

packages/astro/src/core/config/schemas/base.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ export const ASTRO_CONFIG_DEFAULTS = {
9191
security: {
9292
checkOrigin: true,
9393
allowedDomains: [],
94+
actionBodySizeLimit: 1024 * 1024,
9495
},
9596
env: {
9697
schema: {},
@@ -440,6 +441,10 @@ export const AstroConfigSchema = z.object({
440441
)
441442
.optional()
442443
.default(ASTRO_CONFIG_DEFAULTS.security.allowedDomains),
444+
actionBodySizeLimit: z
445+
.number()
446+
.optional()
447+
.default(ASTRO_CONFIG_DEFAULTS.security.actionBodySizeLimit),
443448
})
444449
.optional()
445450
.default(ASTRO_CONFIG_DEFAULTS.security),

packages/astro/src/types/public/config.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,31 @@ export interface AstroUserConfig<
633633
* When not configured, `X-Forwarded-Host` headers are not trusted and will be ignored.
634634
*/
635635
allowedDomains?: Partial<RemotePattern>[];
636+
637+
/**
638+
* @docs
639+
* @name security.actionBodySizeLimit
640+
* @kind h4
641+
* @type {number}
642+
* @default `1048576` (1 MB)
643+
* @version 5.x.0
644+
* @description
645+
*
646+
* Sets the maximum size in bytes allowed for action request bodies.
647+
*
648+
* By default, action request bodies are limited to 1 MB (1048576 bytes) to prevent abuse.
649+
* You can increase this limit if your actions need to accept larger payloads, for example when handling file uploads.
650+
*
651+
* ```js
652+
* // astro.config.mjs
653+
* export default defineConfig({
654+
* security: {
655+
* actionBodySizeLimit: 10 * 1024 * 1024 // 10 MB
656+
* }
657+
* })
658+
* ```
659+
*/
660+
actionBodySizeLimit?: number;
636661
};
637662

638663
/**

packages/astro/src/vite-plugin-astro-server/plugin.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ export default function createVitePluginAstroServer({
130130
warnMissingAdapter(logger, settings);
131131
pipeline.manifest.checkOrigin =
132132
settings.config.security.checkOrigin && settings.buildOutput === 'server';
133+
pipeline.manifest.actionBodySizeLimit =
134+
settings.config.security.actionBodySizeLimit;
133135
pipeline.setManifestData(routesList);
134136
}
135137

@@ -311,6 +313,7 @@ export function createDevelopmentManifest(settings: AstroSettings): SSRManifest
311313
i18n: i18nManifest,
312314
checkOrigin:
313315
(settings.config.security?.checkOrigin && settings.buildOutput === 'server') ?? false,
316+
actionBodySizeLimit: settings.config.security.actionBodySizeLimit,
314317
key: hasEnvironmentKey() ? getEnvironmentKey() : createKey(),
315318
middleware() {
316319
return {

0 commit comments

Comments
 (0)