winhttp: Support WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE.

This commit is contained in:
Paul Gofman 2022-10-07 12:08:10 -05:00 committed by Alexandre Julliard
parent d8552dab2b
commit f78137a8c2
5 changed files with 123 additions and 7 deletions

View file

@ -2165,6 +2165,14 @@ static DWORD send_request( struct request *request, const WCHAR *headers, DWORD
int bytes_sent;
DWORD ret, len;
if (request->flags & REQUEST_FLAG_WEBSOCKET_UPGRADE
&& request->websocket_set_send_buffer_size < MIN_WEBSOCKET_SEND_BUFFER_SIZE)
{
WARN( "Invalid send buffer size %u.\n", request->websocket_set_send_buffer_size );
ret = ERROR_NOT_ENOUGH_MEMORY;
goto end;
}
drain_content( request );
clear_response_headers( request );
@ -2185,6 +2193,7 @@ static DWORD send_request( struct request *request, const WCHAR *headers, DWORD
}
if (request->flags & REQUEST_FLAG_WEBSOCKET_UPGRADE)
{
request->websocket_send_buffer_size = request->websocket_set_send_buffer_size;
process_header( request, L"Upgrade", L"websocket", WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE );
process_header( request, L"Connection", L"Upgrade", WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE );
process_header( request, L"Sec-WebSocket-Version", L"13", WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE );
@ -3245,6 +3254,7 @@ HINTERNET WINAPI WinHttpWebSocketCompleteUpgrade( HINTERNET hrequest, DWORD_PTR
socket->hdr.notify_mask = request->hdr.notify_mask;
socket->hdr.context = context;
socket->keepalive_interval = 30000;
socket->send_buffer_size = request->websocket_send_buffer_size;
InitializeSRWLock( &socket->send_lock );
init_queue( &socket->send_q );
init_queue( &socket->recv_q );
@ -3316,13 +3326,13 @@ static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHOR
}
buffer_size = len + offset + 4;
assert( buffer_size - len < MAX_FRAME_BUFFER_SIZE );
if (buffer_size > socket->send_frame_buffer_size && socket->send_frame_buffer_size < MAX_FRAME_BUFFER_SIZE)
assert( buffer_size - len < socket->send_buffer_size );
if (buffer_size > socket->send_frame_buffer_size && socket->send_frame_buffer_size < socket->send_buffer_size)
{
DWORD new_size;
void *new;
new_size = min( buffer_size, MAX_FRAME_BUFFER_SIZE );
new_size = min( buffer_size, socket->send_buffer_size );
if (!(new = realloc( socket->send_frame_buffer, new_size )))
{
ERR( "out of memory, buffer_size %lu\n", buffer_size);
@ -3352,7 +3362,7 @@ static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHOR
socket->client_buffer_offset = 0;
while (socket->send_remaining_size)
{
len = min( buflen, MAX_FRAME_BUFFER_SIZE - offset );
len = min( buflen, socket->send_buffer_size - offset );
for (i = 0; i < len; ++i)
{
socket->send_frame_buffer[offset++] = buf[socket->client_buffer_offset++]
@ -3396,7 +3406,7 @@ static DWORD complete_send_frame( struct socket *socket, WSAOVERLAPPED *ovr, con
while (socket->send_remaining_size)
{
len = min( socket->send_remaining_size, MAX_FRAME_BUFFER_SIZE );
len = min( socket->send_remaining_size, socket->send_buffer_size );
for (i = 0; i < len; ++i)
{
socket->send_frame_buffer[i] = buf[socket->client_buffer_offset++]

View file

@ -151,6 +151,13 @@ static BOOL session_query_option( struct object_header *hdr, DWORD option, void
*buflen = sizeof(DWORD);
return TRUE;
case WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE:
if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
*(DWORD *)buffer = session->websocket_send_buffer_size;
*buflen = sizeof(DWORD);
return TRUE;
default:
FIXME( "unimplemented option %lu\n", option );
SetLastError( ERROR_INVALID_PARAMETER );
@ -256,6 +263,22 @@ static BOOL session_set_option( struct object_header *hdr, DWORD option, void *b
return TRUE;
}
case WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE:
{
DWORD buffer_size;
if (buflen != sizeof(buffer_size))
{
SetLastError( ERROR_INSUFFICIENT_BUFFER );
return FALSE;
}
buffer_size = *(DWORD *)buffer;
TRACE( "%#lx\n", buffer_size );
session->websocket_send_buffer_size = buffer_size;
return TRUE;
}
default:
FIXME( "unimplemented option %lu\n", option );
SetLastError( ERROR_WINHTTP_INVALID_OPTION );
@ -294,6 +317,7 @@ HINTERNET WINAPI WinHttpOpen( LPCWSTR agent, DWORD access, LPCWSTR proxy, LPCWST
session->receive_timeout = DEFAULT_RECEIVE_TIMEOUT;
session->receive_response_timeout = DEFAULT_RECEIVE_RESPONSE_TIMEOUT;
session->websocket_receive_buffer_size = 32768;
session->websocket_send_buffer_size = 32768;
list_init( &session->cookie_cache );
InitializeCriticalSection( &session->cs );
session->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": session.cs");
@ -873,6 +897,13 @@ static BOOL request_query_option( struct object_header *hdr, DWORD option, void
*buflen = sizeof(DWORD);
return TRUE;
case WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE:
if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
*(DWORD *)buffer = request->websocket_set_send_buffer_size;
*buflen = sizeof(DWORD);
return TRUE;
default:
FIXME( "unimplemented option %lu\n", option );
SetLastError( ERROR_INVALID_PARAMETER );
@ -1125,6 +1156,21 @@ static BOOL request_set_option( struct object_header *hdr, DWORD option, void *b
return TRUE;
}
case WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE:
{
DWORD buffer_size;
if (buflen != sizeof(buffer_size))
{
SetLastError( ERROR_INSUFFICIENT_BUFFER );
return FALSE;
}
buffer_size = *(DWORD *)buffer;
request->websocket_set_send_buffer_size = buffer_size;
TRACE( "Websocket send buffer size %lu.\n", buffer_size);
return TRUE;
}
default:
FIXME( "unimplemented option %lu\n", option );
@ -1223,6 +1269,8 @@ HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, const WCHAR *verb, cons
request->receive_response_timeout = connect->session->receive_response_timeout;
request->max_redirects = 10;
request->websocket_receive_buffer_size = connect->session->websocket_receive_buffer_size;
request->websocket_send_buffer_size = connect->session->websocket_send_buffer_size;
request->websocket_set_send_buffer_size = request->websocket_send_buffer_size;
if (!verb || !verb[0]) verb = L"GET";
if (!(request->verb = strdupW( verb ))) goto end;

View file

@ -113,6 +113,7 @@ static void CALLBACK check_notification( HINTERNET handle, DWORD_PTR context, DW
status_ok = (info->test[info->index].status == status);
function_ok = (info->test[info->index].function == info->function);
ok( status_ok, "%u: expected status %#x got %#lx\n", info->line, info->test[info->index].status, status );
ok(function_ok, "%u: expected function %u got %u\n", info->line, info->test[info->index].function, info->function);
@ -663,6 +664,7 @@ static const struct notification websocket_test[] =
{
{ winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED },
{ winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED },
{ winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, NF_SIGNAL },
{ winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME },
{ winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED },
{ winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER },
@ -796,7 +798,7 @@ static void test_websocket(BOOL secure)
WINHTTP_WEB_SOCKET_ASYNC_RESULT *result;
WINHTTP_WEB_SOCKET_STATUS *ws_status;
WINHTTP_WEB_SOCKET_BUFFER_TYPE type;
DWORD size, status, err;
DWORD size, status, err, value;
BOOL ret, unload = TRUE;
struct info info, *context = &info;
unsigned char *big_buffer;
@ -871,6 +873,20 @@ static void test_websocket(BOOL secure)
ok( ret, "got %lu\n", GetLastError() );
setup_test( &info, winhttp_send_request, __LINE__ );
value = 15;
ret = WinHttpSetOption(request, WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE, &value, sizeof(DWORD));
ok(ret, "got %lu\n", GetLastError());
ret = WinHttpSendRequest( request, NULL, 0, NULL, 0, 0, 0 );
err = GetLastError();
ok( ret, "got err %lu.\n", err );
WaitForSingleObject( info.wait, INFINITE );
value = 32768;
ret = WinHttpSetOption(request, WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE, &value, sizeof(DWORD));
ok(ret, "got %lu\n", GetLastError());
SetLastError( 0xdeadbeef );
ret = WinHttpSendRequest( request, NULL, 0, NULL, 0, 0, 0 );
err = GetLastError();

View file

@ -3236,6 +3236,7 @@ static void test_websocket(int port)
DWORD size, len, count, status, index, error, value;
DWORD_PTR ctx;
WINHTTP_WEB_SOCKET_BUFFER_TYPE type;
BOOL broken_buffer_sizes = FALSE;
WCHAR header[32];
char buf[128], *large_buf;
USHORT close_status;
@ -3435,6 +3436,16 @@ static void test_websocket(int port)
ret = WinHttpSetOption(session, WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE, &value, sizeof(DWORD));
ok(ret, "got %lu\n", GetLastError());
size = 0xdeadbeef;
ret = WinHttpQueryOption(session, WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE, &value, &size);
ok(ret, "got %lu\n", GetLastError());
ok(size == sizeof(DWORD), "got %lu.\n", size);
ok(value == 32768, "got %lu.\n", value);
value = 15;
ret = WinHttpSetOption(session, WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE, &value, sizeof(DWORD));
ok(ret, "got %lu\n", GetLastError());
request = WinHttpOpenRequest(connection, L"GET", L"/", NULL, NULL, NULL, 0);
ok(request != NULL, "got %lu\n", GetLastError());
@ -3443,6 +3454,8 @@ static void test_websocket(int port)
ok(ret, "got %lu\n", GetLastError());
ok(size == sizeof(DWORD), "got %lu.\n", size);
ok(value == 65535 || broken( value == WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE ) /* Win8 */, "got %lu.\n", value);
if (value == WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE)
broken_buffer_sizes = TRUE;
size = 0xdeadbeef;
ret = WinHttpQueryOption(request, WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE, &value, &size);
@ -3471,6 +3484,12 @@ static void test_websocket(int port)
ok(!ret, "got %d\n", ret);
todo_wine ok(GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, "got %lu\n", GetLastError());
size = 0xdeadbeef;
ret = WinHttpQueryOption(request, WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE, &value, &size);
ok(ret, "got %lu\n", GetLastError());
ok(size == sizeof(DWORD), "got %lu.\n", size);
ok(value == 15 || broken( value == WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE ) /* Win8 */, "got %lu.\n", value);
size = sizeof(value);
ret = WinHttpQueryOption(session, WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL, &value, &size);
ok(!ret, "got %d\n", ret);
@ -3489,9 +3508,25 @@ static void test_websocket(int port)
ret = WinHttpSetOption(request, WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, NULL, 0);
ok(ret, "got %lu\n", GetLastError());
if (!broken_buffer_sizes)
{
/* Fails because we have a too small send buffer size set, but is different on Win8. */
ret = WinHttpSendRequest(request, NULL, 0, NULL, 0, 0, 0);
ok(!ret, "got %d\n", ret);
ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY, "got %lu\n", GetLastError());
}
value = 16;
ret = WinHttpSetOption(request, WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE, &value, sizeof(DWORD));
ok(ret, "got %lu\n", GetLastError());
ret = WinHttpSendRequest(request, NULL, 0, NULL, 0, 0, 0);
ok(ret, "got %lu\n", GetLastError());
value = 15;
ret = WinHttpSetOption(request, WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE, &value, sizeof(DWORD));
ok(ret, "got %lu\n", GetLastError());
ret = WinHttpReceiveResponse(request, NULL);
ok(ret, "got %lu\n", GetLastError());
@ -3515,6 +3550,10 @@ static void test_websocket(int port)
ok(!ret, "got %d\n", ret);
todo_wine ok(GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, "got %lu\n", GetLastError());
ret = WinHttpSetOption(socket, WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE, &value, sizeof(DWORD));
ok(!ret, "got %d\n", ret);
todo_wine ok(GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, "got %lu\n", GetLastError());
value = 20000;
ret = WinHttpSetOption(socket, WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL, &value, 2);
ok(!ret, "got %d\n", ret);

View file

@ -86,6 +86,7 @@ struct session
DWORD secure_protocols;
DWORD passport_flags;
unsigned int websocket_receive_buffer_size;
unsigned int websocket_send_buffer_size;
};
struct connect
@ -217,6 +218,7 @@ struct request
WCHAR *password;
} creds[TARGET_MAX][SCHEME_MAX];
unsigned int websocket_receive_buffer_size;
unsigned int websocket_send_buffer_size, websocket_set_send_buffer_size;
};
enum socket_state
@ -255,6 +257,7 @@ struct socket
struct object_header hdr;
struct request *request;
int keepalive_interval;
unsigned int send_buffer_size;
enum socket_state state;
struct queue send_q;
struct queue recv_q;
@ -446,6 +449,6 @@ static inline char *strdupWA_sized( const WCHAR *src, DWORD size )
extern HINSTANCE winhttp_instance DECLSPEC_HIDDEN;
#define MAX_FRAME_BUFFER_SIZE 65536
#define MIN_WEBSOCKET_SEND_BUFFER_SIZE 16
#endif /* _WINE_WINHTTP_PRIVATE_H_ */