[Wininet] Implement proper async InternetOpenUrl.

Lionel Ulmer lionel.ulmer at free.fr
Sat Feb 7 08:30:46 CST 2004


With this patch, Wine's handling of InternetOpenUrl is almost the same as
the one in Windows. The only difference is that we call twice the
HANDLE_CREATED callback, once for InternetConnectA call and one for the
HttpOpenRequestA call whereas Windows only calls it once with the 'real'
handle.

As soon as I have done more tests in real Windows about how it works with
FTP, I will try to send a patch to fix this issue.

Moreover, I have no idea if the handling in the case of failures are OK - ie
should we close the handles ourself in the async case or will the
application do it for us ? I may try to do a test in Windows, but well, even
if the CloseHandle works I will have no idea if this is just luck or if the
handle was really not de-allocated.

But at least this is enough to get this installer to download the file
properly (it must store the latest handle received and not stop at the first
one so it uses the right one to do its HttpQueryInfo :-) ).

                 Lionel

Changelog:
 Implement proper asynchronous InternetOpenUrl handling.

-- 
		 Lionel Ulmer - http://www.bbrox.org/
-------------- next part --------------
--- dlls/wininet_CVS/http.c	Sat Feb  7 15:19:35 2004
+++ dlls/wininet/http.c	Sat Feb  7 15:14:58 2004
@@ -89,13 +89,6 @@
 INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr, LPCSTR lpszField);
 BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQA lpwhr, INT index);
 
-inline static LPSTR HTTP_strdup( LPCSTR str )
-{
-    LPSTR ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
-    if (ret) strcpy( ret, str );
-    return ret;
-}
-
 /***********************************************************************
  *           HttpAddRequestHeadersA (WININET.@)
  *
@@ -131,7 +124,7 @@
       return TRUE;
 
     TRACE("copying header: %s\n", lpszHeader);
-    buffer = HTTP_strdup(lpszHeader);
+    buffer = WININET_strdup(lpszHeader);
     lpszStart = buffer;
 
     do
@@ -252,14 +245,14 @@
 	workRequest.asyncall = HTTPOPENREQUESTA;
 	workRequest.handle = hHttpSession;
         req = &workRequest.u.HttpOpenRequestA;
-	req->lpszVerb = HTTP_strdup(lpszVerb);
-	req->lpszObjectName = HTTP_strdup(lpszObjectName);
+	req->lpszVerb = WININET_strdup(lpszVerb);
+	req->lpszObjectName = WININET_strdup(lpszObjectName);
         if (lpszVersion)
-            req->lpszVersion = HTTP_strdup(lpszVersion);
+            req->lpszVersion = WININET_strdup(lpszVersion);
         else
             req->lpszVersion = 0;
         if (lpszReferrer)
-            req->lpszReferrer = HTTP_strdup(lpszReferrer);
+            req->lpszReferrer = WININET_strdup(lpszReferrer);
         else
             req->lpszReferrer = 0;
 	req->lpszAcceptTypes = lpszAcceptTypes;
@@ -535,7 +528,7 @@
         HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
     lpwhr->lpszPath = url;
     /* FIXME: Do I have to free lpwhs->lpszServerName here ? */
-    lpwhs->lpszServerName = HTTP_strdup(UrlComponents.lpszHostName);
+    lpwhs->lpszServerName = WININET_strdup(UrlComponents.lpszHostName);
     lpwhs->nServerPort = UrlComponents.nPort;
 
     return TRUE;
@@ -622,9 +615,9 @@
     }
 
     if (NULL == lpszVerb)
-        lpwhr->lpszVerb = HTTP_strdup("GET");
+        lpwhr->lpszVerb = WININET_strdup("GET");
     else if (strlen(lpszVerb))
