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