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>
This commit is contained in:
parent
11c835d471
commit
003391dec8
|
@ -3298,13 +3298,65 @@ static BOOL socket_can_receive( struct socket *socket )
|
||||||
return socket->state <= SOCKET_STATE_SHUTDOWN && !socket->close_frame_received;
|
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)
|
switch (type)
|
||||||
{
|
{
|
||||||
case WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE: return SOCKET_OPCODE_TEXT;
|
case WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE:
|
||||||
case WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE: return SOCKET_OPCODE_BINARY;
|
if (socket->sending_fragment_type)
|
||||||
case WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE: return SOCKET_OPCODE_CLOSE;
|
{
|
||||||
|
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:
|
default:
|
||||||
FIXME("buffer type %u not supported\n", type);
|
FIXME("buffer type %u not supported\n", type);
|
||||||
return SOCKET_OPCODE_INVALID;
|
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,
|
static DWORD socket_send( struct socket *socket, WINHTTP_WEB_SOCKET_BUFFER_TYPE type, const void *buf, DWORD len,
|
||||||
WSAOVERLAPPED *ovr )
|
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 )
|
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 );
|
TRACE( "%p, %u, %p, %lu\n", hsocket, type, buf, len );
|
||||||
|
|
||||||
if (len && !buf) return ERROR_INVALID_PARAMETER;
|
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 = (struct socket *)grab_object( hsocket ))) return ERROR_INVALID_HANDLE;
|
||||||
if (socket->hdr.type != WINHTTP_HANDLE_TYPE_SOCKET)
|
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 );
|
release_object( &socket->hdr );
|
||||||
return ERROR_INVALID_OPERATION;
|
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) )))
|
if (!(s = malloc( sizeof(*s) )))
|
||||||
{
|
{
|
||||||
|
@ -3445,7 +3501,18 @@ DWORD WINAPI WinHttpWebSocketSend( HINTERNET hsocket, WINHTTP_WEB_SOCKET_BUFFER_
|
||||||
ret = ERROR_SUCCESS;
|
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 );
|
release_object( &socket->hdr );
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -676,6 +676,8 @@ static const struct notification websocket_test[] =
|
||||||
{ winhttp_websocket_complete_upgrade, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, NF_SIGNAL },
|
{ 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_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_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 },
|
||||||
{ 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;
|
for (i = 0; i < BIG_BUFFER_SIZE; ++i) big_buffer[i] = (i & 0xff) ^ 0xcc;
|
||||||
|
|
||||||
setup_test( &info, winhttp_websocket_send, __LINE__ );
|
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 );
|
ok( err == ERROR_SUCCESS, "got %lu\n", err );
|
||||||
WaitForSingleObject( info.wait, INFINITE );
|
WaitForSingleObject( info.wait, INFINITE );
|
||||||
|
|
||||||
|
|
|
@ -238,6 +238,13 @@ enum socket_opcode
|
||||||
SOCKET_OPCODE_INVALID = 0xff,
|
SOCKET_OPCODE_INVALID = 0xff,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum fragment_type
|
||||||
|
{
|
||||||
|
SOCKET_FRAGMENT_NONE,
|
||||||
|
SOCKET_FRAGMENT_BINARY,
|
||||||
|
SOCKET_FRAGMENT_UTF8,
|
||||||
|
};
|
||||||
|
|
||||||
struct socket
|
struct socket
|
||||||
{
|
{
|
||||||
struct object_header hdr;
|
struct object_header hdr;
|
||||||
|
@ -261,6 +268,7 @@ struct socket
|
||||||
unsigned int client_buffer_offset;
|
unsigned int client_buffer_offset;
|
||||||
SRWLOCK send_lock;
|
SRWLOCK send_lock;
|
||||||
volatile LONG pending_noncontrol_send;
|
volatile LONG pending_noncontrol_send;
|
||||||
|
enum fragment_type sending_fragment_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct send_request
|
struct send_request
|
||||||
|
|
Loading…
Reference in New Issue