From 03044604fd5a931142b7262847811f33c58615cc Mon Sep 17 00:00:00 2001 From: Daniel Arantes Loverde Date: Tue, 7 Jul 2026 13:15:45 -0300 Subject: [PATCH] Update LCEssentials+API.swift --- .../Classes/LCEssentials+API.swift | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/Sources/LCEssentials/Classes/LCEssentials+API.swift b/Sources/LCEssentials/Classes/LCEssentials+API.swift index ed66071..0b04569 100644 --- a/Sources/LCEssentials/Classes/LCEssentials+API.swift +++ b/Sources/LCEssentials/Classes/LCEssentials+API.swift @@ -194,14 +194,31 @@ public struct API { API.requestLOG(method: method, request: request) } - let session = URLSession( - configuration: .default, - delegate: URLSessionDelegateHandler( - certData: API.certData, - password: API.certPassword - ), - delegateQueue: nil - ) + // Only spin up a dedicated session (with its own @MainActor + // delegate hop for every TLS/auth challenge) when client + // certificate auth is actually configured. Creating one of + // these per request unconditionally — and never invalidating + // it — could stall the async challenge callback waiting on an + // already-busy MainActor, hanging the request indefinitely with + // no timeout or error ever surfacing. The common case (no + // client cert) uses the shared session, which has none of this + // risk and is what URLSession is designed to be reused as. + let usesCertSession = API.certData != nil + let session: URLSession = usesCertSession + ? URLSession( + configuration: .default, + delegate: URLSessionDelegateHandler( + certData: API.certData, + password: API.certPassword + ), + delegateQueue: nil + ) + : URLSession.shared + defer { + if usesCertSession { + session.finishTasksAndInvalidate() + } + } do { let (data, response) = try await session.data(for: request) -- 2.49.1