From bc16c7421d338e2406aff3b7ca2a5937bc0917ff Mon Sep 17 00:00:00 2001 From: Eric Quaintance Date: Sat, 7 Feb 2026 16:50:26 -0500 Subject: [PATCH 1/2] Fixed: Use FlareSolverr response body instead of re-requesting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After FlareSolverr solves a Cloudflare challenge, Prowlarr discards the response body and makes a second HTTP request using only the returned cookies. This fails because Cloudflare's cf_clearance cookie is bound to the solver's TLS fingerprint, which .NET's HttpClient cannot replicate. Use the solved HTML body from FlareSolverr directly when available, falling back to the cookie-based retry only if no body was returned. Also fix the error status code reference (response → flaresolverrResponse). Fixes #2561 --- .../IndexerProxies/FlareSolverr/FlareSolverr.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs index 5107bf151..62efabf0f 100644 --- a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs +++ b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs @@ -58,7 +58,7 @@ public override HttpResponse PostResponse(HttpResponse response) if (flaresolverrResponse.StatusCode != HttpStatusCode.OK && flaresolverrResponse.StatusCode != HttpStatusCode.InternalServerError) { - throw new FlareSolverrException("HTTP StatusCode not 200 or 500. Status is :" + response.StatusCode); + throw new FlareSolverrException("HTTP StatusCode not 200 or 500. Status is :" + flaresolverrResponse.StatusCode); } var result = JsonConvert.DeserializeObject(flaresolverrResponse.Content); @@ -71,7 +71,20 @@ public override HttpResponse PostResponse(HttpResponse response) InjectCookies(newRequest, result); - //Request again with User-Agent and Cookies from Flaresolverr + // Use FlareSolverr's response body directly — a second HTTP request + // gets 403'd because cf_clearance is bound to the solver's TLS fingerprint + if (result.Solution.Response.IsNotNullOrWhiteSpace()) + { + return new HttpResponse( + response.Request, + response.Headers, + response.Cookies, + result.Solution.Response, + response.ElapsedTime, + HttpStatusCode.OK); + } + + // Fallback: if FlareSolverr returned no body, try cookies (original behavior) var finalResponse = _httpClient.Execute(newRequest); return finalResponse; From a65ed5a30a36343d56bb53b2c7b7a43203e2d2e3 Mon Sep 17 00:00:00 2001 From: Eric Quaintance Date: Thu, 19 Mar 2026 18:12:46 -0400 Subject: [PATCH 2/2] Add temporary debug logging to FlareSolverr proxy flow Co-Authored-By: Claude Opus 4.6 (1M context) --- .../IndexerProxies/FlareSolverr/FlareSolverr.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs index 62efabf0f..ab3ce017b 100644 --- a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs +++ b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs @@ -63,6 +63,10 @@ public override HttpResponse PostResponse(HttpResponse response) var result = JsonConvert.DeserializeObject(flaresolverrResponse.Content); + _logger.Debug("FlareSolverr response status: {0}, message: {1}", result.Status, result.Message); + _logger.Debug("FlareSolverr solution has response body: {0} (length: {1})", result.Solution.Response.IsNotNullOrWhiteSpace(), result.Solution.Response?.Length ?? 0); + _logger.Debug("FlareSolverr returned {0} cookies, UA: {1}", result.Solution.Cookies?.Length ?? 0, result.Solution.UserAgent); + var newRequest = response.Request; //Cache the user-agent so we can inject it in next request to avoid re-solve @@ -75,6 +79,7 @@ public override HttpResponse PostResponse(HttpResponse response) // gets 403'd because cf_clearance is bound to the solver's TLS fingerprint if (result.Solution.Response.IsNotNullOrWhiteSpace()) { + _logger.Debug("Using FlareSolverr response body directly (skipping cookie retry)"); return new HttpResponse( response.Request, response.Headers, @@ -85,7 +90,9 @@ public override HttpResponse PostResponse(HttpResponse response) } // Fallback: if FlareSolverr returned no body, try cookies (original behavior) + _logger.Debug("Attempting cookie-based retry for {0}", newRequest.Url); var finalResponse = _httpClient.Execute(newRequest); + _logger.Debug("Cookie retry response: {0} (CF protected: {1})", finalResponse.StatusCode, CloudFlareDetectionService.IsCloudflareProtected(finalResponse)); return finalResponse; }