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, &regSize);
    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.