From a1e04fcab899f1243984e93bdef797f5eda66024 Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Tue, 8 Oct 2024 19:17:08 -0400 Subject: [PATCH 1/3] [Auth] Use async flush method to get header value --- .../Sources/Swift/Backend/AuthBackend.swift | 17 ++++++++--------- .../AuthBackendRPCImplementationTests.swift | 4 ++++ FirebaseCore/Extension/FIRHeartbeatLogger.h | 13 +++++++++---- FirebaseCore/Sources/FIRHeartbeatLogger.m | 7 +++++++ 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift b/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift index 84bf5ec55c9..3682176fd93 100644 --- a/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift +++ b/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift @@ -98,6 +98,11 @@ class AuthBackend { class func request(withURL url: URL, contentType: String, requestConfiguration: AuthRequestConfiguration) async -> URLRequest { + // Kick off tasks for the async header values. + async let heartbeatsHeaderValue = requestConfiguration.heartbeatLogger?.asyncHeaderValue!() + async let appCheckTokenHeaderValue = requestConfiguration.appCheck? + .getToken(forcingRefresh: true) + var request = URLRequest(url: url) request.setValue(contentType, forHTTPHeaderField: "Content-Type") let additionalFrameworkMarker = requestConfiguration @@ -106,13 +111,6 @@ class AuthBackend { request.setValue(clientVersion, forHTTPHeaderField: "X-Client-Version") request.setValue(Bundle.main.bundleIdentifier, forHTTPHeaderField: "X-Ios-Bundle-Identifier") request.setValue(requestConfiguration.appID, forHTTPHeaderField: "X-Firebase-GMPID") - if let heartbeatLogger = requestConfiguration.heartbeatLogger { - // The below call synchronously dispatches to a queue. To avoid blocking - // the shared concurrency queue, `async let` will spawn the process on - // a separate thread. - async let heartbeatsHeaderValue = heartbeatLogger.headerValue() - await request.setValue(heartbeatsHeaderValue, forHTTPHeaderField: "X-Firebase-Client") - } request.httpMethod = requestConfiguration.httpMethod let preferredLocalizations = Bundle.main.preferredLocalizations if preferredLocalizations.count > 0 { @@ -122,8 +120,9 @@ class AuthBackend { languageCode.count > 0 { request.setValue(languageCode, forHTTPHeaderField: "X-Firebase-Locale") } - if let appCheck = requestConfiguration.appCheck { - let tokenResult = await appCheck.getToken(forcingRefresh: false) + // Wait for the async header values. + await request.setValue(heartbeatsHeaderValue, forHTTPHeaderField: "X-Firebase-Client") + await appCheckTokenHeaderValue.map { tokenResult in if let error = tokenResult.error { AuthLog.logWarning(code: "I-AUT000018", message: "Error getting App Check token; using placeholder " + diff --git a/FirebaseAuth/Tests/Unit/AuthBackendRPCImplementationTests.swift b/FirebaseAuth/Tests/Unit/AuthBackendRPCImplementationTests.swift index 436d777ca10..92b827de861 100644 --- a/FirebaseAuth/Tests/Unit/AuthBackendRPCImplementationTests.swift +++ b/FirebaseAuth/Tests/Unit/AuthBackendRPCImplementationTests.swift @@ -534,6 +534,10 @@ class AuthBackendRPCImplementationTests: RPCBaseTests { #if COCOAPODS || SWIFT_PACKAGE private class FakeHeartbeatLogger: NSObject, FIRHeartbeatLoggerProtocol { + func asyncHeaderValue() async -> String? { + headerValue() + } + func headerValue() -> String? { let payload = flushHeartbeatsIntoPayload() guard !payload.isEmpty else { diff --git a/FirebaseCore/Extension/FIRHeartbeatLogger.h b/FirebaseCore/Extension/FIRHeartbeatLogger.h index 65793b3db75..b86ddad3b3c 100644 --- a/FirebaseCore/Extension/FIRHeartbeatLogger.h +++ b/FirebaseCore/Extension/FIRHeartbeatLogger.h @@ -35,13 +35,18 @@ typedef NS_ENUM(NSInteger, FIRDailyHeartbeatCode) { /// Asynchronously logs a heartbeat. - (void)log; +/// Gets the heartbeat code for today. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + #ifndef FIREBASE_BUILD_CMAKE -/// Return the headerValue for the HeartbeatLogger. +/// Return the header value for the heartbeat logger. - (NSString *_Nullable)headerValue; -#endif // FIREBASE_BUILD_CMAKE -/// Gets the heartbeat code for today. -- (FIRDailyHeartbeatCode)heartbeatCodeForToday; +@optional +/// Returns the header value for the heartbeat logger via the given completion handler.. +- (void)asyncHeaderValueWithCompletionHandler:(void (^)(NSString *_Nullable))completionHandler + API_AVAILABLE(ios(13.0), macosx(10.15), macCatalyst(13.0), tvos(13.0), watchos(6.0)); +#endif // FIREBASE_BUILD_CMAKE @end diff --git a/FirebaseCore/Sources/FIRHeartbeatLogger.m b/FirebaseCore/Sources/FIRHeartbeatLogger.m index a5a2fcafe79..d1c77ee4f2f 100644 --- a/FirebaseCore/Sources/FIRHeartbeatLogger.m +++ b/FirebaseCore/Sources/FIRHeartbeatLogger.m @@ -74,6 +74,13 @@ - (NSString *_Nullable)headerValue { return FIRHeaderValueFromHeartbeatsPayload([self flushHeartbeatsIntoPayload]); } +- (void)asyncHeaderValueWithCompletionHandler:(void (^)(NSString *_Nullable))completionHandler + API_AVAILABLE(ios(13.0), macosx(10.15), macCatalyst(13.0), tvos(13.0), watchos(6.0)) { + [self flushHeartbeatsIntoPayloadWithCompletionHandler:^(FIRHeartbeatsPayload *payload) { + completionHandler(FIRHeaderValueFromHeartbeatsPayload(payload)); + }]; +} + - (FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload { FIRHeartbeatsPayload *payload = [_heartbeatController flush]; return payload; From a44d799bf2411293dec39b44e569106ae06ea54c Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Wed, 9 Oct 2024 10:57:11 -0400 Subject: [PATCH 2/3] review --- FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift b/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift index 3682176fd93..0063e14898b 100644 --- a/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift +++ b/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift @@ -122,7 +122,7 @@ class AuthBackend { } // Wait for the async header values. await request.setValue(heartbeatsHeaderValue, forHTTPHeaderField: "X-Firebase-Client") - await appCheckTokenHeaderValue.map { tokenResult in + if let tokenResult = await appCheckTokenHeaderValue { if let error = tokenResult.error { AuthLog.logWarning(code: "I-AUT000018", message: "Error getting App Check token; using placeholder " + From d2b64aba725fe133a53a014f02e763b5834ecf6d Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Wed, 9 Oct 2024 11:01:31 -0400 Subject: [PATCH 3/3] Remove optional protocol method, mark sync headerValue unavailable in Swift --- FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift | 2 +- .../Tests/Unit/AuthBackendRPCImplementationTests.swift | 4 ---- FirebaseCore/Extension/FIRHeartbeatLogger.h | 8 ++++---- .../Source/Tests/Unit/FIRInstallationsAPIServiceTests.m | 5 +++++ .../Tests/UnitTests/FIRMessagingTokenOperationsTest.m | 5 +++++ 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift b/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift index 0063e14898b..24726262840 100644 --- a/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift +++ b/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift @@ -99,7 +99,7 @@ class AuthBackend { contentType: String, requestConfiguration: AuthRequestConfiguration) async -> URLRequest { // Kick off tasks for the async header values. - async let heartbeatsHeaderValue = requestConfiguration.heartbeatLogger?.asyncHeaderValue!() + async let heartbeatsHeaderValue = requestConfiguration.heartbeatLogger?.asyncHeaderValue() async let appCheckTokenHeaderValue = requestConfiguration.appCheck? .getToken(forcingRefresh: true) diff --git a/FirebaseAuth/Tests/Unit/AuthBackendRPCImplementationTests.swift b/FirebaseAuth/Tests/Unit/AuthBackendRPCImplementationTests.swift index 92b827de861..754fa761a54 100644 --- a/FirebaseAuth/Tests/Unit/AuthBackendRPCImplementationTests.swift +++ b/FirebaseAuth/Tests/Unit/AuthBackendRPCImplementationTests.swift @@ -535,10 +535,6 @@ class AuthBackendRPCImplementationTests: RPCBaseTests { #if COCOAPODS || SWIFT_PACKAGE private class FakeHeartbeatLogger: NSObject, FIRHeartbeatLoggerProtocol { func asyncHeaderValue() async -> String? { - headerValue() - } - - func headerValue() -> String? { let payload = flushHeartbeatsIntoPayload() guard !payload.isEmpty else { return nil diff --git a/FirebaseCore/Extension/FIRHeartbeatLogger.h b/FirebaseCore/Extension/FIRHeartbeatLogger.h index b86ddad3b3c..12986f8ec97 100644 --- a/FirebaseCore/Extension/FIRHeartbeatLogger.h +++ b/FirebaseCore/Extension/FIRHeartbeatLogger.h @@ -39,13 +39,13 @@ typedef NS_ENUM(NSInteger, FIRDailyHeartbeatCode) { - (FIRDailyHeartbeatCode)heartbeatCodeForToday; #ifndef FIREBASE_BUILD_CMAKE -/// Return the header value for the heartbeat logger. -- (NSString *_Nullable)headerValue; - -@optional /// Returns the header value for the heartbeat logger via the given completion handler.. - (void)asyncHeaderValueWithCompletionHandler:(void (^)(NSString *_Nullable))completionHandler API_AVAILABLE(ios(13.0), macosx(10.15), macCatalyst(13.0), tvos(13.0), watchos(6.0)); + +/// Return the header value for the heartbeat logger. +- (NSString *_Nullable) + headerValue NS_SWIFT_UNAVAILABLE("Use `asyncHeaderValue() async -> String?` instead."); #endif // FIREBASE_BUILD_CMAKE @end diff --git a/FirebaseInstallations/Source/Tests/Unit/FIRInstallationsAPIServiceTests.m b/FirebaseInstallations/Source/Tests/Unit/FIRInstallationsAPIServiceTests.m index f54f1ea809d..93831313c45 100644 --- a/FirebaseInstallations/Source/Tests/Unit/FIRInstallationsAPIServiceTests.m +++ b/FirebaseInstallations/Source/Tests/Unit/FIRInstallationsAPIServiceTests.m @@ -69,6 +69,11 @@ - (NSString *_Nullable)headerValue { return FIRHeaderValueFromHeartbeatsPayload([self flushHeartbeatsIntoPayload]); } +- (void)asyncHeaderValueWithCompletionHandler: + (nonnull void (^)(NSString *_Nullable))completionHandler { + [self doesNotRecognizeSelector:_cmd]; +} + @end #pragma mark - FIRInstallationsAPIService + Internal diff --git a/FirebaseMessaging/Tests/UnitTests/FIRMessagingTokenOperationsTest.m b/FirebaseMessaging/Tests/UnitTests/FIRMessagingTokenOperationsTest.m index 911c2a870d3..0459a8d3e38 100644 --- a/FirebaseMessaging/Tests/UnitTests/FIRMessagingTokenOperationsTest.m +++ b/FirebaseMessaging/Tests/UnitTests/FIRMessagingTokenOperationsTest.m @@ -102,6 +102,11 @@ - (NSString *_Nullable)headerValue { return @"unimplemented"; } +- (void)asyncHeaderValueWithCompletionHandler: + (nonnull void (^)(NSString *_Nullable))completionHandler { + [self doesNotRecognizeSelector:_cmd]; +} + @end #pragma mark - FIRMessagingTokenOperationsTest