Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent refresh race conditions #93

Merged
merged 13 commits into from
Aug 24, 2016
Merged

Prevent refresh race conditions #93

merged 13 commits into from
Aug 24, 2016

Conversation

Stengo
Copy link
Contributor

@Stengo Stengo commented Aug 16, 2016

Description

Making multiple calls to authenticateRequest with an expired access token can lead to multiple requests for a new access token with the same refresh token. As a result, the user might be left with an invalid token.

In order to prevent this, we decided to make calls to authenticateRequest sequential. This is achieved by using a serial queue and limiting its resources via a semaphore.

/// - parameter request: An unauthenticated NSURLRequest.
/// - parameter completion: A callback to invoke with the authenticated request.
public func authenticateRequest(request: NSURLRequest, completion: Result<NSURLRequest, NSError> -> ()) {
dispatch_sync(refreshQueue) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please note that if the completion block is called immediately, e.g. because there is no access token, and the completion block itself tries to authenticate another request, the program will deadlock. However, since the API is asynchronous anyways, you might want to use dispatch_async instead.

@@ -39,6 +39,8 @@ public let HeimdallrErrorNotAuthorized = 2
return accessToken != nil
}

private var refreshQueue = dispatch_queue_create("de.rheinfabrik.Heimdallr.refeshQueue", DISPATCH_QUEUE_SERIAL)
Copy link
Contributor

@bckr bckr Aug 22, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might think about using com.trivago.Heimdallr.refreshQueue here?

also: is it really a refreshQueue? Because all requests get queued here, right?

@@ -208,6 +219,7 @@ public let HeimdallrErrorNotAuthorized = 2
}
return .Failure(error)
}))
self.releaseRefreshQueue()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be a nice use case for a defer, right?

Copy link
Contributor Author

@Stengo Stengo Aug 23, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about that and since it can only be used in this completion block I left it out. But you are right, it's still a bit nicer. Fixed!

EDIT: after considering a bit more, it can be used everywhere else, it just looked a bit odd. I'll add it anyhow.

@hffmnn
Copy link
Contributor

hffmnn commented Aug 24, 2016

@marcelofabri do you have some comments on this one?

@marcelofabri
Copy link
Contributor

Seems good to me! 👏

I didn't know about dispatch_suspend and dispatch_release 💯

@hffmnn hffmnn merged commit 60ff8af into master Aug 24, 2016
@hffmnn hffmnn deleted the prevent-race-conditions branch August 24, 2016 14:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants