wininet Return size when buffer too small

Rotem Zach rotemz at gmail.com
Sun Sep 7 07:58:45 CDT 2008


When InternetQueryOption is called with an insufficient buffer legnth, it returns the needed buffer size.
This patch implements that for severl cases, and it includes a conformance test for the changes.
---
 dlls/wininet/http.c           |   32 +++++++++----
 dlls/wininet/internet.c       |   47 ++++++++++++++----
 dlls/wininet/tests/internet.c |  105 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 163 insertions(+), 21 deletions(-)

diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c
index 00dfa0f..b072cb8 100644
--- a/dlls/wininet/http.c
+++ b/dlls/wininet/http.c
@@ -1442,9 +1442,10 @@ static DWORD HTTPREQ_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b
     case INTERNET_OPTION_HANDLE_TYPE:
         TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
 
-        if (*size < sizeof(ULONG))
+        if (*size < sizeof(DWORD)) {
+            *size = sizeof(DWORD);
             return ERROR_INSUFFICIENT_BUFFER;
-
+        }
         *size = sizeof(DWORD);
         *(DWORD*)buffer = INTERNET_HANDLE_TYPE_HTTP_REQUEST;
         return ERROR_SUCCESS;
@@ -1471,16 +1472,19 @@ static DWORD HTTPREQ_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b
 
         if(unicode) {
             len = (strlenW(url)+1) * sizeof(WCHAR);
-            if(*size < len)
+            if(*size < len) {
+                *size = len;
                 return ERROR_INSUFFICIENT_BUFFER;
-
+            }
             *size = len;
             strcpyW(buffer, url);
             return ERROR_SUCCESS;
         }else {
             len = WideCharToMultiByte(CP_ACP, 0, url, -1, buffer, *size, NULL, NULL);
-            if(len > *size)
+            if(*size < len) {
+                *size = len;
                 return ERROR_INSUFFICIENT_BUFFER;
+            }
 
             *size = len;
             return ERROR_SUCCESS;
@@ -1519,16 +1523,16 @@ static DWORD HTTPREQ_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b
     case INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT: {
         PCCERT_CONTEXT context;
 
-        if(*size < sizeof(INTERNET_CERTIFICATE_INFOW)) {
-            *size = sizeof(INTERNET_CERTIFICATE_INFOW);
-            return ERROR_INSUFFICIENT_BUFFER;
-        }
-
         context = (PCCERT_CONTEXT)NETCON_GetCert(&(req->netConnection));
         if(context) {
             INTERNET_CERTIFICATE_INFOW *info = (INTERNET_CERTIFICATE_INFOW*)buffer;
             DWORD len;
 
+            if(*size < sizeof(INTERNET_CERTIFICATE_INFOW)) {
+                *size = sizeof(INTERNET_CERTIFICATE_INFOW);
+                return ERROR_INSUFFICIENT_BUFFER;
+            }
+            
             memset(info, 0, sizeof(INTERNET_CERTIFICATE_INFOW));
             info->ftExpiry = context->pCertInfo->NotAfter;
             info->ftStart = context->pCertInfo->NotBefore;
@@ -1576,6 +1580,12 @@ static DWORD HTTPREQ_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b
             CertFreeCertificateContext(context);
             return ERROR_SUCCESS;
         }
+        else {
+            if(*size < sizeof(INTERNET_CERTIFICATE_INFOW)) {
+                *size = sizeof(INTERNET_CERTIFICATE_INFOW);
+                return ERROR_INTERNET_INVALID_OPERATION;
+            }
+        }
     }
     }
 
@@ -2311,7 +2321,9 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev
     }
 
     if (lpdwIndex)
+    {
         (*lpdwIndex)++;
+    }
 
     /* coalesce value to requested type */
     if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER)
diff --git a/dlls/wininet/internet.c b/dlls/wininet/internet.c
index d06298f..b9376e1 100644
--- a/dlls/wininet/internet.c
+++ b/dlls/wininet/internet.c
@@ -504,8 +504,10 @@ static DWORD APPINFO_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b
     case INTERNET_OPTION_HANDLE_TYPE:
         TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
 
