Skip to content

Commit a6916e4

Browse files
linguofengematipico
andauthoredMay 22, 2024··
feat: prefer using x-forwarded-for as clientAddress (#11101)
* feat: change node clientAddress use x-forwarded-for when ``` adapter: node({ mode: 'standalone', }) ``` * feat: prefer using x-forwarded-for as clientAddress * Update .changeset/healthy-planets-dream.md Co-authored-by: Emanuele Stoppa <my.burning@gmail.com> * Update .changeset/healthy-planets-dream.md Co-authored-by: Emanuele Stoppa <my.burning@gmail.com> * Apply suggestions from code review --------- Co-authored-by: Emanuele Stoppa <my.burning@gmail.com>
1 parent 2d4c8fa commit a6916e4

File tree

8 files changed

+86
-1
lines changed

8 files changed

+86
-1
lines changed
 

‎.changeset/healthy-planets-dream.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"astro": minor
3+
---
4+
5+
Updates Astro's code for adapters to use the header `x-forwarded-for` to initialize the `clientAddress`.
6+
7+
To take advantage of the new change, integration authors must upgrade the version of Astro in their adapter `peerDependencies` to `4.9.0`.

‎packages/astro/src/core/app/node.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,11 @@ export class NodeApp extends App {
8181
Object.assign(options, makeRequestBody(req));
8282
}
8383
const request = new Request(url, options);
84-
if (req.socket?.remoteAddress) {
84+
85+
const clientIp = req.headers['x-forwarded-for'];
86+
if (clientIp) {
87+
Reflect.set(request, clientAddressSymbol, clientIp);
88+
} else if (req.socket?.remoteAddress) {
8589
Reflect.set(request, clientAddressSymbol, req.socket.remoteAddress);
8690
}
8791
return request;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import * as assert from 'node:assert/strict';
2+
import { describe, it } from 'node:test';
3+
import * as cheerio from 'cheerio';
4+
import { loadFixture } from './test-utils.js';
5+
import { createRequestAndResponse } from './units/test-utils.js';
6+
7+
describe('NodeClientAddress', () => {
8+
it('clientAddress is 1.1.1.1', async () => {
9+
const fixture = await loadFixture({
10+
root: './fixtures/client-address-node/',
11+
});
12+
await fixture.build();
13+
const handle = await fixture.loadNodeAdapterHandler();
14+
const { req, res, text } = createRequestAndResponse({
15+
method: 'GET',
16+
url: '/',
17+
headers: {
18+
'x-forwarded-for': '1.1.1.1',
19+
},
20+
});
21+
handle(req, res);
22+
const html = await text();
23+
const $ = cheerio.load(html);
24+
assert.equal(res.statusCode, 200);
25+
assert.equal($('#address').text(), '1.1.1.1');
26+
});
27+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import node from '@astrojs/node';
2+
import { defineConfig } from 'astro/config';
3+
4+
// https://astro.build/config
5+
export default defineConfig({
6+
output: 'server',
7+
adapter: node({ mode: 'middleware' }),
8+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"name": "@test/client-address-node",
3+
"version": "0.0.0",
4+
"private": true,
5+
"dependencies": {
6+
"@astrojs/node": "workspace:*",
7+
"astro": "workspace:*"
8+
}
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
export const prerender = false;
3+
const address = Astro.clientAddress;
4+
---
5+
<html>
6+
<head>
7+
<title>Astro.clientAddress</title>
8+
</head>
9+
<body>
10+
<h1>Astro.clientAddress</h1>
11+
<div id="address">{ address }</div>
12+
</body>
13+
</html>

‎packages/astro/test/test-utils.js

+8
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ process.env.ASTRO_TELEMETRY_DISABLED = true;
2525
* @typedef {import('../src/core/app/index').App} App
2626
* @typedef {import('../src/cli/check/index').AstroChecker} AstroChecker
2727
* @typedef {import('../src/cli/check/index').CheckPayload} CheckPayload
28+
* @typedef {import('http').IncomingMessage} NodeRequest
29+
* @typedef {import('http').ServerResponse} NodeResponse
2830
*
2931
*
3032
* @typedef {Object} Fixture
@@ -40,6 +42,7 @@ process.env.ASTRO_TELEMETRY_DISABLED = true;
4042
* @property {typeof preview} preview
4143
* @property {() => Promise<void>} clean
4244
* @property {() => Promise<App>} loadTestAdapterApp
45+
* @property {() => Promise<(req: NodeRequest, res: NodeResponse) => void>} loadNodeAdapterHandler
4346
* @property {() => Promise<void>} onNextChange
4447
* @property {typeof check} check
4548
* @property {typeof sync} sync
@@ -213,6 +216,11 @@ export async function loadFixture(inlineConfig) {
213216
});
214217
}
215218
},
219+
loadNodeAdapterHandler: async () => {
220+
const url = new URL(`./server/entry.mjs?id=${fixtureId}`, config.outDir);
221+
const { handler } = await import(url);
222+
return handler;
223+
},
216224
loadTestAdapterApp: async (streaming) => {
217225
const url = new URL(`./server/entry.mjs?id=${fixtureId}`, config.outDir);
218226
const { createApp, manifest } = await import(url);

‎pnpm-lock.yaml

+9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
Please sign in to comment.