diff options
author | 2024-10-14 15:35:24 +0100 | |
---|---|---|
committer | 2024-10-14 15:35:24 +0100 | |
commit | fb5569583b11ef585cd0a79e97e7e9dc653f6afa (patch) | |
tree | 8e1f3d38af8b5eee99329efe5ed38728f09ac1e3 | |
parent | d6f03e405d142363083db5f42b836aacdad561b4 (diff) | |
download | astro-fb5569583b11ef585cd0a79e97e7e9dc653f6afa.tar.gz astro-fb5569583b11ef585cd0a79e97e7e9dc653f6afa.tar.zst astro-fb5569583b11ef585cd0a79e97e7e9dc653f6afa.zip |
fix(middleware): compute client address (#12222)
* fix(middleware): compute client address
* add unit test
-rw-r--r-- | .changeset/slimy-kids-peel.md | 5 | ||||
-rw-r--r-- | packages/astro/src/core/middleware/index.ts | 12 | ||||
-rw-r--r-- | packages/astro/src/core/routing/request.ts | 20 | ||||
-rw-r--r-- | packages/astro/test/units/routing/api-context.test.js | 19 |
4 files changed, 53 insertions, 3 deletions
diff --git a/.changeset/slimy-kids-peel.md b/.changeset/slimy-kids-peel.md new file mode 100644 index 000000000..706d01d47 --- /dev/null +++ b/.changeset/slimy-kids-peel.md @@ -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()` diff --git a/packages/astro/src/core/middleware/index.ts b/packages/astro/src/core/middleware/index.ts index 2ca802126..a684d23c0 100644 --- a/packages/astro/src/core/middleware/index.ts +++ b/packages/astro/src/core/middleware/index.ts @@ -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) { @@ -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; @@ -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); + if (!clientIpAddress) { + throw new AstroError(AstroErrorData.StaticClientAddressNotAvailable); + } + return clientIpAddress; }, get locals() { let locals = Reflect.get(request, clientLocalsSymbol); diff --git a/packages/astro/src/core/routing/request.ts b/packages/astro/src/core/routing/request.ts new file mode 100644 index 000000000..f7e917a53 --- /dev/null +++ b/packages/astro/src/core/routing/request.ts @@ -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')); +} diff --git a/packages/astro/test/units/routing/api-context.test.js b/packages/astro/test/units/routing/api-context.test.js new file mode 100644 index 000000000..1e955e50c --- /dev/null +++ b/packages/astro/test/units/routing/api-context.test.js @@ -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'); + }); +}); |