Hans Leidekker : winhttp: Implement WinHttpReceiveResponse.

Alexandre Julliard julliard at winehq.org
Tue Aug 26 07:07:41 CDT 2008


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

Author: Hans Leidekker <hans at codeweavers.com>
Date:   Tue Aug 26 11:04:04 2008 +0200

winhttp: Implement WinHttpReceiveResponse.

---

 dlls/winhttp/main.c          |   11 ---
 dlls/winhttp/request.c       |  156 +++++++++++++++++++++++++++++++++++++++++-
 dlls/winhttp/tests/winhttp.c |    2 +-
 3 files changed, 155 insertions(+), 14 deletions(-)

diff --git a/dlls/winhttp/main.c b/dlls/winhttp/main.c
index 3fb3026..a87d5ab 100644
--- a/dlls/winhttp/main.c
+++ b/dlls/winhttp/main.c
@@ -106,17 +106,6 @@ BOOL WINAPI WinHttpQueryDataAvailable (HINTERNET hInternet, LPDWORD lpdwNumberOf
 }
 
 /***********************************************************************
- *          WinHttpReceiveResponse (winhttp.@)
- */
-BOOL WINAPI WinHttpReceiveResponse (HINTERNET hRequest, LPVOID lpReserved)
-{
-    FIXME("stub\n");
-
-    SetLastError(ERROR_NOT_SUPPORTED);
-    return FALSE;
-}
-
-/***********************************************************************
  *          WinHttpSetOption (winhttp.@)
  */
 BOOL WINAPI WinHttpSetOption (HINTERNET hInternet, DWORD dwOption, LPVOID lpBuffer, DWORD dwBufferLength)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c
index 8a32320..954f576 100644
--- a/dlls/winhttp/request.c
+++ b/dlls/winhttp/request.c
@@ -278,8 +278,6 @@ static BOOL insert_header( request_t *request, header_t *header )
     DWORD count;
     header_t *hdrs;
 
-    TRACE("inserting %s: %s\n", debugstr_w(header->field), debugstr_w(header->value));
-
     count = request->num_headers + 1;
     if (count > 1)
         hdrs = heap_realloc_zero( request->headers, sizeof(header_t) * count );
@@ -796,3 +794,157 @@ BOOL WINAPI WinHttpSendRequest( HINTERNET hrequest, LPCWSTR headers, DWORD heade
     release_object( &request->hdr );
     return ret;
 }
