Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
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
7 changes: 6 additions & 1 deletion packages/adapter-netlify/src/handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ export function init(manifest) {
const server = new Server(manifest);

return async (event, context) => {
const rendered = await server.respond(to_request(event), { platform: { context } });
const rendered = await server.respond(to_request(event), {
platform: { context },
getClientAddress() {
return event.headers['x-nf-client-connection-ip'];

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ascorbic I wanted to confirm with you if we're doing this correctly because it seems to be undocumented, but is what is suggested in this support post: https://answers.netlify.com/t/is-the-client-ip-header-going-to-be-supported-long-term/11203

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ascorbic I wanted to confirm with you if we're doing this correctly because it seems to be undocumented, but is what is suggested in this support post: https://answers.netlify.com/t/is-the-client-ip-header-going-to-be-supported-long-term/11203

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@benmccann Yes, that's correct. We recently cleaned up the internal headers sent to functions so that all remaining ones are now officially supported. https://answers.netlify.com/t/upcoming-change-stripping-exposed-netlify-headers-from-function-and-proxy-requests/52665

}
});

const partial_response = {
statusCode: rendered.status,
Expand Down
7 changes: 7 additions & 0 deletions packages/kit/src/core/build/prerender/prerender.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ export async function prerender({ config, entries, files, log }) {
const dependencies = new Map();

const response = await server.respond(new Request(`http://sveltekit-prerender${encoded}`), {
getClientAddress,
prerender: {
default: config.kit.prerender.default,
dependencies
Expand Down Expand Up @@ -268,6 +269,7 @@ export async function prerender({ config, entries, files, log }) {
}

const rendered = await server.respond(new Request('http://sveltekit-prerender/[fallback]'), {
getClientAddress,
prerender: {
fallback: true,
default: false,
Expand All @@ -281,3 +283,8 @@ export async function prerender({ config, entries, files, log }) {

return prerendered;
}

/** @return {string} */
function getClientAddress() {
throw new Error('Cannot read clientAddress during prerendering');
}
116 changes: 63 additions & 53 deletions packages/kit/src/core/dev/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -259,62 +259,72 @@ export async function create_plugin(config, cwd) {

const template = load_template(cwd, config);

const rendered = await respond(request, {
amp: config.kit.amp,
csp: config.kit.csp,
dev: true,
floc: config.kit.floc,
get_stack: (error) => {
return fix_stack_trace(error);
},
handle_error: (error, event) => {
hooks.handleError({
error: new Proxy(error, {
get: (target, property) => {
if (property === 'stack') {
return fix_stack_trace(error);
const rendered = await respond(
request,
{
amp: config.kit.amp,
csp: config.kit.csp,
dev: true,
floc: config.kit.floc,
get_stack: (error) => {
return fix_stack_trace(error);
},
handle_error: (error, event) => {
hooks.handleError({
error: new Proxy(error, {
get: (target, property) => {
if (property === 'stack') {
return fix_stack_trace(error);
}

return Reflect.get(target, property, target);
}

return Reflect.get(target, property, target);
}),
event,

// TODO remove for 1.0
// @ts-expect-error
get request() {
throw new Error(
'request in handleError has been replaced with event. See https://github.com/sveltejs/kit/pull/3384 for details'
);
}
}),
event,

// TODO remove for 1.0
// @ts-expect-error
get request() {
throw new Error(
'request in handleError has been replaced with event. See https://github.com/sveltejs/kit/pull/3384 for details'
);
}
});
},
hooks,
hydrate: config.kit.browser.hydrate,
manifest,
method_override: config.kit.methodOverride,
paths: {
base: config.kit.paths.base,
assets
},
prefix: '',
prerender: config.kit.prerender.enabled,
read: (file) => fs.readFileSync(path.join(config.kit.files.assets, file)),
root,
router: config.kit.browser.router,
template: ({ head, body, assets, nonce }) => {
return (
template
.replace(/%svelte\.assets%/g, assets)
.replace(/%svelte\.nonce%/g, nonce)
// head and body must be replaced last, in case someone tries to sneak in %svelte.assets% etc
.replace('%svelte.head%', () => head)
.replace('%svelte.body%', () => body)
);
});
},
hooks,
hydrate: config.kit.browser.hydrate,
manifest,
method_override: config.kit.methodOverride,
paths: {
base: config.kit.paths.base,
assets
},
prefix: '',
prerender: config.kit.prerender.enabled,
read: (file) => fs.readFileSync(path.join(config.kit.files.assets, file)),
root,
router: config.kit.browser.router,
template: ({ head, body, assets, nonce }) => {
return (
template
.replace(/%svelte\.assets%/g, assets)
.replace(/%svelte\.nonce%/g, nonce)
// head and body must be replaced last, in case someone tries to sneak in %svelte.assets% etc
.replace('%svelte.head%', () => head)
.replace('%svelte.body%', () => body)
);
},
template_contains_nonce: template.includes('%svelte.nonce%'),
trailing_slash: config.kit.trailingSlash
},
template_contains_nonce: template.includes('%svelte.nonce%'),
trailing_slash: config.kit.trailingSlash
});
{
getClientAddress: () => {
const { remoteAddress } = req.socket;
if (remoteAddress) return remoteAddress;
throw new Error('Could not determine clientAddress');
Comment thread
Conduitry marked this conversation as resolved.
}
}
);

if (rendered) {
setResponse(res, rendered);
Expand Down
11 changes: 10 additions & 1 deletion packages/kit/src/core/preview/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,16 @@ export async function preview({ port, host, config, https: use_https = false })
return res.end(err.reason || 'Invalid request body');
}

setResponse(res, await server.respond(request));
setResponse(
res,
await server.respond(request, {
getClientAddress: () => {
const { remoteAddress } = req.socket;
if (remoteAddress) return remoteAddress;
throw new Error('Could not determine clientAddress');
Comment thread
Conduitry marked this conversation as resolved.
}
})
);
}
]);

Expand Down
13 changes: 8 additions & 5 deletions packages/kit/src/runtime/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const DATA_SUFFIX = '/__data.json';
const default_transform = ({ html }) => html;

/** @type {import('types').Respond} */
export async function respond(request, options, state = {}) {
export async function respond(request, options, state) {
const url = new URL(request.url);

const normalized = normalize_path(url.pathname, options.trailing_slash);
Expand Down Expand Up @@ -53,11 +53,14 @@ export async function respond(request, options, state = {}) {

/** @type {import('types').RequestEvent} */
const event = {
request,
url,
params: {},
get clientAddress() {
return (event.clientAddress = state.getClientAddress());
},
locals: {},
platform: state.platform
params: {},
platform: state.platform,
request,
url
};

// TODO remove this for 1.0
Expand Down
1 change: 1 addition & 0 deletions packages/kit/src/runtime/server/page/load_node.js
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ export async function load_node({

response = await respond(new Request(new URL(requested, event.url).href, opts), options, {
fetched: requested,
getClientAddress: state.getClientAddress,
initiator: route
});

Expand Down
7 changes: 4 additions & 3 deletions packages/kit/types/internal.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export interface Hooks {
export class InternalServer extends Server {
respond(
request: Request,
options?: RequestOptions & {
options: RequestOptions & {
prerender?: PrerenderOptions;
}
): Promise<Response>;
Expand Down Expand Up @@ -164,7 +164,7 @@ export type RecursiveRequired<T> = {
export type RequiredResolveOptions = Required<ResolveOptions>;

export interface Respond {
(request: Request, options: SSROptions, state?: SSRState): Promise<Response>;
(request: Request, options: SSROptions, state: SSRState): Promise<Response>;
}

export type RouteData = PageData | EndpointData;
Expand Down Expand Up @@ -302,11 +302,12 @@ export interface SSRPagePart {
export type SSRRoute = SSREndpoint | SSRPage;

export interface SSRState {
fallback?: string;
fetched?: string;
getClientAddress: () => string;
initiator?: SSRPage | null;
platform?: any;
prerender?: PrerenderOptions;
fallback?: string;
}

export type StrictBody = string | Uint8Array;
Expand Down
8 changes: 5 additions & 3 deletions packages/kit/types/private.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,14 +234,16 @@ export interface PrerenderErrorHandler {
export type PrerenderOnErrorValue = 'fail' | 'continue' | PrerenderErrorHandler;

export interface RequestEvent<Params = Record<string, string>> {
request: Request;
url: URL;
params: Params;
clientAddress: string;
locals: App.Locals;
params: Params;
platform: Readonly<App.Platform>;
request: Request;
url: URL;
}

export interface RequestOptions {
getClientAddress: () => string;
platform?: App.Platform;
}

Expand Down