Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/calm-peaches-enjoy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

[fix] handle redirects in handle hook while processing data request
19 changes: 13 additions & 6 deletions packages/kit/src/runtime/server/data/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,7 @@ export async function render_data(event, route, options, state, trailing_slash)
const error = normalize_error(e);

if (error instanceof Redirect) {
return json_response(
JSON.stringify({
type: 'redirect',
location: error.location
})
);
return redirect_json_response(error);
} else {
// TODO make it clearer that this was an unexpected error
return json_response(JSON.stringify(handle_error_and_jsonify(event, options, error)));
Expand All @@ -143,3 +138,15 @@ function json_response(json, status = 200) {
}
});
}

/**
* @param {Redirect} redirect
*/
export function redirect_json_response(redirect) {
return json_response(
JSON.stringify({
type: 'redirect',
location: redirect.location
})
);
}
17 changes: 15 additions & 2 deletions packages/kit/src/runtime/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
strip_data_suffix
} from '../../utils/url.js';
import { exec } from '../../utils/routing.js';
import { INVALIDATED_HEADER, render_data } from './data/index.js';
import { INVALIDATED_HEADER, redirect_json_response, render_data } from './data/index.js';
import { add_cookies_to_headers, get_cookies } from './cookie.js';
import { create_fetch } from './fetch.js';
import { Redirect } from '../control.js';
Expand Down Expand Up @@ -289,10 +289,23 @@ export async function respond(request, options, state) {
}
}

// Edge case: If user does `return Response(30x)` in handle hook while processing a data request,
// we need to transform the redirect response to a corresponding JSON response.
if (is_data_request && response.status >= 300 && response.status < 309) {
Comment thread
Rich-Harris marked this conversation as resolved.
Outdated
const location = response.headers.get('location');
if (location) {
return redirect_json_response(new Redirect(/** @type {any} */ (response.status), location));
}
}

return response;
} catch (error) {
if (error instanceof Redirect) {
return redirect_response(error.status, error.location);
if (is_data_request) {
return redirect_json_response(error);
} else {
return redirect_response(error.status, error.location);
}
}
return handle_fatal_error(event, options, error);
}
Expand Down
13 changes: 12 additions & 1 deletion packages/kit/test/apps/basics/src/hooks.server.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fs from 'fs';
import { sequence } from '@sveltejs/kit/hooks';
import { HttpError } from '../../../../src/runtime/control';
import { error } from '@sveltejs/kit';
import { error, redirect } from '@sveltejs/kit';

/**
* Transform an error into a POJO, by copying its `name`, `message`
Expand Down Expand Up @@ -80,6 +80,17 @@ export const handle = sequence(
} catch {}

return response;
},
async ({ event, resolve }) => {
if (event.url.pathname.includes('/redirect/in-handle')) {
if (event.url.search === '?throw') {
throw redirect(307, event.url.origin + '/redirect/c');
} else {
return new Response(undefined, { status: 307, headers: { location: '/redirect/c' } });
}
}

return resolve(event);
}
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@

<a href="/redirect/missing-status/a">a (missing-status)</a>
<a href="/redirect/missing-status/b">b (missing-status)</a>

<a href="/redirect/in-handle?throw">in-handle (throw redirect)</a>
<a href="/redirect/in-handle?response">in-handle (return Response)</a>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export function load() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h1>in-handle</h1>
26 changes: 26 additions & 0 deletions packages/kit/test/apps/basics/test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1337,6 +1337,32 @@ test.describe('Redirects', () => {
expect(await page.textContent('h1')).toBe('Hazaa!');
}
});

test('redirect response in handle hook', async ({ baseURL, clicknav, page }) => {
await page.goto('/redirect');

await clicknav('[href="/redirect/in-handle?response"]');

await page.waitForURL('/redirect/c');
expect(await page.textContent('h1')).toBe('c');
expect(page.url()).toBe(`${baseURL}/redirect/c`);

await page.goBack();
expect(page.url()).toBe(`${baseURL}/redirect`);
});

test('throw redirect in handle hook', async ({ baseURL, clicknav, page }) => {
await page.goto('/redirect');

await clicknav('[href="/redirect/in-handle?throw"]');

await page.waitForURL('/redirect/c');
expect(await page.textContent('h1')).toBe('c');
expect(page.url()).toBe(`${baseURL}/redirect/c`);

await page.goBack();
expect(page.url()).toBe(`${baseURL}/redirect`);
});
});

test.describe('Routing', () => {
Expand Down