Changeset 260518 in webkit


Ignore:
Timestamp:
Apr 22, 2020 9:56:00 AM (4 years ago)
Author:
achristensen@apple.com
Message:

Add unit test for resuming downloads
https://bugs.webkit.org/show_bug.cgi?id=210852

Reviewed by Brady Eidson.

This is a test that we should've written years ago.
I made HTTPServer able to take a Function that takes a nw_connection_t to give it more power than declarative request/response pairs.
I made TestDownloadDelegate to be reused by future tests, like those I'm going to add for bug 210313.

  • TestWebKitAPI/SourcesCocoa.txt:
  • TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
  • TestWebKitAPI/Tests/WebKitCocoa/Download.mm:

(longString):
(TEST):

  • TestWebKitAPI/cocoa/HTTPServer.h:

(TestWebKitAPI::HTTPServer::totalRequests const): Deleted.

  • TestWebKitAPI/cocoa/HTTPServer.mm:

(TestWebKitAPI::HTTPServer::RequestData::RequestData):
(TestWebKitAPI::HTTPServer::listenerParameters):
(TestWebKitAPI::startListening):
(TestWebKitAPI::HTTPServer::HTTPServer):
(TestWebKitAPI::HTTPServer::totalRequests const):
(TestWebKitAPI::dataFromString):
(TestWebKitAPI::nullTerminatedRequest):
(TestWebKitAPI::HTTPServer::respondToRequests):

  • TestWebKitAPI/cocoa/TestDownloadDelegate.h: Added.
  • TestWebKitAPI/cocoa/TestDownloadDelegate.mm: Added.

(-[TestDownloadDelegate _downloadDidStart:]):
(-[TestDownloadDelegate _download:didReceiveServerRedirectToURL:]):
(-[TestDownloadDelegate _download:didReceiveResponse:]):
(-[TestDownloadDelegate _download:didReceiveData:]):
(-[TestDownloadDelegate _download:decideDestinationWithSuggestedFilename:completionHandler:]):
(-[TestDownloadDelegate _downloadDidFinish:]):
(-[TestDownloadDelegate _download:didFailWithError:]):
(-[TestDownloadDelegate _downloadDidCancel:]):
(-[TestDownloadDelegate _download:didReceiveAuthenticationChallenge:completionHandler:]):
(-[TestDownloadDelegate _download:didCreateDestination:]):

  • TestWebKitAPI/cocoa/TestNavigationDelegate.h:
  • TestWebKitAPI/cocoa/TestNavigationDelegate.mm:

(-[TestNavigationDelegate webView:decidePolicyForNavigationResponse:decisionHandler:]):

