wininet: Don't assume that end of chunk means end of stream.

Hans Leidekker hans at codeweavers.com
Wed Sep 11 06:50:18 CDT 2013


This makes Outlook happy. I also tested this with native IE against
test.winehq.org/tests/chunked as well as a local CGI script to trigger some
corner cases.
---
 dlls/wininet/http.c | 69 ++++++++++++++++++++++-------------------------------
 1 file changed, 28 insertions(+), 41 deletions(-)

diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c
index 1832b4f..cf2885f 100644
--- a/dlls/wininet/http.c
+++ b/dlls/wininet/http.c
@@ -400,6 +400,7 @@ typedef struct {
     DWORD buf_size;
     DWORD buf_pos;
     DWORD chunk_size;
+    BOOL end_of_data;
 } chunked_stream_t;
 
 static inline void destroy_data_stream(data_stream_t *stream)
@@ -2697,6 +2698,8 @@ static DWORD read_more_chunked_data(chunked_stream_t *stream, http_request_t *re
     DWORD res;
     int len;
 
+    assert(!stream->end_of_data);
+
     if (stream->buf_pos)
     {
         /* move existing data to the start of the buffer */
@@ -2744,9 +2747,10 @@ static DWORD discard_chunked_eol(chunked_stream_t *stream, http_request_t *req)
 /* read the size of the next chunk (the read section must be held) */
 static DWORD start_next_chunk(chunked_stream_t *stream, http_request_t *req)
 {
-    /* TODOO */
     DWORD chunk_size = 0, res;
 
+    if (stream->end_of_data) return ERROR_NO_MORE_FILES;
+
     if(stream->chunk_size != ~0u && (res = discard_chunked_eol(stream, req)) != ERROR_SUCCESS)
         return res;
 
@@ -2764,6 +2768,8 @@ static DWORD start_next_chunk(chunked_stream_t *stream, http_request_t *req)
                 stream->chunk_size = chunk_size;
                 if (req->contentLength == ~0u) req->contentLength = chunk_size;
                 else req->contentLength += chunk_size;
+
+                if (!chunk_size) stream->end_of_data = TRUE;
                 return discard_chunked_eol(stream, req);
             }
             remove_chunked_data(stream, 1);
@@ -2779,75 +2785,55 @@ static DWORD start_next_chunk(chunked_stream_t *stream, http_request_t *req)
 
 static DWORD chunked_get_avail_data(data_stream_t *stream, http_request_t *req)
 {
-    /* Allow reading only from read buffer */
+    chunked_stream_t *chunked_stream = (chunked_stream_t*)stream;
+    DWORD res;
+
+    if(!chunked_stream->chunk_size || chunked_stream->chunk_size == ~0u) {
+        res = start_next_chunk(chunked_stream, req);
+        if(res != ERROR_SUCCESS)
+            return 0;
+    }
+    /* only report data in read buffer */
     return 0;
 }
 
 static BOOL chunked_end_of_data(data_stream_t *stream, http_request_t *req)
 {
     chunked_stream_t *chunked_stream = (chunked_stream_t*)stream;
-    return !chunked_stream->chunk_size;
+    return chunked_stream->end_of_data;
 }
 
 static DWORD chunked_read(data_stream_t *stream, http_request_t *req, BYTE *buf, DWORD size,
         DWORD *read, read_mode_t read_mode)
 {
     chunked_stream_t *chunked_stream = (chunked_stream_t*)stream;
-    DWORD read_bytes = 0, ret_read = 0, res = ERROR_SUCCESS;
+    DWORD read_bytes = 0, res = ERROR_SUCCESS;
 
-    if(chunked_stream->chunk_size == ~0u) {
+    if(!chunked_stream->chunk_size || chunked_stream->chunk_size == ~0u) {
         res = start_next_chunk(chunked_stream, req);
         if(res != ERROR_SUCCESS)
             return res;
     }
 
-    while(size && chunked_stream->chunk_size) {
+    if(size && chunked_stream->chunk_size) {
         if(chunked_stream->buf_size) {
             read_bytes = min(size, min(chunked_stream->buf_size, chunked_stream->chunk_size));
 
-            /* this could block */
-            if(read_mode == READMODE_NOBLOCK && read_bytes == chunked_stream->chunk_size)
-                break;
-
-            memcpy(buf+ret_read, chunked_stream->buf+chunked_stream->buf_pos, read_bytes);
+            memcpy(buf, chunked_stream->buf+chunked_stream->buf_pos, read_bytes);
             remove_chunked_data(chunked_stream, read_bytes);
         }else {
             read_bytes = min(size, chunked_stream->chunk_size);
 
-            if(read_mode == READMODE_NOBLOCK) {
-                DWORD avail;
-
-                if(!req->netconn || !NETCON_query_data_available(req->netconn, &avail) || !avail)
-                    break;
-                if(read_bytes > avail)
-                    read_bytes = avail;
-
-                /* this could block */
-                if(read_bytes == chunked_stream->chunk_size)
-                    break;
-            }
-
-            res = NETCON_recv(req->netconn, (char *)buf+ret_read, read_bytes, 0, (int*)&read_bytes);
+            res = NETCON_recv(req->netconn, (char *)buf, read_bytes, 0, (int*)&read_bytes);
             if(res != ERROR_SUCCESS)
-                break;
+                return res;
         }
 
         chunked_stream->chunk_size -= read_bytes;
-        size -= read_bytes;
-        ret_read += read_bytes;
-        if(!chunked_stream->chunk_size) {
-            assert(read_mode != READMODE_NOBLOCK);
-            res = start_next_chunk(chunked_stream, req);
-            if(res != ERROR_SUCCESS)
-                break;
-        }
-
-        if(read_mode == READMODE_ASYNC)
-            read_mode = READMODE_NOBLOCK;
     }
 
-    TRACE("read %u bytes\n", ret_read);
-    *read = ret_read;
+    TRACE("read %u bytes\n", read_bytes);
+    *read = read_bytes;
     return res;
 }
 
@@ -2855,8 +2841,8 @@ static BOOL chunked_drain_content(data_stream_t *stream, http_request_t *req)
 {
     chunked_stream_t *chunked_stream = (chunked_stream_t*)stream;
 
-    /* FIXME: we can do better */
-    return !chunked_stream->chunk_size;
+    remove_chunked_data(chunked_stream, chunked_stream->buf_size);
+    return chunked_stream->end_of_data;
 }
 
 static void chunked_destroy(data_stream_t *stream)
@@ -2905,6 +2891,7 @@ static DWORD set_content_length(http_request_t *request)
         chunked_stream->data_stream.vtbl = &chunked_stream_vtbl;
         chunked_stream->buf_size = chunked_stream->buf_pos = 0;
         chunked_stream->chunk_size = ~0u;
+        chunked_stream->end_of_data = FALSE;
 
         if(request->read_size) {
             memcpy(chunked_stream->buf, request->read_buf+request->read_pos, request->read_size);
-- 
1.8.1.5






More information about the wine-patches mailing list