Skip to content

Commit 67db44f

Browse files
bbirmanjwutke-sf
authored andcommitted
Cherry pick of pull request forcedotcom#3958 from bbirman/rest-callbacks
Fix callbacks for RestAPI
1 parent 2a24d9a commit 67db44f

File tree

2 files changed

+71
-33
lines changed

2 files changed

+71
-33
lines changed

libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFRestAPI.m

Lines changed: 17 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -290,14 +290,14 @@ - (void)send:(SFRestRequest *)request
290290
[[SFUserAccountManager sharedInstance] loginWithReason:SFLoginReasonRestCredentials completion:^(SFOAuthInfo *authInfo, SFUserAccount *userAccount) {
291291
__strong typeof(weakSelf) strongSelf = weakSelf;
292292
strongSelf.user = userAccount;
293-
[strongSelf enqueueRequest:request failureBlock:failureBlock successBlock:successBlock shouldRetry:shouldRetry];
293+
[strongSelf enqueueRequest:request shouldRetry:shouldRetry];
294294
} failure:^(SFOAuthInfo *authInfo, NSError *error) {
295295
__strong typeof(weakSelf) strongSelf = weakSelf;
296296
[SFSDKCoreLogger e:[strongSelf class] format:@"Authentication failed in SFRestAPI: %@. Logging out.", error];
297297
[[SFUserAccountManager sharedInstance] logout:SFLogoutReasonUnexpected];
298298
}];
299299
} else {
300-
[self enqueueRequest:request failureBlock:failureBlock successBlock:successBlock shouldRetry:shouldRetry];
300+
[self enqueueRequest:request shouldRetry:shouldRetry];
301301
}
302302
}
303303

@@ -315,10 +315,7 @@ - (SFOAuthSessionRefresher *)sessionRefresherForUser:(SFUserAccount *)user {
315315
return self.oauthSessionRefresher;
316316
}
317317

