From f49985675b25a0c0abbe5a20b36030d5e07f251b Mon Sep 17 00:00:00 2001 From: Calvin-Zikakis <24500770+Calvin-Zikakis@users.noreply.github.com> Date: Tue, 8 Sep 2026 16:36:04 -0700 Subject: [PATCH] Use a separate connection for each GrandSlam request Apple's edge serves at most two requests per connection and 503s everything after that. Signing in takes three requests over one pooled session, so apptokens always fails and the HTML 503 gets parsed as a plist, which is where the 3840 comes from. Same fix as #52, which landed on notarized. This branch still has the bug. --- .../Sources/ALTAppleAPI+Authentication.swift | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/AltSign/Sources/ALTAppleAPI+Authentication.swift b/AltSign/Sources/ALTAppleAPI+Authentication.swift index 2d3e50c2..34149216 100644 --- a/AltSign/Sources/ALTAppleAPI+Authentication.swift +++ b/AltSign/Sources/ALTAppleAPI+Authentication.swift @@ -446,11 +446,28 @@ private extension ALTAppleAPI request.httpBody = bodyData httpHeaders.forEach { request.addValue($0.value, forHTTPHeaderField: $0.key) } - let dataTask = self.session.dataTask(with: request) { (data, response, error) in + // Apple's edge serves at most two requests per connection and answers every request + // after that with a 503 HTML error page. Authenticating takes three requests (init, + // complete, apptokens), so the third one fails whenever they share a pooled connection. + // Give each request its own session, and therefore its own connection. + let configuration = URLSessionConfiguration.ephemeral + configuration.httpMaximumConnectionsPerHost = 1 + let session = URLSession(configuration: configuration) + defer { session.finishTasksAndInvalidate() } + + let dataTask = session.dataTask(with: request) { (data, response, error) in do { guard let data = data else { throw error ?? ALTAppleAPIError.unknown() } + // Surface server errors directly; their HTML bodies are not property lists, and + // parsing them yields a misleading "data couldn't be read" error instead. + if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode >= 500 + { + let message = String(format: NSLocalizedString("Apple's authentication servers returned an error (HTTP %d). This is a problem on Apple's end, not with your Apple ID or password.", comment: ""), httpResponse.statusCode) + throw NSError(domain: ALTUnderlyingAppleAPIErrorDomain, code: httpResponse.statusCode, userInfo: [NSLocalizedDescriptionKey: message]) + } + guard let responseDictionary = try PropertyListSerialization.propertyList(from: data, format: nil) as? [String: Any], let dictionary = responseDictionary["Response"] as? [String: Any], let status = dictionary["Status"] as? [String: Any]