From: Paul Gofman pgofman@codeweavers.com
v2: Determine whether the frame is final in socket_send() instead of passing a BOOL parameter to map_buffer_type().
Signed-off-by: Paul Gofman pgofman@codeweavers.com Signed-off-by: Hans Leidekker hans@codeweavers.com --- 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..48e25023d07 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -3298,13 +3298,65 @@ 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 ) { 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: + 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: + 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 +3385,11 @@ 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 = map_buffer_type( socket, type ); + BOOL final = (type != WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE && + type != WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE);
- 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
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=109451
Your paranoid android.
=== w8adm (32 bit report) ===
winhttp: notification.c:256: Test failed: failed to send request 12007 notification.c:258: Test failed: unexpected function 3, expected 4. probably some notifications were missing notification.c:260: Test failed: failed to receive response 12019 notification.c:264: Test failed: failed unexpectedly 12019 notification.c:265: Test failed: request failed unexpectedly 0 notification.c:268: Test failed: unexpected function 3, expected 13. probably some notifications were missing notification.c:116: Test failed: 268: expected status 0x2 got 0x800 notification.c:117: Test failed: 268: expected function 3 got 13 notification: Timeout
=== w1064v1809 (64 bit report) ===
winhttp: notification.c:116: Test failed: 1061: expected status 0x100 got 0x800 notification: Timeout