0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2025-01-27 22:19:04 -05:00

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>
This commit is contained in:
Matt Kane 2024-06-14 13:57:17 +01:00 committed by GitHub
parent 537e971372
commit d996db6f0b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 97 additions and 0 deletions

View file

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

View file

@ -1266,6 +1266,29 @@ export const ServerOnlyModule = {
message: (name: string) => `The "${name}" module is only available server-side.`,
} satisfies ErrorData;
/**
* @docs
* @description
* `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:
*
* ```js
* const data = await Astro.request.clone().formData();
*
* Astro.rewrite("/target")
* ```
*
* @see
* - [Request.clone()](https://developer.mozilla.org/en-US/docs/Web/API/Request/clone)
* - [Astro.rewrite](https://docs.astro.build/en/reference/configuration-reference/#experimentalrewriting)
*/
export const RewriteWithBodyUsed = {
name: 'RewriteWithBodyUsed',
title: 'Cannot use Astro.rewrite after the request body has been read',
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.',
} satisfies ErrorData;
/**
* @docs
* @kind heading

View file

@ -542,6 +542,9 @@ export class RenderContext {
* @param oldRequest The old `Request`
*/
#copyRequest(newUrl: URL, oldRequest: Request): Request {
if(oldRequest.bodyUsed) {
throw new AstroError(AstroErrorData.RewriteWithBodyUsed);
}
return new Request(newUrl, {
method: oldRequest.method,
headers: oldRequest.headers,

View file

@ -0,0 +1,7 @@
---
---
<form method="post" action="/post/post-body-used">
<input type="text" name="email" value="example@example.com" />
<input type="submit" />
</form>

View file

@ -0,0 +1,15 @@
---
let email = ''
if (Astro.request.method === 'POST') {
try {
const data = await Astro.request.formData();
email = data.get('email');
} catch (e) {
console.log(e)
}
}
---
<h1>Post B</h1>
<h2>{email}</h2>

View file

@ -0,0 +1,17 @@
---
let data
if (Astro.request.method === 'POST') {
try {
data = await Astro.request.text();
} catch (e) {
console.log(e)
}
}
return Astro.rewrite('/post/post-b')
---
<h1>Post body used</h1>
<h2>{data}</h2>

View file

@ -85,6 +85,21 @@ describe('Dev rewrite, hybrid/server', () => {
assert.match($('h1').text(), /Title/);
assert.match($('p').text(), /some-slug/);
});
it('should display an error if a rewrite is attempted after the body has been consumed', async () => {
const formData = new FormData();
formData.append('email', 'example@example.com');
const request = new Request('http://example.com/post/post-body-used', {
method: 'POST',
body: formData,
});
const response = await fixture.fetch('/post/post-body-used', request);
const html = await response.text();
const $ = cheerioLoad(html);
assert.equal($('title').text(), 'RewriteWithBodyUsed');
});
});
describe('Build reroute', () => {
@ -272,6 +287,18 @@ describe('SSR rewrite, hybrid/server', () => {
assert.match($('h1').text(), /Title/);
assert.match($('p').text(), /some-slug/);
});
it('should return a 500 if a rewrite is attempted after the body has been read', async () => {
const formData = new FormData();
formData.append('email', 'example@example.com');
const request = new Request('http://example.com/post/post-body-used', {
method: 'POST',
body: formData,
});
const response = await app.render(request);
assert.equal(response.status, 500);
});
});
describe('Middleware', () => {