Skip to content

Commit d996db6

Browse files
ascorbicsarah11918
andauthoredJun 14, 2024··
fix: throw error if rewrite is attempted after body is used (#11258)
* fix: throw error if rewrite is attempted after body is used * Apply suggestions from code review Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca> --------- Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
1 parent 537e971 commit d996db6

File tree

7 files changed

+97
-0
lines changed

7 files changed

+97
-0
lines changed
 

‎.changeset/healthy-oranges-report.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'astro': patch
3+
---
4+
5+
Adds a new error `RewriteWithBodyUsed` that throws when `Astro.rewrite` is used after the request body has already been read.

‎packages/astro/src/core/errors/errors-data.ts

+23
Original file line numberDiff line numberDiff line change
@@ -1266,6 +1266,29 @@ export const ServerOnlyModule = {
12661266
message: (name: string) => `The "${name}" module is only available server-side.`,
12671267
} satisfies ErrorData;
12681268

1269+
1270+
/**
1271+
* @docs
1272+
* @description
1273+
* `Astro.rewrite()` cannot be used if the request body has already been read. If you need to read the body, first clone the request. For example:
1274+
*
1275+
* ```js
1276+
* const data = await Astro.request.clone().formData();
1277+
*
1278+
* Astro.rewrite("/target")
1279+
* ```
1280+
*
1281+
* @see
1282+
* - [Request.clone()](https://developer.mozilla.org/en-US/docs/Web/API/Request/clone)
1283+
* - [Astro.rewrite](https://docs.astro.build/en/reference/configuration-reference/#experimentalrewriting)
1284+
*/
1285+
1286+
export const RewriteWithBodyUsed = {
1287+
name: 'RewriteWithBodyUsed',
1288+
title: 'Cannot use Astro.rewrite after the request body has been read',
1289+
message: 'Astro.rewrite() cannot be used if the request body has already been read. If you need to read the body, first clone the request.',
1290+
} satisfies ErrorData;
1291+
12691292
/**
12701293
* @docs
12711294
* @kind heading

‎packages/astro/src/core/render-context.ts

+3
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,9 @@ export class RenderContext {
542542
* @param oldRequest The old `Request`
543543
*/
544544
#copyRequest(newUrl: URL, oldRequest: Request): Request {
545+
if(oldRequest.bodyUsed) {
546+
throw new AstroError(AstroErrorData.RewriteWithBodyUsed);
547+
}
545548
return new Request(newUrl, {
546549
method: oldRequest.method,
547550
headers: oldRequest.headers,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
---
3+
4+
<form method="post" action="/post/post-body-used">
5+
<input type="text" name="email" value="example@example.com" />
6+
<input type="submit" />
7+
</form>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
let email = ''
3+
if (Astro.request.method === 'POST') {
4+
try {
5+
const data = await Astro.request.formData();
6+
email = data.get('email');
7+
} catch (e) {
8+
console.log(e)
9+
}
10+
}
11+
---
12+
13+
<h1>Post B</h1>
14+
15+
<h2>{email}</h2>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
let data
3+
if (Astro.request.method === 'POST') {
4+
try {
5+
data = await Astro.request.text();
6+
} catch (e) {
7+
console.log(e)
8+
}
9+
}
10+
11+
return Astro.rewrite('/post/post-b')
12+
13+
---
14+
15+
<h1>Post body used</h1>
16+
17+
<h2>{data}</h2>

‎packages/astro/test/rewrite.test.js

+27
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,21 @@ describe('Dev rewrite, hybrid/server', () => {
8585
assert.match($('h1').text(), /Title/);
8686
assert.match($('p').text(), /some-slug/);
8787
});
88+
89+
it('should display an error if a rewrite is attempted after the body has been consumed', async () => {
90+
const formData = new FormData();
91+
formData.append('email', 'example@example.com');
92+
93+
const request = new Request('http://example.com/post/post-body-used', {
94+
method: 'POST',
95+
body: formData,
96+
});
97+
const response = await fixture.fetch('/post/post-body-used', request);
98+
const html = await response.text();
99+
const $ = cheerioLoad(html);
100+
101+
assert.equal($('title').text(), 'RewriteWithBodyUsed');
102+
});
88103
});
89104

90105
describe('Build reroute', () => {
@@ -272,6 +287,18 @@ describe('SSR rewrite, hybrid/server', () => {
272287
assert.match($('h1').text(), /Title/);
273288
assert.match($('p').text(), /some-slug/);
274289
});
290+
291+
it('should return a 500 if a rewrite is attempted after the body has been read', async () => {
292+
const formData = new FormData();
293+
formData.append('email', 'example@example.com');
294+
295+
const request = new Request('http://example.com/post/post-body-used', {
296+
method: 'POST',
297+
body: formData,
298+
});
299+
const response = await app.render(request);
300+
assert.equal(response.status, 500);
301+
});
275302
});
276303

277304
describe('Middleware', () => {

0 commit comments

Comments
 (0)
Please sign in to comment.