-- v3: winhttp: Support WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE. winhttp: Stub WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE. winhttp: Support WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL.
From: Paul Gofman pgofman@codeweavers.com
--- dlls/winhttp/request.c | 32 ++++++++++++++++++++ dlls/winhttp/tests/winhttp.c | 53 +++++++++++++++++++++++++++++++++- dlls/winhttp/winhttp_private.h | 1 + 3 files changed, 85 insertions(+), 1 deletion(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index 9f769f3dc35..543532c31d8 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/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..52f9eb171ee 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;
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 01e95895eb3..12af5ded251 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 = connect->session->websocket_receive_buffer_size;
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..0af68a4bc74 100644 --- a/dlls/winhttp/tests/winhttp.c +++ b/dlls/winhttp/tests/winhttp.c @@ -3425,9 +3425,52 @@ static void test_websocket(int port) connection = WinHttpConnect(session, L"ws.ifelse.io", 0, 0); ok(connection != 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()); + 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 == 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 == 65535, "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 52f9eb171ee..9c994037bcf 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 | 37 ++++++++++++++++++++++-- dlls/winhttp/winhttp_private.h | 5 +++- 5 files changed, 119 insertions(+), 9 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index 543532c31d8..64f70b61a96 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 12af5ded251..e95d24c1901 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 = 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; 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 0af68a4bc74..9121c3b712c 100644 --- a/dlls/winhttp/tests/winhttp.c +++ b/dlls/winhttp/tests/winhttp.c @@ -3435,6 +3435,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());
@@ -3442,7 +3452,7 @@ static void test_websocket(int port) 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); + ok(value == 65535 || broken( value == 122 ) /* Win8 */, "got %lu.\n", value);
size = 0xdeadbeef; ret = WinHttpQueryOption(request, WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE, &value, &size); @@ -3458,7 +3468,7 @@ static void test_websocket(int port) 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); + ok(value == 65535 || broken( value == 122 ) /* Win8 */, "got %lu.\n", value);
size = 0xdeadbeef; ret = WinHttpQueryOption(request, WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE, &value, &size); @@ -3471,6 +3481,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, "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 +3505,22 @@ static void test_websocket(int port) ret = WinHttpSetOption(request, WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, NULL, 0); ok(ret, "got %lu\n", GetLastError());
+ /* Fails because we have a too small send buffer size set. */ + 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 +3544,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 9c994037bcf..53947f73351 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; @@ -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_ */
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=124924
Your paranoid android.
=== w8 (32 bit report) ===
winhttp: winhttp.c:3461: Test failed: got 122. winhttp.c:3488: Test failed: got 123. winhttp.c:3510: Test failed: got 1 winhttp.c:3511: Test failed: got 0 winhttp.c:3518: Test failed: got 12019 winhttp.c:3525: Test failed: got 12019 winhttp.c:3531: Test failed: got 12019 winhttp.c:3532: Test failed: got 3735928559 winhttp.c:3535: Test failed: got 4317 winhttp.c:3554: Test failed: got 12018 winhttp.c:3559: Test failed: got 12018 winhttp.c:3564: Test failed: got 12018 winhttp.c:3565: Test failed: got 12018 winhttp.c:3570: Test failed: got 12018 winhttp.c:3575: Test failed: got 12018 winhttp.c:3580: Test failed: got 12018 winhttp.c:3585: Test failed: got 12018 winhttp.c:3591: Test failed: got 6 winhttp.c:3592: Test failed: got winhttp.c:3593: Test failed: got 0 winhttp.c:3594: Test failed: got 3735928559 winhttp.c:3597: Test failed: got 6 winhttp.c:3603: Test failed: got 6 winhttp.c:3607: Test failed: got 6 winhttp.c:3610: Test failed: got 6 winhttp.c:3613: Test failed: got 6 winhttp.c:3619: Test failed: got 6 winhttp.c:3620: Test failed: got winhttp.c:3621: Test failed: got 0 winhttp.c:3622: Test failed: got 3735928559 winhttp.c:3628: Test failed: got 6 winhttp.c:3629: Test failed: got winhttp.c:3630: Test failed: got 0 winhttp.c:3631: Test failed: got 3735928559 winhttp.c:3634: Test failed: got 6 winhttp.c:3637: Test failed: got 6 winhttp.c:3641: Test failed: got 6 winhttp.c:3644: Test failed: got 6 winhttp.c:3647: Test failed: got 6 winhttp.c:3651: Test failed: got 6 winhttp.c:3654: Test failed: got 6 winhttp.c:3657: Test failed: got 6 winhttp.c:3660: Test failed: got 6 winhttp.c:3663: Test failed: got 6 winhttp.c:3666: Test failed: got 6 winhttp.c:3670: Test failed: got 6 winhttp.c:3671: Test failed: got 3735928559 winhttp.c:3674: Test failed: got 6 winhttp.c:3680: Test failed: got 6 winhttp.c:3681: Test failed: got 57005 winhttp.c:3682: Test failed: got 3735928559
=== w8adm (32 bit report) ===
winhttp: winhttp.c:3461: Test failed: got 122. winhttp.c:3488: Test failed: got 123. winhttp.c:3510: Test failed: got 1 winhttp.c:3511: Test failed: got 0 winhttp.c:3518: Test failed: got 12019 winhttp.c:3525: Test failed: got 12019 winhttp.c:3531: Test failed: got 12019 winhttp.c:3532: Test failed: got 3735928559 winhttp.c:3535: Test failed: got 4317 winhttp.c:3554: Test failed: got 12018 winhttp.c:3559: Test failed: got 12018 winhttp.c:3564: Test failed: got 12018 winhttp.c:3565: Test failed: got 12018 winhttp.c:3570: Test failed: got 12018 winhttp.c:3575: Test failed: got 12018 winhttp.c:3580: Test failed: got 12018 winhttp.c:3585: Test failed: got 12018 winhttp.c:3591: Test failed: got 6 winhttp.c:3592: Test failed: got winhttp.c:3593: Test failed: got 0 winhttp.c:3594: Test failed: got 3735928559 winhttp.c:3597: Test failed: got 6 winhttp.c:3603: Test failed: got 6 winhttp.c:3607: Test failed: got 6 winhttp.c:3610: Test failed: got 6 winhttp.c:3613: Test failed: got 6 winhttp.c:3619: Test failed: got 6 winhttp.c:3620: Test failed: got winhttp.c:3621: Test failed: got 0 winhttp.c:3622: Test failed: got 3735928559 winhttp.c:3628: Test failed: got 6 winhttp.c:3629: Test failed: got winhttp.c:3630: Test failed: got 0 winhttp.c:3631: Test failed: got 3735928559 winhttp.c:3634: Test failed: got 6 winhttp.c:3637: Test failed: got 6 winhttp.c:3641: Test failed: got 6 winhttp.c:3644: Test failed: got 6 winhttp.c:3647: Test failed: got 6 winhttp.c:3651: Test failed: got 6 winhttp.c:3654: Test failed: got 6 winhttp.c:3657: Test failed: got 6 winhttp.c:3660: Test failed: got 6 winhttp.c:3663: Test failed: got 6 winhttp.c:3666: Test failed: got 6 winhttp.c:3670: Test failed: got 6 winhttp.c:3671: Test failed: got 3735928559 winhttp.c:3674: Test failed: got 6 winhttp.c:3680: Test failed: got 6 winhttp.c:3681: Test failed: got 57005 winhttp.c:3682: Test failed: got 3735928559
=== w864 (32 bit report) ===
winhttp: winhttp.c:3461: Test failed: got 122. winhttp.c:3488: Test failed: got 123. winhttp.c:3510: Test failed: got 1 winhttp.c:3511: Test failed: got 0 winhttp.c:3518: Test failed: got 12019 winhttp.c:3525: Test failed: got 12019 winhttp.c:3531: Test failed: got 12019 winhttp.c:3532: Test failed: got 3735928559 winhttp.c:3535: Test failed: got 4317 winhttp.c:3554: Test failed: got 12018 winhttp.c:3559: Test failed: got 12018 winhttp.c:3564: Test failed: got 12018 winhttp.c:3565: Test failed: got 12018 winhttp.c:3570: Test failed: got 12018 winhttp.c:3575: Test failed: got 12018 winhttp.c:3580: Test failed: got 12018 winhttp.c:3585: Test failed: got 12018 winhttp.c:3591: Test failed: got 6 winhttp.c:3592: Test failed: got winhttp.c:3593: Test failed: got 0 winhttp.c:3594: Test failed: got 3735928559 winhttp.c:3597: Test failed: got 6 winhttp.c:3603: Test failed: got 6 winhttp.c:3607: Test failed: got 6 winhttp.c:3610: Test failed: got 6 winhttp.c:3613: Test failed: got 6 winhttp.c:3619: Test failed: got 6 winhttp.c:3620: Test failed: got winhttp.c:3621: Test failed: got 0 winhttp.c:3622: Test failed: got 3735928559 winhttp.c:3628: Test failed: got 6 winhttp.c:3629: Test failed: got winhttp.c:3630: Test failed: got 0 winhttp.c:3631: Test failed: got 3735928559 winhttp.c:3634: Test failed: got 6 winhttp.c:3637: Test failed: got 6 winhttp.c:3641: Test failed: got 6 winhttp.c:3644: Test failed: got 6 winhttp.c:3647: Test failed: got 6 winhttp.c:3651: Test failed: got 6 winhttp.c:3654: Test failed: got 6 winhttp.c:3657: Test failed: got 6 winhttp.c:3660: Test failed: got 6 winhttp.c:3663: Test failed: got 6 winhttp.c:3666: Test failed: got 6 winhttp.c:3670: Test failed: got 6 winhttp.c:3671: Test failed: got 3735928559 winhttp.c:3674: Test failed: got 6 winhttp.c:3680: Test failed: got 6 winhttp.c:3681: Test failed: got 57005 winhttp.c:3682: Test failed: got 3735928559
=== w864 (64 bit report) ===
winhttp: winhttp.c:3461: Test failed: got 122. winhttp.c:3488: Test failed: got 123. winhttp.c:3510: Test failed: got 1 winhttp.c:3511: Test failed: got 0 winhttp.c:3518: Test failed: got 12019 winhttp.c:3525: Test failed: got 12019 winhttp.c:3531: Test failed: got 12019 winhttp.c:3532: Test failed: got 3735928559 winhttp.c:3535: Test failed: got 4317 winhttp.c:3554: Test failed: got 12018 winhttp.c:3559: Test failed: got 12018 winhttp.c:3564: Test failed: got 12018 winhttp.c:3565: Test failed: got 12018 winhttp.c:3570: Test failed: got 12018 winhttp.c:3575: Test failed: got 12018 winhttp.c:3580: Test failed: got 12018 winhttp.c:3585: Test failed: got 12018 winhttp.c:3591: Test failed: got 6 winhttp.c:3592: Test failed: got winhttp.c:3593: Test failed: got 0 winhttp.c:3594: Test failed: got 3735928559 winhttp.c:3597: Test failed: got 6 winhttp.c:3603: Test failed: got 6 winhttp.c:3607: Test failed: got 6 winhttp.c:3610: Test failed: got 6 winhttp.c:3613: Test failed: got 6 winhttp.c:3619: Test failed: got 6 winhttp.c:3620: Test failed: got winhttp.c:3621: Test failed: got 0 winhttp.c:3622: Test failed: got 3735928559 winhttp.c:3628: Test failed: got 6 winhttp.c:3629: Test failed: got winhttp.c:3630: Test failed: got 0 winhttp.c:3631: Test failed: got 3735928559 winhttp.c:3634: Test failed: got 6 winhttp.c:3637: Test failed: got 6 winhttp.c:3641: Test failed: got 6 winhttp.c:3644: Test failed: got 6 winhttp.c:3647: Test failed: got 6 winhttp.c:3651: Test failed: got 6 winhttp.c:3654: Test failed: got 6 winhttp.c:3657: Test failed: got 6 winhttp.c:3660: Test failed: got 6 winhttp.c:3663: Test failed: got 6 winhttp.c:3666: Test failed: got 6 winhttp.c:3670: Test failed: got 6 winhttp.c:3671: Test failed: got 3735928559 winhttp.c:3674: Test failed: got 6 winhttp.c:3680: Test failed: got 6 winhttp.c:3681: Test failed: got 57005 winhttp.c:3682: Test failed: got 3735928559
=== debian11 (build log) ===
Use of uninitialized value $Flaky in addition (+) at /home/testbot/lib/WineTestBot/LogUtils.pm line 720, <$LogFile> line 24685. Use of uninitialized value $Flaky in addition (+) at /home/testbot/lib/WineTestBot/LogUtils.pm line 720, <$LogFile> line 24685. Use of uninitialized value $Flaky in addition (+) at /home/testbot/lib/WineTestBot/LogUtils.pm line 720, <$LogFile> line 24685.
v3: - change indentation in socket_set_option(); - don't make validate_buffer() global; - inherit send and receive buffer sizes in request from session (and change tests so they really test that).
I left `websocket_set_send_buffer_size` in place for now. It is not only to print an error message or get an error return in the right place. The test suggests that the buffer size is fetched during WinHttpSendRequest on Windows (that is where it fails if setting invalid size and it doesn't fail later if setting invalid size right after this call). It is not apparent that the buffer size sent after WinHttpSendRequest but before WinHttpCompleteUpgrade have no effect so I would expect some apps to set it at the wrong moment. Ignoring that would make us use a different buffer size if it is valid or fail if it is invalid. I guess that is best to avoid. The alternative to using an extra websocket_set_send_buffer_size variable to initialize a web socket structure right in WinHttpSendRequest, but it looks even uglier to me so far than an extra variable.