@@ -31,8 +31,7 @@ protocol AuthBackendRPCIssuer: NSObjectProtocol {
3131 /// on the auth global work queue in the future.
3232 func asyncCallToURL< T: AuthRPCRequest > ( with request: T ,
3333 body: Data ? ,
34- contentType: String ,
35- completionHandler: @escaping ( ( Data ? , Error ? ) -> Void ) )
34+ contentType: String ) async -> ( Data ? , Error ? )
3635}
3736
3837@available ( iOS 13 , tvOS 13 , macOS 10 . 15 , macCatalyst 13 , watchOS 7 , * )
@@ -51,20 +50,22 @@ class AuthBackendRPCIssuerImplementation: NSObject, AuthBackendRPCIssuer {
5150
5251 func asyncCallToURL< T: AuthRPCRequest > ( with request: T ,
5352 body: Data ? ,
54- contentType: String ,
55- completionHandler: @escaping ( ( Data ? , Error ? )
56- -> Void ) ) {
53+ contentType: String ) async -> ( Data ? , Error ? ) {
5754 let requestConfiguration = request. requestConfiguration ( )
58- AuthBackend . request ( withURL: request. requestURL ( ) ,
59- contentType: contentType,
60- requestConfiguration: requestConfiguration) { request in
61- let fetcher = self . fetcherService. fetcher ( with: request)
62- if let _ = requestConfiguration. emulatorHostAndPort {
63- fetcher. allowLocalhostRequest = true
64- fetcher. allowedInsecureSchemes = [ " http " ]
55+ let request = await AuthBackend . request ( withURL: request. requestURL ( ) ,
56+ contentType: contentType,
57+ requestConfiguration: requestConfiguration)
58+ let fetcher = fetcherService. fetcher ( with: request)
59+ if let _ = requestConfiguration. emulatorHostAndPort {
60+ fetcher. allowLocalhostRequest = true
61+ fetcher. allowedInsecureSchemes = [ " http " ]
62+ }
63+ fetcher. bodyData = body
64+
65+ return await withUnsafeContinuation { continuation in
66+ fetcher. beginFetch { data, error in
67+ continuation. resume ( returning: ( data, error) )
6568 }
66- fetcher. bodyData = body
67- fetcher. beginFetch ( completionHandler: completionHandler)
6869 }
6970 }
7071}
@@ -98,8 +99,7 @@ class AuthBackend: NSObject {
9899
99100 class func request( withURL url: URL ,
100101 contentType: String ,
101- requestConfiguration: AuthRequestConfiguration ,
102- completion: @escaping ( URLRequest ) -> Void ) {
102+ requestConfiguration: AuthRequestConfiguration ) async -> URLRequest {
103103 var request = URLRequest ( url: url)
104104 request. setValue ( contentType, forHTTPHeaderField: " Content-Type " )
105105 let additionalFrameworkMarker = requestConfiguration
@@ -121,18 +121,15 @@ class AuthBackend: NSObject {
121121 request. setValue ( languageCode, forHTTPHeaderField: " X-Firebase-Locale " )
122122 }
123123 if let appCheck = requestConfiguration. appCheck {
124- appCheck. getToken ( forcingRefresh: false ) { tokenResult in
125- if let error = tokenResult. error {
126- AuthLog . logWarning ( code: " I-AUT000018 " ,
127- message: " Error getting App Check token; using placeholder " +
128- " token instead. Error: \( error) " )
129- }
130- request. setValue ( tokenResult. token, forHTTPHeaderField: " X-Firebase-AppCheck " )
131- completion ( request)
124+ let tokenResult = await appCheck. getToken ( forcingRefresh: false )
125+ if let error = tokenResult. error {
126+ AuthLog . logWarning ( code: " I-AUT000018 " ,
127+ message: " Error getting App Check token; using placeholder " +
128+ " token instead. Error: \( error) " )
132129 }
133- } else {
134- completion ( request)
130+ request. setValue ( tokenResult. token, forHTTPHeaderField: " X-Firebase-AppCheck " )
135131 }
132+ return request
136133 }
137134}
138135
@@ -270,135 +267,104 @@ private class AuthBackendRPCImplementation: NSObject, AuthBackendImplementation
270267 throw AuthErrorUtils . JSONSerializationErrorForUnencodableType ( )
271268 }
272269 }
273- return try await withCheckedThrowingContinuation { continuation in
274- rpcIssuer
275- . asyncCallToURL ( with: request, body: bodyData, contentType: " application/json " ) {
276- data, error in
277- // If there is an error with no body data at all, then this must be a
278- // network error.
279- guard let data = data else {
280- if let error = error {
281- continuation. resume ( throwing: AuthErrorUtils . networkError ( underlyingError: error) )
282- return
283- } else {
284- // TODO: this was ignored before
285- fatalError ( " Auth Internal error: RPC call didn't return data or an error. " )
286- }
287- }
288- // Try to decode the HTTP response data which may contain either a
289- // successful response or error message.
290- var dictionary : [ String : AnyHashable ]
291- do {
292- let rawDecode = try JSONSerialization . jsonObject ( with: data,
293- options: JSONSerialization
294- . ReadingOptions
295- . mutableLeaves)
296- guard let decodedDictionary = rawDecode as? [ String : AnyHashable ] else {
297- if error != nil {
298- continuation. resume (
299- throwing: AuthErrorUtils . unexpectedErrorResponse ( deserializedResponse: rawDecode,
300- underlyingError: error)
301- )
302- return
303- } else {
304- continuation. resume (
305- throwing: AuthErrorUtils . unexpectedResponse ( deserializedResponse: rawDecode)
306- )
307- return
308- }
309- }
310- dictionary = decodedDictionary
311- } catch let jsonError {
312- if error != nil {
313- // We have an error, but we couldn't decode the body, so we have no
314- // additional information other than the raw response and the
315- // original NSError (the jsonError is inferred by the error code
316- // (AuthErrorCodeUnexpectedHTTPResponse, and is irrelevant.)
317- continuation. resume (
318- throwing: AuthErrorUtils . unexpectedErrorResponse (
319- data: data,
320- underlyingError: error
321- )
322- )
323- return
324- } else {
325- // This is supposed to be a "successful" response, but we couldn't
326- // deserialize the body.
327- continuation. resume (
328- throwing: AuthErrorUtils . unexpectedResponse ( data: data, underlyingError: jsonError)
329- )
330- return
331- }
332- }
270+ let ( data, error) = await rpcIssuer
271+ . asyncCallToURL ( with: request, body: bodyData, contentType: " application/json " )
272+ // If there is an error with no body data at all, then this must be a
273+ // network error.
274+ guard let data = data else {
275+ if let error = error {
276+ throw AuthErrorUtils . networkError ( underlyingError: error)
277+ } else {
278+ // TODO: this was ignored before
279+ fatalError ( " Auth Internal error: RPC call didn't return data or an error. " )
280+ }
281+ }
282+ // Try to decode the HTTP response data which may contain either a
283+ // successful response or error message.
284+ var dictionary : [ String : AnyHashable ]
285+ var rawDecode : Any
286+ do {
287+ rawDecode = try JSONSerialization . jsonObject (
288+ with: data, options: JSONSerialization . ReadingOptions. mutableLeaves
289+ )
290+ } catch let jsonError {
291+ if error != nil {
292+ // We have an error, but we couldn't decode the body, so we have no
293+ // additional information other than the raw response and the
294+ // original NSError (the jsonError is inferred by the error code
295+ // (AuthErrorCodeUnexpectedHTTPResponse, and is irrelevant.)
296+ throw AuthErrorUtils . unexpectedErrorResponse ( data: data, underlyingError: error)
297+ } else {
298+ // This is supposed to be a "successful" response, but we couldn't
299+ // deserialize the body.
300+ throw AuthErrorUtils . unexpectedResponse ( data: data, underlyingError: jsonError)
301+ }
302+ }
303+ guard let decodedDictionary = rawDecode as? [ String : AnyHashable ] else {
304+ if error != nil {
305+ throw AuthErrorUtils . unexpectedErrorResponse ( deserializedResponse: rawDecode,
306+ underlyingError: error)
307+ } else {
308+ throw AuthErrorUtils . unexpectedResponse ( deserializedResponse: rawDecode)
309+ }
310+ }
311+ dictionary = decodedDictionary
333312
334- let response = T . Response ( )
313+ let response = T . Response ( )
335314
336- // At this point we either have an error with successfully decoded
337- // details in the body, or we have a response which must pass further
338- // validation before we know it's truly successful. We deal with the
339- // case where we have an error with successfully decoded error details
340- // first:
341- if error != nil {
342- if let errorDictionary = dictionary [ " error " ] as? [ String : AnyHashable ] {
343- if let errorMessage = errorDictionary [ " message " ] as? String {
344- if let clientError = AuthBackendRPCImplementation . clientError (
345- withServerErrorMessage: errorMessage,
346- errorDictionary: errorDictionary,
347- response: response,
348- error: error
349- ) {
350- continuation. resume ( throwing: clientError)
351- return
352- }
353- }
354- // Not a message we know, return the message directly.
355- continuation. resume (
356- throwing: AuthErrorUtils . unexpectedErrorResponse (
357- deserializedResponse: errorDictionary,
358- underlyingError: error
359- )
360- )
361- return
362- }
363- // No error message at all, return the decoded response.
364- continuation. resume (
365- throwing: AuthErrorUtils
366- . unexpectedErrorResponse ( deserializedResponse: dictionary, underlyingError: error)
367- )
368- return
315+ // At this point we either have an error with successfully decoded
316+ // details in the body, or we have a response which must pass further
317+ // validation before we know it's truly successful. We deal with the
318+ // case where we have an error with successfully decoded error details
319+ // first:
320+ if error != nil {
321+ if let errorDictionary = dictionary [ " error " ] as? [ String : AnyHashable ] {
322+ if let errorMessage = errorDictionary [ " message " ] as? String {
323+ if let clientError = AuthBackendRPCImplementation . clientError (
324+ withServerErrorMessage: errorMessage,
325+ errorDictionary: errorDictionary,
326+ response: response,
327+ error: error
328+ ) {
329+ throw clientError
369330 }
331+ }
332+ // Not a message we know, return the message directly.
333+ throw AuthErrorUtils . unexpectedErrorResponse (
334+ deserializedResponse: errorDictionary,
335+ underlyingError: error
336+ )
337+ }
338+ // No error message at all, return the decoded response.
339+ throw AuthErrorUtils
340+ . unexpectedErrorResponse ( deserializedResponse: dictionary, underlyingError: error)
341+ }
370342
371- // Finally, we try to populate the response object with the JSON values.
372- do {
373- try response. setFields ( dictionary: dictionary)
374- } catch {
375- continuation. resume (
376- throwing: AuthErrorUtils
377- . RPCResponseDecodingError ( deserializedResponse: dictionary, underlyingError: error)
378- )
379- return
380- }
381- // In case returnIDPCredential of a verifyAssertion request is set to
382- // @YES, the server may return a 200 with a response that may contain a
383- // server error.
384- if let verifyAssertionRequest = request as? VerifyAssertionRequest {
385- if verifyAssertionRequest. returnIDPCredential {
386- if let errorMessage = dictionary [ " errorMessage " ] as? String {
387- if let clientError = AuthBackendRPCImplementation . clientError (
388- withServerErrorMessage: errorMessage,
389- errorDictionary: dictionary,
390- response: response,
391- error: error
392- ) {
393- continuation. resume ( throwing: clientError)
394- return
395- }
396- }
397- }
343+ // Finally, we try to populate the response object with the JSON values.
344+ do {
345+ try response. setFields ( dictionary: dictionary)
346+ } catch {
347+ throw AuthErrorUtils
348+ . RPCResponseDecodingError ( deserializedResponse: dictionary, underlyingError: error)
349+ }
350+ // In case returnIDPCredential of a verifyAssertion request is set to
351+ // @YES, the server may return a 200 with a response that may contain a
352+ // server error.
353+ if let verifyAssertionRequest = request as? VerifyAssertionRequest {
354+ if verifyAssertionRequest. returnIDPCredential {
355+ if let errorMessage = dictionary [ " errorMessage " ] as? String {
356+ if let clientError = AuthBackendRPCImplementation . clientError (
357+ withServerErrorMessage: errorMessage,
358+ errorDictionary: dictionary,
359+ response: response,
360+ error: error
361+ ) {
362+ throw clientError
398363 }
399- continuation. resume ( returning: response)
400364 }
365+ }
401366 }
367+ return response
402368 }
403369
404370 private class func clientError( withServerErrorMessage serverErrorMessage: String ,
0 commit comments