From dee8751ca890a62c3b2e10875a75a4f0bbe04f4f Mon Sep 17 00:00:00 2001
From: Robert Shearman <rob@codeweavers.com>
Date: Mon, 19 Jul 2004 20:09:20 +0000
Subject: [PATCH] Fix HttpQueryInfo(HTTP_QUERY_RAW_HEADERS*) so that it returns
 the actual headers received, not just reconstituting them from processed
 data.

---
 dlls/wininet/http.c     | 277 ++++++++++++++++++++--------------------
 dlls/wininet/internet.h |   1 +
 2 files changed, 140 insertions(+), 138 deletions(-)

diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c
index 9e9f8bc0113..d2cbf57d226 100644
--- a/dlls/wininet/http.c
+++ b/dlls/wininet/http.c
@@ -96,6 +96,66 @@ BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr);
 INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField);
 BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, INT index);
 
+/***********************************************************************
+ *           HTTP_Tokenize (internal)
+ *
+ *  Tokenize a string, allocating memory for the tokens.
+ */
+static LPWSTR * HTTP_Tokenize(LPCWSTR string, LPCWSTR token_string)
+{
+    LPWSTR * token_array;
+    int tokens = 0;
+    int i;
+    LPCWSTR next_token;
+
+    /* empty string has no tokens */
+    if (*string)
+        tokens++;
+    /* count tokens */
+    for (i = 0; string[i]; i++)
+        if (!strncmpW(string+i, token_string, strlenW(token_string)))
+        {
+            int j;
+            tokens++;
+            /* we want to skip over separators, but not the null terminator */
+            for (j = 0; j < strlenW(token_string) - 1; j++)
+                if (!string[i+j])
+                    break;
+            i += j;
+        }
+
+    /* add 1 for terminating NULL */
+    token_array = HeapAlloc(GetProcessHeap(), 0, (tokens+1) * sizeof(*token_array));
+    token_array[tokens] = NULL;
+    if (!tokens)
+        return token_array;
+    for (i = 0; i < tokens; i++)
+    {
+        int len;
+        next_token = strstrW(string, token_string);
+        if (!next_token) next_token = string+strlenW(string);
+        len = next_token - string;
+        token_array[i] = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
+        memcpy(token_array[i], string, len*sizeof(WCHAR));
+        token_array[i][len] = '\0';
+        string = next_token+strlenW(token_string);
+    }
+    return token_array;
+}
+
+/***********************************************************************
+ *           HTTP_FreeTokens (internal)
+ *
+ *  Frees memory returned from HTTP_Tokenize.
+ */
+static void HTTP_FreeTokens(LPWSTR * token_array)
+{
+    int i;
+    for (i = 0; token_array[i]; i++)
+        HeapFree(GetProcessHeap(), 0, token_array[i]);
+    HeapFree(GetProcessHeap(), 0, token_array);
+}
+
 /***********************************************************************
  *           HTTP_HttpAddRequestHeadersW (internal)
  */
@@ -788,141 +848,6 @@ HINTERNET WINAPI HTTP_HttpOpenRequestW(HINTERNET hHttpSession,
     return handle;
 }
 
