Alistair Leslie-Hughes : winhttp/tests: Add WebSocket tests.

Alexandre Julliard julliard at winehq.org
Tue Jun 16 17:08:49 CDT 2020


Module: wine
Branch: master
Commit: a46d359e91e299142a27570bb202d8141b9625da
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=a46d359e91e299142a27570bb202d8141b9625da

Author: Alistair Leslie-Hughes <leslie_alistair at hotmail.com>
Date:   Tue Jun 16 11:45:12 2020 +0200

winhttp/tests: Add WebSocket tests.

Signed-off-by: Alistair Leslie-Hughes <leslie_alistair at hotmail.com>
Signed-off-by: Hans Leidekker <hans at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/winhttp/tests/winhttp.c | 215 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 215 insertions(+)

diff --git a/dlls/winhttp/tests/winhttp.c b/dlls/winhttp/tests/winhttp.c
index ab91940ebb..f08f50b9a9 100644
--- a/dlls/winhttp/tests/winhttp.c
+++ b/dlls/winhttp/tests/winhttp.c
@@ -37,6 +37,8 @@
 
 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
 
+static HINTERNET (WINAPI *pWinHttpWebSocketCompleteUpgrade)(HINTERNET,DWORD_PTR);
+
 static BOOL proxy_active(void)
 {
     WINHTTP_PROXY_INFO proxy_info;
@@ -2205,6 +2207,12 @@ static const char passportauth[] =
 "WWW-Authenticate: Passport1.4\r\n"
 "\r\n";
 
+static const char switchprotocols[] =
+"HTTP/1.1 101 Switching Protocols\r\n"
+"Server: winetest\r\n"
+"Upgrade: websocket\r\n"
+"Connection: Upgrade\r\n";
+
 static const char unauthorized[] = "Unauthorized";
 static const char hello_world[] = "Hello World";
 static const char auth_unseen[] = "Auth Unseen";
@@ -2217,6 +2225,31 @@ struct server_info
 
 #define BIG_BUFFER_LEN 0x2250
 
+static void create_websocket_accept(const char *key, char *buf, unsigned int buflen)
+{
+    HCRYPTPROV provider;
+    HCRYPTHASH hash;
+    BYTE sha1[20];
+    char data[128];
+    DWORD len;
+
+    strcpy(data, key);
+    strcat(data, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
+
+    CryptAcquireContextW(&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
+    CryptCreateHash(provider, CALG_SHA1, 0, 0, &hash);
+    CryptHashData(hash, (BYTE *)data, strlen(data), 0);
+
+    len = sizeof(sha1);
+    CryptGetHashParam(hash, HP_HASHVAL, sha1, &len, 0);
+    CryptDestroyHash(hash);
+    CryptReleaseContext(provider, 0);
+
+    buf[0] = 0;
+    len = buflen;
+    CryptBinaryToStringA( (BYTE *)sha1, sizeof(sha1), CRYPT_STRING_BASE64, buf, &len);
+}
+
 static DWORD CALLBACK server_thread(LPVOID param)
 {
     struct server_info *si = param;
@@ -2388,6 +2421,29 @@ static DWORD CALLBACK server_thread(LPVOID param)
         {
             send(c, passportauth, sizeof(passportauth) - 1, 0);
         }
+        else if (strstr(buffer, "GET /websocket"))
+        {
+            char headers[256], key[32], accept[64];
+            const char *pos = strstr(buffer, "Sec-WebSocket-Key: ");
+            if (pos && strstr(buffer, "Connection: Upgrade\r\n") &&
+                (strstr(buffer, "Upgrade: websocket\r\n") || strstr(buffer, "Upgrade: Websocket\r\n")) &&
+                strstr(buffer, "Host: ") && strstr(buffer, "Sec-WebSocket-Version: 13\r\n"))
+            {
+                memcpy(headers, switchprotocols, sizeof(switchprotocols));
+                memcpy(key, pos + 19, 24);
+                key[24] = 0;
+
+                create_websocket_accept(key, accept, sizeof(accept));
+
+                strcat(headers, "Sec-WebSocket-Accept: ");
+                strcat(headers, accept);
+                strcat(headers, "\r\n\r\n");
+
+                send(c, headers, strlen(headers), 0);
+            }
+            else send(c, notokmsg, sizeof(notokmsg) - 1, 0);
+            continue;
+        }
         if (strstr(buffer, "GET /quit"))
         {
             send(c, okmsg, sizeof okmsg - 1, 0);
@@ -3039,6 +3095,161 @@ static void test_head_request(int port)
     WinHttpCloseHandle(ses);
 }
 
+static void test_websocket(int port)
+{
+    HINTERNET session, connection, request, socket;
+    DWORD size, len, count, status, index, error;
+    WCHAR header[32];
+    char buf[128];
+    BOOL ret;
+
+    if (!pWinHttpWebSocketCompleteUpgrade)
+    {
+        win_skip("WinHttpWebSocketCompleteUpgrade not supported\n");
+        return;
+    }
+
+    session = WinHttpOpen(L"winetest", 0, NULL, NULL, 0);
+    ok(session != NULL, "got %u\n", GetLastError());
+
+    connection = WinHttpConnect(session, L"localhost", port, 0);
+    ok(connection != NULL, "got %u\n", GetLastError());
+
+    request = WinHttpOpenRequest(connection, L"GET", L"/websocket", NULL, NULL, NULL, 0);
+    ok(request != NULL, "got %u\n", GetLastError());
+
+    ret = WinHttpSetOption(request, WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, NULL, 0);
+    todo_wine ok(ret, "got %u\n", GetLastError());
+
+    size = sizeof(header);
+    SetLastError(0xdeadbeef);
+    ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_UPGRADE, NULL, &header, &size, NULL);
+    error = GetLastError();
+    ok(!ret, "success\n");
+    todo_wine ok(error == ERROR_WINHTTP_INCORRECT_HANDLE_STATE, "got %u\n", error);
+
+    size = sizeof(header);
+    SetLastError(0xdeadbeef);
+    ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CONNECTION, NULL, &header, &size, NULL);
+    error = GetLastError();
+    ok(!ret, "success\n");
+    todo_wine ok(error == ERROR_WINHTTP_INCORRECT_HANDLE_STATE, "got %u\n", error);
+
+    index = 0;
+    size = sizeof(buf);
+    SetLastError(0xdeadbeef);
+    ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
+                              L"Sec-WebSocket-Key", buf, &size, &index);
+    error = GetLastError();
+    ok(!ret, "success\n");
+    ok(error == ERROR_WINHTTP_HEADER_NOT_FOUND, "got %u\n", error);
+
+    index = 0;
+    size = sizeof(buf);
+    SetLastError(0xdeadbeef);
+    ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
+                              L"Sec-WebSocket-Version", buf, &size, &index);
+    error = GetLastError();
+    ok(!ret, "success\n");
+    ok(error == ERROR_WINHTTP_HEADER_NOT_FOUND, "got %u\n", error);
+
+    ret = WinHttpSendRequest(request, NULL, 0, NULL, 0, 0, 0);
+    ok(ret, "got %u\n", GetLastError());
+
+    size = sizeof(header);
+    SetLastError(0xdeadbeef);
+    ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_UPGRADE, NULL, &header, &size, NULL);
+    error = GetLastError();
+    ok(!ret, "success\n");
+    todo_wine ok(error == ERROR_WINHTTP_INCORRECT_HANDLE_STATE, "got %u\n", error);
+
+    size = sizeof(header);
+    SetLastError(0xdeadbeef);
+    ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CONNECTION, NULL, &header, &size, NULL);
+    error = GetLastError();
+    ok(!ret, "success\n");
+    todo_wine ok(error == ERROR_WINHTTP_INCORRECT_HANDLE_STATE, "got %u\n", error);
+
+    index = 0;
+    buf[0] = 0;
+    size = sizeof(buf);
+    ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
+                              L"Sec-WebSocket-Key", buf, &size, &index);
+    todo_wine ok(ret, "got %u\n", GetLastError());
+
+    index = 0;
+    buf[0] = 0;
+    size = sizeof(buf);
+    ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
+                              L"Sec-WebSocket-Version", buf, &size, &index);
+    todo_wine ok(ret, "got %u\n", GetLastError());
+
+    ret = WinHttpReceiveResponse(request, NULL);
+    todo_wine ok(ret, "got %u\n", GetLastError());
+
+    count = 0xdeadbeef;
+    ret = WinHttpQueryDataAvailable(request, &count);
+    ok(ret, "got %u\n", GetLastError());
+    todo_wine ok(!count, "got %u\n", count);
+
+    header[0] = 0;
+    size = sizeof(header);
+    ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_UPGRADE, NULL, &header, &size, NULL);
+    todo_wine ok(ret, "got %u\n", GetLastError());
+    todo_wine ok(!wcscmp( header, L"websocket" ), "got %s\n", wine_dbgstr_w(header));
+
+    header[0] = 0;
+    size = sizeof(header);
+    ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CONNECTION, NULL, &header, &size, NULL);
+    todo_wine ok(ret, "got %u\n", GetLastError());
+    todo_wine ok(!wcscmp( header, L"Upgrade" ), "got %s\n", wine_dbgstr_w(header));
+
+    status = 0xdeadbeef;
+    size = sizeof(status);
+    ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status,
+                              &size, NULL);
+    ok(ret, "got %u\n", GetLastError());
+    todo_wine ok(status == HTTP_STATUS_SWITCH_PROTOCOLS, "got %u\n", status);
+
+    len = 0xdeadbeef;
+    size = sizeof(len);
+    ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER, NULL, &len,
+                              &size, 0);
+    ok(!ret, "success\n");
+
+    index = 0;
+    size = sizeof(buf);
+    ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM, L"Sec-WebSocket-Accept", buf, &size, &index);
+    todo_wine ok(ret, "got %u\n", GetLastError());
+
+    socket = pWinHttpWebSocketCompleteUpgrade(request, 0);
+    todo_wine ok(socket != NULL, "got %u\n", GetLastError());
+
+    header[0] = 0;
+    size = sizeof(header);
+    ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_UPGRADE, NULL, &header, &size, NULL);
+    todo_wine ok(ret, "got %u\n", GetLastError());
+    todo_wine ok(!wcscmp( header, L"websocket" ), "got %s\n", wine_dbgstr_w(header));
+
+    header[0] = 0;
+    size = sizeof(header);
+    ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CONNECTION, NULL, &header, &size, NULL);
+    todo_wine ok(ret, "got %u\n", GetLastError());
+    todo_wine ok(!wcscmp( header, L"Upgrade" ), "got %s\n", wine_dbgstr_w(header));
+
+    index = 0;
+    size = sizeof(buf);
+    ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM, L"Sec-WebSocket-Accept", buf, &size, &index);
+    todo_wine ok(ret, "got %u\n", GetLastError());
+
+    /* Send/Receive on websock */
+
+    WinHttpCloseHandle(request);
+    WinHttpCloseHandle(socket);
+    WinHttpCloseHandle(connection);
+    WinHttpCloseHandle(session);
+}
+
 static void test_not_modified(int port)
 {
     BOOL ret;
@@ -4710,6 +4921,9 @@ START_TEST (winhttp)
     struct server_info si;
     HANDLE thread;
     DWORD ret;
+    HMODULE mod = GetModuleHandleA("winhttp.dll");
+
+    pWinHttpWebSocketCompleteUpgrade = (void *)GetProcAddress(mod, "WinHttpWebSocketCompleteUpgrade");
 
     test_WinHttpOpenRequest();
     test_WinHttpSendRequest();
@@ -4759,6 +4973,7 @@ START_TEST (winhttp)
     test_cookies(si.port);
     test_request_path_escapes(si.port);
     test_passport_auth(si.port);
+    test_websocket(si.port);
 
     /* send the basic request again to shutdown the server thread */
     test_basic_request(si.port, NULL, L"/quit");




More information about the wine-cvs mailing list