Index: dll/win32/wininet/CMakeLists.txt =================================================================== --- dll/win32/wininet/CMakeLists.txt (revision 56722) +++ dll/win32/wininet/CMakeLists.txt (working copy) @@ -4,6 +4,9 @@ -D_WINE -Dclose=_close) +remove_definitions(-D_WIN32_WINNT=0x502) +add_definitions(-D_WIN32_WINNT=0x600) + include_directories(${REACTOS_SOURCE_DIR}/include/reactos/wine) include_directories(${REACTOS_SOURCE_DIR}/lib/3rdparty/zlib) @@ -30,7 +33,7 @@ set_module_type(wininet win32dll) target_link_libraries(wininet wine ${PSEH_LIB} zlib) -add_delay_importlibs(wininet secur32 crypt32) +add_delay_importlibs(wininet secur32 crypt32 cryptui) add_importlibs(wininet mpr shlwapi shell32 user32 advapi32 ws2_32 msvcrt kernel32 ntdll) add_cd_file(TARGET wininet DESTINATION reactos/system32 FOR all) Index: dll/win32/wininet/cookie.c =================================================================== --- dll/win32/wininet/cookie.c (revision 56722) +++ dll/win32/wininet/cookie.c (working copy) @@ -132,14 +132,14 @@ /* removes a cookie from the list, if its the last cookie we also remove the domain */ static void COOKIE_deleteCookie(cookie *deadCookie, BOOL deleteDomain) { - HeapFree(GetProcessHeap(), 0, deadCookie->lpCookieName); - HeapFree(GetProcessHeap(), 0, deadCookie->lpCookieData); + heap_free(deadCookie->lpCookieName); + heap_free(deadCookie->lpCookieData); list_remove(&deadCookie->entry); /* special case: last cookie, lets remove the domain to save memory */ if (list_empty(&deadCookie->parent->cookie_list) && deleteDomain) COOKIE_deleteDomain(deadCookie->parent); - HeapFree(GetProcessHeap(), 0, deadCookie); + heap_free(deadCookie); } /* allocates a domain and adds it to the end */ @@ -251,13 +251,12 @@ COOKIE_deleteCookie(LIST_ENTRY(cursor, cookie, entry), FALSE); list_remove(cursor); } + heap_free(deadDomain->lpCookieDomain); + heap_free(deadDomain->lpCookiePath); - HeapFree(GetProcessHeap(), 0, deadDomain->lpCookieDomain); - HeapFree(GetProcessHeap(), 0, deadDomain->lpCookiePath); - list_remove(&deadDomain->entry); - HeapFree(GetProcessHeap(), 0, deadDomain); + heap_free(deadDomain); } BOOL get_cookie(const WCHAR *host, const WCHAR *path, WCHAR *cookie_data, DWORD *size) @@ -406,11 +405,9 @@ lpCookieData, *lpdwSize, NULL, NULL ); } } - - HeapFree( GetProcessHeap(), 0, szCookieData ); - HeapFree( GetProcessHeap(), 0, name ); - HeapFree( GetProcessHeap(), 0, url ); - + heap_free( szCookieData ); + heap_free( name ); + heap_free( url ); return r; } @@ -447,12 +444,11 @@ if (!(ptr = strchrW(ptr,';'))) break; *ptr++ = 0; - if (value != data) - HeapFree(GetProcessHeap(), 0, value); + if (value != data) heap_free(value); value = heap_alloc((ptr - data) * sizeof(WCHAR)); if (value == NULL) { - HeapFree(GetProcessHeap(), 0, data); + heap_free(data); ERR("could not allocate the cookie value buffer\n"); return FALSE; } @@ -521,8 +517,8 @@ thisCookieDomain = COOKIE_addDomain(domain, path); else { - HeapFree(GetProcessHeap(),0,data); - if (value != data) HeapFree(GetProcessHeap(), 0, value); + heap_free(data); + if (value != data) heap_free(value); return TRUE; } } @@ -535,13 +531,12 @@ if (!expired && !COOKIE_addCookie(thisCookieDomain, cookie_name, value, expiry)) { - HeapFree(GetProcessHeap(),0,data); - if (value != data) HeapFree(GetProcessHeap(), 0, value); + heap_free(data); + if (value != data) heap_free(value); return FALSE; } - - HeapFree(GetProcessHeap(),0,data); - if (value != data) HeapFree(GetProcessHeap(), 0, value); + heap_free(data); + if (value != data) heap_free(value); return TRUE; } @@ -559,7 +554,7 @@ LPCWSTR lpCookieData) { BOOL ret; - WCHAR hostName[2048], path[2048]; + WCHAR hostName[INTERNET_MAX_HOST_NAME_LENGTH], path[INTERNET_MAX_PATH_LENGTH]; TRACE("(%s,%s,%s)\n", debugstr_w(lpszUrl), debugstr_w(lpszCookieName), debugstr_w(lpCookieData)); @@ -593,7 +588,7 @@ ret = set_cookie(hostName, path, cookie, data); - HeapFree(GetProcessHeap(), 0, cookie); + heap_free(cookie); return ret; } return set_cookie(hostName, path, lpszCookieName, lpCookieData); @@ -625,10 +620,9 @@ r = InternetSetCookieW( url, name, data ); - HeapFree( GetProcessHeap(), 0, data ); - HeapFree( GetProcessHeap(), 0, name ); - HeapFree( GetProcessHeap(), 0, url ); - + heap_free( data ); + heap_free( name ); + heap_free( url ); return r; } Index: dll/win32/wininet/dialogs.c =================================================================== --- dll/win32/wininet/dialogs.c (revision 56722) +++ dll/win32/wininet/dialogs.c (working copy) @@ -50,81 +50,14 @@ struct WININET_ErrorDlgParams { + http_request_t *req; HWND hWnd; - HINTERNET hRequest; DWORD dwError; DWORD dwFlags; LPVOID* lppvData; }; /*********************************************************************** - * WININET_GetProxyServer - * - * Determine the name of the proxy server the request is using - */ -static BOOL WININET_GetProxyServer( HINTERNET hRequest, LPWSTR szBuf, DWORD sz ) -{ - http_request_t *request; - http_session_t *session = NULL; - appinfo_t *hIC = NULL; - BOOL ret = FALSE; - LPWSTR p; - - request = (http_request_t*) get_handle_object( hRequest ); - if (NULL == request) - return FALSE; - - session = request->session; - if (NULL == session) - goto done; - - hIC = session->appInfo; - if (NULL == hIC) - goto done; - - lstrcpynW(szBuf, hIC->proxy, sz); - - /* FIXME: perhaps it would be better to use InternetCrackUrl here */ - p = strchrW(szBuf, ':'); - if (p) - *p = 0; - - ret = TRUE; - -done: - WININET_Release( &request->hdr ); - return ret; -} - -/*********************************************************************** - * WININET_GetServer - * - * Determine the name of the web server - */ -static BOOL WININET_GetServer( HINTERNET hRequest, LPWSTR szBuf, DWORD sz ) -{ - http_request_t *request; - http_session_t *session = NULL; - BOOL ret = FALSE; - - request = (http_request_t*) get_handle_object( hRequest ); - if (NULL == request) - return FALSE; - - session = request->session; - if (NULL == session) - goto done; - - lstrcpynW(szBuf, session->hostName, sz); - - ret = TRUE; - -done: - WININET_Release( &request->hdr ); - return ret; -} - -/*********************************************************************** * WININET_GetAuthRealm * * Determine the name of the (basic) Authentication realm @@ -170,6 +103,10 @@ return TRUE; } +/* These two are not defined in the public headers */ +extern DWORD WINAPI WNetCachePassword(LPSTR,WORD,LPSTR,WORD,BYTE,WORD); +extern DWORD WINAPI WNetGetCachedPassword(LPSTR,WORD,LPSTR,LPWORD,BYTE); + /*********************************************************************** * WININET_GetSetPassword */ @@ -238,60 +175,43 @@ /*********************************************************************** * WININET_SetAuthorization */ -static BOOL WININET_SetAuthorization( HINTERNET hRequest, LPWSTR username, +static BOOL WININET_SetAuthorization( http_request_t *request, LPWSTR username, LPWSTR password, BOOL proxy ) { - http_request_t *request; - http_session_t *session; - BOOL ret = FALSE; + http_session_t *session = request->session; LPWSTR p, q; - request = (http_request_t*) get_handle_object( hRequest ); - if( !request ) - return FALSE; - - session = request->session; - if (NULL == session || session->hdr.htype != WH_HHTTPSESSION) - { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - goto done; - } - p = heap_strdupW(username); if( !p ) - goto done; + return FALSE; q = heap_strdupW(password); if( !q ) { - HeapFree(GetProcessHeap(), 0, username); - goto done; + heap_free(username); + return FALSE; } if (proxy) { appinfo_t *hIC = session->appInfo; - HeapFree(GetProcessHeap(), 0, hIC->proxyUsername); + heap_free(hIC->proxyUsername); hIC->proxyUsername = p; - HeapFree(GetProcessHeap(), 0, hIC->proxyPassword); + heap_free(hIC->proxyPassword); hIC->proxyPassword = q; } else { - HeapFree(GetProcessHeap(), 0, session->userName); + heap_free(session->userName); session->userName = p; - HeapFree(GetProcessHeap(), 0, session->password); + heap_free(session->password); session->password = q; } - ret = TRUE; - -done: - WININET_Release( &request->hdr ); - return ret; + return TRUE; } /*********************************************************************** @@ -313,20 +233,15 @@ SetWindowLongPtrW( hdlg, GWLP_USERDATA, lParam ); /* extract the Realm from the proxy response and show it */ - if( WININET_GetAuthRealm( params->hRequest, + if( WININET_GetAuthRealm( params->req->hdr.hInternet, szRealm, sizeof szRealm/sizeof(WCHAR), TRUE ) ) { hitem = GetDlgItem( hdlg, IDC_REALM ); SetWindowTextW( hitem, szRealm ); } - /* extract the name of the proxy server */ - if( WININET_GetProxyServer( params->hRequest, - szServer, sizeof szServer/sizeof(WCHAR)) ) - { - hitem = GetDlgItem( hdlg, IDC_PROXY ); - SetWindowTextW( hitem, szServer ); - } + hitem = GetDlgItem( hdlg, IDC_PROXY ); + SetWindowTextW( hitem, params->req->session->appInfo->proxy ); WININET_GetSetPassword( hdlg, szServer, szRealm, FALSE ); @@ -356,14 +271,10 @@ hitem = GetDlgItem( hdlg, IDC_SAVEPASSWORD ); if( hitem && SendMessageW( hitem, BM_GETSTATE, 0, 0 ) && - WININET_GetAuthRealm( params->hRequest, - szRealm, sizeof szRealm/sizeof(WCHAR), TRUE ) && - WININET_GetProxyServer( params->hRequest, - szServer, sizeof szServer/sizeof(WCHAR)) ) - { - WININET_GetSetPassword( hdlg, szServer, szRealm, TRUE ); - } - WININET_SetAuthorization( params->hRequest, username, password, TRUE ); + WININET_GetAuthRealm( params->req->hdr.hInternet, + szRealm, sizeof szRealm/sizeof(WCHAR), TRUE) ) + WININET_GetSetPassword( hdlg, params->req->session->appInfo->proxy, szRealm, TRUE ); + WININET_SetAuthorization( params->req, username, password, TRUE ); EndDialog( hdlg, ERROR_INTERNET_FORCE_RETRY ); return TRUE; @@ -397,20 +308,15 @@ SetWindowLongPtrW( hdlg, GWLP_USERDATA, lParam ); /* extract the Realm from the response and show it */ - if( WININET_GetAuthRealm( params->hRequest, + if( WININET_GetAuthRealm( params->req->hdr.hInternet, szRealm, sizeof szRealm/sizeof(WCHAR), FALSE ) ) { hitem = GetDlgItem( hdlg, IDC_REALM ); SetWindowTextW( hitem, szRealm ); } - /* extract the name of the server */ - if( WININET_GetServer( params->hRequest, - szServer, sizeof szServer/sizeof(WCHAR)) ) - { - hitem = GetDlgItem( hdlg, IDC_SERVER ); - SetWindowTextW( hitem, szServer ); - } + hitem = GetDlgItem( hdlg, IDC_SERVER ); + SetWindowTextW( hitem, params->req->session->hostName ); WININET_GetSetPassword( hdlg, szServer, szRealm, FALSE ); @@ -440,14 +346,12 @@ hitem = GetDlgItem( hdlg, IDC_SAVEPASSWORD ); if( hitem && SendMessageW( hitem, BM_GETSTATE, 0, 0 ) && - WININET_GetAuthRealm( params->hRequest, - szRealm, sizeof szRealm/sizeof(WCHAR), FALSE ) && - WININET_GetServer( params->hRequest, - szServer, sizeof szServer/sizeof(WCHAR)) ) + WININET_GetAuthRealm( params->req->hdr.hInternet, + szRealm, sizeof szRealm/sizeof(WCHAR), FALSE )) { - WININET_GetSetPassword( hdlg, szServer, szRealm, TRUE ); + WININET_GetSetPassword( hdlg, params->req->session->hostName, szRealm, TRUE ); } - WININET_SetAuthorization( params->hRequest, username, password, FALSE ); + WININET_SetAuthorization( params->req, username, password, FALSE ); EndDialog( hdlg, ERROR_INTERNET_FORCE_RETRY ); return TRUE; @@ -520,9 +424,10 @@ if( params->dwFlags & FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS ) { + http_request_t *req = params->req; DWORD flags, size = sizeof(flags); - InternetQueryOptionW( params->hRequest, INTERNET_OPTION_SECURITY_FLAGS, &flags, &size ); + InternetQueryOptionW( req->hdr.hInternet, INTERNET_OPTION_SECURITY_FLAGS, &flags, &size ); switch( params->dwError ) { case ERROR_INTERNET_INVALID_CA: @@ -534,19 +439,25 @@ case ERROR_INTERNET_SEC_CERT_CN_INVALID: flags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID; break; + case ERROR_INTERNET_SEC_CERT_REV_FAILED: + flags |= SECURITY_FLAG_IGNORE_REVOCATION; + break; case ERROR_INTERNET_SEC_CERT_ERRORS: - FIXME("Should only add ignore flags as needed.\n"); - flags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID | - SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | - SECURITY_FLAG_IGNORE_UNKNOWN_CA; - /* FIXME: ERROR_INTERNET_SEC_CERT_ERRORS also - * seems to set the corresponding DLG_* flags. - */ + if(flags & _SECURITY_FLAG_CERT_REV_FAILED) + flags |= SECURITY_FLAG_IGNORE_REVOCATION; + if(flags & _SECURITY_FLAG_CERT_INVALID_CA) + flags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA; + if(flags & _SECURITY_FLAG_CERT_INVALID_CN) + flags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID; + if(flags & _SECURITY_FLAG_CERT_INVALID_DATE) + flags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID; break; } - res = InternetSetOptionW( params->hRequest, INTERNET_OPTION_SECURITY_FLAGS, &flags, size ); - if(!res) - WARN("InternetSetOption(INTERNET_OPTION_SECURITY_FLAGS) failed.\n"); + /* FIXME: Use helper function */ + flags |= SECURITY_FLAG_SECURE; + req->security_flags |= flags; + if(req->netconn) + req->netconn->security_flags |= flags; } EndDialog( hdlg, res ? ERROR_SUCCESS : ERROR_NOT_SUPPORTED ); @@ -566,44 +477,30 @@ } /*********************************************************************** - * WININET_GetConnectionStatus - */ -static INT WININET_GetConnectionStatus( HINTERNET hRequest ) -{ - WCHAR szStatus[0x20]; - DWORD sz, index, dwStatus; - - TRACE("%p\n", hRequest ); - - sz = sizeof szStatus; - index = 0; - if( !HttpQueryInfoW( hRequest, HTTP_QUERY_STATUS_CODE, - szStatus, &sz, &index)) - return -1; - dwStatus = atoiW( szStatus ); - - TRACE("request %p status = %d\n", hRequest, dwStatus ); - - return dwStatus; -} - - -/*********************************************************************** * InternetErrorDlg */ DWORD WINAPI InternetErrorDlg(HWND hWnd, HINTERNET hRequest, DWORD dwError, DWORD dwFlags, LPVOID* lppvData) { struct WININET_ErrorDlgParams params; - INT dwStatus; + http_request_t *req = NULL; + DWORD res = ERROR_SUCCESS; TRACE("%p %p %d %08x %p\n", hWnd, hRequest, dwError, dwFlags, lppvData); if( !hWnd && !(dwFlags & FLAGS_ERROR_UI_FLAGS_NO_UI) ) return ERROR_INVALID_HANDLE; + if(hRequest) { + req = (http_request_t*)get_handle_object(hRequest); + if(!req) + return ERROR_INVALID_HANDLE; + if(req->hdr.htype != WH_HHTTPREQ) + return ERROR_SUCCESS; /* Yes, that was tested */ + } + + params.req = req; params.hWnd = hWnd; - params.hRequest = hRequest; params.dwError = dwError; params.dwFlags = dwFlags; params.lppvData = lppvData; @@ -611,40 +508,55 @@ switch( dwError ) { case ERROR_SUCCESS: - case ERROR_INTERNET_INCORRECT_PASSWORD: + case ERROR_INTERNET_INCORRECT_PASSWORD: { if( !dwError && !(dwFlags & FLAGS_ERROR_UI_FILTER_FOR_ERRORS ) ) - return 0; + break; + if(!req) + return ERROR_INVALID_HANDLE; - dwStatus = WININET_GetConnectionStatus( hRequest ); - switch (dwStatus) - { + switch(req->status_code) { case HTTP_STATUS_PROXY_AUTH_REQ: - return DialogBoxParamW( WININET_hModule, MAKEINTRESOURCEW( IDD_PROXYDLG ), - hWnd, WININET_ProxyPasswordDialog, (LPARAM) ¶ms ); + res = DialogBoxParamW( WININET_hModule, MAKEINTRESOURCEW( IDD_PROXYDLG ), + hWnd, WININET_ProxyPasswordDialog, (LPARAM) ¶ms ); + break; case HTTP_STATUS_DENIED: - return DialogBoxParamW( WININET_hModule, MAKEINTRESOURCEW( IDD_AUTHDLG ), + res = DialogBoxParamW( WININET_hModule, MAKEINTRESOURCEW( IDD_AUTHDLG ), hWnd, WININET_PasswordDialog, (LPARAM) ¶ms ); + break; default: - WARN("unhandled status %u\n", dwStatus); - return 0; + WARN("unhandled status %u\n", req->status_code); } + break; + } case ERROR_INTERNET_SEC_CERT_ERRORS: case ERROR_INTERNET_SEC_CERT_CN_INVALID: case ERROR_INTERNET_SEC_CERT_DATE_INVALID: case ERROR_INTERNET_INVALID_CA: - if( dwFlags & FLAGS_ERROR_UI_FLAGS_NO_UI ) - return ERROR_CANCELLED; + case ERROR_INTERNET_SEC_CERT_REV_FAILED: + if( dwFlags & FLAGS_ERROR_UI_FLAGS_NO_UI ) { + res = ERROR_CANCELLED; + break; + } + if(!req) + return ERROR_INVALID_HANDLE; + if( dwFlags & ~FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS ) FIXME("%08x contains unsupported flags.\n", dwFlags); - return DialogBoxParamW( WININET_hModule, MAKEINTRESOURCEW( IDD_INVCERTDLG ), - hWnd, WININET_InvalidCertificateDialog, (LPARAM) ¶ms ); + res = DialogBoxParamW( WININET_hModule, MAKEINTRESOURCEW( IDD_INVCERTDLG ), + hWnd, WININET_InvalidCertificateDialog, (LPARAM) ¶ms ); + break; case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR: case ERROR_INTERNET_POST_IS_NON_SECURE: FIXME("Need to display dialog for error %d\n", dwError); - return ERROR_SUCCESS; + res = ERROR_SUCCESS; + break; + default: + res = ERROR_NOT_SUPPORTED; } - return ERROR_NOT_SUPPORTED; + if(req) + WININET_Release(&req->hdr); + return res; } Index: dll/win32/wininet/ftp.c =================================================================== --- dll/win32/wininet/ftp.c (revision 56722) +++ dll/win32/wininet/ftp.c (working copy) @@ -246,8 +246,8 @@ lpwzNewRemoteFile = heap_strdupAtoW(lpszNewRemoteFile); ret = FtpPutFileW(hConnect, lpwzLocalFile, lpwzNewRemoteFile, dwFlags, dwContext); - HeapFree(GetProcessHeap(), 0, lpwzLocalFile); - HeapFree(GetProcessHeap(), 0, lpwzNewRemoteFile); + heap_free(lpwzLocalFile); + heap_free(lpwzNewRemoteFile); return ret; } @@ -261,8 +261,8 @@ FTP_FtpPutFileW(lpwfs, req->lpszLocalFile, req->lpszNewRemoteFile, req->dwFlags, req->dwContext); - HeapFree(GetProcessHeap(), 0, req->lpszLocalFile); - HeapFree(GetProcessHeap(), 0, req->lpszNewRemoteFile); + heap_free(req->lpszLocalFile); + heap_free(req->lpszNewRemoteFile); } /*********************************************************************** @@ -432,7 +432,7 @@ lpwzDirectory = heap_strdupAtoW(lpszDirectory); ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory); - HeapFree(GetProcessHeap(), 0, lpwzDirectory); + heap_free(lpwzDirectory); return ret; } @@ -445,7 +445,7 @@ TRACE("%p\n", lpwfs); FTP_FtpSetCurrentDirectoryW(lpwfs, req->lpszDirectory); - HeapFree(GetProcessHeap(), 0, req->lpszDirectory); + heap_free(req->lpszDirectory); } /*********************************************************************** @@ -578,7 +578,7 @@ lpwzDirectory = heap_strdupAtoW(lpszDirectory); ret = FtpCreateDirectoryW(hConnect, lpwzDirectory); - HeapFree(GetProcessHeap(), 0, lpwzDirectory); + heap_free(lpwzDirectory); return ret; } @@ -591,7 +591,7 @@ TRACE(" %p\n", lpwfs); FTP_FtpCreateDirectoryW(lpwfs, req->lpszDirectory); - HeapFree(GetProcessHeap(), 0, req->lpszDirectory); + heap_free(req->lpszDirectory); } /*********************************************************************** @@ -728,7 +728,7 @@ lpwzSearchFile = heap_strdupAtoW(lpszSearchFile); lpFindFileDataW = lpFindFileData?&wfd:NULL; ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext); - HeapFree(GetProcessHeap(), 0, lpwzSearchFile); + heap_free(lpwzSearchFile); if (ret && lpFindFileData) WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData); @@ -746,7 +746,7 @@ FTP_FtpFindFirstFileW(lpwfs, req->lpszSearchFile, req->lpFindFileData, req->dwFlags, req->dwContext); - HeapFree(GetProcessHeap(), 0, req->lpszSearchFile); + heap_free(req->lpszSearchFile); } /*********************************************************************** @@ -930,7 +930,7 @@ WideCharToMultiByte(CP_ACP, 0, dir, -1, lpszCurrentDirectory, len, NULL, NULL); if (lpdwCurrentDirectory) *lpdwCurrentDirectory = len; - HeapFree(GetProcessHeap(), 0, dir); + heap_free(dir); return ret; } @@ -1076,7 +1076,7 @@ } else INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); - HeapFree(GetProcessHeap(), 0, lpszResponseBuffer); + heap_free(lpszResponseBuffer); } else FTP_SetResponseError(nResCode); @@ -1115,7 +1115,7 @@ if (lpwh->cache_file_handle != INVALID_HANDLE_VALUE) CloseHandle(lpwh->cache_file_handle); - HeapFree(GetProcessHeap(), 0, lpwh->cache_file); + heap_free(lpwh->cache_file); if (!lpwh->session_deleted) lpwfs->download_in_progress = NULL; @@ -1297,7 +1297,7 @@ FTPFILE_Destroy, NULL, FTPFILE_QueryOption, - NULL, + INET_SetOption, FTPFILE_ReadFile, FTPFILE_ReadFileExA, FTPFILE_ReadFileExW, @@ -1393,13 +1393,13 @@ if (lpwh->cache_file_handle == INVALID_HANDLE_VALUE) { WARN("Could not create cache file: %u\n", GetLastError()); - HeapFree(GetProcessHeap(), 0, lpwh->cache_file); + heap_free(lpwh->cache_file); lpwh->cache_file = NULL; } } - HeapFree(GetProcessHeap(), 0, url); + heap_free(url); } - HeapFree(GetProcessHeap(), 0, uc.lpszUrlPath); + heap_free(uc.lpszUrlPath); } hIC = lpwfs->lpAppInfo; @@ -1425,11 +1425,8 @@ } } - if(!bSuccess) { - if(lpwh) - WININET_Release( &lpwh->hdr ); + if(!bSuccess) return FALSE; - } return lpwh->hdr.hInternet; } @@ -1454,7 +1451,7 @@ lpwzFileName = heap_strdupAtoW(lpszFileName); ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext); - HeapFree(GetProcessHeap(), 0, lpwzFileName); + heap_free(lpwzFileName); return ret; } @@ -1468,7 +1465,7 @@ FTP_FtpOpenFileW(lpwfs, req->lpszFilename, req->dwAccess, req->dwFlags, req->dwContext); - HeapFree(GetProcessHeap(), 0, req->lpszFilename); + heap_free(req->lpszFilename); } /*********************************************************************** @@ -1570,8 +1567,8 @@ lpwzNewFile = heap_strdupAtoW(lpszNewFile); ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext); - HeapFree(GetProcessHeap(), 0, lpwzRemoteFile); - HeapFree(GetProcessHeap(), 0, lpwzNewFile); + heap_free(lpwzRemoteFile); + heap_free(lpwzNewFile); return ret; } @@ -1586,8 +1583,8 @@ FTP_FtpGetFileW(lpwfs, req->lpszRemoteFile, req->lpszNewFile, req->fFailIfExists, req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext); - HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile); - HeapFree(GetProcessHeap(), 0, req->lpszNewFile); + heap_free(req->lpszRemoteFile); + heap_free(req->lpszNewFile); } @@ -1778,7 +1775,7 @@ lpwzFileName = heap_strdupAtoW(lpszFileName); ret = FtpDeleteFileW(hFtpSession, lpwzFileName); - HeapFree(GetProcessHeap(), 0, lpwzFileName); + heap_free(lpwzFileName); return ret; } @@ -1790,7 +1787,7 @@ TRACE("%p\n", lpwfs); FTP_FtpDeleteFileW(lpwfs, req->lpszFilename); - HeapFree(GetProcessHeap(), 0, req->lpszFilename); + heap_free(req->lpszFilename); } /*********************************************************************** @@ -1923,7 +1920,7 @@ lpwzDirectory = heap_strdupAtoW(lpszDirectory); ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory); - HeapFree(GetProcessHeap(), 0, lpwzDirectory); + heap_free(lpwzDirectory); return ret; } @@ -1935,7 +1932,7 @@ TRACE("%p\n", lpwfs); FTP_FtpRemoveDirectoryW(lpwfs, req->lpszDirectory); - HeapFree(GetProcessHeap(), 0, req->lpszDirectory); + heap_free(req->lpszDirectory); } /*********************************************************************** @@ -2071,8 +2068,8 @@ lpwzSrc = heap_strdupAtoW(lpszSrc); lpwzDest = heap_strdupAtoW(lpszDest); ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest); - HeapFree(GetProcessHeap(), 0, lpwzSrc); - HeapFree(GetProcessHeap(), 0, lpwzDest); + heap_free(lpwzSrc); + heap_free(lpwzDest); return ret; } @@ -2084,8 +2081,8 @@ TRACE("%p\n", lpwfs); FTP_FtpRenameFileW(lpwfs, req->lpszSrcFile, req->lpszDestFile); - HeapFree(GetProcessHeap(), 0, req->lpszSrcFile); - HeapFree(GetProcessHeap(), 0, req->lpszDestFile); + heap_free(req->lpszSrcFile); + heap_free(req->lpszDestFile); } /*********************************************************************** @@ -2239,7 +2236,7 @@ r = FtpCommandW(hConnect, fExpectResponse, dwFlags, cmdW, dwContext, phFtpCommand); - HeapFree(GetProcessHeap(), 0, cmdW); + heap_free(cmdW); return r; } @@ -2323,7 +2320,7 @@ lend: WININET_Release( &lpwfs->hdr ); - HeapFree(GetProcessHeap(), 0, cmd); + heap_free( cmd ); return r; } @@ -2341,9 +2338,9 @@ WININET_Release(&lpwfs->lpAppInfo->hdr); - HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword); - HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName); - HeapFree(GetProcessHeap(), 0, lpwfs->servername); + heap_free(lpwfs->lpszPassword); + heap_free(lpwfs->lpszUserName); + heap_free(lpwfs->servername); } static void FTPSESSION_CloseConnection(object_header_t *hdr) @@ -2392,11 +2389,11 @@ FTPSESSION_Destroy, FTPSESSION_CloseConnection, FTPSESSION_QueryOption, + INET_SetOption, NULL, NULL, NULL, NULL, - NULL, NULL }; @@ -2651,7 +2648,7 @@ int nRC = 0; DWORD dwParamLen; - TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket); + TRACE("%d: (%s) %d\n", ftpCmd, debugstr_a(lpszParam), nSocket); if (lpfnStatusCB) { @@ -2674,9 +2671,8 @@ nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0); nBytesSent += nRC; } + heap_free(buf); - HeapFree(GetProcessHeap(), 0, (LPVOID)buf); - if (lpfnStatusCB) { lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_REQUEST_SENT, @@ -2703,7 +2699,7 @@ BOOL ret; LPSTR lpszParamA = heap_strdupWtoA(lpszParam); ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext); - HeapFree(GetProcessHeap(), 0, lpszParamA); + heap_free(lpszParamA); return ret; } @@ -3279,8 +3275,7 @@ TRACE("file transfer complete!\n"); - HeapFree(GetProcessHeap(), 0, lpszBuffer); - + heap_free(lpszBuffer); return nTotalSent; } @@ -3371,9 +3366,8 @@ TRACE("Data transfer complete\n"); recv_end: - HeapFree(GetProcessHeap(), 0, lpszBuffer); - - return (nRC != -1); + heap_free(lpszBuffer); + return (nRC != -1); } /*********************************************************************** @@ -3392,10 +3386,9 @@ for (i = 0; i < lpwfn->size; i++) { - HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName); + heap_free(lpwfn->lpafp[i].lpszName); } - - HeapFree(GetProcessHeap(), 0, lpwfn->lpafp); + heap_free(lpwfn->lpafp); } static DWORD FTPFINDNEXT_FindNextFileProc(WININETFTPFINDNEXTW *find, LPVOID data) @@ -3481,12 +3474,12 @@ FTPFINDNEXT_Destroy, NULL, FTPFINDNEXT_QueryOption, + INET_SetOption, NULL, NULL, NULL, NULL, NULL, - NULL, FTPFINDNEXT_FindNextFileW }; @@ -3725,7 +3718,7 @@ TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName)); } else { - HeapFree(GetProcessHeap(), 0, lpfp->lpszName); + heap_free(lpfp->lpszName); lpfp->lpszName = NULL; } } @@ -3788,7 +3781,7 @@ } else { - HeapFree(GetProcessHeap(), 0, *lpafp); + heap_free(*lpafp); INTERNET_SetLastError(ERROR_NO_MORE_FILES); bSuccess = FALSE; } Index: dll/win32/wininet/http.c =================================================================== --- dll/win32/wininet/http.c (revision 56722) +++ dll/win32/wininet/http.c (working copy) @@ -1,5 +1,5 @@ /* - * Wininet - Http Implementation + * Wininet - HTTP Implementation * * Copyright 1999 Corel Corporation * Copyright 2002 CodeWeavers Inc. @@ -65,6 +65,8 @@ #include "shlwapi.h" #include "sspi.h" #include "wincrypt.h" +#include "winuser.h" +#include "cryptuiapi.h" #include "internet.h" #include "wine/debug.h" @@ -98,6 +100,7 @@ static const WCHAR szCache_Control[] = { 'C','a','c','h','e','-','C','o','n','t','r','o','l',0 }; static const WCHAR szConnection[] = { 'C','o','n','n','e','c','t','i','o','n',0 }; static const WCHAR szContent_Base[] = { 'C','o','n','t','e','n','t','-','B','a','s','e',0 }; +static const WCHAR szContent_Disposition[] = { 'C','o','n','t','e','n','t','-','D','i','s','p','o','s','i','t','i','o','n',0 }; static const WCHAR szContent_Encoding[] = { 'C','o','n','t','e','n','t','-','E','n','c','o','d','i','n','g',0 }; static const WCHAR szContent_ID[] = { 'C','o','n','t','e','n','t','-','I','D',0 }; static const WCHAR szContent_Language[] = { 'C','o','n','t','e','n','t','-','L','a','n','g','u','a','g','e',0 }; @@ -141,10 +144,6 @@ static const WCHAR szWarning[] = { 'W','a','r','n','i','n','g',0 }; static const WCHAR szWWW_Authenticate[] = { 'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0 }; -#define MAXHOSTNAME 100 -#define MAX_FIELD_VALUE_LEN 256 -#define MAX_FIELD_LEN 256 - #define HTTP_REFERER szReferer #define HTTP_ACCEPT szAccept #define HTTP_USERAGENT szUser_Agent @@ -245,20 +244,15 @@ if(InterlockedDecrement(&server->ref)) return; -#ifndef __REACTOS__ - if(!server->ref) - server->keep_until = (DWORD64)GetTickCount() + COLLECT_TIME; -#else - EnterCriticalSection(&connection_pool_cs); list_remove(&server->entry); - LeaveCriticalSection(&connection_pool_cs); - + + if(server->cert_chain) + CertFreeCertificateChain(server->cert_chain); heap_free(server->name); heap_free(server); -#endif } -static server_t *get_server(const WCHAR *name, INTERNET_PORT port) +server_t *get_server(const WCHAR *name, INTERNET_PORT port, BOOL do_create) { server_t *iter, *server = NULL; @@ -272,11 +266,10 @@ } } - if(!server) { - server = heap_alloc(sizeof(*server)); + if(!server && do_create) { + server = heap_alloc_zero(sizeof(*server)); if(server) { - server->addr_len = 0; - server->ref = 1; + server->ref = 2; /* list reference and return */ server->port = port; list_init(&server->conn_pool); server->name = heap_strdupW(name); @@ -294,18 +287,18 @@ return server; } -BOOL collect_connections(BOOL collect_all) +BOOL collect_connections(collect_type_t collect_type) { netconn_t *netconn, *netconn_safe; server_t *server, *server_safe; BOOL remaining = FALSE; DWORD64 now; - now = GetTickCount(); + now = GetTickCount64(); LIST_FOR_EACH_ENTRY_SAFE(server, server_safe, &connection_pool, server_t, entry) { LIST_FOR_EACH_ENTRY_SAFE(netconn, netconn_safe, &server->conn_pool, netconn_t, pool_entry) { - if(collect_all || netconn->keep_until < now) { + if(collect_type > COLLECT_TIMEOUT || netconn->keep_until < now) { TRACE("freeing %p\n", netconn); list_remove(&netconn->pool_entry); free_netconn(netconn); @@ -314,15 +307,10 @@ } } - if(!server->ref) { - if(collect_all || server->keep_until < now) { - list_remove(&server->entry); - - heap_free(server->name); - heap_free(server); - }else { - remaining = TRUE; - } + if(collect_type == COLLECT_CLEANUP) { + list_remove(&server->entry); + list_init(&server->entry); + server_release(server); } } @@ -339,7 +327,7 @@ EnterCriticalSection(&connection_pool_cs); - remaining_conns = collect_connections(FALSE); + remaining_conns = collect_connections(COLLECT_TIMEOUT); if(!remaining_conns) collector_running = FALSE; @@ -517,7 +505,7 @@ static void wininet_zfree(voidpf opaque, voidpf address) { - HeapFree(GetProcessHeap(), 0, address); + heap_free(address); } static DWORD init_gzip_stream(http_request_t *req) @@ -536,7 +524,7 @@ zres = inflateInit2(&gzip_stream->zstream, 0x1f); if(zres != Z_OK) { ERR("inflateInit failed: %d\n", zres); - HeapFree(GetProcessHeap(), 0, gzip_stream); + heap_free(gzip_stream); return ERROR_OUTOFMEMORY; } @@ -626,9 +614,8 @@ 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); + for (i = 0; token_array[i]; i++) heap_free(token_array[i]); + heap_free(token_array); } static void HTTP_FixURL(http_request_t *request) @@ -661,7 +648,7 @@ WCHAR *fixurl = heap_alloc((strlenW(request->path) + 2)*sizeof(WCHAR)); *fixurl = '/'; strcpyW(fixurl + 1, request->path); - HeapFree( GetProcessHeap(), 0, request->path ); + heap_free( request->path ); request->path = fixurl; } } @@ -711,7 +698,7 @@ req[n] = NULL; requestString = HTTP_build_req( req, 4 ); - HeapFree( GetProcessHeap(), 0, req ); + heap_free( req ); /* * Set (header) termination string for request @@ -827,9 +814,9 @@ if (SecIsValidHandle(&authinfo->cred)) FreeCredentialsHandle(&authinfo->cred); - HeapFree(GetProcessHeap(), 0, authinfo->auth_data); - HeapFree(GetProcessHeap(), 0, authinfo->scheme); - HeapFree(GetProcessHeap(), 0, authinfo); + heap_free(authinfo->auth_data); + heap_free(authinfo->scheme); + heap_free(authinfo); } static UINT retrieve_cached_basic_authorization(LPWSTR host, LPWSTR realm, LPSTR *auth_data) @@ -876,7 +863,7 @@ if (ad) { TRACE("Found match in cache, replacing\n"); - HeapFree(GetProcessHeap(),0,ad->authorization); + heap_free(ad->authorization); ad->authorization = heap_alloc(auth_data_len); memcpy(ad->authorization, auth_data, auth_data_len); ad->authorizationLen = auth_data_len; @@ -885,7 +872,7 @@ { ad = heap_alloc(sizeof(basicAuthorizationData)); ad->host = heap_strdupW(host); - ad->host = heap_strdupW(realm); + ad->realm = heap_strdupW(realm); ad->authorization = heap_alloc(auth_data_len); memcpy(ad->authorization, auth_data, auth_data_len); ad->authorizationLen = auth_data_len; @@ -912,9 +899,9 @@ nt_auth_identity->Domain = heap_alloc(sizeof(WCHAR)*ad->domain_len); if(!nt_auth_identity->User || !nt_auth_identity->Password || (!nt_auth_identity->Domain && ad->domain_len)) { - HeapFree(GetProcessHeap(), 0, nt_auth_identity->User); - HeapFree(GetProcessHeap(), 0, nt_auth_identity->Password); - HeapFree(GetProcessHeap(), 0, nt_auth_identity->Domain); + heap_free(nt_auth_identity->User); + heap_free(nt_auth_identity->Password); + heap_free(nt_auth_identity->Domain); break; } @@ -948,9 +935,9 @@ } if(found) { - HeapFree(GetProcessHeap(), 0, ad->user); - HeapFree(GetProcessHeap(), 0, ad->password); - HeapFree(GetProcessHeap(), 0, ad->domain); + heap_free(ad->user); + heap_free(ad->password); + heap_free(ad->domain); } else { ad = heap_alloc(sizeof(authorizationData)); if(!ad) { @@ -972,13 +959,13 @@ if(!ad->host || !ad->scheme || !ad->user || !ad->password || (nt_auth_identity->Domain && !ad->domain)) { - HeapFree(GetProcessHeap(), 0, ad->host); - HeapFree(GetProcessHeap(), 0, ad->scheme); - HeapFree(GetProcessHeap(), 0, ad->user); - HeapFree(GetProcessHeap(), 0, ad->password); - HeapFree(GetProcessHeap(), 0, ad->domain); + heap_free(ad->host); + heap_free(ad->scheme); + heap_free(ad->user); + heap_free(ad->password); + heap_free(ad->domain); list_remove(&ad->entry); - HeapFree(GetProcessHeap(), 0, ad); + heap_free(ad); } LeaveCriticalSection(&authcache_cs); @@ -1019,7 +1006,7 @@ pAuthInfo->scheme = heap_strdupW(szBasic); if (!pAuthInfo->scheme) { - HeapFree(GetProcessHeap(), 0, pAuthInfo); + heap_free(pAuthInfo); return FALSE; } } @@ -1031,7 +1018,7 @@ pAuthInfo->scheme = heap_strdupW(pszAuthValue); if (!pAuthInfo->scheme) { - HeapFree(GetProcessHeap(), 0, pAuthInfo); + heap_free(pAuthInfo); return FALSE; } @@ -1074,9 +1061,9 @@ &exp); if(pAuthData && !domain_and_username) { - HeapFree(GetProcessHeap(), 0, nt_auth_identity.User); - HeapFree(GetProcessHeap(), 0, nt_auth_identity.Domain); - HeapFree(GetProcessHeap(), 0, nt_auth_identity.Password); + heap_free(nt_auth_identity.User); + heap_free(nt_auth_identity.Domain); + heap_free(nt_auth_identity.Password); } if (sec_status == SEC_E_OK) @@ -1093,8 +1080,8 @@ { WARN("AcquireCredentialsHandleW for scheme %s failed with error 0x%08x\n", debugstr_w(pAuthInfo->scheme), sec_status); - HeapFree(GetProcessHeap(), 0, pAuthInfo->scheme); - HeapFree(GetProcessHeap(), 0, pAuthInfo); + heap_free(pAuthInfo->scheme); + heap_free(pAuthInfo); return FALSE; } } @@ -1126,7 +1113,7 @@ auth_data_len = retrieve_cached_basic_authorization(host, szRealm,&auth_data); if (auth_data_len == 0) { - HeapFree(GetProcessHeap(),0,szRealm); + heap_free(szRealm); return FALSE; } } @@ -1139,7 +1126,7 @@ auth_data = heap_alloc(userlen + 1 + passlen); if (!auth_data) { - HeapFree(GetProcessHeap(),0,szRealm); + heap_free(szRealm); return FALSE; } @@ -1154,8 +1141,7 @@ pAuthInfo->auth_data = auth_data; pAuthInfo->auth_data_len = auth_data_len; pAuthInfo->finished = TRUE; - HeapFree(GetProcessHeap(),0,szRealm); - + heap_free(szRealm); return TRUE; } else @@ -1196,7 +1182,7 @@ sec_status = InitializeSecurityContextW(first ? &pAuthInfo->cred : NULL, first ? NULL : &pAuthInfo->ctx, - first ? request->session->serverName : NULL, + first ? request->server->name : NULL, context_req, 0, SECURITY_NETWORK_DREP, in.pvBuffer ? &in_desc : NULL, 0, &pAuthInfo->ctx, &out_desc, @@ -1217,7 +1203,7 @@ else { ERR("InitializeSecurityContextW returned error 0x%08x\n", sec_status); - HeapFree(GetProcessHeap(), 0, out.pvBuffer); + heap_free(out.pvBuffer); destroy_authinfo(pAuthInfo); *ppAuthInfo = NULL; return FALSE; @@ -1291,8 +1277,7 @@ lpszStart = lpszEnd; } while (res == ERROR_SUCCESS); - HeapFree(GetProcessHeap(), 0, buffer); - + heap_free(buffer); return res; } @@ -1304,7 +1289,7 @@ * NOTE * On Windows if dwHeaderLength includes the trailing '\0', then * HttpAddRequestHeadersW() adds it too. However this results in an - * invalid Http header which is rejected by some servers so we probably + * invalid HTTP header which is rejected by some servers so we probably * don't need to match Windows on that point. * * RETURNS @@ -1361,11 +1346,64 @@ r = HttpAddRequestHeadersW( hHttpRequest, hdr, dwHeaderLength, dwModifier ); - HeapFree( GetProcessHeap(), 0, hdr ); - + heap_free( hdr ); return r; } +static void free_accept_types( WCHAR **accept_types ) +{ + WCHAR *ptr, **types = accept_types; + + if (!types) return; + while ((ptr = *types)) + { + heap_free( ptr ); + types++; + } + heap_free( accept_types ); +} + +static WCHAR **convert_accept_types( const char **accept_types ) +{ + unsigned int count; + const char **types = accept_types; + WCHAR **typesW; + BOOL invalid_pointer = FALSE; + + if (!types) return NULL; + count = 0; + while (*types) + { + __TRY + { + /* find out how many there are */ + if (*types && **types) + { + TRACE("accept type: %s\n", debugstr_a(*types)); + count++; + } + } + __EXCEPT_PAGE_FAULT + { + WARN("invalid accept type pointer\n"); + invalid_pointer = TRUE; + } + __ENDTRY; + types++; + } + if (invalid_pointer) return NULL; + if (!(typesW = heap_alloc( sizeof(WCHAR *) * (count + 1) ))) return NULL; + count = 0; + types = accept_types; + while (*types) + { + if (*types && **types) typesW[count++] = heap_strdupAtoW( *types ); + types++; + } + typesW[count] = NULL; + return typesW; +} + /*********************************************************************** * HttpOpenRequestA (WININET.@) * @@ -1383,9 +1421,7 @@ { LPWSTR szVerb = NULL, szObjectName = NULL; LPWSTR szVersion = NULL, szReferrer = NULL, *szAcceptTypes = NULL; - INT acceptTypesCount; HINTERNET rc = FALSE; - LPCSTR *types; TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession, debugstr_a(lpszVerb), debugstr_a(lpszObjectName), @@ -1420,70 +1456,16 @@ goto end; } - if (lpszAcceptTypes) - { - acceptTypesCount = 0; - types = lpszAcceptTypes; - while (*types) - { - __TRY - { - /* find out how many there are */ - if (*types && **types) - { - TRACE("accept type: %s\n", debugstr_a(*types)); - acceptTypesCount++; - } - } - __EXCEPT_PAGE_FAULT - { - WARN("invalid accept type pointer\n"); - } - __ENDTRY; - types++; - } - szAcceptTypes = heap_alloc(sizeof(WCHAR *) * (acceptTypesCount+1)); - if (!szAcceptTypes) goto end; + szAcceptTypes = convert_accept_types( lpszAcceptTypes ); + rc = HttpOpenRequestW(hHttpSession, szVerb, szObjectName, szVersion, szReferrer, + (const WCHAR **)szAcceptTypes, dwFlags, dwContext); - acceptTypesCount = 0; - types = lpszAcceptTypes; - while (*types) - { - __TRY - { - if (*types && **types) - szAcceptTypes[acceptTypesCount++] = heap_strdupAtoW(*types); - } - __EXCEPT_PAGE_FAULT - { - /* ignore invalid pointer */ - } - __ENDTRY; - types++; - } - szAcceptTypes[acceptTypesCount] = NULL; - } - - rc = HttpOpenRequestW(hHttpSession, szVerb, szObjectName, - szVersion, szReferrer, - (LPCWSTR*)szAcceptTypes, dwFlags, dwContext); - end: - if (szAcceptTypes) - { - acceptTypesCount = 0; - while (szAcceptTypes[acceptTypesCount]) - { - HeapFree(GetProcessHeap(), 0, szAcceptTypes[acceptTypesCount]); - acceptTypesCount++; - } - HeapFree(GetProcessHeap(), 0, szAcceptTypes); - } - HeapFree(GetProcessHeap(), 0, szReferrer); - HeapFree(GetProcessHeap(), 0, szVersion); - HeapFree(GetProcessHeap(), 0, szObjectName); - HeapFree(GetProcessHeap(), 0, szVerb); - + free_accept_types(szAcceptTypes); + heap_free(szReferrer); + heap_free(szVersion); + heap_free(szObjectName); + heap_free(szVerb); return rc; } @@ -1652,7 +1634,7 @@ * connection tracking */ if (strcmpiW(pAuthInfo->scheme, wszBasic)) { - HeapFree(GetProcessHeap(), 0, pAuthInfo->auth_data); + heap_free(pAuthInfo->auth_data); pAuthInfo->auth_data = NULL; pAuthInfo->auth_data_len = 0; } @@ -1661,42 +1643,46 @@ TRACE("Inserting authorization: %s\n", debugstr_w(authorization)); HTTP_ProcessHeader(request, header, authorization, HTTP_ADDHDR_FLAG_REQ | HTTP_ADDHDR_FLAG_REPLACE); - - HeapFree(GetProcessHeap(), 0, authorization); + heap_free(authorization); } return TRUE; } static WCHAR *HTTP_BuildProxyRequestUrl(http_request_t *req) { + static const WCHAR slash[] = { '/',0 }; + static const WCHAR format[] = { 'h','t','t','p',':','/','/','%','s',':','%','u',0 }; + static const WCHAR formatSSL[] = { 'h','t','t','p','s',':','/','/','%','s',':','%','u',0 }; + http_session_t *session = req->session; WCHAR new_location[INTERNET_MAX_URL_LENGTH], *url; DWORD size; size = sizeof(new_location); if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_LOCATION, new_location, &size, NULL) == ERROR_SUCCESS) { + URL_COMPONENTSW UrlComponents; + if (!(url = heap_alloc(size + sizeof(WCHAR)))) return NULL; strcpyW( url, new_location ); + + ZeroMemory(&UrlComponents,sizeof(URL_COMPONENTSW)); + if(InternetCrackUrlW(url, 0, 0, &UrlComponents)) goto done; + heap_free(url); } - else - { - static const WCHAR slash[] = { '/',0 }; - static const WCHAR format[] = { 'h','t','t','p',':','/','/','%','s',':','%','u',0 }; - static const WCHAR formatSSL[] = { 'h','t','t','p','s',':','/','/','%','s',':','%','u',0 }; - http_session_t *session = req->session; - size = 16; /* "https://" + sizeof(port#) + ":/\0" */ - size += strlenW( session->hostName ) + strlenW( req->path ); + size = 16; /* "https://" + sizeof(port#) + ":/\0" */ + size += strlenW( session->hostName ) + strlenW( req->path ); - if (!(url = heap_alloc(size * sizeof(WCHAR)))) return NULL; + if (!(url = heap_alloc(size * sizeof(WCHAR)))) return NULL; - if (req->hdr.dwFlags & INTERNET_FLAG_SECURE) - sprintfW( url, formatSSL, session->hostName, session->hostPort ); - else - sprintfW( url, format, session->hostName, session->hostPort ); - if (req->path[0] != '/') strcatW( url, slash ); - strcatW( url, req->path ); - } + if (req->hdr.dwFlags & INTERNET_FLAG_SECURE) + sprintfW( url, formatSSL, session->hostName, session->hostPort ); + else + sprintfW( url, format, session->hostName, session->hostPort ); + if (req->path[0] != '/') strcatW( url, slash ); + strcatW( url, req->path ); + +done: TRACE("url=%s\n", debugstr_w(url)); return url; } @@ -1706,12 +1692,13 @@ */ static BOOL HTTP_DealWithProxy(appinfo_t *hIC, http_session_t *session, http_request_t *request) { - WCHAR buf[MAXHOSTNAME]; - WCHAR protoProxy[MAXHOSTNAME + 15]; - DWORD protoProxyLen = sizeof(protoProxy) / sizeof(protoProxy[0]); - WCHAR proxy[MAXHOSTNAME + 15]; /* 15 == "http://" + sizeof(port#) + ":/\0" */ + WCHAR buf[INTERNET_MAX_HOST_NAME_LENGTH]; + WCHAR protoProxy[INTERNET_MAX_URL_LENGTH]; + DWORD protoProxyLen = INTERNET_MAX_URL_LENGTH; + WCHAR proxy[INTERNET_MAX_URL_LENGTH]; static WCHAR szNul[] = { 0 }; URL_COMPONENTSW UrlComponents; + server_t *new_server; static const WCHAR protoHttp[] = { 'h','t','t','p',0 }; static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/',0 }; static const WCHAR szFormat[] = { 'h','t','t','p',':','/','/','%','s',0 }; @@ -1719,7 +1706,7 @@ memset( &UrlComponents, 0, sizeof UrlComponents ); UrlComponents.dwStructSize = sizeof UrlComponents; UrlComponents.lpszHostName = buf; - UrlComponents.dwHostNameLength = MAXHOSTNAME; + UrlComponents.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH; if (!INTERNET_FindProxyForProtocol(hIC->proxy, protoHttp, protoProxy, &protoProxyLen)) return FALSE; @@ -1739,16 +1726,20 @@ if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER) UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT; - HeapFree(GetProcessHeap(), 0, session->serverName); - session->serverName = heap_strdupW(UrlComponents.lpszHostName); - session->serverPort = UrlComponents.nPort; + new_server = get_server(UrlComponents.lpszHostName, UrlComponents.nPort, TRUE); + if(!new_server) + return FALSE; - TRACE("proxy server=%s port=%d\n", debugstr_w(session->serverName), session->serverPort); + server_release(request->server); + request->server = new_server; + + TRACE("proxy server=%s port=%d\n", debugstr_w(new_server->name), new_server->port); return TRUE; } -static DWORD HTTP_ResolveName(http_request_t *request, server_t *server) +static DWORD HTTP_ResolveName(http_request_t *request) { + server_t *server = request->server; socklen_t addr_len; const void *addr; @@ -1838,29 +1829,31 @@ request->rawHeaders, headersLen, NULL, 0); } } + heap_free(request->cacheFile); - HeapFree(GetProcessHeap(), 0, request->cacheFile); - + request->read_section.DebugInfo->Spare[0] = 0; DeleteCriticalSection( &request->read_section ); WININET_Release(&request->session->hdr); destroy_authinfo(request->authInfo); destroy_authinfo(request->proxyAuthInfo); - HeapFree(GetProcessHeap(), 0, request->path); - HeapFree(GetProcessHeap(), 0, request->verb); - HeapFree(GetProcessHeap(), 0, request->rawHeaders); - HeapFree(GetProcessHeap(), 0, request->version); - HeapFree(GetProcessHeap(), 0, request->statusText); + if(request->server) + server_release(request->server); + heap_free(request->path); + heap_free(request->verb); + heap_free(request->rawHeaders); + heap_free(request->version); + heap_free(request->statusText); + for (i = 0; i < request->nCustHeaders; i++) { - HeapFree(GetProcessHeap(), 0, request->custHeaders[i].lpszField); - HeapFree(GetProcessHeap(), 0, request->custHeaders[i].lpszValue); + heap_free(request->custHeaders[i].lpszField); + heap_free(request->custHeaders[i].lpszValue); } - destroy_data_stream(request->data_stream); - HeapFree(GetProcessHeap(), 0, request->custHeaders); + heap_free(request->custHeaders); } static void http_release_netconn(http_request_t *req, BOOL reuse) @@ -1877,7 +1870,7 @@ EnterCriticalSection(&connection_pool_cs); list_add_head(&req->netconn->server->conn_pool, &req->netconn->pool_entry); - req->netconn->keep_until = (DWORD64)GetTickCount() + COLLECT_TIME; + req->netconn->keep_until = GetTickCount64() + COLLECT_TIME; req->netconn = NULL; run_collector = !collector_running; @@ -1998,6 +1991,9 @@ return ERROR_SUCCESS; } + case 98: + TRACE("Queried undocumented option 98, forwarding to INTERNET_OPTION_SECURITY_FLAGS\n"); + /* fall through */ case INTERNET_OPTION_SECURITY_FLAGS: { DWORD flags; @@ -2006,20 +2002,10 @@ return ERROR_INSUFFICIENT_BUFFER; *size = sizeof(DWORD); - flags = 0; - if (req->hdr.dwFlags & INTERNET_FLAG_SECURE) - flags |= SECURITY_FLAG_SECURE; - flags |= req->security_flags; - if(req->netconn) { - int bits = NETCON_GetCipherStrength(req->netconn); - if (bits >= 128) - flags |= SECURITY_FLAG_STRENGTH_STRONG; - else if (bits >= 56) - flags |= SECURITY_FLAG_STRENGTH_MEDIUM; - else - flags |= SECURITY_FLAG_STRENGTH_WEAK; - } + flags = req->netconn ? req->netconn->security_flags : req->security_flags | req->server->security_flags; *(DWORD *)buffer = flags; + + TRACE("INTERNET_OPTION_SECURITY_FLAGS %x\n", flags); return ERROR_SUCCESS; } @@ -2098,7 +2084,7 @@ ts->ftExpires = info->ExpireTime; ts->ftLastModified = info->LastModifiedTime; - HeapFree(GetProcessHeap(), 0, info); + heap_free(info); *size = sizeof(*ts); return ERROR_SUCCESS; } @@ -2151,25 +2137,54 @@ info->ftExpiry = context->pCertInfo->NotAfter; info->ftStart = context->pCertInfo->NotBefore; len = CertNameToStrA(context->dwCertEncodingType, - &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR, NULL, 0); + &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR|CERT_NAME_STR_CRLF_FLAG, NULL, 0); info->lpszSubjectInfo = LocalAlloc(0, len); if(info->lpszSubjectInfo) CertNameToStrA(context->dwCertEncodingType, - &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR, + &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR|CERT_NAME_STR_CRLF_FLAG, info->lpszSubjectInfo, len); len = CertNameToStrA(context->dwCertEncodingType, - &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR, NULL, 0); + &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR|CERT_NAME_STR_CRLF_FLAG, NULL, 0); info->lpszIssuerInfo = LocalAlloc(0, len); if(info->lpszIssuerInfo) CertNameToStrA(context->dwCertEncodingType, - &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR, + &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR|CERT_NAME_STR_CRLF_FLAG, info->lpszIssuerInfo, len); info->dwKeySize = NETCON_GetCipherStrength(req->netconn); CertFreeCertificateContext(context); return ERROR_SUCCESS; } } + case INTERNET_OPTION_CONNECT_TIMEOUT: + if (*size < sizeof(DWORD)) + return ERROR_INSUFFICIENT_BUFFER; + + *size = sizeof(DWORD); + *(DWORD *)buffer = req->connect_timeout; + return ERROR_SUCCESS; + case INTERNET_OPTION_REQUEST_FLAGS: { + DWORD flags = 0; + + if (*size < sizeof(DWORD)) + return ERROR_INSUFFICIENT_BUFFER; + + /* FIXME: Add support for: + * INTERNET_REQFLAG_FROM_CACHE + * INTERNET_REQFLAG_CACHE_WRITE_DISABLED + */ + + if(req->session->appInfo->proxy) + flags |= INTERNET_REQFLAG_VIA_PROXY; + if(!req->rawHeaders) + flags |= INTERNET_REQFLAG_NO_HEADERS; + + TRACE("INTERNET_OPTION_REQUEST_FLAGS returning %x\n", flags); + + *size = sizeof(DWORD); + *(DWORD*)buffer = flags; + return ERROR_SUCCESS; } + } return INET_QueryOption(hdr, option, buffer, size, unicode); } @@ -2179,6 +2194,15 @@ http_request_t *req = (http_request_t*)hdr; switch(option) { + case 99: /* Undocumented, seems to be INTERNET_OPTION_SECURITY_FLAGS with argument validation */ + TRACE("Undocumented option 99\n"); + + if (!buffer || size != sizeof(DWORD)) + return ERROR_INVALID_PARAMETER; + if(*(DWORD*)buffer & ~SECURITY_SET_MASK) + return ERROR_INTERNET_OPTION_NOT_SETTABLE; + + /* fall through */ case INTERNET_OPTION_SECURITY_FLAGS: { DWORD flags; @@ -2186,34 +2210,35 @@ if (!buffer || size != sizeof(DWORD)) return ERROR_INVALID_PARAMETER; flags = *(DWORD *)buffer; - TRACE("%08x\n", flags); - req->security_flags = flags; + TRACE("INTERNET_OPTION_SECURITY_FLAGS %08x\n", flags); + flags &= SECURITY_SET_MASK; + req->security_flags |= flags; if(req->netconn) - req->netconn->security_flags = flags; + req->netconn->security_flags |= flags; return ERROR_SUCCESS; } + case INTERNET_OPTION_CONNECT_TIMEOUT: + if (!buffer || size != sizeof(DWORD)) return ERROR_INVALID_PARAMETER; + req->connect_timeout = *(DWORD *)buffer; + return ERROR_SUCCESS; + case INTERNET_OPTION_SEND_TIMEOUT: + if (!buffer || size != sizeof(DWORD)) return ERROR_INVALID_PARAMETER; + req->send_timeout = *(DWORD *)buffer; + return ERROR_SUCCESS; + case INTERNET_OPTION_RECEIVE_TIMEOUT: - TRACE("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT\n"); + if (!buffer || size != sizeof(DWORD)) return ERROR_INVALID_PARAMETER; + req->receive_timeout = *(DWORD *)buffer; + return ERROR_SUCCESS; - if (size != sizeof(DWORD)) - return ERROR_INVALID_PARAMETER; - - if(!req->netconn) { - FIXME("unsupported without active connection\n"); - return ERROR_SUCCESS; - } - - return NETCON_set_timeout(req->netconn, option == INTERNET_OPTION_SEND_TIMEOUT, - *(DWORD*)buffer); - case INTERNET_OPTION_USERNAME: - HeapFree(GetProcessHeap(), 0, req->session->userName); + heap_free(req->session->userName); if (!(req->session->userName = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; return ERROR_SUCCESS; case INTERNET_OPTION_PASSWORD: - HeapFree(GetProcessHeap(), 0, req->session->password); + heap_free(req->session->password); if (!(req->session->password = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; return ERROR_SUCCESS; case INTERNET_OPTION_HTTP_DECODING: @@ -2223,7 +2248,7 @@ return ERROR_SUCCESS; } - return ERROR_INTERNET_INVALID_OPTION; + return INET_SetOption(hdr, option, buffer, size); } /* read some more data into the read buffer (the read section must be held) */ @@ -2369,6 +2394,8 @@ if(size && req->netconn) { if(NETCON_recv(req->netconn, buf, size, read_mode == READMODE_SYNC ? MSG_WAITALL : 0, &len) != ERROR_SUCCESS) len = 0; + if(!len) + netconn_stream->content_length = netconn_stream->content_read; } netconn_stream->content_read += *read = len; @@ -2594,13 +2621,13 @@ }; /* set the request content length based on the headers */ -static DWORD set_content_length(http_request_t *request, DWORD status_code) +static DWORD set_content_length(http_request_t *request) { static const WCHAR szChunked[] = {'c','h','u','n','k','e','d',0}; WCHAR encoding[20]; DWORD size; - if(status_code == HTTP_STATUS_NO_CONTENT) { + if(request->status_code == HTTP_STATUS_NO_CONTENT) { request->contentLength = request->netconn_stream.content_length = 0; return ERROR_SUCCESS; } @@ -2650,10 +2677,20 @@ return ERROR_SUCCESS; } +static void send_request_complete(http_request_t *req, DWORD_PTR result, DWORD error) +{ + INTERNET_ASYNC_RESULT iar; + + iar.dwResult = result; + iar.dwError = error; + + INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar, + sizeof(INTERNET_ASYNC_RESULT)); +} + static void HTTP_ReceiveRequestData(http_request_t *req, BOOL first_notif) { - INTERNET_ASYNC_RESULT iar; - DWORD res, read = 0; + DWORD res, read = 0, avail = 0; read_mode_t mode; TRACE("%p\n", req); @@ -2662,13 +2699,8 @@ mode = first_notif && req->read_size ? READMODE_NOBLOCK : READMODE_ASYNC; res = refill_read_buffer(req, mode, &read); - if(res == ERROR_SUCCESS) { - iar.dwResult = (DWORD_PTR)req->hdr.hInternet; - iar.dwError = first_notif ? 0 : get_avail_data(req); - }else { - iar.dwResult = 0; - iar.dwError = res; - } + if(res == ERROR_SUCCESS && !first_notif) + avail = get_avail_data(req); LeaveCriticalSection( &req->read_section ); @@ -2677,8 +2709,10 @@ http_release_netconn(req, FALSE); } - INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar, - sizeof(INTERNET_ASYNC_RESULT)); + if(res == ERROR_SUCCESS) + send_request_complete(req, req->session->hdr.dwInternalFlags & INET_OPENURL ? (DWORD_PTR)req->hdr.hInternet : 1, avail); + else + send_request_complete(req, 0, res); } /* read data from the http connection (the read section must be held) */ @@ -2748,7 +2782,6 @@ { struct WORKREQ_INTERNETREADFILEEXA const *data = &workRequest->u.InternetReadFileExA; http_request_t *req = (http_request_t*)workRequest->hdr; - INTERNET_ASYNC_RESULT iar; DWORD res; TRACE("INTERNETREADFILEEXA %p\n", workRequest->hdr); @@ -2756,12 +2789,7 @@ res = HTTPREQ_Read(req, data->lpBuffersOut->lpvBuffer, data->lpBuffersOut->dwBufferLength, &data->lpBuffersOut->dwBufferLength, TRUE); - iar.dwResult = res == ERROR_SUCCESS; - iar.dwError = res; - - INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, - INTERNET_STATUS_REQUEST_COMPLETE, &iar, - sizeof(INTERNET_ASYNC_RESULT)); + send_request_complete(req, res == ERROR_SUCCESS, res); } static DWORD HTTPREQ_ReadFileExA(object_header_t *hdr, INTERNET_BUFFERSA *buffers, @@ -2855,7 +2883,6 @@ { struct WORKREQ_INTERNETREADFILEEXW const *data = &workRequest->u.InternetReadFileExW; http_request_t *req = (http_request_t*)workRequest->hdr; - INTERNET_ASYNC_RESULT iar; DWORD res; TRACE("INTERNETREADFILEEXW %p\n", workRequest->hdr); @@ -2863,12 +2890,7 @@ res = HTTPREQ_Read(req, data->lpBuffersOut->lpvBuffer, data->lpBuffersOut->dwBufferLength, &data->lpBuffersOut->dwBufferLength, TRUE); - iar.dwResult = res == ERROR_SUCCESS; - iar.dwError = res; - - INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, - INTERNET_STATUS_REQUEST_COMPLETE, &iar, - sizeof(INTERNET_ASYNC_RESULT)); + send_request_complete(req, res == ERROR_SUCCESS, res); } static DWORD HTTPREQ_ReadFileExW(object_header_t *hdr, INTERNET_BUFFERSW *buffers, @@ -3054,6 +3076,7 @@ { appinfo_t *hIC = session->appInfo; http_request_t *request; + INTERNET_PORT port; DWORD len, res = ERROR_SUCCESS; TRACE("-->\n"); @@ -3069,13 +3092,27 @@ request->netconn_stream.data_stream.vtbl = &netconn_stream_vtbl; request->data_stream = &request->netconn_stream.data_stream; + request->connect_timeout = session->connect_timeout; + request->send_timeout = session->send_timeout; + request->receive_timeout = session->receive_timeout; InitializeCriticalSection( &request->read_section ); + request->read_section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": http_request_t.read_section"); WININET_AddRef( &session->hdr ); request->session = session; list_add_head( &session->hdr.children, &request->hdr.entry ); + port = session->hostPort; + if(port == INTERNET_INVALID_PORT_NUMBER) + port = dwFlags & INTERNET_FLAG_SECURE ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT; + + request->server = get_server(session->hostName, port, TRUE); + if(!request->server) { + WININET_Release(&request->hdr); + return ERROR_OUTOFMEMORY; + } + if (dwFlags & INTERNET_FLAG_IGNORE_CERT_CN_INVALID) request->security_flags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID; if (dwFlags & INTERNET_FLAG_IGNORE_CERT_DATE_INVALID) @@ -3143,11 +3180,6 @@ HTTP_ProcessHeader(request, hostW, session->hostName, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ); - if (session->serverPort == INTERNET_INVALID_PORT_NUMBER) - session->serverPort = (dwFlags & INTERNET_FLAG_SECURE ? - INTERNET_DEFAULT_HTTPS_PORT : - INTERNET_DEFAULT_HTTP_PORT); - if (session->hostPort == INTERNET_INVALID_PORT_NUMBER) session->hostPort = (dwFlags & INTERNET_FLAG_SECURE ? INTERNET_DEFAULT_HTTPS_PORT : @@ -3277,7 +3309,7 @@ szCookie, /* HTTP_QUERY_COOKIE = 44 */ NULL, /* HTTP_QUERY_REQUEST_METHOD = 45 */ NULL, /* HTTP_QUERY_REFRESH = 46 */ - NULL, /* HTTP_QUERY_CONTENT_DISPOSITION = 47 */ + szContent_Disposition, /* HTTP_QUERY_CONTENT_DISPOSITION = 47 */ szAge, /* HTTP_QUERY_AGE = 48 */ szCache_Control, /* HTTP_QUERY_CACHE_CONTROL = 49 */ szContent_Base, /* HTTP_QUERY_CONTENT_BASE = 50 */ @@ -3357,8 +3389,7 @@ } *lpdwBufferLength = len; - if (request_only) - HeapFree(GetProcessHeap(), 0, headers); + if (request_only) heap_free(headers); return res; } case HTTP_QUERY_RAW_HEADERS: @@ -3432,6 +3463,37 @@ index = HTTP_GetCustomHeaderIndex(request, header_lookup[request->read_gzip ? HTTP_QUERY_CONTENT_TYPE : level], requested_index,request_only); break; + case HTTP_QUERY_STATUS_CODE: { + DWORD res = ERROR_SUCCESS; + + if(request_only) + return ERROR_HTTP_INVALID_QUERY_REQUEST; + + if(requested_index) + break; + + if(dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) { + if(*lpdwBufferLength >= sizeof(DWORD)) + *(DWORD*)lpBuffer = request->status_code; + else + res = ERROR_INSUFFICIENT_BUFFER; + *lpdwBufferLength = sizeof(DWORD); + }else { + WCHAR buf[12]; + DWORD size; + static const WCHAR formatW[] = {'%','u',0}; + + size = (sprintfW(buf, formatW, request->status_code)+1) * sizeof(WCHAR); + + if(size <= *lpdwBufferLength) + memcpy(lpBuffer, buf, size); + else + res = ERROR_INSUFFICIENT_BUFFER; + + *lpdwBufferLength = size; + } + return res; + } default: assert (LAST_TABLE_HEADER == (HTTP_QUERY_UNLESS_MODIFIED_SINCE + 1)); @@ -3451,7 +3513,7 @@ return ERROR_HTTP_HEADER_NOT_FOUND; } - if (lpdwIndex && level != HTTP_QUERY_STATUS_CODE) (*lpdwIndex)++; + if (lpdwIndex) (*lpdwIndex)++; /* coalesce value to requested type */ if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER && lpBuffer) @@ -3711,8 +3773,7 @@ * the Unicode characters can be reduced to a single byte */ *lpdwBufferLength = len / sizeof(WCHAR); - HeapFree(GetProcessHeap(), 0, bufferW ); - + heap_free( bufferW ); return result; } @@ -3754,7 +3815,7 @@ url_length = url_length / sizeof(WCHAR) - 1; if (!InternetCreateUrlW(&urlComponents, 0, orig_url, &url_length)) { - HeapFree(GetProcessHeap(), 0, orig_url); + heap_free(orig_url); return NULL; } @@ -3762,18 +3823,18 @@ if (!InternetCombineUrlW(orig_url, lpszUrl, NULL, &url_length, ICU_ENCODE_SPACES_ONLY) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) { - HeapFree(GetProcessHeap(), 0, orig_url); + heap_free(orig_url); return NULL; } combined_url = heap_alloc(url_length * sizeof(WCHAR)); if (!InternetCombineUrlW(orig_url, lpszUrl, combined_url, &url_length, ICU_ENCODE_SPACES_ONLY)) { - HeapFree(GetProcessHeap(), 0, orig_url); - HeapFree(GetProcessHeap(), 0, combined_url); + heap_free(orig_url); + heap_free(combined_url); return NULL; } - HeapFree(GetProcessHeap(), 0, orig_url); + heap_free(orig_url); return combined_url; } @@ -3786,7 +3847,7 @@ http_session_t *session = request->session; appinfo_t *hIC = session->appInfo; BOOL using_proxy = hIC->proxy && hIC->proxy[0]; - WCHAR path[INTERNET_MAX_URL_LENGTH]; + WCHAR path[INTERNET_MAX_PATH_LENGTH]; int index; if(lpszUrl[0]=='/') @@ -3797,74 +3858,61 @@ else { URL_COMPONENTSW urlComponents; - WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024]; - static WCHAR szHttp[] = {'h','t','t','p',0}; - static WCHAR szHttps[] = {'h','t','t','p','s',0}; + WCHAR protocol[INTERNET_MAX_SCHEME_LENGTH]; + WCHAR hostName[INTERNET_MAX_HOST_NAME_LENGTH]; + WCHAR userName[INTERNET_MAX_USER_NAME_LENGTH]; + BOOL custom_port = FALSE; + static WCHAR httpW[] = {'h','t','t','p',0}; + static WCHAR httpsW[] = {'h','t','t','p','s',0}; + userName[0] = 0; hostName[0] = 0; protocol[0] = 0; urlComponents.dwStructSize = sizeof(URL_COMPONENTSW); urlComponents.lpszScheme = protocol; - urlComponents.dwSchemeLength = 32; + urlComponents.dwSchemeLength = INTERNET_MAX_SCHEME_LENGTH; urlComponents.lpszHostName = hostName; - urlComponents.dwHostNameLength = MAXHOSTNAME; + urlComponents.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH; urlComponents.lpszUserName = userName; - urlComponents.dwUserNameLength = 1024; + urlComponents.dwUserNameLength = INTERNET_MAX_USER_NAME_LENGTH; urlComponents.lpszPassword = NULL; urlComponents.dwPasswordLength = 0; urlComponents.lpszUrlPath = path; - urlComponents.dwUrlPathLength = 2048; + urlComponents.dwUrlPathLength = INTERNET_MAX_PATH_LENGTH; urlComponents.lpszExtraInfo = NULL; urlComponents.dwExtraInfoLength = 0; if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents)) return INTERNET_GetLastError(); - if (!strncmpW(szHttp, urlComponents.lpszScheme, strlenW(szHttp)) && - (request->hdr.dwFlags & INTERNET_FLAG_SECURE)) - { - TRACE("redirect from secure page to non-secure page\n"); - /* FIXME: warn about from secure redirect to non-secure page */ - request->hdr.dwFlags &= ~INTERNET_FLAG_SECURE; - } - if (!strncmpW(szHttps, urlComponents.lpszScheme, strlenW(szHttps)) && - !(request->hdr.dwFlags & INTERNET_FLAG_SECURE)) - { - TRACE("redirect from non-secure page to secure page\n"); - /* FIXME: notify about redirect to secure page */ - request->hdr.dwFlags |= INTERNET_FLAG_SECURE; - } + if(!strcmpiW(protocol, httpW)) { + if(request->hdr.dwFlags & INTERNET_FLAG_SECURE) { + TRACE("redirect from secure page to non-secure page\n"); + /* FIXME: warn about from secure redirect to non-secure page */ + request->hdr.dwFlags &= ~INTERNET_FLAG_SECURE; + } - if (urlComponents.nPort == INTERNET_INVALID_PORT_NUMBER) - { - if (lstrlenW(protocol)>4) /*https*/ + if(urlComponents.nPort == INTERNET_INVALID_PORT_NUMBER) + urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT; + else if(urlComponents.nPort != INTERNET_DEFAULT_HTTP_PORT) + custom_port = TRUE; + }else if(!strcmpiW(protocol, httpsW)) { + if(!(request->hdr.dwFlags & INTERNET_FLAG_SECURE)) { + TRACE("redirect from non-secure page to secure page\n"); + /* FIXME: notify about redirect to secure page */ + request->hdr.dwFlags |= INTERNET_FLAG_SECURE; + } + + if(urlComponents.nPort == INTERNET_INVALID_PORT_NUMBER) urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT; - else /*http*/ - urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT; + else if(urlComponents.nPort != INTERNET_DEFAULT_HTTPS_PORT) + custom_port = TRUE; } -#if 0 - /* - * This upsets redirects to binary files on sourceforge.net - * and gives an html page instead of the target file - * Examination of the HTTP request sent by native wininet.dll - * reveals that it doesn't send a referrer in that case. - * Maybe there's a flag that enables this, or maybe a referrer - * shouldn't be added in case of a redirect. - */ + heap_free(session->hostName); - /* consider the current host as the referrer */ - if (session->lpszServerName && *session->lpszServerName) - HTTP_ProcessHeader(request, HTTP_REFERER, session->lpszServerName, - HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE| - HTTP_ADDHDR_FLAG_ADD_IF_NEW); -#endif - - HeapFree(GetProcessHeap(), 0, session->hostName); - if (urlComponents.nPort != INTERNET_DEFAULT_HTTP_PORT && - urlComponents.nPort != INTERNET_DEFAULT_HTTPS_PORT) - { + if(custom_port) { int len; static const WCHAR fmt[] = {'%','s',':','%','u',0}; len = lstrlenW(hostName); @@ -3877,23 +3925,22 @@ HTTP_ProcessHeader(request, hostW, session->hostName, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDHDR_FLAG_REQ); - HeapFree(GetProcessHeap(), 0, session->userName); + heap_free(session->userName); session->userName = NULL; if (userName[0]) session->userName = heap_strdupW(userName); reset_data_stream(request); - if(!using_proxy) { - if(strcmpiW(session->serverName, hostName)) { - HeapFree(GetProcessHeap(), 0, session->serverName); - session->serverName = heap_strdupW(hostName); - } - session->serverPort = urlComponents.nPort; + if(!using_proxy && (strcmpiW(request->server->name, hostName) || request->server->port != urlComponents.nPort)) { + server_t *new_server; + + new_server = get_server(hostName, urlComponents.nPort, TRUE); + server_release(request->server); + request->server = new_server; } } - - HeapFree(GetProcessHeap(), 0, request->path); + heap_free(request->path); request->path=NULL; if (*path) { @@ -3965,20 +4012,20 @@ lpszPath = heap_alloc((lstrlenW( session->hostName ) + 13)*sizeof(WCHAR)); sprintfW( lpszPath, szFormat, session->hostName, session->hostPort ); requestString = HTTP_BuildHeaderRequestString( request, szConnect, lpszPath, g_szHttp1_1 ); - HeapFree( GetProcessHeap(), 0, lpszPath ); + heap_free( lpszPath ); len = WideCharToMultiByte( CP_ACP, 0, requestString, -1, NULL, 0, NULL, NULL ); len--; /* the nul terminator isn't needed */ ascii_req = heap_alloc(len); - WideCharToMultiByte( CP_ACP, 0, requestString, -1, - ascii_req, len, NULL, NULL ); - HeapFree( GetProcessHeap(), 0, requestString ); + WideCharToMultiByte( CP_ACP, 0, requestString, -1, ascii_req, len, NULL, NULL ); + heap_free( requestString ); TRACE("full request -> %s\n", debugstr_an( ascii_req, len ) ); + NETCON_set_timeout( request->netconn, TRUE, request->send_timeout ); res = NETCON_send( request->netconn, ascii_req, len, 0, &cnt ); - HeapFree( GetProcessHeap(), 0, ascii_req ); + heap_free( ascii_req ); if (res != ERROR_SUCCESS) return res; @@ -4017,7 +4064,7 @@ heap_free(cookies); } -static WORD HTTP_ParseDay(LPCWSTR day) +static WORD HTTP_ParseWkday(LPCWSTR day) { static const WCHAR days[7][4] = {{ 's','u','n',0 }, { 'm','o','n',0 }, @@ -4135,7 +4182,7 @@ dayPtr - day < sizeof(day) / sizeof(day[0]) - 1; ptr++, dayPtr++) *dayPtr = *ptr; *dayPtr = 0; - st.wDayOfWeek = HTTP_ParseDay(day); + st.wDayOfWeek = HTTP_ParseWkday(day); if (st.wDayOfWeek >= 7) { ERR("unexpected weekday %s\n", debugstr_w(day)); @@ -4214,15 +4261,15 @@ return FALSE; if (ptr - value != 3) { - ERR("unexpected weekday %s\n", debugstr_wn(value, ptr - value)); + WARN("unexpected weekday %s\n", debugstr_wn(value, ptr - value)); return FALSE; } memcpy(day, value, (ptr - value) * sizeof(WCHAR)); day[3] = 0; - st.wDayOfWeek = HTTP_ParseDay(day); + st.wDayOfWeek = HTTP_ParseWkday(day); if (st.wDayOfWeek > 6) { - ERR("unexpected weekday %s\n", debugstr_wn(value, ptr - value)); + WARN("unexpected weekday %s\n", debugstr_wn(value, ptr - value)); return FALSE; } ptr++; @@ -4233,7 +4280,7 @@ num = strtoulW(ptr, &nextPtr, 10); if (!nextPtr || nextPtr <= ptr || !num || num > 31) { - ERR("unexpected day %s\n", debugstr_w(value)); + WARN("unexpected day %s\n", debugstr_w(value)); return FALSE; } ptr = nextPtr; @@ -4250,7 +4297,7 @@ st.wMonth = HTTP_ParseMonth(month); if (!st.wMonth || st.wMonth > 12) { - ERR("unexpected month %s\n", debugstr_w(month)); + WARN("unexpected month %s\n", debugstr_w(month)); return FALSE; } @@ -4280,11 +4327,125 @@ return SystemTimeToFileTime(&st, ft); } -/* FIXME: only accepts dates in RFC 1123 format and asctime() format, - * which may not be the only formats actually seen in the wild. - * http://www.hackcraft.net/web/datetime/ suggests at least RFC 850 dates - * should be accepted as well. - */ +static WORD HTTP_ParseWeekday(LPCWSTR day) +{ + static const WCHAR days[7][10] = {{ 's','u','n','d','a','y',0 }, + { 'm','o','n','d','a','y',0 }, + { 't','u','e','s','d','a','y',0 }, + { 'w','e','d','n','e','s','d','a','y',0 }, + { 't','h','u','r','s','d','a','y',0 }, + { 'f','r','i','d','a','y',0 }, + { 's','a','t','u','r','d','a','y',0 }}; + int i; + for (i = 0; i < sizeof(days)/sizeof(*days); i++) + if (!strcmpiW(day, days[i])) + return i; + + /* Invalid */ + return 7; +} + +static BOOL HTTP_ParseRfc850Date(LPCWSTR value, FILETIME *ft) +{ + static const WCHAR gmt[]= { 'G','M','T',0 }; + WCHAR *nextPtr, day[10], month[4], *monthPtr; + LPCWSTR ptr; + unsigned long num; + SYSTEMTIME st = { 0 }; + + ptr = strchrW(value, ','); + if (!ptr) + return FALSE; + if (ptr - value == 3) + { + memcpy(day, value, (ptr - value) * sizeof(WCHAR)); + day[3] = 0; + st.wDayOfWeek = HTTP_ParseWkday(day); + if (st.wDayOfWeek > 6) + { + ERR("unexpected weekday %s\n", debugstr_wn(value, ptr - value)); + return FALSE; + } + } + else if (ptr - value < sizeof(day) / sizeof(day[0])) + { + memcpy(day, value, (ptr - value) * sizeof(WCHAR)); + day[ptr - value + 1] = 0; + st.wDayOfWeek = HTTP_ParseWeekday(day); + if (st.wDayOfWeek > 6) + { + ERR("unexpected weekday %s\n", debugstr_wn(value, ptr - value)); + return FALSE; + } + } + else + { + ERR("unexpected weekday %s\n", debugstr_wn(value, ptr - value)); + return FALSE; + } + ptr++; + + while (isspaceW(*ptr)) + ptr++; + + num = strtoulW(ptr, &nextPtr, 10); + if (!nextPtr || nextPtr <= ptr || !num || num > 31) + { + ERR("unexpected day %s\n", debugstr_w(value)); + return FALSE; + } + ptr = nextPtr; + st.wDay = (WORD)num; + + if (*ptr != '-') + { + ERR("unexpected month format %s\n", debugstr_w(ptr)); + return FALSE; + } + ptr++; + + for (monthPtr = month; *ptr != '-' && + monthPtr - month < sizeof(month) / sizeof(month[0]) - 1; + monthPtr++, ptr++) + *monthPtr = *ptr; + *monthPtr = 0; + st.wMonth = HTTP_ParseMonth(month); + if (!st.wMonth || st.wMonth > 12) + { + ERR("unexpected month %s\n", debugstr_w(month)); + return FALSE; + } + + if (*ptr != '-') + { + ERR("unexpected year format %s\n", debugstr_w(ptr)); + return FALSE; + } + ptr++; + + num = strtoulW(ptr, &nextPtr, 10); + if (!nextPtr || nextPtr <= ptr || num < 1601 || num > 30827) + { + ERR("unexpected year %s\n", debugstr_w(value)); + return FALSE; + } + ptr = nextPtr; + st.wYear = (WORD)num; + + if (!HTTP_ParseTime(&st, &ptr)) + return FALSE; + + while (isspaceW(*ptr)) + ptr++; + + if (strcmpW(ptr, gmt)) + { + ERR("unexpected time zone %s\n", debugstr_w(ptr)); + return FALSE; + } + return SystemTimeToFileTime(&st, ft); +} + static BOOL HTTP_ParseDate(LPCWSTR value, FILETIME *ft) { static const WCHAR zero[] = { '0',0 }; @@ -4296,7 +4457,15 @@ ret = TRUE; } else if (strchrW(value, ',')) + { ret = HTTP_ParseRfc1123Date(value, ft); + if (!ret) + { + ret = HTTP_ParseRfc850Date(value, ft); + if (!ret) + ERR("unexpected date format %s\n", debugstr_w(value)); + } + } else { ret = HTTP_ParseDateAsAsctime(value, ft); @@ -4433,7 +4602,7 @@ b = CreateUrlCacheEntryW(url, request->contentLength, NULL, cacheFileName, 0); if(b) { - HeapFree(GetProcessHeap(), 0, request->cacheFile); + heap_free(request->cacheFile); CloseHandle(request->hCacheFile); request->cacheFile = heap_strdupW(cacheFileName); @@ -4451,28 +4620,20 @@ static DWORD open_http_connection(http_request_t *request, BOOL *reusing) { const BOOL is_https = (request->hdr.dwFlags & INTERNET_FLAG_SECURE) != 0; - http_session_t *session = request->session; netconn_t *netconn = NULL; - server_t *server; DWORD res; assert(!request->netconn); reset_data_stream(request); - server = get_server(session->serverName, session->serverPort); - if(!server) - return ERROR_OUTOFMEMORY; - - res = HTTP_ResolveName(request, server); - if(res != ERROR_SUCCESS) { - server_release(server); + res = HTTP_ResolveName(request); + if(res != ERROR_SUCCESS) return res; - } EnterCriticalSection(&connection_pool_cs); - while(!list_empty(&server->conn_pool)) { - netconn = LIST_ENTRY(list_head(&server->conn_pool), netconn_t, pool_entry); + while(!list_empty(&request->server->conn_pool)) { + netconn = LIST_ENTRY(list_head(&request->server->conn_pool), netconn_t, pool_entry); list_remove(&netconn->pool_entry); if(NETCON_is_alive(netconn)) @@ -4494,11 +4655,12 @@ INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER, - server->addr_str, - strlen(server->addr_str)+1); + request->server->addr_str, + strlen(request->server->addr_str)+1); - res = create_netconn(is_https, server, request->security_flags, &netconn); - server_release(server); + res = create_netconn(is_https, request->server, request->security_flags, + (request->hdr.ErrorMask & INTERNET_ERROR_MASK_COMBINED_SEC_CERT) != 0, + request->connect_timeout, &netconn); if(res != ERROR_SUCCESS) { ERR("create_netconn failed: %u\n", res); return res; @@ -4508,7 +4670,7 @@ INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER, - server->addr_str, strlen(server->addr_str)+1); + request->server->addr_str, strlen(request->server->addr_str)+1); if(is_https) { /* Note: we differ from Microsoft's WinINet here. they seem to have @@ -4517,24 +4679,10 @@ * behaviour to be more correct and to not cause any incompatibilities * because using a secure connection through a proxy server is a rare * case that would be hard for anyone to depend on */ - if(session->appInfo->proxy) + if(request->session->appInfo->proxy) res = HTTP_SecureProxyConnect(request); if(res == ERROR_SUCCESS) - res = NETCON_secure_connect(request->netconn, session->hostName); - if(res != ERROR_SUCCESS) - { - WARN("Couldn't connect securely to host\n"); - - if((request->hdr.ErrorMask&INTERNET_ERROR_MASK_COMBINED_SEC_CERT) && ( - res == ERROR_INTERNET_SEC_CERT_DATE_INVALID - || res == ERROR_INTERNET_INVALID_CA - || res == ERROR_INTERNET_SEC_CERT_NO_REV - || res == ERROR_INTERNET_SEC_CERT_REV_FAILED - || res == ERROR_INTERNET_SEC_CERT_REVOKED - || res == ERROR_INTERNET_SEC_INVALID_CERT - || res == ERROR_INTERNET_SEC_CERT_CN_INVALID)) - res = ERROR_INTERNET_SEC_CERT_ERRORS; - } + res = NETCON_secure_connect(request->netconn); } if(res != ERROR_SUCCESS) { @@ -4543,7 +4691,7 @@ } *reusing = FALSE; - TRACE("Created connection to %s: %p\n", debugstr_w(server->name), netconn); + TRACE("Created connection to %s: %p\n", debugstr_w(request->server->name), netconn); return ERROR_SUCCESS; } @@ -4566,7 +4714,6 @@ LPWSTR requestString = NULL; INT responseLen; BOOL loop_next; - INTERNET_ASYNC_RESULT iar; static const WCHAR szPost[] = { 'P','O','S','T',0 }; static const WCHAR szContentLength[] = { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','l','i','\r','\n',0 }; @@ -4598,7 +4745,7 @@ sprintfW(agent_header, user_agent, request->session->appInfo->agent); HTTP_HttpAddRequestHeadersW(request, agent_header, strlenW(agent_header), HTTP_ADDREQ_FLAG_ADD_IF_NEW); - HeapFree(GetProcessHeap(), 0, agent_header); + heap_free(agent_header); } if (request->hdr.dwFlags & INTERNET_FLAG_PRAGMA_NOCACHE) { @@ -4612,6 +4759,10 @@ HTTP_HttpAddRequestHeadersW(request, cache_control, strlenW(cache_control), HTTP_ADDREQ_FLAG_ADD_IF_NEW); } + /* add the headers the caller supplied */ + if( lpszHeaders && dwHeaderLength ) + HTTP_HttpAddRequestHeadersW(request, lpszHeaders, dwHeaderLength, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REPLACE); + do { DWORD len; @@ -4645,18 +4796,11 @@ if (!(request->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES)) HTTP_InsertCookies(request); - /* add the headers the caller supplied */ - if( lpszHeaders && dwHeaderLength ) - { - HTTP_HttpAddRequestHeadersW(request, lpszHeaders, dwHeaderLength, - HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REPLACE); - } - if (request->session->appInfo->proxy && request->session->appInfo->proxy[0]) { WCHAR *url = HTTP_BuildProxyRequestUrl(request); requestString = HTTP_BuildHeaderRequestString(request, request->verb, url, request->version); - HeapFree(GetProcessHeap(), 0, url); + heap_free(url); } else requestString = HTTP_BuildHeaderRequestString(request, request->verb, request->path, request->version); @@ -4684,8 +4828,9 @@ INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0); + NETCON_set_timeout( request->netconn, TRUE, request->send_timeout ); res = NETCON_send(request->netconn, ascii_req, len, 0, &cnt); - HeapFree( GetProcessHeap(), 0, ascii_req ); + heap_free( ascii_req ); if(res != ERROR_SUCCESS) { TRACE("send failed: %u\n", res); if(!reusing_connection) @@ -4704,7 +4849,6 @@ if (bEndRequest) { DWORD dwBufferSize; - DWORD dwStatusCode; INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); @@ -4728,12 +4872,7 @@ HTTP_ProcessExpires(request); HTTP_ProcessLastModified(request); - dwBufferSize = sizeof(dwStatusCode); - if (HTTP_HttpQueryInfoW(request,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, - &dwStatusCode,&dwBufferSize,NULL) != ERROR_SUCCESS) - dwStatusCode = 0; - - res = set_content_length(request, dwStatusCode); + res = set_content_length(request); if(res != ERROR_SUCCESS) goto lend; if(!request->contentLength) @@ -4743,15 +4882,18 @@ { WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH]; dwBufferSize=sizeof(szNewLocation); - if ((dwStatusCode == HTTP_STATUS_REDIRECT || - dwStatusCode == HTTP_STATUS_MOVED || - dwStatusCode == HTTP_STATUS_REDIRECT_KEEP_VERB || - dwStatusCode == HTTP_STATUS_REDIRECT_METHOD) && - HTTP_HttpQueryInfoW(request,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,NULL) == ERROR_SUCCESS) - { - if (strcmpW(request->verb, szGET) && strcmpW(request->verb, szHEAD)) + switch(request->status_code) { + case HTTP_STATUS_REDIRECT: + case HTTP_STATUS_MOVED: + case HTTP_STATUS_REDIRECT_KEEP_VERB: + case HTTP_STATUS_REDIRECT_METHOD: + if(HTTP_HttpQueryInfoW(request,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,NULL) != ERROR_SUCCESS) + break; + + if (strcmpW(request->verb, szGET) && strcmpW(request->verb, szHEAD) && + request->status_code != HTTP_STATUS_REDIRECT_KEEP_VERB) { - HeapFree(GetProcessHeap(), 0, request->verb); + heap_free(request->verb); request->verb = heap_strdupW(szGET); } drain_content(request); @@ -4762,10 +4904,10 @@ res = HTTP_HandleRedirect(request, new_url); if (res == ERROR_SUCCESS) { - HeapFree(GetProcessHeap(), 0, requestString); + heap_free(requestString); loop_next = TRUE; } - HeapFree( GetProcessHeap(), 0, new_url ); + heap_free( new_url ); } redirected = TRUE; } @@ -4774,7 +4916,7 @@ { WCHAR szAuthValue[2048]; dwBufferSize=2048; - if (dwStatusCode == HTTP_STATUS_DENIED) + if (request->status_code == HTTP_STATUS_DENIED) { LPHTTPHEADERW Host = HTTP_GetHeader(request, hostW); DWORD dwIndex = 0; @@ -4786,7 +4928,7 @@ request->session->password, Host->lpszValue)) { - HeapFree(GetProcessHeap(), 0, requestString); + heap_free(requestString); loop_next = TRUE; break; } @@ -4798,7 +4940,7 @@ request->authInfo = NULL; } } - if (dwStatusCode == HTTP_STATUS_PROXY_AUTH_REQ) + if (request->status_code == HTTP_STATUS_PROXY_AUTH_REQ) { DWORD dwIndex = 0; while (HTTP_HttpQueryInfoW(request,HTTP_QUERY_PROXY_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex) == ERROR_SUCCESS) @@ -4831,23 +4973,20 @@ HTTP_CacheRequest(request); lend: + heap_free(requestString); - HeapFree(GetProcessHeap(), 0, requestString); - /* TODO: send notification for P3P header */ if (request->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) { - if (res == ERROR_SUCCESS && request->contentLength && request->bytesWritten == request->bytesToWrite) - HTTP_ReceiveRequestData(request, TRUE); - else - { - iar.dwResult = (res==ERROR_SUCCESS ? (DWORD_PTR)request->hdr.hInternet : 0); - iar.dwError = res; - - INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, - INTERNET_STATUS_REQUEST_COMPLETE, &iar, - sizeof(INTERNET_ASYNC_RESULT)); + if (res == ERROR_SUCCESS) { + if(bEndRequest && request->contentLength && request->bytesWritten == request->bytesToWrite) + HTTP_ReceiveRequestData(request, TRUE); + else + send_request_complete(request, + request->session->hdr.dwInternalFlags & INET_OPENURL ? (DWORD_PTR)request->hdr.hInternet : 1, 0); + }else { + send_request_complete(request, 0, res); } } @@ -4871,17 +5010,22 @@ req->dwHeaderLength, req->lpOptional, req->dwOptionalLength, req->dwContentLength, req->bEndRequest); - HeapFree(GetProcessHeap(), 0, req->lpszHeader); + heap_free(req->lpszHeader); } static DWORD HTTP_HttpEndRequestW(http_request_t *request, DWORD dwFlags, DWORD_PTR dwContext) { + DWORD dwBufferSize; INT responseLen; - DWORD dwCode, dwCodeLength; - DWORD dwBufferSize; DWORD res = ERROR_SUCCESS; + if(!request->netconn) { + WARN("Not connected\n"); + send_request_complete(request, 0, ERROR_INTERNET_OPERATION_CANCELLED); + return ERROR_INTERNET_OPERATION_CANCELLED; + } + INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); @@ -4898,56 +5042,48 @@ HTTP_ProcessExpires(request); HTTP_ProcessLastModified(request); - dwCodeLength = sizeof(dwCode); - if (HTTP_HttpQueryInfoW(request,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, - &dwCode,&dwCodeLength,NULL) != ERROR_SUCCESS) - dwCode = 0; - - if ((res = set_content_length( request, dwCode )) == ERROR_SUCCESS) { + if ((res = set_content_length(request)) == ERROR_SUCCESS) { if(!request->contentLength) http_release_netconn(request, TRUE); } if (res == ERROR_SUCCESS && !(request->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT)) { - if (dwCode == HTTP_STATUS_REDIRECT || - dwCode == HTTP_STATUS_MOVED || - dwCode == HTTP_STATUS_REDIRECT_METHOD || - dwCode == HTTP_STATUS_REDIRECT_KEEP_VERB) - { + switch(request->status_code) { + case HTTP_STATUS_REDIRECT: + case HTTP_STATUS_MOVED: + case HTTP_STATUS_REDIRECT_METHOD: + case HTTP_STATUS_REDIRECT_KEEP_VERB: { WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH]; dwBufferSize=sizeof(szNewLocation); - if (HTTP_HttpQueryInfoW(request, HTTP_QUERY_LOCATION, szNewLocation, &dwBufferSize, NULL) == ERROR_SUCCESS) + if (HTTP_HttpQueryInfoW(request, HTTP_QUERY_LOCATION, szNewLocation, &dwBufferSize, NULL) != ERROR_SUCCESS) + break; + + if (strcmpW(request->verb, szGET) && strcmpW(request->verb, szHEAD) && + request->status_code != HTTP_STATUS_REDIRECT_KEEP_VERB) { - if (strcmpW(request->verb, szGET) && strcmpW(request->verb, szHEAD)) - { - HeapFree(GetProcessHeap(), 0, request->verb); - request->verb = heap_strdupW(szGET); - } - drain_content(request); - if ((new_url = HTTP_GetRedirectURL( request, szNewLocation ))) - { - INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_REDIRECT, - new_url, (strlenW(new_url) + 1) * sizeof(WCHAR)); - res = HTTP_HandleRedirect(request, new_url); - if (res == ERROR_SUCCESS) - res = HTTP_HttpSendRequestW(request, NULL, 0, NULL, 0, 0, TRUE); - HeapFree( GetProcessHeap(), 0, new_url ); - } + heap_free(request->verb); + request->verb = heap_strdupW(szGET); } + drain_content(request); + if ((new_url = HTTP_GetRedirectURL( request, szNewLocation ))) + { + INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_REDIRECT, + new_url, (strlenW(new_url) + 1) * sizeof(WCHAR)); + res = HTTP_HandleRedirect(request, new_url); + if (res == ERROR_SUCCESS) + res = HTTP_HttpSendRequestW(request, NULL, 0, NULL, 0, 0, TRUE); + heap_free( new_url ); + } } + } } - if (res == ERROR_SUCCESS && request->contentLength) { + if (res == ERROR_SUCCESS && request->contentLength) HTTP_ReceiveRequestData(request, TRUE); - }else { - INTERNET_ASYNC_RESULT iar = {0, res}; + else + send_request_complete(request, res == ERROR_SUCCESS, res); - INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, - INTERNET_STATUS_REQUEST_COMPLETE, &iar, - sizeof(INTERNET_ASYNC_RESULT)); - } - return res; } @@ -5001,7 +5137,7 @@ http_request_t *request; DWORD res; - TRACE("-->\n"); + TRACE("%p %p %x %lx -->\n", hRequest, lpBuffersOut, dwFlags, dwContext); if (lpBuffersOut) { @@ -5096,8 +5232,7 @@ rc = HttpSendRequestExW(hRequest, lpBuffersIn ? &BuffersInW : NULL, NULL, dwFlags, dwContext); - HeapFree(GetProcessHeap(),0,header); - + heap_free(header); return rc; } @@ -5312,8 +5447,8 @@ szHeaders = heap_alloc(nLen*sizeof(WCHAR)); MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,szHeaders,nLen); } - result=HttpSendRequestW(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength); - HeapFree(GetProcessHeap(),0,szHeaders); + result = HttpSendRequestW(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength); + heap_free(szHeaders); return result; } @@ -5331,14 +5466,15 @@ WININET_Release(&session->appInfo->hdr); - HeapFree(GetProcessHeap(), 0, session->hostName); - HeapFree(GetProcessHeap(), 0, session->serverName); - HeapFree(GetProcessHeap(), 0, session->password); - HeapFree(GetProcessHeap(), 0, session->userName); + heap_free(session->hostName); + heap_free(session->password); + heap_free(session->userName); } static DWORD HTTPSESSION_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) { + http_session_t *ses = (http_session_t *)hdr; + switch(option) { case INTERNET_OPTION_HANDLE_TYPE: TRACE("INTERNET_OPTION_HANDLE_TYPE\n"); @@ -5349,6 +5485,35 @@ *size = sizeof(DWORD); *(DWORD*)buffer = INTERNET_HANDLE_TYPE_CONNECT_HTTP; return ERROR_SUCCESS; + case INTERNET_OPTION_CONNECT_TIMEOUT: + TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n"); + + if (*size < sizeof(DWORD)) + return ERROR_INSUFFICIENT_BUFFER; + + *size = sizeof(DWORD); + *(DWORD *)buffer = ses->connect_timeout; + return ERROR_SUCCESS; + + case INTERNET_OPTION_SEND_TIMEOUT: + TRACE("INTERNET_OPTION_SEND_TIMEOUT\n"); + + if (*size < sizeof(DWORD)) + return ERROR_INSUFFICIENT_BUFFER; + + *size = sizeof(DWORD); + *(DWORD *)buffer = ses->send_timeout; + return ERROR_SUCCESS; + + case INTERNET_OPTION_RECEIVE_TIMEOUT: + TRACE("INTERNET_OPTION_RECEIVE_TIMEOUT\n"); + + if (*size < sizeof(DWORD)) + return ERROR_INSUFFICIENT_BUFFER; + + *size = sizeof(DWORD); + *(DWORD *)buffer = ses->receive_timeout; + return ERROR_SUCCESS; } return INET_QueryOption(hdr, option, buffer, size, unicode); @@ -5361,20 +5526,38 @@ switch(option) { case INTERNET_OPTION_USERNAME: { - HeapFree(GetProcessHeap(), 0, ses->userName); + heap_free(ses->userName); if (!(ses->userName = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; return ERROR_SUCCESS; } case INTERNET_OPTION_PASSWORD: { - HeapFree(GetProcessHeap(), 0, ses->password); + heap_free(ses->password); if (!(ses->password = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; return ERROR_SUCCESS; } + case INTERNET_OPTION_CONNECT_TIMEOUT: + { + if (!buffer || size != sizeof(DWORD)) return ERROR_INVALID_PARAMETER; + ses->connect_timeout = *(DWORD *)buffer; + return ERROR_SUCCESS; + } + case INTERNET_OPTION_SEND_TIMEOUT: + { + if (!buffer || size != sizeof(DWORD)) return ERROR_INVALID_PARAMETER; + ses->send_timeout = *(DWORD *)buffer; + return ERROR_SUCCESS; + } + case INTERNET_OPTION_RECEIVE_TIMEOUT: + { + if (!buffer || size != sizeof(DWORD)) return ERROR_INVALID_PARAMETER; + ses->receive_timeout = *(DWORD *)buffer; + return ERROR_SUCCESS; + } default: break; } - return ERROR_INTERNET_INVALID_OPTION; + return INET_SetOption(hdr, option, buffer, size); } static const object_vtbl_t HTTPSESSIONVtbl = { @@ -5435,14 +5618,15 @@ if(hIC->proxyBypass) FIXME("Proxy bypass is ignored.\n"); } - session->serverName = heap_strdupW(lpszServerName); session->hostName = heap_strdupW(lpszServerName); if (lpszUserName && lpszUserName[0]) session->userName = heap_strdupW(lpszUserName); if (lpszPassword && lpszPassword[0]) session->password = heap_strdupW(lpszPassword); - session->serverPort = serverPort; session->hostPort = serverPort; + session->connect_timeout = hIC->connect_timeout; + session->send_timeout = INFINITE; + session->receive_timeout = INFINITE; /* Don't send a handle created callback if this handle was created with InternetOpenUrl */ if (!(session->hdr.dwInternalFlags & INET_OPENURL)) @@ -5515,6 +5699,7 @@ if(!request->netconn) goto lend; + NETCON_set_timeout( request->netconn, FALSE, request->receive_timeout ); do { static const WCHAR szHundred[] = {'1','0','0',0}; /* @@ -5547,6 +5732,8 @@ goto lend; *status_text++=0; + request->status_code = atoiW(status_code); + TRACE("version [%s] status code [%s] status text [%s]\n", debugstr_w(buffer), debugstr_w(status_code), debugstr_w(status_text) ); @@ -5556,13 +5743,14 @@ { WARN("No status line at head of response (%s)\n", debugstr_w(buffer)); - HeapFree(GetProcessHeap(), 0, request->version); - HeapFree(GetProcessHeap(), 0, request->statusText); + heap_free(request->version); + heap_free(request->statusText); + request->status_code = HTTP_STATUS_OK; request->version = heap_strdupW(g_szHttp1_0); request->statusText = heap_strdupW(szOK); - HeapFree(GetProcessHeap(), 0, request->rawHeaders); + heap_free(request->rawHeaders); request->rawHeaders = heap_strdupW(szDefaultHeader); bSuccess = TRUE; @@ -5574,8 +5762,8 @@ HTTP_ProcessHeader(request, szStatus, status_code, HTTP_ADDHDR_FLAG_REPLACE); - HeapFree(GetProcessHeap(),0,request->version); - HeapFree(GetProcessHeap(),0,request->statusText); + heap_free(request->version); + heap_free(request->statusText); request->version = heap_strdupW(buffer); request->statusText = heap_strdupW(status_text); @@ -5653,7 +5841,7 @@ memcpy(&lpszRawHeaders[cchRawHeaders], szCrLf, sizeof(szCrLf)); - HeapFree(GetProcessHeap(), 0, request->rawHeaders); + heap_free(request->rawHeaders); request->rawHeaders = lpszRawHeaders; TRACE("raw headers: %s\n", debugstr_w(lpszRawHeaders)); bSuccess = TRUE; @@ -5665,7 +5853,7 @@ return rc; else { - HeapFree(GetProcessHeap(), 0, lpszRawHeaders); + heap_free(lpszRawHeaders); return 0; } } @@ -5930,8 +6118,8 @@ return FALSE; request->nCustHeaders--; - HeapFree(GetProcessHeap(), 0, request->custHeaders[index].lpszField); - HeapFree(GetProcessHeap(), 0, request->custHeaders[index].lpszValue); + heap_free(request->custHeaders[index].lpszField); + heap_free(request->custHeaders[index].lpszValue); memmove( &request->custHeaders[index], &request->custHeaders[index+1], (request->nCustHeaders - index)* sizeof(HTTPHEADERW) ); @@ -5985,3 +6173,30 @@ FIXME("stub: %s %p\n", debugstr_w(url), window); return FALSE; } + +/*********************************************************************** + * ShowX509EncodedCertificate (@) + */ +DWORD WINAPI ShowX509EncodedCertificate(HWND parent, LPBYTE cert, DWORD len) +{ + PCCERT_CONTEXT certContext = CertCreateCertificateContext(X509_ASN_ENCODING, + cert, len); + DWORD ret; + + if (certContext) + { + CRYPTUI_VIEWCERTIFICATE_STRUCTW view; + + memset(&view, 0, sizeof(view)); + view.hwndParent = parent; + view.pCertContext = certContext; + if (CryptUIDlgViewCertificateW(&view, NULL)) + ret = ERROR_SUCCESS; + else + ret = GetLastError(); + CertFreeCertificateContext(certContext); + } + else + ret = GetLastError(); + return ret; +} Index: dll/win32/wininet/inet_ntop.c =================================================================== --- dll/win32/wininet/inet_ntop.c (revision 56722) +++ dll/win32/wininet/inet_ntop.c (working copy) @@ -50,7 +50,8 @@ * Paul Vixie, 1996. */ const char * -inet_ntop(int af, const void *src, char *dst, size_t size) +__stdcall +inet_ntop(int af, void *src, char *dst, size_t size) { switch (af) { Index: dll/win32/wininet/internet.c =================================================================== --- dll/win32/wininet/internet.c (revision 56722) +++ dll/win32/wininet/internet.c (working copy) @@ -29,8 +29,6 @@ #include "config.h" #include "wine/port.h" -#define MAXHOSTNAME 100 /* from http.c */ - #if defined(__MINGW32__) || defined (_MSC_VER) #include #endif @@ -63,7 +61,6 @@ #include "winreg.h" #include "winuser.h" #include "wininet.h" -#include "winineti.h" #include "winnls.h" #include "wine/debug.h" #include "winerror.h" @@ -105,11 +102,14 @@ typedef struct { - DWORD dwProxyEnabled; - LPWSTR lpszProxyServer; - LPWSTR lpszProxyBypass; + DWORD proxyEnabled; + LPWSTR proxy; + LPWSTR proxyBypass; } proxyinfo_t; +static ULONG max_conns = 2, max_1_0_conns = 4; +static ULONG connect_timeout = 60000; + static const WCHAR szInternetSettings[] = { 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\', 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', @@ -289,36 +289,38 @@ g_dwTlsErrIndex = TlsAlloc(); - if (g_dwTlsErrIndex == TLS_OUT_OF_INDEXES) - return FALSE; + if (g_dwTlsErrIndex == TLS_OUT_OF_INDEXES) + return FALSE; +#ifndef __REACTOS__ + URLCacheContainers_CreateDefaults(); +#endif + WININET_hModule = hinstDLL; + break; case DLL_THREAD_ATTACH: - break; + break; case DLL_THREAD_DETACH: - if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES) - { - LPVOID lpwite = TlsGetValue(g_dwTlsErrIndex); - HeapFree(GetProcessHeap(), 0, lpwite); - } - break; + if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES) + { + heap_free(TlsGetValue(g_dwTlsErrIndex)); + } + break; case DLL_PROCESS_DETACH: - collect_connections(TRUE); + collect_connections(COLLECT_CLEANUP); NETCON_unload(); + URLCacheContainers_DeleteAll(); - URLCacheContainers_DeleteAll(); - - if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES) - { - HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex)); - TlsFree(g_dwTlsErrIndex); - } + if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES) + { + heap_free(TlsGetValue(g_dwTlsErrIndex)); + TlsFree(g_dwTlsErrIndex); + } break; } - return TRUE; } @@ -338,15 +340,15 @@ if ((ret = RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key ))) return ret; - if ((ret = RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE*)&lpwpi->dwProxyEnabled, sizeof(DWORD)))) + if ((ret = RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE*)&lpwpi->proxyEnabled, sizeof(DWORD)))) { RegCloseKey( key ); return ret; } - if (lpwpi->lpszProxyServer) + if (lpwpi->proxy) { - if ((ret = RegSetValueExW( key, szProxyServer, 0, REG_SZ, (BYTE*)lpwpi->lpszProxyServer, sizeof(WCHAR) * (lstrlenW(lpwpi->lpszProxyServer) + 1)))) + if ((ret = RegSetValueExW( key, szProxyServer, 0, REG_SZ, (BYTE*)lpwpi->proxy, sizeof(WCHAR) * (lstrlenW(lpwpi->proxy) + 1)))) { RegCloseKey( key ); return ret; @@ -495,14 +497,28 @@ static void FreeProxyInfo( proxyinfo_t *lpwpi ) { - HeapFree(GetProcessHeap(), 0, lpwpi->lpszProxyServer); - HeapFree(GetProcessHeap(), 0, lpwpi->lpszProxyBypass); + heap_free(lpwpi->proxy); + heap_free(lpwpi->proxyBypass); } +static proxyinfo_t *global_proxy; + +static void free_global_proxy( void ) +{ + EnterCriticalSection( &WININET_cs ); + if (global_proxy) + { + FreeProxyInfo( global_proxy ); + heap_free( global_proxy ); + } + LeaveCriticalSection( &WININET_cs ); +} + /*********************************************************************** * INTERNET_LoadProxySettings * - * Loads proxy information from the registry or environment into lpwpi. + * Loads proxy information from process-wide global settings, the registry, + * or the environment into lpwpi. * * The caller should call FreeProxyInfo when done with lpwpi. * @@ -517,21 +533,30 @@ LPCSTR envproxy; LONG ret; + EnterCriticalSection( &WININET_cs ); + if (global_proxy) + { + lpwpi->proxyEnabled = global_proxy->proxyEnabled; + lpwpi->proxy = heap_strdupW( global_proxy->proxy ); + lpwpi->proxyBypass = heap_strdupW( global_proxy->proxyBypass ); + } + LeaveCriticalSection( &WININET_cs ); + if ((ret = RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key ))) return ret; len = sizeof(DWORD); - if (RegQueryValueExW( key, szProxyEnable, NULL, &type, (BYTE *)&lpwpi->dwProxyEnabled, &len ) || type != REG_DWORD) + if (RegQueryValueExW( key, szProxyEnable, NULL, &type, (BYTE *)&lpwpi->proxyEnabled, &len ) || type != REG_DWORD) { - lpwpi->dwProxyEnabled = 0; - if((ret = RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE *)&lpwpi->dwProxyEnabled, sizeof(DWORD) ))) + lpwpi->proxyEnabled = 0; + if((ret = RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE *)&lpwpi->proxyEnabled, sizeof(DWORD) ))) { RegCloseKey( key ); return ret; } } - if (!(envproxy = getenv( "http_proxy" )) || lpwpi->dwProxyEnabled) + if (!(envproxy = getenv( "http_proxy" )) || lpwpi->proxyEnabled) { TRACE("Proxy is enabled.\n"); @@ -558,14 +583,14 @@ p = strchrW( szProxy, ' ' ); if (p) *p = 0; - lpwpi->lpszProxyServer = szProxy; + lpwpi->proxy = szProxy; - TRACE("http proxy = %s\n", debugstr_w(lpwpi->lpszProxyServer)); + TRACE("http proxy = %s\n", debugstr_w(lpwpi->proxy)); } else { TRACE("No proxy server settings in registry.\n"); - lpwpi->lpszProxyServer = NULL; + lpwpi->proxy = NULL; } } else if (envproxy) @@ -577,14 +602,14 @@ return ERROR_OUTOFMEMORY; MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, envproxyW, len ); - lpwpi->dwProxyEnabled = 1; - lpwpi->lpszProxyServer = envproxyW; + lpwpi->proxyEnabled = 1; + lpwpi->proxy = envproxyW; - TRACE("http proxy (from environment) = %s\n", debugstr_w(lpwpi->lpszProxyServer)); + TRACE("http proxy (from environment) = %s\n", debugstr_w(lpwpi->proxy)); } RegCloseKey( key ); - lpwpi->lpszProxyBypass = NULL; + lpwpi->proxyBypass = NULL; return ERROR_SUCCESS; } @@ -599,11 +624,49 @@ if (INTERNET_LoadProxySettings( &wpi )) return FALSE; - if (wpi.dwProxyEnabled) + if (wpi.proxyEnabled) { - lpwai->accessType = INTERNET_OPEN_TYPE_PROXY; - lpwai->proxy = wpi.lpszProxyServer; - return TRUE; + WCHAR proxyurl[INTERNET_MAX_URL_LENGTH]; + WCHAR username[INTERNET_MAX_USER_NAME_LENGTH]; + WCHAR password[INTERNET_MAX_PASSWORD_LENGTH]; + WCHAR hostname[INTERNET_MAX_HOST_NAME_LENGTH]; + URL_COMPONENTSW UrlComponents; + + UrlComponents.dwStructSize = sizeof UrlComponents; + UrlComponents.dwSchemeLength = 0; + UrlComponents.lpszHostName = hostname; + UrlComponents.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH; + UrlComponents.lpszUserName = username; + UrlComponents.dwUserNameLength = INTERNET_MAX_USER_NAME_LENGTH; + UrlComponents.lpszPassword = password; + UrlComponents.dwPasswordLength = INTERNET_MAX_PASSWORD_LENGTH; + UrlComponents.dwUrlPathLength = 0; + UrlComponents.dwExtraInfoLength = 0; + + if(InternetCrackUrlW(wpi.proxy, 0, 0, &UrlComponents)) + { + static const WCHAR szFormat[] = { 'h','t','t','p',':','/','/','%','s',':','%','u',0 }; + + if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER) + UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT; + sprintfW(proxyurl, szFormat, hostname, UrlComponents.nPort); + + lpwai->accessType = INTERNET_OPEN_TYPE_PROXY; + lpwai->proxy = heap_strdupW(proxyurl); + if (UrlComponents.dwUserNameLength) + { + lpwai->proxyUsername = heap_strdupW(UrlComponents.lpszUserName); + lpwai->proxyPassword = heap_strdupW(UrlComponents.lpszPassword); + } + + TRACE("http proxy = %s\n", debugstr_w(lpwai->proxy)); + return TRUE; + } + else + { + TRACE("Failed to parse proxy: %s\n", debugstr_w(wpi.proxy)); + lpwai->proxy = NULL; + } } lpwai->accessType = INTERNET_OPEN_TYPE_DIRECT; @@ -679,11 +742,11 @@ TRACE("%p\n",lpwai); - HeapFree(GetProcessHeap(), 0, lpwai->agent); - HeapFree(GetProcessHeap(), 0, lpwai->proxy); - HeapFree(GetProcessHeap(), 0, lpwai->proxyBypass); - HeapFree(GetProcessHeap(), 0, lpwai->proxyUsername); - HeapFree(GetProcessHeap(), 0, lpwai->proxyPassword); + heap_free(lpwai->agent); + heap_free(lpwai->proxy); + heap_free(lpwai->proxyBypass); + heap_free(lpwai->proxyUsername); + heap_free(lpwai->proxyPassword); } static DWORD APPINFO_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) @@ -745,6 +808,7 @@ } case INTERNET_OPTION_PROXY: + if(!size) return ERROR_INVALID_PARAMETER; if (unicode) { INTERNET_PROXY_INFOW *pi = (INTERNET_PROXY_INFOW *)buffer; DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0; @@ -812,20 +876,55 @@ *size = sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired; return ERROR_SUCCESS; } + + case INTERNET_OPTION_CONNECT_TIMEOUT: + TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n"); + + if (*size < sizeof(ULONG)) + return ERROR_INSUFFICIENT_BUFFER; + + *(ULONG*)buffer = ai->connect_timeout; + *size = sizeof(ULONG); + + return ERROR_SUCCESS; } return INET_QueryOption(hdr, option, buffer, size, unicode); } +static DWORD APPINFO_SetOption(object_header_t *hdr, DWORD option, void *buf, DWORD size) +{ + appinfo_t *ai = (appinfo_t*)hdr; + + switch(option) { + case INTERNET_OPTION_CONNECT_TIMEOUT: + TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n"); + + if(size != sizeof(connect_timeout)) + return ERROR_INTERNET_BAD_OPTION_LENGTH; + if(!*(ULONG*)buf) + return ERROR_BAD_ARGUMENTS; + + ai->connect_timeout = *(ULONG*)buf; + return ERROR_SUCCESS; + case INTERNET_OPTION_USER_AGENT: + heap_free(ai->agent); + if (!(ai->agent = heap_strdupW(buf))) return ERROR_OUTOFMEMORY; + return ERROR_SUCCESS; + } + + return INET_SetOption(hdr, option, buf, size); +} + static const object_vtbl_t APPINFOVtbl = { APPINFO_Destroy, NULL, APPINFO_QueryOption, + APPINFO_SetOption, NULL, NULL, NULL, NULL, - NULL, NULL }; @@ -884,6 +983,7 @@ lpwai->accessType = dwAccessType; lpwai->proxyUsername = NULL; lpwai->proxyPassword = NULL; + lpwai->connect_timeout = connect_timeout; lpwai->agent = heap_strdupW(lpszAgent); if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG) @@ -923,10 +1023,9 @@ rc = InternetOpenW(szAgent, dwAccessType, szProxy, szBypass, dwFlags); - HeapFree(GetProcessHeap(), 0, szAgent); - HeapFree(GetProcessHeap(), 0, szProxy); - HeapFree(GetProcessHeap(), 0, szBypass); - + heap_free(szAgent); + heap_free(szProxy); + heap_free(szBypass); return rc; } @@ -1091,10 +1190,8 @@ { WideCharToMultiByte(CP_ACP,0,lpwszConnectionName,-1,lpszConnectionName, dwNameLen, NULL, NULL); - - HeapFree(GetProcessHeap(),0,lpwszConnectionName); + heap_free(lpwszConnectionName); } - return rc; } @@ -1118,7 +1215,7 @@ HINTERNET rc = NULL; DWORD res = ERROR_SUCCESS; - TRACE("(%p, %s, %i, %s, %s, %i, %i, %lx)\n", hInternet, debugstr_w(lpszServerName), + TRACE("(%p, %s, %i, %s, %s, %i, %x, %lx)\n", hInternet, debugstr_w(lpszServerName), nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword), dwService, dwFlags, dwContext); @@ -1190,9 +1287,9 @@ rc = InternetConnectW(hInternet, szServerName, nServerPort, szUserName, szPassword, dwService, dwFlags, dwContext); - HeapFree(GetProcessHeap(), 0, szServerName); - HeapFree(GetProcessHeap(), 0, szUserName); - HeapFree(GetProcessHeap(), 0, szPassword); + heap_free(szServerName); + heap_free(szUserName); + heap_free(szPassword); return rc; } @@ -1439,13 +1536,13 @@ debugstr_an(lpUrlComponents->lpszUrlPath, lpUrlComponents->dwUrlPathLength), debugstr_an(lpUrlComponents->lpszExtraInfo, lpUrlComponents->dwExtraInfoLength)); } - HeapFree(GetProcessHeap(), 0, lpwszUrl); - HeapFree(GetProcessHeap(), 0, hostname); - HeapFree(GetProcessHeap(), 0, username); - HeapFree(GetProcessHeap(), 0, password); - HeapFree(GetProcessHeap(), 0, path); - HeapFree(GetProcessHeap(), 0, scheme); - HeapFree(GetProcessHeap(), 0, extra); + heap_free(lpwszUrl); + heap_free(hostname); + heap_free(username); + heap_free(password); + heap_free(path); + heap_free(scheme); + heap_free(extra); return ret; } @@ -1579,7 +1676,7 @@ url_tmp[dwUrlLength] = 0; if (!(lpszUrl_decode = heap_alloc(len * sizeof(WCHAR)))) { - HeapFree(GetProcessHeap(), 0, url_tmp); + heap_free(url_tmp); INTERNET_SetLastError(ERROR_OUTOFMEMORY); return FALSE; } @@ -1588,7 +1685,7 @@ dwUrlLength = len; lpszUrl = lpszUrl_decode; } - HeapFree(GetProcessHeap(), 0, url_tmp); + heap_free(url_tmp); } lpszap = lpszUrl; @@ -1846,7 +1943,7 @@ debugstr_wn(lpUC->lpszUrlPath,lpUC->dwUrlPathLength), debugstr_wn(lpUC->lpszExtraInfo,lpUC->dwExtraInfoLength)); - HeapFree(GetProcessHeap(), 0, lpszUrl_decode ); + heap_free( lpszUrl_decode ); return TRUE; } @@ -2051,7 +2148,7 @@ DWORD WINAPI InternetSetFilePointer(HINTERNET hFile, LONG lDistanceToMove, PVOID pReserved, DWORD dwMoveContext, DWORD_PTR dwContext) { - FIXME("stub\n"); + FIXME("(%p %d %p %d %lx): stub\n", hFile, lDistanceToMove, pReserved, dwMoveContext, dwContext); return FALSE; } @@ -2218,22 +2315,11 @@ return res == ERROR_SUCCESS; } -DWORD INET_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) +static DWORD query_global_option(DWORD option, void *buffer, DWORD *size, BOOL unicode) { - static BOOL warn = TRUE; - + /* FIXME: This function currently handles more options than it should. Options requiring + * proper handles should be moved to proper functions */ switch(option) { - case INTERNET_OPTION_REQUEST_FLAGS: - TRACE("INTERNET_OPTION_REQUEST_FLAGS\n"); - - if (*size < sizeof(ULONG)) - return ERROR_INSUFFICIENT_BUFFER; - - *(ULONG*)buffer = 4; - *size = sizeof(ULONG); - - return ERROR_SUCCESS; - case INTERNET_OPTION_HTTP_VERSION: if (*size < sizeof(HTTP_VERSION_INFO)) return ERROR_INSUFFICIENT_BUFFER; @@ -2248,10 +2334,8 @@ return ERROR_SUCCESS; case INTERNET_OPTION_CONNECTED_STATE: - if (warn) { - FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n"); - warn = FALSE; - } + FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n"); + if (*size < sizeof(ULONG)) return ERROR_INSUFFICIENT_BUFFER; @@ -2279,7 +2363,7 @@ if (*size < sizeof(ULONG)) return ERROR_INSUFFICIENT_BUFFER; - *(ULONG*)buffer = 2; + *(ULONG*)buffer = max_conns; *size = sizeof(ULONG); return ERROR_SUCCESS; @@ -2290,7 +2374,7 @@ if (*size < sizeof(ULONG)) return ERROR_INSUFFICIENT_BUFFER; - *(ULONG*)buffer = 4; + *(ULONG*)buffer = max_1_0_conns; *size = sizeof(ULONG); return ERROR_SUCCESS; @@ -2337,7 +2421,7 @@ switch (optionW->dwOption) { case INTERNET_PER_CONN_FLAGS: - if(pi.dwProxyEnabled) + if(pi.proxyEnabled) optionW->Value.dwValue = PROXY_TYPE_PROXY; else optionW->Value.dwValue = PROXY_TYPE_DIRECT; @@ -2345,16 +2429,16 @@ case INTERNET_PER_CONN_PROXY_SERVER: if (unicode) - optionW->Value.pszValue = heap_strdupW(pi.lpszProxyServer); + optionW->Value.pszValue = heap_strdupW(pi.proxy); else - optionA->Value.pszValue = heap_strdupWtoA(pi.lpszProxyServer); + optionA->Value.pszValue = heap_strdupWtoA(pi.proxy); break; case INTERNET_PER_CONN_PROXY_BYPASS: if (unicode) - optionW->Value.pszValue = heap_strdupW(pi.lpszProxyBypass); + optionW->Value.pszValue = heap_strdupW(pi.proxyBypass); else - optionA->Value.pszValue = heap_strdupWtoA(pi.lpszProxyBypass); + optionA->Value.pszValue = heap_strdupWtoA(pi.proxyBypass); break; case INTERNET_PER_CONN_AUTOCONFIG_URL: @@ -2377,19 +2461,36 @@ return res; } + case INTERNET_OPTION_REQUEST_FLAGS: case INTERNET_OPTION_USER_AGENT: + *size = 0; return ERROR_INTERNET_INCORRECT_HANDLE_TYPE; case INTERNET_OPTION_POLICY: return ERROR_INVALID_PARAMETER; + case INTERNET_OPTION_CONNECT_TIMEOUT: + TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n"); + + if (*size < sizeof(ULONG)) + return ERROR_INSUFFICIENT_BUFFER; + + *(ULONG*)buffer = connect_timeout; + *size = sizeof(ULONG); + + return ERROR_SUCCESS; + } + + FIXME("Stub for %d\n", option); + return ERROR_INTERNET_INCORRECT_HANDLE_TYPE; +} + +DWORD INET_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) +{ + switch(option) { case INTERNET_OPTION_CONTEXT_VALUE: - { - if (!hdr) - return ERROR_INTERNET_INCORRECT_HANDLE_TYPE; if (!size) return ERROR_INVALID_PARAMETER; - if (*size < sizeof(DWORD_PTR)) - { + if (*size < sizeof(DWORD_PTR)) { *size = sizeof(DWORD_PTR); return ERROR_INSUFFICIENT_BUFFER; } @@ -2399,11 +2500,20 @@ *(DWORD_PTR *)buffer = hdr->dwContext; *size = sizeof(DWORD_PTR); return ERROR_SUCCESS; + + case INTERNET_OPTION_REQUEST_FLAGS: + WARN("INTERNET_OPTION_REQUEST_FLAGS\n"); + *size = sizeof(DWORD); + return ERROR_INTERNET_INCORRECT_HANDLE_TYPE; + + case INTERNET_OPTION_MAX_CONNS_PER_SERVER: + case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER: + WARN("Called on global option %u\n", option); + return ERROR_INTERNET_INVALID_OPERATION; } - } - FIXME("Stub for %d\n", option); - return ERROR_INTERNET_INCORRECT_HANDLE_TYPE; + /* FIXME: we shouldn't call it here */ + return query_global_option(option, buffer, size, unicode); } /*********************************************************************** @@ -2431,7 +2541,7 @@ WININET_Release(hdr); } }else { - res = INET_QueryOption(NULL, dwOption, lpBuffer, lpdwBufferLength, TRUE); + res = query_global_option(dwOption, lpBuffer, lpdwBufferLength, TRUE); } if(res != ERROR_SUCCESS) @@ -2464,7 +2574,7 @@ WININET_Release(hdr); } }else { - res = INET_QueryOption(NULL, dwOption, lpBuffer, lpdwBufferLength, FALSE); + res = query_global_option(dwOption, lpBuffer, lpdwBufferLength, FALSE); } if(res != ERROR_SUCCESS) @@ -2472,7 +2582,70 @@ return res == ERROR_SUCCESS; } +DWORD INET_SetOption(object_header_t *hdr, DWORD option, void *buf, DWORD size) +{ + switch(option) { + case INTERNET_OPTION_CALLBACK: + WARN("Not settable option %u\n", option); + return ERROR_INTERNET_OPTION_NOT_SETTABLE; + case INTERNET_OPTION_MAX_CONNS_PER_SERVER: + case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER: + WARN("Called on global option %u\n", option); + return ERROR_INTERNET_INVALID_OPERATION; + } + return ERROR_INTERNET_INVALID_OPTION; +} + +static DWORD set_global_option(DWORD option, void *buf, DWORD size) +{ + switch(option) { + case INTERNET_OPTION_CALLBACK: + WARN("Not global option %u\n", option); + return ERROR_INTERNET_INCORRECT_HANDLE_TYPE; + + case INTERNET_OPTION_MAX_CONNS_PER_SERVER: + TRACE("INTERNET_OPTION_MAX_CONNS_PER_SERVER\n"); + + if(size != sizeof(max_conns)) + return ERROR_INTERNET_BAD_OPTION_LENGTH; + if(!*(ULONG*)buf) + return ERROR_BAD_ARGUMENTS; + + max_conns = *(ULONG*)buf; + return ERROR_SUCCESS; + + case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER: + TRACE("INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER\n"); + + if(size != sizeof(max_1_0_conns)) + return ERROR_INTERNET_BAD_OPTION_LENGTH; + if(!*(ULONG*)buf) + return ERROR_BAD_ARGUMENTS; + + max_1_0_conns = *(ULONG*)buf; + return ERROR_SUCCESS; + + case INTERNET_OPTION_CONNECT_TIMEOUT: + TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n"); + + if(size != sizeof(connect_timeout)) + return ERROR_INTERNET_BAD_OPTION_LENGTH; + if(!*(ULONG*)buf) + return ERROR_BAD_ARGUMENTS; + + connect_timeout = *(ULONG*)buf; + return ERROR_SUCCESS; + + case INTERNET_OPTION_SETTINGS_CHANGED: + FIXME("INTERNETOPTION_SETTINGS_CHANGED semi-stub\n"); + collect_connections(COLLECT_CONNECTIONS); + return ERROR_SUCCESS; + } + + return ERROR_INTERNET_INVALID_OPTION; +} + /*********************************************************************** * InternetSetOptionW (WININET.@) * @@ -2488,37 +2661,28 @@ { object_header_t *lpwhh; BOOL ret = TRUE; + DWORD res; TRACE("(%p %d %p %d)\n", hInternet, dwOption, lpBuffer, dwBufferLength); lpwhh = (object_header_t*) get_handle_object( hInternet ); - if(lpwhh && lpwhh->vtbl->SetOption) { - DWORD res; - + if(lpwhh) res = lpwhh->vtbl->SetOption(lpwhh, dwOption, lpBuffer, dwBufferLength); - if(res != ERROR_INTERNET_INVALID_OPTION) { - WININET_Release( lpwhh ); + else + res = set_global_option(dwOption, lpBuffer, dwBufferLength); - if(res != ERROR_SUCCESS) - SetLastError(res); + if(res != ERROR_INTERNET_INVALID_OPTION) { + if(lpwhh) + WININET_Release(lpwhh); - return res == ERROR_SUCCESS; - } + if(res != ERROR_SUCCESS) + SetLastError(res); + + return res == ERROR_SUCCESS; } switch (dwOption) { - case INTERNET_OPTION_CALLBACK: - { - if (!lpwhh) - { - SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - return FALSE; - } - WININET_Release(lpwhh); - SetLastError(ERROR_INTERNET_OPTION_NOT_SETTABLE); - return FALSE; - } case INTERNET_OPTION_HTTP_VERSION: { HTTP_VERSION_INFO* pVersion=(HTTP_VERSION_INFO*)lpBuffer; @@ -2539,9 +2703,52 @@ SetLastError(ERROR_INTERNET_BAD_OPTION_LENGTH); ret = FALSE; } else + TRACE("INTERNET_OPTION_ERROR_MASK: %x\n", *(ULONG*)lpBuffer); lpwhh->ErrorMask = *(ULONG*)lpBuffer; } break; + case INTERNET_OPTION_PROXY: + { + INTERNET_PROXY_INFOW *info = lpBuffer; + + if (!lpBuffer || dwBufferLength < sizeof(INTERNET_PROXY_INFOW)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + if (!hInternet) + { + EnterCriticalSection( &WININET_cs ); + free_global_proxy(); + global_proxy = heap_alloc( sizeof(proxyinfo_t) ); + if (global_proxy) + { + if (info->dwAccessType == INTERNET_OPEN_TYPE_PROXY) + { + global_proxy->proxyEnabled = 1; + global_proxy->proxy = heap_strdupW( info->lpszProxy ); + global_proxy->proxyBypass = heap_strdupW( info->lpszProxyBypass ); + } + else + { + global_proxy->proxyEnabled = 0; + global_proxy->proxy = global_proxy->proxyBypass = NULL; + } + } + LeaveCriticalSection( &WININET_cs ); + } + else + { + /* In general, each type of object should handle + * INTERNET_OPTION_PROXY directly. This FIXME ensures it doesn't + * get silently dropped. + */ + FIXME("INTERNET_OPTION_PROXY unimplemented\n"); + SetLastError(ERROR_INTERNET_INVALID_OPTION); + ret = FALSE; + } + break; + } case INTERNET_OPTION_CODEPAGE: { ULONG codepage = *(ULONG *)lpBuffer; @@ -2566,18 +2773,6 @@ FIXME("Option INTERNET_OPTION_DATA_RECEIVE_TIMEOUT (%d): STUB\n", receivetimeout); } break; - case INTERNET_OPTION_MAX_CONNS_PER_SERVER: - { - ULONG conns = *(ULONG *)lpBuffer; - FIXME("Option INTERNET_OPTION_MAX_CONNS_PER_SERVER (%d): STUB\n", conns); - } - break; - case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER: - { - ULONG conns = *(ULONG *)lpBuffer; - FIXME("Option INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER (%d): STUB\n", conns); - } - break; case INTERNET_OPTION_RESET_URLCACHE_SESSION: FIXME("Option INTERNET_OPTION_RESET_URLCACHE_SESSION: STUB\n"); break; @@ -2673,18 +2868,18 @@ switch (option->dwOption) { case INTERNET_PER_CONN_PROXY_SERVER: - HeapFree(GetProcessHeap(), 0, pi.lpszProxyServer); - pi.lpszProxyServer = heap_strdupW(option->Value.pszValue); + heap_free(pi.proxy); + pi.proxy = heap_strdupW(option->Value.pszValue); break; case INTERNET_PER_CONN_FLAGS: if(option->Value.dwValue & PROXY_TYPE_PROXY) - pi.dwProxyEnabled = 1; + pi.proxyEnabled = 1; else { if(option->Value.dwValue != PROXY_TYPE_DIRECT) FIXME("Unhandled flags: 0x%x\n", option->Value.dwValue); - pi.dwProxyEnabled = 0; + pi.proxyEnabled = 0; } break; @@ -2746,19 +2941,6 @@ switch( dwOption ) { - case INTERNET_OPTION_CALLBACK: - { - object_header_t *lpwh; - - if (!(lpwh = get_handle_object(hInternet))) - { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - return FALSE; - } - WININET_Release(lpwh); - INTERNET_SetLastError(ERROR_INTERNET_OPTION_NOT_SETTABLE); - return FALSE; - } case INTERNET_OPTION_PROXY: { LPINTERNET_PROXY_INFOA pi = (LPINTERNET_PROXY_INFOA) lpBuffer; @@ -2868,15 +3050,15 @@ case INTERNET_PER_CONN_PROXY_SERVER: case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL: case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL: - HeapFree( GetProcessHeap(), 0, opt->Value.pszValue ); + heap_free( opt->Value.pszValue ); break; default: break; } } - HeapFree( GetProcessHeap(), 0, list->pOptions ); + heap_free( list->pOptions ); } - HeapFree( GetProcessHeap(), 0, wbuffer ); + heap_free( wbuffer ); } return r; @@ -2993,7 +3175,7 @@ if (stringW) { ret = InternetTimeToSystemTimeW( stringW, time, reserved ); - HeapFree( GetProcessHeap(), 0, stringW ); + heap_free( stringW ); } return ret; } @@ -3100,7 +3282,7 @@ static const CHAR ping[] = "ping -c 1 "; static const CHAR redirect[] = " >/dev/null 2>/dev/null"; CHAR *command = NULL; - WCHAR hostW[1024]; + WCHAR hostW[INTERNET_MAX_HOST_NAME_LENGTH]; DWORD len; INTERNET_PORT port; int status = -1; @@ -3128,7 +3310,7 @@ ZeroMemory(&components,sizeof(URL_COMPONENTSW)); components.lpszHostName = (LPWSTR)hostW; - components.dwHostNameLength = 1024; + components.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH; if (!InternetCrackUrlW(lpszUrl,0,0,&components)) goto End; @@ -3177,8 +3359,7 @@ } End: - - HeapFree( GetProcessHeap(), 0, command ); + heap_free( command ); if (rc == FALSE) INTERNET_SetLastError(ERROR_NOT_CONNECTED); @@ -3209,7 +3390,7 @@ rc = InternetCheckConnectionW(url, dwFlags, dwReserved); - HeapFree(GetProcessHeap(), 0, url); + heap_free(url); return rc; } @@ -3226,8 +3407,12 @@ LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext) { URL_COMPONENTSW urlComponents; - WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024]; - WCHAR password[1024], path[2048], extra[1024]; + WCHAR protocol[INTERNET_MAX_SCHEME_LENGTH]; + WCHAR hostName[INTERNET_MAX_HOST_NAME_LENGTH]; + WCHAR userName[INTERNET_MAX_USER_NAME_LENGTH]; + WCHAR password[INTERNET_MAX_PASSWORD_LENGTH]; + WCHAR path[INTERNET_MAX_PATH_LENGTH]; + WCHAR extra[1024]; HINTERNET client = NULL, client1 = NULL; DWORD res; @@ -3236,15 +3421,15 @@ urlComponents.dwStructSize = sizeof(URL_COMPONENTSW); urlComponents.lpszScheme = protocol; - urlComponents.dwSchemeLength = 32; + urlComponents.dwSchemeLength = INTERNET_MAX_SCHEME_LENGTH; urlComponents.lpszHostName = hostName; - urlComponents.dwHostNameLength = MAXHOSTNAME; + urlComponents.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH; urlComponents.lpszUserName = userName; - urlComponents.dwUserNameLength = 1024; + urlComponents.dwUserNameLength = INTERNET_MAX_USER_NAME_LENGTH; urlComponents.lpszPassword = password; - urlComponents.dwPasswordLength = 1024; + urlComponents.dwPasswordLength = INTERNET_MAX_PASSWORD_LENGTH; urlComponents.lpszUrlPath = path; - urlComponents.dwUrlPathLength = 2048; + urlComponents.dwUrlPathLength = INTERNET_MAX_PATH_LENGTH; urlComponents.lpszExtraInfo = extra; urlComponents.dwExtraInfoLength = 1024; if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents)) @@ -3296,7 +3481,7 @@ strcpyW(path_extra, urlComponents.lpszUrlPath); strcatW(path_extra, urlComponents.lpszExtraInfo); client1 = HttpOpenRequestW(client, NULL, path_extra, NULL, NULL, accept, dwFlags, dwContext); - HeapFree(GetProcessHeap(), 0, path_extra); + heap_free(path_extra); } else client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext); @@ -3343,8 +3528,8 @@ INTERNET_InternetOpenUrlW(hIC, req->lpszUrl, req->lpszHeaders, req->dwHeadersLength, req->dwFlags, req->dwContext); - HeapFree(GetProcessHeap(), 0, req->lpszUrl); - HeapFree(GetProcessHeap(), 0, req->lpszHeaders); + heap_free(req->lpszUrl); + heap_free(req->lpszHeaders); } HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl, @@ -3430,7 +3615,7 @@ lenHeaders = MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, NULL, 0 ); szHeaders = heap_alloc(lenHeaders*sizeof(WCHAR)); if(!szHeaders) { - HeapFree(GetProcessHeap(), 0, szUrl); + heap_free(szUrl); return NULL; } MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, szHeaders, lenHeaders); @@ -3439,9 +3624,8 @@ rc = InternetOpenUrlW(hInternet, szUrl, szHeaders, lenHeaders, dwFlags, dwContext); - HeapFree(GetProcessHeap(), 0, szUrl); - HeapFree(GetProcessHeap(), 0, szHeaders); - + heap_free(szUrl); + heap_free(szHeaders); return rc; } @@ -3458,10 +3642,9 @@ if (!TlsSetValue(g_dwTlsErrIndex, lpwite)) { - HeapFree(GetProcessHeap(), 0, lpwite); + heap_free(lpwite); return NULL; } - return lpwite; } @@ -3521,14 +3704,14 @@ TRACE("\n"); workRequest = *lpRequest; - HeapFree(GetProcessHeap(), 0, lpRequest); + heap_free(lpRequest); workRequest.asyncproc(&workRequest); WININET_Release( workRequest.hdr ); if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES) { - HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex)); + heap_free(TlsGetValue(g_dwTlsErrIndex)); TlsSetValue(g_dwTlsErrIndex, NULL); } return TRUE; @@ -3559,10 +3742,9 @@ bSuccess = QueueUserWorkItem(INTERNET_WorkerThreadFunc, lpNewRequest, WT_EXECUTELONGFUNCTION); if (!bSuccess) { - HeapFree(GetProcessHeap(), 0, lpNewRequest); + heap_free(lpNewRequest); return ERROR_INTERNET_ASYNC_THREAD_FAILED; } - return ERROR_SUCCESS; } @@ -3595,6 +3777,7 @@ LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen) { + // ReactOS: use select instead of poll fd_set infd; struct timeval tv; BOOL bSuccess = FALSE; @@ -3661,13 +3844,13 @@ * data is available. */ BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile, - LPDWORD lpdwNumberOfBytesAvailble, + LPDWORD lpdwNumberOfBytesAvailable, DWORD dwFlags, DWORD_PTR dwContext) { object_header_t *hdr; DWORD res; - TRACE("(%p %p %x %lx)\n", hFile, lpdwNumberOfBytesAvailble, dwFlags, dwContext); + TRACE("(%p %p %x %lx)\n", hFile, lpdwNumberOfBytesAvailable, dwFlags, dwContext); hdr = get_handle_object( hFile ); if (!hdr) { @@ -3676,7 +3859,7 @@ } if(hdr->vtbl->QueryDataAvailable) { - res = hdr->vtbl->QueryDataAvailable(hdr, lpdwNumberOfBytesAvailble, dwFlags, dwContext); + res = hdr->vtbl->QueryDataAvailable(hdr, lpdwNumberOfBytesAvailable, dwFlags, dwContext); }else { WARN("wrong handle\n"); res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; @@ -4029,14 +4212,13 @@ if (ret) WideCharToMultiByte(CP_ACP, 0, urlW, -1, lpszUrl, *lpdwUrlLength + 1, NULL, NULL); - HeapFree(GetProcessHeap(), 0, urlCompW.lpszScheme); - HeapFree(GetProcessHeap(), 0, urlCompW.lpszHostName); - HeapFree(GetProcessHeap(), 0, urlCompW.lpszUserName); - HeapFree(GetProcessHeap(), 0, urlCompW.lpszPassword); - HeapFree(GetProcessHeap(), 0, urlCompW.lpszUrlPath); - HeapFree(GetProcessHeap(), 0, urlCompW.lpszExtraInfo); - HeapFree(GetProcessHeap(), 0, urlW); - + heap_free(urlCompW.lpszScheme); + heap_free(urlCompW.lpszHostName); + heap_free(urlCompW.lpszUserName); + heap_free(urlCompW.lpszPassword); + heap_free(urlCompW.lpszUrlPath); + heap_free(urlCompW.lpszExtraInfo); + heap_free(urlW); return ret; } @@ -4237,6 +4419,74 @@ return 0; } +/*********************************************************************** + * InternetGetSecurityInfoByURLA (WININET.@) + */ +BOOL WINAPI InternetGetSecurityInfoByURLA(LPSTR lpszURL, PCCERT_CHAIN_CONTEXT *ppCertChain, DWORD *pdwSecureFlags) +{ + WCHAR *url; + BOOL res; + + TRACE("(%s %p %p)\n", debugstr_a(lpszURL), ppCertChain, pdwSecureFlags); + + url = heap_strdupAtoW(lpszURL); + if(!url) + return FALSE; + + res = InternetGetSecurityInfoByURLW(url, ppCertChain, pdwSecureFlags); + heap_free(url); + return res; +} + +/*********************************************************************** + * InternetGetSecurityInfoByURLW (WININET.@) + */ +BOOL WINAPI InternetGetSecurityInfoByURLW(LPCWSTR lpszURL, PCCERT_CHAIN_CONTEXT *ppCertChain, DWORD *pdwSecureFlags) +{ + WCHAR hostname[INTERNET_MAX_HOST_NAME_LENGTH]; + URL_COMPONENTSW url = {sizeof(url)}; + server_t *server; + BOOL res = FALSE; + + TRACE("(%s %p %p)\n", debugstr_w(lpszURL), ppCertChain, pdwSecureFlags); + + url.lpszHostName = hostname; + url.dwHostNameLength = sizeof(hostname)/sizeof(WCHAR); + + res = InternetCrackUrlW(lpszURL, 0, 0, &url); + if(!res || url.nScheme != INTERNET_SCHEME_HTTPS) { + SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND); + return FALSE; + } + + if(url.nPort == INTERNET_INVALID_PORT_NUMBER) + url.nPort = INTERNET_DEFAULT_HTTPS_PORT; + + server = get_server(hostname, url.nPort, FALSE); + if(!server) { + SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND); + return FALSE; + } + + if(server->cert_chain) { + const CERT_CHAIN_CONTEXT *chain_dup; + + chain_dup = CertDuplicateCertificateChain(server->cert_chain); + if(chain_dup) { + *ppCertChain = chain_dup; + *pdwSecureFlags = server->security_flags & _SECURITY_ERROR_FLAGS_MASK; + }else { + res = FALSE; + } + }else { + SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND); + res = FALSE; + } + + server_release(server); + return res; +} + DWORD WINAPI InternetDialA( HWND hwndParent, LPSTR lpszConnectoid, DWORD dwFlags, DWORD_PTR* lpdwConnection, DWORD dwReserved ) { @@ -4290,3 +4540,9 @@ FIXME("(%p, %08lx) stub\n", a, b); return 0; } + +DWORD WINAPI ShowClientAuthCerts(HWND parent) +{ + FIXME("%p: stub\n", parent); + return 0; +} Index: dll/win32/wininet/internet.h =================================================================== --- dll/win32/wininet/internet.h (revision 56722) +++ dll/win32/wininet/internet.h (working copy) @@ -47,6 +47,12 @@ #define ioctlsocket ioctl #endif /* __MINGW32__ */ +/* ReactOS-specific definitions */ +#undef CP_UNIXCP +#define CP_UNIXCP CP_THREAD_ACP + +#include "winineti.h" + extern HMODULE WININET_hModule DECLSPEC_HIDDEN; #ifndef INET6_ADDRSTRLEN @@ -61,16 +67,24 @@ char addr_str[INET6_ADDRSTRLEN]; LONG ref; - DWORD64 keep_until; + DWORD security_flags; + const CERT_CHAIN_CONTEXT *cert_chain; + struct list entry; struct list conn_pool; } server_t; void server_addref(server_t*) DECLSPEC_HIDDEN; void server_release(server_t*) DECLSPEC_HIDDEN; -BOOL collect_connections(BOOL) DECLSPEC_HIDDEN; +typedef enum { + COLLECT_TIMEOUT, + COLLECT_CONNECTIONS, + COLLECT_CLEANUP +} collect_type_t; +BOOL collect_connections(collect_type_t) DECLSPEC_HIDDEN; + /* used for netconnection.c stuff */ typedef struct { @@ -79,6 +93,7 @@ void *ssl_s; server_t *server; DWORD security_flags; + BOOL mask_errors; BOOL keep_alive; DWORD64 keep_until; @@ -253,6 +268,7 @@ LPWSTR proxyUsername; LPWSTR proxyPassword; DWORD accessType; + DWORD connect_timeout; } appinfo_t; typedef struct @@ -260,11 +276,12 @@ object_header_t hdr; appinfo_t *appInfo; LPWSTR hostName; /* the final destination of the request */ - LPWSTR serverName; /* the name of the server we directly connect to */ LPWSTR userName; LPWSTR password; INTERNET_PORT hostPort; /* the final destination port of the request */ - INTERNET_PORT serverPort; /* the port of the server we directly connect to */ + DWORD connect_timeout; + DWORD send_timeout; + DWORD receive_timeout; } http_session_t; #define HDR_ISREQUEST 0x0001 @@ -300,12 +317,17 @@ { object_header_t hdr; http_session_t *session; + server_t *server; LPWSTR path; LPWSTR verb; LPWSTR rawHeaders; netconn_t *netconn; DWORD security_flags; + DWORD connect_timeout; + DWORD send_timeout; + DWORD receive_timeout; LPWSTR version; + DWORD status_code; LPWSTR statusText; DWORD bytesToWrite; DWORD bytesWritten; @@ -480,7 +502,8 @@ object_header_t *WININET_AddRef( object_header_t *info ) DECLSPEC_HIDDEN; BOOL WININET_Release( object_header_t *info ) DECLSPEC_HIDDEN; -DWORD INET_QueryOption( object_header_t *, DWORD, void *, DWORD *, BOOL ) DECLSPEC_HIDDEN; +DWORD INET_QueryOption(object_header_t*,DWORD,void*,DWORD*,BOOL) DECLSPEC_HIDDEN; +DWORD INET_SetOption(object_header_t*,DWORD,void*,DWORD) DECLSPEC_HIDDEN; time_t ConvertTimeString(LPCWSTR asctime) DECLSPEC_HIDDEN; @@ -515,10 +538,10 @@ DWORD dwStatusInfoLength) DECLSPEC_HIDDEN; BOOL INTERNET_FindProxyForProtocol(LPCWSTR szProxy, LPCWSTR proto, WCHAR *foundProxy, DWORD *foundProxyLen) DECLSPEC_HIDDEN; -DWORD create_netconn(BOOL,server_t*,DWORD,netconn_t**) DECLSPEC_HIDDEN; +DWORD create_netconn(BOOL,server_t*,DWORD,BOOL,DWORD,netconn_t**) DECLSPEC_HIDDEN; void free_netconn(netconn_t*) DECLSPEC_HIDDEN; void NETCON_unload(void) DECLSPEC_HIDDEN; -DWORD NETCON_secure_connect(netconn_t *connection, LPWSTR hostname) DECLSPEC_HIDDEN; +DWORD NETCON_secure_connect(netconn_t *connection) DECLSPEC_HIDDEN; DWORD NETCON_send(netconn_t *connection, const void *msg, size_t len, int flags, int *sent /* out */) DECLSPEC_HIDDEN; DWORD NETCON_recv(netconn_t *connection, void *buf, size_t len, int flags, @@ -527,9 +550,11 @@ BOOL NETCON_is_alive(netconn_t*) DECLSPEC_HIDDEN; LPCVOID NETCON_GetCert(netconn_t *connection) DECLSPEC_HIDDEN; int NETCON_GetCipherStrength(netconn_t*) DECLSPEC_HIDDEN; -DWORD NETCON_set_timeout(netconn_t *connection, BOOL send, int value) DECLSPEC_HIDDEN; +DWORD NETCON_set_timeout(netconn_t *connection, BOOL send, DWORD value) DECLSPEC_HIDDEN; #define sock_get_error(x) WSAGetLastError() +server_t *get_server(const WCHAR*,INTERNET_PORT,BOOL); + extern void URLCacheContainers_CreateDefaults(void) DECLSPEC_HIDDEN; extern void URLCacheContainers_DeleteAll(void) DECLSPEC_HIDDEN; @@ -542,4 +567,16 @@ const char* name; } wininet_flag_info; +/* Undocumented security flags */ +#define _SECURITY_FLAG_CERT_REV_FAILED 0x00800000 +#define _SECURITY_FLAG_CERT_INVALID_CA 0x01000000 +#define _SECURITY_FLAG_CERT_INVALID_CN 0x02000000 +#define _SECURITY_FLAG_CERT_INVALID_DATE 0x04000000 + +#define _SECURITY_ERROR_FLAGS_MASK \ + (_SECURITY_FLAG_CERT_REV_FAILED \ + |_SECURITY_FLAG_CERT_INVALID_CA \ + |_SECURITY_FLAG_CERT_INVALID_CN \ + |_SECURITY_FLAG_CERT_INVALID_DATE) + #endif /* _WINE_INTERNET_H_ */ Index: dll/win32/wininet/netconnection.c =================================================================== --- dll/win32/wininet/netconnection.c (revision 56722) +++ dll/win32/wininet/netconnection.c (working copy) @@ -80,7 +80,6 @@ #include "winbase.h" #include "wininet.h" #include "winerror.h" -#include "wincrypt.h" #include "wine/debug.h" #include "internet.h" @@ -114,7 +113,6 @@ static SSL_METHOD *meth; #endif static SSL_CTX *ctx; -static int hostname_idx; static int error_idx; static int conn_idx; @@ -210,105 +208,178 @@ if (malloced) free(buffer); else - HeapFree(GetProcessHeap(),0,buffer); + heap_free(buffer); return ret; } -static DWORD netconn_verify_cert(PCCERT_CONTEXT cert, HCERTSTORE store, - WCHAR *server, DWORD security_flags) +static DWORD netconn_verify_cert(netconn_t *conn, PCCERT_CONTEXT cert, HCERTSTORE store) { BOOL ret; CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } }; PCCERT_CHAIN_CONTEXT chain; char oid_server_auth[] = szOID_PKIX_KP_SERVER_AUTH; char *server_auth[] = { oid_server_auth }; - DWORD err = ERROR_SUCCESS, chainFlags = 0; + DWORD err = ERROR_SUCCESS, chainFlags = 0, errors; - TRACE("verifying %s\n", debugstr_w(server)); + static const DWORD supportedErrors = + CERT_TRUST_IS_NOT_TIME_VALID | + CERT_TRUST_IS_UNTRUSTED_ROOT | + CERT_TRUST_IS_PARTIAL_CHAIN | + CERT_TRUST_IS_OFFLINE_REVOCATION | + CERT_TRUST_REVOCATION_STATUS_UNKNOWN | + CERT_TRUST_IS_REVOKED | + CERT_TRUST_IS_NOT_VALID_FOR_USAGE; + + TRACE("verifying %s\n", debugstr_w(conn->server->name)); + chainPara.RequestedUsage.Usage.cUsageIdentifier = 1; chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = server_auth; - if (!(security_flags & SECURITY_FLAG_IGNORE_REVOCATION)) + if (!(conn->security_flags & SECURITY_FLAG_IGNORE_REVOCATION)) chainFlags |= CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT; - if ((ret = CertGetCertificateChain(NULL, cert, NULL, store, &chainPara, - chainFlags, NULL, &chain))) - { - if (chain->TrustStatus.dwErrorStatus) - { - static const DWORD supportedErrors = - CERT_TRUST_IS_NOT_TIME_VALID | - CERT_TRUST_IS_UNTRUSTED_ROOT | - CERT_TRUST_IS_OFFLINE_REVOCATION | - CERT_TRUST_REVOCATION_STATUS_UNKNOWN | - CERT_TRUST_IS_REVOKED | - CERT_TRUST_IS_NOT_VALID_FOR_USAGE; - if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID && - !(security_flags & SECURITY_FLAG_IGNORE_CERT_DATE_INVALID)) - err = ERROR_INTERNET_SEC_CERT_DATE_INVALID; - else if (chain->TrustStatus.dwErrorStatus & - CERT_TRUST_IS_UNTRUSTED_ROOT && - !(security_flags & SECURITY_FLAG_IGNORE_UNKNOWN_CA)) - err = ERROR_INTERNET_INVALID_CA; - else if (!(security_flags & SECURITY_FLAG_IGNORE_REVOCATION) && - ((chain->TrustStatus.dwErrorStatus & - CERT_TRUST_IS_OFFLINE_REVOCATION) || - (chain->TrustStatus.dwErrorStatus & - CERT_TRUST_REVOCATION_STATUS_UNKNOWN))) - err = ERROR_INTERNET_SEC_CERT_NO_REV; - else if (!(security_flags & SECURITY_FLAG_IGNORE_REVOCATION) && - (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED)) - err = ERROR_INTERNET_SEC_CERT_REVOKED; - else if (!(security_flags & SECURITY_FLAG_IGNORE_WRONG_USAGE) && - (chain->TrustStatus.dwErrorStatus & - CERT_TRUST_IS_NOT_VALID_FOR_USAGE)) - err = ERROR_INTERNET_SEC_INVALID_CERT; - else if (chain->TrustStatus.dwErrorStatus & ~supportedErrors) - err = ERROR_INTERNET_SEC_INVALID_CERT; + if (!(ret = CertGetCertificateChain(NULL, cert, NULL, store, &chainPara, chainFlags, NULL, &chain))) { + TRACE("failed\n"); + return GetLastError(); + } + + errors = chain->TrustStatus.dwErrorStatus; + + if (chain->TrustStatus.dwErrorStatus & ~supportedErrors) { + WARN("error status %x\n", chain->TrustStatus.dwErrorStatus & ~supportedErrors); + if(conn->mask_errors) + WARN("CERT_TRUST_IS_NOT_TIME_VALID, unknown error flags\n"); + err = conn->mask_errors && err ? ERROR_INTERNET_SEC_CERT_ERRORS : ERROR_INTERNET_SEC_INVALID_CERT; + errors &= supportedErrors; + } + + if(errors & CERT_TRUST_IS_NOT_TIME_VALID) { + WARN("CERT_TRUST_IS_NOT_TIME_VALID\n"); + if(conn->mask_errors) + conn->security_flags |= _SECURITY_FLAG_CERT_INVALID_DATE; + if(!(conn->security_flags & SECURITY_FLAG_IGNORE_CERT_DATE_INVALID)) + err = conn->mask_errors && err ? ERROR_INTERNET_SEC_CERT_ERRORS : ERROR_INTERNET_SEC_CERT_DATE_INVALID; + errors &= ~CERT_TRUST_IS_NOT_TIME_VALID; + } + + if(errors & CERT_TRUST_IS_UNTRUSTED_ROOT) { + WARN("CERT_TRUST_IS_UNTRUSTED_ROOT\n"); + if(conn->mask_errors) + WARN("CERT_TRUST_IS_UNTRUSTED_ROOT, unknown flags\n"); + if(!(conn->security_flags & SECURITY_FLAG_IGNORE_UNKNOWN_CA)) + err = conn->mask_errors && err ? ERROR_INTERNET_SEC_CERT_ERRORS : ERROR_INTERNET_INVALID_CA; + errors &= ~CERT_TRUST_IS_UNTRUSTED_ROOT; + } + + /* This seems strange, but that's what tests show */ + if(errors & CERT_TRUST_IS_PARTIAL_CHAIN) { + WARN("CERT_TRUST_IS_PARTIAL_CHAIN\n"); + if(!(conn->security_flags & SECURITY_FLAG_IGNORE_UNKNOWN_CA)) { + if(!(conn->security_flags & _SECURITY_FLAG_CERT_REV_FAILED)) + err = conn->mask_errors && err ? ERROR_INTERNET_SEC_CERT_ERRORS : ERROR_INTERNET_SEC_CERT_REV_FAILED; + else + err = conn->mask_errors ? ERROR_INTERNET_SEC_CERT_ERRORS : ERROR_INTERNET_INVALID_CA; } - if (!err) - { - CERT_CHAIN_POLICY_PARA policyPara; - SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslExtraPolicyPara; - CERT_CHAIN_POLICY_STATUS policyStatus; - CERT_CHAIN_CONTEXT chainCopy; + if(conn->mask_errors) { + if(!(conn->security_flags & _SECURITY_FLAG_CERT_REV_FAILED)) + conn->security_flags |= _SECURITY_FLAG_CERT_REV_FAILED; + else + conn->security_flags |= _SECURITY_FLAG_CERT_INVALID_CA; + } + errors &= ~CERT_TRUST_IS_PARTIAL_CHAIN; + } - /* Clear chain->TrustStatus.dwErrorStatus so - * CertVerifyCertificateChainPolicy will verify additional checks - * rather than stopping with an existing, ignored error. - */ - memcpy(&chainCopy, chain, sizeof(chainCopy)); - chainCopy.TrustStatus.dwErrorStatus = 0; - sslExtraPolicyPara.u.cbSize = sizeof(sslExtraPolicyPara); - sslExtraPolicyPara.dwAuthType = AUTHTYPE_SERVER; - sslExtraPolicyPara.pwszServerName = server; - sslExtraPolicyPara.fdwChecks = security_flags; - policyPara.cbSize = sizeof(policyPara); - policyPara.dwFlags = 0; - policyPara.pvExtraPolicyPara = &sslExtraPolicyPara; - ret = CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, + if(errors & (CERT_TRUST_IS_OFFLINE_REVOCATION | CERT_TRUST_REVOCATION_STATUS_UNKNOWN)) { + WARN("CERT_TRUST_IS_OFFLINE_REVOCATION | CERT_TRUST_REVOCATION_STATUS_UNKNOWN\n"); + if(conn->mask_errors) + WARN("TRUST_IS_OFFLINE_REVOCATION | CERT_TRUST_REVOCATION_STATUS_UNKNOWN, unknown error flags\n"); + if(!(conn->security_flags & SECURITY_FLAG_IGNORE_REVOCATION)) + err = conn->mask_errors && err ? ERROR_INTERNET_SEC_CERT_ERRORS : ERROR_INTERNET_SEC_CERT_NO_REV; + errors &= ~(CERT_TRUST_IS_OFFLINE_REVOCATION | CERT_TRUST_REVOCATION_STATUS_UNKNOWN); + } + + if(errors & CERT_TRUST_IS_REVOKED) { + WARN("CERT_TRUST_IS_REVOKED\n"); + if(conn->mask_errors) + WARN("TRUST_IS_OFFLINE_REVOCATION | CERT_TRUST_REVOCATION_STATUS_UNKNOWN, unknown error flags\n"); + if(!(conn->security_flags & SECURITY_FLAG_IGNORE_REVOCATION)) + err = conn->mask_errors && err ? ERROR_INTERNET_SEC_CERT_ERRORS : ERROR_INTERNET_SEC_CERT_REVOKED; + errors &= ~CERT_TRUST_IS_REVOKED; + } + + if(errors & CERT_TRUST_IS_NOT_VALID_FOR_USAGE) { + WARN("CERT_TRUST_IS_NOT_VALID_FOR_USAGE\n"); + if(conn->mask_errors) + WARN("CERT_TRUST_IS_NOT_VALID_FOR_USAGE, unknown error flags\n"); + if(!(conn->security_flags & SECURITY_FLAG_IGNORE_WRONG_USAGE)) + err = conn->mask_errors && err ? ERROR_INTERNET_SEC_CERT_ERRORS : ERROR_INTERNET_SEC_INVALID_CERT; + errors &= ~CERT_TRUST_IS_NOT_VALID_FOR_USAGE; + } + + if(!err || conn->mask_errors) { + CERT_CHAIN_POLICY_PARA policyPara; + SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslExtraPolicyPara; + CERT_CHAIN_POLICY_STATUS policyStatus; + CERT_CHAIN_CONTEXT chainCopy; + + /* Clear chain->TrustStatus.dwErrorStatus so + * CertVerifyCertificateChainPolicy will verify additional checks + * rather than stopping with an existing, ignored error. + */ + memcpy(&chainCopy, chain, sizeof(chainCopy)); + chainCopy.TrustStatus.dwErrorStatus = 0; + sslExtraPolicyPara.u.cbSize = sizeof(sslExtraPolicyPara); + sslExtraPolicyPara.dwAuthType = AUTHTYPE_SERVER; + sslExtraPolicyPara.pwszServerName = conn->server->name; + sslExtraPolicyPara.fdwChecks = conn->security_flags; + policyPara.cbSize = sizeof(policyPara); + policyPara.dwFlags = 0; + policyPara.pvExtraPolicyPara = &sslExtraPolicyPara; + ret = CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, &chainCopy, &policyPara, &policyStatus); - /* Any error in the policy status indicates that the - * policy couldn't be verified. - */ - if (ret && policyStatus.dwError) - { - if (policyStatus.dwError == CERT_E_CN_NO_MATCH) - err = ERROR_INTERNET_SEC_CERT_CN_INVALID; - else - err = ERROR_INTERNET_SEC_INVALID_CERT; + /* Any error in the policy status indicates that the + * policy couldn't be verified. + */ + if(ret) { + if(policyStatus.dwError == CERT_E_CN_NO_MATCH) { + WARN("CERT_E_CN_NO_MATCH\n"); + if(conn->mask_errors) + conn->security_flags |= _SECURITY_FLAG_CERT_INVALID_CN; + err = conn->mask_errors && err ? ERROR_INTERNET_SEC_CERT_ERRORS : ERROR_INTERNET_SEC_CERT_CN_INVALID; + }else if(policyStatus.dwError) { + WARN("policyStatus.dwError %x\n", policyStatus.dwError); + if(conn->mask_errors) + WARN("unknown error flags for policy status %x\n", policyStatus.dwError); + err = conn->mask_errors && err ? ERROR_INTERNET_SEC_CERT_ERRORS : ERROR_INTERNET_SEC_INVALID_CERT; } + }else { + err = GetLastError(); } + } + + if(err) { + WARN("failed %u\n", err); CertFreeCertificateChain(chain); + if(conn->server->cert_chain) { + CertFreeCertificateChain(conn->server->cert_chain); + conn->server->cert_chain = NULL; + } + if(conn->mask_errors) + conn->server->security_flags |= conn->security_flags & _SECURITY_ERROR_FLAGS_MASK; + return err; } - TRACE("returning %08x\n", err); - return err; + + /* FIXME: Reuse cached chain */ + if(conn->server->cert_chain) + CertFreeCertificateChain(chain); + else + conn->server->cert_chain = chain; + return ERROR_SUCCESS; } static int netconn_secure_verify(int preverify_ok, X509_STORE_CTX *ctx) { SSL *ssl; - WCHAR *server; BOOL ret = FALSE; HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL); @@ -316,7 +387,6 @@ ssl = pX509_STORE_CTX_get_ex_data(ctx, pSSL_get_ex_data_X509_STORE_CTX_idx()); - server = pSSL_get_ex_data(ssl, hostname_idx); conn = pSSL_get_ex_data(ssl, conn_idx); if (store) { @@ -333,20 +403,15 @@ cert = (X509 *)psk_value(chain, i); if ((context = X509_to_cert_context(cert))) { - if (i == 0) - ret = CertAddCertificateContextToStore(store, context, - CERT_STORE_ADD_ALWAYS, &endCert); - else - ret = CertAddCertificateContextToStore(store, context, - CERT_STORE_ADD_ALWAYS, NULL); + ret = CertAddCertificateContextToStore(store, context, + CERT_STORE_ADD_ALWAYS, i ? NULL : &endCert); CertFreeCertificateContext(context); } } if (!endCert) ret = FALSE; if (ret) { - DWORD_PTR err = netconn_verify_cert(endCert, store, server, - conn->security_flags); + DWORD_PTR err = netconn_verify_cert(conn, endCert, store); if (err) { @@ -460,12 +525,6 @@ return ERROR_OUTOFMEMORY; } - hostname_idx = pSSL_get_ex_new_index(0, (void *)"hostname index", NULL, NULL, NULL); - if(hostname_idx == -1) { - ERR("SSL_get_ex_new_index failed; %s\n", pERR_error_string(pERR_get_error(), 0)); - return ERROR_OUTOFMEMORY; - } - error_idx = pSSL_get_ex_new_index(0, (void *)"error index", NULL, NULL, NULL); if(error_idx == -1) { ERR("SSL_get_ex_new_index failed; %s\n", pERR_error_string(pERR_get_error(), 0)); @@ -482,12 +541,15 @@ pCRYPTO_set_id_callback(ssl_thread_id); num_ssl_locks = pCRYPTO_num_locks(); - ssl_locks = HeapAlloc(GetProcessHeap(), 0, num_ssl_locks * sizeof(CRITICAL_SECTION)); + ssl_locks = heap_alloc(num_ssl_locks * sizeof(CRITICAL_SECTION)); if(!ssl_locks) return ERROR_OUTOFMEMORY; for(i = 0; i < num_ssl_locks; i++) + { InitializeCriticalSection(&ssl_locks[i]); + ssl_locks[i].DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ssl_locks"); + } pCRYPTO_set_locking_callback(ssl_lock_callback); return ERROR_SUCCESS; @@ -497,7 +559,7 @@ #endif } -DWORD create_netconn(BOOL useSSL, server_t *server, DWORD security_flags, netconn_t **ret) +DWORD create_netconn(BOOL useSSL, server_t *server, DWORD security_flags, BOOL mask_errors, DWORD timeout, netconn_t **ret) { netconn_t *netconn; int result, flag; @@ -520,15 +582,50 @@ netconn->useSSL = useSSL; netconn->socketFD = -1; - netconn->security_flags = security_flags; + netconn->security_flags = security_flags | server->security_flags; + netconn->mask_errors = mask_errors; list_init(&netconn->pool_entry); assert(server->addr_len); result = netconn->socketFD = socket(server->addr.ss_family, SOCK_STREAM, 0); if(result != -1) { + flag = 1; + ioctlsocket(netconn->socketFD, FIONBIO, &flag); result = connect(netconn->socketFD, (struct sockaddr*)&server->addr, server->addr_len); if(result == -1) + { + if (sock_get_error(errno) == WSAEINPROGRESS) { + // ReactOS: use select instead of poll + fd_set outfd; + struct timeval tv; + int res; + + FD_ZERO(&outfd); + FD_SET(netconn->socketFD, &outfd); + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + res = select(0, NULL, &outfd, NULL, &tv); + if (!res) + { + closesocket(netconn->socketFD); + heap_free(netconn); + return ERROR_INTERNET_CANNOT_CONNECT; + } + else if (res > 0) + { + int err; + socklen_t len = sizeof(err); + if (!getsockopt(netconn->socketFD, SOL_SOCKET, SO_ERROR, &err, &len) && !err) + result = 0; + } + } + } + if(result == -1) closesocket(netconn->socketFD); + else { + flag = 0; + ioctlsocket(netconn->socketFD, FIONBIO, &flag); + } } if(result == -1) { heap_free(netconn); @@ -581,13 +678,17 @@ if (ssl_locks) { int i; - for (i = 0; i < num_ssl_locks; i++) DeleteCriticalSection(&ssl_locks[i]); - HeapFree(GetProcessHeap(), 0, ssl_locks); + for (i = 0; i < num_ssl_locks; i++) + { + ssl_locks[i].DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&ssl_locks[i]); + } + heap_free(ssl_locks); } #endif } -#if 0 +#ifndef __REACTOS__ /* translate a unix error code into a winsock one */ int sock_get_error( int err ) { @@ -660,12 +761,13 @@ * NETCON_secure_connect * Initiates a secure connection over an existing plaintext connection. */ -DWORD NETCON_secure_connect(netconn_t *connection, LPWSTR hostname) +DWORD NETCON_secure_connect(netconn_t *connection) { + DWORD res = ERROR_NOT_SUPPORTED; +#ifdef SONAME_LIBSSL void *ssl_s; - DWORD res = ERROR_NOT_SUPPORTED; + int bits; -#ifdef SONAME_LIBSSL /* can't connect if we are already connected */ if (connection->ssl_s) { @@ -689,13 +791,6 @@ goto fail; } - if (!pSSL_set_ex_data(ssl_s, hostname_idx, hostname)) - { - ERR("SSL_set_ex_data failed: %s\n", - pERR_error_string(pERR_get_error(), 0)); - res = ERROR_INTERNET_SECURITY_CHANNEL_ERROR; - goto fail; - } if (!pSSL_set_ex_data(ssl_s, conn_idx, connection)) { ERR("SSL_set_ex_data failed: %s\n", @@ -713,6 +808,18 @@ } connection->ssl_s = ssl_s; + + bits = NETCON_GetCipherStrength(connection); + if (bits >= 128) + connection->security_flags |= SECURITY_FLAG_STRENGTH_STRONG; + else if (bits >= 56) + connection->security_flags |= SECURITY_FLAG_STRENGTH_MEDIUM; + else + connection->security_flags |= SECURITY_FLAG_STRENGTH_WEAK; + connection->security_flags |= SECURITY_FLAG_SECURE; + + if(connection->mask_errors) + connection->server->security_flags = connection->security_flags; return ERROR_SUCCESS; fail: @@ -895,24 +1002,29 @@ #endif } -DWORD NETCON_set_timeout(netconn_t *connection, BOOL send, int value) +DWORD NETCON_set_timeout(netconn_t *connection, BOOL send, DWORD value) { int result; struct timeval tv; /* value is in milliseconds, convert to struct timeval */ - tv.tv_sec = value / 1000; - tv.tv_usec = (value % 1000) * 1000; - + if (value == INFINITE) + { + tv.tv_sec = 0; + tv.tv_usec = 0; + } + else + { + tv.tv_sec = value / 1000; + tv.tv_usec = (value % 1000) * 1000; + } result = setsockopt(connection->socketFD, SOL_SOCKET, send ? SO_SNDTIMEO : SO_RCVTIMEO, (void*)&tv, sizeof(tv)); - if (result == -1) { WARN("setsockopt failed (%s)\n", strerror(errno)); return sock_get_error(errno); } - return ERROR_SUCCESS; } Index: dll/win32/wininet/urlcache.c =================================================================== --- dll/win32/wininet/urlcache.c (revision 56722) +++ dll/win32/wininet/urlcache.c (working copy) @@ -60,18 +60,25 @@ WINE_DEFAULT_DEBUG_CHANNEL(wininet); -#define ENTRY_START_OFFSET 0x4000 -#define DIR_LENGTH 8 -#define BLOCKSIZE 128 -#define HASHTABLE_SIZE 448 -#define HASHTABLE_BLOCKSIZE 7 -#define HASHTABLE_FREE 3 +#define ENTRY_START_OFFSET 0x4000 +#define DIR_LENGTH 8 +#define BLOCKSIZE 128 +#define HASHTABLE_SIZE 448 +#define HASHTABLE_NUM_ENTRIES 64 /* this needs to be power of 2, that divides HASHTABLE_SIZE */ +#define HASHTABLE_BLOCKSIZE (HASHTABLE_SIZE / HASHTABLE_NUM_ENTRIES) #define ALLOCATION_TABLE_OFFSET 0x250 -#define ALLOCATION_TABLE_SIZE (0x1000 - ALLOCATION_TABLE_OFFSET) -#define HASHTABLE_NUM_ENTRIES (HASHTABLE_SIZE / HASHTABLE_BLOCKSIZE) -#define NEWFILE_NUM_BLOCKS 0xd80 -#define NEWFILE_SIZE (NEWFILE_NUM_BLOCKS * BLOCKSIZE + ENTRY_START_OFFSET) +#define ALLOCATION_TABLE_SIZE (ENTRY_START_OFFSET - ALLOCATION_TABLE_OFFSET) +#define MIN_BLOCK_NO 0x80 +#define MAX_BLOCK_NO (ALLOCATION_TABLE_SIZE * 8) +#define FILE_SIZE(blocks) ((blocks) * BLOCKSIZE + ENTRY_START_OFFSET) +#define HASHTABLE_URL 0 +#define HASHTABLE_DEL 1 +#define HASHTABLE_LOCK 2 +#define HASHTABLE_FREE 3 +#define HASHTABLE_REDR 5 +#define HASHTABLE_FLAG_BITS 5 + #define DWORD_SIG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24)) #define URL_SIGNATURE DWORD_SIG('U','R','L',' ') #define REDR_SIGNATURE DWORD_SIG('R','E','D','R') @@ -182,6 +189,7 @@ /* List of all containers available */ static struct list UrlContainers = LIST_INIT(UrlContainers); +// ReactOS r54992 BOOL bDefaultContainersAdded = FALSE; static DWORD URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash, HASH_CACHEFILE_ENTRY **ppHash); @@ -216,11 +224,11 @@ * Any other Win32 error code if failed * */ -static DWORD URLCacheContainer_OpenIndex(URLCACHECONTAINER * pContainer) +static DWORD URLCacheContainer_OpenIndex(URLCACHECONTAINER * pContainer, DWORD blocks_no) { HANDLE hFile; WCHAR wszFilePath[MAX_PATH]; - DWORD dwFileSize; + DWORD dwFileSize, new_file_size; static const WCHAR wszIndex[] = {'i','n','d','e','x','.','d','a','t',0}; static const WCHAR wszMappingFormat[] = {'%','s','%','s','_','%','l','u',0}; @@ -256,7 +264,13 @@ return GetLastError(); } - if (dwFileSize == 0) + if (blocks_no < MIN_BLOCK_NO) + blocks_no = MIN_BLOCK_NO; + else if (blocks_no > MAX_BLOCK_NO) + blocks_no = MAX_BLOCK_NO; + new_file_size = FILE_SIZE(blocks_no); + + if (dwFileSize < new_file_size) { static const CHAR szCacheContent[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Content"; HKEY key; @@ -264,17 +278,21 @@ DWORD dwOffset; DWORD dwError = ERROR_SUCCESS; + if (SetFilePointer(hFile, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER) + dwError = GetLastError(); + /* Write zeroes to the entire file so we can safely map it without * fear of getting a SEGV because the disk is full. */ memset(achZeroes, 0, sizeof(achZeroes)); - for (dwOffset = 0; dwOffset < NEWFILE_SIZE; dwOffset += sizeof(achZeroes)) + for (dwOffset = dwFileSize; dwOffsetdwFileSize = new_file_size; + pHeader->dwIndexCapacityInBlocks = blocks_no; + } + else if (pHeader) + { WCHAR *pwchDir; WCHAR wszDirPath[MAX_PATH]; FILETIME ft; int i, j; HASH_CACHEFILE_ENTRY *pHashEntry; - dwFileSize = NEWFILE_SIZE; - /* First set some constants and defaults in the header */ strcpy(pHeader->szSignature, "WINE URLCache Ver 0.2005001"); - pHeader->dwFileSize = dwFileSize; - pHeader->dwIndexCapacityInBlocks = NEWFILE_NUM_BLOCKS; + pHeader->dwFileSize = new_file_size; + pHeader->dwIndexCapacityInBlocks = blocks_no; /* 127MB - taken from default for Windows 2000 */ pHeader->CacheLimit.QuadPart = 0x07ff5400; /* Copied from a Windows 2000 cache index */ @@ -403,6 +422,7 @@ { dwError = GetLastError(); } + dwFileSize = new_file_size; CloseHandle(hMapping); } else @@ -421,6 +441,7 @@ } + pContainer->file_size = dwFileSize; wsprintfW(wszFilePath, wszMappingFormat, pContainer->path, wszIndex, dwFileSize); URLCache_PathToObjectName(wszFilePath, '_'); pContainer->hMapping = OpenFileMappingW(FILE_MAP_WRITE, FALSE, wszFilePath); @@ -470,15 +491,15 @@ pContainer->path = heap_strdupW(path); if (!pContainer->path) { - HeapFree(GetProcessHeap(), 0, pContainer); + heap_free(pContainer); return FALSE; } pContainer->cache_prefix = heap_alloc((cache_prefix_len + 1) * sizeof(WCHAR)); if (!pContainer->cache_prefix) { - HeapFree(GetProcessHeap(), 0, pContainer->path); - HeapFree(GetProcessHeap(), 0, pContainer); + heap_free(pContainer->path); + heap_free(pContainer); return FALSE; } @@ -490,8 +511,8 @@ if ((pContainer->hMutex = CreateMutexW(NULL, FALSE, mutex_name)) == NULL) { ERR("couldn't create mutex (error is %d)\n", GetLastError()); - HeapFree(GetProcessHeap(), 0, pContainer->path); - HeapFree(GetProcessHeap(), 0, pContainer); + heap_free(pContainer->path); + heap_free(pContainer); return FALSE; } @@ -506,9 +527,9 @@ URLCacheContainer_CloseIndex(pContainer); CloseHandle(pContainer->hMutex); - HeapFree(GetProcessHeap(), 0, pContainer->path); - HeapFree(GetProcessHeap(), 0, pContainer->cache_prefix); - HeapFree(GetProcessHeap(), 0, pContainer); + heap_free(pContainer->path); + heap_free(pContainer->cache_prefix); + heap_free(pContainer); } void URLCacheContainers_CreateDefaults(void) @@ -519,7 +540,6 @@ static const WCHAR HistoryPrefix[] = {'V','i','s','i','t','e','d',':',0}; static const WCHAR CookieSuffix[] = {0}; static const WCHAR CookiePrefix[] = {'C','o','o','k','i','e',':',0}; - static const WCHAR UserProfile[] = {'U','S','E','R','P','R','O','F','I','L','E',0}; static const struct { int nFolder; /* CSIDL_* constant */ @@ -533,12 +553,6 @@ }; DWORD i; - if (GetEnvironmentVariableW(UserProfile, NULL, 0) == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND) - { - TRACE("Environment variable 'USERPROFILE' does not exist!\n"); - return; - } - for (i = 0; i < sizeof(DefaultContainerData) / sizeof(DefaultContainerData[0]); i++) { WCHAR wszCachePath[MAX_PATH]; @@ -592,6 +606,7 @@ if(!lpwszUrl) return ERROR_INVALID_PARAMETER; + // ReactOS r54992 if (!bDefaultContainersAdded) URLCacheContainers_CreateDefaults(); @@ -618,7 +633,7 @@ return ERROR_OUTOFMEMORY; ret = URLCacheContainers_FindContainerW(url, ppContainer); - HeapFree(GetProcessHeap(), 0, url); + heap_free(url); return ret; } @@ -633,6 +648,7 @@ if (lpwszSearchPattern && dwIndex > 0) return FALSE; + // ReactOS r54992 if (!bDefaultContainersAdded) URLCacheContainers_CreateDefaults(); @@ -697,7 +713,7 @@ { UnmapViewOfFile( pHeader ); URLCacheContainer_CloseIndex(pContainer); - error = URLCacheContainer_OpenIndex(pContainer); + error = URLCacheContainer_OpenIndex(pContainer, MIN_BLOCK_NO); if (error != ERROR_SUCCESS) { ReleaseMutex(pContainer->hMutex); @@ -736,7 +752,44 @@ return UnmapViewOfFile(pHeader); } +/*********************************************************************** + * URLCacheContainer_CleanIndex (Internal) + * + * This function is meant to make place in index file by removing old + * entries and resizing the file. + * + * CAUTION: file view may get mapped to new memory + * TODO: implement entries cleaning + * + * RETURNS + * ERROR_SUCCESS when new memory is available + * error code otherwise + */ +static DWORD URLCacheContainer_CleanIndex(URLCACHECONTAINER *container, URLCACHE_HEADER **file_view) +{ + URLCACHE_HEADER *header = *file_view; + DWORD ret; + FIXME("(%s %s) semi-stub\n", debugstr_w(container->cache_prefix), debugstr_w(container->path)); + + if(header->dwFileSize >= ALLOCATION_TABLE_SIZE*8*BLOCKSIZE + ENTRY_START_OFFSET) { + WARN("index file has maximal size\n"); + return ERROR_NOT_ENOUGH_MEMORY; + } + + URLCacheContainer_CloseIndex(container); + ret = URLCacheContainer_OpenIndex(container, header->dwIndexCapacityInBlocks*2); + if(ret != ERROR_SUCCESS) + return ret; + header = MapViewOfFile(container->hMapping, FILE_MAP_WRITE, 0, 0, 0); + if(!header) + return GetLastError(); + + UnmapViewOfFile(*file_view); + *file_view = header; + return ERROR_SUCCESS; +} + #ifndef CHAR_BIT #define CHAR_BIT (8 * sizeof(CHAR)) #endif @@ -794,11 +847,11 @@ * sets ppEntry to point to it. * * RETURNS - * TRUE if it had enough space - * FALSE if it couldn't find enough space + * ERROR_SUCCESS when free memory block was found + * Any other Win32 error code if the entry could not be added * */ -static BOOL URLCache_FindFirstFreeEntry(URLCACHE_HEADER * pHeader, DWORD dwBlocksNeeded, CACHEFILE_ENTRY ** ppEntry) +static DWORD URLCache_FindFirstFreeEntry(URLCACHE_HEADER * pHeader, DWORD dwBlocksNeeded, CACHEFILE_ENTRY ** ppEntry) { LPBYTE AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET; DWORD dwBlockNumber; @@ -819,12 +872,14 @@ for (index = 0; index < dwBlocksNeeded; index++) URLCache_Allocation_BlockAllocate(AllocationTable, dwBlockNumber + index); *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE); + for (index = 0; index < dwBlocksNeeded * BLOCKSIZE / sizeof(DWORD); index++) + ((DWORD*)*ppEntry)[index] = 0xdeadbeef; (*ppEntry)->dwBlocksUsed = dwBlocksNeeded; - return TRUE; + return ERROR_SUCCESS; } } - FIXME("Grow file\n"); - return FALSE; + + return ERROR_HANDLE_DISK_FULL; } /*********************************************************************** @@ -844,11 +899,10 @@ BYTE * AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET; /* update allocation table */ - dwStartBlock = ((DWORD)((BYTE *)pEntry - (BYTE *)pHeader)) / BLOCKSIZE; + dwStartBlock = ((DWORD)((BYTE *)pEntry - (BYTE *)pHeader) - ENTRY_START_OFFSET) / BLOCKSIZE; for (dwBlock = dwStartBlock; dwBlock < dwStartBlock + pEntry->dwBlocksUsed; dwBlock++) URLCache_Allocation_BlockFree(AllocationTable, dwBlock); - ZeroMemory(pEntry, pEntry->dwBlocksUsed * BLOCKSIZE); return TRUE; } @@ -1184,7 +1238,7 @@ DWORD i; for (i = 0; i < sizeof(key) / sizeof(key[0]); i++) - key[i] = lookupTable[i]; + key[i] = lookupTable[(*lpszKey + i) & 0xFF]; for (lpszKey++; *lpszKey && ((lpszKey[0] != '/') || (lpszKey[1] != 0)); lpszKey++) { @@ -1214,19 +1268,19 @@ * each block therefore contains a chain of 7 key/offset pairs * how position in table is calculated: * 1. the url is hashed in helper function - * 2. the key % 64 * 8 is the offset - * 3. the key in the hash table is the hash key aligned to 64 + * 2. the key % HASHTABLE_NUM_ENTRIES is the bucket number + * 3. bucket number * HASHTABLE_BLOCKSIZE is offset of the bucket * * note: * there can be multiple hash tables in the file and the offset to * the next one is stored in the header of the hash table */ DWORD key = URLCache_HashKey(lpszUrl); - DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY); + DWORD offset = (key & (HASHTABLE_NUM_ENTRIES-1)) * HASHTABLE_BLOCKSIZE; HASH_CACHEFILE_ENTRY * pHashEntry; DWORD dwHashTableNumber = 0; - key = (key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES; + key >>= HASHTABLE_FLAG_BITS; for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable); URLCache_IsHashEntryValid(pHeader, pHashEntry); @@ -1248,7 +1302,7 @@ for (i = 0; i < HASHTABLE_BLOCKSIZE; i++) { struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i]; - if (key == (pHashElement->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES) + if (key == pHashElement->dwHashKey>>HASHTABLE_FLAG_BITS) { /* FIXME: we should make sure that this is the right element * before returning and claiming that it is. We can do this @@ -1277,25 +1331,22 @@ } ret = URLCache_FindHash(pHeader, urlA, ppHashEntry); - HeapFree(GetProcessHeap(), 0, urlA); + heap_free(urlA); return ret; } /*********************************************************************** - * URLCache_HashEntrySetUse (Internal) + * URLCache_HashEntrySetFlags (Internal) * - * Searches all the hash tables in the index for the given URL and - * sets the use count (stored or'ed with key) + * Sets special bits in hash key * * RETURNS - * TRUE if the entry was found - * FALSE if the entry could not be found + * nothing * */ -static BOOL URLCache_HashEntrySetUse(struct _HASH_ENTRY * pHashEntry, DWORD dwUseCount) +static void URLCache_HashEntrySetFlags(struct _HASH_ENTRY * pHashEntry, DWORD dwFlag) { - pHashEntry->dwHashKey = dwUseCount | (pHashEntry->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES; - return TRUE; + pHashEntry->dwHashKey = (pHashEntry->dwHashKey >> HASHTABLE_FLAG_BITS << HASHTABLE_FLAG_BITS) | dwFlag; } /*********************************************************************** @@ -1311,8 +1362,7 @@ */ static BOOL URLCache_DeleteEntryFromHash(struct _HASH_ENTRY * pHashEntry) { - pHashEntry->dwHashKey = HASHTABLE_FREE; - pHashEntry->dwOffsetEntry = HASHTABLE_FREE; + pHashEntry->dwHashKey = HASHTABLE_DEL; return TRUE; } @@ -1328,23 +1378,25 @@ * Any other Win32 error code if the entry could not be added * */ -static DWORD URLCache_AddEntryToHash(LPURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwOffsetEntry) +static DWORD URLCache_AddEntryToHash(LPURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwOffsetEntry, DWORD dwFieldType) { /* see URLCache_FindEntryInHash for structure of hash tables */ DWORD key = URLCache_HashKey(lpszUrl); - DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY); - HASH_CACHEFILE_ENTRY * pHashEntry; + DWORD offset = (key & (HASHTABLE_NUM_ENTRIES-1)) * HASHTABLE_BLOCKSIZE; + HASH_CACHEFILE_ENTRY * pHashEntry, *pHashPrev = NULL; DWORD dwHashTableNumber = 0; DWORD error; - key = (key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES; + key = ((key >> HASHTABLE_FLAG_BITS) << HASHTABLE_FLAG_BITS) + dwFieldType; for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable); URLCache_IsHashEntryValid(pHeader, pHashEntry); pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext)) { int i; + pHashPrev = pHashEntry; + if (pHashEntry->dwHashTableNumber != dwHashTableNumber++) { ERR("not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber); @@ -1360,7 +1412,7 @@ for (i = 0; i < HASHTABLE_BLOCKSIZE; i++) { struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i]; - if (pHashElement->dwHashKey == HASHTABLE_FREE) /* if the slot is free */ + if (pHashElement->dwHashKey==HASHTABLE_FREE || pHashElement->dwHashKey==HASHTABLE_DEL) /* if the slot is free */ { pHashElement->dwHashKey = key; pHashElement->dwOffsetEntry = dwOffsetEntry; @@ -1368,7 +1420,7 @@ } } } - error = URLCache_CreateHashTable(pHeader, pHashEntry, &pHashEntry); + error = URLCache_CreateHashTable(pHeader, pHashPrev, &pHashEntry); if (error != ERROR_SUCCESS) return error; @@ -1390,14 +1442,11 @@ */ static DWORD URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash, HASH_CACHEFILE_ENTRY **ppHash) { - DWORD dwOffset; + DWORD dwOffset, error; int i; - if (!URLCache_FindFirstFreeEntry(pHeader, 0x20, (CACHEFILE_ENTRY **)ppHash)) - { - FIXME("no free space for hash table\n"); - return ERROR_DISK_FULL; - } + if ((error = URLCache_FindFirstFreeEntry(pHeader, 0x20, (CACHEFILE_ENTRY **)ppHash)) != ERROR_SUCCESS) + return error; dwOffset = (BYTE *)*ppHash - (BYTE *)pHeader; @@ -1407,10 +1456,11 @@ pHeader->dwOffsetFirstHashTable = dwOffset; (*ppHash)->CacheFileEntry.dwSignature = HASH_SIGNATURE; (*ppHash)->CacheFileEntry.dwBlocksUsed = 0x20; + (*ppHash)->dwAddressNext = 0; (*ppHash)->dwHashTableNumber = pPrevHash ? pPrevHash->dwHashTableNumber + 1 : 0; for (i = 0; i < HASHTABLE_SIZE; i++) { - (*ppHash)->HashTable[i].dwOffsetEntry = 0; + (*ppHash)->HashTable[i].dwOffsetEntry = HASHTABLE_FREE; (*ppHash)->HashTable[i].dwHashKey = HASHTABLE_FREE; } return ERROR_SUCCESS; @@ -1465,7 +1515,7 @@ { for (; *index < HASHTABLE_SIZE ; (*index)++) { - if (pHashEntry->HashTable[*index].dwHashKey == HASHTABLE_FREE) + if (pHashEntry->HashTable[*index].dwHashKey==HASHTABLE_FREE || pHashEntry->HashTable[*index].dwHashKey==HASHTABLE_DEL) continue; *ppHashEntry = &pHashEntry->HashTable[*index]; @@ -1539,6 +1589,7 @@ return FALSE; } + // ReactOS r54992 if (!bDefaultContainersAdded) URLCacheContainers_CreateDefaults(); @@ -1554,7 +1605,7 @@ /* unlock, delete, recreate and lock cache */ URLCacheContainer_CloseIndex(pContainer); ret_del = URLCache_DeleteCacheDirectory(pContainer->path); - ret_open = URLCacheContainer_OpenIndex(pContainer); + ret_open = URLCacheContainer_OpenIndex(pContainer, MIN_BLOCK_NO); ReleaseMutex(pContainer->hMutex); return ret_del && (ret_open == ERROR_SUCCESS); @@ -1643,7 +1694,7 @@ return FALSE; } - error = URLCacheContainer_OpenIndex(pContainer); + error = URLCacheContainer_OpenIndex(pContainer, MIN_BLOCK_NO); if (error != ERROR_SUCCESS) { SetLastError(error); @@ -1725,7 +1776,7 @@ return FALSE; } - error = URLCacheContainer_OpenIndex(pContainer); + error = URLCacheContainer_OpenIndex(pContainer, MIN_BLOCK_NO); if (error != ERROR_SUCCESS) { SetLastError(error); @@ -1844,7 +1895,7 @@ return FALSE; } - error = URLCacheContainer_OpenIndex(pContainer); + error = URLCacheContainer_OpenIndex(pContainer, MIN_BLOCK_NO); if (error != ERROR_SUCCESS) { SetLastError(error); @@ -1901,7 +1952,7 @@ return FALSE; } - error = URLCacheContainer_OpenIndex(pContainer); + error = URLCacheContainer_OpenIndex(pContainer, MIN_BLOCK_NO); if (error != ERROR_SUCCESS) { SetLastError(error); @@ -1976,7 +2027,7 @@ return FALSE; } - error = URLCacheContainer_OpenIndex(pContainer); + error = URLCacheContainer_OpenIndex(pContainer, MIN_BLOCK_NO); if (error != ERROR_SUCCESS) { SetLastError(error); @@ -2027,7 +2078,7 @@ pUrlEntry->dwHitRate++; pUrlEntry->dwUseCount++; - URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount); + URLCache_HashEntrySetFlags(pHashEntry, HASHTABLE_LOCK); GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime); URLCacheContainer_UnlockIndex(pContainer, pHeader); @@ -2073,7 +2124,7 @@ return FALSE; } - error = URLCacheContainer_OpenIndex(pContainer); + error = URLCacheContainer_OpenIndex(pContainer, MIN_BLOCK_NO); if (error != ERROR_SUCCESS) { SetLastError(error); @@ -2128,7 +2179,7 @@ pUrlEntry->dwHitRate++; pUrlEntry->dwUseCount++; - URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount); + URLCache_HashEntrySetFlags(pHashEntry, HASHTABLE_LOCK); GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime); URLCacheContainer_UnlockIndex(pContainer, pHeader); @@ -2150,7 +2201,17 @@ SetLastError(ERROR_FILE_NOT_FOUND); return FALSE; } + pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry; + if ((pHashEntry->dwHashKey & ((1<CacheEntryType |= DELETED_CACHE_ENTRY; + SetLastError(ERROR_SHARING_VIOLATION); + return FALSE; + } + if (pUrlEntry->CacheDir < pHeader->DirectoryCount) { if (pHeader->directory_data[pUrlEntry->CacheDir].dwNumFiles) @@ -2209,7 +2270,7 @@ return FALSE; } - error = URLCacheContainer_OpenIndex(pContainer); + error = URLCacheContainer_OpenIndex(pContainer, MIN_BLOCK_NO); if (error != ERROR_SUCCESS) { SetLastError(error); @@ -2244,7 +2305,12 @@ return FALSE; } pUrlEntry->dwUseCount--; - URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount); + if (!pUrlEntry->dwUseCount) + { + URLCache_HashEntrySetFlags(pHashEntry, HASHTABLE_URL); + if (pUrlEntry->CacheEntryType & DELETED_CACHE_ENTRY) + DeleteUrlCacheEntryInternal(pHeader, pHashEntry); + } URLCacheContainer_UnlockIndex(pContainer, pHeader); @@ -2280,7 +2346,7 @@ return FALSE; } - error = URLCacheContainer_OpenIndex(pContainer); + error = URLCacheContainer_OpenIndex(pContainer, MIN_BLOCK_NO); if (error != ERROR_SUCCESS) { SetLastError(error); @@ -2315,7 +2381,8 @@ return FALSE; } pUrlEntry->dwUseCount--; - URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount); + if (!pUrlEntry->dwUseCount) + URLCache_HashEntrySetFlags(pHashEntry, HASHTABLE_URL); URLCacheContainer_UnlockIndex(pContainer, pHeader); @@ -2345,32 +2412,31 @@ if (lpszUrlName && (url_name = heap_strdupAtoW(lpszUrlName))) { - if (!lpszFileExtension || (file_extension = heap_strdupAtoW(lpszFileExtension))) - { - if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved)) - { - if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH) - { - bSuccess = TRUE; - } - else - { - dwError = GetLastError(); - } - } - else - { - dwError = GetLastError(); - } - HeapFree(GetProcessHeap(), 0, file_extension); - } - else - { - dwError = GetLastError(); - } - HeapFree(GetProcessHeap(), 0, url_name); - if (!bSuccess) - SetLastError(dwError); + if (!lpszFileExtension || (file_extension = heap_strdupAtoW(lpszFileExtension))) + { + if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved)) + { + if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH) + { + bSuccess = TRUE; + } + else + { + dwError = GetLastError(); + } + } + else + { + dwError = GetLastError(); + } + heap_free(file_extension); + } + else + { + dwError = GetLastError(); + } + heap_free(url_name); + if (!bSuccess) SetLastError(dwError); } return bSuccess; } @@ -2470,7 +2536,7 @@ return FALSE; } - error = URLCacheContainer_OpenIndex(pContainer); + error = URLCacheContainer_OpenIndex(pContainer, MIN_BLOCK_NO); if (error != ERROR_SUCCESS) { SetLastError(error); @@ -2590,6 +2656,7 @@ struct _HASH_ENTRY * pHashEntry; CACHEFILE_ENTRY * pEntry; URL_CACHEFILE_ENTRY * pUrlEntry; + DWORD url_entry_offset; DWORD dwBytesNeeded = DWORD_ALIGN(sizeof(*pUrlEntry)); DWORD dwOffsetLocalFileName = 0; DWORD dwOffsetHeader = 0; @@ -2649,7 +2716,7 @@ return FALSE; } - error = URLCacheContainer_OpenIndex(pContainer); + error = URLCacheContainer_OpenIndex(pContainer, MIN_BLOCK_NO); if (error != ERROR_SUCCESS) { SetLastError(error); @@ -2674,6 +2741,14 @@ if (URLCache_FindHash(pHeader, lpszUrlNameA, &pHashEntry)) { + if ((pHashEntry->dwHashKey & ((1<CacheFileEntry.dwSignature = URL_SIGNATURE; pUrlEntry->CacheDir = cDirectory; pUrlEntry->CacheEntryType = CacheEntryType; @@ -2788,14 +2868,23 @@ strcpy((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, lpszUrlNameA); if (dwOffsetLocalFileName) - strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), pchLocalFileName + DIR_LENGTH + 1); + strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), pchLocalFileName); if (dwOffsetHeader) memcpy((LPBYTE)pUrlEntry + dwOffsetHeader, lpHeaderInfo, dwHeaderSize); if (dwOffsetFileExtension) strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetFileExtension), lpszFileExtensionA); - error = URLCache_AddEntryToHash(pHeader, lpszUrlNameA, - (DWORD)((LPBYTE)pUrlEntry - (LPBYTE)pHeader)); + error = URLCache_AddEntryToHash(pHeader, lpszUrlNameA, url_entry_offset, HASHTABLE_URL); + while (error == ERROR_HANDLE_DISK_FULL) + { + error = URLCacheContainer_CleanIndex(pContainer, &pHeader); + if (error == ERROR_SUCCESS) + { + pUrlEntry = (URL_CACHEFILE_ENTRY *)((LPBYTE)pHeader + url_entry_offset); + error = URLCache_AddEntryToHash(pHeader, lpszUrlNameA, + url_entry_offset, HASHTABLE_URL); + } + } if (error != ERROR_SUCCESS) URLCache_DeleteEntry(pHeader, &pUrlEntry->CacheFileEntry); else @@ -2813,8 +2902,8 @@ cleanup: URLCacheContainer_UnlockIndex(pContainer, pHeader); - HeapFree(GetProcessHeap(), 0, lpszUrlNameA); - HeapFree(GetProcessHeap(), 0, lpszFileExtensionA); + heap_free(lpszUrlNameA); + heap_free(lpszFileExtensionA); if (error == ERROR_SUCCESS) return TRUE; @@ -2884,11 +2973,10 @@ file_extension, original_url); cleanup: - HeapFree(GetProcessHeap(), 0, original_url); - HeapFree(GetProcessHeap(), 0, file_extension); - HeapFree(GetProcessHeap(), 0, local_file_name); - HeapFree(GetProcessHeap(), 0, url_name); - + heap_free(original_url); + heap_free(file_extension); + heap_free(local_file_name); + heap_free(url_name); return bSuccess; } @@ -2935,7 +3023,7 @@ } if (header_info) { - HeapFree(GetProcessHeap(), 0, header_info); + heap_free(header_info); if (!bSuccess) SetLastError(dwError); } @@ -3120,12 +3208,8 @@ if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0)) return FALSE; - /* close file handle */ CloseHandle(pStream->hFile); - - /* free allocated space */ - HeapFree(GetProcessHeap(), 0, pStream); - + heap_free(pStream); return TRUE; } @@ -3151,7 +3235,7 @@ return FALSE; } - error = URLCacheContainer_OpenIndex(pContainer); + error = URLCacheContainer_OpenIndex(pContainer, MIN_BLOCK_NO); if (error != ERROR_SUCCESS) { SetLastError(error); @@ -3201,22 +3285,22 @@ error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer); if (error != ERROR_SUCCESS) { - HeapFree(GetProcessHeap(), 0, urlA); + heap_free(urlA); SetLastError(error); return FALSE; } - error = URLCacheContainer_OpenIndex(pContainer); + error = URLCacheContainer_OpenIndex(pContainer, MIN_BLOCK_NO); if (error != ERROR_SUCCESS) { - HeapFree(GetProcessHeap(), 0, urlA); + heap_free(urlA); SetLastError(error); return FALSE; } if (!(pHeader = URLCacheContainer_LockIndex(pContainer))) { - HeapFree(GetProcessHeap(), 0, urlA); + heap_free(urlA); return FALSE; } @@ -3224,7 +3308,7 @@ { URLCacheContainer_UnlockIndex(pContainer, pHeader); TRACE("entry %s not found!\n", debugstr_a(urlA)); - HeapFree(GetProcessHeap(), 0, urlA); + heap_free(urlA); SetLastError(ERROR_FILE_NOT_FOUND); return FALSE; } @@ -3232,8 +3316,7 @@ ret = DeleteUrlCacheEntryInternal(pHeader, pHashEntry); URLCacheContainer_UnlockIndex(pContainer, pHeader); - - HeapFree(GetProcessHeap(), 0, urlA); + heap_free(urlA); return ret; } @@ -3377,7 +3460,7 @@ pEntryHandle->lpszUrlSearchPattern = heap_strdupAtoW(lpszUrlSearchPattern); if (!pEntryHandle->lpszUrlSearchPattern) { - HeapFree(GetProcessHeap(), 0, pEntryHandle); + heap_free(pEntryHandle); return NULL; } } @@ -3389,7 +3472,7 @@ if (!FindNextUrlCacheEntryA(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize)) { - HeapFree(GetProcessHeap(), 0, pEntryHandle); + heap_free(pEntryHandle); return NULL; } return pEntryHandle; @@ -3416,7 +3499,7 @@ pEntryHandle->lpszUrlSearchPattern = heap_strdupW(lpszUrlSearchPattern); if (!pEntryHandle->lpszUrlSearchPattern) { - HeapFree(GetProcessHeap(), 0, pEntryHandle); + heap_free(pEntryHandle); return NULL; } } @@ -3428,7 +3511,7 @@ if (!FindNextUrlCacheEntryW(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize)) { - HeapFree(GetProcessHeap(), 0, pEntryHandle); + heap_free(pEntryHandle); return NULL; } return pEntryHandle; @@ -3456,7 +3539,7 @@ HASH_CACHEFILE_ENTRY *pHashTableEntry; DWORD error; - error = URLCacheContainer_OpenIndex(pContainer); + error = URLCacheContainer_OpenIndex(pContainer, MIN_BLOCK_NO); if (error != ERROR_SUCCESS) { SetLastError(error); @@ -3562,9 +3645,8 @@ } pEntryHandle->dwMagic = 0; - HeapFree(GetProcessHeap(), 0, pEntryHandle->lpszUrlSearchPattern); - HeapFree(GetProcessHeap(), 0, pEntryHandle); - + heap_free(pEntryHandle->lpszUrlSearchPattern); + heap_free(pEntryHandle); return TRUE; } @@ -3795,7 +3877,7 @@ return TRUE; } - if (URLCacheContainer_OpenIndex(pContainer)) + if (URLCacheContainer_OpenIndex(pContainer, MIN_BLOCK_NO)) { memset(pftLastModified, 0, sizeof(*pftLastModified)); return TRUE; @@ -3863,7 +3945,7 @@ return TRUE; } - if (URLCacheContainer_OpenIndex(pContainer)) + if (URLCacheContainer_OpenIndex(pContainer, MIN_BLOCK_NO)) { memset(pftLastModified, 0, sizeof(*pftLastModified)); return TRUE; @@ -3950,3 +4032,13 @@ FIXME("(%u, %p)\n", index, data); return FALSE; } + +/*********************************************************************** + * RunOnceUrlCache (WININET.@) + */ + +DWORD WINAPI RunOnceUrlCache(HWND hwnd, HINSTANCE hinst, LPSTR cmd, int cmdshow) +{ + FIXME("(%p, %p, %s, %d): stub\n", hwnd, hinst, debugstr_a(cmd), cmdshow); + return 0; +} Index: dll/win32/wininet/utility.c =================================================================== --- dll/win32/wininet/utility.c (revision 56722) +++ dll/win32/wininet/utility.c (working copy) @@ -184,18 +184,18 @@ hints.ai_family = AF_INET; ret = getaddrinfo( name, NULL, &hints, &res ); - HeapFree( GetProcessHeap(), 0, name ); if (ret != 0) { TRACE("failed to get IPv4 address of %s (%s), retrying with IPv6\n", debugstr_w(lpszServerName), gai_strerror(ret)); hints.ai_family = AF_INET6; ret = getaddrinfo( name, NULL, &hints, &res ); - if (ret != 0) - { - TRACE("failed to get address of %s (%s)\n", debugstr_w(lpszServerName), gai_strerror(ret)); - return FALSE; - } } + heap_free( name ); + if (ret != 0) + { + TRACE("failed to get address of %s (%s)\n", debugstr_w(lpszServerName), gai_strerror(ret)); + return FALSE; + } if (*sa_len < res->ai_addrlen) { WARN("address too small\n"); @@ -219,7 +219,7 @@ #else EnterCriticalSection( &cs_gethostbyname ); phe = gethostbyname(name); - HeapFree( GetProcessHeap(), 0, name ); + heap_free( name ); if (NULL == phe) { @@ -286,6 +286,18 @@ return "Unknown"; } +static const char *debugstr_status_info(DWORD status, void *info) +{ + switch(status) { + case INTERNET_STATUS_REQUEST_COMPLETE: { + INTERNET_ASYNC_RESULT *iar = info; + return wine_dbg_sprintf("{%s, %d}", wine_dbgstr_longlong(iar->dwResult), iar->dwError); + } + default: + return wine_dbg_sprintf("%p", info); + } +} + VOID INTERNET_SendCallback(object_header_t *hdr, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInfo, DWORD dwStatusInfoLength) @@ -331,9 +343,9 @@ } } - TRACE(" callback(%p) (%p (%p), %08lx, %d (%s), %p, %d)\n", + TRACE(" callback(%p) (%p (%p), %08lx, %d (%s), %s, %d)\n", hdr->lpfnStatusCB, hdr->hInternet, hdr, dwContext, dwInternetStatus, get_callback_name(dwInternetStatus), - lpvNewInfo, dwStatusInfoLength); + debugstr_status_info(dwInternetStatus, lpvNewInfo), dwStatusInfoLength); hdr->lpfnStatusCB(hdr->hInternet, dwContext, dwInternetStatus, lpvNewInfo, dwStatusInfoLength); @@ -341,7 +353,7 @@ TRACE(" end callback().\n"); if(lpvNewInfo != lpvStatusInfo) - HeapFree(GetProcessHeap(), 0, lpvNewInfo); + heap_free(lpvNewInfo); } static void SendAsyncCallbackProc(WORKREQUEST *workRequest) @@ -355,7 +367,7 @@ req->dwStatusInfoLength); /* And frees the copy of the status info */ - HeapFree(GetProcessHeap(), 0, req->lpvStatusInfo); + heap_free(req->lpvStatusInfo); } void SendAsyncCallback(object_header_t *hdr, DWORD_PTR dwContext, Index: dll/win32/wininet/wininet.spec =================================================================== --- dll/win32/wininet/wininet.spec (revision 56722) +++ dll/win32/wininet/wininet.spec (working copy) @@ -16,8 +16,8 @@ 122 stub -noname FreeP3PObject 123 stub -noname GetP3PRequestStatus -@ stdcall CommitUrlCacheEntryA(str str double double long str long str str) -@ stdcall CommitUrlCacheEntryW(wstr wstr double double long wstr long wstr wstr) +@ stdcall CommitUrlCacheEntryA(str str int64 int64 long str long str str) +@ stdcall CommitUrlCacheEntryW(wstr wstr int64 int64 long wstr long wstr wstr) @ stdcall CreateMD5SSOHash(wstr wstr wstr ptr) @ stdcall CreateUrlCacheContainerA(long long long long long long long long) @ stdcall CreateUrlCacheContainerW(long long long long long long long long) @@ -30,15 +30,15 @@ @ stdcall DeleteUrlCacheEntry(str) DeleteUrlCacheEntryA @ stdcall DeleteUrlCacheEntryA(str) @ stdcall DeleteUrlCacheEntryW(wstr) -@ stdcall DeleteUrlCacheGroup(double long ptr) +@ stdcall DeleteUrlCacheGroup(int64 long ptr) @ stdcall DetectAutoProxyUrl(str long long) @ stdcall -private DllInstall(long wstr) @ stdcall FindCloseUrlCache(long) @ stdcall FindFirstUrlCacheContainerA(ptr ptr ptr long) @ stdcall FindFirstUrlCacheContainerW(ptr ptr ptr long) @ stdcall FindFirstUrlCacheEntryA(str ptr ptr) -@ stdcall FindFirstUrlCacheEntryExA(str long long double ptr ptr ptr ptr ptr) -@ stdcall FindFirstUrlCacheEntryExW(wstr long long double ptr ptr ptr ptr ptr) +@ stdcall FindFirstUrlCacheEntryExA(str long long int64 ptr ptr ptr ptr ptr) +@ stdcall FindFirstUrlCacheEntryExW(wstr long long int64 ptr ptr ptr ptr ptr) @ stdcall FindFirstUrlCacheEntryW(wstr ptr ptr) @ stdcall FindFirstUrlCacheGroup(long long ptr long ptr ptr) @ stdcall FindNextUrlCacheContainerA(long ptr ptr) @@ -83,8 +83,8 @@ @ stdcall GetUrlCacheEntryInfoExA(str ptr ptr str ptr ptr long) @ stdcall GetUrlCacheEntryInfoExW(wstr ptr ptr wstr ptr ptr long) @ stdcall GetUrlCacheEntryInfoW(wstr ptr long) -@ stdcall GetUrlCacheGroupAttributeA(double long long ptr ptr ptr) -@ stdcall GetUrlCacheGroupAttributeW(double long long ptr ptr ptr) +@ stdcall GetUrlCacheGroupAttributeA(int64 long long ptr ptr ptr) +@ stdcall GetUrlCacheGroupAttributeW(int64 long long ptr ptr ptr) @ stub GetUrlCacheHeaderData @ stdcall GopherCreateLocatorA(str long str str long str ptr) @ stdcall GopherCreateLocatorW(wstr long wstr wstr long wstr ptr) @@ -157,6 +157,9 @@ @ stdcall InternetGetLastResponseInfoW(ptr ptr ptr) @ stdcall InternetGetPerSiteCookieDecisionA(str ptr) @ stdcall InternetGetPerSiteCookieDecisionW(wstr ptr) +@ stdcall InternetGetSecurityInfoByURL(str ptr ptr) InternetGetSecurityInfoByURLA +@ stdcall InternetGetSecurityInfoByURLA(str ptr ptr) +@ stdcall InternetGetSecurityInfoByURLW(wstr ptr ptr) @ stdcall InternetGoOnline(str long long) InternetGoOnlineA @ stdcall InternetGoOnlineA(str long long) @ stdcall InternetGoOnlineW(wstr long long) @@ -222,21 +225,21 @@ @ stdcall RetrieveUrlCacheEntryFileW(wstr ptr ptr long) @ stdcall RetrieveUrlCacheEntryStreamA(str ptr ptr long long) @ stdcall RetrieveUrlCacheEntryStreamW(wstr ptr ptr long long) -@ stub RunOnceUrlCache +@ stdcall RunOnceUrlCache(ptr ptr str long) @ stdcall SetUrlCacheConfigInfoA(ptr long) @ stdcall SetUrlCacheConfigInfoW(ptr long) -@ stdcall SetUrlCacheEntryGroup(str long double ptr long ptr) SetUrlCacheEntryGroupA -@ stdcall SetUrlCacheEntryGroupA(str long double ptr long ptr) -@ stdcall SetUrlCacheEntryGroupW(wstr long double ptr long ptr) +@ stdcall SetUrlCacheEntryGroup(str long int64 ptr long ptr) SetUrlCacheEntryGroupA +@ stdcall SetUrlCacheEntryGroupA(str long int64 ptr long ptr) +@ stdcall SetUrlCacheEntryGroupW(wstr long int64 ptr long ptr) @ stdcall SetUrlCacheEntryInfoA(str ptr long) @ stdcall SetUrlCacheEntryInfoW(wstr ptr long) -@ stdcall SetUrlCacheGroupAttributeA(double long long ptr ptr) -@ stdcall SetUrlCacheGroupAttributeW(double long long ptr ptr) +@ stdcall SetUrlCacheGroupAttributeA(int64 long long ptr ptr) +@ stdcall SetUrlCacheGroupAttributeW(int64 long long ptr ptr) @ stub SetUrlCacheHeaderData @ stub ShowCertificate -@ stub ShowClientAuthCerts +@ stdcall ShowClientAuthCerts(ptr) @ stub ShowSecurityInfo -@ stub ShowX509EncodedCertificate +@ stdcall ShowX509EncodedCertificate(ptr ptr long) @ stdcall UnlockUrlCacheEntryFile(str long) UnlockUrlCacheEntryFileA @ stdcall UnlockUrlCacheEntryFileA(str long) @ stdcall UnlockUrlCacheEntryFileW(wstr long) Index: include/psdk/wininet.h =================================================================== --- include/psdk/wininet.h (revision 56722) +++ include/psdk/wininet.h (working copy) @@ -687,7 +687,7 @@ #define INTERNET_STATE_IDLE 0x00000100 #define INTERNET_STATE_BUSY 0x00000200 -#define INTERNET_INVALID_STATUS_CALLBACK ((INTERNET_STATUS_CALLBACK)(-1L)) +#define INTERNET_INVALID_STATUS_CALLBACK ((INTERNET_STATUS_CALLBACK)(-1)) #define FTP_TRANSFER_TYPE_UNKNOWN 0x00000000 #define FTP_TRANSFER_TYPE_ASCII 0x00000001 @@ -1496,6 +1496,7 @@ #define EDITED_CACHE_ENTRY 0x00000008 #define COOKIE_CACHE_ENTRY 0x00100000 #define URLHISTORY_CACHE_ENTRY 0x00200000 +#define DELETED_CACHE_ENTRY 0x00400000 #define TRACK_OFFLINE_CACHE_ENTRY 0x00000010 #define TRACK_ONLINE_CACHE_ENTRY 0x00000020 #define SPARSE_CACHE_ENTRY 0x00010000 Index: include/psdk/winineti.h =================================================================== --- include/psdk/winineti.h (revision 56722) +++ include/psdk/winineti.h (working copy) @@ -21,6 +21,7 @@ /* FIXME: #include */ #include +#include typedef struct _INTERNET_CACHE_CONFIG_PATH_ENTRYA { @@ -122,6 +123,9 @@ BOOL WINAPI SetUrlCacheConfigInfoA(LPINTERNET_CACHE_CONFIG_INFOA,DWORD); BOOL WINAPI SetUrlCacheConfigInfoW(LPINTERNET_CACHE_CONFIG_INFOW,DWORD); #define SetUrlCacheConfigInfo WINELIB_NAME_AW(SetUrlCacheConfigInfo) +BOOL WINAPI InternetGetSecurityInfoByURLA(LPSTR,PCCERT_CHAIN_CONTEXT*,DWORD*); +BOOL WINAPI InternetGetSecurityInfoByURLW(LPCWSTR,PCCERT_CHAIN_CONTEXT*,DWORD*); +#define InternetGetSecurityInfoByURL WINELIB_NAME_AW(InternetGetSecurityInfoByURL) #ifdef __cplusplus }