-/***********************************************************************
- *           HTTP_build_resp_header (internal)
- *
- *   This function reconstructs the response header.  It takes an array
- *  of strings in the response buffer, and the count of those strings.
- *  A null pointer in the array represents a separator.
- *
- *  RETURNS:
- *    a buffer allocated and initialized with the reconstructed response
- *    *pSize is set to the number of wide characters in the returned buffer
- */
-static LPWSTR HTTP_build_resp_header( 
-          LPCWSTR *str, DWORD count, BOOL bUseCrlf, DWORD *pSize )
-{
-    static const WCHAR szcrlf[] = { '\r','\n',0 };
-    DWORD len, i;
-    LPWSTR ret;
-
-    /* calculate the length of the response buffer */
-    len = 0;
-    for( i=0; i<count; i++ )
-    {
-        if( str[i] )
-            len += strlenW( str[i] );
-        else if( bUseCrlf )
-            len += 2;
-        else
-            len ++;
-    }
-    len++;
-
-    /* fill the buffer in */
-    ret = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
-    len = 0;
-    for( i=0; i<count; i++ )
-    {
-        if( str[i] )
-        {
-            strcpyW( &ret[len], str[i] );
-            len += strlenW( str[i] );
-        }
-        else if( bUseCrlf )
-        {
-            strcpyW( &ret[len], szcrlf );
-            len += 2;
-        }
-        else
-            ret[len++] = 0;
-    }
-    ret[len++] = 0;
-    *pSize = len;
-    return ret;
-}
-
-/***********************************************************************
- *           HTTP_query_raw_headers (internal)
- *
- *  Reconstruct the raw HTTP header and copy it into the buffer provided
- */
-static BOOL HTTP_query_raw_headers( LPWININETHTTPREQW lpwhr, BOOL bUseCrlf,
-	                     LPVOID lpBuffer, LPDWORD lpdwBufferLength )
-{
-    static const WCHAR szColonSpace[] = { ':',' ',0 };
-    static const WCHAR szSpace[] = { ' ',0 };
-    BOOL bSuccess = FALSE;
-    LPCWSTR *str;
-    DWORD i, n, size = 0;
-    LPWSTR hdr;
-
-    n = 7 + ( HTTP_QUERY_MAX + 1 + lpwhr->nCustHeaders )*4 ;
-    str = HeapAlloc( GetProcessHeap(), 0, sizeof(LPCWSTR)*n );
-    n = 0;
-
-    /* reconstruct the status line */
-    str[n++] = lpwhr->StdHeaders[HTTP_QUERY_VERSION].lpszValue;
-    str[n++] = szSpace;
-    str[n++] = lpwhr->StdHeaders[HTTP_QUERY_STATUS_CODE].lpszValue;
-    str[n++] = szSpace;
-    str[n++] = lpwhr->StdHeaders[HTTP_QUERY_STATUS_TEXT].lpszValue;
-    str[n++] = NULL;
-
-    /* Append standard request heades */
-    for (i = 0; i <= HTTP_QUERY_MAX; i++)
-    {
-        if( lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST )
-            continue;
-        if( !lpwhr->StdHeaders[i].lpszField )
-            continue;
-        if( !lpwhr->StdHeaders[i].lpszValue )
-            continue;
-        /* ignore the stuff that's in the status line */
-        if( ( i == HTTP_QUERY_VERSION ) ||
-            ( i == HTTP_QUERY_STATUS_CODE ) ||
-            ( i == HTTP_QUERY_STATUS_TEXT ) )
-            continue;
-        str[n++] = lpwhr->StdHeaders[i].lpszField;
-        str[n++] = szColonSpace;
-        str[n++] = lpwhr->StdHeaders[i].lpszValue,
-        str[n++] = NULL;
-    }
-
-    /* Append custom request heades */
-    for (i = 0; i < lpwhr->nCustHeaders; i++)
-    {
-        if( lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
-            continue;
-        if( !lpwhr->pCustHeaders[i].lpszField )
-            continue;
-        if( !lpwhr->pCustHeaders[i].lpszValue )
-            continue;
-        str[n++] = lpwhr->pCustHeaders[i].lpszField;
-        str[n++] = szColonSpace;
-        str[n++] = lpwhr->pCustHeaders[i].lpszValue;
-        str[n++] = NULL;
-    }
-    str[n++] = NULL;
-
-    /* concatenate all the strings together */
-    hdr = HTTP_build_resp_header( str, n, bUseCrlf, &size );
-    HeapFree( GetProcessHeap(), 0, str );
-
-    /* check that the target buffer is big enough */
-    if ( size > (*lpdwBufferLength/sizeof(WCHAR)) )
-        INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
-    else
-    {
-        memcpy( lpBuffer, hdr, size*sizeof(WCHAR) );
-        bSuccess = TRUE;
-    }
-    HeapFree( GetProcessHeap(), 0, hdr );
-    *lpdwBufferLength = size*sizeof(WCHAR);
-
-    return bSuccess;
-}
-
 /***********************************************************************
  *           HTTP_HttpQueryInfoW (internal)
  */
@@ -947,9 +872,52 @@ BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLevel,
         INT index = dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK;
 
         if (index == HTTP_QUERY_RAW_HEADERS_CRLF)
-            return HTTP_query_raw_headers(lpwhr, TRUE, lpBuffer, lpdwBufferLength );
-        if (index == HTTP_QUERY_RAW_HEADERS)
-            return HTTP_query_raw_headers(lpwhr, FALSE, lpBuffer, lpdwBufferLength );
+        {
+            int len = strlenW(lpwhr->lpszRawHeaders);
+            if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
+            {
+                *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
+                INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
+                return FALSE;
+            }
+            memcpy(lpBuffer, lpwhr->lpszRawHeaders, (len+1)*sizeof(WCHAR));
+            *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
+            return TRUE;
+        }
+        else if (index == HTTP_QUERY_RAW_HEADERS)
+        {
+            static const WCHAR szCrLf[] = {'\r','\n',0};
+            LPWSTR * ppszRawHeaderLines = HTTP_Tokenize(lpwhr->lpszRawHeaders, szCrLf);
+            int size = 0;
+            int i;
+            LPWSTR pszString = (WCHAR*)lpBuffer;
+
+            for (i = 0; ppszRawHeaderLines[i]; i++)
+                size += strlenW(ppszRawHeaderLines[i]) + 1;
+
+            if (size + 1 > *lpdwBufferLength/sizeof(WCHAR))
+            {
+                HTTP_FreeTokens(ppszRawHeaderLines);
+                *lpdwBufferLength = (size + 1) * sizeof(WCHAR);
+                INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
+                return FALSE;
+            }
+
+            for (i = 0; ppszRawHeaderLines[i]; i++)
+            {
+                int len = strlenW(ppszRawHeaderLines[i]);
+                memcpy(pszString, ppszRawHeaderLines[i], (len+1)*sizeof(WCHAR));
+                pszString += len+1;
+            }
+            *pszString = '\0';
+
+            TRACE("returning data: %s\n", debugstr_wn((WCHAR*)lpBuffer, size));
+
+            *lpdwBufferLength = (size + 1) * sizeof(WCHAR);
+            HTTP_FreeTokens(ppszRawHeaderLines);
+
+            return TRUE;
+        }
 	else if (index >= 0 && index <= HTTP_QUERY_MAX && lpwhr->StdHeaders[index].lpszValue)
 	{
 	    lphttpHdr = &lpwhr->StdHeaders[index];
@@ -2011,8 +1979,12 @@ BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr)
     INT  rc = 0;
     WCHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
     static const WCHAR szHttp[] = { 'H','T','T','P',0 };
+    static const WCHAR szCrLf[] = {'\r','\n',0};
     char bufferA[MAX_REPLY_LEN];
     LPWSTR status_code, status_text;
+    int cchMaxRawHeaders = 1024;
+    LPWSTR lpszRawHeaders = HeapAlloc(GetProcessHeap(), 0, (cchMaxRawHeaders+1)*sizeof(WCHAR));
+    int cchRawHeaders = 0;
 
     TRACE("-->\n");
 
@@ -2039,6 +2011,18 @@ BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr)
     if (strncmpW(buffer, szHttp, 4) != 0)
         goto lend;
 
