gecko-dev/dom/webauthn/WebAuthnRequest.h

138 строки
3.6 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_WebAuthnAsync_h
#define mozilla_dom_WebAuthnAsync_h
#include "mozilla/MozPromise.h"
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/SharedThreadPool.h"
#include "mozilla/TimeStamp.h"
namespace mozilla {
namespace dom {
//extern mozilla::LazyLogModule gWebauthLog; // defined in U2F.cpp
// WebAuthnRequest tracks the completion of a single WebAuthn request that
// may run on multiple kinds of authenticators, and be subject to a deadline.
template<class Success>
class WebAuthnRequest {
public:
WebAuthnRequest()
: mCancelled(false)
, mSuccess(false)
, mCountTokens(0)
, mTokensFailed(0)
, mReentrantMonitor("WebAuthnRequest")
{}
void AddActiveToken(const char* aCallSite)
{
// MOZ_LOG(gWebauthLog, LogLevel::Debug,
// ("WebAuthnRequest is tracking a new token, called from [%s]",
// aCallSite));
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MOZ_ASSERT(!IsComplete());
mCountTokens += 1;
}
bool IsComplete()
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mCancelled || mSuccess ||
(mCountTokens > 0 && mTokensFailed == mCountTokens);
}
void CancelNow()
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
// It's possible for a race to cause CancelNow to get called after
// a success or a cancel. We only complete once.
if (IsComplete()) {
return;
}
mCancelled = true;
mPromise.Reject(NS_ERROR_DOM_NOT_ALLOWED_ERR, __func__);
}
void SetFailure(nsresult aError)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
// It's possible for a race to cause SetFailure to get called after
// a success or a cancel. We only complete once.
if (IsComplete()) {
return;
}
mTokensFailed += 1;
MOZ_ASSERT(mTokensFailed <= mCountTokens);
if (mTokensFailed == mCountTokens) {
// Provide the final error as being indicitive of the whole set.
mPromise.Reject(aError, __func__);
}
}
void SetSuccess(const Success& aResult)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
// It's possible for a race to cause multiple calls to SetSuccess
// in succession. We will only select the earliest.
if (IsComplete()) {
return;
}
mSuccess = true;
mPromise.Resolve(aResult, __func__);
}
void SetDeadline(TimeDuration aDeadline)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MOZ_ASSERT(!IsComplete());
// TODO: Monitor the deadline and stop with a timeout error if it expires.
}
RefPtr<MozPromise<Success, nsresult, false>> Ensure()
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MOZ_ASSERT(!IsComplete());
return mPromise.Ensure(__func__);
}
void CompleteTask()
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (mCountTokens == 0) {
// Special case for there being no tasks to complete
mPromise.Reject(NS_ERROR_DOM_NOT_ALLOWED_ERR, __func__);
}
}
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebAuthnRequest)
private:
~WebAuthnRequest() {};
bool mCancelled;
bool mSuccess;
int mCountTokens;
int mTokensFailed;
ReentrantMonitor mReentrantMonitor;
MozPromiseHolder<MozPromise<Success, nsresult, false>> mPromise;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_WebAuthnAsync_h