318-
- (void)enqueueRequest:(SFRestRequest *)request
319-
failureBlock:(SFRestRequestFailBlock)failureBlock
320-
successBlock:(SFRestResponseBlock)successBlock
321-
shouldRetry:(BOOL)shouldRetry {
318+
- (void)enqueueRequest:(SFRestRequest *)request shouldRetry:(BOOL)shouldRetry {
322319
__weak __typeof(self) weakSelf = self;
323320
NSURLRequest *finalRequest = [request prepareRequestForSend:self.user];
324321
if (finalRequest) {
@@ -338,16 +335,16 @@ - (void)enqueueRequest:(SFRestRequest *)request
338335
if (error) {
339336
[SFSDKCoreLogger d:[strongSelf class] format:@"REST request failed with error: Error Code: %ld, Description: %@, URL: %@", (long) error.code, error.localizedDescription, finalRequest.URL];
340337
id dataForDelegate = [strongSelf prepareDataForDelegate:data request:request response:response];
341-
if (failureBlock) {
342-
failureBlock(dataForDelegate, error, response);
338+
if (request.failureBlock) {
339+
request.failureBlock(dataForDelegate, error, response);
343340
}
344341
return;
345342
}
346343

347344
// Timeout.
348345
if (!response) {
349-
if (failureBlock) {
350-
failureBlock(nil, nil, nil);
346+
if (request.failureBlock) {
347+
request.failureBlock(nil, nil, nil);
351348
}
352349
return;
353350
}
@@ -356,18 +353,18 @@ - (void)enqueueRequest:(SFRestRequest *)request
356353
// 2xx indicates success.
357354
if ([SFRestAPI isStatusCodeSuccess:statusCode]) {
358355
id dataForDelegate = [strongSelf prepareDataForDelegate:data request:request response:response];
359-
if (successBlock) {
360-
successBlock(dataForDelegate, response);
356+
if (request.successBlock) {
357+
request.successBlock(dataForDelegate, response);
361358
}
362359
} else {
363360
if (shouldRetry && [self shouldRetryTask:dataTask withData:data]) {
364-
[strongSelf replayRequest:request response:response failureBlock:failureBlock successBlock:successBlock];
361+
[strongSelf replayRequest:request response:response];
365362
} else {
366363
// Other status codes indicate failure.
367364
NSError *errorForDelegate = [strongSelf prepareErrorForDelegate:data response:response];
368365
id dataForDelegate = [strongSelf prepareDataForDelegate:data request:request response:response];
369-
if (failureBlock) {
370-
failureBlock(dataForDelegate, errorForDelegate, response);
366+
if (request.failureBlock) {
367+
request.failureBlock(dataForDelegate, errorForDelegate, response);
371368
}
372369
}
373370
}
@@ -447,10 +444,7 @@ - (NSError*) prepareErrorForDelegate:(NSData *)data response:(NSURLResponse *)re
447444
return [[NSError alloc] initWithDomain:kSFRestErrorDomain code:statusCode userInfo:errorDict];
448445
}
449446

450-
- (void)replayRequest:(SFRestRequest *)request
451-
response:(NSURLResponse *)response
452-
failureBlock:(SFRestRequestFailBlock)failureBlock
453-
successBlock:(SFRestResponseBlock)successBlock {
447+
- (void)replayRequest:(SFRestRequest *)request response:(NSURLResponse *)response {
454448
[SFSDKCoreLogger i:[self class] format:@"%@: REST request failed due to expired credentials. Attempting to refresh credentials.", NSStringFromSelector(_cmd)];
455449

456450
/*
@@ -470,22 +464,13 @@ - (void)replayRequest:(SFRestRequest *)request
470464
@synchronized (strongSelf) {
471465
if (!strongSelf.pendingRequestsBeingProcessed) {
472466
strongSelf.pendingRequestsBeingProcessed = YES;
473-
[strongSelf resendActiveRequestsRequiringAuthenticationWithFailureBlock:failureBlock
474-
successBlock:successBlock];
467+
[strongSelf resendActiveRequestsRequiringAuthentication];
475468
}
476469
}
477470
} error:^(NSError *refreshError) {
478471
__strong typeof(weakSelf) strongSelf = weakSelf;
479472
[SFSDKCoreLogger e:[strongSelf class] format:@"Failed to refresh expired session. Error: %@", refreshError];
480-
481-
// Call the failure block for the triggering request first
482-
if (failureBlock) {
483-
failureBlock(nil, refreshError, response);
484-
}
485-
486473
strongSelf.pendingRequestsBeingProcessed = YES;
487-
// Remove the triggering request from active requests to avoid double callback
488-
[strongSelf.activeRequests removeObject:request];
489474
[strongSelf flushPendingRequestQueue:refreshError rawResponse:response];
490475
strongSelf.sessionRefreshInProgress = NO;
491476
strongSelf.oauthSessionRefresher = nil;
@@ -514,14 +499,13 @@ - (void)flushPendingRequestQueue:(NSError *)error rawResponse:(NSURLResponse *)r
514499
}
515500
}
516501

517-
- (void)resendActiveRequestsRequiringAuthenticationWithFailureBlock:(SFRestRequestFailBlock)failureBlock
518-
successBlock:(SFRestResponseBlock)successBlock {
502+
- (void)resendActiveRequestsRequiringAuthentication {
519503
@synchronized (self) {
520504
NSSet *pendingRequests = [self.activeRequests asSet];
521505
for (SFRestRequest *request in pendingRequests) {
522506
[self send:request
523-
failureBlock:failureBlock
524-
successBlock:successBlock
507+
failureBlock:request.failureBlock
508+
successBlock:request.successBlock
525509
shouldRetry:NO];
526510
}
527511
self.pendingRequestsBeingProcessed = NO;

libs/SalesforceSDKCore/SalesforceSDKCoreTests/RestClientTest.swift

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,60 @@ class RestClientTests: XCTestCase {
771771
}
772772
}
773773

774+
func testRefreshWithSuccesfulRequests() async throws {
775+
// Revoke access token
776+
try await revokeAccessToken()
777+
778+
// Send multiple requests for replay and verify completion block is only called once per request
779+
let resourcesRequest = RestClient.shared.request(forResources: nil)
780+
let resourcesExpectation = XCTestExpectation(description: "Resources request")
781+
resourcesExpectation.assertForOverFulfill = true
782+
RestClient.shared.send(resourcesRequest) { _, error, _ in
783+
XCTFail("Request unexpectedly failed with error: \(error.debugDescription)")
784+
} successBlock: { _,_ in
785+
resourcesExpectation.fulfill()
786+
}
787+
788+
let describeRequest = RestClient.shared.request(forDescribeGlobal: nil)
789+
let describeExpectation = XCTestExpectation(description: "Describe request")
790+
describeExpectation.assertForOverFulfill = true
791+
RestClient.shared.send(describeRequest) { _, error, _ in
792+
XCTFail("Request unexpectedly failed with error: \(error.debugDescription)")
793+
} successBlock: { _,_ in
794+
describeExpectation.fulfill()
795+
}
796+
797+
let contactRequest = RestClient.shared.requestForDescribe(withObjectType: "Contact", apiVersion: nil)
798+
let contactExpectation = XCTestExpectation(description: "Contact request")
799+
contactExpectation.assertForOverFulfill = true
800+
RestClient.shared.send(contactRequest) { _, error, _ in
801+
XCTFail("Request unexpectedly failed with error: \(error.debugDescription)")
802+
} successBlock: { _,_ in
803+
contactExpectation.fulfill()
804+
}
805+
806+
await fulfillment(of: [resourcesExpectation, describeExpectation, contactExpectation])
807+
}
808+
809+
private func revokeAccessToken() async throws {
810+
guard let currentUser = UserAccountManager.shared.currentUserAccount,
811+
let accessToken = currentUser.credentials.accessToken,
812+
let encodedToken = accessToken.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {
813+
XCTFail("No current user access token")
814+
return
815+
}
816+
817+
let request = RestRequest(method: .POST, path: "/services/oauth2/revoke", queryParams: nil)
818+
request.endpoint = ""
819+
820+
// Set the request body with URL-encoded token
821+
let bodyString = "token=\(encodedToken)"
822+
request.setCustomRequestBodyString(bodyString, contentType: "application/x-www-form-urlencoded")
823+
824+
// Send the request
825+
_ = try await RestClient.shared.send(request: request)
826+
}
827+
774828
private func generateRecordName() -> String {
775829
let timecode = Date.timeIntervalSinceReferenceDate
776830
return "SwiftTestsiOS\(timecode)"

0 commit comments

Comments
 (0)