Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(middleware): compute client address #12222

Merged
merged 2 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 5 additions & 0 deletions .changeset/slimy-kids-peel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Fixes an issue where the edge middleware couldn't correctly compute the client IP address when calling `ctx.clientAddress()`
12 changes: 9 additions & 3 deletions packages/astro/src/core/middleware/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import { ASTRO_VERSION, clientAddressSymbol, clientLocalsSymbol } from '../constants.js';
import { AstroCookies } from '../cookies/index.js';
import { AstroError, AstroErrorData } from '../errors/index.js';
import { getClientIpAddress } from '../routing/request.js';
import { sequence } from './sequence.js';

function defineMiddleware(fn: MiddlewareHandler) {
Expand Down Expand Up @@ -50,6 +51,7 @@ function createContext({
let preferredLocale: string | undefined = undefined;
let preferredLocaleList: string[] | undefined = undefined;
let currentLocale: string | undefined = undefined;
let clientIpAddress: string | undefined;
const url = new URL(request.url);
const route = url.pathname;

Expand Down Expand Up @@ -85,10 +87,14 @@ function createContext({
},
url,
get clientAddress() {
if (clientAddressSymbol in request) {
return Reflect.get(request, clientAddressSymbol) as string;
if (clientIpAddress) {
return clientIpAddress;
}
throw new AstroError(AstroErrorData.StaticClientAddressNotAvailable);
clientIpAddress = getClientIpAddress(request);
Copy link
Contributor

Choose a reason for hiding this comment

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

I assume this is done here so that we don't need to update each adapter to provide it?

Copy link
Member Author

Choose a reason for hiding this comment

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

Exactly!

if (!clientIpAddress) {
throw new AstroError(AstroErrorData.StaticClientAddressNotAvailable);
}
return clientIpAddress;
},
get locals() {
let locals = Reflect.get(request, clientLocalsSymbol);
Expand Down
20 changes: 20 additions & 0 deletions packages/astro/src/core/routing/request.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Utilities for extracting information from `Request`
*/

// Parses multiple header and returns first value if available.
export function getFirstForwardedValue(multiValueHeader?: string | string[] | null) {
return multiValueHeader
?.toString()
?.split(',')
.map((e) => e.trim())?.[0];
}

/**
* Returns the first value associated to the `x-forwarded-for` header.
*
* @param {Request} request
*/
export function getClientIpAddress(request: Request): string | undefined {
return getFirstForwardedValue(request.headers.get('x-forwarded-for'));
}
19 changes: 19 additions & 0 deletions packages/astro/test/units/routing/api-context.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import assert from 'node:assert/strict';
import { describe, it } from 'node:test';
import { createContext } from '../../../dist/core/middleware/index.js';

describe('createAPIContext', () => {
it('should return the clientAddress', () => {
const request = new Request('http://example.com', {
headers: {
'x-forwarded-for': '192.0.2.43, 172.16.58.3',
},
});

const context = createContext({
request,
});

assert.equal(context.clientAddress, '192.0.2.43');
});
});
Loading