+
+static void clear_response_headers( request_t *request )
+{
+    unsigned int i;
+
+    for (i = 0; i < request->num_headers; i++)
+    {
+        if (!request->headers[i].field) continue;
+        if (!request->headers[i].value) continue;
+        if (request->headers[i].is_request) continue;
+        delete_header( request, i );
+        i--;
+    }
+}
+
+#define MAX_REPLY_LEN   1460
+#define INITIAL_HEADER_BUFFER_SIZE  512
+
+static BOOL receive_response( request_t *request, BOOL clear )
+{
+    static const WCHAR crlf[] = {'\r','\n',0};
+
+    char buffer[MAX_REPLY_LEN];
+    DWORD buflen, len, offset, received_len, crlf_len = 2; /* strlenW(crlf) */
+    char *status_code, *status_text;
+    WCHAR *versionW, *status_textW, *raw_headers;
+    WCHAR status_codeW[4]; /* sizeof("nnn") */
+
+    if (!netconn_connected( &request->netconn )) return FALSE;
+
+    /* clear old response headers (eg. from a redirect response) */
+    if (clear) clear_response_headers( request );
+
+    send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NULL, 0 );
+
+    received_len = 0;
+    do
+    {
+        buflen = MAX_REPLY_LEN;
+        if (!netconn_get_next_line( &request->netconn, buffer, &buflen )) return FALSE;
+        received_len += buflen;
+
+        /* first line should look like 'HTTP/1.x nnn OK' where nnn is the status code */
+        if (!(status_code = strchr( buffer, ' ' ))) return FALSE;
+        status_code++;
+        if (!(status_text = strchr( status_code, ' ' ))) return FALSE;
+        if ((len = status_text - status_code) != sizeof("nnn") - 1) return FALSE;
+        status_text++;
+
+        TRACE("version [%s] status code [%s] status text [%s]\n",
+              debugstr_an(buffer, status_code - buffer - 1),
+              debugstr_an(status_code, len),
+              debugstr_a(status_text));
+
+    } while (!memcmp( status_code, "100", len )); /* ignore "100 Continue" responses */
+
+    /*  we rely on the fact that the protocol is ascii */
+    MultiByteToWideChar( CP_ACP, 0, status_code, len, status_codeW, len );
+    status_codeW[len] = 0;
+    if (!(process_header( request, attr_status, status_codeW, WINHTTP_ADDREQ_FLAG_REPLACE, FALSE ))) return FALSE;
+
+    len = status_code - buffer;
+    if (!(versionW = heap_alloc( len * sizeof(WCHAR) ))) return FALSE;
+    MultiByteToWideChar( CP_ACP, 0, buffer, len - 1, versionW, len -1 );
+    versionW[len - 1] = 0;
+
+    heap_free( request->version );
+    request->version = versionW;
+
+    len = buflen - (status_text - buffer);
+    if (!(status_textW = heap_alloc( len * sizeof(WCHAR) ))) return FALSE;
+    MultiByteToWideChar( CP_ACP, 0, status_text, len, status_textW, len );
+
+    heap_free( request->status_text );
+    request->status_text = status_textW;
+
+    len = max( buflen + crlf_len, INITIAL_HEADER_BUFFER_SIZE );
+    if (!(raw_headers = heap_alloc( len * sizeof(WCHAR) ))) return FALSE;
+    MultiByteToWideChar( CP_ACP, 0, buffer, buflen, raw_headers, buflen );
+    memcpy( raw_headers + buflen - 1, crlf, sizeof(crlf) );
+
+    heap_free( request->raw_headers );
+    request->raw_headers = raw_headers;
+
+    offset = buflen + crlf_len - 1;
+    for (;;)
+    {
+        header_t *header;
+
+        buflen = MAX_REPLY_LEN;
+        if (!netconn_get_next_line( &request->netconn, buffer, &buflen )) goto end;
+        received_len += buflen;
+        if (!*buffer) break;
+
+        while (len - offset < buflen + crlf_len)
+        {
+            WCHAR *tmp;
+            len *= 2;
+            if (!(tmp = heap_realloc( raw_headers, len * sizeof(WCHAR) ))) return FALSE;
+            request->raw_headers = raw_headers = tmp;
+        }
+        MultiByteToWideChar( CP_ACP, 0, buffer, buflen, raw_headers + offset, buflen );
+
+        if (!(header = parse_header( raw_headers + offset ))) break;
+        if (!(process_header( request, header->field, header->value, WINHTTP_ADDREQ_FLAG_ADD, FALSE )))
+        {
+            free_header( header );
+            break;
+        }
+        free_header( header );
+        memcpy( raw_headers + offset + buflen - 1, crlf, sizeof(crlf) );
+        offset += buflen + crlf_len - 1;
+    }
+
+    TRACE("raw headers: %s\n", debugstr_w(raw_headers));
+
+end:
+    send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, &received_len, sizeof(DWORD) );
+    return TRUE;
+}
+
+/***********************************************************************
+ *          WinHttpReceiveResponse (winhttp.@)
+ */
+BOOL WINAPI WinHttpReceiveResponse( HINTERNET hrequest, LPVOID reserved )
+{
+    BOOL ret = TRUE;
+    request_t *request;
+    DWORD size, query;
+
+    TRACE("%p, %p\n", hrequest, reserved);
+
+    if (!(request = (request_t *)grab_object( hrequest )))
+    {
+        set_last_error( ERROR_INVALID_HANDLE );
+        return FALSE;
+    }
+    if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST)
+    {
+        release_object( &request->hdr );
+        set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
+        return FALSE;
+    }
+
+    ret = receive_response( request, TRUE );
+
+    size = sizeof(DWORD);
+    query = WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER;
+    if (!query_headers( request, query, NULL, &request->content_length, &size, NULL ))
+        request->content_length = ~0UL;
+
+    release_object( &request->hdr );
+    return ret;
+}
diff --git a/dlls/winhttp/tests/winhttp.c b/dlls/winhttp/tests/winhttp.c
index 985c7de..a247938 100644
--- a/dlls/winhttp/tests/winhttp.c
+++ b/dlls/winhttp/tests/winhttp.c
@@ -122,7 +122,7 @@ static void test_SendRequest (void)
     }
 
     ret = WinHttpReceiveResponse(request, NULL);
-    todo_wine ok(ret == TRUE, "WinHttpReceiveResponse failed: %u.\n", GetLastError());
+    ok(ret == TRUE, "WinHttpReceiveResponse failed: %u.\n", GetLastError());
 
     bytes_rw = -1;
     ret = WinHttpReadData(request, buffer, sizeof(buffer) - 1, &bytes_rw);




More information about the wine-cvs mailing list