Introduce CompletionHandler-based Async IPC messages with replies
authorachristensen@apple.com <achristensen@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 19 Oct 2018 17:40:20 +0000 (17:40 +0000)
committerachristensen@apple.com <achristensen@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 19 Oct 2018 17:40:20 +0000 (17:40 +0000)
https://bugs.webkit.org/show_bug.cgi?id=190746

Reviewed by Tim Horton.

Before this patch, to make an asynchronous IPC message with a reply you had to find two objects that
can talk to each other, make two new message types, send a generated identifier, keep track of that
identifier, make a HashMap somewhere to store the object waiting for the response, and hook it all up.
What a mess.  No wonder people take shortcuts and make strange design decisions.

Now, you can just use a CompletionHandler and mark the reply as Async in *.messages.in.
I've adopted this with a message whose behavior is covered by the storage/indexeddb/modern/blob-cursor.html
layout test and many others.  I intent to refine and further adopt this incrementally.

* NetworkProcess/NetworkProcess.cpp:
(WebKit::NetworkProcess::getSandboxExtensionsForBlobFiles):
(WebKit::NetworkProcess::didGetSandboxExtensionsForBlobFiles): Deleted.
* NetworkProcess/NetworkProcess.h:
* NetworkProcess/NetworkProcess.messages.in:
This is representative of how code will be simplified with greater adoption.
* NetworkProcess/NetworkResourceLoadParameters.cpp:
(WebKit::NetworkResourceLoadParameters::decode):
Modernize HandleArray decoding.
* Platform/IPC/Connection.cpp:
(IPC::Connection::dispatchMessage):
(IPC::nextAsyncReplyHandlerID):
(IPC::asyncReplyHandlerMap):
Handle async replies when looking at incoming messages from the sending process.
* Platform/IPC/Connection.h:
(IPC::Connection::sendWithAsyncReply):
Send a message with an async reply and prepare the reply receiver.
* Platform/IPC/Encoder.h:
Make the uint64_t encoder public so we can use it when encoding the listenerID.
* Platform/IPC/HandleMessage.h:
(IPC::handleMessageAsync):
Handle an asynchronous message with a reply from the receiving process.
This is similar to how DelayedReply messages are handled, but the listenerID is automatically captured and sent back.
* Scripts/webkit/messages.py:
Generate code for async message replies.
* Shared/Databases/IndexedDB/WebIDBResult.cpp:
(WebKit::WebIDBResult::decode):
* Shared/SandboxExtension.h:
(WebKit::SandboxExtension::HandleArray::at):
(WebKit::SandboxExtension::HandleArray::decode):
* Shared/WebProcessCreationParameters.cpp:
(WebKit::WebProcessCreationParameters::decode):
* Shared/mac/SandboxExtensionMac.mm:
(WebKit::SandboxExtension::HandleArray::decode):
Modernize the decoding of HandleArray to work with generated decoding.
* UIProcess/Network/NetworkProcessProxy.cpp:
(WebKit::NetworkProcessProxy::getSandboxExtensionsForBlobFiles):
* UIProcess/Network/NetworkProcessProxy.h:
* UIProcess/Network/NetworkProcessProxy.messages.in:
This is also representative of how code will be simplified with greater adoption.
* WebProcess/MediaStream/MediaDeviceSandboxExtensions.cpp:
(WebKit::MediaDeviceSandboxExtensions::decode):
Modernize HandleArray decoding.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@237294 268f45cc-cd09-0410-ab3c-d52691b4dbfc

18 files changed:
Source/WebKit/ChangeLog
Source/WebKit/NetworkProcess/NetworkProcess.cpp
Source/WebKit/NetworkProcess/NetworkProcess.h
Source/WebKit/NetworkProcess/NetworkProcess.messages.in
Source/WebKit/NetworkProcess/NetworkResourceLoadParameters.cpp
Source/WebKit/Platform/IPC/Connection.cpp
Source/WebKit/Platform/IPC/Connection.h
Source/WebKit/Platform/IPC/Encoder.h
Source/WebKit/Platform/IPC/HandleMessage.h
Source/WebKit/Scripts/webkit/messages.py
Source/WebKit/Shared/Databases/IndexedDB/WebIDBResult.cpp
Source/WebKit/Shared/SandboxExtension.h
Source/WebKit/Shared/WebProcessCreationParameters.cpp
Source/WebKit/Shared/mac/SandboxExtensionMac.mm
Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp
Source/WebKit/UIProcess/Network/NetworkProcessProxy.h
Source/WebKit/UIProcess/Network/NetworkProcessProxy.messages.in
Source/WebKit/WebProcess/MediaStream/MediaDeviceSandboxExtensions.cpp

