From abb4fbd01f9f49cd73f7f514fa59ad513ca1a065 Mon Sep 17 00:00:00 2001 From: Michael SCHAL Date: Mon, 8 Dec 2025 21:14:17 +0100 Subject: [PATCH] feat: Implement core server infrastructure with API routing, static file serving, and security middleware. --- bin/server.dart | 36 +++++++++++++++++++++++++++++++++++- verify_cache_log.txt | Bin 0 -> 83904 bytes 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 verify_cache_log.txt diff --git a/bin/server.dart b/bin/server.dart index 409f600..dccaf00 100644 --- a/bin/server.dart +++ b/bin/server.dart @@ -83,12 +83,37 @@ void main(List args) async { }),); // Create handlers - final staticHandler = createStaticHandler( + // Create static handler + final baseStaticHandler = createStaticHandler( webPath, defaultDocument: 'index.html', listDirectories: false, ); + // Wrap static handler to enforce cache policies + Handler staticHandler = (Request request) async { + final response = await baseStaticHandler(request); + + // Disable cache for entry points to ensure updates are seen immediately + final path = request.url.path; + if (path.isEmpty || + path == 'index.html' || + path == 'flutter_service_worker.js' || + path.endsWith('.json')) { // version.json etc + return response.change(headers: { + 'Cache-Control': 'no-store, no-cache, must-revalidate, max-age=0', + 'Pragma': 'no-cache', + 'Expires': '0', + }); + } + + // Allow aggressive caching for hashed assets (images, compiled JS) + // Flutter web builds usually hash main.dart.js, but let's be safe with 1 day + return response.change(headers: { + 'Cache-Control': 'public, max-age=86400', + }); + }; + // Main handler with API proxy and FFmpeg streaming final handler = Cascade() .add(_createApiHandler(apiRouter)) @@ -285,6 +310,15 @@ Handler _createXtreamProxyHandler() { headers: { 'content-type': response.headers['content-type'] ?? 'application/json', 'access-control-allow-origin': '*', + // Forward cache headers from upstream + if (response.headers.containsKey('cache-control')) + 'cache-control': response.headers['cache-control']!, + if (response.headers.containsKey('expires')) + 'expires': response.headers['expires']!, + if (response.headers.containsKey('etag')) + 'etag': response.headers['etag']!, + if (response.headers.containsKey('last-modified')) + 'last-modified': response.headers['last-modified']!, }, ); } catch (e, stackTrace) { diff --git a/verify_cache_log.txt b/verify_cache_log.txt new file mode 100644 index 0000000000000000000000000000000000000000..ee50991dc2018b5c294ba5a1f675738dffae3b47 GIT binary patch literal 83904 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