+    /* regenerate raw headers */
+    while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders)
+    {
+        cchMaxRawHeaders *= 2;
+        lpszRawHeaders = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR));
+    }
+    memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR));
+    cchRawHeaders += (buflen-1);
+    memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf));
+    cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1;
+    lpszRawHeaders[cchRawHeaders] = '\0';
+
     /* split the version from the status code */
     status_code = strchrW( buffer, ' ' );
     if( !status_code )
@@ -2065,6 +2049,18 @@ BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr)
 	{
             TRACE("got line %s, now interpretting\n", debugstr_a(bufferA));
             MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
+
+            while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders)
+            {
+                cchMaxRawHeaders *= 2;
+                lpszRawHeaders = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR));
+            }
+            memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR));
+            cchRawHeaders += (buflen-1);
+            memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf));
+            cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1;
+            lpszRawHeaders[cchRawHeaders] = '\0';
+
             if (!HTTP_InterpretHttpHeader(buffer, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
                 break;
 
@@ -2078,6 +2074,9 @@ BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr)
 	}
     }while(1);
 
+    if (lpwhr->lpszRawHeaders) HeapFree(GetProcessHeap(), 0, lpszRawHeaders);
+    lpwhr->lpszRawHeaders = lpszRawHeaders;
+    TRACE("raw headers: %s\n", debugstr_w(lpszRawHeaders));
     bSuccess = TRUE;
 
 lend:
@@ -2468,6 +2467,8 @@ void HTTP_CloseHTTPRequestHandle(LPWININETHTTPREQW lpwhr)
         HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
     if (lpwhr->lpszHostName)
         HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
+    if (lpwhr->lpszRawHeaders)
+        HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders);
 
     for (i = 0; i <= HTTP_QUERY_MAX; i++)
     {
diff --git a/dlls/wininet/internet.h b/dlls/wininet/internet.h
index f2e93cfaad0..fbd516135b4 100644
--- a/dlls/wininet/internet.h
+++ b/dlls/wininet/internet.h
@@ -173,6 +173,7 @@ typedef struct
     LPWSTR lpszPath;
     LPWSTR lpszVerb;
     LPWSTR lpszHostName;
+    LPWSTR lpszRawHeaders;
     WININET_NETCONNECTION netConnection;
     HTTPHEADERW StdHeaders[HTTP_QUERY_MAX+1];
     HTTPHEADERW *pCustHeaders;
-- 
GitLab