Skip to content

Commit

Permalink
fix(core): prevent 404 when accessing /page.html (#7184)
Browse files Browse the repository at this point in the history
  • Loading branch information
Josh-Cena authored Apr 22, 2022
1 parent 4e4aa6a commit c4e92c8
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 17 deletions.
1 change: 1 addition & 0 deletions jest.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ process.env.TZ = 'UTC';
const ignorePatterns = [
'/node_modules/',
'__fixtures__',
'__mocks__',
'/testUtils.ts',
'/packages/docusaurus/lib',
'/packages/docusaurus-logger/lib',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

export default [
{
path: '/page.html',
exact: true,
component: '',
},
{
path: '/docs',
exact: false,
component: '',
routes: [
{
path: '/docs/installation',
exact: true,
component: '',
},
],
},
{
path: '*',
component: '',
},
];
39 changes: 27 additions & 12 deletions packages/docusaurus/src/client/__tests__/normalizeLocation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,33 @@ describe('normalizeLocation', () => {
});
});

it('removes html extension', () => {
expect(
normalizeLocation({
pathname: '/docs/installation.html',
}),
).toEqual({
pathname: '/docs/installation',
});
expect(
normalizeLocation({
pathname: '/docs/introduction/foo.html',
search: '',
hash: '#bar',
}),
).toEqual({
pathname: '/docs/introduction/foo',
search: '',
hash: '#bar',
});
});

it('does not strip extension if the route location has one', () => {
expect(normalizeLocation({pathname: '/page.html'})).toEqual({
pathname: '/page.html',
});
});

it('leaves pathnames untouched', () => {
const replaceMock = jest.spyOn(String.prototype, 'replace');

Expand Down Expand Up @@ -72,18 +99,6 @@ describe('normalizeLocation', () => {
});
expect(replaceMock).toBeCalledTimes(1);

expect(
normalizeLocation({
pathname: '/docs/introduction/foo.html',
search: '',
hash: '#bar',
}),
).toEqual({
pathname: '/docs/introduction/foo.html',
search: '',
hash: '#bar',
});

expect(
normalizeLocation({
pathname: '/',
Expand Down
20 changes: 15 additions & 5 deletions packages/docusaurus/src/client/normalizeLocation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,33 @@
* LICENSE file in the root directory of this source tree.
*/

import {matchRoutes} from 'react-router-config';
import routes from '@generated/routes';
import type {Location} from 'history';

// Memoize previously normalized pathnames.
const pathnames: {[rawPathname: string]: string} = {};
const pathnames = new Map<string, string>();

export default function normalizeLocation<T extends Location>(location: T): T {
if (pathnames[location.pathname]) {
if (pathnames.has(location.pathname)) {
return {
...location,
pathname: pathnames[location.pathname],
pathname: pathnames.get(location.pathname),
};
}

// If the location was registered with an `.html` extension, we don't strip it
// away, or it will render to a 404 page.
const matchedRoutes = matchRoutes(routes, location.pathname);
if (matchedRoutes.some(({route}) => route.exact === true)) {
pathnames.set(location.pathname, location.pathname);
return location;
}

const pathname =
location.pathname.trim().replace(/\/index\.html$/, '') || '/';
location.pathname.trim().replace(/(?:\/index)?\.html$/, '') || '/';

pathnames[location.pathname] = pathname;
pathnames.set(location.pathname, pathname);

return {
...location,
Expand Down
4 changes: 4 additions & 0 deletions website/_dogfooding/_docs tests/dummy.md
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
---
slug: dummy.html
---

# Just a dummy page

0 comments on commit c4e92c8

Please sign in to comment.