Location:
trunk/Tools
Files:
2 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/Tools/ChangeLog

    r260515 r260518  
     12020-04-22  Alex Christensen  <achristensen@webkit.org>
     2
     3        Add unit test for resuming downloads
     4        https://bugs.webkit.org/show_bug.cgi?id=210852
     5
     6        Reviewed by Brady Eidson.
     7
     8        This is a test that we should've written years ago.
     9        I made HTTPServer able to take a Function that takes a nw_connection_t to give it more power than declarative request/response pairs.
     10        I made TestDownloadDelegate to be reused by future tests, like those I'm going to add for  bug 210313.
     11
     12        * TestWebKitAPI/SourcesCocoa.txt:
     13        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
     14        * TestWebKitAPI/Tests/WebKitCocoa/Download.mm:
     15        (longString):
     16        (TEST):
     17        * TestWebKitAPI/cocoa/HTTPServer.h:
     18        (TestWebKitAPI::HTTPServer::totalRequests const): Deleted.
     19        * TestWebKitAPI/cocoa/HTTPServer.mm:
     20        (TestWebKitAPI::HTTPServer::RequestData::RequestData):
     21        (TestWebKitAPI::HTTPServer::listenerParameters):
     22        (TestWebKitAPI::startListening):
     23        (TestWebKitAPI::HTTPServer::HTTPServer):
     24        (TestWebKitAPI::HTTPServer::totalRequests const):
     25        (TestWebKitAPI::dataFromString):
     26        (TestWebKitAPI::nullTerminatedRequest):
     27        (TestWebKitAPI::HTTPServer::respondToRequests):
     28        * TestWebKitAPI/cocoa/TestDownloadDelegate.h: Added.
     29        * TestWebKitAPI/cocoa/TestDownloadDelegate.mm: Added.
     30        (-[TestDownloadDelegate _downloadDidStart:]):
     31        (-[TestDownloadDelegate _download:didReceiveServerRedirectToURL:]):
     32        (-[TestDownloadDelegate _download:didReceiveResponse:]):
     33        (-[TestDownloadDelegate _download:didReceiveData:]):
     34        (-[TestDownloadDelegate _download:decideDestinationWithSuggestedFilename:completionHandler:]):
     35        (-[TestDownloadDelegate _downloadDidFinish:]):
     36        (-[TestDownloadDelegate _download:didFailWithError:]):
     37        (-[TestDownloadDelegate _downloadDidCancel:]):
     38        (-[TestDownloadDelegate _download:didReceiveAuthenticationChallenge:completionHandler:]):
     39        (-[TestDownloadDelegate _download:didCreateDestination:]):
     40        * TestWebKitAPI/cocoa/TestNavigationDelegate.h:
     41        * TestWebKitAPI/cocoa/TestNavigationDelegate.mm:
     42        (-[TestNavigationDelegate webView:decidePolicyForNavigationResponse:decisionHandler:]):
     43
    1442020-04-22  Saam Barati  <sbarati@apple.com>
    245
  • trunk/Tools/TestWebKitAPI/SourcesCocoa.txt

    r259307 r260518  
    2727cocoa/PlatformUtilitiesCocoa.mm
    2828cocoa/TestCocoa.mm
     29cocoa/TestDownloadDelegate.mm
    2930cocoa/TestNavigationDelegate.mm
    3031cocoa/TestProtocol.mm
  • trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj

    r260449 r260518  
    20652065                5C6E27A6224EEBEA00128736 /* URLCanonicalization.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = URLCanonicalization.mm; sourceTree = "<group>"; };
    20662066                5C7148942123A40700FDE3C5 /* WKWebsiteDatastore.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKWebsiteDatastore.mm; sourceTree = "<group>"; };
     2067                5C72E8CD244FFCE300381EB7 /* TestDownloadDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestDownloadDelegate.h; path = cocoa/TestDownloadDelegate.h; sourceTree = "<group>"; };
     2068                5C72E8CE244FFCE400381EB7 /* TestDownloadDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = TestDownloadDelegate.mm; path = cocoa/TestDownloadDelegate.mm; sourceTree = "<group>"; };
    20672069                5C73A81A2323059800DEA85A /* TLSDeprecation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TLSDeprecation.mm; sourceTree = "<group>"; };
    20682070                5C75715F221249BD00B9E5AC /* BundleRetainPagePlugIn.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = BundleRetainPagePlugIn.mm; sourceTree = "<group>"; };
     
    29202922                                5CE7594822A883A500C12409 /* TestContextMenuDriver.h */,
    29212923                                5CE7594722A883A500C12409 /* TestContextMenuDriver.mm */,
     2924                                5C72E8CD244FFCE300381EB7 /* TestDownloadDelegate.h */,
     2925                                5C72E8CE244FFCE400381EB7 /* TestDownloadDelegate.mm */,
    29222926                                2D1C04A51D76298B000A6816 /* TestNavigationDelegate.h */,
    29232927                                2D1C04A61D76298B000A6816 /* TestNavigationDelegate.mm */,
     
    48824886                                7CCE7EF61A411AE600447C4C /* FrameMIMETypeHTML.cpp in Sources */,
    48834887                                7CCE7EF71A411AE600447C4C /* FrameMIMETypePNG.cpp in Sources */,
     4888                                CDCF78A8244A32F700480311 /* FullscreenAlert.mm in Sources */,
    48844889                                CD78E11D1DB7EA660014A2DE /* FullscreenDelegate.mm in Sources */,
    48854890                                CDBFCC451A9FF45300A7B691 /* FullscreenZoomInitialFrame.mm in Sources */,
     
    50465051                                5CFACF65226FD2DC0056C7D0 /* Proxy.mm in Sources */,
    50475052                                041A1E34216FFDBC00789E0A /* PublicSuffix.cpp in Sources */,
    5048                                 CDCF78A8244A32F700480311 /* FullscreenAlert.mm in Sources */,
    50495053                                7C83E0C21D0A653500FEBCF3 /* QuickLook.mm in Sources */,
    50505054                                6B4E861C2220A5520022F389 /* RegistrableDomain.cpp in Sources */,
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/Download.mm

    r255961 r260518  
    3333#import "TCPServer.h"
    3434#import "Test.h"
     35#import "TestDownloadDelegate.h"
     36#import "TestNavigationDelegate.h"
    3537#import "TestProtocol.h"
    3638#import "TestWKWebView.h"
     
    4749#import <WebKit/_WKProcessPoolConfiguration.h>
    4850#import <WebKit/_WKWebsiteDataStoreConfiguration.h>
     51#import <wtf/BlockPtr.h>
    4952#import <wtf/FileSystem.h>
    5053#import <wtf/MainThread.h>
     
    11581161}
    11591162
     1163#if HAVE(NETWORK_FRAMEWORK)
     1164
     1165template<size_t length>
     1166String longString(LChar c)
     1167{
     1168    Vector<LChar> vector(length, c);
     1169    return String(vector.data(), length);
     1170}
     1171
     1172TEST(_WKDownload, Resume)
     1173{
     1174    using namespace TestWebKitAPI;
     1175    HTTPServer server([connectionCount = 0](nw_connection_t connection) mutable {
     1176        switch (++connectionCount) {
     1177        case 1:
     1178            nw_connection_receive(connection, 1, std::numeric_limits<uint32_t>::max(), makeBlockPtr([connection = retainPtr(connection)](dispatch_data_t content, nw_content_context_t context, bool, nw_error_t error) {
     1179                EXPECT_TRUE(content);
     1180                EXPECT_FALSE(error);
     1181                auto data = dataFromString(makeString(
     1182                    "HTTP/1.1 200 OK\r\n"
     1183                    "ETag: test\r\n"
     1184                    "Content-Length: 10000\r\n"
     1185                    "Content-Disposition: attachment; filename=\"example.txt\"\r\n"
     1186                    "\r\n", longString<5000>('a')));
     1187                nw_connection_send(connection.get(), data.get(), context, false, ^(nw_error_t error) {
     1188                    ASSERT(!error);
     1189                });
     1190            }).get());
     1191            break;
     1192        case 2:
     1193            nw_connection_receive(connection, 1, std::numeric_limits<uint32_t>::max(), makeBlockPtr([connection = retainPtr(connection)](dispatch_data_t content, nw_content_context_t context, bool, nw_error_t error) {
     1194                EXPECT_TRUE(content);
     1195                EXPECT_FALSE(error);
     1196
     1197                auto request = nullTerminatedRequest(content);
     1198                EXPECT_TRUE(strstr(request.data(), "Range: bytes=5000-\r\n"));
     1199
     1200                auto data = dataFromString(makeString(
     1201                    "HTTP/1.1 206 Partial Content\r\n"
     1202                    "ETag: test\r\n"
     1203                    "Content-Length: 5000\r\n"
     1204                    "Content-Range: bytes 5000-9999/10000\r\n"
     1205                    "\r\n", longString<5000>('b')));
     1206                nw_connection_send(connection.get(), data.get(), context, true, ^(nw_error_t error) {
     1207                    ASSERT(!error);
     1208                });
     1209            }).get());
     1210            break;
     1211        default:
     1212            ASSERT_NOT_REACHED();
     1213        }
     1214    });
     1215
     1216    NSURL *tempDir = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"DownloadResumeTest"] isDirectory:YES];
     1217    [[NSFileManager defaultManager] createDirectoryAtURL:tempDir withIntermediateDirectories:YES attributes:nil error:nil];
     1218    NSURL *expectedDownloadFile = [tempDir URLByAppendingPathComponent:@"example.txt"];
     1219    [[NSFileManager defaultManager] removeItemAtURL:expectedDownloadFile error:nil];
     1220
     1221    auto navigationDelegate = adoptNS([TestNavigationDelegate new]);
     1222    navigationDelegate.get().decidePolicyForNavigationResponse = ^(WKNavigationResponse *, void (^completionHandler)(WKNavigationResponsePolicy)) {
     1223        completionHandler(_WKNavigationResponsePolicyBecomeDownload);
     1224    };
     1225
     1226    enum class Callback : uint8_t { Start, ReceiveData, DecideDestination, CreateDestination, Cancel, Finish };
     1227    __block Vector<Callback> callbacks;
     1228    __block bool didCancel = false;
     1229    __block bool didFinish = false;
     1230    __block bool receivedData = false;
     1231    __block RetainPtr<_WKDownload> download;
     1232    __block RetainPtr<NSData> resumeData;
     1233
     1234    auto downloadDelegate = adoptNS([TestDownloadDelegate new]);
     1235    downloadDelegate.get().decideDestinationWithSuggestedFilename = ^(_WKDownload *, NSString *suggestedFilename, void (^completionHandler)(BOOL, NSString *)) {
     1236        callbacks.append(Callback::DecideDestination);
     1237        completionHandler(YES, [tempDir URLByAppendingPathComponent:suggestedFilename].path);
     1238    };
     1239    downloadDelegate.get().didReceiveData = ^(_WKDownload *download, uint64_t length) {
     1240        callbacks.append(Callback::ReceiveData);
     1241        EXPECT_EQ(length, 5000u);
     1242        receivedData = true;
     1243    };
     1244    downloadDelegate.get().downloadDidStart = ^(_WKDownload *downloadFromDelegate) {
     1245        callbacks.append(Callback::Start);
     1246        download = downloadFromDelegate;
     1247    };
     1248    downloadDelegate.get().didCreateDestination = ^(_WKDownload *, NSString *destination) {
     1249        callbacks.append(Callback::CreateDestination);
     1250        EXPECT_WK_STREQ(destination, [tempDir URLByAppendingPathComponent:@"example.txt"].path);
     1251    };
     1252    downloadDelegate.get().downloadDidCancel = ^(_WKDownload *download) {
     1253        callbacks.append(Callback::Cancel);
     1254        resumeData = download.resumeData;
     1255        didCancel = true;
     1256    };
     1257    downloadDelegate.get().downloadDidFinish = ^(_WKDownload *) {
     1258        callbacks.append(Callback::Finish);
     1259        didFinish = true;
     1260    };
     1261
     1262    auto webView = adoptNS([WKWebView new]);
     1263    [webView setNavigationDelegate:navigationDelegate.get()];
     1264    [webView configuration].processPool._downloadDelegate = downloadDelegate.get();
     1265    [webView loadRequest:server.request()];
     1266    Util::run(&receivedData);
     1267    [download cancel];
     1268    Util::run(&didCancel);
     1269
     1270    [[webView configuration].processPool _resumeDownloadFromData:resumeData.get() websiteDataStore:[WKWebsiteDataStore defaultDataStore] path:expectedDownloadFile.path originatingWebView:webView.get()];
     1271    Util::run(&didFinish);
     1272   
     1273    EXPECT_EQ(callbacks.size(), 7u);
     1274    EXPECT_EQ(callbacks[0], Callback::Start);
     1275    EXPECT_EQ(callbacks[1], Callback::DecideDestination);
     1276    EXPECT_EQ(callbacks[2], Callback::CreateDestination);
     1277    EXPECT_EQ(callbacks[3], Callback::ReceiveData);
     1278    EXPECT_EQ(callbacks[4], Callback::Cancel);
     1279    EXPECT_EQ(callbacks[5], Callback::ReceiveData);
     1280    EXPECT_EQ(callbacks[6], Callback::Finish);
     1281
     1282    NSData *fileContents = [NSData dataWithContentsOfURL:expectedDownloadFile];
     1283    EXPECT_EQ(fileContents.length, 10000u);
     1284    for (size_t i = 0; i < 5000; i++)
     1285        EXPECT_EQ(static_cast<const char*>(fileContents.bytes)[i], 'a');
     1286    for (size_t i = 5000; i < 10000; i++)
     1287        EXPECT_EQ(static_cast<const char*>(fileContents.bytes)[i], 'b');
     1288}
     1289
     1290#endif // HAVE(NETWORK_FRAMEWORK)
     1291
    11601292@interface DownloadTestSchemeDelegate : NSObject <WKNavigationDelegate>
    11611293@end
  • trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.h

    r260302 r260518  
    4040public:
    4141    struct HTTPResponse;
     42    struct RequestData;
    4243    enum class Protocol : uint8_t { Http, Https, HttpsWithLegacyTLS };
    43     HTTPServer(std::initializer_list<std::pair<String, HTTPResponse>>, Protocol = Protocol::Http, Function<void(sec_protocol_metadata_t, sec_trust_t, sec_protocol_verify_complete_t)>&& = nullptr);
     44    using CertificateVerifier = Function<void(sec_protocol_metadata_t, sec_trust_t, sec_protocol_verify_complete_t)>;
     45
     46    HTTPServer(std::initializer_list<std::pair<String, HTTPResponse>>, Protocol = Protocol::Http, CertificateVerifier&& = nullptr);
     47    HTTPServer(Function<void(nw_connection_t)>&&, Protocol = Protocol::Http);
     48    ~HTTPServer();
    4449    uint16_t port() const;
    4550    NSURLRequest *request() const;
    46     size_t totalRequests() const { return m_totalRequests; }
    47    
     51    size_t totalRequests() const;
     52
    4853private:
    49     void respondToRequests(nw_connection_t);
    50    
     54    static RetainPtr<nw_parameters_t> listenerParameters(Protocol, CertificateVerifier&&);
     55    static void respondToRequests(nw_connection_t, RefPtr<RequestData>);
     56
     57    RefPtr<RequestData> m_requestData;
    5158    RetainPtr<nw_listener_t> m_listener;
    52     const Protocol m_protocol;
    53     const Function<void(sec_protocol_metadata_t, sec_trust_t, sec_protocol_verify_complete_t)> m_certVerifier;
    54     const HashMap<String, HTTPResponse> m_requestResponseMap;
    55     size_t m_totalRequests { 0 };
     59    Protocol m_protocol { Protocol::Http };
    5660};
     61
     62RetainPtr<dispatch_data_t> dataFromString(String&&);
     63Vector<char> nullTerminatedRequest(dispatch_data_t);
    5764
    5865struct HTTPServer::HTTPResponse {
  • trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.mm

    r260302 r260518  
    3838namespace TestWebKitAPI {
    3939
    40 HTTPServer::HTTPServer(std::initializer_list<std::pair<String, HTTPResponse>> responses, Protocol protocol, Function<void(sec_protocol_metadata_t, sec_trust_t, sec_protocol_verify_complete_t)>&& verify)
    41     : m_protocol(protocol)
    42     , m_certVerifier(WTFMove(verify))
    43     , m_requestResponseMap([](std::initializer_list<std::pair<String, HTTPServer::HTTPResponse>> list) {
     40struct HTTPServer::RequestData : public RefCounted<RequestData> {
     41    RequestData(std::initializer_list<std::pair<String, HTTPResponse>> responses)
     42    : requestMap([](std::initializer_list<std::pair<String, HTTPServer::HTTPResponse>> list) {
    4443        HashMap<String, HTTPServer::HTTPResponse> map;
    4544        for (auto& pair : list)
    4645            map.add(pair.first, pair.second);
    4746        return map;
    48     }(responses))
    49 {
    50     auto configureTLS = protocol == Protocol::Http ? NW_PARAMETERS_DISABLE_PROTOCOL : ^(nw_protocol_options_t protocolOptions) {
     47    }(responses)) { }
     48   
     49    size_t requestCount { 0 };
     50    const HashMap<String, HTTPResponse> requestMap;
     51};
     52
     53RetainPtr<nw_parameters_t> HTTPServer::listenerParameters(Protocol protocol, CertificateVerifier&& verifier)
     54{
     55    auto configureTLS = protocol == Protocol::Http ? makeBlockPtr(NW_PARAMETERS_DISABLE_PROTOCOL) : makeBlockPtr([protocol, verifier = WTFMove(verifier)] (nw_protocol_options_t protocolOptions) mutable {
    5156#if HAVE(TLS_PROTOCOL_VERSION_T)
    5257        auto options = adoptNS(nw_tls_copy_sec_protocol_options(protocolOptions));
     
    5560        if (protocol == Protocol::HttpsWithLegacyTLS)
    5661            sec_protocol_options_set_max_tls_protocol_version(options.get(), tls_protocol_version_TLSv10);
    57         if (m_certVerifier) {
     62        if (verifier) {
    5863            sec_protocol_options_set_peer_authentication_required(options.get(), true);
    59             sec_protocol_options_set_verify_block(options.get(), ^(sec_protocol_metadata_t metadata, sec_trust_t trust, sec_protocol_verify_complete_t completion) {
    60                 m_certVerifier(metadata, trust, completion);
    61             }, dispatch_get_main_queue());
     64            sec_protocol_options_set_verify_block(options.get(), makeBlockPtr([verifier = WTFMove(verifier)](sec_protocol_metadata_t metadata, sec_trust_t trust, sec_protocol_verify_complete_t completion) {
     65                verifier(metadata, trust, completion);
     66            }).get(), dispatch_get_main_queue());
    6267        }
    6368#else
     
    6570        ASSERT_UNUSED(protocol, protocol != Protocol::HttpsWithLegacyTLS);
    6671#endif
    67     };
    68     auto parameters = adoptNS(nw_parameters_create_secure_tcp(configureTLS, NW_PARAMETERS_DEFAULT_CONFIGURATION));
    69     m_listener = adoptNS(nw_listener_create(parameters.get()));
    70     nw_listener_set_queue(m_listener.get(), dispatch_get_main_queue());
    71     nw_listener_set_new_connection_handler(m_listener.get(), ^(nw_connection_t connection) {
    72         nw_connection_set_queue(connection, dispatch_get_main_queue());
    73         nw_connection_start(connection);
    74         respondToRequests(connection);
    7572    });
     73    return adoptNS(nw_parameters_create_secure_tcp(configureTLS.get(), NW_PARAMETERS_DEFAULT_CONFIGURATION));
     74}
     75
     76static void startListening(nw_listener_t listener)
     77{
    7678    __block bool ready = false;
    77     nw_listener_set_state_changed_handler(m_listener.get(), ^(nw_listener_state_t state, nw_error_t error) {
     79    nw_listener_set_state_changed_handler(listener, ^(nw_listener_state_t state, nw_error_t error) {
    7880        ASSERT_UNUSED(error, !error);
    7981        if (state == nw_listener_state_ready)
    8082            ready = true;
    8183    });
    82     nw_listener_start(m_listener.get());
     84    nw_listener_start(listener);
    8385    Util::run(&ready);
     86}
     87
     88HTTPServer::HTTPServer(std::initializer_list<std::pair<String, HTTPResponse>> responses, Protocol protocol, CertificateVerifier&& verifier)
     89    : m_requestData(adoptRef(new RequestData(responses)))
     90    , m_listener(adoptNS(nw_listener_create(listenerParameters(protocol, WTFMove(verifier)).get())))
     91    , m_protocol(protocol)
     92{
     93    nw_listener_set_queue(m_listener.get(), dispatch_get_main_queue());
     94    nw_listener_set_new_connection_handler(m_listener.get(), makeBlockPtr([requestData = m_requestData](nw_connection_t connection) {
     95        nw_connection_set_queue(connection, dispatch_get_main_queue());
     96        nw_connection_start(connection);
     97        respondToRequests(connection, requestData);
     98    }).get());
     99    startListening(m_listener.get());
     100}
     101
     102HTTPServer::HTTPServer(Function<void(nw_connection_t)>&& connectionHandler, Protocol protocol)
     103    : m_listener(adoptNS(nw_listener_create(listenerParameters(protocol, nullptr).get())))
     104    , m_protocol(protocol)
     105{
     106    nw_listener_set_queue(m_listener.get(), dispatch_get_main_queue());
     107    nw_listener_set_new_connection_handler(m_listener.get(), makeBlockPtr([connectionHandler = WTFMove(connectionHandler)] (nw_connection_t connection) {
     108        nw_connection_set_queue(connection, dispatch_get_main_queue());
     109        nw_connection_start(connection);
     110        connectionHandler(connection);
     111    }).get());
     112    startListening(m_listener.get());
     113}
     114
     115HTTPServer::~HTTPServer() = default;
     116
     117size_t HTTPServer::totalRequests() const
     118{
     119    if (!m_requestData)
     120        return 0;
     121    return m_requestData->requestCount;
    84122}
    85123
     
    98136}
    99137
    100 void HTTPServer::respondToRequests(nw_connection_t connection)
    101 {
    102     nw_connection_receive(connection, 1, std::numeric_limits<uint32_t>::max(), ^(dispatch_data_t content, nw_content_context_t context, bool complete, nw_error_t error) {
     138RetainPtr<dispatch_data_t> dataFromString(String&& s)
     139{
     140    auto impl = s.releaseImpl();
     141    ASSERT(impl->is8Bit());
     142    return adoptNS(dispatch_data_create(impl->characters8(), impl->length(), dispatch_get_main_queue(), ^{
     143        (void)impl;
     144    }));
     145}
     146
     147Vector<char> nullTerminatedRequest(dispatch_data_t content)
     148{
     149    __block Vector<char> request;
     150    dispatch_data_apply(content, ^bool(dispatch_data_t, size_t, const void* buffer, size_t size) {
     151        request.append(static_cast<const char*>(buffer), size);
     152        return true;
     153    });
     154    request.append('\0');
     155    return request;
     156}
     157
     158void HTTPServer::respondToRequests(nw_connection_t connection, RefPtr<RequestData> requestData)
     159{
     160    nw_connection_receive(connection, 1, std::numeric_limits<uint32_t>::max(), makeBlockPtr([connection = retainPtr(connection), requestData](dispatch_data_t content, nw_content_context_t context, bool complete, nw_error_t error) {
    103161        if (error || !content)
    104162            return;
    105         __block Vector<char> request;
    106         dispatch_data_apply(content, ^bool(dispatch_data_t, size_t, const void* buffer, size_t size) {
    107             request.append(static_cast<const char*>(buffer), size);
    108             return true;
    109         });
    110         request.append('\0');
    111 
    112         m_totalRequests++;
     163
     164        requestData->requestCount++;
     165        auto request = nullTerminatedRequest(content);
    113166
    114167        const char* getPathPrefix = "GET ";
     
    127180        size_t pathLength = pathEnd - request.data() - pathPrefixLength;
    128181        String path(request.data() + pathPrefixLength, pathLength);
    129         ASSERT_WITH_MESSAGE(m_requestResponseMap.contains(path), "This HTTPServer does not know how to respond to a request for %s", path.utf8().data());
    130 
    131         CompletionHandler<void()> sendResponse = [this, connection = retainPtr(connection), context = retainPtr(context), path = WTFMove(path)] {
    132             auto response = m_requestResponseMap.get(path);
     182        ASSERT_WITH_MESSAGE(requestData->requestMap.contains(path), "This HTTPServer does not know how to respond to a request for %s", path.utf8().data());
     183
     184        CompletionHandler<void()> sendResponse = [connection, context = retainPtr(context), path = WTFMove(path), requestData] {
     185            auto response = requestData->requestMap.get(path);
    133186            if (response.terminateConnection == HTTPResponse::TerminateConnection::Yes) {
    134187                nw_connection_cancel(connection.get());
     
    151204            responseBuilder.append("\r\n");
    152205            responseBuilder.append(response.body);
    153             auto responseBodyAndHeader = responseBuilder.toString().releaseImpl();
    154             auto responseData = adoptNS(dispatch_data_create(responseBodyAndHeader->characters8(), responseBodyAndHeader->length(), dispatch_get_main_queue(), ^{
    155                 (void)responseBodyAndHeader;
    156             }));
    157             nw_connection_send(connection.get(), responseData.get(), context.get(), true, ^(nw_error_t error) {
     206            nw_connection_send(connection.get(), dataFromString(responseBuilder.toString()).get(), context.get(), true, ^(nw_error_t error) {
    158207                ASSERT(!error);
    159                 respondToRequests(connection.get());
     208                respondToRequests(connection.get(), requestData);
    160209            });
    161210        };
     
    166215            constexpr size_t nullTerminationLength = 1;
    167216            if (request.size() - nullTerminationLength - headerLength < contentLength) {
    168                 nw_connection_receive(connection, 1, std::numeric_limits<uint32_t>::max(), makeBlockPtr([sendResponse = WTFMove(sendResponse)] (dispatch_data_t content, nw_content_context_t context, bool complete, nw_error_t error) mutable {
     217                nw_connection_receive(connection.get(), 1, std::numeric_limits<uint32_t>::max(), makeBlockPtr([sendResponse = WTFMove(sendResponse)] (dispatch_data_t content, nw_content_context_t context, bool complete, nw_error_t error) mutable {
    169218                    if (error || !content)
    170219                        return;
     
    175224        }
    176225        sendResponse();
    177     });
     226    }).get());
    178227}
    179228
  • trunk/Tools/TestWebKitAPI/cocoa/TestNavigationDelegate.h

    r260366 r260518  
    3131@property (nonatomic, copy) void (^decidePolicyForNavigationAction)(WKNavigationAction *, void (^)(WKNavigationActionPolicy));
    3232@property (nonatomic, copy) void (^decidePolicyForNavigationActionWithPreferences)(WKNavigationAction *, WKWebpagePreferences *, void (^)(WKNavigationActionPolicy, WKWebpagePreferences *));
     33@property (nonatomic, copy) void (^decidePolicyForNavigationResponse)(WKNavigationResponse *, void (^)(WKNavigationResponsePolicy));
    3334@property (nonatomic, copy) void (^didFailProvisionalNavigation)(WKWebView *, WKNavigation *, NSError *);
    3435@property (nonatomic, copy) void (^didStartProvisionalNavigation)(WKWebView *, WKNavigation *);
  • trunk/Tools/TestWebKitAPI/cocoa/TestNavigationDelegate.mm

    r256715 r260518  
    4545}
    4646
     47- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
     48{
     49    if (_decidePolicyForNavigationResponse)
     50        _decidePolicyForNavigationResponse(navigationResponse, decisionHandler);
     51    else
     52        decisionHandler(WKNavigationResponsePolicyAllow);
     53}
     54
    4755- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation
    4856{
Note: See TracChangeset for help on using the changeset viewer.