Skip to content

Commit fb55695

Browse files
authoredOct 14, 2024··
fix(middleware): compute client address (#12222)
* fix(middleware): compute client address * add unit test
1 parent d6f03e4 commit fb55695

File tree

4 files changed

+53
-3
lines changed

4 files changed

+53
-3
lines changed
 

‎.changeset/slimy-kids-peel.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'astro': patch
3+
---
4+
5+
Fixes an issue where the edge middleware couldn't correctly compute the client IP address when calling `ctx.clientAddress()`

‎packages/astro/src/core/middleware/index.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
import { ASTRO_VERSION, clientAddressSymbol, clientLocalsSymbol } from '../constants.js';
99
import { AstroCookies } from '../cookies/index.js';
1010
import { AstroError, AstroErrorData } from '../errors/index.js';
11+
import { getClientIpAddress } from '../routing/request.js';
1112
import { sequence } from './sequence.js';
1213

1314
function defineMiddleware(fn: MiddlewareHandler) {
@@ -50,6 +51,7 @@ function createContext({
5051
let preferredLocale: string | undefined = undefined;
5152
let preferredLocaleList: string[] | undefined = undefined;
5253
let currentLocale: string | undefined = undefined;
54+
let clientIpAddress: string | undefined;
5355
const url = new URL(request.url);
5456
const route = url.pathname;
5557

@@ -85,10 +87,14 @@ function createContext({
8587
},
8688
url,
8789
get clientAddress() {
88-
if (clientAddressSymbol in request) {
89-
return Reflect.get(request, clientAddressSymbol) as string;
90+
if (clientIpAddress) {
91+
return clientIpAddress;
9092
}
91-
throw new AstroError(AstroErrorData.StaticClientAddressNotAvailable);
93+
clientIpAddress = getClientIpAddress(request);
94+
if (!clientIpAddress) {
95+
throw new AstroError(AstroErrorData.StaticClientAddressNotAvailable);
96+
}
97+
return clientIpAddress;
9298
},
9399
get locals() {
94100
let locals = Reflect.get(request, clientLocalsSymbol);
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* Utilities for extracting information from `Request`
3+
*/
4+
5+
// Parses multiple header and returns first value if available.
6+
export function getFirstForwardedValue(multiValueHeader?: string | string[] | null) {
7+
return multiValueHeader
8+
?.toString()
9+
?.split(',')
10+
.map((e) => e.trim())?.[0];
11+
}
12+
13+
/**
14+
* Returns the first value associated to the `x-forwarded-for` header.
15+
*
16+
* @param {Request} request
17+
*/
18+
export function getClientIpAddress(request: Request): string | undefined {
19+
return getFirstForwardedValue(request.headers.get('x-forwarded-for'));
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import assert from 'node:assert/strict';
2+
import { describe, it } from 'node:test';
3+
import { createContext } from '../../../dist/core/middleware/index.js';
4+
5+
describe('createAPIContext', () => {
6+
it('should return the clientAddress', () => {
7+
const request = new Request('http://example.com', {
8+
headers: {
9+
'x-forwarded-for': '192.0.2.43, 172.16.58.3',
10+
},
11+
});
12+
13+
const context = createContext({
14+
request,
15+
});
16+
17+
assert.equal(context.clientAddress, '192.0.2.43');
18+
});
19+
});

0 commit comments

Comments
 (0)
Please sign in to comment.