⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 277336 in webkit


Ignore:
Timestamp:
May 11, 2021, 12:47:50 PM (5 years ago)
Author:
commit-queue@webkit.org
Message:

Add SPI to restrict networking to a set of hosts
https://bugs.webkit.org/show_bug.cgi?id=225426
<rdar://77571521>

Patch by Alex Christensen <achristensen@webkit.org> on 2021-05-11
Reviewed by Tim Horton.

Source/WebCore:

In r259392 I added SPI to turn network access on and off, but a client needs finer grained control.
This uses the same infrastructure to add a set of hosts to allow. Setting it to nil (the default) allows all hosts,
but setting it to an empty set allows no network access. This accomplishes the same ability as the old SPI, so I'm deprecating it
with this as a replacement. The new ability to specify a finite number of hosts to allow creates a limited WKWebView.

  • Modules/websockets/ThreadableWebSocketChannel.cpp:

(WebCore::ThreadableWebSocketChannel::validateURL):

  • loader/ResourceLoadNotifier.cpp:

(WebCore::ResourceLoadNotifier::dispatchWillSendRequest):

  • page/Page.cpp:

(WebCore::Page::allowsLoadFromURL const):

  • page/Page.h:

(WebCore::Page::loadsFromNetwork const): Deleted.

  • page/PageConfiguration.h:

Source/WebKit:

  • Shared/WebPageCreationParameters.cpp:

(WebKit::WebPageCreationParameters::encode const):
(WebKit::WebPageCreationParameters::decode):

  • Shared/WebPageCreationParameters.h:
  • UIProcess/API/APIPageConfiguration.cpp:

(API::PageConfiguration::copy const):

  • UIProcess/API/APIPageConfiguration.h:

(API::PageConfiguration::allowedNetworkHosts const):
(API::PageConfiguration::setAllowedNetworkHosts):
(API::PageConfiguration::loadsFromNetwork const): Deleted.
(API::PageConfiguration::setLoadsFromNetwork): Deleted.

  • UIProcess/API/Cocoa/WKWebViewConfiguration.mm:

(-[WKWebViewConfiguration _setLoadsFromNetwork:]):
(-[WKWebViewConfiguration _loadsFromNetwork]):
(-[WKWebViewConfiguration _setAllowedNetworkHosts:]):
(-[WKWebViewConfiguration _allowedNetworkHosts]):

  • UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h:
  • UIProcess/WebPageProxy.cpp:

(WebKit::WebPageProxy::creationParameters):

  • WebProcess/WebPage/WebPage.cpp:

(WebKit::m_lastNavigationWasAppBound):

Tools:

  • TestWebKitAPI/Tests/WebKitCocoa/ContentRuleListNotification.mm:

(TEST):
(webSocketAcceptValue): Deleted.

  • TestWebKitAPI/Tests/WebKitCocoa/WKURLSchemeHandler-1.mm:
  • TestWebKitAPI/cocoa/HTTPServer.h:

(TestWebKitAPI::Connection::webSocketHandshake):

  • TestWebKitAPI/cocoa/HTTPServer.mm:

(TestWebKitAPI::Connection::webSocketHandshake):