index 2eb2ab9..10db42c 100644 (file)
@@ -1,3 +1,63 @@
+2018-10-19  Alex Christensen  <achristensen@webkit.org>
+
+        Introduce CompletionHandler-based Async IPC messages with replies
+        https://bugs.webkit.org/show_bug.cgi?id=190746
+
+        Reviewed by Tim Horton.
+
+        Before this patch, to make an asynchronous IPC message with a reply you had to find two objects that
+        can talk to each other, make two new message types, send a generated identifier, keep track of that
+        identifier, make a HashMap somewhere to store the object waiting for the response, and hook it all up.
+        What a mess.  No wonder people take shortcuts and make strange design decisions.
+
+        Now, you can just use a CompletionHandler and mark the reply as Async in *.messages.in.
+        I've adopted this with a message whose behavior is covered by the storage/indexeddb/modern/blob-cursor.html
+        layout test and many others.  I intent to refine and further adopt this incrementally.
+
+        * NetworkProcess/NetworkProcess.cpp:
+        (WebKit::NetworkProcess::getSandboxExtensionsForBlobFiles):
+        (WebKit::NetworkProcess::didGetSandboxExtensionsForBlobFiles): Deleted.
+        * NetworkProcess/NetworkProcess.h:
+        * NetworkProcess/NetworkProcess.messages.in:
+        This is representative of how code will be simplified with greater adoption. 
+        * NetworkProcess/NetworkResourceLoadParameters.cpp:
+        (WebKit::NetworkResourceLoadParameters::decode):
+        Modernize HandleArray decoding.
+        * Platform/IPC/Connection.cpp:
+        (IPC::Connection::dispatchMessage):
+        (IPC::nextAsyncReplyHandlerID):
+        (IPC::asyncReplyHandlerMap):
+        Handle async replies when looking at incoming messages from the sending process.
+        * Platform/IPC/Connection.h:
+        (IPC::Connection::sendWithAsyncReply):
+        Send a message with an async reply and prepare the reply receiver.
+        * Platform/IPC/Encoder.h:
+        Make the uint64_t encoder public so we can use it when encoding the listenerID.
+        * Platform/IPC/HandleMessage.h:
+        (IPC::handleMessageAsync):
+        Handle an asynchronous message with a reply from the receiving process.
+        This is similar to how DelayedReply messages are handled, but the listenerID is automatically captured and sent back.
+        * Scripts/webkit/messages.py:
+        Generate code for async message replies.
+        * Shared/Databases/IndexedDB/WebIDBResult.cpp:
+        (WebKit::WebIDBResult::decode):
+        * Shared/SandboxExtension.h:
+        (WebKit::SandboxExtension::HandleArray::at):
+        (WebKit::SandboxExtension::HandleArray::decode):
+        * Shared/WebProcessCreationParameters.cpp:
+        (WebKit::WebProcessCreationParameters::decode):
+        * Shared/mac/SandboxExtensionMac.mm:
+        (WebKit::SandboxExtension::HandleArray::decode):
+        Modernize the decoding of HandleArray to work with generated decoding.
+        * UIProcess/Network/NetworkProcessProxy.cpp:
+        (WebKit::NetworkProcessProxy::getSandboxExtensionsForBlobFiles):
+        * UIProcess/Network/NetworkProcessProxy.h:
+        * UIProcess/Network/NetworkProcessProxy.messages.in:
+        This is also representative of how code will be simplified with greater adoption.
+        * WebProcess/MediaStream/MediaDeviceSandboxExtensions.cpp:
+        (WebKit::MediaDeviceSandboxExtensions::decode):
+        Modernize HandleArray decoding.
+
 2018-10-19  Chris Dumez  <cdumez@apple.com>
 
         [PSON] WebPageProxy::didCompletePageTransition() may interact with a SuspendedPageProxy from a previous navigation
