]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/commitdiff
feat(ui-server): add HTTP body size and rate limiting
authorJérôme Benoit <jerome.benoit@sap.com>
Wed, 11 Feb 2026 15:46:57 +0000 (16:46 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Thu, 12 Feb 2026 17:49:18 +0000 (18:49 +0100)
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
src/charging-station/ui-server/UIHttpServer.ts

index 4b122606b9712879deedb134a9699361e83af45b..a86f72185e96b9d52adf90e606ead080de7b3d9c 100644 (file)
@@ -23,10 +23,19 @@ import {
   logPrefix,
 } from '../../utils/index.js'
 import { AbstractUIServer } from './AbstractUIServer.js'
+import {
+  createBodySizeLimiter,
+  createRateLimiter,
+  DEFAULT_MAX_BODY_SIZE,
+  DEFAULT_RATE_LIMIT,
+  DEFAULT_RATE_WINDOW,
+} from './UIServerSecurity.js'
 import { isProtocolAndVersionSupported } from './UIServerUtils.js'
 
 const moduleName = 'UIHttpServer'
 
+const rateLimiter = createRateLimiter(DEFAULT_RATE_LIMIT, DEFAULT_RATE_WINDOW)
+
 enum HttpMethods {
   GET = 'GET',
   PATCH = 'PATCH',
@@ -87,6 +96,20 @@ export class UIHttpServer extends AbstractUIServer {
   }
 
   private requestListener (req: IncomingMessage, res: ServerResponse): void {
+    // Rate limiting check
+    const clientIp = req.socket.remoteAddress ?? 'unknown'
+    if (!rateLimiter(clientIp)) {
+      res
+        .writeHead(StatusCodes.TOO_MANY_REQUESTS, {
+          'Content-Type': 'text/plain',
+          'Retry-After': '60',
+        })
+        .end(`${StatusCodes.TOO_MANY_REQUESTS.toString()} Too Many Requests`)
+      res.destroy()
+      req.destroy()
+      return
+    }
+
     this.authenticate(req, err => {
       if (err != null) {
         res
@@ -144,8 +167,19 @@ export class UIHttpServer extends AbstractUIServer {
         }
 
         const bodyBuffer: Uint8Array[] = []
+        const checkBodySize = createBodySizeLimiter(DEFAULT_MAX_BODY_SIZE)
         req
           .on('data', (chunk: Uint8Array) => {
+            if (!checkBodySize(chunk.length)) {
+              res
+                .writeHead(StatusCodes.REQUEST_TOO_LONG, {
+                  'Content-Type': 'text/plain',
+                })
+                .end(`${StatusCodes.REQUEST_TOO_LONG.toString()} Payload Too Large`)
+              res.destroy()
+              req.destroy()
+              return
+            }
             bodyBuffer.push(chunk)
           })
           .on('end', () => {