Index: Source/modules/crypto/CryptoResultImpl.cpp |
diff --git a/Source/modules/crypto/CryptoResultImpl.cpp b/Source/modules/crypto/CryptoResultImpl.cpp |
index 2360727a13a91f34ae1e4352523c2068b1c2c2e2..2c681633c886c9057cc863e32bdec1e7a3165a11 100644 |
--- a/Source/modules/crypto/CryptoResultImpl.cpp |
+++ b/Source/modules/crypto/CryptoResultImpl.cpp |
@@ -63,7 +63,7 @@ static void rejectWithTypeError(const String& errorDetails, ScriptPromiseResolve |
class CryptoResultImpl::Resolver final : public ScriptPromiseResolver { |
public: |
- static PassRefPtrWillBeRawPtr<ScriptPromiseResolver> create(ScriptState* scriptState, CryptoResultImpl* result) |
+ static PassRefPtrWillBeRawPtr<Resolver> create(ScriptState* scriptState, CryptoResultImpl* result) |
{ |
RefPtrWillBeRawPtr<Resolver> resolver = adoptRefWillBeNoop(new Resolver(scriptState, result)); |
resolver->suspendIfNeeded(); |
@@ -74,16 +74,22 @@ public: |
void stop() override |
{ |
m_result->cancel(); |
- m_result->clearResolver(); |
m_result = nullptr; |
ScriptPromiseResolver::stop(); |
} |
+ DEFINE_INLINE_VIRTUAL_TRACE() |
+ { |
+ visitor->trace(m_result); |
+ ScriptPromiseResolver::trace(visitor); |
+ } |
+ |
private: |
Resolver(ScriptState* scriptState, CryptoResultImpl* result) |
: ScriptPromiseResolver(scriptState) |
, m_result(result) { } |
- RefPtr<CryptoResultImpl> m_result; |
+ |
+ RefPtrWillBeMember<CryptoResultImpl> m_result; |
}; |
ExceptionCode webCryptoErrorToExceptionCode(WebCryptoErrorType errorType) |
@@ -107,11 +113,30 @@ ExceptionCode webCryptoErrorToExceptionCode(WebCryptoErrorType errorType) |
return 0; |
} |
+CryptoResultImpl::CryptoResultImpl(ScriptState* scriptState) |
+ : m_resultOwner(nullptr) |
+{ |
+ ASSERT(scriptState->contextIsValid()); |
+ if (scriptState->executionContext()->activeDOMObjectsAreStopped()) { |
+ // If active dom objects have been stopped, avoid creating |
+ // CryptoResultImpl::Resolver. |
+ m_resolver = nullptr; |
+ } else { |
+ m_resolver = Resolver::create(scriptState, this).get(); |
+ } |
+} |
+ |
CryptoResultImpl::~CryptoResultImpl() |
{ |
ASSERT(!m_resolver); |
} |
+DEFINE_TRACE(CryptoResultImpl) |
+{ |
+ visitor->trace(m_resolver); |
+ CryptoResult::trace(visitor); |
+} |
+ |
void CryptoResultImpl::clearResolver() |
{ |
m_resolver = nullptr; |
@@ -124,101 +149,123 @@ PassRefPtrWillBeRawPtr<CryptoResultImpl> CryptoResultImpl::create(ScriptState* s |
void CryptoResultImpl::completeWithError(WebCryptoErrorType errorType, const WebString& errorDetails) |
{ |
- if (m_resolver) { |
- ExceptionCode ec = webCryptoErrorToExceptionCode(errorType); |
+ if (!m_resolver) |
+ return; |
- // Handle TypeError separately, as it cannot be created using |
- // DOMException. |
- if (ec == V8TypeError) |
- rejectWithTypeError(errorDetails, m_resolver); |
- else |
- m_resolver->reject(DOMException::create(ec, errorDetails)); |
- } |
+ ExceptionCode ec = webCryptoErrorToExceptionCode(errorType); |
+ |
+ // Handle TypeError separately, as it cannot be created using |
+ // DOMException. |
+ if (ec == V8TypeError) |
+ rejectWithTypeError(errorDetails, m_resolver); |
+ else |
+ m_resolver->reject(DOMException::create(ec, errorDetails)); |
clearResolver(); |
} |
void CryptoResultImpl::completeWithBuffer(const void* bytes, unsigned bytesSize) |
{ |
- if (m_resolver) |
- m_resolver->resolve(DOMArrayBuffer::create(bytes, bytesSize)); |
+ if (!m_resolver) |
+ return; |
+ |
+ m_resolver->resolve(DOMArrayBuffer::create(bytes, bytesSize)); |
clearResolver(); |
} |
void CryptoResultImpl::completeWithJson(const char* utf8Data, unsigned length) |
{ |
- if (m_resolver) { |
- ScriptPromiseResolver* resolver = m_resolver; |
- ScriptState* scriptState = resolver->scriptState(); |
- ScriptState::Scope scope(scriptState); |
+ if (!m_resolver) |
+ return; |
- v8::Local<v8::String> jsonString = v8AtomicString(scriptState->isolate(), utf8Data, length); |
+ ScriptState* scriptState = m_resolver->scriptState(); |
+ ScriptState::Scope scope(scriptState); |
- v8::TryCatch exceptionCatcher; |
- v8::Local<v8::Value> jsonDictionary; |
- if (v8Call(v8::JSON::Parse(scriptState->isolate(), jsonString), jsonDictionary, exceptionCatcher)) |
- resolver->resolve(jsonDictionary); |
- else |
- resolver->reject(exceptionCatcher.Exception()); |
- } |
+ v8::Local<v8::String> jsonString = v8AtomicString(scriptState->isolate(), utf8Data, length); |
+ |
+ v8::TryCatch exceptionCatcher; |
+ v8::Local<v8::Value> jsonDictionary; |
+ if (v8Call(v8::JSON::Parse(scriptState->isolate(), jsonString), jsonDictionary, exceptionCatcher)) |
+ m_resolver->resolve(jsonDictionary); |
+ else |
+ m_resolver->reject(exceptionCatcher.Exception()); |
clearResolver(); |
} |
void CryptoResultImpl::completeWithBoolean(bool b) |
{ |
- if (m_resolver) |
- m_resolver->resolve(b); |
+ if (!m_resolver) |
+ return; |
+ |
+ m_resolver->resolve(b); |
clearResolver(); |
} |
void CryptoResultImpl::completeWithKey(const WebCryptoKey& key) |
{ |
- if (m_resolver) |
- m_resolver->resolve(CryptoKey::create(key)); |
+ if (!m_resolver) |
+ return; |
+ |
+ m_resolver->resolve(CryptoKey::create(key)); |
clearResolver(); |
} |
void CryptoResultImpl::completeWithKeyPair(const WebCryptoKey& publicKey, const WebCryptoKey& privateKey) |
{ |
- if (m_resolver) { |
- ScriptState* scriptState = m_resolver->scriptState(); |
- ScriptState::Scope scope(scriptState); |
+ if (!m_resolver) |
+ return; |
- V8ObjectBuilder keyPair(scriptState); |
+ ScriptState* scriptState = m_resolver->scriptState(); |
+ ScriptState::Scope scope(scriptState); |
- keyPair.add("publicKey", ScriptValue::from(scriptState, CryptoKey::create(publicKey))); |
- keyPair.add("privateKey", ScriptValue::from(scriptState, CryptoKey::create(privateKey))); |
+ V8ObjectBuilder keyPair(scriptState); |
- m_resolver->resolve(keyPair.v8Value()); |
- } |
+ keyPair.add("publicKey", ScriptValue::from(scriptState, CryptoKey::create(publicKey))); |
+ keyPair.add("privateKey", ScriptValue::from(scriptState, CryptoKey::create(privateKey))); |
+ |
+ m_resolver->resolve(keyPair.v8Value()); |
clearResolver(); |
} |
-bool CryptoResultImpl::cancelled() const |
+void CryptoResultImpl::cancel() |
{ |
- return acquireLoad(&m_cancelled); |
+ // Hold a lock to prevent m_resultOwner being updated by a webcrypto thread |
+ // while cancelling. |
+ MutexLocker lock(m_mutex); |
+ |
+ if (!m_resultOwner) |
+ return; |
+ |
+ // Eagerly detach the WebCryptoResult, so as to allow clean shutdowns. |
+ m_resultOwner->clear(); |
+ // Verify that it unregistered. |
+ ASSERT(!m_resultOwner); |
+ |
+ clearResolver(); |
} |
-void CryptoResultImpl::cancel() |
+ScriptPromise CryptoResultImpl::promise() |
{ |
- releaseStore(&m_cancelled, 1); |
+ return m_resolver ? m_resolver->promise() : ScriptPromise(); |
} |
-CryptoResultImpl::CryptoResultImpl(ScriptState* scriptState) |
- : m_cancelled(0) |
+bool CryptoResultImpl::registerResult(WebCryptoResult* result) |
{ |
- ASSERT(scriptState->contextIsValid()); |
- if (scriptState->executionContext()->activeDOMObjectsAreStopped()) { |
- // If active dom objects have been stopped, avoid creating |
- // CryptoResultResolver. |
- m_resolver = nullptr; |
- } else { |
- m_resolver = Resolver::create(scriptState, this).get(); |
- } |
+ MutexLocker lock(m_mutex); |
+ |
+ // Cancelled? |
+ if (!m_resolver) |
+ return true; |
+ |
+ m_resultOwner = result; |
+ return false; |
} |
-ScriptPromise CryptoResultImpl::promise() |
+void CryptoResultImpl::unregisterResult(WebCryptoResult* result) |
{ |
- return m_resolver ? m_resolver->promise() : ScriptPromise(); |
+ MutexLocker lock(m_mutex); |
+ |
+ if (result == m_resultOwner) |
+ m_resultOwner = nullptr; |
} |
} // namespace blink |