[PATCH 5/5] winhttp: Consider short read from netconn_recv() in receive_bytes().

Paul Gofman pgofman at codeweavers.com
Thu Jan 20 09:35:34 CST 2022


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
 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;
 
-- 
2.34.1




More information about the wine-devel mailing list