Liang's Blog
2012年10月8日 星期一
Use Macro to dynamically load wininet.dll
#ifndef WININETMANAGER_H
#define WININETMANAGER_H
#include <WinInet.h>
#define DECLARE_FUNCTION(functionName, resultType, callingConvention, parameterDeclarations) \
static resultType functionName parameterDeclarations ;
#define DEFINE_FUNCTION(functionName, resultType, callingConvention, parameterDeclarations, parameterNames) \
resultType WinInetManager::##functionName parameterDeclarations \
{\
resultType (callingConvention*softLink##functionName) parameterDeclarations; \
softLink##functionName = reinterpret_cast<resultType (callingConvention*) parameterDeclarations>(GetProcAddress(WinInetManager::instance().getDllHandle(), L#functionName)); \
return softLink##functionName parameterNames; \
}
namespace WebCore
{
class String;
class WinInetManager
{
public:
static WinInetManager& instance();
HRESULT freeLibrary();
const HMODULE& getDllHandle();
HRESULT setCookieCacheFolder(const String& location);
HRESULT setCookieCacheFullPath(const String& path);
HRESULT cacheReserveSize(DWORD *size);
HRESULT setCacheReserveSize(DWORD size);
~WinInetManager();
DECLARE_FUNCTION(InternetOpenUrlW,HINTERNET ,WINAPI, (HINTERNET hInternet,LPCWSTR lpszUrl,LPCWSTR lpszHeaders,DWORD dwHeadersLength,DWORD dwFlags,DWORD_PTR dwContext))
DECLARE_FUNCTION(InternetCloseHandle, BOOL, WINAPI, (HINTERNET hInternet))
DECLARE_FUNCTION(DeleteUrlCacheEntryW,BOOL,WINAPI, (LPCWSTR lpszUrlName))
DECLARE_FUNCTION(InternetSetStatusCallbackW, INTERNET_STATUS_CALLBACK, WINAPI, (HINTERNET hInternet,INTERNET_STATUS_CALLBACK lpfnInternetCallback))
DECLARE_FUNCTION(InternetGetLastResponseInfoW, BOOL, WINAPI, (LPDWORD lpdwError,LPWSTR lpszBuffer,LPDWORD lpdwBufferLength))
DECLARE_FUNCTION(InternetErrorDlg, DWORD, WINAPI, (HWND hWnd,HINTERNET hRequest,DWORD dwError,DWORD dwFlags,LPVOID * lppvData))
DECLARE_FUNCTION(InternetReadFileExA, BOOL, WINAPI, (HINTERNET hFile,LPINTERNET_BUFFERSA lpBuffersOut,DWORD dwFlags,DWORD_PTR dwContext))
DECLARE_FUNCTION(InternetWriteFile, BOOL, WINAPI, (HINTERNET hFile,LPCVOID lpBuffer,DWORD dwNumberOfBytesToWrite,LPDWORD lpdwNumberOfBytesWritten))
DECLARE_FUNCTION(InternetConnectW, HINTERNET, WINAPI, (HINTERNET hInternet,LPCWSTR lpszServerName,INTERNET_PORT nServerPort,LPCWSTR lpszUserName,LPCWSTR lpszPassword,DWORD dwService,DWORD dwFlags,DWORD_PTR dwContext))
DECLARE_FUNCTION(HttpOpenRequestW, HINTERNET, WINAPI, (HINTERNET hConnect,LPCWSTR lpszVerb,LPCWSTR lpszObjectName,LPCWSTR lpszVersion,LPCWSTR lpszReferrer,LPCWSTR FAR * lplpszAcceptTypes,DWORD dwFlags,DWORD_PTR dwContext))
DECLARE_FUNCTION(HttpSendRequestExW, BOOL, WINAPI, (HINTERNET hRequest,LPINTERNET_BUFFERSW lpBuffersIn,LPINTERNET_BUFFERSW lpBuffersOut,DWORD dwFlags,DWORD_PTR dwContext))
DECLARE_FUNCTION(HttpEndRequestW, BOOL, WINAPI, (HINTERNET hRequest,LPINTERNET_BUFFERSW lpBuffersOut,DWORD dwFlags,DWORD_PTR dwContext))
DECLARE_FUNCTION(ResumeSuspendedDownload, BOOL, WINAPI, (HINTERNET hRequest,DWORD dwResultCode))
DECLARE_FUNCTION(HttpQueryInfoW, BOOL, WINAPI, (HINTERNET hRequest,DWORD dwInfoLevel,LPVOID lpBuffer,LPDWORD lpdwBufferLength,LPDWORD lpdwIndex))
DECLARE_FUNCTION(InternetOpenW, HINTERNET, WINAPI, (LPCWSTR lpszAgent,DWORD dwAccessType,LPCWSTR lpszProxy,LPCWSTR lpszProxyBypass,DWORD dwFlags))
DECLARE_FUNCTION(InternetQueryOptionW, BOOL, WINAPI, (HINTERNET hInternet,DWORD dwOption,LPVOID lpBuffer,LPDWORD lpdwBufferLength))
DECLARE_FUNCTION(InternetSetOptionW, BOOL, WINAPI, (HINTERNET hInternet,DWORD dwOption,LPVOID lpBuffer,DWORD dwBufferLength))
DECLARE_FUNCTION(InternetSetCookieW,BOOL,WINAPI, (LPCWSTR lpszUrl,LPCWSTR lpszCookieName,LPCWSTR lpszCookieData))
DECLARE_FUNCTION(InternetGetCookieW,BOOL,WINAPI, (LPCWSTR lpszUrl,LPCWSTR lpszCookieName,LPCWSTR lpszCookieData,LPDWORD lpdwSize))
DECLARE_FUNCTION(FindFirstUrlCacheEntryW,HINTERNET,WINAPI, (LPCWSTR lpszUrlSearchPattern,LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,LPDWORD lpcbCacheEntryInfo))
DECLARE_FUNCTION(FindNextUrlCacheEntryW,BOOL,WINAPI, (HANDLE hEnumHandle,LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,LPDWORD lpcbCacheEntryInfo))
DECLARE_FUNCTION(GetUrlCacheEntryInfoW,BOOL,WINAPI, (LPCWSTR lpszUrlName,LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,LPDWORD lpcbCacheEntryInfo))
private:
HRESULT setUserName(const String& name);
HRESULT setCookieDirectory(HKEY key, const String& dir);
HRESULT setCacheDirectory(HKEY key, const String& dir);
HRESULT setHistoryDirectory(HKEY key, const String& dir);
WinInetManager();
private:
HMODULE m_module;
};
}
#endif //WININETMANAGER_H
#include "config.h"
#include "WinInetManager.h"
#include "FileSystem.h"
#include "WTFString.h"
namespace WebCore
{
static const WCHAR* const WININET_DLL_NAME = L"wininet.dll";
static const WCHAR* const REGISTRY_SHELL_FOLDERS = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders";
static const WCHAR* const BASE_DIRECTORY = L"\\Windows\\Profiles\\";
static const WCHAR* const TEMP_FILE_DIRECTORY = L"\\Temporary Internet Files";
static const WCHAR* const COOKIE_DIRECTORY = L"\\Cookies";
static const WCHAR* const HISTORY_DIRECTORY = L"\\History";
static const WCHAR* const KEY_USER_NAME = L"Username";
static const WCHAR* const KEY_CACHE = L"Cache";
static const WCHAR* const KEY_COOKIE = L"Cookies";
static const WCHAR* const KEY_HISTORY = L"History";
static const WCHAR* const KEY_IDENT = L"Ident";
static const WCHAR* const REGISTRY_CACHE_CONTENT = L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\5.0\\Cache\\Content";
static const WCHAR* const KEY_CACHE_LIMIT = L"CacheLimit";
static const WCHAR* const PATH_SEPARATOR = L"\\";
DEFINE_FUNCTION(InternetOpenUrlW,HINTERNET ,WINAPI, (HINTERNET hInternet,LPCWSTR lpszUrl,LPCWSTR lpszHeaders,DWORD dwHeadersLength,DWORD dwFlags,DWORD_PTR dwContext), (hInternet,lpszUrl,lpszHeaders,dwHeadersLength,dwFlags,dwContext))
DEFINE_FUNCTION(InternetCloseHandle, BOOL, WINAPI, (HINTERNET hInternet), (hInternet))
DEFINE_FUNCTION(InternetSetStatusCallbackW, INTERNET_STATUS_CALLBACK, WINAPI, (HINTERNET hInternet,INTERNET_STATUS_CALLBACK lpfnInternetCallback),(hInternet,lpfnInternetCallback))
DEFINE_FUNCTION(InternetGetLastResponseInfoW, BOOL, WINAPI, (LPDWORD lpdwError,LPWSTR lpszBuffer,LPDWORD lpdwBufferLength), (lpdwError,lpszBuffer,lpdwBufferLength))
DEFINE_FUNCTION(InternetErrorDlg, DWORD, WINAPI, (HWND hWnd,HINTERNET hRequest,DWORD dwError,DWORD dwFlags,LPVOID * lppvData), (hWnd,hRequest,dwError,dwFlags,lppvData))
DEFINE_FUNCTION(InternetReadFileExA, BOOL, WINAPI, (HINTERNET hFile,LPINTERNET_BUFFERSA lpBuffersOut,DWORD dwFlags,DWORD_PTR dwContext), (hFile,lpBuffersOut,dwFlags,dwContext))
DEFINE_FUNCTION(InternetWriteFile, BOOL, WINAPI, (HINTERNET hFile,LPCVOID lpBuffer,DWORD dwNumberOfBytesToWrite,LPDWORD lpdwNumberOfBytesWritten), (hFile,lpBuffer,dwNumberOfBytesToWrite,lpdwNumberOfBytesWritten))
DEFINE_FUNCTION(InternetConnectW, HINTERNET, WINAPI, (HINTERNET hInternet,LPCWSTR lpszServerName,INTERNET_PORT nServerPort,LPCWSTR lpszUserName,LPCWSTR lpszPassword,DWORD dwService,DWORD dwFlags,DWORD_PTR dwContext), (hInternet,lpszServerName,nServerPort,lpszUserName,lpszPassword,dwService,dwFlags,dwContext))
DEFINE_FUNCTION(HttpOpenRequestW, HINTERNET, WINAPI, (HINTERNET hConnect,LPCWSTR lpszVerb,LPCWSTR lpszObjectName,LPCWSTR lpszVersion,LPCWSTR lpszReferrer,LPCWSTR FAR * lplpszAcceptTypes,DWORD dwFlags,DWORD_PTR dwContext), (hConnect,lpszVerb,lpszObjectName,lpszVersion,lpszReferrer,lplpszAcceptTypes,dwFlags,dwContext))
DEFINE_FUNCTION(HttpSendRequestExW, BOOL, WINAPI, (HINTERNET hRequest,LPINTERNET_BUFFERSW lpBuffersIn,LPINTERNET_BUFFERSW lpBuffersOut,DWORD dwFlags,DWORD_PTR dwContext), (hRequest,lpBuffersIn,lpBuffersOut,dwFlags,dwContext))
DEFINE_FUNCTION(HttpEndRequestW, BOOL, WINAPI, (HINTERNET hRequest,LPINTERNET_BUFFERSW lpBuffersOut,DWORD dwFlags,DWORD_PTR dwContext), (hRequest,lpBuffersOut,dwFlags,dwContext))
DEFINE_FUNCTION(ResumeSuspendedDownload, BOOL, WINAPI, (HINTERNET hRequest,DWORD dwResultCode),(hRequest,dwResultCode))
DEFINE_FUNCTION(HttpQueryInfoW, BOOL, WINAPI, (HINTERNET hRequest,DWORD dwInfoLevel,LPVOID lpBuffer,LPDWORD lpdwBufferLength,LPDWORD lpdwIndex),(hRequest,dwInfoLevel,lpBuffer,lpdwBufferLength,lpdwIndex))
DEFINE_FUNCTION(InternetOpenW, HINTERNET, WINAPI, (LPCWSTR lpszAgent,DWORD dwAccessType,LPCWSTR lpszProxy,LPCWSTR lpszProxyBypass,DWORD dwFlags),(lpszAgent,dwAccessType,lpszProxy,lpszProxyBypass,dwFlags))
DEFINE_FUNCTION(InternetQueryOptionW, BOOL, WINAPI, (HINTERNET hInternet,DWORD dwOption,LPVOID lpBuffer,LPDWORD lpdwBufferLength),(hInternet,dwOption,lpBuffer,lpdwBufferLength))
DEFINE_FUNCTION(InternetSetOptionW, BOOL, WINAPI, (HINTERNET hInternet,DWORD dwOption,LPVOID lpBuffer,DWORD dwBufferLength),(hInternet,dwOption,lpBuffer,dwBufferLength))
DEFINE_FUNCTION(InternetSetCookieW,BOOL,WINAPI, (LPCWSTR lpszUrl,LPCWSTR lpszCookieName,LPCWSTR lpszCookieData), (lpszUrl,lpszCookieName,lpszCookieData))
DEFINE_FUNCTION(InternetGetCookieW,BOOL,WINAPI, (LPCWSTR lpszUrl,LPCWSTR lpszCookieName,LPCWSTR lpszCookieData,LPDWORD lpdwSize), (lpszUrl,lpszCookieName,lpszCookieData,lpdwSize))
DEFINE_FUNCTION(DeleteUrlCacheEntryW,BOOL,WINAPI, (LPCWSTR lpszUrlName), (lpszUrlName))
DEFINE_FUNCTION(FindFirstUrlCacheEntryW,HINTERNET,WINAPI, (LPCWSTR lpszUrlSearchPattern,LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,LPDWORD lpcbCacheEntryInfo), (lpszUrlSearchPattern,lpFirstCacheEntryInfo,lpcbCacheEntryInfo))
DEFINE_FUNCTION(FindNextUrlCacheEntryW,BOOL,WINAPI, (HANDLE hEnumHandle,LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,LPDWORD lpcbCacheEntryInfo), (hEnumHandle,lpNextCacheEntryInfo,lpcbCacheEntryInfo))
DEFINE_FUNCTION(GetUrlCacheEntryInfoW,BOOL,WINAPI, (LPCWSTR lpszUrlName,LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,LPDWORD lpcbCacheEntryInfo), (lpszUrlName,lpCacheEntryInfo,lpcbCacheEntryInfo))
WinInetManager::WinInetManager()
:m_module(NULL)
{
}
WinInetManager::~WinInetManager()
{
}
WinInetManager& WinInetManager::instance()
{
static WinInetManager manager;
return manager;
}
HRESULT WinInetManager::freeLibrary()
{
HMODULE hModule = ::GetModuleHandle(WININET_DLL_NAME);
///Strange! I just called the LoadLibrary("wininet.dll") one time.
///But I cann't really free the library until call the FreeLibrary three times.
int leftTimes = 20;
while (hModule != NULL && leftTimes > 0)
{
::FreeLibrary(hModule);
hModule = ::GetModuleHandle(WININET_DLL_NAME);
-- leftTimes;
}
HRESULT res = S_OK;
if (hModule != NULL)
{
DEBUGMSG(0, (L"WinInetManager::freeLibrary Failed \n"));
res = S_FALSE;
}
m_module = NULL;
return res;
}
const HMODULE& WinInetManager::getDllHandle()
{
if(NULL == m_module)
{
m_module = ::LoadLibraryW(WININET_DLL_NAME);
}
return m_module;
}
static bool makeDirectory(const String& location)
{
String path(BASE_DIRECTORY);
path.append(location);
return makeAllDirectories(path);
}
static HRESULT setStringValue(HKEY hKey, const String& key, const String& value)
{
String tempKey = key;
String tempValue = value;
int valueSize = value.length() * sizeof(TCHAR);
const BYTE* valueStr = (const BYTE*)tempValue.charactersWithNullTermination();
HRESULT result = RegSetValueEx(hKey, tempKey.charactersWithNullTermination(), 0, REG_SZ, valueStr, valueSize);
if (FAILED(result))
{
DEBUGMSG(result, (L"WinInetManager setStringValue error \n"));
}
return result;
}
static HRESULT setIntegerValue(HKEY hKey, const String& key, const DWORD& value)
{
String tempKey = key;
HRESULT result = HRESULT_FROM_WIN32(RegSetValueEx(hKey, tempKey.charactersWithNullTermination(), 0, REG_DWORD, (BYTE*)(&value), sizeof(value)));
if (FAILED(result))
{
DEBUGMSG(result, (L"WinInetManager setIntegerValue error \n"));
}
return result;
}
static HRESULT integerValueForKey(HKEY hKey, const String& key, DWORD* value)
{
String tempKey = key;
DWORD dwData = 0;
DWORD dwSize = sizeof(DWORD);
HRESULT result = E_FAIL;
if(ERROR_SUCCESS == RegQueryValueEx(hKey, tempKey.charactersWithNullTermination(), NULL, NULL, (BYTE*)(&dwData), &dwSize))
{
*value = dwData;
result = S_OK;
}
else
DEBUGMSG(result, (L"WinInetManager integerValueForKey error \n"));
return result;
}
HRESULT WinInetManager::setCookieCacheFolder(const String& location)
{
if (!makeDirectory(location))
{
DEBUGMSG(0, (L"WinInetManager::setCookieCacheFolder makeDirectory error \n"));
return E_INVALIDARG;
}
LONG result = setUserName(location);
if(FAILED(result))
{
DEBUGMSG(0, (L"WinInetManager::setCookieCacheFolder setUserName error \n"));
return result;
}
HKEY hKey = NULL;
result = RegOpenKeyEx(HKEY_CURRENT_USER, REGISTRY_SHELL_FOLDERS, 0, KEY_WRITE, &hKey);
if (FAILED(result))
{
DEBUGMSG(result, (L"WinInetManager::setCookieCacheFolder RegOpenKeyEx error \n"));
return result;
}
result = setCacheDirectory(hKey, location);
if (FAILED(result))
{
DEBUGMSG(result, (L"WinInetManager::setCookieCacheFolder setCacheDirectory error \n"));
return result;
}
result = setCookieDirectory(hKey, location);
if (FAILED(result))
{
DEBUGMSG(result, (L"WinInetManager::setCookieCacheFolder setCookieDirectory error \n"));
return result;
}
result = setHistoryDirectory(hKey, location);
if (FAILED(result))
{
DEBUGMSG(result, (L"WinInetManager::setCookieCacheFolder setHistoryDirectory error \n"));
return result;
}
return RegCloseKey(hKey);
}
static HRESULT setDirectoryValue(HKEY hKey, const String& key, const String& basePath, const String& subPath)
{
if(basePath.endsWith(PATH_SEPARATOR))
{
return S_FALSE;
}
return setStringValue(hKey, key, basePath + subPath);
}
HRESULT WinInetManager::setCookieCacheFullPath(const String& path)
{
if (!makeAllDirectories(path))
{
DEBUGMSG(1, (L"WinInetManager::setCookieCacheFullPath makeAllDirectories error \n"));
return E_FAIL;
}
HKEY hKey = NULL;
LONG result = RegOpenKeyEx(HKEY_CURRENT_USER, REGISTRY_SHELL_FOLDERS, 0, KEY_WRITE, &hKey);
if (FAILED(result))
{
DEBUGMSG(result, (L"WinInetManager::setCookieCacheFullPath RegOpenKeyEx error \n"));
return result;
}
result = setDirectoryValue(hKey, KEY_CACHE, path, TEMP_FILE_DIRECTORY);
if(FAILED(result))
{
DEBUGMSG(result, (L"WinInetManager::setDirectoryValue TEMP_FILE_DIRECTORY error \n"));
goto FAIL;
}
result = setDirectoryValue(hKey, KEY_COOKIE, path, COOKIE_DIRECTORY);
if(FAILED(result))
{
DEBUGMSG(result, (L"WinInetManager::setDirectoryValue COOKIE_DIRECTORY error \n"));
goto FAIL;
}
result = setDirectoryValue(hKey, KEY_HISTORY, path, HISTORY_DIRECTORY);
if(FAILED(result))
{
DEBUGMSG(result, (L"WinInetManager::setDirectoryValue HISTORY_DIRECTORY error \n"));
goto FAIL;
}
FAIL:
RegCloseKey(hKey);
return result;
}
HRESULT WinInetManager::setUserName(const String& name)
{
HKEY hKey;
HRESULT result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, KEY_IDENT, 0, KEY_WRITE, &hKey);
if(FAILED(result))
{
DEBUGMSG(result, (L"WinInetManager::setUserName RegOpenKeyEx error \n"));
return result;
}
String key(KEY_USER_NAME);
if (FAILED(setStringValue(hKey, key, name)))
{
DEBUGMSG(result, (L"WinInetManager::setUserName setStringValue error \n"));
return result;
}
return RegCloseKey(hKey);
}
HRESULT WinInetManager::setCacheDirectory(HKEY hKey, const String& location)
{
// change Cache directory
String value(BASE_DIRECTORY);
value = value + location + TEMP_FILE_DIRECTORY;
return setStringValue(hKey, KEY_CACHE, value);
}
HRESULT WinInetManager::setCookieDirectory(HKEY hKey, const String& location)
{
// change cookies directory
String value(BASE_DIRECTORY);
value = value + location + COOKIE_DIRECTORY;
return setStringValue(hKey, KEY_COOKIE, value);
}
HRESULT WinInetManager::setHistoryDirectory(HKEY hKey, const String& location)
{
// change history directory
String value(BASE_DIRECTORY);
value = value + location + HISTORY_DIRECTORY;
return setStringValue(hKey, KEY_HISTORY, value);
}
HRESULT WinInetManager::cacheReserveSize(DWORD *size)
{
HKEY hKey = NULL;
HRESULT result = E_FAIL;
if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_CURRENT_USER, REGISTRY_CACHE_CONTENT, 0, KEY_READ, &hKey))
{
DEBUGMSG(result, (L"WinInetManager::cacheReserveSize RegOpenKeyEx error \n"));
return result;
}
String key(KEY_CACHE_LIMIT);
DWORD regSize = 0;
result = integerValueForKey(hKey, key, ®Size);
if (FAILED(result))
{
DEBUGMSG(result, (L"WinInetManager::cacheReserveSize integerValueForKey error \n"));
*size = 0;
}
else
*size = regSize * 1024;
RegCloseKey(hKey);
return S_OK;
}
HRESULT WinInetManager::setCacheReserveSize(DWORD size)
{
HKEY hKey = NULL;
HRESULT result = E_FAIL;
if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_CURRENT_USER, REGISTRY_CACHE_CONTENT, 0, KEY_WRITE, &hKey))
{
DEBUGMSG(result, (L"WinInetManager::setCacheReserveSize RegOpenKeyEx error \n"));
return result;
}
String key(KEY_CACHE_LIMIT);
result = setIntegerValue(hKey, key, size/1024);
if (FAILED(result))
{
DEBUGMSG(result, (L"WinInetManager::setCacheReserveSize setIntegerValue error \n"));
}
RegCloseKey(hKey);
return result;
}
}
Manage the certificates received from ssl website
#ifndef SSLACCESSCONTROLLER_H
#define SSLACCESSCONTROLLER_H
#include "Noncopyable.h"
#include <WinCrypt.h>
namespace WebCore
{
class ResourceHandle;
class ResourceResponse;
class SSLAccessController :public Noncopyable
{
public:
SSLAccessController();
bool didReceiveCertificate(ResourceHandle& handle, HANDLE hInternet);
void didReceiveSSLError(ResourceHandle& handle, long errorID, HANDLE hInternet);
void didReceiveClientAuthNeededError(ResourceHandle& handle, long errorID, HANDLE hInternet);
void continueVisitSSLSite(ResourceHandle& handle, HANDLE hInternet, void* certificate);
void cancelVisitSSLSite(ResourceHandle& handle);
private:
void resetFlagMembers();
void sendCurrentRequest(ResourceHandle& handle, bool noSecurityChecks);
void receiveSSLError(ResourceHandle& handle, long errorID, HANDLE hInternet);
bool notifyCertificate(ResourceHandle& handle, HANDLE hInternet);
void sendSSLErrorToUI(const ResourceResponse& response, ResourceHandle& handle, long errorID, HANDLE hInternet);
private:
bool m_continueVisit;
bool m_hasSSLError;
bool m_clientAuthNeeded;
PCCERT_CONTEXT m_certContext;
};
}
#endif //SSLACCESSCONTROLLER_H
#include "config.h"
#include "SSLAccessController.h"
#include "ResourceHandle.h"
#include "ResourceHandleInternal.h"
#include "ResourceHandleClient.h"
#include "ResourceError.h"
#include "WinInetManager.h"
#include "SSLCertStoreManager.h"
namespace WebCore
{
class CertContextDeleter
{
public:
CertContextDeleter(PCCERT_CONTEXT cert)
:m_cert(cert){}
~CertContextDeleter(){CertFreeCertificateContext(m_cert);}
private:
PCCERT_CONTEXT m_cert;
};
SSLAccessController::SSLAccessController()
{
resetFlagMembers();
}
static bool needToHandleSSLMessage(ResourceHandle& handle)
{
return handle.request().url().protocol().lower() == "https" &&
handle.request().targetType() == ResourceRequestBase::TargetIsMainFrame;
}
static PCCERT_CONTEXT getCertFromWininet(HANDLE hInternet)
{
PCCERT_CONTEXT pInfo = NULL;
DWORD certInfoLength = sizeof(PCCERT_CONTEXT);
BOOL succ = WinInetManager::InternetQueryOptionW(
hInternet,
INTERNET_OPTION_SERVER_CERT_CONTEXT,
&pInfo,
&certInfoLength);
if (!succ)
pInfo = NULL;
return pInfo;
}
static bool findCertInStore(bool& inAcceptingStore, PCCERT_CONTEXT cert)
{
return SSLCertStoreManager::getInstance().findCertInStore(inAcceptingStore, cert);
}
static bool saveCertInStore(bool inAcceptingStore, PCCERT_CONTEXT cert)
{
if (NULL == cert)
return false;
return SSLCertStoreManager::getInstance().saveCertInStore(inAcceptingStore, cert);
}
static void buildResourceResponse(ResourceResponse& response, INTERNET_CERTIFICATE_INFO* info)
{
response.setMimeType("text/html");
response.setTextEncodingName("UTF-16");
response.setSSLPeerCertificate(info);
}
static bool buildResponseWithCertificate(HINTERNET handle, ResourceResponse& response, INTERNET_CERTIFICATE_INFO* info)
{
bool result = false;
DWORD certInfoLength = sizeof(INTERNET_CERTIFICATE_INFO);
if (WinInetManager::InternetQueryOptionW(handle,
INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT,
info,
&certInfoLength))
{
buildResourceResponse(response, info);
result = true;
}
return result;
}
static void releaseCertificateInfo(INTERNET_CERTIFICATE_INFO* info)
{
static const int ARRAY_COUNT = 5;
LPTSTR strs[ARRAY_COUNT] = {
info->lpszEncryptionAlgName,
info->lpszIssuerInfo,
info->lpszProtocolName,
info->lpszSignatureAlgName,
info->lpszSubjectInfo};
for (int i = 0; i < ARRAY_COUNT; ++i)
{
if (strs[i])
LocalFree(strs[i]);
}
}
bool SSLAccessController::notifyCertificate(ResourceHandle& handle, HANDLE hInternet)
{
ResourceResponse response;
INTERNET_CERTIFICATE_INFO certificateInfo;
if(!buildResponseWithCertificate(hInternet, response, &certificateInfo))
{
return false;
}
ResourceHandleInternal *handleInternal = handle.d.get();
handleInternal->m_currentWebChallenge.setAuthenticationClient(&handle);
handle.client()->didReceiveCertificate(&handle, response, handleInternal->m_currentWebChallenge);
releaseCertificateInfo(&certificateInfo);
return true;
}
bool SSLAccessController::didReceiveCertificate(ResourceHandle& handle, HANDLE hInternet)
{
if (!needToHandleSSLMessage(handle))
return true;
m_certContext = getCertFromWininet(hInternet);
if (!m_certContext)
return false;
CertContextDeleter temp(m_certContext);
bool inAcceptingStore = false;
if (findCertInStore(inAcceptingStore, m_certContext))
{
return inAcceptingStore;
}
if (!notifyCertificate(handle, hInternet))
return false;
//m_continueVisit will be changed by notifyCertificate in continueVisitSSLSite()
//or cancelVisitSSLSite()
return m_continueVisit;
}
void SSLAccessController::sendSSLErrorToUI(const ResourceResponse& response, ResourceHandle& handle, long errorID, HANDLE hInternet)
{
ResourceHandleInternal *handleInternal = handle.d.get();
handleInternal->m_currentWebChallenge.setAuthenticationClient(&handle);
ResourceError resourceError("Error", WebURLErrorUnknown, handle.request().url().string(), "");
resourceError.setPlatformCustomError(errorID);
//Send error info to UI
handle.client()->didReceiveSSLError(&handle, response, resourceError, handleInternal->m_currentWebChallenge);
}
void SSLAccessController::receiveSSLError(ResourceHandle& handle, long errorID, HANDLE hInternet)
{
if (!needToHandleSSLMessage(handle))
return;
m_certContext = getCertFromWininet(hInternet);
if (!m_certContext)
return;
CertContextDeleter temp(m_certContext);
bool inAcceptingStore = false;
if (findCertInStore(inAcceptingStore, m_certContext))
{
//the certificate is already in store.
if (!inAcceptingStore) // do nothing
return;
if (inAcceptingStore) // Continue visiting
return sendCurrentRequest(handle, true);
}
ResourceResponse response;
INTERNET_CERTIFICATE_INFO certificateInfo;
if(!buildResponseWithCertificate(hInternet, response, &certificateInfo))
return;
sendSSLErrorToUI(response, handle, errorID, hInternet);
releaseCertificateInfo(&certificateInfo);
}
void SSLAccessController::didReceiveSSLError(ResourceHandle& handle, long errorID, HANDLE hInternet)
{
if (handle.request().targetType() != ResourceRequestBase::TargetIsMainFrame)
return sendCurrentRequest(handle, true);
m_hasSSLError = true;
receiveSSLError(handle, errorID, hInternet);
}
void SSLAccessController::didReceiveClientAuthNeededError(ResourceHandle& handle, long errorID, HANDLE hInternet)
{
m_clientAuthNeeded = true;
ResourceResponse response;
buildResourceResponse(response, NULL);
sendSSLErrorToUI(response, handle, errorID, hInternet);
}
void SSLAccessController::sendCurrentRequest(ResourceHandle& handle, bool noSecurityChecks)
{
bool temp = handle.d->m_noSecurityChecks;
handle.d->m_noSecurityChecks = noSecurityChecks;
handle.sendCurrentRequest();
handle.d->m_noSecurityChecks = temp;
}
void SSLAccessController::continueVisitSSLSite(ResourceHandle& handle, HANDLE hInternet, void* certificate)
{
m_continueVisit = true;
if(!m_clientAuthNeeded)
saveCertInStore(true, m_certContext);
if (certificate != NULL && m_clientAuthNeeded)
{
WinInetManager::InternetSetOptionW(
hInternet,
INTERNET_OPTION_CLIENT_CERT_CONTEXT,
(LPVOID)certificate,
sizeof(CERT_CONTEXT));
}
if (m_hasSSLError)
{
sendCurrentRequest(handle, true);
}
if (m_clientAuthNeeded)
{
sendCurrentRequest(handle, false);
}
resetFlagMembers();
}
void SSLAccessController::cancelVisitSSLSite(ResourceHandle& handle)
{
m_continueVisit = false;
if(!m_clientAuthNeeded)
saveCertInStore(false, m_certContext);
resetFlagMembers();
}
void SSLAccessController::resetFlagMembers()
{
m_continueVisit = true;
m_hasSSLError = false;
m_clientAuthNeeded = false;
}
}
Save certificates to file store
#ifndef SSLCERTSTOREMANAGER_H
#define SSLCERTSTOREMANAGER_H
#include "Noncopyable.h"
#include <WinCrypt.h>
namespace WebCore
{
class SSLCertStoreManager :public Noncopyable
{
public:
static SSLCertStoreManager& getInstance();
bool findCertInStore(bool& inAcceptingStore, PCCERT_CONTEXT cert);
bool saveCertInStore(bool inAcceptingStore, PCCERT_CONTEXT cert);
~SSLCertStoreManager();
private:
SSLCertStoreManager();
bool init();
bool isStoreReady();
bool find(PCCERT_CONTEXT cert, HCERTSTORE store);
bool save(bool inAcceptingStore, PCCERT_CONTEXT cert);
void flush();
void open();
void close();
HCERTSTORE m_trustedStore;
HCERTSTORE m_untrustedStore;
bool m_ready;
};
}
#endif //SSLCERTSTOREMANAGER_H
#include "config.h"
#include "SSLCertStoreManager.h"
#include "WTFString.h"
#define ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
const LPCTSTR WebkitRegistryRoot = L"Software\\WebKit\\";
const LPCTSTR TrustedStorePosition = L"TrustedStoreKey";
const LPCTSTR UntrustedStorePosition = L"UntrustedStoreKey";
const LPCTSTR TrustedStoreFileName = L"\\SD\\BROWSER\\TrustedStore.sto";
const LPCTSTR UntrustedStoreFileName = L"\\SD\\BROWSER\\UntrustedStore.sto";
namespace WebCore
{
SSLCertStoreManager& SSLCertStoreManager::getInstance()
{
static SSLCertStoreManager instance;
return instance;
}
static HKEY getKey(LPCTSTR subKey)
{
String strKey(WebkitRegistryRoot);
strKey += subKey;
HKEY hKey;
if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_CURRENT_USER,
strKey.charactersWithNullTermination(), 0, KEY_ALL_ACCESS, &hKey))
{
DWORD dwDisp = 0;
int succ = RegCreateKeyEx(HKEY_CURRENT_USER,
strKey.charactersWithNullTermination(), 0, NULL, 0, 0, NULL, &hKey, &dwDisp);
if (succ != ERROR_SUCCESS)
return NULL;
RegCloseKey(hKey);
return getKey(subKey);
}
return hKey;
}
static HANDLE getFileHandle(LPCTSTR storeFileName)
{
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = FALSE;
// Obtain a file handle.
return CreateFile(
storeFileName,
GENERIC_READ|GENERIC_WRITE,
0,
&sa,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
}
static HCERTSTORE openStore(LPCTSTR storeFileName)
{
HANDLE hFile = getFileHandle(storeFileName);
if (!hFile)
return NULL;
HCERTSTORE store = CertOpenStore(
CERT_STORE_PROV_FILE, // load certificates from a file
ENCODING_TYPE,
NULL, // use the default HCRYPTPROV
0,
hFile
);
CloseHandle(hFile);
return store;
}
bool SSLCertStoreManager::init()
{
m_trustedStore = openStore(TrustedStoreFileName);
m_untrustedStore = openStore(UntrustedStoreFileName);
m_ready = m_trustedStore && m_untrustedStore;
return m_ready;
}
SSLCertStoreManager::SSLCertStoreManager()
{
init();
}
SSLCertStoreManager::~SSLCertStoreManager()
{
if (m_trustedStore)
CertCloseStore(m_trustedStore, CERT_CLOSE_STORE_FORCE_FLAG);
if (m_untrustedStore)
CertCloseStore(m_untrustedStore, CERT_CLOSE_STORE_FORCE_FLAG);
}
bool SSLCertStoreManager::isStoreReady()
{
return m_ready;
}
bool SSLCertStoreManager::find(PCCERT_CONTEXT cert, HCERTSTORE store)
{
PCCERT_CONTEXT temp = CertFindCertificateInStore(
store,
ENCODING_TYPE, // Use X509_ASN_ENCODING
0, // No dwFlags needed
CERT_FIND_EXISTING,
cert,
NULL);
bool succ = (temp != NULL);
if (temp != NULL)
CertFreeCertificateContext(temp);
return succ;
}
bool SSLCertStoreManager::findCertInStore(bool& inAcceptingStore, PCCERT_CONTEXT cert)
{
if (!isStoreReady())
return false;
if (find(cert, m_trustedStore))
{
inAcceptingStore = true;
return true;
}
if (find(cert, m_untrustedStore))
{
inAcceptingStore = false;
return true;
}
return false;
}
bool SSLCertStoreManager::save(bool inAcceptingStore, PCCERT_CONTEXT cert)
{
HCERTSTORE hStore = inAcceptingStore? m_trustedStore:m_untrustedStore;
BOOL succ = CertAddCertificateContextToStore(hStore, cert, CERT_STORE_ADD_NEW, 0);
if (!succ)
return false;
LPCTSTR storeName = inAcceptingStore? TrustedStoreFileName:UntrustedStoreFileName;
HANDLE hFile = getFileHandle(storeName);
if (!hFile)
return false;
succ = CertSaveStore(
hStore,
ENCODING_TYPE,
CERT_STORE_SAVE_AS_STORE,
CERT_STORE_SAVE_TO_FILE,
hFile,
0);
CloseHandle(hFile);
return succ && succ;
}
bool SSLCertStoreManager::saveCertInStore(bool inAcceptingStore, PCCERT_CONTEXT cert)
{
if (!isStoreReady())
return false;
return save(inAcceptingStore, cert);
}
}
Use winsocket to implement the websocket in webkit
#ifndef SocketStreamHandlePrivate_h
#define SocketStreamHandlePrivate_h
#include "SocketStreamHandleBase.h"
#include "Timer.h"
#include <wtf/MessageQueue.h>
#include <Winsock2.h>
namespace WebCore {
class AuthenticationChallenge;
class Credential;
class SocketStreamHandleClient;
class SocketStreamHandlePrivate;
class ReceivedBuffer;
class SocketStreamHandlePrivate
{
public:
SocketStreamHandlePrivate(SocketStreamHandle*, const KURL&);
virtual ~SocketStreamHandlePrivate();
virtual void connect();
int send(const char* data, int len);
void closeAll();
void receivedData();
protected:
virtual void notifyClientDataReceived(ReceivedBuffer* buffer);
void notifyClientSocketClosed();
void notifyClientSocketConnected();
void socketConnectedTimerFired(Timer<SocketStreamHandlePrivate>*);
void socketErrorTimerFired(Timer<SocketStreamHandlePrivate>*);
bool socketHandleReady();
protected:
SOCKET m_socket;
SocketStreamHandle* m_streamHandle;
KURL m_url;
Timer<SocketStreamHandlePrivate> m_socketConnectedTimer;
Timer<SocketStreamHandlePrivate> m_socketErrorTimer;
friend class ReceiveThread;
ReceiveThread* m_receiveThread;
bool m_socketStartup;
};
class SocketStreamHandlePrivateOverProxy :public SocketStreamHandlePrivate
{
public:
SocketStreamHandlePrivateOverProxy(SocketStreamHandle*, const KURL&);
void connect();
void notifyClientDataReceived(ReceivedBuffer* buffer);
private:
void socketConnectProxyTimerFired(Timer<SocketStreamHandlePrivateOverProxy>*);
Timer<SocketStreamHandlePrivateOverProxy> m_socketConnectProxyTimer;
bool m_webSocketReady;
};
}
#endif
#include "config.h"
#include "SocketStreamHandle.h"
#include "KURL.h"
#include "Logging.h"
#include "NotImplemented.h"
#include "SocketStreamHandleClient.h"
#include "SocketStreamHandlePrivate.h"
#include "wtf/text/CString.h"
#include "StringBuilder.h"
#include "wtf/text/WTFString.h"
#include "wtf/HashSet.h"
#include "CustomEventHandler.h"
#include "CustomEventType.h"
#include "PassOwnPtr.h"
#include <ws2tcpip.h>
#define MAX_SOCKET_BUFFER_LEN 1024
namespace WebCore {
static String proxyName;
static String proxyPort;
const String connectedResponseString("HTTP/1.1 200 OK");
static int WSACleanupReferenceCount = 0;
static HashSet<SocketStreamHandlePrivate*> streamHandlePrivateObjectSet;
static bool initSocket()
{
if (WSACleanupReferenceCount != 0)
{
WSACleanupReferenceCount ++;
}
else
{
WSADATA wsd;
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
{
return false;
}
WSACleanupReferenceCount ++;
}
return true;
}
static void cleanupSocket()
{
if (WSACleanupReferenceCount > 0)
-- WSACleanupReferenceCount;
else
WSACleanup();
}
static SOCKET connectThroughProxy()
{
SOCKET hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (hSocket == INVALID_SOCKET)
return hSocket;
sockaddr_in proxyAddr;
proxyAddr.sin_family = AF_INET;
proxyAddr.sin_addr.s_addr = inet_addr(proxyName.ascii().data());
proxyAddr.sin_port = htons(proxyPort.toInt());
// Connect to the proxy.
int succ = connect(hSocket, (SOCKADDR *)&proxyAddr, sizeof(proxyAddr));
if (succ == SOCKET_ERROR)
{
closesocket(hSocket);
hSocket = INVALID_SOCKET;
}
return hSocket;
}
static SOCKET connectDirectly(const KURL& url)
{
SOCKET hSocket;
ADDRINFO *result = NULL, *ptr = NULL, hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
String port = String::number((url.port()>0)?url.port():80);
//Resolve the server address and port
int succ = getaddrinfo(url.host().utf8().data(), port.ascii().data(), &hints, &result);
if ( succ != 0 )
return INVALID_SOCKET;
// Attempt to connect to an address until one succeeds
for(ptr=result; ptr != NULL ;ptr=ptr->ai_next)
{
// Create a SOCKET for connecting to server
hSocket = socket(ptr->ai_family, ptr->ai_socktype,ptr->ai_protocol);
if (hSocket == INVALID_SOCKET)
return hSocket;
// Connect to server.
succ = connect( hSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (SOCKET_ERROR == succ)
{
closesocket(hSocket);
hSocket = INVALID_SOCKET;
}
else
{
break;
}
}
freeaddrinfo(result);
return hSocket;
}
static bool dataArrived(SOCKET hSocket)
{
fd_set fdread;
int ret;
struct timeval tv;
FD_ZERO(&fdread);
FD_SET(hSocket, &fdread);
ret = select(0, &fdread, NULL, NULL, NULL);
return ret > 0;
}
static bool isUseProxy()
{
return proxyName.length() != 0 && proxyPort.toInt() > 0;
}
static bool sendConnectCommand(SOCKET hSocket, const KURL& url)
{
int sentSize = 0;
if (INVALID_SOCKET != hSocket)
{
StringBuilder builder;
builder.append("CONNECT ");
builder.append(url.host().utf8().data());
builder.append(":");
builder.append(String::number((url.port()>0)?url.port():80));
builder.append(" HTTP/1.1\r\n");
builder.append("HOST: ");
builder.append(url.host().utf8().data());
builder.append("\r\n\r\n");
sentSize = ::send(hSocket, builder.toString().utf8().data(), builder.length(), 0);
}
return sentSize > 0;
}
//////----ReceivedBuffer-------------------------------------------------------
class ReceivedBuffer :public Noncopyable
{
public:
ReceivedBuffer()
{
m_buffer = new char[MAX_SOCKET_BUFFER_LEN];
memset(m_buffer, '\0', MAX_SOCKET_BUFFER_LEN);
m_bufferUsed = 0;
}
ReceivedBuffer::~ReceivedBuffer()
{
delete []m_buffer;
}
inline char* ReceivedBuffer::getBuffer()
{
return m_buffer;
}
inline int ReceivedBuffer::getMaxLength()
{
return MAX_SOCKET_BUFFER_LEN;
}
inline void ReceivedBuffer::setBufferUsed(int len)
{
m_bufferUsed = len;
}
inline int ReceivedBuffer::getLength()
{
return m_bufferUsed;
}
private:
char* m_buffer;
int m_bufferUsed;
};
//////---- Event Callback-------------------------------------------
static LRESULT CALLBACK PostEventCallBack(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
SocketStreamHandlePrivate* handle = (SocketStreamHandlePrivate*)lParam;
if (streamHandlePrivateObjectSet.contains(handle))
{
handle->receivedData();
}
return 0;
}
//////----ReceiveThread-------------------------------------------------------
class ReceiveThread :public Noncopyable
{
public:
ReceiveThread::ReceiveThread(SocketStreamHandlePrivate* streamHandlePrivate)
:m_streamHandlePrivate(streamHandlePrivate),m_threadID(0){}
ReceiveThread::~ReceiveThread(){}
bool ReceiveThread::start()
{
ASSERT(isMainThread());
if (!m_threadID)
m_threadID = createThread(ReceiveThread::threadEntryPointCallback, this, "WebCore: WebSocket");
return m_threadID;
}
void terminate()
{
ASSERT(isMainThread());
if (!m_threadID)
return;
void* returnValue;
waitForThreadCompletion(m_threadID, &returnValue);
m_threadID = 0;
}
static void* ReceiveThread::threadEntryPointCallback(void* thread)
{
return static_cast<ReceiveThread*>(thread)->threadEntryPoint();
}
void* ReceiveThread::threadEntryPoint()
{
SOCKET hSocket = m_streamHandlePrivate->m_socket;
while(dataArrived(hSocket))
{
ReceivedBuffer* buffer = new ReceivedBuffer;
int receivedSize = recv(hSocket, buffer->getBuffer(), buffer->getMaxLength(), 0);
if (receivedSize <= 0)
break;
buffer->setBufferUsed(receivedSize);
m_queue.append(buffer);
CustomEventHandler::PostCustomEvent(
Custom_EV_WebSocket,
NULL,
0,
0,
(LPARAM)m_streamHandlePrivate,
&(PostEventCallBack));
}
return NULL;
}
ThreadIdentifier m_threadID;
MessageQueue<ReceivedBuffer> m_queue;
SocketStreamHandlePrivate* m_streamHandlePrivate;
};
//////----SocketStreamHandlePrivate-----------------------------------------
bool SocketStreamHandlePrivate::socketHandleReady()
{
return m_socket != INVALID_SOCKET;
}
SocketStreamHandlePrivate::SocketStreamHandlePrivate(SocketStreamHandle* streamHandle, const KURL& url)
:m_receiveThread(NULL), m_socketStartup(false),m_socket(INVALID_SOCKET),
m_streamHandle(streamHandle),
m_socketConnectedTimer(this,&SocketStreamHandlePrivate::socketConnectedTimerFired),
m_socketErrorTimer(this, &SocketStreamHandlePrivate::socketErrorTimerFired)
{
m_url = url.copy();
m_receiveThread = new ReceiveThread(this);
streamHandlePrivateObjectSet.add(this);
}
SocketStreamHandlePrivate::~SocketStreamHandlePrivate()
{
streamHandlePrivateObjectSet.remove(this);
closeAll();
if (m_receiveThread != NULL)
{
m_receiveThread->terminate();
delete m_receiveThread;
}
}
void SocketStreamHandlePrivate::connect()
{
if (!initSocket())
return;
m_socketStartup = true;
m_socket = connectDirectly(m_url);
if (INVALID_SOCKET == m_socket)
{
LOG(Network, "SocketStreamHandlePrivate connect to websocket server fail.");
m_socketErrorTimer.startOneShot(0);
return;
}
m_receiveThread->start();
m_socketConnectedTimer.startOneShot(0);
}
void SocketStreamHandlePrivate::notifyClientSocketClosed()
{
if (!m_streamHandle || !m_streamHandle->client())
return;
SocketStreamHandle* streamHandle = m_streamHandle;
m_streamHandle = 0;
// This following call deletes _this_. Nothing should be after it.
streamHandle->client()->didClose(streamHandle);
}
void SocketStreamHandlePrivate::notifyClientDataReceived(ReceivedBuffer* buffer)
{
if (!m_streamHandle || !m_streamHandle->client())
return;
m_streamHandle->client()->didReceiveData(m_streamHandle, buffer->getBuffer(), buffer->getLength());
}
void SocketStreamHandlePrivate::notifyClientSocketConnected()
{
if (!m_streamHandle || !m_streamHandle->client())
return;
m_streamHandle->m_state = SocketStreamHandleBase::Open;
m_streamHandle->client()->didOpen(m_streamHandle);
}
void SocketStreamHandlePrivate::closeAll()
{
if (m_socket != INVALID_SOCKET)
{
closesocket(m_socket);
m_socket = INVALID_SOCKET;
}
if (m_socketStartup)
{
cleanupSocket();
m_socketStartup = false;
}
notifyClientSocketClosed();
}
void SocketStreamHandlePrivate::socketConnectedTimerFired(Timer<SocketStreamHandlePrivate>*)
{
notifyClientSocketConnected();
}
void SocketStreamHandlePrivate::socketErrorTimerFired(Timer<SocketStreamHandlePrivate>*)
{
closeAll();
}
int SocketStreamHandlePrivate::send(const char* data, int len)
{
if (!socketHandleReady())
return 0;
int sentSize = ::send( m_socket, data, len, 0 );
if (sentSize == SOCKET_ERROR)
{
closeAll();
return 0;
}
return sentSize;
}
void SocketStreamHandlePrivate::receivedData()
{
OwnPtr<ReceivedBuffer> buffer = m_receiveThread->m_queue.waitForMessage();
notifyClientDataReceived(buffer.get());
}
//////----SocketStreamHandlePrivateOverProxy-----------------------------------------
SocketStreamHandlePrivateOverProxy::SocketStreamHandlePrivateOverProxy(SocketStreamHandle* streamHandle, const KURL& url)
:SocketStreamHandlePrivate(streamHandle, url),m_webSocketReady(false),
m_socketConnectProxyTimer(this, &SocketStreamHandlePrivateOverProxy::socketConnectProxyTimerFired)
{
}
void SocketStreamHandlePrivateOverProxy::connect()
{
if (!initSocket())
return;
m_socketStartup = true;
m_socket = connectThroughProxy();
bool succ = sendConnectCommand(m_socket, m_url);
if(!succ && INVALID_SOCKET != m_socket)
{
LOG(Network, "SocketStreamHandlePrivate sentConnectCommand fail.");
m_socketErrorTimer.startOneShot(0);
return;
}
m_receiveThread->start();
m_socketConnectProxyTimer.startOneShot(20);
}
void SocketStreamHandlePrivateOverProxy::socketConnectProxyTimerFired(Timer<SocketStreamHandlePrivateOverProxy>*)
{
if (!m_webSocketReady)
closeAll();
}
void SocketStreamHandlePrivateOverProxy::notifyClientDataReceived(ReceivedBuffer* buffer)
{
if (!m_streamHandle || !m_streamHandle->client())
return;
if (m_webSocketReady)
m_streamHandle->client()->didReceiveData(m_streamHandle, buffer->getBuffer(), buffer->getLength());
else
{
String packet(buffer->getBuffer());
if (packet.contains(connectedResponseString))
{
m_webSocketReady = true;
// Notify that client the connection have already established
m_socketConnectedTimer.startOneShot(0);
}
}
}
//////----SocketStreamHandle-----------------------------------------
SocketStreamHandle::SocketStreamHandle(const KURL& url, SocketStreamHandleClient* client)
: SocketStreamHandleBase(url, client)
{
LOG(Network, "SocketStreamHandle %p new client %p", this, m_client);
if (!isUseProxy())
m_p = new SocketStreamHandlePrivate(this, url);
else
m_p = new SocketStreamHandlePrivateOverProxy(this, url);
m_p->connect();
}
SocketStreamHandle::~SocketStreamHandle()
{
LOG(Network, "SocketStreamHandle %p delete", this);
setClient(0);
delete m_p;
}
void SocketStreamHandle::setHttpProxy(const String& name, const String& port)
{
proxyName = name;
proxyPort = port;
}
int SocketStreamHandle::platformSend(const char* data, int len)
{
LOG(Network, "SocketStreamHandle %p platformSend", this);
return m_p->send(data, len);
}
void SocketStreamHandle::platformClose()
{
LOG(Network, "SocketStreamHandle %p platformClose", this);
m_p->closeAll();
}
void SocketStreamHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge&)
{
notImplemented();
}
void SocketStreamHandle::receivedCredential(const AuthenticationChallenge&, const Credential&)
{
notImplemented();
}
void SocketStreamHandle::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&)
{
notImplemented();
}
void SocketStreamHandle::receivedCancellation(const AuthenticationChallenge&)
{
notImplemented();
}
} // namespace WebCore
A simple implement for global new override to track memory.
// heaplog.h
#ifndef BRWHEAPLOG_H
#define BRWHEAPLOG_H
extern const char* __file__;
extern size_t __line__;
#define new (__file__=__FILE__,__line__=__LINE__) && 0 ? NULL : new
void closeLoggingFile();
#endif
//heaplog.cpp
//#include "BrwHeapLog.h"
#include <stdlib.h>
#include <stdio.h>
#include <WTypes.h>
//typedef hash_map<void*, string> AllocHashMap;
static int AllocCount = 0;
HANDLE& getFileHandle()
{
static HANDLE handle = ::CreateFile(TEXT("\\Release\\MemoryTest.txt"),
GENERIC_WRITE,FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
return handle;
}
static void writeFile(HANDLE& handle, char* str)
{
::SetFilePointer(handle, 0, NULL, FILE_END);
DWORD writeLen = 0;
::WriteFile(handle, str, strlen(str), &writeLen, NULL);
}
static void recordAlloc(void* p, const char* fileName, size_t line, size_t size)
{
AllocCount += size;
HANDLE& handle = getFileHandle();
char str[1024];
static char* above = "More";
static char* less = "Less";
char* temp = less;
if(size/1024)
temp = above;
sprintf_s(str, "[%d] File-%s Line-%d Size-%d :%s Than 1KB SUM:%d\r\n", p, fileName, line, size, temp, AllocCount);
writeFile(handle, str);
}
static void unrecordAlloc(void* p)
{
HANDLE& handle = getFileHandle();
char str[100];
sprintf_s(str, "[%d] was deleted\r\n",p);
writeFile(handle, str);
}
void closeLoggingFile()
{
::CloseHandle(getFileHandle());
}
const char* __file__ = "unknown";
size_t __line__ = 0;
void* operator new(size_t size)
{
void *ptr = malloc(size);
recordAlloc(ptr,__file__,__line__, size);
__file__ = "unknown";
__line__ = 0;
return ptr;
}
void operator delete(void *ptr)
{
if(ptr)
{
unrecordAlloc(ptr);
free(ptr);
}
}
Memory corruption reasons
1. wrong type cast, such as convert base class object to a derived one;
2. use invalid pointer. such as access a pointer that have been deleted;
3. Memory over write; array over bound;
4. access error data damaged by multi-thread.
2. use invalid pointer. such as access a pointer that have been deleted;
3. Memory over write; array over bound;
4. access error data damaged by multi-thread.
2012年9月11日 星期二
fatal error C1001: An internal error has occurred in the compiler.
It may be caused by the object file. remove the related obj file!
and sometime the obj files can't be deleted , close all of visual studio or restart windows.
and sometime the obj files can't be deleted , close all of visual studio or restart windows.
訂閱:
文章 (Atom)