index dbaa315..d3fa714 100644 (file)
@@ -1190,21 +1190,11 @@ void NetworkProcess::addIndexedDatabaseSession(PAL::SessionID sessionID, String&
 #endif // ENABLE(INDEXED_DATABASE)
 
 #if ENABLE(SANDBOX_EXTENSIONS)
-void NetworkProcess::getSandboxExtensionsForBlobFiles(const Vector<String>& filenames, Function<void(SandboxExtension::HandleArray&&)>&& completionHandler)
+void NetworkProcess::getSandboxExtensionsForBlobFiles(const Vector<String>& filenames, CompletionHandler<void(SandboxExtension::HandleArray&&)>&& completionHandler)
 {
-    static uint64_t lastRequestID;
-    
-    uint64_t requestID = ++lastRequestID;
-    m_sandboxExtensionForBlobsCompletionHandlersStorageForNetworkProcess.set(requestID, WTFMove(completionHandler));
-    parentProcessConnection()->send(Messages::NetworkProcessProxy::GetSandboxExtensionsForBlobFiles(requestID, filenames), 0);
+    parentProcessConnection()->sendWithAsyncReply(Messages::NetworkProcessProxy::GetSandboxExtensionsForBlobFiles(filenames), WTFMove(completionHandler));
 }
 
-void NetworkProcess::didGetSandboxExtensionsForBlobFiles(uint64_t requestID, SandboxExtension::HandleArray&& handles)
-{
-    if (auto handler = m_sandboxExtensionForBlobsCompletionHandlersStorageForNetworkProcess.take(requestID))
-        handler(WTFMove(handles));
-}
-    
 void NetworkProcess::updateTemporaryFileSandboxExtensions(const Vector<String>& paths, SandboxExtension::HandleArray& handles)
 {
     for (size_t i = 0; i < handles.size(); ++i) {
index dbc0bb0..ec8e57a 100644 (file)
@@ -193,7 +193,7 @@ public:
 #endif
 
 #if ENABLE(SANDBOX_EXTENSIONS)
-    void getSandboxExtensionsForBlobFiles(const Vector<String>& filenames, WTF::Function<void(SandboxExtension::HandleArray&&)>&& completionHandler);
+    void getSandboxExtensionsForBlobFiles(const Vector<String>& filenames, CompletionHandler<void(SandboxExtension::HandleArray&&)>&&);
     void updateTemporaryFileSandboxExtensions(const Vector<String>& paths, SandboxExtension::HandleArray&);
 #endif
 
@@ -314,10 +314,6 @@ private:
     void registerURLSchemeAsCORSEnabled(const String&) const;
     void registerURLSchemeAsCanDisplayOnlyIfCanRequest(const String&) const;
 
-#if ENABLE(SANDBOX_EXTENSIONS)
-    void didGetSandboxExtensionsForBlobFiles(uint64_t requestID, SandboxExtension::HandleArray&&);
-#endif
-
 #if ENABLE(INDEXED_DATABASE)
     void addIndexedDatabaseSession(PAL::SessionID, String&, SandboxExtension::Handle&);
     HashSet<WebCore::SecurityOriginData> indexedDatabaseOrigins(const String& path);
@@ -398,7 +394,6 @@ private:
 #endif
 
     HashMap<String, RefPtr<SandboxExtension>> m_blobTemporaryFileSandboxExtensions;
-    HashMap<uint64_t, WTF::Function<void(SandboxExtension::HandleArray&&)>> m_sandboxExtensionForBlobsCompletionHandlersStorageForNetworkProcess;
     
     Deque<CrossThreadTask> m_storageTasks;
     Lock m_storageTaskMutex;
index 0bf653f..721ab6c 100644 (file)
@@ -73,10 +73,6 @@ messages -> NetworkProcess LegacyReceiver {
     CancelPrepareToSuspend()
     ProcessDidResume()
 
-#if ENABLE(SANDBOX_EXTENSIONS)
-    DidGetSandboxExtensionsForBlobFiles(uint64_t requestID, WebKit::SandboxExtension::HandleArray extensions)
-#endif
-
     WriteBlobToFilePath(WebCore::URL blobURL, String path, WebKit::SandboxExtension::Handle handle, uint64_t callbackID)
 
     PreconnectTo(WebCore::URL url, enum:bool WebCore::StoredCredentialsPolicy storedCredentialsPolicy);
index 4408db8..6415626 100644 (file)
@@ -133,11 +133,12 @@ bool NetworkResourceLoadParameters::decode(IPC::Decoder& decoder, NetworkResourc
             return false;
         result.request.setHTTPBody(WTFMove(formData));
 
-        SandboxExtension::HandleArray requestBodySandboxExtensionHandles;
-        if (!decoder.decode(requestBodySandboxExtensionHandles))
+        std::optional<SandboxExtension::HandleArray> requestBodySandboxExtensionHandles;
+        decoder >> requestBodySandboxExtensionHandles;
+        if (!requestBodySandboxExtensionHandles)
             return false;
-        for (size_t i = 0; i < requestBodySandboxExtensionHandles.size(); ++i) {
-            if (auto extension = SandboxExtension::create(WTFMove(requestBodySandboxExtensionHandles[i])))
+        for (size_t i = 0; i < requestBodySandboxExtensionHandles->size(); ++i) {
+            if (auto extension = SandboxExtension::create(WTFMove(requestBodySandboxExtensionHandles->at(i))))
                 result.requestBodySandboxExtensions.append(WTFMove(extension));
         }
     }
index c02108f..188d36c 100644 (file)
@@ -237,6 +237,12 @@ static HashMap<IPC::Connection::UniqueID, Connection*>& allConnections()
     return map;
 }
 
+static HashMap<uintptr_t, HashMap<uint64_t, CompletionHandler<void(Decoder*)>>>& asyncReplyHandlerMap()
+{
+    static NeverDestroyed<HashMap<uintptr_t, HashMap<uint64_t, CompletionHandler<void(Decoder*)>>>> map;
+    return map.get();
+}
+    
 Connection::Connection(Identifier identifier, bool isServer, Client& client)
     : m_client(client)
     , m_uniqueID(generateObjectIdentifier<UniqueIDType>())
@@ -271,6 +277,12 @@ Connection::~Connection()
     ASSERT(!isValid());
 
     allConnections().remove(m_uniqueID);
+    
+    auto map = asyncReplyHandlerMap().take(reinterpret_cast<uintptr_t>(this));
+    for (auto& handler : map.values()) {
+        if (handler)
+            handler(nullptr);
+    }
 }
 
 Connection* Connection::connection(UniqueID uniqueID)
@@ -948,6 +960,21 @@ void Connection::enqueueIncomingMessage(std::unique_ptr<Decoder> incomingMessage
 void Connection::dispatchMessage(Decoder& decoder)
 {
     RELEASE_ASSERT(isValid());
+    if (decoder.messageReceiverName() == "AsyncReply") {
+        std::optional<uint64_t> listenerID;
+        decoder >> listenerID;
+        if (!listenerID) {
+            ASSERT_NOT_REACHED();
+            return;
+        }
+        auto handler = takeAsyncReplyHandler(*this, *listenerID);
+        if (!handler) {
+            ASSERT_NOT_REACHED();
+            return;
+        }
+        handler(&decoder);
+        return;
+    }
     m_client.didReceiveMessage(*this, decoder);
 }
 
@@ -1093,6 +1120,36 @@ void Connection::dispatchIncomingMessages()
     }
 }
 
+uint64_t nextAsyncReplyHandlerID()
+{
+    static uint64_t identifier { 0 };
+    return ++identifier;
+}
+
+void addAsyncReplyHandler(Connection& connection, uint64_t identifier, CompletionHandler<void(Decoder*)>&& completionHandler)
+{
+    auto result = asyncReplyHandlerMap().ensure(reinterpret_cast<uintptr_t>(&connection), [] {
+        return HashMap<uint64_t, CompletionHandler<void(Decoder*)>>();
+    }).iterator->value.add(identifier, WTFMove(completionHandler));
+    ASSERT_UNUSED(result, result.isNewEntry);
+}
+
+CompletionHandler<void(Decoder*)> takeAsyncReplyHandler(Connection& connection, uint64_t identifier)
+{
+    auto iterator = asyncReplyHandlerMap().find(reinterpret_cast<uintptr_t>(&connection));
+    if (iterator != asyncReplyHandlerMap().end()) {
+        if (!iterator->value.isValidKey(identifier)) {
+            ASSERT_NOT_REACHED();
+            connection.markCurrentlyDispatchedMessageAsInvalid();
+            return nullptr;
+        }
+        ASSERT(iterator->value.contains(identifier));
+        return iterator->value.take(identifier);
+    }
+    ASSERT_NOT_REACHED();
+    return nullptr;
+}
+
 void Connection::wakeUpRunLoop()
 {
     RunLoop::main().wakeUp();
index 72f0eaa..0a7b33f 100644 (file)
@@ -177,6 +177,7 @@ public:
 
     void postConnectionDidCloseOnConnectionWorkQueue();
 
+    template<typename T, typename... Args> void sendWithAsyncReply(T&& message, CompletionHandler<void(Args...)>&& args, uint64_t destinationID = 0);
     template<typename T> bool send(T&& message, uint64_t destinationID, OptionSet<SendOption> sendOptions = { });
     template<typename T> void sendWithReply(T&& message, uint64_t destinationID, FunctionDispatcher& replyDispatcher, Function<void(std::optional<typename CodingType<typename T::Reply>::Type>)>&& replyHandler);
     template<typename T> bool sendSync(T&& message, typename T::Reply&& reply, uint64_t destinationID, Seconds timeout = Seconds::infinity(), OptionSet<SendSyncOption> sendSyncOptions = { });
@@ -410,6 +411,28 @@ bool Connection::send(T&& message, uint64_t destinationID, OptionSet<SendOption>
     return sendMessage(WTFMove(encoder), sendOptions);
 }
 
+uint64_t nextAsyncReplyHandlerID();
+void addAsyncReplyHandler(Connection&, uint64_t, CompletionHandler<void(Decoder*)>&&);
+CompletionHandler<void(Decoder*)> takeAsyncReplyHandler(Connection&, uint64_t);
+
+template<typename T, typename... Args>
+void Connection::sendWithAsyncReply(T&& message, CompletionHandler<void(Args...)>&& completionHandler, uint64_t destinationID)
+{
+    COMPILE_ASSERT(!T::isSync, AsyncMessageExpected);
+
+    auto encoder = std::make_unique<Encoder>(T::receiverName(), T::name(), destinationID);
+    uint64_t listenerID = nextAsyncReplyHandlerID();
+    encoder->encode(listenerID);
+    encoder->encode(message.arguments());
+    sendMessage(WTFMove(encoder), { });
+    addAsyncReplyHandler(*this, listenerID, [completionHandler = WTFMove(completionHandler)] (Decoder* decoder) mutable {
+        if (decoder && !decoder->isInvalid())
+            T::callReply(*decoder, WTFMove(completionHandler));
+        else
+            T::cancelReply(WTFMove(completionHandler));
+    });
+}
+
 template<typename T>
 void Connection::sendWithReply(T&& message, uint64_t destinationID, FunctionDispatcher& replyDispatcher, Function<void(std::optional<typename CodingType<typename T::Reply>::Type>)>&& replyHandler)
 {
index 98dce74..294796b 100644 (file)
@@ -94,6 +94,8 @@ public:
 
     static const bool isIPCEncoder = true;
 
+    void encode(uint64_t);
+
 private:
     uint8_t* grow(unsigned alignment, size_t);
 
@@ -101,7 +103,6 @@ private:
     void encode(uint8_t);
     void encode(uint16_t);
     void encode(uint32_t);
-    void encode(uint64_t);
     void encode(int16_t);
     void encode(int32_t);
     void encode(int64_t);
index 6247426..50da248 100644 (file)
@@ -187,4 +187,28 @@ void handleMessageDelayed(Connection& connection, Decoder& decoder, std::unique_
     callMemberFunction(WTFMove(arguments), WTFMove(completionHandler), object, function);
 }
 
+template<typename T, typename C, typename MF>
+void handleMessageAsync(Connection& connection, Decoder& decoder, C* object, MF function)
+{
+    std::optional<uint64_t> listenerID;
+    decoder >> listenerID;
+    if (!listenerID) {
+        ASSERT(decoder.isInvalid());
+        return;
+    }
+    
+    typename CodingType<typename T::Arguments>::Type arguments;
+    if (!decoder.decode(arguments)) {
+        ASSERT(decoder.isInvalid());
+        return;
+    }
+
+    typename T::AsyncReply completionHandler = [listenerID = *listenerID, connection = makeRef(connection)] (auto&&... args) mutable {
+        auto encoder = std::make_unique<Encoder>("AsyncReply", T::asyncMessageReplyName(), 0);
+        *encoder << listenerID;
+        T::send(WTFMove(encoder), WTFMove(connection), args...);
+    };
+    callMemberFunction(WTFMove(arguments), WTFMove(completionHandler), object, function);
+}
+
 } // namespace IPC
index 4d89602..c16cf05 100644 (file)
@@ -29,6 +29,7 @@ from webkit import parser
 WANTS_CONNECTION_ATTRIBUTE = 'WantsConnection'
 LEGACY_RECEIVER_ATTRIBUTE = 'LegacyReceiver'
 DELAYED_ATTRIBUTE = 'Delayed'
+ASYNC_ATTRIBUTE = 'Async'
 
 _license_header = """/*
  * Copyright (C) 2010-2018 Apple Inc. All rights reserved.
@@ -96,6 +97,10 @@ def reply_parameter_type(type):
     return '%s&' % type
 
 
+def move_type(type):
+    return '%s&&' % type
+
+
 def arguments_type(message):
     return 'std::tuple<%s>' % ', '.join(function_parameter_type(parameter.type, parameter.kind) for parameter in message.parameters)
 
@@ -113,20 +118,25 @@ def message_to_struct_declaration(message):
     result.append('\n')
     result.append('    static IPC::StringReference receiverName() { return messageReceiverName(); }\n')
     result.append('    static IPC::StringReference name() { return IPC::StringReference("%s"); }\n' % message.name)
-    result.append('    static const bool isSync = %s;\n' % ('false', 'true')[message.reply_parameters != None])
+    result.append('    static const bool isSync = %s;\n' % ('false', 'true')[message.reply_parameters != None and not message.has_attribute(ASYNC_ATTRIBUTE)])
     result.append('\n')
     if message.reply_parameters != None:
-        if message.has_attribute(DELAYED_ATTRIBUTE):
-            send_parameters = [(function_parameter_type(x.type, x.kind), x.name) for x in message.reply_parameters]
-            result.append('    using DelayedReply = CompletionHandler<void(')
-            if len(send_parameters):
-                result.append('%s' % ', '.join([' '.join(x) for x in send_parameters]))
-            result.append(')>;\n')
+        send_parameters = [(function_parameter_type(x.type, x.kind), x.name) for x in message.reply_parameters]
+        if message.has_attribute(DELAYED_ATTRIBUTE) or message.has_attribute(ASYNC_ATTRIBUTE):
+            completion_handler_parameters = '%s' % ', '.join([' '.join(x) for x in send_parameters])
+            if message.has_attribute(ASYNC_ATTRIBUTE):
+                move_parameters = ', '.join([move_type(x.type) for x in message.reply_parameters])
+                result.append('    static void callReply(IPC::Decoder&, CompletionHandler<void(%s)>&&);\n' % move_parameters)
+                result.append('    static void cancelReply(CompletionHandler<void(%s)>&&);\n' % move_parameters)
+                result.append('    static IPC::StringReference asyncMessageReplyName() { return { "%sReply" }; }\n' % message.name)
+                result.append('    using AsyncReply')
+            else:
+                result.append('    using DelayedReply')
+            result.append(' = CompletionHandler<void(%s)>;\n' % completion_handler_parameters)
             result.append('    static void send(std::unique_ptr<IPC::Encoder>&&, IPC::Connection&')
             if len(send_parameters):
-                result.append(', %s' % ', '.join([' '.join(x) for x in send_parameters]))
+                result.append(', %s' % completion_handler_parameters)
             result.append(');\n')
-
         result.append('    typedef %s Reply;\n' % reply_type(message))
 
     if len(function_parameters):
@@ -276,6 +286,9 @@ def async_message_statement(receiver, message):
     dispatch_function_args = ['decoder', 'this', '&%s' % handler_function(receiver, message)]
 
     dispatch_function = 'handleMessage'
+    if message.has_attribute(ASYNC_ATTRIBUTE):
+        dispatch_function += 'Async'
+        dispatch_function_args.insert(0, 'connection')
 
     if message.has_attribute(WANTS_CONNECTION_ATTRIBUTE):
         dispatch_function_args.insert(0, 'connection')
@@ -292,12 +305,14 @@ def sync_message_statement(receiver, message):
     dispatch_function = 'handleMessage'
     if message.has_attribute(DELAYED_ATTRIBUTE):
         dispatch_function += 'Delayed'
+    if message.has_attribute(ASYNC_ATTRIBUTE):
+        dispatch_function += 'Async'
 
     wants_connection = message.has_attribute(DELAYED_ATTRIBUTE) or message.has_attribute(WANTS_CONNECTION_ATTRIBUTE)
 
     result = []
     result.append('    if (decoder.messageName() == Messages::%s::%s::name()) {\n' % (receiver.name, message.name))
-    result.append('        IPC::%s<Messages::%s::%s>(%sdecoder, %sreplyEncoder, this, &%s);\n' % (dispatch_function, receiver.name, message.name, 'connection, ' if wants_connection else '', '' if message.has_attribute(DELAYED_ATTRIBUTE) else '*', handler_function(receiver, message)))
+    result.append('        IPC::%s<Messages::%s::%s>(%sdecoder, %sreplyEncoder, this, &%s);\n' % (dispatch_function, receiver.name, message.name, 'connection, ' if wants_connection else '', '' if message.has_attribute(DELAYED_ATTRIBUTE) or message.has_attribute(ASYNC_ATTRIBUTE) else '*', handler_function(receiver, message)))
     result.append('        return;\n')
     result.append('    }\n')
     return surround_in_condition(''.join(result), message.condition)
@@ -525,20 +540,32 @@ def generate_message_handler(file):
             result += ['#include %s\n' % header]
     result.append('\n')
 
-    sync_delayed_messages = []
+    delayed_or_async_messages = []
     for message in receiver.messages:
-        if message.reply_parameters != None and message.has_attribute(DELAYED_ATTRIBUTE):
-            sync_delayed_messages.append(message)
+        if message.reply_parameters != None and (message.has_attribute(DELAYED_ATTRIBUTE) or message.has_attribute(ASYNC_ATTRIBUTE)):
+            delayed_or_async_messages.append(message)
 
-    if sync_delayed_messages:
+    if delayed_or_async_messages:
         result.append('namespace Messages {\n\nnamespace %s {\n\n' % receiver.name)
 
-        for message in sync_delayed_messages:
+        for message in delayed_or_async_messages:
             send_parameters = [(function_parameter_type(x.type, x.kind), x.name) for x in message.reply_parameters]
 
             if message.condition:
                 result.append('#if %s\n\n' % message.condition)
 
+            if message.has_attribute(ASYNC_ATTRIBUTE):
+                move_parameters = message.name, ', '.join([move_type(x.type) for x in message.reply_parameters])
+                result.append('void %s::callReply(IPC::Decoder& decoder, CompletionHandler<void(%s)>&& completionHandler)\n{\n' % move_parameters)
+                for x in message.reply_parameters:
+                    result.append('    std::optional<%s> %s;\n' % (x.type, x.name))
+                    result.append('    decoder >> %s;\n' % x.name)
+                    result.append('    if (!%s) {\n        ASSERT_NOT_REACHED();\n        return;\n    }\n' % x.name)
+                result.append('    completionHandler(WTFMove(*%s));\n}\n\n' % (', *'.join(x.name for x in message.reply_parameters)))
+                result.append('void %s::cancelReply(CompletionHandler<void(%s)>&& completionHandler)\n{\n    completionHandler(' % move_parameters)
+                result.append(', '.join(['{ }' for x in message.reply_parameters]))
+                result.append(');\n}\n\n')
+
             result.append('void %s::send(std::unique_ptr<IPC::Encoder>&& encoder, IPC::Connection& connection' % (message.name))
             if len(send_parameters):
                 result.append(', %s' % ', '.join([' '.join(x) for x in send_parameters]))
@@ -558,7 +585,7 @@ def generate_message_handler(file):
     async_messages = []
     sync_messages = []
     for message in receiver.messages:
-        if message.reply_parameters is not None:
+        if message.reply_parameters is not None and not message.has_attribute(ASYNC_ATTRIBUTE):
             sync_messages.append(message)
         else:
             async_messages.append(message)
@@ -586,7 +613,7 @@ def generate_message_handler(file):
         result.append('    ASSERT_NOT_REACHED();\n')
         result.append('}\n')
 
-    result.append('\n} // namespace WebKit\n')
+    result.append('\n} // namespace WebKit\n\n')
 
     if receiver.condition:
         result.append('\n#endif // %s\n' % receiver.condition)
index de8467e..a5d5b74 100644 (file)
@@ -46,8 +46,11 @@ bool WebIDBResult::decode(IPC::Decoder& decoder, WebIDBResult& result)
         return false;
     result.m_resultData = WTFMove(*resultData);
 
-    if (!SandboxExtension::HandleArray::decode(decoder, result.m_handles))
+    std::optional<SandboxExtension::HandleArray> handles;
+    decoder >> handles;
+    if (!handles)
         return false;
+    result.m_handles = WTFMove(*handles);
 
     return true;
 }
index cb53aad..116b9c8 100644 (file)
@@ -77,14 +77,16 @@ public:
     public:
         HandleArray();
         HandleArray(HandleArray&&) = default;
+        HandleArray& operator=(HandleArray&&) = default;
         ~HandleArray();
         void allocate(size_t);
         Handle& operator[](size_t i);
+        Handle& at(size_t i) { return operator[](i); }
         const Handle& operator[](size_t i) const;
         size_t size() const;
         void encode(IPC::Encoder&) const;
-        static bool decode(IPC::Decoder&, HandleArray&);
-       
+        static std::optional<HandleArray> decode(IPC::Decoder&);
+
     private:
 #if ENABLE(SANDBOX_EXTENSIONS)
         Vector<Handle> m_data;
@@ -128,7 +130,7 @@ inline size_t SandboxExtension::HandleArray::size() const { return 0; }
 inline const SandboxExtension::Handle& SandboxExtension::HandleArray::operator[](size_t) const { return m_emptyHandle; }
 inline SandboxExtension::Handle& SandboxExtension::HandleArray::operator[](size_t) { return m_emptyHandle; }
 inline void SandboxExtension::HandleArray::encode(IPC::Encoder&) const { }
-inline bool SandboxExtension::HandleArray::decode(IPC::Decoder&, HandleArray&) { return true; }
+inline auto SandboxExtension::HandleArray::decode(IPC::Decoder&) -> std::optional<HandleArray> { return {{ }}; }
 inline RefPtr<SandboxExtension> SandboxExtension::create(Handle&&) { return nullptr; }
 inline bool SandboxExtension::createHandle(const String&, Type, Handle&) { return true; }
 inline bool SandboxExtension::createHandleWithoutResolvingPath(const String&, Type, Handle&) { return true; }
index 47e88f4..b484ac0 100644 (file)
@@ -175,8 +175,11 @@ bool WebProcessCreationParameters::decode(IPC::Decoder& decoder, WebProcessCreat
         return false;
     parameters.injectedBundlePathExtensionHandle = WTFMove(*injectedBundlePathExtensionHandle);
 
-    if (!decoder.decode(parameters.additionalSandboxExtensionHandles))
+    std::optional<SandboxExtension::HandleArray> additionalSandboxExtensionHandles;
+    decoder >> additionalSandboxExtensionHandles;
+    if (!additionalSandboxExtensionHandles)
         return false;
+    parameters.additionalSandboxExtensionHandles = WTFMove(*additionalSandboxExtensionHandles);
     if (!decoder.decode(parameters.initializationUserData))
         return false;
     if (!decoder.decode(parameters.applicationCacheDirectory))
index b771a24..3f23ad2 100644 (file)
@@ -190,20 +190,22 @@ void SandboxExtension::HandleArray::encode(IPC::Encoder& encoder) const
         encoder << handle;
 }
 
-bool SandboxExtension::HandleArray::decode(IPC::Decoder& decoder, SandboxExtension::HandleArray& handles)
+std::optional<SandboxExtension::HandleArray> SandboxExtension::HandleArray::decode(IPC::Decoder& decoder)
 {
-    uint64_t size;
-    if (!decoder.decode(size))
-        return false;
-    handles.allocate(size);
-    for (size_t i = 0; i < size; i++) {
+    std::optional<uint64_t> size;
+    decoder >> size;
+    if (!size)
+        return std::nullopt;
+    SandboxExtension::HandleArray handles;
+    handles.allocate(*size);
+    for (size_t i = 0; i < *size; ++i) {
         std::optional<SandboxExtension::Handle> handle;
         decoder >> handle;
         if (!handle)
-            return false;
+            return std::nullopt;
         handles[i] = WTFMove(*handle);
     }
-    return true;
+    return WTFMove(handles);
 }
 
 RefPtr<SandboxExtension> SandboxExtension::create(Handle&& handle)
index a0d0878..f14a2fb 100644 (file)
@@ -692,7 +692,7 @@ void NetworkProcessProxy::sendProcessDidTransitionToBackground()
 }
 
 #if ENABLE(SANDBOX_EXTENSIONS)
-void NetworkProcessProxy::getSandboxExtensionsForBlobFiles(uint64_t requestID, const Vector<String>& paths)
+void NetworkProcessProxy::getSandboxExtensionsForBlobFiles(const Vector<String>& paths, Messages::NetworkProcessProxy::GetSandboxExtensionsForBlobFiles::AsyncReply&& reply)
 {
     SandboxExtension::HandleArray extensions;
     extensions.allocate(paths.size());
@@ -700,8 +700,7 @@ void NetworkProcessProxy::getSandboxExtensionsForBlobFiles(uint64_t requestID, c
         // ReadWrite is required for creating hard links, which is something that might be done with these extensions.
         SandboxExtension::createHandle(paths[i], SandboxExtension::Type::ReadWrite, extensions[i]);
     }
-    
-    send(Messages::NetworkProcess::DidGetSandboxExtensionsForBlobFiles(requestID, extensions), 0);
+    reply(WTFMove(extensions));
 }
 #endif
 
index 3a0896a..4f684be 100644 (file)
@@ -30,6 +30,7 @@
 #if ENABLE(LEGACY_CUSTOM_PROTOCOL_MANAGER)
 #include "LegacyCustomProtocolManagerProxy.h"
 #endif
+#include "NetworkProcessProxyMessages.h"
 #include "ProcessLauncher.h"
 #include "ProcessThrottler.h"
 #include "ProcessThrottlerClient.h"
@@ -156,7 +157,7 @@ private:
 #endif
 
 #if ENABLE(SANDBOX_EXTENSIONS)
-    void getSandboxExtensionsForBlobFiles(uint64_t requestID, const Vector<String>& paths);
+    void getSandboxExtensionsForBlobFiles(const Vector<String>& paths, Messages::NetworkProcessProxy::GetSandboxExtensionsForBlobFiles::AsyncReply&&);
 #endif
 
 #if ENABLE(SERVICE_WORKER)
index eef24e1..3d6c1a2 100644 (file)
@@ -56,7 +56,7 @@ messages -> NetworkProcessProxy LegacyReceiver {
     RetrieveCacheStorageParameters(PAL::SessionID sessionID)
 
 #if ENABLE(SANDBOX_EXTENSIONS)
-    GetSandboxExtensionsForBlobFiles(uint64_t requestID, Vector<String> paths)
+    GetSandboxExtensionsForBlobFiles(Vector<String> paths) -> (WebKit::SandboxExtension::HandleArray extensions) Async
 #endif
 
 #if ENABLE(SERVICE_WORKER)
index 06b6617..bb90de1 100644 (file)
@@ -50,8 +50,11 @@ bool MediaDeviceSandboxExtensions::decode(IPC::Decoder& decoder, MediaDeviceSand
     if (!decoder.decode(result.m_ids))
         return false;
 
-    if (!SandboxExtension::HandleArray::decode(decoder, result.m_handles))
+    std::optional<SandboxExtension::HandleArray> handles;
+    decoder >> handles;
+    if (!handles)
         return false;
+    result.m_handles = WTFMove(*handles);
 
     return true;
 }