diff --git a/src/router.js b/src/router.js
index 02e68b0..80e1f53 100644
--- a/src/router.js
+++ b/src/router.js
@@ -75,7 +75,7 @@ export const exec = (url, route, matches = {}) => {
if (!m && param == val) continue;
// /foo/* match
if (!m && val && flag == '*') {
- matches.rest = '/' + url.slice(i).map(decodeURIComponent).join('/');
+ matches.rest = '/' + url.slice(i).join('/');
break;
}
// segment mismatch / missing required field:
diff --git a/test/node/router-match.test.js b/test/node/router-match.test.js
index 266a79e..ba90952 100644
--- a/test/node/router-match.test.js
+++ b/test/node/router-match.test.js
@@ -116,6 +116,11 @@ test('Handles leading/trailing slashes', () => {
});
});
+test('Percent-encoded characters in rest are not decoded', () => {
+ const result = execPath('/nested/child/%25', '/nested/*');
+ assert.equal(result, { path: '/nested/child/%25', params: {}, query: {}, rest: '/child/%25' });
+});
+
test('should not overwrite existing properties', () => {
const result = execPath('/foo/bar', '/:path/:query', { path: '/custom-path' });
assert.equal(result, {
diff --git a/test/router.test.js b/test/router.test.js
index de12b91..349e957 100644
--- a/test/router.test.js
+++ b/test/router.test.js
@@ -927,6 +927,35 @@ describe('Router', () => {
expect(params).to.deep.include({ id: 'bar' });
});
+ it('should not double-decode percent-encoded characters in nested routes', async () => {
+ let route;
+ const Inner = () => (
+
+ {
+ route = useRoute();
+ return null;
+ }}
+ />
+
+ );
+
+ render(
+
+
+
+
+
+ ,
+ scratch
+ );
+
+ scratch.querySelector('a[href="/nested/child/%25"]').click();
+ await sleep(1);
+ expect(route).to.deep.include({ params: { id: '%' } });
+ });
+
it('should replace the current URL', async () => {
const pushState = sinon.spy(history, 'pushState');
const replaceState = sinon.spy(history, 'replaceState');