Signed-off-by: Paul Gofman pgofman@codeweavers.com --- Similar to WinHttpWebSocketReceive() but requires a separate variable because control frame send may be queued from read operation for pong. It is not quite straightforward to add to test as most of the time the send is executed synchronously. I tested that manually however and repeated sends without wait in between trigger this error on Windows.
I am not aware of any app depending on this behaviour but it simplifies the synchronization for the next patch.
dlls/winhttp/request.c | 16 +++++++++++++++- dlls/winhttp/winhttp_private.h | 1 + 2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index d0732952e11..de011060236 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -3349,6 +3349,7 @@ static void CALLBACK task_socket_send( TP_CALLBACK_INSTANCE *instance, void *ctx else ret = socket_send( s->socket, s->type, s->buf, s->len, NULL );
send_io_complete( &s->socket->hdr ); + InterlockedExchange( &s->socket->pending_noncontrol_send, 0 ); socket_send_complete( s->socket, ret, s->type, s->len );
release_object( &s->socket->hdr ); @@ -3386,8 +3387,16 @@ DWORD WINAPI WinHttpWebSocketSend( HINTERNET hsocket, WINHTTP_WEB_SOCKET_BUFFER_ BOOL async_send, complete_async = FALSE; struct socket_send *s;
+ if (InterlockedCompareExchange( &socket->pending_noncontrol_send, 1, 0 )) + { + WARN( "Previous send is still queued.\n" ); + release_object( &socket->hdr ); + return ERROR_INVALID_OPERATION; + } + if (!(s = malloc( sizeof(*s) ))) { + InterlockedExchange( &socket->pending_noncontrol_send, 0 ); release_object( &socket->hdr ); return ERROR_OUTOFMEMORY; } @@ -3417,11 +3426,16 @@ DWORD WINAPI WinHttpWebSocketSend( HINTERNET hsocket, WINHTTP_WEB_SOCKET_BUFFER_ if ((ret = queue_task( &socket->send_q, task_socket_send, s ))) { InterlockedDecrement( &socket->hdr.pending_sends ); + InterlockedExchange( &socket->pending_noncontrol_send, 0 ); release_object( &socket->hdr ); free( s ); } } - else InterlockedDecrement( &socket->hdr.pending_sends ); + else + { + InterlockedDecrement( &socket->hdr.pending_sends ); + InterlockedExchange( &socket->pending_noncontrol_send, 0 ); + } ReleaseSRWLockExclusive( &socket->send_lock ); if (!async_send) { diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h index 732f0afaa88..cf6655f561f 100644 --- a/dlls/winhttp/winhttp_private.h +++ b/dlls/winhttp/winhttp_private.h @@ -260,6 +260,7 @@ struct socket unsigned int bytes_in_send_frame_buffer; unsigned int client_buffer_offset; SRWLOCK send_lock; + volatile LONG pending_noncontrol_send; };
struct send_request
--- dlls/winhttp/tests/winhttp.c | 101 +++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+)
diff --git a/dlls/winhttp/tests/winhttp.c b/dlls/winhttp/tests/winhttp.c index 23ae6167c68..3b1c39988e5 100644 --- a/dlls/winhttp/tests/winhttp.c +++ b/dlls/winhttp/tests/winhttp.c @@ -5531,6 +5531,104 @@ static void test_client_cert_authentication(void) WinHttpCloseHandle( ses ); }
+static void test_websocket_fragment(void) +{ + HINTERNET session, connection, request, socket; + DWORD size, len, status, error, count; + WINHTTP_WEB_SOCKET_BUFFER_TYPE type; + USHORT close_status; + char buf[128]; + BOOL ret; + + session = WinHttpOpen(L"winetest", 0, NULL, NULL, 0); + ok(session != NULL, "got %lu\n", GetLastError()); + + connection = WinHttpConnect(session, L"192.168.1.3", 12345, 0); + ok(connection != NULL, "got %lu\n", GetLastError()); + + request = WinHttpOpenRequest(connection, L"GET", L"/", NULL, NULL, NULL, 0); + ok(request != NULL, "got %lu\n", GetLastError()); + + ret = WinHttpSetOption(request, WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, NULL, 0); + ok(ret, "got %lu\n", GetLastError()); + + ret = WinHttpSendRequest(request, NULL, 0, NULL, 0, 0, 0); + ok(ret, "got %lu\n", GetLastError()); + + ret = WinHttpReceiveResponse(request, NULL); + ok(ret, "got %lu\n", GetLastError()); + + status = 0xdeadbeef; + size = sizeof(status); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, + &size, NULL); + ok(ret, "got %lu\n", GetLastError()); + ok(status == HTTP_STATUS_SWITCH_PROTOCOLS, "got %lu\n", status); + + socket = pWinHttpWebSocketCompleteUpgrade(request, 0); + ok(socket != NULL, "got %lu\n", GetLastError()); + + buf[0] = 0; + count = 0; + type = 0xdeadbeef; + error = pWinHttpWebSocketReceive(socket, buf, sizeof(buf), &count, &type); + ok(!error, "got %lu\n", error); + ok(count == 9, "got %lu\n", count); + ok(!strncmp(buf, "fragment1", 9), "got %s\n", buf); + ok(type == WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE, "got %u\n", type); + + buf[0] = 0; + count = 0; + type = 0xdeadbeef; + error = pWinHttpWebSocketReceive(socket, buf, sizeof(buf), &count, &type); + ok(!error, "got %lu\n", error); + ok(count == 9, "got %lu\n", count); + ok(!strncmp(buf, "fragment2", 9), "got %s\n", buf); + ok(type == WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE, "got %u\n", type); + + buf[0] = 0; + count = 0; + type = 0xdeadbeef; + error = pWinHttpWebSocketReceive(socket, buf, sizeof(buf), &count, &type); + ok(!error, "got %lu\n", error); + ok(count == 9, "got %lu\n", count); + ok(!strncmp(buf, "fragment3", 9), "got %s\n", buf); + ok(type == WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE, "got %u\n", type); + + buf[0] = 0; + count = 0; + type = 0xdeadbeef; + error = pWinHttpWebSocketReceive(socket, buf, sizeof(buf), &count, &type); + ok(!error, "got %lu\n", error); + ok(count == 0, "got %lu\n", count); + ok(type == WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE, "got %u\n", type); + + buf[0] = 0; + count = 0; + type = 0xdeadbeef; + error = pWinHttpWebSocketReceive(socket, buf, sizeof(buf), &count, &type); + ok(!error, "got %lu\n", error); + ok(count == 0, "got %lu\n", count); + ok(type == WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE, "got %u\n", type); + + error = pWinHttpWebSocketClose(socket, WINHTTP_WEB_SOCKET_SUCCESS_CLOSE_STATUS, (void *)"success2", + sizeof("success2")); + ok(!error, "got %lu\n", error); + + close_status = 0xdead; + len = 0xdeadbeef; + memset(buf, 0, sizeof(buf)); + error = pWinHttpWebSocketQueryCloseStatus(socket, &close_status, buf, sizeof(buf), &len); + ok(!error, "got %lu\n", error); + ok(close_status == 1000, "got %d\n", close_status); + ok(!len, "got %lu\n", len); + + WinHttpCloseHandle(socket); + WinHttpCloseHandle(request); + WinHttpCloseHandle(connection); + WinHttpCloseHandle(session); +} + START_TEST (winhttp) { struct server_info si; @@ -5545,6 +5643,7 @@ START_TEST (winhttp) pWinHttpWebSocketShutdown = (void *)GetProcAddress(mod, "WinHttpWebSocketShutdown"); pWinHttpWebSocketReceive = (void *)GetProcAddress(mod, "WinHttpWebSocketReceive");
+if(0){ test_WinHttpOpenRequest(); test_WinHttpSendRequest(); test_WinHttpTimeFromSystemTime(); @@ -5603,4 +5702,6 @@ START_TEST (winhttp)
WaitForSingleObject(thread, 3000); CloseHandle(thread); +} + test_websocket_fragment(); }
Sorry, this patch got mailed by mistake (it is not inside the series and the rest of the series does not depend on it).
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=109221
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
winhttp: winhttp.c:5536: Test failed: got 12009 winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12019 winhttp.c:5549: Test failed: got 3735928559 02d4:winhttp: unhandled exception c0000005 at 00000000
=== w7u_adm (32 bit report) ===
winhttp: winhttp.c:5536: Test failed: got 12009 winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12019 winhttp.c:5549: Test failed: got 3735928559 0868:winhttp: unhandled exception c0000005 at 00000000
=== w7u_el (32 bit report) ===
winhttp: winhttp.c:5536: Test failed: got 12009 winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12019 winhttp.c:5549: Test failed: got 3735928559 086c:winhttp: unhandled exception c0000005 at 00000000
=== w8 (32 bit report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12019 winhttp.c:5549: Test failed: got 3735928559 winhttp.c:5552: Test failed: got 4317 winhttp.c:5558: Test failed: got 6 winhttp.c:5559: Test failed: got 0 winhttp.c:5560: Test failed: got winhttp.c:5561: Test failed: got 3735928559 winhttp.c:5567: Test failed: got 6 winhttp.c:5568: Test failed: got 0 winhttp.c:5569: Test failed: got winhttp.c:5570: Test failed: got 3735928559 winhttp.c:5576: Test failed: got 6 winhttp.c:5577: Test failed: got 0 winhttp.c:5578: Test failed: got winhttp.c:5579: Test failed: got 3735928559 winhttp.c:5585: Test failed: got 6 winhttp.c:5587: Test failed: got 3735928559 winhttp.c:5593: Test failed: got 6 winhttp.c:5595: Test failed: got 3735928559 winhttp.c:5599: Test failed: got 6 winhttp.c:5605: Test failed: got 6 winhttp.c:5606: Test failed: got 57005 winhttp.c:5607: Test failed: got 3735928559
=== w8adm (32 bit report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12019 winhttp.c:5549: Test failed: got 3735928559 winhttp.c:5552: Test failed: got 4317 winhttp.c:5558: Test failed: got 6 winhttp.c:5559: Test failed: got 0 winhttp.c:5560: Test failed: got winhttp.c:5561: Test failed: got 3735928559 winhttp.c:5567: Test failed: got 6 winhttp.c:5568: Test failed: got 0 winhttp.c:5569: Test failed: got winhttp.c:5570: Test failed: got 3735928559 winhttp.c:5576: Test failed: got 6 winhttp.c:5577: Test failed: got 0 winhttp.c:5578: Test failed: got winhttp.c:5579: Test failed: got 3735928559 winhttp.c:5585: Test failed: got 6 winhttp.c:5587: Test failed: got 3735928559 winhttp.c:5593: Test failed: got 6 winhttp.c:5595: Test failed: got 3735928559 winhttp.c:5599: Test failed: got 6 winhttp.c:5605: Test failed: got 6 winhttp.c:5606: Test failed: got 57005 winhttp.c:5607: Test failed: got 3735928559
=== w864 (32 bit report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12019 winhttp.c:5549: Test failed: got 3735928559 winhttp.c:5552: Test failed: got 4317 winhttp.c:5558: Test failed: got 6 winhttp.c:5559: Test failed: got 0 winhttp.c:5560: Test failed: got winhttp.c:5561: Test failed: got 3735928559 winhttp.c:5567: Test failed: got 6 winhttp.c:5568: Test failed: got 0 winhttp.c:5569: Test failed: got winhttp.c:5570: Test failed: got 3735928559 winhttp.c:5576: Test failed: got 6 winhttp.c:5577: Test failed: got 0 winhttp.c:5578: Test failed: got winhttp.c:5579: Test failed: got 3735928559 winhttp.c:5585: Test failed: got 6 winhttp.c:5587: Test failed: got 3735928559 winhttp.c:5593: Test failed: got 6 winhttp.c:5595: Test failed: got 3735928559 winhttp.c:5599: Test failed: got 6 winhttp.c:5605: Test failed: got 6 winhttp.c:5606: Test failed: got 57005 winhttp.c:5607: Test failed: got 3735928559
=== w1064v1507 (32 bit report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12019 winhttp.c:5549: Test failed: got 3735928559 winhttp.c:5552: Test failed: got 4317 winhttp.c:5558: Test failed: got 6 winhttp.c:5559: Test failed: got 0 winhttp.c:5560: Test failed: got winhttp.c:5561: Test failed: got 3735928559 winhttp.c:5567: Test failed: got 6 winhttp.c:5568: Test failed: got 0 winhttp.c:5569: Test failed: got winhttp.c:5570: Test failed: got 3735928559 winhttp.c:5576: Test failed: got 6 winhttp.c:5577: Test failed: got 0 winhttp.c:5578: Test failed: got winhttp.c:5579: Test failed: got 3735928559 winhttp.c:5585: Test failed: got 6 winhttp.c:5587: Test failed: got 3735928559 winhttp.c:5593: Test failed: got 6 winhttp.c:5595: Test failed: got 3735928559 winhttp.c:5599: Test failed: got 6 winhttp.c:5605: Test failed: got 6 winhttp.c:5606: Test failed: got 57005 winhttp.c:5607: Test failed: got 3735928559
=== w1064v1809 (32 bit report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12019 winhttp.c:5549: Test failed: got 3735928559 winhttp.c:5552: Test failed: got 4317 winhttp.c:5558: Test failed: got 6 winhttp.c:5559: Test failed: got 0 winhttp.c:5560: Test failed: got winhttp.c:5561: Test failed: got 3735928559 winhttp.c:5567: Test failed: got 6 winhttp.c:5568: Test failed: got 0 winhttp.c:5569: Test failed: got winhttp.c:5570: Test failed: got 3735928559 winhttp.c:5576: Test failed: got 6 winhttp.c:5577: Test failed: got 0 winhttp.c:5578: Test failed: got winhttp.c:5579: Test failed: got 3735928559 winhttp.c:5585: Test failed: got 6 winhttp.c:5587: Test failed: got 3735928559 winhttp.c:5593: Test failed: got 6 winhttp.c:5595: Test failed: got 3735928559 winhttp.c:5599: Test failed: got 6 winhttp.c:5605: Test failed: got 6 winhttp.c:5606: Test failed: got 57005 winhttp.c:5607: Test failed: got 3735928559
=== w1064 (32 bit report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12019 winhttp.c:5549: Test failed: got 3735928559 winhttp.c:5552: Test failed: got 4317 winhttp.c:5558: Test failed: got 6 winhttp.c:5559: Test failed: got 0 winhttp.c:5560: Test failed: got winhttp.c:5561: Test failed: got 3735928559 winhttp.c:5567: Test failed: got 6 winhttp.c:5568: Test failed: got 0 winhttp.c:5569: Test failed: got winhttp.c:5570: Test failed: got 3735928559 winhttp.c:5576: Test failed: got 6 winhttp.c:5577: Test failed: got 0 winhttp.c:5578: Test failed: got winhttp.c:5579: Test failed: got 3735928559 winhttp.c:5585: Test failed: got 6 winhttp.c:5587: Test failed: got 3735928559 winhttp.c:5593: Test failed: got 6 winhttp.c:5595: Test failed: got 3735928559 winhttp.c:5599: Test failed: got 6 winhttp.c:5605: Test failed: got 6 winhttp.c:5606: Test failed: got 57005 winhttp.c:5607: Test failed: got 3735928559
=== w1064_tsign (32 bit report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12019 winhttp.c:5549: Test failed: got 3735928559 winhttp.c:5552: Test failed: got 4317 winhttp.c:5558: Test failed: got 6 winhttp.c:5559: Test failed: got 0 winhttp.c:5560: Test failed: got winhttp.c:5561: Test failed: got 3735928559 winhttp.c:5567: Test failed: got 6 winhttp.c:5568: Test failed: got 0 winhttp.c:5569: Test failed: got winhttp.c:5570: Test failed: got 3735928559 winhttp.c:5576: Test failed: got 6 winhttp.c:5577: Test failed: got 0 winhttp.c:5578: Test failed: got winhttp.c:5579: Test failed: got 3735928559 winhttp.c:5585: Test failed: got 6 winhttp.c:5587: Test failed: got 3735928559 winhttp.c:5593: Test failed: got 6 winhttp.c:5595: Test failed: got 3735928559 winhttp.c:5599: Test failed: got 6 winhttp.c:5605: Test failed: got 6 winhttp.c:5606: Test failed: got 57005 winhttp.c:5607: Test failed: got 3735928559
=== w10pro64 (32 bit report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12019 winhttp.c:5549: Test failed: got 3735928559 winhttp.c:5552: Test failed: got 4317 winhttp.c:5558: Test failed: got 6 winhttp.c:5559: Test failed: got 0 winhttp.c:5560: Test failed: got winhttp.c:5561: Test failed: got 3735928559 winhttp.c:5567: Test failed: got 6 winhttp.c:5568: Test failed: got 0 winhttp.c:5569: Test failed: got winhttp.c:5570: Test failed: got 3735928559 winhttp.c:5576: Test failed: got 6 winhttp.c:5577: Test failed: got 0 winhttp.c:5578: Test failed: got winhttp.c:5579: Test failed: got 3735928559 winhttp.c:5585: Test failed: got 6 winhttp.c:5587: Test failed: got 3735928559 winhttp.c:5593: Test failed: got 6 winhttp.c:5595: Test failed: got 3735928559 winhttp.c:5599: Test failed: got 6 winhttp.c:5605: Test failed: got 6 winhttp.c:5606: Test failed: got 57005 winhttp.c:5607: Test failed: got 3735928559
=== w864 (64 bit report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12019 winhttp.c:5549: Test failed: got 3735928559 winhttp.c:5552: Test failed: got 4317 winhttp.c:5558: Test failed: got 6 winhttp.c:5559: Test failed: got 0 winhttp.c:5560: Test failed: got winhttp.c:5561: Test failed: got 3735928559 winhttp.c:5567: Test failed: got 6 winhttp.c:5568: Test failed: got 0 winhttp.c:5569: Test failed: got winhttp.c:5570: Test failed: got 3735928559 winhttp.c:5576: Test failed: got 6 winhttp.c:5577: Test failed: got 0 winhttp.c:5578: Test failed: got winhttp.c:5579: Test failed: got 3735928559 winhttp.c:5585: Test failed: got 6 winhttp.c:5587: Test failed: got 3735928559 winhttp.c:5593: Test failed: got 6 winhttp.c:5595: Test failed: got 3735928559 winhttp.c:5599: Test failed: got 6 winhttp.c:5605: Test failed: got 6 winhttp.c:5606: Test failed: got 57005 winhttp.c:5607: Test failed: got 3735928559
=== w1064v1507 (64 bit report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12019 winhttp.c:5549: Test failed: got 3735928559 winhttp.c:5552: Test failed: got 4317 winhttp.c:5558: Test failed: got 6 winhttp.c:5559: Test failed: got 0 winhttp.c:5560: Test failed: got winhttp.c:5561: Test failed: got 3735928559 winhttp.c:5567: Test failed: got 6 winhttp.c:5568: Test failed: got 0 winhttp.c:5569: Test failed: got winhttp.c:5570: Test failed: got 3735928559 winhttp.c:5576: Test failed: got 6 winhttp.c:5577: Test failed: got 0 winhttp.c:5578: Test failed: got winhttp.c:5579: Test failed: got 3735928559 winhttp.c:5585: Test failed: got 6 winhttp.c:5587: Test failed: got 3735928559 winhttp.c:5593: Test failed: got 6 winhttp.c:5595: Test failed: got 3735928559 winhttp.c:5599: Test failed: got 6 winhttp.c:5605: Test failed: got 6 winhttp.c:5606: Test failed: got 57005 winhttp.c:5607: Test failed: got 3735928559
=== w1064v1809 (64 bit report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12019 winhttp.c:5549: Test failed: got 3735928559 winhttp.c:5552: Test failed: got 4317 winhttp.c:5558: Test failed: got 6 winhttp.c:5559: Test failed: got 0 winhttp.c:5560: Test failed: got winhttp.c:5561: Test failed: got 3735928559 winhttp.c:5567: Test failed: got 6 winhttp.c:5568: Test failed: got 0 winhttp.c:5569: Test failed: got winhttp.c:5570: Test failed: got 3735928559 winhttp.c:5576: Test failed: got 6 winhttp.c:5577: Test failed: got 0 winhttp.c:5578: Test failed: got winhttp.c:5579: Test failed: got 3735928559 winhttp.c:5585: Test failed: got 6 winhttp.c:5587: Test failed: got 3735928559 winhttp.c:5593: Test failed: got 6 winhttp.c:5595: Test failed: got 3735928559 winhttp.c:5599: Test failed: got 6 winhttp.c:5605: Test failed: got 6 winhttp.c:5606: Test failed: got 57005 winhttp.c:5607: Test failed: got 3735928559
=== w1064 (64 bit report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12019 winhttp.c:5549: Test failed: got 3735928559 winhttp.c:5552: Test failed: got 4317 winhttp.c:5558: Test failed: got 6 winhttp.c:5559: Test failed: got 0 winhttp.c:5560: Test failed: got winhttp.c:5561: Test failed: got 3735928559 winhttp.c:5567: Test failed: got 6 winhttp.c:5568: Test failed: got 0 winhttp.c:5569: Test failed: got winhttp.c:5570: Test failed: got 3735928559 winhttp.c:5576: Test failed: got 6 winhttp.c:5577: Test failed: got 0 winhttp.c:5578: Test failed: got winhttp.c:5579: Test failed: got 3735928559 winhttp.c:5585: Test failed: got 6 winhttp.c:5587: Test failed: got 3735928559 winhttp.c:5593: Test failed: got 6 winhttp.c:5595: Test failed: got 3735928559 winhttp.c:5599: Test failed: got 6 winhttp.c:5605: Test failed: got 6 winhttp.c:5606: Test failed: got 57005 winhttp.c:5607: Test failed: got 3735928559
=== w1064_2qxl (64 bit report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12019 winhttp.c:5549: Test failed: got 3735928559 winhttp.c:5552: Test failed: got 4317 winhttp.c:5558: Test failed: got 6 winhttp.c:5559: Test failed: got 0 winhttp.c:5560: Test failed: got winhttp.c:5561: Test failed: got 3735928559 winhttp.c:5567: Test failed: got 6 winhttp.c:5568: Test failed: got 0 winhttp.c:5569: Test failed: got winhttp.c:5570: Test failed: got 3735928559 winhttp.c:5576: Test failed: got 6 winhttp.c:5577: Test failed: got 0 winhttp.c:5578: Test failed: got winhttp.c:5579: Test failed: got 3735928559 winhttp.c:5585: Test failed: got 6 winhttp.c:5587: Test failed: got 3735928559 winhttp.c:5593: Test failed: got 6 winhttp.c:5595: Test failed: got 3735928559 winhttp.c:5599: Test failed: got 6 winhttp.c:5605: Test failed: got 6 winhttp.c:5606: Test failed: got 57005 winhttp.c:5607: Test failed: got 3735928559
=== w1064_tsign (64 bit report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12019 winhttp.c:5549: Test failed: got 3735928559 winhttp.c:5552: Test failed: got 4317 winhttp.c:5558: Test failed: got 6 winhttp.c:5559: Test failed: got 0 winhttp.c:5560: Test failed: got winhttp.c:5561: Test failed: got 3735928559 winhttp.c:5567: Test failed: got 6 winhttp.c:5568: Test failed: got 0 winhttp.c:5569: Test failed: got winhttp.c:5570: Test failed: got 3735928559 winhttp.c:5576: Test failed: got 6 winhttp.c:5577: Test failed: got 0 winhttp.c:5578: Test failed: got winhttp.c:5579: Test failed: got 3735928559 winhttp.c:5585: Test failed: got 6 winhttp.c:5587: Test failed: got 3735928559 winhttp.c:5593: Test failed: got 6 winhttp.c:5595: Test failed: got 3735928559 winhttp.c:5599: Test failed: got 6 winhttp.c:5605: Test failed: got 6 winhttp.c:5606: Test failed: got 57005 winhttp.c:5607: Test failed: got 3735928559
=== w10pro64 (64 bit report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12019 winhttp.c:5549: Test failed: got 3735928559 winhttp.c:5552: Test failed: got 4317 winhttp.c:5558: Test failed: got 6 winhttp.c:5559: Test failed: got 0 winhttp.c:5560: Test failed: got winhttp.c:5561: Test failed: got 3735928559 winhttp.c:5567: Test failed: got 6 winhttp.c:5568: Test failed: got 0 winhttp.c:5569: Test failed: got winhttp.c:5570: Test failed: got 3735928559 winhttp.c:5576: Test failed: got 6 winhttp.c:5577: Test failed: got 0 winhttp.c:5578: Test failed: got winhttp.c:5579: Test failed: got 3735928559 winhttp.c:5585: Test failed: got 6 winhttp.c:5587: Test failed: got 3735928559 winhttp.c:5593: Test failed: got 6 winhttp.c:5595: Test failed: got 3735928559 winhttp.c:5599: Test failed: got 6 winhttp.c:5605: Test failed: got 6 winhttp.c:5606: Test failed: got 57005 winhttp.c:5607: Test failed: got 3735928559
=== w10pro64_ar (64 bit report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12019 winhttp.c:5549: Test failed: got 3735928559 winhttp.c:5552: Test failed: got 4317 winhttp.c:5558: Test failed: got 6 winhttp.c:5559: Test failed: got 0 winhttp.c:5560: Test failed: got winhttp.c:5561: Test failed: got 3735928559 winhttp.c:5567: Test failed: got 6 winhttp.c:5568: Test failed: got 0 winhttp.c:5569: Test failed: got winhttp.c:5570: Test failed: got 3735928559 winhttp.c:5576: Test failed: got 6 winhttp.c:5577: Test failed: got 0 winhttp.c:5578: Test failed: got winhttp.c:5579: Test failed: got 3735928559 winhttp.c:5585: Test failed: got 6 winhttp.c:5587: Test failed: got 3735928559 winhttp.c:5593: Test failed: got 6 winhttp.c:5595: Test failed: got 3735928559 winhttp.c:5599: Test failed: got 6 winhttp.c:5605: Test failed: got 6 winhttp.c:5606: Test failed: got 57005 winhttp.c:5607: Test failed: got 3735928559
=== w10pro64_he (64 bit report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12019 winhttp.c:5549: Test failed: got 3735928559 winhttp.c:5552: Test failed: got 4317 winhttp.c:5558: Test failed: got 6 winhttp.c:5559: Test failed: got 0 winhttp.c:5560: Test failed: got winhttp.c:5561: Test failed: got 3735928559 winhttp.c:5567: Test failed: got 6 winhttp.c:5568: Test failed: got 0 winhttp.c:5569: Test failed: got winhttp.c:5570: Test failed: got 3735928559 winhttp.c:5576: Test failed: got 6 winhttp.c:5577: Test failed: got 0 winhttp.c:5578: Test failed: got winhttp.c:5579: Test failed: got 3735928559 winhttp.c:5585: Test failed: got 6 winhttp.c:5587: Test failed: got 3735928559 winhttp.c:5593: Test failed: got 6 winhttp.c:5595: Test failed: got 3735928559 winhttp.c:5599: Test failed: got 6 winhttp.c:5605: Test failed: got 6 winhttp.c:5606: Test failed: got 57005 winhttp.c:5607: Test failed: got 3735928559
=== w10pro64_ja (64 bit report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12019 winhttp.c:5549: Test failed: got 3735928559 winhttp.c:5552: Test failed: got 4317 winhttp.c:5558: Test failed: got 6 winhttp.c:5559: Test failed: got 0 winhttp.c:5560: Test failed: got winhttp.c:5561: Test failed: got 3735928559 winhttp.c:5567: Test failed: got 6 winhttp.c:5568: Test failed: got 0 winhttp.c:5569: Test failed: got winhttp.c:5570: Test failed: got 3735928559 winhttp.c:5576: Test failed: got 6 winhttp.c:5577: Test failed: got 0 winhttp.c:5578: Test failed: got winhttp.c:5579: Test failed: got 3735928559 winhttp.c:5585: Test failed: got 6 winhttp.c:5587: Test failed: got 3735928559 winhttp.c:5593: Test failed: got 6 winhttp.c:5595: Test failed: got 3735928559 winhttp.c:5599: Test failed: got 6 winhttp.c:5605: Test failed: got 6 winhttp.c:5606: Test failed: got 57005 winhttp.c:5607: Test failed: got 3735928559
=== w10pro64_zh_CN (64 bit report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12019 winhttp.c:5549: Test failed: got 3735928559 winhttp.c:5552: Test failed: got 4317 winhttp.c:5558: Test failed: got 6 winhttp.c:5559: Test failed: got 0 winhttp.c:5560: Test failed: got winhttp.c:5561: Test failed: got 3735928559 winhttp.c:5567: Test failed: got 6 winhttp.c:5568: Test failed: got 0 winhttp.c:5569: Test failed: got winhttp.c:5570: Test failed: got 3735928559 winhttp.c:5576: Test failed: got 6 winhttp.c:5577: Test failed: got 0 winhttp.c:5578: Test failed: got winhttp.c:5579: Test failed: got 3735928559 winhttp.c:5585: Test failed: got 6 winhttp.c:5587: Test failed: got 3735928559 winhttp.c:5593: Test failed: got 6 winhttp.c:5595: Test failed: got 3735928559 winhttp.c:5599: Test failed: got 6 winhttp.c:5605: Test failed: got 6 winhttp.c:5606: Test failed: got 57005 winhttp.c:5607: Test failed: got 3735928559
=== debian11 (32 bit report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12150 winhttp.c:5549: Test failed: got 3735928559 Unhandled exception: page fault on read access to 0x00000090 in 32-bit code (0x6960546c).
=== debian11 (32 bit Arabic:Morocco report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12150 winhttp.c:5549: Test failed: got 3735928559 Unhandled exception: page fault on read access to 0x00000090 in 32-bit code (0x6960546c).
=== debian11 (32 bit German report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12150 winhttp.c:5549: Test failed: got 3735928559 Unhandled exception: page fault on read access to 0x00000090 in 32-bit code (0x6960546c).
=== debian11 (32 bit French report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12150 winhttp.c:5549: Test failed: got 3735928559 Unhandled exception: page fault on read access to 0x00000090 in 32-bit code (0x6960546c).
=== debian11 (32 bit Hebrew:Israel report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12150 winhttp.c:5549: Test failed: got 3735928559 Unhandled exception: page fault on read access to 0x00000090 in 32-bit code (0x6960546c).
=== debian11 (32 bit Hindi:India report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12150 winhttp.c:5549: Test failed: got 3735928559 Unhandled exception: page fault on read access to 0x00000090 in 32-bit code (0x6960546c).
=== debian11 (32 bit Japanese:Japan report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12150 winhttp.c:5549: Test failed: got 3735928559 Unhandled exception: page fault on read access to 0x00000090 in 32-bit code (0x6960546c).
=== debian11 (32 bit Chinese:China report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12150 winhttp.c:5549: Test failed: got 3735928559 Unhandled exception: page fault on read access to 0x00000090 in 32-bit code (0x6960546c).
=== debian11 (32 bit WoW report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12150 winhttp.c:5549: Test failed: got 3735928559 Unhandled exception: page fault on read access to 0x00000090 in 32-bit code (0x6960546c).
=== debian11 (64 bit WoW report) ===
winhttp: winhttp.c:5539: Test failed: got 12002 winhttp.c:5542: Test failed: got 12019 winhttp.c:5548: Test failed: got 12150 winhttp.c:5549: Test failed: got 3735928559 Unhandled exception: page fault on read access to 0x0000000000000098 in 64-bit code (0x0000000069405578).
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- This is conformant to rfc6455, Section 5.4.
dlls/winhttp/request.c | 91 +++++++++++++++++++++++++++---- dlls/winhttp/tests/notification.c | 22 +++++++- dlls/winhttp/winhttp_private.h | 8 +++ 3 files changed, 108 insertions(+), 13 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index de011060236..ac3449c0507 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -3298,13 +3298,64 @@ static BOOL socket_can_receive( struct socket *socket ) return socket->state <= SOCKET_STATE_SHUTDOWN && !socket->close_frame_received; }
-static enum socket_opcode map_buffer_type( WINHTTP_WEB_SOCKET_BUFFER_TYPE type ) +static BOOL validate_buffer_type( WINHTTP_WEB_SOCKET_BUFFER_TYPE type, enum fragment_type current_fragment ) +{ + switch (current_fragment) + { + case SOCKET_FRAGMENT_NONE: + return type == WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE + || type == WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE + || type == WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE + || type == WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE; + case SOCKET_FRAGMENT_BINARY: + return type == WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE + || type == WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE; + case SOCKET_FRAGMENT_UTF8: + return type == WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE + || type == WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE; + } + assert( 0 ); + return FALSE; +} + +static enum socket_opcode map_buffer_type( struct socket *socket, WINHTTP_WEB_SOCKET_BUFFER_TYPE type, BOOL *final ) { + *final = TRUE; + switch (type) { - case WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE: return SOCKET_OPCODE_TEXT; - case WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE: return SOCKET_OPCODE_BINARY; - case WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE: return SOCKET_OPCODE_CLOSE; + case WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE: + if (socket->sending_fragment_type) + { + socket->sending_fragment_type = SOCKET_FRAGMENT_NONE; + return SOCKET_OPCODE_CONTINUE; + } + return SOCKET_OPCODE_TEXT; + case WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE: + if (socket->sending_fragment_type) + { + socket->sending_fragment_type = SOCKET_FRAGMENT_NONE; + return SOCKET_OPCODE_CONTINUE; + } + return SOCKET_OPCODE_BINARY; + case WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE: + *final = FALSE; + if (!socket->sending_fragment_type) + { + socket->sending_fragment_type = SOCKET_FRAGMENT_UTF8; + return SOCKET_OPCODE_TEXT; + } + return SOCKET_OPCODE_CONTINUE; + case WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE: + *final = FALSE; + if (!socket->sending_fragment_type) + { + socket->sending_fragment_type = SOCKET_FRAGMENT_BINARY; + return SOCKET_OPCODE_BINARY; + } + return SOCKET_OPCODE_CONTINUE; + case WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE: + return SOCKET_OPCODE_CLOSE; default: FIXME("buffer type %u not supported\n", type); return SOCKET_OPCODE_INVALID; @@ -3333,9 +3384,12 @@ static void socket_send_complete( struct socket *socket, DWORD ret, WINHTTP_WEB_ static DWORD socket_send( struct socket *socket, WINHTTP_WEB_SOCKET_BUFFER_TYPE type, const void *buf, DWORD len, WSAOVERLAPPED *ovr ) { - enum socket_opcode opcode = map_buffer_type( type ); + enum socket_opcode opcode; + BOOL final; + + opcode = map_buffer_type( socket, type, &final );
- return send_frame( socket, opcode, 0, buf, len, TRUE, ovr ); + return send_frame( socket, opcode, 0, buf, len, final, ovr ); }
static void CALLBACK task_socket_send( TP_CALLBACK_INSTANCE *instance, void *ctx, TP_WORK *work ) @@ -3364,11 +3418,6 @@ DWORD WINAPI WinHttpWebSocketSend( HINTERNET hsocket, WINHTTP_WEB_SOCKET_BUFFER_ TRACE( "%p, %u, %p, %lu\n", hsocket, type, buf, len );
if (len && !buf) return ERROR_INVALID_PARAMETER; - if (type != WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE && type != WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE) - { - FIXME("buffer type %u not supported\n", type); - return ERROR_NOT_SUPPORTED; - }
if (!(socket = (struct socket *)grab_object( hsocket ))) return ERROR_INVALID_HANDLE; if (socket->hdr.type != WINHTTP_HANDLE_TYPE_SOCKET) @@ -3393,6 +3442,13 @@ DWORD WINAPI WinHttpWebSocketSend( HINTERNET hsocket, WINHTTP_WEB_SOCKET_BUFFER_ release_object( &socket->hdr ); return ERROR_INVALID_OPERATION; } + if (!validate_buffer_type( type, socket->sending_fragment_type )) + { + WARN( "Invalid buffer type %u, sending_fragment_type %u.\n", type, socket->sending_fragment_type ); + InterlockedExchange( &socket->pending_noncontrol_send, 0 ); + release_object( &socket->hdr ); + return ERROR_INVALID_PARAMETER; + }
if (!(s = malloc( sizeof(*s) ))) { @@ -3445,7 +3501,18 @@ DWORD WINAPI WinHttpWebSocketSend( HINTERNET hsocket, WINHTTP_WEB_SOCKET_BUFFER_ ret = ERROR_SUCCESS; } } - else ret = socket_send( socket, type, buf, len, NULL ); + else + { + if (validate_buffer_type( type, socket->sending_fragment_type )) + { + ret = socket_send( socket, type, buf, len, NULL ); + } + else + { + WARN( "Invalid buffer type %u, sending_fragment_type %u.\n", type, socket->sending_fragment_type ); + ret = ERROR_INVALID_PARAMETER; + } + }
release_object( &socket->hdr ); return ret; diff --git a/dlls/winhttp/tests/notification.c b/dlls/winhttp/tests/notification.c index ffde61b3bf5..50874a49a07 100644 --- a/dlls/winhttp/tests/notification.c +++ b/dlls/winhttp/tests/notification.c @@ -676,6 +676,8 @@ static const struct notification websocket_test[] = { winhttp_websocket_complete_upgrade, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, NF_SIGNAL }, { winhttp_websocket_send, WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, NF_MAIN_THREAD | NF_SIGNAL }, { winhttp_websocket_send, WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, NF_MAIN_THREAD | NF_SIGNAL }, + { winhttp_websocket_send, WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, NF_MAIN_THREAD | NF_SIGNAL }, + { winhttp_websocket_send, WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, NF_MAIN_THREAD | NF_SIGNAL }, { winhttp_websocket_shutdown, WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE, NF_MAIN_THREAD | NF_SIGNAL }, { winhttp_websocket_receive, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SAVE_BUFFER | NF_SIGNAL }, { winhttp_websocket_receive, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SAVE_BUFFER | NF_SIGNAL }, @@ -867,7 +869,25 @@ static void test_websocket(BOOL secure) for (i = 0; i < BIG_BUFFER_SIZE; ++i) big_buffer[i] = (i & 0xff) ^ 0xcc;
setup_test( &info, winhttp_websocket_send, __LINE__ ); - err = pWinHttpWebSocketSend( socket, WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE, big_buffer, BIG_BUFFER_SIZE ); + err = pWinHttpWebSocketSend( socket, WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE, big_buffer, BIG_BUFFER_SIZE / 2 ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + WaitForSingleObject( info.wait, INFINITE ); + + err = pWinHttpWebSocketSend( socket, WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE, + big_buffer + BIG_BUFFER_SIZE / 2, BIG_BUFFER_SIZE / 2 ); + ok( err == ERROR_INVALID_PARAMETER, "got %lu\n", err ); + err = pWinHttpWebSocketSend( socket, WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE, + big_buffer + BIG_BUFFER_SIZE / 2, BIG_BUFFER_SIZE / 2 ); + ok( err == ERROR_INVALID_PARAMETER, "got %lu\n", err ); + + setup_test( &info, winhttp_websocket_send, __LINE__ ); + err = pWinHttpWebSocketSend( socket, WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE, + big_buffer + BIG_BUFFER_SIZE / 2, BIG_BUFFER_SIZE / 2 ); + ok( err == ERROR_SUCCESS, "got %lu\n", err ); + WaitForSingleObject( info.wait, INFINITE ); + + setup_test( &info, winhttp_websocket_send, __LINE__ ); + err = pWinHttpWebSocketSend( socket, WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE, NULL, 0 ); ok( err == ERROR_SUCCESS, "got %lu\n", err ); WaitForSingleObject( info.wait, INFINITE );
diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h index cf6655f561f..bebc3ac1a07 100644 --- a/dlls/winhttp/winhttp_private.h +++ b/dlls/winhttp/winhttp_private.h @@ -238,6 +238,13 @@ enum socket_opcode SOCKET_OPCODE_INVALID = 0xff, };
+enum fragment_type +{ + SOCKET_FRAGMENT_NONE, + SOCKET_FRAGMENT_BINARY, + SOCKET_FRAGMENT_UTF8, +}; + struct socket { struct object_header hdr; @@ -261,6 +268,7 @@ struct socket unsigned int client_buffer_offset; SRWLOCK send_lock; volatile LONG pending_noncontrol_send; + enum fragment_type sending_fragment_type; };
struct send_request
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- Our test server doesn't seem to send fragmented frames but I tested that using this using: - this python script as websocket server: https://gist.github.com/gofman/863f295effd6dc2be692c2c480c4225f - this local patch with the test: https://gist.github.com/gofman/44193231a593968cf3d9befc53ae8bc8 (L"192.168.1.3" should be changed to the test ws server host address).
dlls/winhttp/request.c | 66 +++++++++++++++++++++++++++++----- dlls/winhttp/winhttp_private.h | 2 ++ 2 files changed, 59 insertions(+), 9 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index ac3449c0507..131138ed313 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -3550,6 +3550,7 @@ static BOOL is_supported_opcode( enum socket_opcode opcode ) { switch (opcode) { + case SOCKET_OPCODE_CONTINUE: case SOCKET_OPCODE_TEXT: case SOCKET_OPCODE_BINARY: case SOCKET_OPCODE_CLOSE: @@ -3562,7 +3563,7 @@ static BOOL is_supported_opcode( enum socket_opcode opcode ) } }
-static DWORD receive_frame( struct socket *socket, DWORD *ret_len, enum socket_opcode *opcode ) +static DWORD receive_frame( struct socket *socket, DWORD *ret_len, enum socket_opcode *opcode, BOOL *final ) { DWORD ret, len, count; char hdr[2]; @@ -3573,7 +3574,8 @@ static DWORD receive_frame( struct socket *socket, DWORD *ret_len, enum socket_o return ERROR_WINHTTP_INVALID_SERVER_RESPONSE; } *opcode = hdr[0] & 0xf; - TRACE("received %02x frame\n", *opcode); + *final = hdr[0] & FIN_BIT; + TRACE("received %02x frame, final %#x\n", *opcode, *final);
len = hdr[1] & ~MASK_BIT; if (len == 126) @@ -3720,18 +3722,49 @@ static DWORD handle_control_frame( struct socket *socket ) return ERROR_SUCCESS; }
-static WINHTTP_WEB_SOCKET_BUFFER_TYPE map_opcode( enum socket_opcode opcode, BOOL fragment ) +static WINHTTP_WEB_SOCKET_BUFFER_TYPE map_opcode( struct socket *socket, enum socket_opcode opcode, BOOL fragment ) { + enum fragment_type frag_type = socket->receiving_fragment_type; + switch (opcode) { case SOCKET_OPCODE_TEXT: - if (fragment) return WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE; + if (frag_type && frag_type != SOCKET_FRAGMENT_UTF8) + FIXME( "Received SOCKET_OPCODE_TEXT with prev fragment %u.\n", frag_type ); + if (fragment) + { + socket->receiving_fragment_type = SOCKET_FRAGMENT_UTF8; + return WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE; + } + socket->receiving_fragment_type = SOCKET_FRAGMENT_NONE; return WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE;
case SOCKET_OPCODE_BINARY: - if (fragment) return WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE; + if (frag_type && frag_type != SOCKET_FRAGMENT_BINARY) + FIXME( "Received SOCKET_OPCODE_BINARY with prev fragment %u.\n", frag_type ); + if (fragment) + { + socket->receiving_fragment_type = SOCKET_FRAGMENT_BINARY; + return WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE; + } + socket->receiving_fragment_type = SOCKET_FRAGMENT_NONE; return WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE;
+ case SOCKET_OPCODE_CONTINUE: + if (!frag_type) + { + FIXME( "Received SOCKET_OPCODE_CONTINUE without starting fragment.\n" ); + return ~0u; + } + if (fragment) + { + return frag_type == SOCKET_FRAGMENT_BINARY ? WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE + : WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE; + } + socket->receiving_fragment_type = SOCKET_FRAGMENT_NONE; + return frag_type == SOCKET_FRAGMENT_BINARY ? WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE + : WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE; + case SOCKET_OPCODE_CLOSE: return WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE;
@@ -3744,13 +3777,14 @@ static WINHTTP_WEB_SOCKET_BUFFER_TYPE map_opcode( enum socket_opcode opcode, BOO static DWORD socket_receive( struct socket *socket, void *buf, DWORD len, DWORD *ret_len, WINHTTP_WEB_SOCKET_BUFFER_TYPE *ret_type ) { + BOOL final = socket->last_receive_final; DWORD count, ret = ERROR_SUCCESS;
if (!socket->read_size) { for (;;) { - if (!(ret = receive_frame( socket, &socket->read_size, &socket->opcode ))) + if (!(ret = receive_frame( socket, &socket->read_size, &socket->opcode, &final ))) { if (!(socket->opcode & CONTROL_BIT) || (ret = handle_control_frame( socket )) || socket->opcode == SOCKET_OPCODE_CLOSE) break; @@ -3759,7 +3793,11 @@ static DWORD socket_receive( struct socket *socket, void *buf, DWORD len, DWORD if (ret) break; } } - if (!ret) ret = receive_bytes( socket, buf, min(len, socket->read_size), &count, FALSE ); + if (!ret) + { + socket->last_receive_final = final; + ret = receive_bytes( socket, buf, min(len, socket->read_size), &count, FALSE ); + } if (!ret) { if (count < socket->read_size) @@ -3767,7 +3805,14 @@ static DWORD socket_receive( struct socket *socket, void *buf, DWORD len, DWORD
socket->read_size -= count; *ret_len = count; - *ret_type = map_opcode( socket->opcode, socket->read_size != 0 ); + *ret_type = map_opcode( socket, socket->opcode, !final || socket->read_size != 0 ); + TRACE( "len %lu, *ret_len %lu, *ret_type %u.\n", len, *ret_len, *ret_type ); + if (*ret_type == ~0u) + { + FIXME( "Unexpected opcode %u.\n", socket->opcode ); + socket->read_size = 0; + return ERROR_WINHTTP_INVALID_SERVER_RESPONSE; + } } return ret; } @@ -3978,6 +4023,7 @@ DWORD WINAPI WinHttpWebSocketShutdown( HINTERNET hsocket, USHORT status, void *r
static DWORD socket_close( struct socket *socket ) { + BOOL final = FALSE; DWORD ret, count;
if (socket->close_frame_received) return socket->close_frame_receive_err; @@ -3986,12 +4032,14 @@ static DWORD socket_close( struct socket *socket )
while (1) { - if ((ret = receive_frame( socket, &count, &socket->opcode ))) return ret; + if ((ret = receive_frame( socket, &count, &socket->opcode, &final ))) return ret; if (socket->opcode == SOCKET_OPCODE_CLOSE) break;
socket->read_size = count; if ((ret = socket_drain( socket ))) return ret; } + if (!final) + FIXME( "Received close opcode without FIN bit.\n" );
return receive_close_status( socket, count ); } diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h index bebc3ac1a07..19ef9a35e2d 100644 --- a/dlls/winhttp/winhttp_private.h +++ b/dlls/winhttp/winhttp_private.h @@ -269,6 +269,8 @@ struct socket SRWLOCK send_lock; volatile LONG pending_noncontrol_send; enum fragment_type sending_fragment_type; + enum fragment_type receiving_fragment_type; + BOOL last_receive_final; };
struct send_request