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_ */