Skip to content

Commit b9611dc

Browse files
authored
Expose request remote IP (#7)
2 parents d40416a + 0e2dd8e commit b9611dc

File tree

6 files changed

+37
-4
lines changed

6 files changed

+37
-4
lines changed

package-lock.json

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"typescript": "^5.8.2"
3636
},
3737
"dependencies": {
38+
"@cldn/ip": "^1.0.3",
3839
"multipart-ts": "^1.3.2"
3940
}
4041
}

src/Request.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import {IPAddress, IPv4, IPv6} from "@cldn/ip";
12
import {Multipart} from "multipart-ts";
23
import http, {OutgoingHttpHeader} from "node:http";
34
import stream from "node:stream";
@@ -26,28 +27,37 @@ export class Request {
2627
*/
2728
public readonly bodyStream: stream.Readable;
2829

30+
/**
31+
* IP address of request sender.
32+
*/
33+
public readonly ip: IPv4 | IPv6;
34+
2935
/**
3036
* Construct a new Request.
3137
* @param method See {@link Request#method}.
3238
* @param url See {@link Request#url}.
3339
* @param headers See {@link Request#headers}.
3440
* @param bodyStream See {@link Request#bodyStream}.
41+
* @param ip See {@link Request#ip}.
3542
*/
3643
protected constructor(
3744
method: Request["method"],
3845
url: Request["url"],
3946
headers: Request["headers"],
4047
bodyStream: Request["bodyStream"],
48+
ip: Request["ip"],
4149
) {
4250
this.method = method;
4351
this.url = url;
4452
this.headers = headers;
4553
this.bodyStream = bodyStream;
54+
this.ip = ip;
4655
}
4756

4857
/**
4958
* Create a new Request from a Node.js incoming HTTP request.
5059
* @throws {@link Request.BadUrlError} If the request URL is invalid.
60+
* @throws {@link Request.SocketClosedError} If the request socket was closed before the request could be handled.
5161
*/
5262
public static incomingMessage(incomingMessage: http.IncomingMessage) {
5363
const auth =
@@ -66,7 +76,11 @@ export class Request {
6676

6777
const headers = Request.headersFromNodeDict(incomingMessage.headers);
6878

69-
return new Request(incomingMessage.method as Request.Method, new URL(url), headers, incomingMessage);
79+
const remoteAddress = incomingMessage.socket.remoteAddress;
80+
if (remoteAddress === undefined)
81+
throw new Request.SocketClosedError();
82+
83+
return new Request(incomingMessage.method as Request.Method, new URL(url), headers, incomingMessage, IPAddress.fromString(remoteAddress));
7084
}
7185

7286
/**
@@ -212,4 +226,13 @@ export namespace Request {
212226
UNLOCK = "UNLOCK",
213227
UNSUBSCRIBE = "UNSUBSCRIBE",
214228
}
229+
230+
/**
231+
* Socket closed by peer.
232+
*/
233+
export class SocketClosedError extends Error {
234+
public constructor() {
235+
super("The socker was closed by the peer.");
236+
}
237+
}
215238
}

src/Server.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ class Server {
4747
this.errors._get(ServerErrorRegistry.ErrorCodes.BAD_URL)._send(res, this);
4848
return;
4949
}
50+
if (e instanceof Request.SocketClosedError)
51+
return;
5052
throw e;
5153
}
5254

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* Auto-generated by generateIndices.sh */
2-
export * from "./Request.js";
32
export * from "./Server.js";
3+
export * from "./Request.js";
44
export * from "./ServerErrorRegistry.js";
55
export * from "./response/index.js";
66
export * from "./routing/index.js";

src/response/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* Auto-generated by generateIndices.sh */
2-
export * from "./Response.js";
32
export * from "./EmptyResponse.js";
43
export * from "./BufferResponse.js";
5-
export * from "./JsonResponse.js";
64
export * from "./TextResponse.js";
5+
export * from "./JsonResponse.js";
6+
export * from "./Response.js";

0 commit comments

Comments
 (0)