From: Paul Gofman pgofman@codeweavers.com
--- dlls/winhttp/request.c | 32 ++++++++++++++++++++ dlls/winhttp/session.c | 2 +- dlls/winhttp/tests/winhttp.c | 53 +++++++++++++++++++++++++++++++++- dlls/winhttp/winhttp_private.h | 3 ++ 4 files changed, 88 insertions(+), 2 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index 9f769f3dc35..4aedb7e0980 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -3151,6 +3151,13 @@ static void socket_handle_closing( struct object_header *hdr )
static BOOL socket_query_option( struct object_header *hdr, DWORD option, void *buffer, DWORD *buflen ) { + switch (option) + { + case WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL: + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + FIXME( "unimplemented option %lu\n", option ); SetLastError( ERROR_WINHTTP_INVALID_OPTION ); return FALSE; @@ -3172,6 +3179,28 @@ static void socket_destroy( struct object_header *hdr )
static BOOL socket_set_option( struct object_header *hdr, DWORD option, void *buffer, DWORD buflen ) { + struct socket *socket = (struct socket *)hdr; + + switch (option) + { + case WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL: + { + DWORD interval; + + if (buflen != sizeof(DWORD) || (interval = *(DWORD *)buffer) < 15000) + { + WARN( "Invalid parameters for WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL.\n" ); + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + socket->keepalive_interval = interval; + netconn_set_timeout( socket->request->netconn, FALSE, socket->keepalive_interval ); + SetLastError( ERROR_SUCCESS ); + TRACE( "WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL %lu.\n", interval); + return TRUE; + } + } + FIXME( "unimplemented option %lu\n", option ); SetLastError( ERROR_WINHTTP_INVALID_OPTION ); return FALSE; @@ -3215,6 +3244,7 @@ HINTERNET WINAPI WinHttpWebSocketCompleteUpgrade( HINTERNET hrequest, DWORD_PTR socket->hdr.callback = request->hdr.callback; socket->hdr.notify_mask = request->hdr.notify_mask; socket->hdr.context = context; + socket->keepalive_interval = 30000; InitializeSRWLock( &socket->send_lock ); init_queue( &socket->send_q ); init_queue( &socket->recv_q ); @@ -3222,6 +3252,8 @@ HINTERNET WINAPI WinHttpWebSocketCompleteUpgrade( HINTERNET hrequest, DWORD_PTR addref_object( &request->hdr ); socket->request = request;
+ netconn_set_timeout( socket->request->netconn, FALSE, socket->keepalive_interval ); + if ((hsocket = alloc_handle( &socket->hdr ))) { send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hsocket, sizeof(hsocket) ); diff --git a/dlls/winhttp/session.c b/dlls/winhttp/session.c index 01e95895eb3..90a86be5dd2 100644 --- a/dlls/winhttp/session.c +++ b/dlls/winhttp/session.c @@ -84,7 +84,7 @@ static void session_destroy( struct object_header *hdr ) free( session ); }
-static BOOL validate_buffer( void *buffer, DWORD *buflen, DWORD required ) +BOOL validate_buffer( void *buffer, DWORD *buflen, DWORD required ) { if (!buffer || *buflen < required) { diff --git a/dlls/winhttp/tests/winhttp.c b/dlls/winhttp/tests/winhttp.c index d1dd58fdad4..ed3d06038af 100644 --- a/dlls/winhttp/tests/winhttp.c +++ b/dlls/winhttp/tests/winhttp.c @@ -3233,7 +3233,7 @@ static void test_redirect(int port) static void test_websocket(int port) { HINTERNET session, connection, request, socket, socket2; - DWORD size, len, count, status, index, error; + DWORD size, len, count, status, index, error, value; DWORD_PTR ctx; WINHTTP_WEB_SOCKET_BUFFER_TYPE type; WCHAR header[32]; @@ -3428,6 +3428,21 @@ static void test_websocket(int port) request = WinHttpOpenRequest(connection, L"GET", L"/", NULL, NULL, NULL, 0); ok(request != NULL, "got %lu\n", GetLastError());
+ size = sizeof(value); + ret = WinHttpQueryOption(session, WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL, &value, &size); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); + + size = sizeof(value); + ret = WinHttpQueryOption(request, WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL, &value, &size); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); + + value = 20000; + ret = WinHttpSetOption(request, WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL, &value, sizeof(DWORD)); + ok(!ret, "got %d\n", ret); + todo_wine ok(GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, "got %lu\n", GetLastError()); + ret = WinHttpSetOption(request, WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, NULL, 0); ok(ret, "got %lu\n", GetLastError());
@@ -3447,6 +3462,42 @@ static void test_websocket(int port) socket = pWinHttpWebSocketCompleteUpgrade(request, 0); ok(socket != NULL, "got %lu\n", GetLastError());
+ value = 20000; + ret = WinHttpSetOption(socket, WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL, &value, 2); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); + + value = 20000; + ret = WinHttpSetOption(socket, WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL, &value, sizeof(DWORD) * 2); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + value = 20000; + ret = WinHttpSetOption(socket, WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL, &value, sizeof(DWORD)); + ok(ret, "got %lu\n", GetLastError()); + ok(!GetLastError(), "got %lu\n", GetLastError()); + + size = sizeof(value); + ret = WinHttpQueryOption(socket, WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL, &value, &size); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); + + size = 0; + ret = WinHttpQueryOption(socket, WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL, NULL, &size); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); + + value = 10000; + ret = WinHttpSetOption(socket, WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL, &value, sizeof(DWORD)); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); + + value = 10000; + ret = WinHttpSetOption(socket, WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL, &value, 2); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); + buf[0] = 0; count = 0; type = 0xdeadbeef; diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h index 79941dee31a..382dce38573 100644 --- a/dlls/winhttp/winhttp_private.h +++ b/dlls/winhttp/winhttp_private.h @@ -252,6 +252,7 @@ struct socket { struct object_header hdr; struct request *request; + int keepalive_interval; enum socket_state state; struct queue send_q; struct queue recv_q; @@ -359,6 +360,8 @@ void release_object( struct object_header * ) DECLSPEC_HIDDEN; HINTERNET alloc_handle( struct object_header * ) DECLSPEC_HIDDEN; BOOL free_handle( HINTERNET ) DECLSPEC_HIDDEN;
+BOOL validate_buffer( void *buffer, DWORD *buflen, DWORD required ) DECLSPEC_HIDDEN; + void send_callback( struct object_header *, DWORD, LPVOID, DWORD ) DECLSPEC_HIDDEN; void close_connection( struct request * ) DECLSPEC_HIDDEN; void init_queue( struct queue *queue ) DECLSPEC_HIDDEN;
From: Paul Gofman pgofman@codeweavers.com
--- dlls/winhttp/session.c | 49 +++++++++++++++++++++++++++++++ dlls/winhttp/tests/winhttp.c | 53 ++++++++++++++++++++++++++++++++++ dlls/winhttp/winhttp_private.h | 2 ++ 3 files changed, 104 insertions(+)
diff --git a/dlls/winhttp/session.c b/dlls/winhttp/session.c index 90a86be5dd2..b1192c9e201 100644 --- a/dlls/winhttp/session.c +++ b/dlls/winhttp/session.c @@ -144,6 +144,13 @@ static BOOL session_query_option( struct object_header *hdr, DWORD option, void *buflen = sizeof(DWORD); return TRUE;
+ case WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE: + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; + + *(DWORD *)buffer = session->websocket_receive_buffer_size; + *buflen = sizeof(DWORD); + return TRUE; + default: FIXME( "unimplemented option %lu\n", option ); SetLastError( ERROR_INVALID_PARAMETER ); @@ -233,6 +240,22 @@ static BOOL session_set_option( struct object_header *hdr, DWORD option, void *b FIXME( "WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER: %lu\n", *(DWORD *)buffer ); return TRUE;
+ case WINHTTP_OPTION_WEB_SOCKET_RECEIVE_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_receive_buffer_size = buffer_size; + return TRUE; + } + default: FIXME( "unimplemented option %lu\n", option ); SetLastError( ERROR_WINHTTP_INVALID_OPTION ); @@ -270,6 +293,7 @@ HINTERNET WINAPI WinHttpOpen( LPCWSTR agent, DWORD access, LPCWSTR proxy, LPCWST session->send_timeout = DEFAULT_SEND_TIMEOUT; session->receive_timeout = DEFAULT_RECEIVE_TIMEOUT; session->receive_response_timeout = DEFAULT_RECEIVE_RESPONSE_TIMEOUT; + session->websocket_receive_buffer_size = 32768; list_init( &session->cookie_cache ); InitializeCriticalSection( &session->cs ); session->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": session.cs"); @@ -842,6 +866,13 @@ static BOOL request_query_option( struct object_header *hdr, DWORD option, void *buflen = sizeof(DWORD); return TRUE;
+ case WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE: + if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE; + + *(DWORD *)buffer = request->websocket_receive_buffer_size; + *buflen = sizeof(DWORD); + return TRUE; + default: FIXME( "unimplemented option %lu\n", option ); SetLastError( ERROR_INVALID_PARAMETER ); @@ -1078,6 +1109,23 @@ static BOOL request_set_option( struct object_header *hdr, DWORD option, void *b SetLastError(ERROR_INVALID_PARAMETER); return FALSE;
+ case WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE: + { + DWORD buffer_size; + + if (buflen != sizeof(buffer_size)) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return FALSE; + } + + buffer_size = *(DWORD *)buffer; + WARN( "Setting websocket receive buffer size currently has not effct, size %lu\n", buffer_size ); + request->websocket_receive_buffer_size = buffer_size; + return TRUE; + } + + default: FIXME( "unimplemented option %lu\n", option ); SetLastError( ERROR_WINHTTP_INVALID_OPTION ); @@ -1174,6 +1222,7 @@ HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, const WCHAR *verb, cons request->receive_timeout = connect->session->receive_timeout; request->receive_response_timeout = connect->session->receive_response_timeout; request->max_redirects = 10; + request->websocket_receive_buffer_size = 32768;
if (!verb || !verb[0]) verb = L"GET"; if (!(request->verb = strdupW( verb ))) goto end; diff --git a/dlls/winhttp/tests/winhttp.c b/dlls/winhttp/tests/winhttp.c index ed3d06038af..82aeccedade 100644 --- a/dlls/winhttp/tests/winhttp.c +++ b/dlls/winhttp/tests/winhttp.c @@ -3428,6 +3428,49 @@ static void test_websocket(int port) request = WinHttpOpenRequest(connection, L"GET", L"/", NULL, NULL, NULL, 0); ok(request != NULL, "got %lu\n", GetLastError());
+ size = 0xdeadbeef; + ret = WinHttpQueryOption(session, WINHTTP_OPTION_WEB_SOCKET_RECEIVE_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 = 65535; + 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_RECEIVE_BUFFER_SIZE, &value, &size); + ok(ret, "got %lu\n", GetLastError()); + ok(size == sizeof(DWORD), "got %lu.\n", size); + ok(value == 65535, "got %lu.\n", value); + + size = 0xdeadbeef; + ret = WinHttpQueryOption(request, WINHTTP_OPTION_WEB_SOCKET_RECEIVE_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 = 1048576; + ret = WinHttpSetOption(request, 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_RECEIVE_BUFFER_SIZE, &value, &size); + ok(ret, "got %lu\n", GetLastError()); + ok(size == sizeof(DWORD), "got %lu.\n", size); + ok(value == 65535, "got %lu.\n", value); + + size = 0xdeadbeef; + ret = WinHttpQueryOption(request, WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE, &value, &size); + ok(ret, "got %lu\n", GetLastError()); + ok(size == sizeof(DWORD), "got %lu.\n", size); + ok(value == 1048576, "got %lu.\n", value); + + size = 0xdeadbeef; + ret = WinHttpQueryOption(connection, WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE, &value, &size); + ok(!ret, "got %d\n", ret); + todo_wine ok(GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, "got %lu\n", GetLastError()); + size = sizeof(value); ret = WinHttpQueryOption(session, WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL, &value, &size); ok(!ret, "got %d\n", ret); @@ -3462,6 +3505,16 @@ static void test_websocket(int port) socket = pWinHttpWebSocketCompleteUpgrade(request, 0); ok(socket != NULL, "got %lu\n", GetLastError());
+ size = sizeof(value); + ret = WinHttpQueryOption(socket, WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE, &value, &size); + ok(!ret, "got %d\n", ret); + todo_wine ok(GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, "got %lu\n", GetLastError()); + + value = 65535; + ret = WinHttpSetOption(socket, WINHTTP_OPTION_WEB_SOCKET_RECEIVE_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); diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h index 382dce38573..a8fcf215768 100644 --- a/dlls/winhttp/winhttp_private.h +++ b/dlls/winhttp/winhttp_private.h @@ -85,6 +85,7 @@ struct session HANDLE unload_event; DWORD secure_protocols; DWORD passport_flags; + unsigned int websocket_receive_buffer_size; };
struct connect @@ -215,6 +216,7 @@ struct request WCHAR *username; WCHAR *password; } creds[TARGET_MAX][SCHEME_MAX]; + unsigned int websocket_receive_buffer_size; };
enum socket_state
From: Paul Gofman pgofman@codeweavers.com
--- dlls/winhttp/request.c | 20 +++++++++---- dlls/winhttp/session.c | 48 +++++++++++++++++++++++++++++++ dlls/winhttp/tests/notification.c | 18 +++++++++++- dlls/winhttp/tests/winhttp.c | 32 +++++++++++++++++++++ dlls/winhttp/winhttp_private.h | 5 +++- 5 files changed, 116 insertions(+), 7 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index 4aedb7e0980..8e01e926078 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -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++] diff --git a/dlls/winhttp/session.c b/dlls/winhttp/session.c index b1192c9e201..4fa857be40e 100644 --- a/dlls/winhttp/session.c +++ b/dlls/winhttp/session.c @@ -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 = 32768; + request->websocket_send_buffer_size = 32768; + 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; diff --git a/dlls/winhttp/tests/notification.c b/dlls/winhttp/tests/notification.c index 55823b42b85..cab297d3f4c 100644 --- a/dlls/winhttp/tests/notification.c +++ b/dlls/winhttp/tests/notification.c @@ -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(); diff --git a/dlls/winhttp/tests/winhttp.c b/dlls/winhttp/tests/winhttp.c index 82aeccedade..a287274684f 100644 --- a/dlls/winhttp/tests/winhttp.c +++ b/dlls/winhttp/tests/winhttp.c @@ -3471,6 +3471,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 == 32768, "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 +3495,31 @@ static void test_websocket(int port) ret = WinHttpSetOption(request, WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, NULL, 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()); + + 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, "got %lu.\n", value); + + 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 = 1; + 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 +3543,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); diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h index a8fcf215768..638a10460a5 100644 --- a/dlls/winhttp/winhttp_private.h +++ b/dlls/winhttp/winhttp_private.h @@ -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; @@ -448,6 +451,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_ */
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=124898
Your paranoid android.
=== w1064v1507 (32 bit report) ===
winhttp: notification: Timeout
=== w8 (32 bit report) ===
winhttp: winhttp.c:3445: Test failed: got 122. winhttp.c:3461: Test failed: got 122.
=== w8adm (32 bit report) ===
winhttp: winhttp.c:3445: Test failed: got 122. winhttp.c:3461: Test failed: got 122.
=== w864 (32 bit report) ===
winhttp: winhttp.c:3445: Test failed: got 122. winhttp.c:3461: Test failed: got 122.
=== w864 (64 bit report) ===
winhttp: winhttp.c:3445: Test failed: got 122. winhttp.c:3461: Test failed: got 122.
=== debian11 (build log) ===
Use of uninitialized value $Flaky in addition (+) at /home/testbot/lib/WineTestBot/LogUtils.pm line 720, <$LogFile> line 24680. Use of uninitialized value $Flaky in addition (+) at /home/testbot/lib/WineTestBot/LogUtils.pm line 720, <$LogFile> line 24680. Use of uninitialized value $Flaky in addition (+) at /home/testbot/lib/WineTestBot/LogUtils.pm line 720, <$LogFile> line 24680.