-        lpwhr->lpszVerb = HTTP_strdup(lpszVerb);
+        lpwhr->lpszVerb = WININET_strdup(lpszVerb);
 
     if (NULL != lpszReferrer && strlen(lpszReferrer))
     {
@@ -638,9 +631,9 @@
 
         InternetCrackUrlA(lpszReferrer, 0, 0, &UrlComponents);
         if (strlen(UrlComponents.lpszHostName))
-            lpwhr->lpszHostName = HTTP_strdup(UrlComponents.lpszHostName);
+            lpwhr->lpszHostName = WININET_strdup(UrlComponents.lpszHostName);
     } else {
-        lpwhr->lpszHostName = HTTP_strdup(lpwhs->lpszServerName);
+        lpwhr->lpszHostName = WININET_strdup(lpwhs->lpszServerName);
     }
     if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0)
         HTTP_DealWithProxy( hIC, lpwhs, lpwhr );
@@ -996,7 +989,7 @@
         workRequest.handle = hHttpRequest;
         req = &workRequest.u.HttpSendRequestA;
         if (lpszHeaders)
-            req->lpszHeader = HTTP_strdup(lpszHeaders);
+            req->lpszHeader = WININET_strdup(lpszHeaders);
         else
             req->lpszHeader = 0;
         req->dwHeaderLength = dwHeaderLength;
@@ -1109,15 +1102,15 @@
         
         if (NULL != lpwhs->lpszServerName)
             HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
-        lpwhs->lpszServerName = HTTP_strdup(hostName);
+        lpwhs->lpszServerName = WININET_strdup(hostName);
         if (NULL != lpwhs->lpszUserName)
             HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
-        lpwhs->lpszUserName = HTTP_strdup(userName);
+        lpwhs->lpszUserName = WININET_strdup(userName);
         lpwhs->nServerPort = urlComponents.nPort;
 
         if (NULL != lpwhr->lpszHostName)
             HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
