Hans Leidekker : wininet: Implement chunked reads.

Alexandre Julliard julliard at winehq.org
Wed Mar 26 09:16:13 CDT 2008


Module: wine
Branch: master
Commit: 0936601f5b2628c1e0dab4b8bd3c9d097ba14717
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=0936601f5b2628c1e0dab4b8bd3c9d097ba14717

Author: Hans Leidekker <hans at it.vu.nl>
Date:   Wed Mar 26 11:31:21 2008 +0100

wininet: Implement chunked reads.

---

 dlls/wininet/http.c |  107 ++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 98 insertions(+), 9 deletions(-)

diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c
index 2d16924..3bb8a76 100644
--- a/dlls/wininet/http.c
+++ b/dlls/wininet/http.c
@@ -107,7 +107,7 @@ struct HttpAuthInfo
 };
 
 static BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr);
-static BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr);
+static BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear);
 static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier);
 static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer);
 static BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr);
@@ -846,7 +846,7 @@ BOOL WINAPI HttpEndRequestW(HINTERNET hRequest,
     SendAsyncCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
             INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
 
-    responseLen = HTTP_GetResponseHeaders(lpwhr);
+    responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE);
     if (responseLen)
 	    rc = TRUE;
 
@@ -1573,8 +1573,7 @@ static DWORD HTTPREQ_Read(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD
         if(req->dwContentLength != -1 && req->dwContentRead != req->dwContentLength)
             ERR("not all data received %d/%d\n", req->dwContentRead, req->dwContentLength);
 
-        /* always returns TRUE, even if the network layer returns an
-         * error */
+        /* always return success, even if the network layer returns an error */
         *read = 0;
         HTTP_FinishedReading(req);
         return ERROR_SUCCESS;
@@ -1597,11 +1596,101 @@ static DWORD HTTPREQ_Read(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD
     return ERROR_SUCCESS;
 }
 
+static DWORD get_chunk_size(const char *buffer)
+{
+    const char *p;
+    DWORD size = 0;
+
+    for (p = buffer; *p; p++)
+    {
+        if (*p >= '0' && *p <= '9') size = size * 16 + *p - '0';
+        else if (*p >= 'a' && *p <= 'f') size = size * 16 + *p - 'a' + 10;
+        else if (*p >= 'A' && *p <= 'F') size = size * 16 + *p - 'A' + 10;
+        else if (*p == ';') break;
+    }
+    return size;
+}
+
+static DWORD HTTPREQ_ReadChunked(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD *read, BOOL sync)
+{
+    char reply[MAX_REPLY_LEN], *p = buffer;
+    DWORD buflen, to_write = size;
+    size_t to_read;
+    int bytes_read;
+
+    *read = 0;
+    for (;;)
+    {
+        if (*read == size) break;
+
+        if (req->dwContentLength == ~0UL) /* new chunk */
+        {
+            buflen = sizeof(reply);
+            if (!NETCON_getNextLine(&req->netConnection, reply, &buflen)) break;
+
+            if (!(req->dwContentLength = get_chunk_size(reply)))
+            {
+                /* zero sized chunk marks end of transfer; read any trailing headers and return */
+                HTTP_GetResponseHeaders(req, FALSE);
+                break;
+            }
+        }
+        to_read = min(to_write, req->dwContentLength - req->dwContentRead);
+
+        if (!NETCON_recv(&req->netConnection, p, to_read, sync ? MSG_WAITALL : 0, &bytes_read))
+        {
+            if (bytes_read != to_read)
+                ERR("Not all data received %d/%d\n", bytes_read, to_read);
+
+            /* always return success, even if the network layer returns an error */
+            *read = 0;
+            break;
+        }
+        if (!bytes_read) break;
+
+        req->dwContentRead += bytes_read;
+        to_write -= bytes_read;
+        *read += bytes_read;
+
+        if (req->lpszCacheFile)
+        {
+            if (!WriteFile(req->hCacheFile, p, bytes_read, NULL, NULL))
+                WARN("WriteFile failed: %u\n", GetLastError());
+        }
+        p += bytes_read;
+
+        if (req->dwContentRead == req->dwContentLength) /* chunk complete */
+        {
+            req->dwContentRead = 0;
+            req->dwContentLength = ~0UL;
+
+            buflen = sizeof(reply);
+            if (!NETCON_getNextLine(&req->netConnection, reply, &buflen))
+            {
+                ERR("Malformed chunk\n");
+                *read = 0;
+                break;
+            }
+        }
+    }
+    if (!*read) HTTP_FinishedReading(req);
+    return ERROR_SUCCESS;
+}
+
 static DWORD HTTPREQ_ReadFile(WININETHANDLEHEADER *hdr, void *buffer, DWORD size, DWORD *read)
 {
     WININETHTTPREQW *req = (WININETHTTPREQW*)hdr;
+    static WCHAR encoding[20];
+    DWORD buflen = sizeof(encoding);
+    static const WCHAR szChunked[] = {'c','h','u','n','k','e','d',0};
 
-    return HTTPREQ_Read(req, buffer, size, read, TRUE);
+    if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_TRANSFER_ENCODING, encoding, &buflen, NULL) &&
+        !strcmpiW(encoding, szChunked))
+    {
+        return HTTPREQ_ReadChunked(req, buffer, size, read, TRUE);
+    }
+    else
+        return HTTPREQ_Read(req, buffer, size, read, TRUE);
 }
 
 static void HTTPREQ_AsyncReadFileExProc(WORKREQUEST *workRequest)
@@ -3002,7 +3091,7 @@ static BOOL HTTP_SecureProxyConnect(LPWININETHTTPREQW lpwhr)
     if (!ret || cnt < 0)
         return FALSE;
 
-    responseLen = HTTP_GetResponseHeaders( lpwhr );
+    responseLen = HTTP_GetResponseHeaders( lpwhr, TRUE );
     if (!responseLen)
         return FALSE;
 
@@ -3128,7 +3217,7 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders,
             if (cnt < 0)
                 goto lend;
     
-            responseLen = HTTP_GetResponseHeaders(lpwhr);
+            responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE);
             if (responseLen)
                 bSuccess = TRUE;
     
@@ -3523,7 +3612,7 @@ static void HTTP_clear_response_headers( LPWININETHTTPREQW lpwhr )
  *   TRUE  on success
  *   FALSE on error
  */
-static INT HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr)
+static INT HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear)
 {
     INT cbreaks = 0;
     WCHAR buffer[MAX_REPLY_LEN];
@@ -3541,7 +3630,7 @@ static INT HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr)
     TRACE("-->\n");
 
     /* clear old response headers (eg. from a redirect response) */
-    HTTP_clear_response_headers( lpwhr );
+    if (clear) HTTP_clear_response_headers( lpwhr );
 
     if (!NETCON_connected(&lpwhr->netConnection))
         goto lend;




More information about the wine-cvs mailing list