-        if (*size < sizeof(ULONG))
+        if (*size < sizeof(DWORD)) {
+            *size = sizeof(DWORD);
             return ERROR_INSUFFICIENT_BUFFER;
+        }
 
         *size = sizeof(DWORD);
         *(DWORD*)buffer = INTERNET_HANDLE_TYPE_INTERNET;
@@ -545,8 +547,10 @@ static DWORD APPINFO_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b
                 proxyBytesRequired = (lstrlenW(ai->lpszProxy) + 1) * sizeof(WCHAR);
             if (ai->lpszProxyBypass)
                 proxyBypassBytesRequired = (lstrlenW(ai->lpszProxyBypass) + 1) * sizeof(WCHAR);
-            if (*size < sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired)
-                    return ERROR_INSUFFICIENT_BUFFER;
+            if (*size < sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired) {
+                *size = sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired;
+                return ERROR_INSUFFICIENT_BUFFER;
+            }
 
             proxy = (LPWSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOW));
             proxy_bypass = (LPWSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired);
@@ -577,7 +581,10 @@ static DWORD APPINFO_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b
                 proxyBypassBytesRequired = WideCharToMultiByte(CP_ACP, 0, ai->lpszProxyBypass, -1,
                         NULL, 0, NULL, NULL);
             if (*size < sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired)
+            {
+                *size = sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired;
                 return ERROR_INSUFFICIENT_BUFFER;
+            }
 
             proxy = (LPSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOA));
             proxy_bypass = (LPSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired);
@@ -599,6 +606,10 @@ static DWORD APPINFO_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b
             *size = sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired;
             return ERROR_SUCCESS;
         }
+    case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
+    case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
+        *size = 0;
+        return ERROR_INTERNET_INVALID_OPERATION;
     }
 
     return INET_QueryOption(option, buffer, size, unicode);
@@ -2028,8 +2039,10 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode)
     case INTERNET_OPTION_REQUEST_FLAGS:
         TRACE("INTERNET_OPTION_REQUEST_FLAGS\n");
 
-        if (*size < sizeof(ULONG))
+        if (*size < sizeof(ULONG)) {
+            *size = sizeof(ULONG);
             return ERROR_INSUFFICIENT_BUFFER;
+        }
 
         *(ULONG*)buffer = 4;
         *size = sizeof(ULONG);
@@ -2037,8 +2050,10 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode)
         return ERROR_SUCCESS;
 
     case INTERNET_OPTION_HTTP_VERSION:
-        if (*size < sizeof(HTTP_VERSION_INFO))
+        if (*size < sizeof(HTTP_VERSION_INFO)) {
+            *size = sizeof(HTTP_VERSION_INFO);
             return ERROR_INSUFFICIENT_BUFFER;
+        }
 
         /*
          * Presently hardcoded to 1.1
@@ -2052,8 +2067,10 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode)
     case INTERNET_OPTION_CONNECTED_STATE:
         FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n");
 
-        if (*size < sizeof(ULONG))
+        if (*size < sizeof(ULONG)) {
+            *size = sizeof(ULONG);
             return ERROR_INSUFFICIENT_BUFFER;
+        }
 
         *(ULONG*)buffer = INTERNET_STATE_CONNECTED;
         *size = sizeof(ULONG);
@@ -2072,9 +2089,11 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode)
 
     case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
         TRACE("INTERNET_OPTION_MAX_CONNS_PER_SERVER\n");
-
-        if (*size < sizeof(ULONG))
+        
+        if (*size < sizeof(ULONG)) {
+            *size = sizeof(ULONG);
             return ERROR_INSUFFICIENT_BUFFER;
+        }
 
         *(ULONG*)buffer = 2;
         *size = sizeof(ULONG);
@@ -2084,8 +2103,10 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode)
     case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
             TRACE("INTERNET_OPTION_MAX_CONNS_1_0_SERVER\n");
 
-            if (*size < sizeof(ULONG))
+            if (*size < sizeof(ULONG)) {
+                *size = sizeof(ULONG);
                 return ERROR_INSUFFICIENT_BUFFER;
+            }
 
             *(ULONG*)size = 4;
             *size = sizeof(ULONG);
@@ -2101,8 +2122,10 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode)
 
         TRACE("INTERNET_OPTION_VERSION\n");
 
-        if (*size < sizeof(INTERNET_VERSION_INFO))
+        if (*size < sizeof(INTERNET_VERSION_INFO)) {
+            *size = sizeof(INTERNET_VERSION_INFO);
             return ERROR_INSUFFICIENT_BUFFER;
+        }
 
         memcpy(buffer, &info, sizeof(info));
         *size = sizeof(info);
@@ -2116,8 +2139,10 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode)
 
         FIXME("INTERNET_OPTION_PER_CONNECTION_OPTION stub\n");
 
-        if (*size < sizeof(INTERNET_PER_CONN_OPTION_LISTW))
+        if (*size < sizeof(INTERNET_PER_CONN_OPTION_LISTW)) {
+            *size = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
             return ERROR_INSUFFICIENT_BUFFER;
+        }
 
         for (i = 0; i < con->dwOptionCount; i++) {
             INTERNET_PER_CONN_OPTIONW *option = con->pOptions + i;
diff --git a/dlls/wininet/tests/internet.c b/dlls/wininet/tests/internet.c
index 14adc43..143e287 100644
--- a/dlls/wininet/tests/internet.c
+++ b/dlls/wininet/tests/internet.c
@@ -363,6 +363,110 @@ static void test_version(void)
 }
 
 /* ############################### */
