From: Paul Gofman gofmanp@gmail.com
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/winhttp/request.c | 56 ++++++++++++++++++++++------------ dlls/winhttp/winhttp_private.h | 4 +++ 2 files changed, 41 insertions(+), 19 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index e8576256fe7..a5bd828c9b7 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -3145,10 +3145,10 @@ static DWORD send_bytes( struct socket *socket, char *bytes, int len, int *sent, static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHORT status, const char *buf, DWORD buflen, BOOL final, WSAOVERLAPPED *ovr ) { - DWORD i = 0, j, offset = 2, len = buflen; - DWORD buffer_size, ret = 0, send_size; - char hdr[14], *mask = NULL; + DWORD i, offset = 2, len = buflen; + DWORD buffer_size, ret = 0; int sent_size; + char hdr[14]; char *ptr;
TRACE( "sending %02x frame, len %u.\n", opcode, len ); @@ -3179,7 +3179,6 @@ 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 (ovr && buffer_size > MAX_FRAME_BUFFER_SIZE) return WSAEWOULDBLOCK; if (buffer_size > socket->send_frame_buffer_size && socket->send_frame_buffer_size < MAX_FRAME_BUFFER_SIZE) { DWORD new_size; @@ -3199,27 +3198,32 @@ static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHOR memcpy(ptr, hdr, offset); ptr += offset;
- mask = &hdr[offset]; - RtlGenRandom( mask, 4 ); - memcpy( ptr, mask, 4 ); + RtlGenRandom( socket->mask, 4 ); + memcpy( ptr, socket->mask, 4 ); ptr += 4; + socket->mask_index = 0;
if (opcode == SOCKET_OPCODE_CLOSE) /* prepend status code */ { - *ptr++ = (status >> 8) ^ mask[i++ % 4]; - *ptr++ = (status & 0xff) ^ mask[i++ % 4]; + *ptr++ = (status >> 8) ^ socket->mask[socket->mask_index++ % 4]; + *ptr++ = (status & 0xff) ^ socket->mask[socket->mask_index++ % 4]; }
offset = ptr - socket->send_frame_buffer; - send_size = offset + buflen; - while (1) + socket->send_remaining_size = offset + buflen; + socket->client_buffer_offset = 0; + while (socket->send_remaining_size) { - j = 0; - while (j < buflen && offset < MAX_FRAME_BUFFER_SIZE) - socket->send_frame_buffer[offset++] = buf[j++] ^ mask[i++ % 4]; + len = min( buflen, MAX_FRAME_BUFFER_SIZE - offset ); + for (i = 0; i < len; ++i) + { + socket->send_frame_buffer[offset++] = buf[socket->client_buffer_offset++] + ^ socket->mask[socket->mask_index++ % 4]; + }
sent_size = 0; ret = send_bytes( socket, socket->send_frame_buffer, offset, &sent_size, ovr ); + socket->send_remaining_size -= sent_size; if (ret) { if (ovr && ret == WSA_IO_PENDING) @@ -3229,17 +3233,16 @@ static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHOR } return ret; } - if (!(send_size -= offset)) break; + assert( sent_size == offset ); offset = 0; - buf += j; - buflen -= j; + buflen -= len; } return ERROR_SUCCESS; }
static DWORD complete_send_frame( struct socket *socket, WSAOVERLAPPED *ovr, const char *buf ) { - DWORD ret, retflags, len; + DWORD ret, retflags, len, i;
if (!WSAGetOverlappedResult( socket->request->netconn->socket, ovr, &len, TRUE, &retflags )) return WSAGetLastError(); @@ -3249,6 +3252,22 @@ static DWORD complete_send_frame( struct socket *socket, WSAOVERLAPPED *ovr, con ret = send_bytes( socket, socket->send_frame_buffer, socket->bytes_in_send_frame_buffer, NULL, NULL ); if (ret) return ret; } + + assert( socket->bytes_in_send_frame_buffer <= socket->send_remaining_size ); + socket->send_remaining_size -= socket->bytes_in_send_frame_buffer; + + while (socket->send_remaining_size) + { + len = min( socket->send_remaining_size, MAX_FRAME_BUFFER_SIZE ); + for (i = 0; i < len; ++i) + { + socket->send_frame_buffer[i] = buf[socket->client_buffer_offset++] + ^ socket->mask[socket->mask_index++ % 4]; + } + ret = send_bytes( socket, socket->send_frame_buffer, len, NULL, NULL ); + if (ret) return ret; + socket->send_remaining_size -= len; + } return ERROR_SUCCESS; }
@@ -3371,7 +3390,6 @@ DWORD WINAPI WinHttpWebSocketSend( HINTERNET hsocket, WINHTTP_WEB_SOCKET_BUFFER_ async_send = TRUE; complete_async = TRUE; } - else if (ret == WSAEWOULDBLOCK) async_send = TRUE; }
if (async_send) diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h index 639c97b126e..b41eb0ee676 100644 --- a/dlls/winhttp/winhttp_private.h +++ b/dlls/winhttp/winhttp_private.h @@ -247,6 +247,8 @@ struct socket struct queue recv_q; enum socket_opcode opcode; DWORD read_size; + char mask[4]; + unsigned int mask_index; BOOL close_frame_received; DWORD close_frame_receive_err; USHORT status; @@ -254,7 +256,9 @@ struct socket DWORD reason_len; char *send_frame_buffer; unsigned int send_frame_buffer_size; + unsigned int send_remaining_size; unsigned int bytes_in_send_frame_buffer; + unsigned int client_buffer_offset; };
struct send_request