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

Alexandre Julliard julliard at winehq.org
Fri Sep 20 14:21:30 CDT 2013


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

Author: Hans Leidekker <hans at codeweavers.com>
Date:   Wed Sep 18 13:40:24 2013 +0200

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

---

 dlls/wininet/http.c       |   26 ++++++++++++++++++--------
 dlls/wininet/tests/http.c |   30 ++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+), 8 deletions(-)

diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c
index 1832b4f..2d11040 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,10 +2747,14 @@ 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->chunk_size != ~0u && (res = discard_chunked_eol(stream, req)) != ERROR_SUCCESS)
+    assert(!stream->chunk_size || stream->chunk_size == ~0u);
+
+    if (stream->end_of_data) return ERROR_NO_MORE_FILES;
+
+    /* read terminator for the previous chunk */
+    if(!stream->chunk_size && (res = discard_chunked_eol(stream, req)) != ERROR_SUCCESS)
         return res;
 
     for (;;)
@@ -2764,6 +2771,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);
@@ -2786,7 +2795,7 @@ static DWORD chunked_get_avail_data(data_stream_t *stream, http_request_t *req)
 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,
@@ -2795,13 +2804,13 @@ static DWORD chunked_read(data_stream_t *stream, http_request_t *req, BYTE *buf,
     chunked_stream_t *chunked_stream = (chunked_stream_t*)stream;
     DWORD read_bytes = 0, ret_read = 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) {
+    while(size && chunked_stream->chunk_size && !chunked_stream->end_of_data) {
         if(chunked_stream->buf_size) {
             read_bytes = min(size, min(chunked_stream->buf_size, chunked_stream->chunk_size));
 
@@ -2835,7 +2844,7 @@ static DWORD chunked_read(data_stream_t *stream, http_request_t *req, BYTE *buf,
         chunked_stream->chunk_size -= read_bytes;
         size -= read_bytes;
         ret_read += read_bytes;
-        if(!chunked_stream->chunk_size) {
+        if(size && !chunked_stream->chunk_size) {
             assert(read_mode != READMODE_NOBLOCK);
             res = start_next_chunk(chunked_stream, req);
             if(res != ERROR_SUCCESS)
@@ -2855,8 +2864,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 +2914,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);
diff --git a/dlls/wininet/tests/http.c b/dlls/wininet/tests/http.c
index bf57223..2526681 100644
--- a/dlls/wininet/tests/http.c
+++ b/dlls/wininet/tests/http.c
@@ -4777,8 +4777,37 @@ static const struct notification async_send_request_ex_resolve_failure_test[] =
     { internet_close_handle, INTERNET_STATUS_HANDLE_CLOSING, 0, }
 };
 
+static const struct notification async_send_request_ex_chunked_test[] =
+{
+    { internet_connect,      INTERNET_STATUS_HANDLE_CREATED },
+    { http_open_request,     INTERNET_STATUS_HANDLE_CREATED },
+    { http_send_request_ex,  INTERNET_STATUS_DETECTING_PROXY, 1, 0, 1 },
+    { http_send_request_ex,  INTERNET_STATUS_COOKIE_SENT, 1, 0, 1 },
+    { http_send_request_ex,  INTERNET_STATUS_RESOLVING_NAME, 1, 0, 1 },
+    { http_send_request_ex,  INTERNET_STATUS_NAME_RESOLVED, 1, 0, 1 },
+    { http_send_request_ex,  INTERNET_STATUS_CONNECTING_TO_SERVER, 1 },
+    { http_send_request_ex,  INTERNET_STATUS_CONNECTED_TO_SERVER, 1 },
+    { http_send_request_ex,  INTERNET_STATUS_SENDING_REQUEST, 1 },
+    { http_send_request_ex,  INTERNET_STATUS_REQUEST_SENT, 1 },
+    { http_send_request_ex,  INTERNET_STATUS_REQUEST_COMPLETE, 1 },
+    { http_end_request,      INTERNET_STATUS_RECEIVING_RESPONSE, 1 },
+    { http_end_request,      INTERNET_STATUS_RESPONSE_RECEIVED, 1 },
+    { http_end_request,      INTERNET_STATUS_REQUEST_COMPLETE, 1 },
+    { internet_close_handle, INTERNET_STATUS_CLOSING_CONNECTION },
+    { internet_close_handle, INTERNET_STATUS_CONNECTION_CLOSED },
+    { internet_close_handle, INTERNET_STATUS_HANDLE_CLOSING },
+    { internet_close_handle, INTERNET_STATUS_HANDLE_CLOSING }
+};
+
 static const struct notification_data notification_data[] = {
     {
+        async_send_request_ex_chunked_test,
+        sizeof(async_send_request_ex_chunked_test)/sizeof(async_send_request_ex_chunked_test[0]),
+        "GET",
+        "test.winehq.org",
+        "tests/data.php"
+    },
+    {
         async_send_request_ex_test,
         sizeof(async_send_request_ex_test)/sizeof(async_send_request_ex_test[0]),
         "POST",
@@ -5100,6 +5129,7 @@ START_TEST(http)
     test_async_HttpSendRequestEx(&notification_data[0]);
     test_async_HttpSendRequestEx(&notification_data[1]);
     test_async_HttpSendRequestEx(&notification_data[2]);
+    test_async_HttpSendRequestEx(&notification_data[3]);
     InternetOpenRequest_test();
     test_http_cache();
     InternetOpenUrlA_test();




More information about the wine-cvs mailing list