+static void internetQWCheckOption(HINTERNET hinet,DWORD dwOption,LPCWSTR format,int goodSize)
+{
+  int retval,len=0;
+  
+  retval=InternetQueryOptionW(hinet,dwOption,NULL,&len);
+  ok(len == goodSize,format,len,goodSize);
+}
+
+static void internetQWCheckErr(DWORD goodErr,LPCWSTR format)
+{
+  int retval,err;
+  
+  err = GetLastError();
+  ok(err == goodErr,format,err, goodErr);
+}
+
+static void test_InternetQueryOptionWNullBuffer(void)
+{
+  HINTERNET hinet,hinet1;
+  DWORD len;
+  const WCHAR useragent[] = {'W','i','n','i','n','e','t',' ','T','e','s','t',0};
+  char *buffer;
+  int retval,err;
+  BOOL fail;
+  const WCHAR szUrl[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g',0};
+  
+  internetQWCheckOption(NULL,INTERNET_OPTION_MAX_CONNS_PER_SERVER,(WCHAR*)"Open: INTERNET_OPTION_MAX_CONNS_PER_SERVER Got wrong length %d instead of %d\n",sizeof(ULONG));
+  internetQWCheckErr(ERROR_INSUFFICIENT_BUFFER,(WCHAR*)"Open: INTERNET_OPTION_MAX_CONNS_PER_SERVER Wrong Error %d Expecting %d\n");
+
+  internetQWCheckOption(NULL,INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER,(WCHAR*)"Open: INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER Got wrong length %d instead of %d\n",sizeof(ULONG));
+  internetQWCheckErr(ERROR_INSUFFICIENT_BUFFER,(WCHAR*)"Open: INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER Wrong Error %d Expecting %d\n");
+  
+  
+  hinet = InternetOpenW(useragent,0,NULL,NULL,0);
+  ok((hinet != 0x0),"InternetOpen Failed\n");
+
+  internetQWCheckOption(hinet,INTERNET_OPTION_REQUEST_FLAGS,"INTERNET_OPTION_REQUEST_FLAGS Got wrong length %d instead of %d\n",sizeof(ULONG));
+
+  internetQWCheckOption(hinet,INTERNET_OPTION_HTTP_VERSION,"INTERNET_OPTION_HTTP_VERSION Got wrong length %d instead of %d\n",sizeof(HTTP_VERSION_INFO));
+
+  internetQWCheckOption(hinet,INTERNET_OPTION_CONNECTED_STATE,(WCHAR*)"INTERNET_OPTION_CONNECTED_STATE Got wrong length %d instead of %d\n",sizeof(ULONG));
+  
+  internetQWCheckOption(hinet,INTERNET_OPTION_PROXY,(WCHAR*)"INTERNET_OPTION_PROXY Got wrong length %d instead of %d\n",sizeof(INTERNET_PROXY_INFO));
+  
+  internetQWCheckOption(hinet,INTERNET_OPTION_VERSION,(WCHAR*)"INTERNET_OPTION_VERSION Got wrong length %d instead of %d\n",sizeof(INTERNET_VERSION_INFO));
+
+  internetQWCheckOption(hinet,INTERNET_OPTION_MAX_CONNS_PER_SERVER,(WCHAR*)"INTERNET_OPTION_MAX_CONNS_PER_SERVER Got wrong length %d instead of %d\n",0);
+  internetQWCheckErr(ERROR_INTERNET_INVALID_OPERATION,(WCHAR*)"INTERNET_OPTION_MAX_CONNS_PER_SERVER Wrong Error %d Expecting %d\n");
+
+  internetQWCheckOption(hinet,INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER,(WCHAR*)"INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER Got wrong length %d instead of %d\n",0);
+  internetQWCheckErr(ERROR_INTERNET_INVALID_OPERATION,(WCHAR*)"INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER Wrong Error %d Expecting %d\n");
+
+  internetQWCheckOption(hinet,INTERNET_OPTION_SECURITY_FLAGS,(WCHAR*)"INTERNET_OPTION_SECURITY_FLAGS Got wrong length %d instead of %d\n",0);
+  todo_wine{internetQWCheckErr(ERROR_INTERNET_INCORRECT_HANDLE_TYPE,(WCHAR*)"INTERNET_OPTION_SECURITY_FLAGS Wrong Error %d Expecting %d\n");}
+
+  todo_wine{ internetQWCheckOption(hinet,INTERNET_OPTION_PER_CONNECTION_OPTION,(WCHAR*)"INTERNET_OPTION_PER_CONNECTION_OPTION Got wrong length %d instead of %d\n",0);
+  internetQWCheckErr(ERROR_INVALID_PARAMETER,(WCHAR*)"INTERNET_OPTION_PER_CONNECTION_OPTION Wrong Error %d Expecting %d\n"); }
+  
+  internetQWCheckOption(hinet,INTERNET_OPTION_HANDLE_TYPE,(WCHAR*)"INTERNET_OPTION_HANDLE_TYPE Got wrong length %d instead of %d\n",sizeof(DWORD));
+  internetQWCheckErr(ERROR_INSUFFICIENT_BUFFER,(WCHAR*)"INTERNET_OPTION_HANDLE_TYPE Wrong Error %d Expecting %d\n");
+
+  internetQWCheckOption(hinet,INTERNET_OPTION_USER_AGENT,(WCHAR*)"INTERNET_OPTION_USER_AGENT Got wrong length %d instead of %d\n",sizeof(useragent));
+  internetQWCheckErr(ERROR_INSUFFICIENT_BUFFER,(WCHAR*)"INTERNET_OPTION_USER_AGENT Wrong Error %d Expecting %d\n");
+
+  internetQWCheckOption(hinet,INTERNET_OPTION_URL,(WCHAR*)"INTERNET_OPTION_URL Got wrong length %d instead of %d\n",0);
+  internetQWCheckErr(ERROR_INTERNET_INCORRECT_HANDLE_TYPE,(WCHAR*)"INTERNET_OPTION_URL Wrong Error %d Expecting %d\n");
+  
+  internetQWCheckOption(hinet,INTERNET_OPTION_DATAFILE_NAME,(WCHAR*)"INTERNET_OPTION_DATAFILE_NAME Got wrong length %d instead of %d\n",0);
+  internetQWCheckErr(ERROR_INTERNET_INCORRECT_HANDLE_TYPE,(WCHAR*)"INTERNET_OPTION_DATAFILE_NAME Wrong Error %d Expecting %d\n");
+  
+  internetQWCheckOption(hinet,INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT,(WCHAR*)"INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT Got wrong length %d instead of %d\n",0);
+  internetQWCheckErr(ERROR_INTERNET_INCORRECT_HANDLE_TYPE,(WCHAR*)"INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT Wrong Error %d Expecting %d\n");
+
+
+  hinet1 = InternetOpenUrlW(hinet,szUrl,0,0,0,0);
+
+  todo_wine {internetQWCheckOption(hinet1,INTERNET_OPTION_SECURITY_FLAGS,(WCHAR*)"Open: INTERNET_OPTION_SECURITY_FLAGS Got wrong length %d instead of %d\n",sizeof(ULONG));
+  internetQWCheckErr(ERROR_INSUFFICIENT_BUFFER,(WCHAR*)"Open: INTERNET_OPTION_SECURITY_FLAGS Wrong Error %d Expecting %d\n");
+
+  internetQWCheckOption(hinet1,INTERNET_OPTION_PER_CONNECTION_OPTION,(WCHAR*)"Open: INTERNET_OPTION_PER_CONNECTION_OPTION Got wrong length %d instead of %d\n",0);
+  internetQWCheckErr(ERROR_INVALID_PARAMETER,(WCHAR*)"Open: INTERNET_OPTION_PER_CONNECTION_OPTION Wrong Error %d Expecting %d\n");}
+
+  internetQWCheckOption(hinet1,INTERNET_OPTION_HANDLE_TYPE,(WCHAR*)"Open: INTERNET_OPTION_HANDLE_TYPE Got wrong length %d instead of %d\n",sizeof(DWORD));
+  internetQWCheckErr(ERROR_INSUFFICIENT_BUFFER,(WCHAR*)"Open: INTERNET_OPTION_HANDLE_TYPE Wrong Error %d Expecting %d\n");
+  
+  internetQWCheckOption(hinet1,INTERNET_OPTION_USER_AGENT,(WCHAR*)"Open: INTERNET_OPTION_USER_AGENT Got wrong length %d instead of %d\n",0);
+  internetQWCheckErr(ERROR_INTERNET_INCORRECT_HANDLE_TYPE,(WCHAR*)"Open: INTERNET_OPTION_USER_AGENT Wrong Error %d Expecting %d\n");
+
+  internetQWCheckOption(hinet1,INTERNET_OPTION_URL,(WCHAR*)"Open: INTERNET_OPTION_URL Got wrong length %d instead of %d\n",sizeof(szUrl)+2);
+  internetQWCheckErr(ERROR_INSUFFICIENT_BUFFER,(WCHAR*)"Open: INTERNET_OPTION_URL Wrong Error %d Expecting %d\n");
+  
+  internetQWCheckOption(hinet1,INTERNET_OPTION_DATAFILE_NAME,(WCHAR*)"Open: INTERNET_OPTION_DATAFILE_NAME Got wrong length %d instead of %d\n",0);
+  internetQWCheckErr(ERROR_INTERNET_ITEM_NOT_FOUND,(WCHAR*)"Open: INTERNET_OPTION_DATAFILE_NAME Wrong Error %d Expecting %d\n");
+  
+  internetQWCheckOption(hinet1,INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT,(WCHAR*)"Open: INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT Got wrong length %d instead of %d\n",sizeof(INTERNET_CERTIFICATE_INFO));
+  internetQWCheckErr(ERROR_INTERNET_INVALID_OPERATION,(WCHAR*)"Open: INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT Wrong Error %d Expecting %d\n");
+
+
+  InternetCloseHandle(hinet1);
+  InternetCloseHandle(hinet);
+
+}
+
+/* ############################### */
 
 START_TEST(internet)
 {
@@ -371,4 +475,5 @@ START_TEST(internet)
   test_get_cookie();
   test_version();
   test_null();
+  test_InternetQueryOptionWNullBuffer();
 }
-- 
1.6.0.1


--------------050706000203070306070005--



More information about the wine-patches mailing list