Changeset 264687 in webkit


Ignore:
Timestamp:
Jul 21, 2020, 6:11:14 PM (5 years ago)
Author:
commit-queue@webkit.org
Message:

Safari does not present CertificateInfo for service-worker served documents
https://bugs.webkit.org/show_bug.cgi?id=206403

Patch by Alex Christensen <achristensen@webkit.org> on 2020-07-21
Reviewed by Brady Eidson.

This is actually just a failing test that reproduces the issue 100% of the time.

  • TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm:
  • TestWebKitAPI/cocoa/HTTPServer.h:
  • TestWebKitAPI/cocoa/HTTPServer.mm:

(TestWebKitAPI::HTTPServer::cancel):
(TestWebKitAPI::HTTPServer::HTTPServer):
(TestWebKitAPI::m_protocol):
(TestWebKitAPI::HTTPServer::totalRequests const):
(TestWebKitAPI::HTTPServer::respondToRequests):
(TestWebKitAPI::Connection::terminate):
(TestWebKitAPI::Connection::cancel):
(TestWebKitAPI::Connection::terminate const): Deleted.

Location:
trunk/Tools
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Tools/ChangeLog

    r264680 r264687  
     12020-07-21  Alex Christensen  <achristensen@webkit.org>
     2
     3        Safari does not present CertificateInfo for service-worker served documents
     4        https://bugs.webkit.org/show_bug.cgi?id=206403
     5
     6        Reviewed by Brady Eidson.
     7
     8        This is actually just a failing test that reproduces the issue 100% of the time.
     9
     10        * TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm:
     11        * TestWebKitAPI/cocoa/HTTPServer.h:
     12        * TestWebKitAPI/cocoa/HTTPServer.mm:
     13        (TestWebKitAPI::HTTPServer::cancel):
     14        (TestWebKitAPI::HTTPServer::HTTPServer):
     15        (TestWebKitAPI::m_protocol):
     16        (TestWebKitAPI::HTTPServer::totalRequests const):
     17        (TestWebKitAPI::HTTPServer::respondToRequests):
     18        (TestWebKitAPI::Connection::terminate):
     19        (TestWebKitAPI::Connection::cancel):
     20        (TestWebKitAPI::Connection::terminate const): Deleted.
     21
    1222020-07-21  Jonathan Bedard  <jbedard@apple.com>
    223
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm

    r263066 r264687  
    3131#import "Test.h"
    3232#import "TestNavigationDelegate.h"
     33#import "TestUIDelegate.h"
    3334#import "TestWKWebView.h"
    3435#import <WebKit/WKPreferencesPrivate.h>
     
    21132114    TestWebKitAPI::Util::run(&doneRemoving);
    21142115}
     2116
     2117#if HAVE(NETWORK_FRAMEWORK) && HAVE(TLS_PROTOCOL_VERSION_T)
     2118
     2119static bool isTestServerTrust(SecTrustRef trust)
     2120{
     2121    if (!trust)
     2122        return false;
     2123    if (SecTrustGetCertificateCount(trust) != 1)
     2124        return false;
     2125    if (![adoptNS((NSString *)SecCertificateCopySubjectSummary(SecTrustGetCertificateAtIndex(trust, 0))) isEqualToString:@"Me"])
     2126        return false;
     2127    return true;
     2128}
     2129
     2130enum class ResponseType { Synthetic, Cached, Fetched };
     2131static void runTest(ResponseType responseType)
     2132{
     2133    using namespace TestWebKitAPI;
     2134   
     2135    __block bool removedAnyExistingData = false;
     2136    [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] modifiedSince:[NSDate distantPast] completionHandler:^() {
     2137        removedAnyExistingData = true;
     2138    }];
     2139    TestWebKitAPI::Util::run(&removedAnyExistingData);
     2140
     2141    static const char* main =
     2142    "<script>"
     2143    "try {"
     2144    "    navigator.serviceWorker.register('/sw.js').then(function(reg) {"
     2145    "        if (reg.active) {"
     2146    "            alert('worker unexpectedly already active');"
     2147    "            return;"
     2148    "        }"
     2149    "        worker = reg.installing;"
     2150    "        worker.addEventListener('statechange', function() {"
     2151    "            if (worker.state == 'activated')"
     2152    "                alert('successfully registered');"
     2153    "        });"
     2154    "    }).catch(function(error) {"
     2155    "        alert('Registration failed with: ' + error);"
     2156    "    });"
     2157    "} catch(e) {"
     2158    "    alert('Exception: ' + e);"
     2159    "}"
     2160    "</script>";
     2161   
     2162    const char* js = nullptr;
     2163    const char* expectedAlert = nullptr;
     2164    size_t expectedServerRequests1 = 0;
     2165    size_t expectedServerRequests2 = 0;
     2166
     2167    switch (responseType) {
     2168    case ResponseType::Synthetic:
     2169        js = "self.addEventListener('fetch', (event) => { event.respondWith(new Response(new Blob(['<script>alert(\"synthetic response\")</script>'], {type: 'text/html'}))); })";
     2170        expectedAlert = "synthetic response";
     2171        expectedServerRequests1 = 2;
     2172        expectedServerRequests2 = 2;
     2173        break;
     2174    case ResponseType::Cached:
     2175        js = "self.addEventListener('install', (event) => { event.waitUntil( caches.open('v1').then((cache) => { return cache.addAll(['/cached.html']); }) ); });"
     2176            "self.addEventListener('fetch', (event) => { event.respondWith(caches.match('/cached.html')) });";
     2177        expectedAlert = "loaded from cache";
     2178        expectedServerRequests1 = 3;
     2179        expectedServerRequests2 = 3;
     2180        break;
     2181    case ResponseType::Fetched:
     2182        js = "self.addEventListener('fetch', (event) => { event.respondWith(fetch('/fetched.html')) });";
     2183        expectedAlert = "fetched from server";
     2184        expectedServerRequests1 = 2;
     2185        expectedServerRequests2 = 3;
     2186        break;
     2187    }
     2188
     2189    HTTPServer server({
     2190        { "/", { main } },
     2191        { "/sw.js", { {{ "Content-Type", "application/javascript" }}, js } },
     2192        { "/cached.html", { "<script>alert('loaded from cache')</script>" } },
     2193        { "/fetched.html", { "<script>alert('fetched from server')</script>" } },
     2194    }, HTTPServer::Protocol::Https);
     2195
     2196    auto webView = adoptNS([WKWebView new]);
     2197
     2198    auto delegate = adoptNS([TestNavigationDelegate new]);
     2199    [delegate setDidReceiveAuthenticationChallenge:^(WKWebView *, NSURLAuthenticationChallenge *challenge, void (^callback)(NSURLSessionAuthChallengeDisposition, NSURLCredential *)) {
     2200        EXPECT_WK_STREQ(challenge.protectionSpace.authenticationMethod, NSURLAuthenticationMethodServerTrust);
     2201        callback(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
     2202    }];
     2203    webView.get().navigationDelegate = delegate.get();
     2204
     2205    [webView loadRequest:server.request()];
     2206    EXPECT_WK_STREQ([webView _test_waitForAlert], "successfully registered");
     2207
     2208    EXPECT_EQ(server.totalRequests(), expectedServerRequests1);
     2209    EXPECT_TRUE(isTestServerTrust(webView.get().serverTrust));
     2210    if (responseType != ResponseType::Fetched)
     2211        server.cancel();
     2212
     2213    [webView reload];
     2214    EXPECT_WK_STREQ([webView _test_waitForAlert], expectedAlert);
     2215    EXPECT_EQ(server.totalRequests(), expectedServerRequests2);
     2216    EXPECT_NULL(webView.get().serverTrust); // FIXME: This should be EXPECT_TRUE(isTestServerTrust(webView.get().serverTrust));
     2217}
     2218
     2219TEST(ServiceWorkers, ServerTrust)
     2220{
     2221    runTest(ResponseType::Synthetic);
     2222    runTest(ResponseType::Cached);
     2223    runTest(ResponseType::Fetched);
     2224}
     2225
     2226#endif // HAVE(NETWORK_FRAMEWORK) && HAVE(TLS_PROTOCOL_VERSION_T)
  • trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.h

    r263879 r264687  
    5353    NSURLRequest *request(const String& path = "/"_str) const;
    5454    size_t totalRequests() const;
     55    void cancel();
    5556
    5657    static void respondWithChallengeThenOK(Connection);
     
    5859private:
    5960    static RetainPtr<nw_parameters_t> listenerParameters(Protocol, CertificateVerifier&&);
    60     static void respondToRequests(Connection, RefPtr<RequestData>);
     61    static void respondToRequests(Connection, Ref<RequestData>);
    6162
    62     RefPtr<RequestData> m_requestData;
     63    Ref<RequestData> m_requestData;
    6364    RetainPtr<nw_listener_t> m_listener;
    6465    Protocol m_protocol { Protocol::Http };
     
    7273    void receiveBytes(CompletionHandler<void(Vector<uint8_t>&&)>&&) const;
    7374    void receiveHTTPRequest(CompletionHandler<void(Vector<char>&&)>&&, Vector<char>&& buffer = { }) const;
    74     void terminate() const;
     75    void terminate();
     76    void cancel();
    7577
    7678private:
  • trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.mm

    r263879 r264687  
    5050    size_t requestCount { 0 };
    5151    const HashMap<String, HTTPResponse> requestMap;
     52    Vector<Connection> connections;
    5253};
    5354
     
    8990}
    9091
     92void HTTPServer::cancel()
     93{
     94    __block bool cancelled = false;
     95    nw_listener_set_state_changed_handler(m_listener.get(), ^(nw_listener_state_t state, nw_error_t error) {
     96        ASSERT_UNUSED(error, !error);
     97        if (state == nw_listener_state_cancelled)
     98            cancelled = true;
     99    });
     100    nw_listener_cancel(m_listener.get());
     101    Util::run(&cancelled);
     102    m_listener = nullptr;
     103    for (auto& connection : std::exchange(m_requestData->connections, { }))
     104        connection.cancel();
     105}
     106
    91107HTTPServer::HTTPServer(std::initializer_list<std::pair<String, HTTPResponse>> responses, Protocol protocol, CertificateVerifier&& verifier)
    92     : m_requestData(adoptRef(new RequestData(responses)))
     108    : m_requestData(adoptRef(*new RequestData(responses)))
    93109    , m_listener(adoptNS(nw_listener_create(listenerParameters(protocol, WTFMove(verifier)).get())))
    94110    , m_protocol(protocol)
     
    96112    nw_listener_set_queue(m_listener.get(), dispatch_get_main_queue());
    97113    nw_listener_set_new_connection_handler(m_listener.get(), makeBlockPtr([requestData = m_requestData](nw_connection_t connection) {
     114        requestData->connections.append(Connection(connection));
    98115        nw_connection_set_queue(connection, dispatch_get_main_queue());
    99116        nw_connection_start(connection);
     
    104121
    105122HTTPServer::HTTPServer(Function<void(Connection)>&& connectionHandler, Protocol protocol)
    106     : m_listener(adoptNS(nw_listener_create(listenerParameters(protocol, nullptr).get())))
     123    : m_requestData(adoptRef(*new RequestData({ })))
     124    , m_listener(adoptNS(nw_listener_create(listenerParameters(protocol, nullptr).get())))
    107125    , m_protocol(protocol)
    108126{
    109127    nw_listener_set_queue(m_listener.get(), dispatch_get_main_queue());
    110     nw_listener_set_new_connection_handler(m_listener.get(), makeBlockPtr([connectionHandler = WTFMove(connectionHandler)] (nw_connection_t connection) {
     128    nw_listener_set_new_connection_handler(m_listener.get(), makeBlockPtr([requestData = m_requestData, connectionHandler = WTFMove(connectionHandler)] (nw_connection_t connection) {
     129        requestData->connections.append(Connection(connection));
    111130        nw_connection_set_queue(connection, dispatch_get_main_queue());
    112131        nw_connection_start(connection);
     
    140159size_t HTTPServer::totalRequests() const
    141160{
    142     if (!m_requestData)
    143         return 0;
    144161    return m_requestData->requestCount;
    145162}
     
    188205}
    189206
    190 void HTTPServer::respondToRequests(Connection connection, RefPtr<RequestData> requestData)
    191 {
    192     connection.receiveHTTPRequest([connection, requestData] (Vector<char>&& request) {
     207void HTTPServer::respondToRequests(Connection connection, Ref<RequestData> requestData)
     208{
     209    connection.receiveHTTPRequest([connection, requestData] (Vector<char>&& request) mutable {
    193210        if (!request.size())
    194211            return;
     
    292309}
    293310
    294 void Connection::terminate() const
     311void Connection::terminate()
    295312{
    296313    nw_connection_cancel(m_connection.get());
     314}
     315
     316void Connection::cancel()
     317{
     318    __block bool cancelled = false;
     319    nw_connection_set_state_changed_handler(m_connection.get(), ^(nw_connection_state_t state, nw_error_t error) {
     320        ASSERT_UNUSED(error, !error);
     321        if (state == nw_connection_state_cancelled)
     322            cancelled = true;
     323    });
     324    nw_connection_cancel(m_connection.get());
     325    Util::run(&cancelled);
     326    m_connection = nullptr;
    297327}
    298328
Note: See TracChangeset for help on using the changeset viewer.