Skip to content

Commit

Permalink
fix: correctly restore trailing slash in url pathname for data reques…
Browse files Browse the repository at this point in the history
…ts (#10475)

Fixes #9595
Fixes #10125
  • Loading branch information
GingerAdonis authored Aug 11, 2023
1 parent e133aba commit 75d88d3
Show file tree
Hide file tree
Showing 11 changed files with 54 additions and 4 deletions.
5 changes: 5 additions & 0 deletions .changeset/mighty-crews-switch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

fix: correctly restore trailing slash in url pathname for data requests
5 changes: 5 additions & 0 deletions .changeset/pink-sloths-join.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

fix: load trailing slash option from server even when there's no load function
2 changes: 1 addition & 1 deletion packages/kit/src/core/postbuild/analyse.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ async function analyse({ manifest_path, env }) {
const node = await loader();

metadata.nodes[node.index] = {
has_server_load: node.server?.load !== undefined
has_server_load: node.server?.load !== undefined || node.server?.trailingSlash !== undefined
};
}

Expand Down
5 changes: 4 additions & 1 deletion packages/kit/src/runtime/client/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { compact } from '../../utils/array.js';
import { validate_page_exports } from '../../utils/exports.js';
import { unwrap_promises } from '../../utils/promises.js';
import { HttpError, Redirect } from '../control.js';
import { INVALIDATED_PARAM, validate_depends } from '../shared.js';
import { INVALIDATED_PARAM, TRAILING_SLASH_PARAM, validate_depends } from '../shared.js';
import { INDEX_KEY, PRELOAD_PRIORITIES, SCROLL_KEY, SNAPSHOT_KEY } from './constants.js';
import { stores } from './singletons.js';

Expand Down Expand Up @@ -1819,6 +1819,9 @@ export function create_client(app, target) {
async function load_data(url, invalid) {
const data_url = new URL(url);
data_url.pathname = add_data_suffix(url.pathname);
if (url.pathname.endsWith('/')) {
data_url.searchParams.append(TRAILING_SLASH_PARAM, '1');
}
if (DEV && url.searchParams.has(INVALIDATED_PARAM)) {
throw new Error(`Cannot used reserved query parameter "${INVALIDATED_PARAM}"`);
}
Expand Down
7 changes: 5 additions & 2 deletions packages/kit/src/runtime/server/respond.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
import { get_option } from '../../utils/options.js';
import { error, json, text } from '../../exports/index.js';
import { action_json_redirect, is_action_json_request } from './page/actions.js';
import { INVALIDATED_PARAM } from '../shared.js';
import { INVALIDATED_PARAM, TRAILING_SLASH_PARAM } from '../shared.js';

/* global __SVELTEKIT_ADAPTER_NAME__ */

Expand Down Expand Up @@ -100,7 +100,10 @@ export async function respond(request, options, manifest, state) {
let invalidated_data_nodes;
if (is_data_request) {
decoded = strip_data_suffix(decoded) || '/';
url.pathname = strip_data_suffix(url.pathname) || '/';
url.pathname =
strip_data_suffix(url.pathname) +
(url.searchParams.get(TRAILING_SLASH_PARAM) === '1' ? '/' : '') || '/';
url.searchParams.delete(TRAILING_SLASH_PARAM);
invalidated_data_nodes = url.searchParams
.get(INVALIDATED_PARAM)
?.split('')
Expand Down
2 changes: 2 additions & 0 deletions packages/kit/src/runtime/shared.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ export function validate_depends(route_id, dep) {
}

export const INVALIDATED_PARAM = 'x-sveltekit-invalidated';

export const TRAILING_SLASH_PARAM = 'x-sveltekit-trailing-slash';
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
export let data;
</script>

<ul>
<li><a href="/routing/trailing-slash-server/always">/always</a></li>
<li><a href="/routing/trailing-slash-server/ignore">/ignore</a></li>
<li><a href="/routing/trailing-slash-server/ignore/">/ignore/</a></li>
<li><a href="/routing/trailing-slash-server/never/">/never/</a></li>
</ul>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const trailingSlash = 'ignore';
Empty file.
28 changes: 28 additions & 0 deletions packages/kit/test/apps/basics/test/cross-platform/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -936,6 +936,34 @@ test.describe('Routing', () => {
);
});

test('trailing slash server with config ignore and no trailing slash in URL', async ({
page,
clicknav
}) => {
await page.goto('/routing/trailing-slash-server');
await clicknav('[href="/routing/trailing-slash-server/ignore"]');
expect(await page.textContent('[data-test-id="pathname-store"]')).toBe(
'/routing/trailing-slash-server/ignore'
);
expect(await page.textContent('[data-test-id="pathname-data"]')).toBe(
'/routing/trailing-slash-server/ignore'
);
});

test('trailing slash server with config ignore and trailing slash in URL', async ({
page,
clicknav
}) => {
await page.goto('/routing/trailing-slash-server');
await clicknav('[href="/routing/trailing-slash-server/ignore/"]');
expect(await page.textContent('[data-test-id="pathname-store"]')).toBe(
'/routing/trailing-slash-server/ignore/'
);
expect(await page.textContent('[data-test-id="pathname-data"]')).toBe(
'/routing/trailing-slash-server/ignore/'
);
});

test('trailing slash server with config never', async ({ page, clicknav }) => {
await page.goto('/routing/trailing-slash-server');
await clicknav('[href="/routing/trailing-slash-server/never/"]');
Expand Down

0 comments on commit 75d88d3

Please sign in to comment.