-        lpwhr->lpszHostName=HTTP_strdup(hostName);
+        lpwhr->lpszHostName=WININET_strdup(hostName);
 
         SendAsyncCallback(hIC, lpwhs, lpwhr->hdr.dwContext,
                       INTERNET_STATUS_RESOLVING_NAME,
@@ -1238,7 +1231,7 @@
 
         /* If we don't have a path we set it to root */
         if (NULL == lpwhr->lpszPath)
-            lpwhr->lpszPath = HTTP_strdup("/");
+            lpwhr->lpszPath = WININET_strdup("/");
 
         if(strncmp(lpwhr->lpszPath, "http://", sizeof("http://") -1) != 0
            && lpwhr->lpszPath[0] != '/') /* not an absolute path ?? --> fix it !! */
@@ -1270,7 +1263,7 @@
 	     */
 	    if ((len > 2) && (memcmp(lpszHeaders + (len - 2), "\r\n", 2) == 0))
 	    {
-		lpszHeaders_r_n = HTTP_strdup(lpszHeaders);
+		lpszHeaders_r_n = WININET_strdup(lpszHeaders);
 	    }
 	    else
 	    {
@@ -1617,9 +1610,9 @@
             FIXME("Proxy bypass is ignored.\n");
     }
     if (NULL != lpszServerName)
-        lpwhs->lpszServerName = HTTP_strdup(lpszServerName);
+        lpwhs->lpszServerName = WININET_strdup(lpszServerName);
     if (NULL != lpszUserName)
-        lpwhs->lpszUserName = HTTP_strdup(lpszUserName);
+        lpwhs->lpszUserName = WININET_strdup(lpszUserName);
     lpwhs->nServerPort = nServerPort;
 
     if (hIC->lpfnStatusCB)
@@ -1976,7 +1969,7 @@
 
         if (!lpwhr->StdHeaders[index].lpszField)
         {
-            lphttpHdr->lpszField = HTTP_strdup(field);
+            lphttpHdr->lpszField = WININET_strdup(field);
 
             if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
                 lphttpHdr->wFlags |= HDR_ISREQUEST;
@@ -2237,8 +2230,8 @@
     if (NULL != lph)
     {
 	lpwhr->pCustHeaders = lph;
-        lpwhr->pCustHeaders[count-1].lpszField = HTTP_strdup(lpHdr->lpszField);
-        lpwhr->pCustHeaders[count-1].lpszValue = HTTP_strdup(lpHdr->lpszValue);
+        lpwhr->pCustHeaders[count-1].lpszField = WININET_strdup(lpHdr->lpszField);
+        lpwhr->pCustHeaders[count-1].lpszValue = WININET_strdup(lpHdr->lpszValue);
         lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags;
         lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount;
 	lpwhr->nCustHeaders++;
--- dlls/wininet_CVS/internet.c	Sat Feb  7 08:28:57 2004
+++ dlls/wininet/internet.c	Sat Feb  7 15:14:58 2004
@@ -82,6 +82,8 @@
 } WITHREADERROR, *LPWITHREADERROR;
 
 BOOL WINAPI INTERNET_FindNextFileA(HINTERNET hFind, LPVOID lpvFindData);
+HINTERNET WINAPI INTERNET_InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
+					   LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext);
 VOID INTERNET_ExecuteWork();
 
 DWORD g_dwTlsErrIndex = TLS_OUT_OF_INDEXES;
@@ -1996,81 +1998,142 @@
 
 
 /**********************************************************
- *	InternetOpenUrlA (WININET.@)
+ *	INTERNET_InternetOpenUrlA (internal)
  *
  * Opens an URL
  *
  * RETURNS
  *   handle of connection or NULL on failure
  */
-HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
+HINTERNET WINAPI INTERNET_InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
     LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
 {
-  URL_COMPONENTSA urlComponents;
-  char protocol[32], hostName[MAXHOSTNAME], userName[1024];
-  char password[1024], path[2048], extra[1024];
-  HINTERNET client = NULL, client1 = NULL;
-
-  TRACE("(%p, %s, %s, %08lx, %08lx, %08lx\n", hInternet, debugstr_a(lpszUrl), debugstr_a(lpszHeaders),
-       dwHeadersLength, dwFlags, dwContext);
-
-  urlComponents.dwStructSize = sizeof(URL_COMPONENTSA);
-  urlComponents.lpszScheme = protocol;
-  urlComponents.dwSchemeLength = 32;
-  urlComponents.lpszHostName = hostName;
-  urlComponents.dwHostNameLength = MAXHOSTNAME;
-  urlComponents.lpszUserName = userName;
-  urlComponents.dwUserNameLength = 1024;
-  urlComponents.lpszPassword = password;
-  urlComponents.dwPasswordLength = 1024;
-  urlComponents.lpszUrlPath = path;
-  urlComponents.dwUrlPathLength = 2048;
-  urlComponents.lpszExtraInfo = extra;
-  urlComponents.dwExtraInfoLength = 1024;
-  if(!InternetCrackUrlA(lpszUrl, strlen(lpszUrl), 0, &urlComponents))
-    return NULL;
-  switch(urlComponents.nScheme) {
-  case INTERNET_SCHEME_FTP:
-    if(urlComponents.nPort == 0)
-      urlComponents.nPort = INTERNET_DEFAULT_FTP_PORT;
-    client = InternetConnectA(hInternet, hostName, urlComponents.nPort,
-        userName, password, INTERNET_SERVICE_FTP, dwFlags, dwContext);
-    return FtpOpenFileA(client, path, GENERIC_READ, dwFlags, dwContext);
-  case INTERNET_SCHEME_HTTP:
-  case INTERNET_SCHEME_HTTPS:
-  {
-    LPCSTR accept[2] = { "*/*", NULL };
-    if(urlComponents.nPort == 0) {
-      if(urlComponents.nScheme == INTERNET_SCHEME_HTTP)
-        urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
-      else
-	urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
-    }
-    client = InternetConnectA(hInternet, hostName, urlComponents.nPort, userName,
-        password, INTERNET_SERVICE_HTTP, dwFlags, dwContext);
-    if(client == NULL)
-      return NULL;
-    client1 = HttpOpenRequestA(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
-    if(client1 == NULL) {
-      InternetCloseHandle(client);
-      return NULL;
-    }
-    HttpAddRequestHeadersA(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
-    if((!HttpSendRequestA(client1, NULL, 0, NULL, 0)) && (GetLastError() != ERROR_IO_PENDING)) {
-      InternetCloseHandle(client1);
-      InternetCloseHandle(client);
-      return NULL;
+    URL_COMPONENTSA urlComponents;
+    char protocol[32], hostName[MAXHOSTNAME], userName[1024];
+    char password[1024], path[2048], extra[1024];
+    HINTERNET client = NULL, client1 = NULL;
+    
+    TRACE("(%p, %s, %s, %08lx, %08lx, %08lx\n", hInternet, debugstr_a(lpszUrl), debugstr_a(lpszHeaders),
+	  dwHeadersLength, dwFlags, dwContext);
+    
+    urlComponents.dwStructSize = sizeof(URL_COMPONENTSA);
+    urlComponents.lpszScheme = protocol;
+    urlComponents.dwSchemeLength = 32;
+    urlComponents.lpszHostName = hostName;
+    urlComponents.dwHostNameLength = MAXHOSTNAME;
+    urlComponents.lpszUserName = userName;
+    urlComponents.dwUserNameLength = 1024;
+    urlComponents.lpszPassword = password;
+    urlComponents.dwPasswordLength = 1024;
+    urlComponents.lpszUrlPath = path;
+    urlComponents.dwUrlPathLength = 2048;
+    urlComponents.lpszExtraInfo = extra;
+    urlComponents.dwExtraInfoLength = 1024;
+    if(!InternetCrackUrlA(lpszUrl, strlen(lpszUrl), 0, &urlComponents))
+	return NULL;
+    switch(urlComponents.nScheme) {
+    case INTERNET_SCHEME_FTP:
+	if(urlComponents.nPort == 0)
+	    urlComponents.nPort = INTERNET_DEFAULT_FTP_PORT;
+	client = InternetConnectA(hInternet, hostName, urlComponents.nPort,
+				  userName, password, INTERNET_SERVICE_FTP, dwFlags, dwContext);
+	client1 = FtpOpenFileA(client, path, GENERIC_READ, dwFlags, dwContext);
+	break;
+	
+    case INTERNET_SCHEME_HTTP:
+    case INTERNET_SCHEME_HTTPS: {
+	LPCSTR accept[2] = { "*/*", NULL };
+	if(urlComponents.nPort == 0) {
+	    if(urlComponents.nScheme == INTERNET_SCHEME_HTTP)
+		urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
+	    else
+		urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
+	}
+	client = InternetConnectA(hInternet, hostName, urlComponents.nPort, userName,
+				  password, INTERNET_SERVICE_HTTP, dwFlags, dwContext);
+	if(client == NULL)
+	    break;
+	client1 = HttpOpenRequestA(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
+	if(client1 == NULL) {
+	    InternetCloseHandle(client);
+	    break;
+	}
+	HttpAddRequestHeadersA(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
+	if (!HTTP_HttpSendRequestA(client1, NULL, 0, NULL, 0)) {
+	    InternetCloseHandle(client1);
+	    InternetCloseHandle(client);
+	    client1 = NULL;
+	    break;
+	}
+    }
+    case INTERNET_SCHEME_GOPHER:
+	/* gopher doesn't seem to be implemented in wine, but it's supposed
+	 * to be supported by InternetOpenUrlA. */
+    default:
+	break;
     }
+
+    TRACE(" %p <--\n", client1);
+    
     return client1;
-  }
-  case INTERNET_SCHEME_GOPHER:
-    /* gopher doesn't seem to be implemented in wine, but it's supposed
-     * to be supported by InternetOpenUrlA. */
-  default:
-    return NULL;
-  }
 }
 
+/**********************************************************
+ *	InternetOpenUrlA (WININET.@)
+ *
+ * Opens an URL
+ *
+ * RETURNS
+ *   handle of connection or NULL on failure
+ */
+HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
+    LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
+{
+    HINTERNET ret = NULL;
+    LPWININETAPPINFOA hIC = NULL;
+
+    TRACE("(%p, %s, %s, %08lx, %08lx, %08lx\n", hInternet, debugstr_a(lpszUrl), debugstr_a(lpszHeaders),
+ 	  dwHeadersLength, dwFlags, dwContext);
+ 
+    hIC = (LPWININETAPPINFOA) WININET_GetObject( hInternet );
+    if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT) {
+	INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+ 	goto lend;
+    }
+    
+    if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) {
+	WORKREQUEST workRequest;
+	struct WORKREQ_INTERNETOPENURLA *req;
+	
+	workRequest.asyncall = INTERNETOPENURLA;
+	workRequest.handle = hInternet;
+	req = &workRequest.u.InternetOpenUrlA;
+	if (lpszUrl)
+	    req->lpszUrl = WININET_strdup(lpszUrl);
+	else
+	    req->lpszUrl = 0;
+	if (lpszHeaders)
+	    req->lpszHeaders = WININET_strdup(lpszHeaders);
+	else
+	    req->lpszHeaders = 0;
+	req->dwHeadersLength = dwHeadersLength;
+	req->dwFlags = dwFlags;
+	req->dwContext = dwContext;
+	
+	INTERNET_AsyncCall(&workRequest);
+	/*
+	 * This is from windows.
+	 */
+	SetLastError(ERROR_IO_PENDING);
+    } else {
+	ret = INTERNET_InternetOpenUrlA(hInternet, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext);
+    }
+    
+  lend:
+    TRACE(" %p <--\n", ret);
+    
+    return ret;
+}
 
 /**********************************************************
  *	InternetOpenUrlW (WININET.@)
@@ -2470,6 +2533,17 @@
                 req->dwStatusInfoLength);
         }
         break;
+
+    case INTERNETOPENURLA:
+	{
+	struct WORKREQ_INTERNETOPENURLA *req = &workRequest.u.InternetOpenUrlA;
+	
+	INTERNET_InternetOpenUrlA(workRequest.handle, req->lpszUrl,
+				  req->lpszHeaders, req->dwHeadersLength, req->dwFlags, req->dwContext);
+	HeapFree(GetProcessHeap(), 0, req->lpszUrl);
+	HeapFree(GetProcessHeap(), 0, req->lpszHeaders);
+	}
+	break;
     }
 }
 
--- dlls/wininet_CVS/internet.h	Sat Feb  7 08:28:57 2004
+++ dlls/wininet/internet.h	Sat Feb  7 15:14:58 2004
@@ -54,6 +54,13 @@
 #endif
 } WININET_NETCONNECTION;
 
+inline static LPSTR WININET_strdup( LPCSTR str )
+{
+    LPSTR ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
+    if (ret) strcpy( ret, str );
+    return ret;
+}
+
 typedef enum
 {
     WH_HINIT = INTERNET_HANDLE_TYPE_INTERNET,
@@ -181,6 +188,7 @@
     HTTPSENDREQUESTA,
     HTTPOPENREQUESTA,
     SENDCALLBACK,
+    INTERNETOPENURLA,
 } ASYNC_FUNC;
 
 struct WORKREQ_FTPPUTFILEA
@@ -282,6 +290,16 @@
     DWORD     dwStatusInfoLength;
 };
 
+struct WORKREQ_INTERNETOPENURLA
+{
+    HINTERNET hInternet;
+    LPSTR     lpszUrl;
+    LPSTR     lpszHeaders;
+    DWORD     dwHeadersLength;
+    DWORD     dwFlags;
+    DWORD     dwContext;
+};
+
 typedef struct WORKREQ
 {
     ASYNC_FUNC asyncall;
@@ -302,6 +320,7 @@
         struct WORKREQ_HTTPOPENREQUESTA         HttpOpenRequestA;
         struct WORKREQ_HTTPSENDREQUESTA         HttpSendRequestA;
         struct WORKREQ_SENDCALLBACK             SendCallback;
+	struct WORKREQ_INTERNETOPENURLA         InternetOpenUrlA;
     } u;
 
     struct WORKREQ *next;


More information about the wine-patches mailing list