Skip to content

Commit

Permalink
feat: prefer using x-forwarded-for as clientAddress (#11101)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>

* Update .changeset/healthy-planets-dream.md

Co-authored-by: Emanuele Stoppa <[email protected]>

* Apply suggestions from code review

---------

Co-authored-by: Emanuele Stoppa <[email protected]>
  • Loading branch information
linguofeng and ematipico authored May 22, 2024
1 parent 2d4c8fa commit a6916e4
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 1 deletion.
7 changes: 7 additions & 0 deletions .changeset/healthy-planets-dream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"astro": minor
---

Updates Astro's code for adapters to use the header `x-forwarded-for` to initialize the `clientAddress`.

To take advantage of the new change, integration authors must upgrade the version of Astro in their adapter `peerDependencies` to `4.9.0`.
6 changes: 5 additions & 1 deletion packages/astro/src/core/app/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,11 @@ export class NodeApp extends App {
Object.assign(options, makeRequestBody(req));
}
const request = new Request(url, options);
if (req.socket?.remoteAddress) {

const clientIp = req.headers['x-forwarded-for'];
if (clientIp) {
Reflect.set(request, clientAddressSymbol, clientIp);
} else if (req.socket?.remoteAddress) {
Reflect.set(request, clientAddressSymbol, req.socket.remoteAddress);
}
return request;
Expand Down
27 changes: 27 additions & 0 deletions packages/astro/test/client-address-node.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import * as assert from 'node:assert/strict';
import { describe, it } from 'node:test';
import * as cheerio from 'cheerio';
import { loadFixture } from './test-utils.js';
import { createRequestAndResponse } from './units/test-utils.js';

describe('NodeClientAddress', () => {
it('clientAddress is 1.1.1.1', async () => {
const fixture = await loadFixture({
root: './fixtures/client-address-node/',
});
await fixture.build();
const handle = await fixture.loadNodeAdapterHandler();
const { req, res, text } = createRequestAndResponse({
method: 'GET',
url: '/',
headers: {
'x-forwarded-for': '1.1.1.1',
},
});
handle(req, res);
const html = await text();
const $ = cheerio.load(html);
assert.equal(res.statusCode, 200);
assert.equal($('#address').text(), '1.1.1.1');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import node from '@astrojs/node';
import { defineConfig } from 'astro/config';

// https://astro.build/config
export default defineConfig({
output: 'server',
adapter: node({ mode: 'middleware' }),
});
9 changes: 9 additions & 0 deletions packages/astro/test/fixtures/client-address-node/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "@test/client-address-node",
"version": "0.0.0",
"private": true,
"dependencies": {
"@astrojs/node": "workspace:*",
"astro": "workspace:*"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
export const prerender = false;
const address = Astro.clientAddress;
---
<html>
<head>
<title>Astro.clientAddress</title>
</head>
<body>
<h1>Astro.clientAddress</h1>
<div id="address">{ address }</div>
</body>
</html>
8 changes: 8 additions & 0 deletions packages/astro/test/test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ process.env.ASTRO_TELEMETRY_DISABLED = true;
* @typedef {import('../src/core/app/index').App} App
* @typedef {import('../src/cli/check/index').AstroChecker} AstroChecker
* @typedef {import('../src/cli/check/index').CheckPayload} CheckPayload
* @typedef {import('http').IncomingMessage} NodeRequest
* @typedef {import('http').ServerResponse} NodeResponse
*
*
* @typedef {Object} Fixture
Expand All @@ -40,6 +42,7 @@ process.env.ASTRO_TELEMETRY_DISABLED = true;
* @property {typeof preview} preview
* @property {() => Promise<void>} clean
* @property {() => Promise<App>} loadTestAdapterApp
* @property {() => Promise<(req: NodeRequest, res: NodeResponse) => void>} loadNodeAdapterHandler
* @property {() => Promise<void>} onNextChange
* @property {typeof check} check
* @property {typeof sync} sync
Expand Down Expand Up @@ -213,6 +216,11 @@ export async function loadFixture(inlineConfig) {
});
}
},
loadNodeAdapterHandler: async () => {
const url = new URL(`./server/entry.mjs?id=${fixtureId}`, config.outDir);
const { handler } = await import(url);
return handler;
},
loadTestAdapterApp: async (streaming) => {
const url = new URL(`./server/entry.mjs?id=${fixtureId}`, config.outDir);
const { createApp, manifest } = await import(url);
Expand Down
9 changes: 9 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit a6916e4

Please sign in to comment.