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:
parent
537e971372
commit
d996db6f0b
7 changed files with 97 additions and 0 deletions
5
.changeset/healthy-oranges-report.md
Normal file
5
.changeset/healthy-oranges-report.md
Normal 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.
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
7
packages/astro/test/fixtures/rewrite-server/src/pages/post/index.astro
vendored
Normal file
7
packages/astro/test/fixtures/rewrite-server/src/pages/post/index.astro
vendored
Normal 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>
|
15
packages/astro/test/fixtures/rewrite-server/src/pages/post/post-b.astro
vendored
Normal file
15
packages/astro/test/fixtures/rewrite-server/src/pages/post/post-b.astro
vendored
Normal 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>
|
17
packages/astro/test/fixtures/rewrite-server/src/pages/post/post-body-used.astro
vendored
Normal file
17
packages/astro/test/fixtures/rewrite-server/src/pages/post/post-body-used.astro
vendored
Normal 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>
|
|
@ -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', () => {
|
||||
|
|
Loading…
Add table
Reference in a new issue