Title: [294492] trunk/Tools/TestWebKitAPI
Revision
294492
Author
achristen...@apple.com
Date
2022-05-19 10:40:17 -0700 (Thu, 19 May 2022)

Log Message

Begin using coroutines in testing code
https://bugs.webkit.org/show_bug.cgi?id=235730

Reviewed by Darin Adler.

co_await is nicer than nested lambdas.
This begins WebKit's use of C++ coroutines in a small, incomplete, and low-risk way by using it with test code.

Canonical link: https://commits.webkit.org/250751@main

Modified Paths

Diff

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKWebViewEvaluateJavaScript.mm (294491 => 294492)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKWebViewEvaluateJavaScript.mm	2022-05-19 17:13:30 UTC (rev 294491)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKWebViewEvaluateJavaScript.mm	2022-05-19 17:40:17 UTC (rev 294492)
@@ -336,14 +336,12 @@
     // Evaluating _javascript_ in such a document should fail and result in an error.
 
     using namespace TestWebKitAPI;
-    HTTPServer server([](Connection connection) {
-        connection.receiveHTTPRequest([=](Vector<char>&&) {
-            constexpr auto response = "HTTP/1.1 200 OK\r\n"
-                "Content-Length: 12\r\n"
-                "Content-Disposition: attachment; filename=fromHeader.txt;\r\n\r\n"
-                "Hello world!"_s;
-            connection.send(response);
-        });
+    HTTPServer server(HTTPServer::UseCoroutines::Yes, [](Connection connection) -> Task {
+        co_await connection.awaitableReceiveHTTPRequest();
+        co_await connection.awaitableSend("HTTP/1.1 200 OK\r\n"
+            "Content-Length: 12\r\n"
+            "Content-Disposition: attachment; filename=fromHeader.txt;\r\n\r\n"
+            "Hello world!"_s);
     });
     auto webView = adoptNS([TestWKWebView new]);
     [webView synchronouslyLoadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://127.0.0.1:%d/", server.port()]]]];

Modified: trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.h (294491 => 294492)


--- trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.h	2022-05-19 17:13:30 UTC (rev 294491)
+++ trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.h	2022-05-19 17:40:17 UTC (rev 294492)
@@ -26,6 +26,7 @@
 #pragma once
 
 #import <Network/Network.h>
+#import <experimental/coroutine>
 #import <wtf/CompletionHandler.h>
 #import <wtf/Forward.h>
 #import <wtf/HashMap.h>
@@ -39,6 +40,35 @@
 class Connection;
 struct HTTPResponse;
 
+template<typename PromiseType>
+struct CoroutineHandle {
+    CoroutineHandle(std::experimental::coroutine_handle<PromiseType>&& handle)
+        : handle(WTFMove(handle)) { }
+    CoroutineHandle(const CoroutineHandle&) = delete;
+    CoroutineHandle(CoroutineHandle&& other)
+        : handle(std::exchange(other.handle, nullptr)) { }
+    ~CoroutineHandle()
+    {
+        if (handle)
+            handle.destroy();
+    }
+    std::experimental::coroutine_handle<PromiseType> handle;
+};
+
+struct Task {
+    struct promise_type {
+        Task get_return_object() { return { std::experimental::coroutine_handle<promise_type>::from_promise(*this) }; }
+        std::experimental::suspend_never initial_suspend() { return { }; }
+        std::experimental::suspend_never final_suspend() noexcept { return { }; }
+        void unhandled_exception() { }
+        void return_void() { }
+    };
+    CoroutineHandle<promise_type> handle;
+};
+
+class ReceiveOperation;
+class SendOperation;
+
 class HTTPServer {
     WTF_MAKE_FAST_ALLOCATED;
 public:
@@ -48,6 +78,8 @@
 
     HTTPServer(std::initializer_list<std::pair<String, HTTPResponse>>, Protocol = Protocol::Http, CertificateVerifier&& = nullptr, RetainPtr<SecIdentityRef>&& = nullptr, std::optional<uint16_t> port = { });
     HTTPServer(Function<void(Connection)>&&, Protocol = Protocol::Http);
+    enum class UseCoroutines : bool { Yes };
+    HTTPServer(UseCoroutines, Function<Task(Connection)>&&, Protocol = Protocol::Http);
     ~HTTPServer();
     uint16_t port() const;
     String origin() const;
@@ -80,9 +112,12 @@
 public:
     void send(String&&, CompletionHandler<void()>&& = nullptr) const;
     void send(Vector<uint8_t>&&, CompletionHandler<void()>&& = nullptr) const;
+    void send(RetainPtr<dispatch_data_t>&&, CompletionHandler<void(bool)>&& = nullptr) const;
+    SendOperation awaitableSend(String&&);
     void sendAndReportError(Vector<uint8_t>&&, CompletionHandler<void(bool)>&&) const;
     void receiveBytes(CompletionHandler<void(Vector<uint8_t>&&)>&&, size_t minimumSize = 1) const;
     void receiveHTTPRequest(CompletionHandler<void(Vector<char>&&)>&&, Vector<char>&& buffer = { }) const;
+    ReceiveOperation awaitableReceiveHTTPRequest() const;
     void webSocketHandshake(CompletionHandler<void()>&& = { });
     void terminate();
     void cancel();
@@ -92,11 +127,33 @@
     Connection(nw_connection_t connection)
         : m_connection(connection) { }
 
-    void send(RetainPtr<dispatch_data_t>&&, CompletionHandler<void(bool)>&&) const;
-
     RetainPtr<nw_connection_t> m_connection;
 };
 
+class ReceiveOperation : public std::experimental::suspend_never {
+public:
+    ReceiveOperation(const Connection& connection)
+        : m_connection(connection) { }
+    bool await_ready() { return false; }
+    void await_suspend(std::experimental::coroutine_handle<>);
+    Vector<char> await_resume() { return WTFMove(m_result); }
+private:
+    Connection m_connection;
+    Vector<char> m_result;
+};
+
+class SendOperation : public std::experimental::suspend_never {
+public:
+    SendOperation(RetainPtr<dispatch_data_t>&& data, const Connection& connection)
+        : m_data(WTFMove(data))
+        , m_connection(connection) { }
+    bool await_ready() { return false; }
+    void await_suspend(std::experimental::coroutine_handle<>);
+private:
+    RetainPtr<dispatch_data_t> m_data;
+    Connection m_connection;
+};
+
 struct HTTPResponse {
     enum class TerminateConnection { No, Yes };
 

Modified: trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.mm (294491 => 294492)


--- trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.mm	2022-05-19 17:13:30 UTC (rev 294491)
+++ trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.mm	2022-05-19 17:40:17 UTC (rev 294492)
@@ -46,10 +46,11 @@
             map.add(pair.first, pair.second);
         return map;
     }(responses)) { }
-    
+
     size_t requestCount { 0 };
     HashMap<String, HTTPResponse> requestMap;
     Vector<Connection> connections;
+    Vector<CoroutineHandle<Task::promise_type>> coroutineHandles;
 };
 
 static RetainPtr<nw_protocol_definition_t> proxyDefinition(HTTPServer::Protocol protocol)
@@ -214,6 +215,21 @@
     startListening(m_listener.get());
 }
 
