Module: wine Branch: master Commit: 003391dec89d724a9dd86e66f9b28f624600b6ab URL: https://source.winehq.org/git/wine.git/?a=commit;h=003391dec89d724a9dd86e66f...
Author: Paul Gofman pgofman@codeweavers.com Date: Mon Feb 28 12:37:50 2022 +0100
winhttp: Support sending web socket buffer fragments.
Signed-off-by: Paul Gofman pgofman@codeweavers.com Signed-off-by: Hans Leidekker hans@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
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