From a2db43d2356c7bdc5d7ec526cc0487187e9f9b71 Mon Sep 17 00:00:00 2001 From: metoli86 Date: Thu, 16 Jul 2026 01:35:10 +0300 Subject: [PATCH] feat: enable CORS headers in the HTTP API (#2594) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #2558. Enables the Arduino WebServer's built-in CORS support (`enableCORS(true)`), which adds `Access-Control-Allow-Origin/Methods/Headers: *` to every response, and answers preflight `OPTIONS` requests with `204` in `handleNotFound()` — routes are registered per-method, so OPTIONS always lands there. The AP-mode captive-portal redirect is untouched (the OPTIONS check runs before it, and browsers don't send preflights for captive-portal probes). This lets web-based clients and PWAs served from other origins call the JSON API (`/api/status`, `/api/files`, `/api/settings`, ...) directly from the browser. Overhead is three static response headers; no behavior change for the built-in web UI. Note: not yet tested on hardware. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: metoli Co-authored-by: Claude Fable 5 --- src/network/CrossPointWebServer.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/network/CrossPointWebServer.cpp b/src/network/CrossPointWebServer.cpp index 5624b76a..a6b2e103 100644 --- a/src/network/CrossPointWebServer.cpp +++ b/src/network/CrossPointWebServer.cpp @@ -132,6 +132,11 @@ void CrossPointWebServer::begin() { return; } + // Add Access-Control-Allow-* headers to every response so web-based clients + // and PWAs on other origins can use the HTTP API. Preflight OPTIONS requests + // are answered in handleNotFound(). + server->enableCORS(true); + // Setup routes LOG_DBG("WEB", "Setting up routes..."); server->on("/", HTTP_GET, [this] { handleRoot(); }); @@ -353,6 +358,13 @@ void CrossPointWebServer::handleJszip() const { } void CrossPointWebServer::handleNotFound() const { + // CORS preflight: routes are registered per-method, so OPTIONS requests land + // here. The Access-Control-Allow-* headers are added by enableCORS(). + if (server->method() == HTTP_OPTIONS) { + server->send(204, "text/plain", ""); + return; + } + // in AP mode, redirect unmatched browser/captive-portal requests to "/" so the OS auto-opens the browser // API requests (/api/*) still return 404 so XHR errors surface correctly // see https://en.wikipedia.org/wiki/Captive_portal#Detection