Location:
trunk
Files:
20 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r277330 r277336  
     12021-05-11  Alex Christensen  <achristensen@webkit.org>
     2
     3        Add SPI to restrict networking to a set of hosts
     4        https://bugs.webkit.org/show_bug.cgi?id=225426
     5        <rdar://77571521>
     6
     7        Reviewed by Tim Horton.
     8
     9        In r259392 I added SPI to turn network access on and off, but a client needs finer grained control.
     10        This uses the same infrastructure to add a set of hosts to allow.  Setting it to nil (the default) allows all hosts,
     11        but setting it to an empty set allows no network access.  This accomplishes the same ability as the old SPI, so I'm deprecating it
     12        with this as a replacement.  The new ability to specify a finite number of hosts to allow creates a limited WKWebView.
     13
     14        * Modules/websockets/ThreadableWebSocketChannel.cpp:
     15        (WebCore::ThreadableWebSocketChannel::validateURL):
     16        * loader/ResourceLoadNotifier.cpp:
     17        (WebCore::ResourceLoadNotifier::dispatchWillSendRequest):
     18        * page/Page.cpp:
     19        (WebCore::Page::allowsLoadFromURL const):
     20        * page/Page.h:
     21        (WebCore::Page::loadsFromNetwork const): Deleted.
     22        * page/PageConfiguration.h:
     23
    1242021-05-11  Megan Gardner  <megan_gardner@apple.com>
    225
  • trunk/Source/WebCore/Modules/websockets/ThreadableWebSocketChannel.cpp

    r275078 r277336  
    9090    ValidatedURL validatedURL { requestedURL, true };
    9191    if (auto* page = document.page()) {
    92         if (!page->loadsFromNetwork())
     92        if (!page->allowsLoadFromURL(requestedURL))
    9393            return { };
    9494#if ENABLE(CONTENT_EXTENSIONS)
  • trunk/Source/WebCore/loader/ResourceLoadNotifier.cpp

    r260709 r277336  
    138138            if (!m_frame.isMainFrame() || (m_initialRequestIdentifier && *m_initialRequestIdentifier != identifier))
    139139                request = { };
    140         } else if (!page->loadsFromNetwork() && request.url().protocolIsInHTTPFamily())
     140        } else if (!page->allowsLoadFromURL(request.url()))
    141141            request = { };
    142142    }
  • trunk/Source/WebCore/page/Page.cpp

    r277295 r277336  
    306306#endif
    307307    , m_corsDisablingPatterns(WTFMove(pageConfiguration.corsDisablingPatterns))
     308    , m_allowedNetworkHosts(WTFMove(pageConfiguration.allowedNetworkHosts))
    308309    , m_loadsSubresources(pageConfiguration.loadsSubresources)
    309     , m_loadsFromNetwork(pageConfiguration.loadsFromNetwork)
    310310    , m_shouldRelaxThirdPartyCookieBlocking(pageConfiguration.shouldRelaxThirdPartyCookieBlocking)
    311311    , m_httpsUpgradeEnabled(pageConfiguration.httpsUpgradeEnabled)
     
    33003300}
    33013301
     3302bool Page::allowsLoadFromURL(const URL& url) const
     3303{
     3304    if (!m_allowedNetworkHosts)
     3305        return true;
     3306    if (!url.protocolIsInHTTPFamily() && !url.protocolIs("ws") && !url.protocolIs("wss"))
     3307        return true;
     3308    return m_allowedNetworkHosts->contains(url.host().toStringWithoutCopying());
     3309}
     3310
    33023311void Page::applicationWillResignActive()
    33033312{
  • trunk/Source/WebCore/page/Page.h

    r276952 r277336  
    795795
    796796    bool loadsSubresources() const { return m_loadsSubresources; }
    797     bool loadsFromNetwork() const { return m_loadsFromNetwork; }
     797    bool allowsLoadFromURL(const URL&) const;
    798798    ShouldRelaxThirdPartyCookieBlocking shouldRelaxThirdPartyCookieBlocking() const { return m_shouldRelaxThirdPartyCookieBlocking; }
    799799
     
    11431143    Vector<UserContentURLPattern> m_corsDisablingPatterns;
    11441144    Vector<UserStyleSheet> m_userStyleSheetsPendingInjection;
     1145    Optional<HashSet<String>> m_allowedNetworkHosts;
    11451146    bool m_isTakingSnapshotsForApplicationSuspension { false };
    11461147    bool m_loadsSubresources { true };
    1147     bool m_loadsFromNetwork { true };
    11481148    bool m_canUseCredentialStorage { true };
    11491149    ShouldRelaxThirdPartyCookieBlocking m_shouldRelaxThirdPartyCookieBlocking { ShouldRelaxThirdPartyCookieBlocking::No };
  • trunk/Source/WebCore/page/PageConfiguration.h

    r274192 r277336  
    133133    // FIXME: These should be all be Settings.
    134134    bool loadsSubresources { true };
    135     bool loadsFromNetwork { true };
     135    Optional<HashSet<String>> allowedNetworkHosts;
    136136    bool userScriptsShouldWaitUntilNotification { true };
    137137    ShouldRelaxThirdPartyCookieBlocking shouldRelaxThirdPartyCookieBlocking { ShouldRelaxThirdPartyCookieBlocking::No };
  • trunk/Source/WebKit/ChangeLog

    r277331 r277336  
     12021-05-11  Alex Christensen  <achristensen@webkit.org>
     2
     3        Add SPI to restrict networking to a set of hosts
     4        https://bugs.webkit.org/show_bug.cgi?id=225426
     5        <rdar://77571521>
     6
     7        Reviewed by Tim Horton.
     8
     9        * Shared/WebPageCreationParameters.cpp:
     10        (WebKit::WebPageCreationParameters::encode const):
     11        (WebKit::WebPageCreationParameters::decode):
     12        * Shared/WebPageCreationParameters.h:
     13        * UIProcess/API/APIPageConfiguration.cpp:
     14        (API::PageConfiguration::copy const):
     15        * UIProcess/API/APIPageConfiguration.h:
     16        (API::PageConfiguration::allowedNetworkHosts const):
     17        (API::PageConfiguration::setAllowedNetworkHosts):
     18        (API::PageConfiguration::loadsFromNetwork const): Deleted.
     19        (API::PageConfiguration::setLoadsFromNetwork): Deleted.
     20        * UIProcess/API/Cocoa/WKWebViewConfiguration.mm:
     21        (-[WKWebViewConfiguration _setLoadsFromNetwork:]):
     22        (-[WKWebViewConfiguration _loadsFromNetwork]):
     23        (-[WKWebViewConfiguration _setAllowedNetworkHosts:]):
     24        (-[WKWebViewConfiguration _allowedNetworkHosts]):
     25        * UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h:
     26        * UIProcess/WebPageProxy.cpp:
     27        (WebKit::WebPageProxy::creationParameters):
     28        * WebProcess/WebPage/WebPage.cpp:
     29        (WebKit::m_lastNavigationWasAppBound):
     30
    1312021-05-11  Brent Fulgham  <bfulgham@apple.com>
    232
  • trunk/Source/WebKit/Shared/WebPageCreationParameters.cpp

    r276892 r277336  
    152152    encoder << corsDisablingPatterns;
    153153    encoder << loadsSubresources;
    154     encoder << loadsFromNetwork;
     154    encoder << allowedNetworkHosts;
    155155    encoder << userScriptsShouldWaitUntilNotification;
    156156    encoder << crossOriginAccessControlCheckEnabled;
     
    510510    parameters.loadsSubresources = *loadsSubresources;
    511511
    512     Optional<bool> loadsFromNetwork;
    513     decoder >> loadsFromNetwork;
    514     if (!loadsFromNetwork)
    515         return WTF::nullopt;
    516     parameters.loadsFromNetwork = *loadsFromNetwork;
     512    Optional<Optional<HashSet<String>>> allowedNetworkHosts;
     513    decoder >> allowedNetworkHosts;
     514    if (!allowedNetworkHosts)
     515        return WTF::nullopt;
     516    parameters.allowedNetworkHosts = *allowedNetworkHosts;
    517517
    518518    Optional<bool> userScriptsShouldWaitUntilNotification;
  • trunk/Source/WebKit/Shared/WebPageCreationParameters.h

    r274192 r277336  
    223223    bool userScriptsShouldWaitUntilNotification { true };
    224224    bool loadsSubresources { true };
    225     bool loadsFromNetwork { true };
     225    Optional<HashSet<String>> allowedNetworkHosts;
    226226
    227227    bool crossOriginAccessControlCheckEnabled { true };
  • trunk/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp

    r272920 r277336  
    8888    copy->m_processDisplayName = this->m_processDisplayName;
    8989    copy->m_loadsSubresources = this->m_loadsSubresources;
    90     copy->m_loadsFromNetwork = this->m_loadsFromNetwork;
     90    copy->m_allowedNetworkHosts = this->m_allowedNetworkHosts;
    9191#if ENABLE(APP_BOUND_DOMAINS)
    9292    copy->m_ignoresAppBoundDomains = this->m_ignoresAppBoundDomains;
  • trunk/Source/WebKit/UIProcess/API/APIPageConfiguration.h

    r276880 r277336  
    3131#include <wtf/GetPtr.h>
    3232#include <wtf/HashMap.h>
     33#include <wtf/HashSet.h>
    3334#include <wtf/text/WTFString.h>
    3435
     
    147148    void setLoadsSubresources(bool loads) { m_loadsSubresources = loads; }
    148149
    149     bool loadsFromNetwork() const { return m_loadsFromNetwork; }
    150     void setLoadsFromNetwork(bool loads) { m_loadsFromNetwork = loads; }
     150    const Optional<HashSet<WTF::String>>& allowedNetworkHosts() const { return m_allowedNetworkHosts; }
     151    void setAllowedNetworkHosts(Optional<HashSet<WTF::String>>&& hosts) { m_allowedNetworkHosts = WTFMove(hosts); }
    151152
    152153#if ENABLE(APP_BOUND_DOMAINS)
     
    206207    WTF::String m_processDisplayName;
    207208    bool m_loadsSubresources { true };
    208     bool m_loadsFromNetwork { true };
     209    Optional<HashSet<WTF::String>> m_allowedNetworkHosts;
    209210   
    210211#if ENABLE(APP_BOUND_DOMAINS)
  • trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfiguration.mm

    r277030 r277336  
    953953- (void)_setLoadsFromNetwork:(BOOL)loads
    954954{
    955     _pageConfiguration->setLoadsFromNetwork(loads);
     955    _pageConfiguration->setAllowedNetworkHosts(loads ? WTF::nullopt : Optional<HashSet<String>> { HashSet<String> { } });
    956956}
    957957
    958958- (BOOL)_loadsFromNetwork
    959959{
    960     return _pageConfiguration->loadsFromNetwork();
     960    return _pageConfiguration->allowedNetworkHosts() == WTF::nullopt;
     961}
     962
     963- (void)_setAllowedNetworkHosts:(NSSet<NSString *> *)hosts
     964{
     965    if (!hosts)
     966        return _pageConfiguration->setAllowedNetworkHosts(WTF::nullopt);
     967    HashSet<String> set;
     968    for (NSString *host in hosts)
     969        set.add(host);
     970    _pageConfiguration->setAllowedNetworkHosts(WTFMove(set));
     971}
     972
     973- (NSSet<NSString *> *)_allowedNetworkHosts
     974{
     975    const auto& hosts = _pageConfiguration->allowedNetworkHosts();
     976    if (!hosts)
     977        return nil;
     978    NSMutableSet<NSString *> *set = [NSMutableSet setWithCapacity:hosts->size()];
     979    for (const auto& host : *hosts)
     980        [set addObject:host];
     981    return set;
    961982}
    962983
  • trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h

    r277030 r277336  
    8080@property (nonatomic, setter=_setCrossOriginAccessControlCheckEnabled:) BOOL _crossOriginAccessControlCheckEnabled WK_API_AVAILABLE(macos(11.0), ios(14.0));
    8181
    82 @property (nonatomic, setter=_setLoadsFromNetwork:) BOOL _loadsFromNetwork WK_API_AVAILABLE(macos(11.0), ios(14.0));
     82@property (nonatomic, setter=_setLoadsFromNetwork:) BOOL _loadsFromNetwork WK_API_DEPRECATED_WITH_REPLACEMENT("_allowedNetworkHosts", macos(11.0, WK_MAC_TBA), ios(14.0, WK_IOS_TBA));
     83@property (nonatomic, copy, setter=_setAllowedNetworkHosts:) NSSet<NSString *> *_allowedNetworkHosts WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
    8384@property (nonatomic, setter=_setLoadsSubresources:) BOOL _loadsSubresources WK_API_AVAILABLE(macos(11.0), ios(14.0));
    8485@property (nonatomic, setter=_setIgnoresAppBoundDomains:) BOOL _ignoresAppBoundDomains WK_API_AVAILABLE(macos(11.0), ios(14.0));
  • trunk/Source/WebKit/UIProcess/WebPageProxy.cpp

    r277331 r277336  
    80348034    parameters.corsDisablingPatterns = corsDisablingPatterns();
    80358035    parameters.userScriptsShouldWaitUntilNotification = m_configuration->userScriptsShouldWaitUntilNotification();
    8036     parameters.loadsFromNetwork = m_configuration->loadsFromNetwork();
     8036    parameters.allowedNetworkHosts = m_configuration->allowedNetworkHosts();
    80378037    parameters.loadsSubresources = m_configuration->loadsSubresources();
    80388038    parameters.crossOriginAccessControlCheckEnabled = m_configuration->crossOriginAccessControlCheckEnabled();
  • trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp

    r277295 r277336  
    606606    pageConfiguration.userScriptsShouldWaitUntilNotification = parameters.userScriptsShouldWaitUntilNotification;
    607607    pageConfiguration.loadsSubresources = parameters.loadsSubresources;
    608     pageConfiguration.loadsFromNetwork = parameters.loadsFromNetwork;
     608    pageConfiguration.allowedNetworkHosts = parameters.allowedNetworkHosts;
    609609    pageConfiguration.shouldRelaxThirdPartyCookieBlocking = parameters.shouldRelaxThirdPartyCookieBlocking;
    610610    pageConfiguration.httpsUpgradeEnabled = parameters.httpsUpgradeEnabled;
  • trunk/Tools/ChangeLog

    r277319 r277336  
     12021-05-11  Alex Christensen  <achristensen@webkit.org>
     2
     3        Add SPI to restrict networking to a set of hosts
     4        https://bugs.webkit.org/show_bug.cgi?id=225426
     5        <rdar://77571521>
     6
     7        Reviewed by Tim Horton.
     8
     9        * TestWebKitAPI/Tests/WebKitCocoa/ContentRuleListNotification.mm:
     10        (TEST):
     11        (webSocketAcceptValue): Deleted.
     12        * TestWebKitAPI/Tests/WebKitCocoa/WKURLSchemeHandler-1.mm:
     13        * TestWebKitAPI/cocoa/HTTPServer.h:
     14        (TestWebKitAPI::Connection::webSocketHandshake):
     15        * TestWebKitAPI/cocoa/HTTPServer.mm:
     16        (TestWebKitAPI::Connection::webSocketHandshake):
     17
    1182021-05-11  Diego Pino Garcia  <dpino@igalia.com>
    219
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ContentRuleListNotification.mm

    r277268 r277336  
    4444#import <WebKit/_WKWebsiteDataStoreConfiguration.h>
    4545#import <wtf/RetainPtr.h>
    46 #import <wtf/SHA1.h>
    4746#import <wtf/URL.h>
    4847#import <wtf/cocoa/VectorCocoa.h>
    49 #import <wtf/text/Base64.h>
    5048#import <wtf/text/WTFString.h>
    5149
     
    222220}
    223221
    224 static String webSocketAcceptValue(const Vector<char>& request)
    225 {
    226     constexpr auto* keyHeaderField = "Sec-WebSocket-Key: ";
    227     const char* keyBegin = strnstr(request.data(), keyHeaderField, request.size()) + strlen(keyHeaderField);
    228     EXPECT_NOT_NULL(keyBegin);
    229     const char* keyEnd = strnstr(keyBegin, "\r\n", request.size() + (keyBegin - request.data()));
    230     EXPECT_NOT_NULL(keyEnd);
    231 
    232     constexpr auto* webSocketKeyGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
    233     SHA1 sha1;
    234     sha1.addBytes(reinterpret_cast<const uint8_t*>(keyBegin), keyEnd - keyBegin);
    235     sha1.addBytes(reinterpret_cast<const uint8_t*>(webSocketKeyGUID), strlen(webSocketKeyGUID));
    236     SHA1::Digest hash;
    237     sha1.computeHash(hash);
    238     return base64Encode(hash.data(), SHA1::hashSize);
    239 }
    240 
    241222TEST(ContentRuleList, ResourceTypes)
    242223{
    243224    using namespace TestWebKitAPI;
    244225    HTTPServer webSocketServer([](Connection connection) {
    245         connection.receiveHTTPRequest([=](Vector<char>&& request) {
    246             connection.send(HTTPResponse(101, {
    247                 { "Upgrade", "websocket" },
    248                 { "Connection", "Upgrade" },
    249                 { "Sec-WebSocket-Accept", webSocketAcceptValue(request) }
    250             }).serialize(HTTPResponse::IncludeContentLength::No));
    251         });
     226        connection.webSocketHandshake();
    252227    });
    253228    auto serverPort = webSocketServer.port();
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKURLSchemeHandler-1.mm

    r276932 r277336  
    4949#import <wtf/Vector.h>
    5050#import <wtf/WeakObjCPtr.h>
     51#import <wtf/text/StringConcatenateNumbers.h>
    5152#import <wtf/text/StringHash.h>
    5253#import <wtf/text/WTFString.h>
     
    11011102TEST(URLSchemeHandler, LoadsFromNetwork)
    11021103{
    1103     TestWebKitAPI::HTTPServer server({
     1104    using namespace TestWebKitAPI;
     1105    HTTPServer server({
    11041106        { "/", { {{ "Access-Control-Allow-Origin", "*" }}, "test content" } }
    11051107    });
    11061108
    1107     bool loadSuccess = false;
    1108     bool loadFail = false;
     1109    HTTPServer webSocketServer([](Connection connection) {
     1110        connection.webSocketHandshake();
     1111    });
     1112
     1113    Optional<bool> loadSuccess;
     1114    Optional<bool> webSocketSuccess;
    11091115    bool done = false;
    11101116
     
    11151121
    11161122    [handler setStartURLSchemeTaskHandler:[&](WKWebView *, id<WKURLSchemeTask> task) {
    1117         if ([task.request.URL.path isEqualToString:@"/main.html"]) {
    1118             NSData *data = [[NSString stringWithFormat:@"<script>"
    1119                 "fetch('http://127.0.0.1:%d/').then(()=>{"
    1120                     "fetch('/loadSuccess')"
     1123        NSString *path = task.request.URL.path;
     1124        if ([path isEqualToString:@"/main.html"]) {
     1125            respond(task, [NSString stringWithFormat:@"<script>"
     1126                "function checkWebSockets() {"
     1127                    "var ws = new WebSocket('ws://127.0.0.1:%d');"
     1128                    "ws.onerror = function() { fetch('/webSocketFail') };"
     1129                    "ws.onopen = function() { fetch('/webSocketSuccess') };"
     1130                "}"
     1131                "fetch('http://localhost:%d/').then(()=>{"
     1132                    "fetch('/loadSuccess').then(()=>{ checkWebSockets() })"
    11211133                "}).catch(()=>{"
    1122                     "var ws = new WebSocket('ws://127.0.0.1:%d');"
    1123                     "ws.onerror = function() { fetch('/loadFail') };"
     1134                    "fetch('/loadFail').then(()=>{ checkWebSockets() })"
    11241135                "})"
    1125                 "</script>", server.port(), server.port()] dataUsingEncoding:NSUTF8StringEncoding];
    1126             [task didReceiveResponse:adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:@"text/html" expectedContentLength:data.length textEncodingName:nil]).get()];
    1127             [task didReceiveData:data];
    1128             [task didFinish];
    1129         } else if ([task.request.URL.path isEqualToString:@"/loadSuccess"]) {
     1136                "</script>", webSocketServer.port(), server.port()].UTF8String);
     1137        } else if ([path isEqualToString:@"/loadSuccess"]) {
     1138            respond(task, "hi");
    11301139            loadSuccess = true;
     1140        } else if ([path isEqualToString:@"/loadFail"]) {
     1141            respond(task, "hi");
     1142            loadSuccess = false;
     1143        } else if ([path isEqualToString:@"/webSocketSuccess"]) {
     1144            webSocketSuccess = true;
    11311145            done = true;
    1132         } else if ([task.request.URL.path isEqualToString:@"/loadFail"]) {
    1133             loadFail = true;
     1146        } else if ([path isEqualToString:@"/webSocketFail"]) {
     1147            webSocketSuccess = false;
    11341148            done = true;
    11351149        } else
     
    11371151    }];
    11381152   
    1139     {
     1153    auto runTest = [&] {
     1154        loadSuccess = WTF::nullopt;
     1155        webSocketSuccess = WTF::nullopt;
     1156        done = false;
    11401157        auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
    11411158        [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"test://host1/main.html"]]];
    11421159        TestWebKitAPI::Util::run(&done);
    1143     }
    1144     EXPECT_TRUE(loadSuccess);
    1145     EXPECT_FALSE(loadFail);
     1160    };
     1161
     1162    runTest();
     1163    EXPECT_TRUE(*loadSuccess);
     1164    EXPECT_TRUE(*webSocketSuccess);
    11461165    EXPECT_EQ(server.totalRequests(), 1u);
    1147    
    1148     loadSuccess = false;
    1149     loadFail = false;
    1150     done = false;
    11511166
    11521167    configuration.get()._loadsFromNetwork = NO;
    1153     {
     1168    runTest();
     1169    EXPECT_FALSE(*loadSuccess);
     1170    EXPECT_FALSE(*webSocketSuccess);
     1171    EXPECT_EQ(server.totalRequests(), 1u);
     1172   
     1173    configuration.get()._allowedNetworkHosts = [NSSet set];
     1174    runTest();
     1175    EXPECT_FALSE(*loadSuccess);
     1176    EXPECT_FALSE(*webSocketSuccess);
     1177    EXPECT_EQ(server.totalRequests(), 1u);
     1178
     1179    configuration.get()._allowedNetworkHosts = nil;
     1180    runTest();
     1181    EXPECT_TRUE(*loadSuccess);
     1182    EXPECT_TRUE(*webSocketSuccess);
     1183    EXPECT_EQ(server.totalRequests(), 2u);
     1184
     1185    configuration.get()._allowedNetworkHosts = [NSSet setWithObject:@"localhost"];
     1186    runTest();
     1187    EXPECT_TRUE(*loadSuccess);
     1188    EXPECT_FALSE(*webSocketSuccess);
     1189    EXPECT_EQ(server.totalRequests(), 3u);
     1190}
     1191
     1192TEST(URLSchemeHandler, AllowedNetworkHostsRedirect)
     1193{
     1194    TestWebKitAPI::HTTPServer serverLocalhost({
     1195        { "/redirectTarget", { {{ "Access-Control-Allow-Origin", "*" }}, "test content" } }
     1196    });
     1197    TestWebKitAPI::HTTPServer server127001({
     1198        { "/", { 301, {
     1199            { "Access-Control-Allow-Origin", "*" },
     1200            { "Location", makeString("http://localhost:", serverLocalhost.port(), "/redirectTarget") }
     1201        }}},
     1202    });
     1203
     1204    Optional<bool> loadSuccess;
     1205    bool done = false;
     1206
     1207    auto handler = adoptNS([TestURLSchemeHandler new]);
     1208
     1209    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
     1210    [configuration setURLSchemeHandler:handler.get() forURLScheme:@"test"];
     1211
     1212    [handler setStartURLSchemeTaskHandler:[&](WKWebView *, id<WKURLSchemeTask> task) {
     1213        NSString *path = task.request.URL.path;
     1214        if ([path isEqualToString:@"/main.html"]) {
     1215            respond(task, [NSString stringWithFormat:@"<script>"
     1216                "fetch('http://127.0.0.1:%d/').then(()=>{"
     1217                    "fetch('/loadSuccess')"
     1218                "}).catch(()=>{"
     1219                    "fetch('/loadFail')"
     1220                "})"
     1221                "</script>", server127001.port()].UTF8String);
     1222        } else if ([path isEqualToString:@"/loadSuccess"]) {
     1223            loadSuccess = true;
     1224            done = true;
     1225        } else if ([path isEqualToString:@"/loadFail"]) {
     1226            loadSuccess = false;
     1227            done = true;
     1228        }
     1229    }];
     1230
     1231    auto runTest = [&] {
     1232        loadSuccess = WTF::nullopt;
     1233        done = false;
     1234        configuration.get().websiteDataStore = [WKWebsiteDataStore nonPersistentDataStore];
    11541235        auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
    11551236        [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"test://host1/main.html"]]];
    11561237        TestWebKitAPI::Util::run(&done);
    1157     }
    1158     EXPECT_FALSE(loadSuccess);
    1159     EXPECT_TRUE(loadFail);
    1160     EXPECT_EQ(server.totalRequests(), 1u);
     1238    };
     1239
     1240    runTest();
     1241    EXPECT_TRUE(*loadSuccess);
     1242    EXPECT_EQ(serverLocalhost.totalRequests(), 1u);
     1243    EXPECT_EQ(server127001.totalRequests(), 1u);
     1244   
     1245    configuration.get()._allowedNetworkHosts = [NSSet set];
     1246    runTest();
     1247    EXPECT_FALSE(*loadSuccess);
     1248    EXPECT_EQ(serverLocalhost.totalRequests(), 1u);
     1249    EXPECT_EQ(server127001.totalRequests(), 1u);
     1250
     1251    configuration.get()._allowedNetworkHosts = [NSSet setWithObject:@"127.0.0.1"];
     1252    runTest();
     1253    EXPECT_FALSE(*loadSuccess);
     1254    EXPECT_EQ(serverLocalhost.totalRequests(), 1u);
     1255    EXPECT_EQ(server127001.totalRequests(), 2u);
    11611256}
    11621257
  • trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.h

    r272908 r277336  
    7272    void receiveBytes(CompletionHandler<void(Vector<uint8_t>&&)>&&) const;
    7373    void receiveHTTPRequest(CompletionHandler<void(Vector<char>&&)>&&, Vector<char>&& buffer = { }) const;
     74    void webSocketHandshake(CompletionHandler<void()>&& = { });
    7475    void terminate();
    7576    void cancel();
  • trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.mm

    r273897 r277336  
    3131#import <wtf/CompletionHandler.h>
    3232#import <wtf/RetainPtr.h>
     33#import <wtf/SHA1.h>
    3334#import <wtf/ThreadSafeRefCounted.h>
     35#import <wtf/text/Base64.h>
    3436#import <wtf/text/StringBuilder.h>
    3537#import <wtf/text/WTFString.h>
     
    324326            completionHandler();
    325327    }).get());
     328}
     329
     330void Connection::webSocketHandshake(CompletionHandler<void()>&& connectionHandler)
     331{
     332    receiveHTTPRequest([connection = Connection(*this), connectionHandler = WTFMove(connectionHandler)] (Vector<char>&& request) mutable {
     333
     334        auto webSocketAcceptValue = [] (const Vector<char>& request) {
     335            constexpr auto* keyHeaderField = "Sec-WebSocket-Key: ";
     336            const char* keyBegin = strnstr(request.data(), keyHeaderField, request.size()) + strlen(keyHeaderField);
     337            ASSERT(keyBegin);
     338            const char* keyEnd = strnstr(keyBegin, "\r\n", request.size() + (keyBegin - request.data()));
     339            ASSERT(keyEnd);
     340
     341            constexpr auto* webSocketKeyGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
     342            SHA1 sha1;
     343            sha1.addBytes(reinterpret_cast<const uint8_t*>(keyBegin), keyEnd - keyBegin);
     344            sha1.addBytes(reinterpret_cast<const uint8_t*>(webSocketKeyGUID), strlen(webSocketKeyGUID));
     345            SHA1::Digest hash;
     346            sha1.computeHash(hash);
     347            return base64Encode(hash.data(), SHA1::hashSize);
     348        };
     349
     350        connection.send(HTTPResponse(101, {
     351            { "Upgrade", "websocket" },
     352            { "Connection", "Upgrade" },
     353            { "Sec-WebSocket-Accept", webSocketAcceptValue(request) }
     354        }).serialize(HTTPResponse::IncludeContentLength::No), WTFMove(connectionHandler));
     355    });
    326356}
    327357
Note: See TracChangeset for help on using the changeset viewer.