Implemented proper asynchronous InternetOpenUrl handling.

This commit is contained in:
Lionel Ulmer 2004-02-09 21:45:38 +00:00 committed by Alexandre Julliard
parent f9ce2138d3
commit e0e314780a
3 changed files with 175 additions and 89 deletions

View File

@ -89,13 +89,6 @@ BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr);
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 @@ BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest,
return TRUE;
TRACE("copying header: %s\n", lpszHeader);
buffer = HTTP_strdup(lpszHeader);
buffer = WININET_strdup(lpszHeader);
lpszStart = buffer;
do
@ -252,14 +245,14 @@ HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
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 @@ static BOOL HTTP_DealWithProxy( LPWININETAPPINFOA hIC,
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 @@ HINTERNET WINAPI HTTP_HttpOpenRequestA(HINTERNET hHttpSession,
}
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 @@ HINTERNET WINAPI HTTP_HttpOpenRequestA(HINTERNET hHttpSession,
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 @@ BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
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 @@ static BOOL HTTP_HandleRedirect(LPWININETHTTPREQA lpwhr, LPCSTR lpszUrl, LPCSTR
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 @@ BOOL WINAPI HTTP_HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
/* 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 @@ BOOL WINAPI HTTP_HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
*/
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 @@ HINTERNET HTTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
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 @@ BOOL HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr, LPCSTR field, LPCSTR value, DWO
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 @@ BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr)
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++;

View File

@ -82,6 +82,8 @@ typedef struct
} 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;
@ -1995,6 +1997,87 @@ BOOL WINAPI InternetCheckConnectionW(LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwRes
}
/**********************************************************
* INTERNET_InternetOpenUrlA (internal)
*
* Opens an URL
*
* RETURNS
* handle of connection or NULL on failure
*/
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);
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;
}
/**********************************************************
* InternetOpenUrlA (WININET.@)
*
@ -2006,72 +2089,52 @@ BOOL WINAPI InternetCheckConnectionW(LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwRes
HINTERNET WINAPI 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;
HINTERNET ret = NULL;
LPWININETAPPINFOA hIC = NULL;
TRACE("(%p, %s, %s, %08lx, %08lx, %08lx\n", hInternet, debugstr_a(lpszUrl), debugstr_a(lpszHeaders),
dwHeadersLength, dwFlags, dwContext);
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;
hIC = (LPWININETAPPINFOA) WININET_GetObject( hInternet );
if (NULL == hIC || hIC->hdr.htype != WH_HINIT) {
INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
goto lend;
}
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;
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);
}
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;
}
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;
}
lend:
TRACE(" %p <--\n", ret);
return ret;
}
/**********************************************************
* InternetOpenUrlW (WININET.@)
*
@ -2470,6 +2533,17 @@ VOID INTERNET_ExecuteWork()
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;
}
}

View File

@ -54,6 +54,13 @@ typedef struct
#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 @@ typedef enum
HTTPSENDREQUESTA,
HTTPOPENREQUESTA,
SENDCALLBACK,
INTERNETOPENURLA,
} ASYNC_FUNC;
struct WORKREQ_FTPPUTFILEA
@ -282,6 +290,16 @@ struct WORKREQ_SENDCALLBACK
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 @@ typedef struct WORKREQ
struct WORKREQ_HTTPOPENREQUESTA HttpOpenRequestA;
struct WORKREQ_HTTPSENDREQUESTA HttpSendRequestA;
struct WORKREQ_SENDCALLBACK SendCallback;
struct WORKREQ_INTERNETOPENURLA InternetOpenUrlA;
} u;
struct WORKREQ *next;