Signed-off-by: Alistair Leslie-Hughes leslie_alistair@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);