summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.changeset/chilled-hornets-press.md5
-rw-r--r--packages/astro/src/core/routing/params.ts5
-rw-r--r--packages/astro/test/units/routing/route-sanitization.test.js66
3 files changed, 75 insertions, 1 deletions
diff --git a/.changeset/chilled-hornets-press.md b/.changeset/chilled-hornets-press.md
new file mode 100644
index 000000000..5283117fe
--- /dev/null
+++ b/.changeset/chilled-hornets-press.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Sanitize route params for leading and trailing slashes
diff --git a/packages/astro/src/core/routing/params.ts b/packages/astro/src/core/routing/params.ts
index fc05c9696..d2856563e 100644
--- a/packages/astro/src/core/routing/params.ts
+++ b/packages/astro/src/core/routing/params.ts
@@ -1,5 +1,6 @@
import type { GetStaticPathsItem, Params, RouteData } from '../../@types/astro';
import { validateGetStaticPathsParameter } from './validation.js';
+import { trimSlashes } from '../path.js';
/**
* given an array of params like `['x', 'y', 'z']` for
@@ -32,7 +33,9 @@ export function stringifyParams(params: GetStaticPathsItem['params'], route: Rou
const validatedParams = Object.entries(params).reduce((acc, next) => {
validateGetStaticPathsParameter(next, route.component);
const [key, value] = next;
- acc[key] = value?.toString();
+ if (value !== undefined) {
+ acc[key] = typeof value === 'string' ? trimSlashes(value) : value.toString()
+ }
return acc;
}, {} as Params);
diff --git a/packages/astro/test/units/routing/route-sanitization.test.js b/packages/astro/test/units/routing/route-sanitization.test.js
new file mode 100644
index 000000000..3bddeb92a
--- /dev/null
+++ b/packages/astro/test/units/routing/route-sanitization.test.js
@@ -0,0 +1,66 @@
+import {
+ createBasicSettings,
+ createFs,
+ createRequestAndResponse,
+ defaultLogger,
+} from '../test-utils.js';
+import { fileURLToPath } from 'node:url';
+import { expect } from 'chai';
+import { createContainer } from '../../../dist/core/dev/container.js';
+import * as cheerio from 'cheerio';
+import testAdapter from '../../test-adapter.js';
+
+const root = new URL('../../fixtures/alias/', import.meta.url);
+const fileSystem = {
+'/src/pages/[...testSlashTrim].astro': `
+ ---
+ export function getStaticPaths() {
+ return [
+ {
+ params: {
+ testSlashTrim: "/a-route-param-with-leading-trailing-slash/",
+ },
+ },
+ ];
+ }
+ ---
+ <p>Success!</p>
+`,
+};
+
+describe('Route sanitization', () => {
+ let container;
+ let settings;
+
+ before(async () => {
+ const fs = createFs(fileSystem, root);
+ settings = await createBasicSettings({
+ root: fileURLToPath(root),
+ trailingSlash: 'never',
+ output: 'hybrid',
+ adapter: testAdapter(),
+ });
+ container = await createContainer({
+ fs,
+ settings,
+ logger: defaultLogger,
+ });
+ });
+
+ after(async () => {
+ await container.close();
+ });
+
+ describe('Request', () => {
+ it('should correctly match a route param with a trailing slash', async () => {
+ const { req, res, text } = createRequestAndResponse({
+ method: 'GET',
+ url: '/a-route-param-with-leading-trailing-slash',
+ });
+ container.handle(req, res);
+ const html = await text();
+ const $ = cheerio.load(html);
+ expect($('p').text()).to.equal('Success!');
+ });
+ });
+});