+HTTPServer::HTTPServer(UseCoroutines, WTF::Function<Task(Connection)>&& connectionHandler, Protocol protocol)
+    : m_requestData(adoptRef(*new RequestData({ })))
+    , m_listener(adoptNS(nw_listener_create(listenerParameters(protocol, nullptr, nullptr, { }).get())))
+    , m_protocol(protocol)
+{
+    nw_listener_set_queue(m_listener.get(), dispatch_get_main_queue());
+    nw_listener_set_new_connection_handler(m_listener.get(), makeBlockPtr([requestData = m_requestData, connectionHandler = WTFMove(connectionHandler)] (nw_connection_t connection) {
+        requestData->connections.append(Connection(connection));
+        nw_connection_set_queue(connection, dispatch_get_main_queue());
+        nw_connection_start(connection);
+        requestData->coroutineHandles.append(connectionHandler(Connection(connection)).handle);
+    }).get());
+    startListening(m_listener.get());
+}
+
 HTTPServer::~HTTPServer() = default;
 
 void HTTPServer::addResponse(String&& path, HTTPResponse&& response)
@@ -423,6 +439,31 @@
     });
 }
 
+ReceiveOperation Connection::awaitableReceiveHTTPRequest() const
+{
+    return { *this };
+}
+
+void ReceiveOperation::await_suspend(std::experimental::coroutine_handle<> handle)
+{
+    m_connection.receiveHTTPRequest([this, handle](Vector<char>&& result) mutable {
+        m_result = WTFMove(result);
+        handle();
+    });
+}
+
+void SendOperation::await_suspend(std::experimental::coroutine_handle<> handle)
+{
+    m_connection.send(WTFMove(m_data), [handle] (bool) mutable {
+        handle();
+    });
+}
+
+SendOperation Connection::awaitableSend(String&& message)
+{
+    return { dataFromString(WTFMove(message)), *this };
+}
+
 void Connection::send(String&& message, CompletionHandler<void()>&& completionHandler) const
 {
     send(dataFromString(WTFMove(message)), [completionHandler = WTFMove(completionHandler)] (bool) mutable {
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to