From b5b066f62aaef7eb3f5ebdcac6b61bf48fb22f5b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 20 Jan 2022 18:35:34 +0300 Subject: [PATCH] winhttp: Consider short read from netconn_recv() in receive_bytes(). Signed-off-by: Paul Gofman Signed-off-by: Hans Leidekker Signed-off-by: Alexandre Julliard --- dlls/winhttp/request.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index f215b984f6e..af04292ea06 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -3328,7 +3328,7 @@ DWORD WINAPI WinHttpWebSocketSend( HINTERNET hsocket, WINHTTP_WEB_SOCKET_BUFFER_ return ret; } -static DWORD receive_bytes( struct socket *socket, char *buf, DWORD len, DWORD *ret_len ) +static DWORD receive_bytes( struct socket *socket, char *buf, DWORD len, DWORD *ret_len, BOOL read_full_buffer ) { DWORD err, size = 0, needed = len; char *ptr = buf; @@ -3342,8 +3342,17 @@ static DWORD receive_bytes( struct socket *socket, char *buf, DWORD len, DWORD * needed -= size; ptr += size; } - if ((err = netconn_recv( socket->request->netconn, ptr, needed, 0, &received ))) return err; - if ((*ret_len = size + received) != len) return ERROR_WINHTTP_INVALID_SERVER_RESPONSE; + while (size != len) + { + if ((err = netconn_recv( socket->request->netconn, ptr, needed, 0, &received ))) return err; + if (!received) break; + size += received; + if (!read_full_buffer) break; + needed -= received; + ptr += received; + } + *ret_len = size; + if (size != len && (read_full_buffer || !size)) return ERROR_WINHTTP_INVALID_SERVER_RESPONSE; return ERROR_SUCCESS; } @@ -3368,7 +3377,7 @@ static DWORD receive_frame( struct socket *socket, DWORD *ret_len, enum socket_o DWORD ret, len, count; char hdr[2]; - if ((ret = receive_bytes( socket, hdr, sizeof(hdr), &count ))) return ret; + if ((ret = receive_bytes( socket, hdr, sizeof(hdr), &count, TRUE ))) return ret; if ((hdr[0] & RESERVED_BIT) || (hdr[1] & MASK_BIT) || !is_supported_opcode( hdr[0] & 0xf )) { return ERROR_WINHTTP_INVALID_SERVER_RESPONSE; @@ -3380,13 +3389,13 @@ static DWORD receive_frame( struct socket *socket, DWORD *ret_len, enum socket_o if (len == 126) { USHORT len16; - if ((ret = receive_bytes( socket, (char *)&len16, sizeof(len16), &count ))) return ret; + if ((ret = receive_bytes( socket, (char *)&len16, sizeof(len16), &count, TRUE ))) return ret; len = RtlUshortByteSwap( len16 ); } else if (len == 127) { ULONGLONG len64; - if ((ret = receive_bytes( socket, (char *)&len64, sizeof(len64), &count ))) return ret; + if ((ret = receive_bytes( socket, (char *)&len64, sizeof(len64), &count, TRUE ))) return ret; if ((len64 = RtlUlonglongByteSwap( len64 )) > ~0u) return ERROR_NOT_SUPPORTED; len = len64; } @@ -3434,7 +3443,7 @@ static DWORD socket_drain( struct socket *socket ) while (socket->read_size) { char buf[1024]; - if ((ret = receive_bytes( socket, buf, min(socket->read_size, sizeof(buf)), &count ))) return ret; + if ((ret = receive_bytes( socket, buf, min(socket->read_size, sizeof(buf)), &count, TRUE ))) return ret; socket->read_size -= count; } return ERROR_SUCCESS; @@ -3496,9 +3505,12 @@ static DWORD socket_receive( struct socket *socket, void *buf, DWORD len, DWORD if (ret) break; } } - if (!ret) ret = receive_bytes( socket, buf, min(len, socket->read_size), &count ); + if (!ret) ret = receive_bytes( socket, buf, min(len, socket->read_size), &count, FALSE ); if (!ret) { + if (count < socket->read_size) + WARN("Short read.\n"); + socket->read_size -= count; if (!async) { @@ -3685,9 +3697,9 @@ static DWORD socket_close( struct socket *socket, USHORT status, const void *rea if (count) { DWORD reason_len = count - sizeof(socket->status); - if ((ret = receive_bytes( socket, (char *)&socket->status, sizeof(socket->status), &count ))) goto done; + if ((ret = receive_bytes( socket, (char *)&socket->status, sizeof(socket->status), &count, TRUE ))) goto done; socket->status = RtlUshortByteSwap( socket->status ); - if ((ret = receive_bytes( socket, socket->reason, reason_len, &socket->reason_len ))) goto done; + if ((ret = receive_bytes( socket, socket->reason, reason_len, &socket->reason_len, TRUE ))) goto done; } socket->state = SOCKET_STATE_CLOSED;