diff options
author | 2023-04-04 15:48:28 +0200 | |
---|---|---|
committer | 2023-04-04 15:48:28 +0200 | |
commit | 4cc1bf61b832dba9aab1916b56f5260ceac2d97d (patch) | |
tree | 58da283fba308ca9b25653f03f14e8c0f39f3c8d /packages/integrations | |
parent | 1ec1df12641290ec8b3a417a6284fd8d752c02bf (diff) | |
download | astro-4cc1bf61b832dba9aab1916b56f5260ceac2d97d.tar.gz astro-4cc1bf61b832dba9aab1916b56f5260ceac2d97d.tar.zst astro-4cc1bf61b832dba9aab1916b56f5260ceac2d97d.zip |
fix(node): Fix malformed URLs crashing the server in certain cases (#6746)
Diffstat (limited to 'packages/integrations')
4 files changed, 75 insertions, 3 deletions
diff --git a/packages/integrations/node/src/http-server.ts b/packages/integrations/node/src/http-server.ts index f0dde82d5..850d61bbb 100644 --- a/packages/integrations/node/src/http-server.ts +++ b/packages/integrations/node/src/http-server.ts @@ -12,16 +12,32 @@ interface CreateServerOptions { removeBase: (pathname: string) => string; } +function parsePathname(pathname: string, host: string | undefined, port: number) { + try { + const urlPathname = new URL(pathname, `http://${host}:${port}`).pathname; + return decodeURI(encodeURI(urlPathname)); + } catch (err) { + return undefined; + } +} + export function createServer( { client, port, host, removeBase }: CreateServerOptions, handler: http.RequestListener ) { const listener: http.RequestListener = (req, res) => { if (req.url) { - let pathname = removeBase(req.url); + let pathname: string | undefined = removeBase(req.url); pathname = pathname[0] === '/' ? pathname : '/' + pathname; - pathname = new URL(pathname, `http://${host}:${port}`).pathname; - const stream = send(req, encodeURI(decodeURI(pathname)), { + const encodedURI = parsePathname(pathname, host, port); + + if (!encodedURI) { + res.writeHead(400); + res.end('Bad request.'); + return res; + } + + const stream = send(req, encodedURI, { root: fileURLToPath(client), dotfiles: pathname.startsWith('/.well-known/') ? 'allow' : 'deny', }); diff --git a/packages/integrations/node/test/bad-urls.test.js b/packages/integrations/node/test/bad-urls.test.js new file mode 100644 index 000000000..24a6e7747 --- /dev/null +++ b/packages/integrations/node/test/bad-urls.test.js @@ -0,0 +1,46 @@ +import { expect } from 'chai'; +import nodejs from '../dist/index.js'; +import { loadFixture } from './test-utils.js'; + +describe('API routes', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + let devPreview; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/bad-urls/', + output: 'server', + adapter: nodejs({ mode: 'standalone' }), + }); + await fixture.build(); + devPreview = await fixture.preview(); + }); + + after(async () => { + await devPreview.stop(); + }); + + it('Does not crash on bad urls', async () => { + const weirdURLs = [ + '/\\xfs.bxss.me%3Fastrojs.com/hello-world', + '/asdasdasd@ax_zX=.zxczasđ„%/Ășadasd000%/', + '%', + '%80', + '%c', + '%c0%80', + '%20foobar%', + ]; + + for (const weirdUrl of weirdURLs) { + const fetchResult = await fixture.fetch(weirdUrl); + expect([400, 500]).to.include( + fetchResult.status, + `${weirdUrl} returned something else than 400 or 500` + ); + } + const stillWork = await fixture.fetch('/'); + const text = await stillWork.text(); + expect(text).to.equal('<!DOCTYPE html>\nHello!'); + }); +}); diff --git a/packages/integrations/node/test/fixtures/bad-urls/package.json b/packages/integrations/node/test/fixtures/bad-urls/package.json new file mode 100644 index 000000000..73c119663 --- /dev/null +++ b/packages/integrations/node/test/fixtures/bad-urls/package.json @@ -0,0 +1,9 @@ +{ + "name": "@test/nodejs-badurls", + "version": "0.0.0", + "private": true, + "dependencies": { + "astro": "workspace:*", + "@astrojs/node": "workspace:*" + } +} diff --git a/packages/integrations/node/test/fixtures/bad-urls/src/pages/index.astro b/packages/integrations/node/test/fixtures/bad-urls/src/pages/index.astro new file mode 100644 index 000000000..10ddd6d25 --- /dev/null +++ b/packages/integrations/node/test/fixtures/bad-urls/src/pages/index.astro @@ -0,0 +1 @@ +Hello! |