[PATCH] winhttp/tests: Add Websocket Tests

Alistair Leslie-Hughes leslie_alistair at hotmail.com
Sat Jun 13 06:24:44 CDT 2020


Signed-off-by: Alistair Leslie-Hughes <leslie_alistair at hotmail.com>
---
 dlls/winhttp/tests/winhttp.c | 161 +++++++++++++++++++++++++++++++++++
 1 file changed, 161 insertions(+)

diff --git a/dlls/winhttp/tests/winhttp.c b/dlls/winhttp/tests/winhttp.c
index ab91940ebb..cbcadd7e03 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,13 @@ static const char passportauth[] =
 "WWW-Authenticate: Passport1.4\r\n"
 "\r\n";
 
+static const char switchprotocol[] =
+"HTTP/1.1 101 Switching Protocols\r\n"
+"Server: winetest\r\n"
+"Cache-Control: private\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 +2226,47 @@ struct server_info
 
 #define BIG_BUFFER_LEN 0x2250
 
+static char *create_websocket_accept(const char *key)
+{
+    static char buffer[256];
+    static const char serverkey[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+    HCRYPTPROV provider;
+    BYTE hash_data[20];
+    HCRYPTHASH hash;
+    unsigned int i, length;
+    static char sha1[41];
+    BOOL ret;
+
+    strcpy(buffer, key);
+    strcat(buffer, serverkey);
+
+    ret = CryptAcquireContextW(&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
+    ok(ret, "Failed to acquire crypt context.\n");
+    ret = CryptCreateHash(provider, CALG_SHA1, 0, 0, &hash);
+    ok(ret, "Failed to create hash.\n");
+
+    ret = CryptHashData(hash, (BYTE *)buffer, strlen(buffer), 0);
+    ok(ret, "Failed to hash data.\n");
+
+    i = sizeof(hash_data);
+    ret = CryptGetHashParam(hash, HP_HASHVAL, hash_data, &i, 0);
+    ok(ret, "Failed to get hash value.\n");
+    ok(i == sizeof(hash_data), "Got unexpected hash size %u.\n", i);
+
+    ret = CryptDestroyHash(hash);
+    ok(ret, "Failed to destroy hash.\n");
+    ret = CryptReleaseContext(provider, 0);
+    ok(ret, "Failed to release crypt context.\n");
+
+    length = sizeof(sha1);
+    if (CryptBinaryToStringA( (BYTE*)hash_data, sizeof(hash_data), CRYPT_STRING_BASE64, sha1, &length))
+    {
+        return sha1;
+    }
+
+    return NULL;
+}
+
 static DWORD CALLBACK server_thread(LPVOID param)
 {
     struct server_info *si = param;
@@ -2321,6 +2371,31 @@ static DWORD CALLBACK server_thread(LPVOID param)
         {
             send(c, multiauth, sizeof multiauth - 1, 0);
         }
+        if (strstr(buffer, "GET /switchwebsocket"))
+        {
+            char switchbuffer[128];
+            char key[64];
+            char *p;
+            char *pos = strstr(buffer, "Sec-WebSocket-Key: ");
+            if(pos)
+            {
+                memcpy(switchbuffer, switchprotocol, sizeof(switchprotocol));
+                memcpy(key, pos+19, 24);
+                key[24] = 0;
+
+                p = create_websocket_accept(key);
+
+                strcat(switchbuffer, "Sec-WebSocket-Accept: ");
+                strcat(switchbuffer, p);
+                strcat(switchbuffer, "\r\n\r\n");
+
+                send(c, switchbuffer, strlen(switchbuffer), 0);
+            }
+            else
+                send(c, notokmsg, sizeof(notokmsg) - 1, 0);
+
+            continue;
+        }
         if (strstr(buffer, "GET /largeauth"))
         {
             if (strstr(buffer, "Authorization: NTLM"))
@@ -3039,6 +3114,88 @@ static void test_head_request(int port)
     WinHttpCloseHandle(ses);
 }
 
+static void test_websocket_upgrade(int port)
+{
+    HINTERNET ses, con, req, websock;
+    char buf[128];
+    DWORD size, len, count, status, index;
+    BOOL ret;
+
+    if(!pWinHttpWebSocketCompleteUpgrade)
+    {
+        win_skip("WinHttpWebSocketCompleteUpgrade not supported.\n");
+        return;
+    }
+
+    ses = WinHttpOpen(L"winetest", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0);
+    ok(ses != NULL, "failed to open session %u\n", GetLastError());
+
+    con = WinHttpConnect(ses, L"localhost", port, 0);
+    ok(con != NULL, "failed to open a connection %u\n", GetLastError());
+
+    req = WinHttpOpenRequest(con, L"GET", L"/switchwebsocket", NULL, NULL, NULL, 0);
+    ok(req != NULL, "failed to open a request %u\n", GetLastError());
+
+    ret = WinHttpSetOption(req, WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, NULL, 0);
+    todo_wine ok(ret, "failed to send request %u\n", GetLastError());
+
+    index = 0;
+    buf[0] = 0;
+    len = sizeof(buf);
+    ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
+                              L"Sec-WebSocket-Key", buf, &len, &index);
+    ok(GetLastError() == ERROR_WINHTTP_HEADER_NOT_FOUND, "Found Header\n");
+
+    ret = WinHttpSendRequest(req, WINHTTP_NO_ADDITIONAL_HEADERS, 0, NULL, 0, 0, 0);
+    ok(ret, "failed to send request %u\n", GetLastError());
+
+    index = 0;
+    buf[0] = 0;
+    len = sizeof(buf);
+    ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
+                              L"Sec-WebSocket-Key", buf, &len, &index);
+    todo_wine ok(ret, "failed to find header %u\n", GetLastError());
+
+    ret = WinHttpReceiveResponse(req, NULL);
+    todo_wine ok(ret, "failed to receive response %u\n", GetLastError());
+
+    count = 0xdeadbeef;
+    ret = WinHttpQueryDataAvailable(req, &count);
+    ok(ret, "failed to query data available %u\n", GetLastError());
+    todo_wine ok(!count, "got %u\n", count);
+
+    status = 0xdeadbeef;
+    size = sizeof(status);
+    ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
+                              NULL, &status, &size, NULL);
+    ok(ret, "failed to get status code %u\n", GetLastError());
+    todo_wine ok(status == HTTP_STATUS_SWITCH_PROTOCOLS, "got %u\n", status);
+
+    len = 0xdeadbeef;
+    size = sizeof(len);
+    ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER,
+                              NULL, &len, &size, 0);
+    ok(!ret, "failed to get content-length header %u\n", GetLastError());
+
+    websock = pWinHttpWebSocketCompleteUpgrade(req, 0);
+    todo_wine ok(websock != NULL, "failed to upgrade scoket %u\n", GetLastError());
+
+    index = 0;
+    buf[0] = 0;
+    len = sizeof(buf);
+    ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_CUSTOM,
+                              L"Sec-WebSocket-Accept", buf, &len, &index);
+    todo_wine ok(ret, "failed to WinHttpQueryHeaders %u\n", GetLastError());
+
+    WinHttpCloseHandle(req);
+
+    /* Send/Receive on websock */
+
+    WinHttpCloseHandle(websock);
+    WinHttpCloseHandle(con);
+    WinHttpCloseHandle(ses);
+}
+
 static void test_not_modified(int port)
 {
     BOOL ret;
@@ -4710,6 +4867,7 @@ START_TEST (winhttp)
     struct server_info si;
     HANDLE thread;
     DWORD ret;
+    HMODULE mod = GetModuleHandleA("winhttp.dll");
 
     test_WinHttpOpenRequest();
     test_WinHttpSendRequest();
@@ -4744,12 +4902,15 @@ START_TEST (winhttp)
         return;
     }
 
+    pWinHttpWebSocketCompleteUpgrade = (void*)GetProcAddress(mod, "WinHttpWebSocketCompleteUpgrade");
+
     test_IWinHttpRequest(si.port);
     test_connection_info(si.port);
     test_basic_request(si.port, NULL, L"/basic");
     test_no_headers(si.port);
     test_no_content(si.port);
     test_head_request(si.port);
+    test_websocket_upgrade(si.port);
     test_not_modified(si.port);
     test_basic_authentication(si.port);
     test_multi_authentication(si.port);
-- 
2.26.2




More information about the wine-devel mailing list