From 36cd85f4d00dad1f1f6bec700282fb52bc533a26 Mon Sep 17 00:00:00 2001 From: Michele Bigi Date: Wed, 26 Aug 2026 01:01:56 +0200 Subject: [PATCH] Fix web radio reconnect busy-loop on non-2xx HTTP status openStream() only established the TCP/TLS connection; it never checked the HTTP status code. A 4xx/5xx response (wrong stream path, station temporarily down, etc.) still returned a valid client handle, so streamWhileEnabled() entered its pump loop, immediately read 0 bytes (no body), and returned -- skipping the kReconnectDelay branch entirely, which only fired when openStream() itself returned nullptr. run()'s outer loop then retried immediately: a full TCP+TLS handshake in a tight loop bounded only by network RTT, not the intended 5s backoff -- observed live at roughly 2 attempts/second. This mattered beyond wasted reconnects: a concurrent full FM band scan (POST /api/tuner/scan/full, which legitimately takes 70-135s) lost its HTTP connection outright while this loop was running, before this fix. After adding the status-code check and routing non-2xx through the same reconnect delay as a failed connection, the same scan completed cleanly twice in a row under the same conditions. Co-Authored-By: Claude Sonnet 5 --- Software/main/web_radio_stream.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Software/main/web_radio_stream.cpp b/Software/main/web_radio_stream.cpp index 3fa874b..ecbe2d3 100644 --- a/Software/main/web_radio_stream.cpp +++ b/Software/main/web_radio_stream.cpp @@ -190,6 +190,25 @@ void streamWhileEnabled(webradio::WebRadioService& service, return; } + // esp_http_client_open() only establishes the TCP/TLS connection; a 4xx/ + // 5xx HTTP response (wrong path, station offline, etc.) still returns a + // valid client handle here. Without this check, such a response reads + // as an empty body -> pumpOneFrame() returns false on its first call -> + // the reconnect delay below is skipped entirely, and run()'s outer loop + // immediately retries: a full TCP+TLS handshake in a tight loop, bounded + // only by network RTT, not kReconnectDelay. Observed live 2026-08-26 at + // roughly 2 attempts/second against a misconfigured URL, competing for + // CPU/heap with an unrelated concurrent FM scan on the same board. + const int status = esp_http_client_get_status_code(client); + if (status < 200 || status >= 300) { + ESP_LOGW(kTag, "stream %s returned HTTP %d, not audio -- backing off", + url.c_str(), status); + esp_http_client_close(client); + esp_http_client_cleanup(client); + vTaskDelay(kReconnectDelay); + return; + } + InputBuffer in; bool loggedFormat = false; while (service.config().enabled