Commit a0e5fcdc authored by Paul Gofman's avatar Paul Gofman Committed by Alexandre Julliard

winhttp: Attemp sync websocket send even if data doesn't fit SSL buffer.

parent 67252dec
......@@ -436,21 +436,23 @@ static DWORD send_ssl_chunk( struct netconn *conn, const void *msg, size_t size,
DWORD netconn_send( struct netconn *conn, const void *msg, size_t len, int *sent, WSAOVERLAPPED *ovr )
{
DWORD err;
if (conn->secure)
{
const BYTE *ptr = msg;
size_t chunk_size;
DWORD res;
if (ovr && len > conn->ssl_sizes.cbMaximumMessage) return WSAEWOULDBLOCK;
*sent = 0;
while (len)
{
chunk_size = min( len, conn->ssl_sizes.cbMaximumMessage );
if ((res = send_ssl_chunk( conn, ptr, chunk_size, ovr )))
{
if (res == WSA_IO_PENDING) *sent += chunk_size;
return res;
}
*sent += chunk_size;
ptr += chunk_size;
len -= chunk_size;
......@@ -459,7 +461,12 @@ DWORD netconn_send( struct netconn *conn, const void *msg, size_t len, int *sent
return ERROR_SUCCESS;
}
if ((*sent = sock_send( conn->socket, msg, len, ovr )) < 0) return WSAGetLastError();
if ((*sent = sock_send( conn->socket, msg, len, ovr )) < 0)
{
err = WSAGetLastError();
*sent = (err == WSA_IO_PENDING) ? len : 0;
return err;
}
return ERROR_SUCCESS;
}
......
......@@ -3127,12 +3127,14 @@ HINTERNET WINAPI WinHttpWebSocketCompleteUpgrade( HINTERNET hrequest, DWORD_PTR
return hsocket;
}
static DWORD send_bytes( struct socket *socket, char *bytes, int len, WSAOVERLAPPED *ovr )
static DWORD send_bytes( struct socket *socket, char *bytes, int len, int *sent, WSAOVERLAPPED *ovr )
{
int count;
DWORD err;
if ((err = netconn_send( socket->request->netconn, bytes, len, &count, ovr ))) return err;
return (count == len) ? ERROR_SUCCESS : ERROR_INTERNAL_ERROR;
err = netconn_send( socket->request->netconn, bytes, len, &count, ovr );
if (sent) *sent = count;
if (err) return err;
return (count == len || (ovr && count)) ? ERROR_SUCCESS : ERROR_INTERNAL_ERROR;
}
#define FIN_BIT (1 << 7)
......@@ -3146,6 +3148,7 @@ static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHOR
DWORD i = 0, j, offset = 2, len = buflen;
DWORD buffer_size, ret = 0, send_size;
char hdr[14], *mask = NULL;
int sent_size;
char *ptr;
TRACE( "sending %02x frame, len %u.\n", opcode, len );
......@@ -3215,8 +3218,17 @@ static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHOR
while (j < buflen && offset < MAX_FRAME_BUFFER_SIZE)
socket->send_frame_buffer[offset++] = buf[j++] ^ mask[i++ % 4];
if ((ret = send_bytes( socket, socket->send_frame_buffer, offset, ovr ))) return ret;
sent_size = 0;
ret = send_bytes( socket, socket->send_frame_buffer, offset, &sent_size, ovr );
if (ret)
{
if (ovr && ret == WSA_IO_PENDING)
{
memmove( socket->send_frame_buffer, socket->send_frame_buffer + sent_size, offset - sent_size );
socket->bytes_in_send_frame_buffer = offset - sent_size;
}
return ret;
}
if (!(send_size -= offset)) break;
offset = 0;
buf += j;
......@@ -3225,13 +3237,18 @@ static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHOR
return ERROR_SUCCESS;
}
static DWORD complete_send_frame( struct socket *socket, WSAOVERLAPPED *ovr )
static DWORD complete_send_frame( struct socket *socket, WSAOVERLAPPED *ovr, const char *buf )
{
DWORD retflags, len;
DWORD ret, retflags, len;
if (!WSAGetOverlappedResult( socket->request->netconn->socket, ovr, &len, TRUE, &retflags ))
return WSAGetLastError();
if (socket->bytes_in_send_frame_buffer)
{
ret = send_bytes( socket, socket->send_frame_buffer, socket->bytes_in_send_frame_buffer, NULL, NULL );
if (ret) return ret;
}
return ERROR_SUCCESS;
}
......@@ -3298,7 +3315,7 @@ static void CALLBACK task_socket_send( TP_CALLBACK_INSTANCE *instance, void *ctx
TRACE("running %p\n", work);
if (s->complete_async) ret = complete_send_frame( s->socket, &s->ovr );
if (s->complete_async) ret = complete_send_frame( s->socket, &s->ovr, s->buf );
else ret = socket_send( s->socket, s->type, s->buf, s->len, NULL );
send_io_complete( &s->socket->hdr );
......@@ -3360,6 +3377,7 @@ DWORD WINAPI WinHttpWebSocketSend( HINTERNET hsocket, WINHTTP_WEB_SOCKET_BUFFER_
if (async_send)
{
s->complete_async = complete_async;
TRACE("queueing, complete_async %#x.\n", complete_async);
s->socket = socket;
s->type = type;
s->buf = buf;
......@@ -3375,6 +3393,7 @@ DWORD WINAPI WinHttpWebSocketSend( HINTERNET hsocket, WINHTTP_WEB_SOCKET_BUFFER_
}
else
{
TRACE("sent sync.\n");
InterlockedDecrement( &socket->hdr.pending_sends );
free( s );
socket_send_complete( socket, ret, type, len );
......
......@@ -678,8 +678,8 @@ static const struct notification websocket_test[] =
{ 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_SIGNAL },
{ winhttp_websocket_receive, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SIGNAL },
{ winhttp_websocket_receive, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, 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_close, WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE, NF_SIGNAL },
{ winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING },
{ winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, NF_WINE_ALLOW },
......@@ -712,18 +712,22 @@ static const struct notification websocket_test2[] =
{ winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }
};
#define BIG_BUFFER_SIZE (32 * 1024)
static void test_websocket(BOOL secure)
{
HANDLE session, connection, request, socket, event;
WINHTTP_WEB_SOCKET_ASYNC_RESULT *result;
WINHTTP_WEB_SOCKET_STATUS *ws_status;
WINHTTP_WEB_SOCKET_BUFFER_TYPE type;
DWORD size, status, err;
BOOL ret, unload = TRUE;
struct info info, *context = &info;
unsigned char *big_buffer;
char buffer[1024];
USHORT close_status;
DWORD protocols, flags;
unsigned int i;
unsigned int i, test_index, offset;
if (!pWinHttpWebSocketCompleteUpgrade)
{
......@@ -831,17 +835,24 @@ static void test_websocket(BOOL secure)
ok( err == ERROR_SUCCESS, "got %u\n", err );
WaitForSingleObject( info.wait, INFINITE );
for (i = 0; i < 2; ++i)
{
/* The send is executed synchronously (even if sending a reasonably big buffer exceeding SSL buffer size).
* It is possible to trigger queueing the send into another thread but that involves sending a considerable
* amount of big enough buffers. */
setup_test( &info, winhttp_websocket_send, __LINE__ );
err = pWinHttpWebSocketSend( socket, WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE,
(void*)"hello", sizeof("hello") );
ok( err == ERROR_SUCCESS, "got %u\n", err );
WaitForSingleObject( info.wait, INFINITE );
}
/* The send is executed synchronously (even if sending a reasonably big buffer exceeding SSL buffer size).
* It is possible to trigger queueing the send into another thread but that involves sending a considerable
* amount of big enough buffers. */
big_buffer = malloc( BIG_BUFFER_SIZE );
for (i = 0; i < BIG_BUFFER_SIZE; ++i)
big_buffer[i] = (i & 0xff) ^ 0xcc;
setup_test( &info, winhttp_websocket_send, __LINE__ );
err = pWinHttpWebSocketSend( socket, WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE,
big_buffer, BIG_BUFFER_SIZE );
ok( err == ERROR_SUCCESS, "got %u\n", err );
WaitForSingleObject( info.wait, INFINITE );
setup_test( &info, winhttp_websocket_send, __LINE__ );
err = pWinHttpWebSocketSend( socket, WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE,
(void*)"hello", sizeof("hello") );
ok( err == ERROR_SUCCESS, "got %u\n", err );
WaitForSingleObject( info.wait, INFINITE );
setup_test( &info, winhttp_websocket_shutdown, __LINE__ );
err = pWinHttpWebSocketShutdown( socket, 1000, (void *)"success", sizeof("success") );
......@@ -866,20 +877,47 @@ static void test_websocket(BOOL secure)
err = pWinHttpWebSocketReceive( socket, buffer, sizeof(buffer), &size, &type );
ok( err == ERROR_SUCCESS, "got %u\n", err );
WaitForSingleObject( info.wait, INFINITE );
ok( info.buflen == sizeof(*ws_status), "got unexpected buflen %u.\n", info.buflen );
ws_status = (WINHTTP_WEB_SOCKET_STATUS *)info.buffer;
ok( ws_status->eBufferType == WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE,
"Got unexpected eBufferType %u.\n", ws_status->eBufferType );
ok( size == 0xdeadbeef, "got %u\n", size );
ok( type == 0xdeadbeef, "got %u\n", type );
ok( buffer[0] == 'R', "unexpected data\n" );
setup_test( &info, winhttp_websocket_receive, __LINE__ );
buffer[0] = 0;
size = 0xdeadbeef;
type = 0xdeadbeef;
err = pWinHttpWebSocketReceive( socket, buffer, sizeof(buffer), &size, &type );
ok( err == ERROR_SUCCESS, "got %u\n", err );
WaitForSingleObject( info.wait, INFINITE );
ok( size == 0xdeadbeef, "got %u\n", size );
ok( type == 0xdeadbeef, "got %u\n", type );
ok( buffer[0] == 'h', "unexpected data\n" );
memset( big_buffer, 0, BIG_BUFFER_SIZE );
offset = 0;
test_index = info.index;
do
{
info.index = test_index;
setup_test( &info, winhttp_websocket_receive, __LINE__ );
size = 0xdeadbeef;
type = 0xdeadbeef;
ws_status = (WINHTTP_WEB_SOCKET_STATUS *)info.buffer;
ws_status->eBufferType = ~0u;
err = pWinHttpWebSocketReceive( socket, big_buffer + offset, BIG_BUFFER_SIZE - offset, &size, &type );
ok( err == ERROR_SUCCESS, "got %u\n", err );
WaitForSingleObject( info.wait, INFINITE );
ok( info.buflen == sizeof(*ws_status), "got unexpected buflen %u.\n", info.buflen );
ok( ws_status->eBufferType == WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE
|| ws_status->eBufferType == WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE,
"Got unexpected eBufferType %u.\n", ws_status->eBufferType );
offset += ws_status->dwBytesTransferred;
ok( offset <= BIG_BUFFER_SIZE, "Got unexpected dwBytesTransferred %u.\n",
ws_status->dwBytesTransferred );
ok( size == 0xdeadbeef, "got %u\n", size );
ok( type == 0xdeadbeef, "got %u\n", type );
}
while (ws_status->eBufferType == WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE);
ok( offset == BIG_BUFFER_SIZE, "Got unexpected offset %u.\n", offset );
for (i = 0; i < BIG_BUFFER_SIZE; ++i)
if (big_buffer[i] != ((i & 0xff) ^ 0xcc)) break;
ok( i == BIG_BUFFER_SIZE, "unexpected data %#x at %u\n", (unsigned char)big_buffer[i], i );
free( big_buffer );
close_status = 0xdead;
size = sizeof(buffer) + 1;
......
......@@ -254,6 +254,7 @@ struct socket
DWORD reason_len;
char *send_frame_buffer;
unsigned int send_frame_buffer_size;
unsigned int bytes_in_send_frame_buffer;
};
struct send_request
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment