2015-06-23 18:18:18 -04:00
|
|
|
// Licensed to the Software Freedom Conservancy (SFC) under one
|
|
|
|
|
// or more contributor license agreements. See the NOTICE file
|
|
|
|
|
// distributed with this work for additional information
|
|
|
|
|
// regarding copyright ownership. The SFC licenses this file
|
|
|
|
|
// to you under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
|
//
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
//
|
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
|
|
#include "CookieManager.h"
|
2017-02-14 09:48:56 -08:00
|
|
|
|
2015-06-23 18:18:18 -04:00
|
|
|
#include <UrlMon.h>
|
|
|
|
|
#include <wininet.h>
|
2017-02-14 09:48:56 -08:00
|
|
|
|
2015-08-11 15:17:10 -07:00
|
|
|
#include "errorcodes.h"
|
2015-06-23 18:18:18 -04:00
|
|
|
#include "logging.h"
|
2017-02-14 09:48:56 -08:00
|
|
|
|
|
|
|
|
#include "BrowserCookie.h"
|
|
|
|
|
#include "HookProcessor.h"
|
2015-06-23 18:18:18 -04:00
|
|
|
#include "messages.h"
|
2017-02-14 09:48:56 -08:00
|
|
|
#include "StringUtilities.h"
|
2015-06-23 18:18:18 -04:00
|
|
|
|
|
|
|
|
#define TICKS_PER_SECOND 10000000
|
|
|
|
|
#define UNIX_TIME_OFFSET_SECONDS 11644473600L
|
|
|
|
|
|
|
|
|
|
namespace webdriver {
|
|
|
|
|
|
|
|
|
|
struct CookieSendMessageInfo {
|
|
|
|
|
HWND window_handle;
|
|
|
|
|
unsigned int message;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
CookieManager::CookieManager(void) {
|
|
|
|
|
this->window_handle_ = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CookieManager::~CookieManager(void) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CookieManager::Initialize(HWND window_handle) {
|
|
|
|
|
LOG(TRACE) << "Entering CookieManager::Initialize";
|
|
|
|
|
this->window_handle_ = window_handle;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-04 13:15:36 -08:00
|
|
|
bool CookieManager::IsAdvancedCookiesApi() {
|
|
|
|
|
FARPROC address = NULL;
|
|
|
|
|
HMODULE wininet_handle = ::GetModuleHandle(L"wininet");
|
|
|
|
|
if (wininet_handle) {
|
|
|
|
|
address = ::GetProcAddress(wininet_handle, "InternetGetCookieEx2");
|
|
|
|
|
}
|
|
|
|
|
return address != NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-11 15:17:10 -07:00
|
|
|
int CookieManager::SetCookie(const std::string& url,
|
|
|
|
|
const BrowserCookie& cookie) {
|
|
|
|
|
std::string full_data = url + "|" + cookie.ToString();
|
2015-07-07 16:15:26 -04:00
|
|
|
WPARAM set_flags = 0;
|
2015-08-11 15:17:10 -07:00
|
|
|
if (cookie.is_httponly()) {
|
2015-07-07 16:15:26 -04:00
|
|
|
set_flags = INTERNET_COOKIE_HTTPONLY;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-23 18:18:18 -04:00
|
|
|
HookSettings hook_settings;
|
|
|
|
|
hook_settings.hook_procedure_name = "CookieWndProc";
|
|
|
|
|
hook_settings.hook_procedure_type = WH_CALLWNDPROC;
|
|
|
|
|
hook_settings.window_handle = this->window_handle_;
|
|
|
|
|
hook_settings.communication_type = OneWay;
|
|
|
|
|
|
|
|
|
|
HookProcessor hook;
|
2015-08-11 15:17:10 -07:00
|
|
|
if (!hook.CanSetWindowsHook(this->window_handle_)) {
|
|
|
|
|
LOG(WARN) << "Cannot set cookie because driver and browser are not the "
|
|
|
|
|
<< "same bit-ness.";
|
|
|
|
|
return EUNHANDLEDERROR;
|
|
|
|
|
}
|
2015-06-23 18:18:18 -04:00
|
|
|
hook.Initialize(hook_settings);
|
|
|
|
|
hook.PushData(StringUtilities::ToWString(full_data));
|
2015-07-07 16:15:26 -04:00
|
|
|
::SendMessage(this->window_handle_, WD_SET_COOKIE, set_flags, NULL);
|
2015-06-23 18:18:18 -04:00
|
|
|
int status = HookProcessor::GetDataBufferSize();
|
|
|
|
|
if (status != 0) {
|
2015-08-11 15:17:10 -07:00
|
|
|
LOG(WARN) << "Setting cookie encountered error " << status;
|
|
|
|
|
return EINVALIDCOOKIEDOMAIN;
|
2015-06-23 18:18:18 -04:00
|
|
|
}
|
2015-08-11 15:17:10 -07:00
|
|
|
return WD_SUCCESS;
|
2015-06-23 18:18:18 -04:00
|
|
|
}
|
|
|
|
|
|
2015-07-06 18:12:46 -04:00
|
|
|
int CookieManager::GetCookies(const std::string& url,
|
2015-06-29 13:42:37 -04:00
|
|
|
std::vector<BrowserCookie>* all_cookies) {
|
2015-06-23 18:18:18 -04:00
|
|
|
LOG(TRACE) << "Entering CookieManager::GetCookies";
|
2015-06-29 13:42:37 -04:00
|
|
|
std::wstring wide_url = StringUtilities::ToWString(url);
|
|
|
|
|
CComPtr<IUri> parsed_url;
|
|
|
|
|
::CreateUri(wide_url.c_str(), Uri_CREATE_ALLOW_RELATIVE, 0, &parsed_url);
|
|
|
|
|
DWORD url_scheme = 0;
|
|
|
|
|
parsed_url->GetScheme(&url_scheme);
|
|
|
|
|
bool is_secure_url = URL_SCHEME_HTTPS == url_scheme;
|
|
|
|
|
|
2015-06-23 18:18:18 -04:00
|
|
|
HookSettings hook_settings;
|
|
|
|
|
hook_settings.hook_procedure_name = "CookieWndProc";
|
|
|
|
|
hook_settings.hook_procedure_type = WH_CALLWNDPROC;
|
|
|
|
|
hook_settings.window_handle = this->window_handle_;
|
|
|
|
|
hook_settings.communication_type = TwoWay;
|
|
|
|
|
|
|
|
|
|
HookProcessor hook;
|
2015-08-11 15:17:10 -07:00
|
|
|
if (!hook.CanSetWindowsHook(this->window_handle_)) {
|
|
|
|
|
LOG(WARN) << "Cannot get cookies because driver and browser are not the "
|
|
|
|
|
<< "same bit-ness.";
|
|
|
|
|
return EUNHANDLEDERROR;
|
|
|
|
|
}
|
2015-06-23 18:18:18 -04:00
|
|
|
hook.Initialize(hook_settings);
|
|
|
|
|
|
2018-03-04 13:15:36 -08:00
|
|
|
bool supports_advanced_api = this->IsAdvancedCookiesApi();
|
|
|
|
|
if (supports_advanced_api) {
|
|
|
|
|
// The version of WinINet installed supports the InternetGetCookieEx2
|
|
|
|
|
// API, which gets all cookies (session and persistent) at once.
|
|
|
|
|
std::wstring raw_cookie_data =
|
|
|
|
|
this->SendGetCookieMessage(wide_url,
|
|
|
|
|
WD_GET_ALL_COOKIES,
|
|
|
|
|
&hook);
|
|
|
|
|
std::string all_cookies_list = StringUtilities::ToString(raw_cookie_data);
|
|
|
|
|
std::map<std::string, BrowserCookie> cookies;
|
|
|
|
|
this->ParseCookieList(all_cookies_list,
|
|
|
|
|
is_secure_url,
|
|
|
|
|
&cookies);
|
|
|
|
|
std::map<std::string, BrowserCookie>::const_iterator cookie_iterator;
|
|
|
|
|
for (cookie_iterator = cookies.begin();
|
|
|
|
|
cookie_iterator != cookies.end();
|
|
|
|
|
++cookie_iterator) {
|
|
|
|
|
all_cookies->push_back(cookie_iterator->second);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Get all cookies for the current URL visible to JavaScript.
|
|
|
|
|
std::wstring scriptable_cookie_string =
|
|
|
|
|
this->SendGetCookieMessage(wide_url,
|
|
|
|
|
WD_GET_SCRIPTABLE_COOKIES,
|
|
|
|
|
&hook);
|
|
|
|
|
std::map<std::string, std::string> scriptable_cookies;
|
|
|
|
|
this->ParseCookieString(scriptable_cookie_string, &scriptable_cookies);
|
|
|
|
|
|
|
|
|
|
// Get all cookies for the insecure version of the current URL,
|
|
|
|
|
// which will include HttpOnly cookies.
|
|
|
|
|
std::wstring insecure_cookie_string =
|
|
|
|
|
this->SendGetCookieMessage(wide_url,
|
|
|
|
|
WD_GET_HTTPONLY_COOKIES,
|
|
|
|
|
&hook);
|
|
|
|
|
std::map<std::string, std::string> insecure_cookies;
|
|
|
|
|
this->ParseCookieString(insecure_cookie_string, &insecure_cookies);
|
|
|
|
|
|
|
|
|
|
// Get all cookies for the current secure URL. This will include
|
|
|
|
|
// HttpOnly cookies.
|
|
|
|
|
std::wstring secure_cookie_string =
|
|
|
|
|
this->SendGetCookieMessage(wide_url,
|
|
|
|
|
WD_GET_SECURE_COOKIES,
|
|
|
|
|
&hook);
|
|
|
|
|
std::map<std::string, std::string> secure_cookies;
|
|
|
|
|
this->ParseCookieString(secure_cookie_string, &secure_cookies);
|
|
|
|
|
|
|
|
|
|
// Get all of the persistent cookie files in the cache for the
|
|
|
|
|
// URL currently being browsed.
|
|
|
|
|
std::wstring file_list =
|
|
|
|
|
this->SendGetCookieMessage(wide_url,
|
|
|
|
|
WD_GET_COOKIE_CACHE_FILES,
|
|
|
|
|
&hook);
|
|
|
|
|
std::vector<std::wstring> files;
|
|
|
|
|
StringUtilities::Split(file_list, L"|", &files);
|
|
|
|
|
|
|
|
|
|
// Parse the persistent cookie files to produce a list of
|
|
|
|
|
// cookies.
|
|
|
|
|
std::map<std::string, BrowserCookie> persistent_cookies;
|
|
|
|
|
std::vector<std::wstring>::const_iterator file_iterator;
|
|
|
|
|
for (file_iterator = files.begin();
|
|
|
|
|
file_iterator != files.end();
|
|
|
|
|
++file_iterator) {
|
|
|
|
|
std::string cookie_file_contents = this->ReadCookieFile(*file_iterator);
|
|
|
|
|
this->ParseCookieList(cookie_file_contents,
|
|
|
|
|
is_secure_url,
|
|
|
|
|
&persistent_cookies);
|
|
|
|
|
}
|
2015-06-23 18:18:18 -04:00
|
|
|
|
2018-03-04 13:15:36 -08:00
|
|
|
// Loop through the entire list of cookies, including HttpOnly and secure
|
|
|
|
|
// cookies. If the cookie exists as a persistent cookie, use its data from
|
|
|
|
|
// the cache. If the cookie is found in the list of cookies visible to
|
|
|
|
|
// JavaScript, set the HttpOnly property of the cookie to false. If the
|
|
|
|
|
// cookie is found in the list of cookies set on the insecure version of
|
|
|
|
|
// the URL, set the Secure property of the cookie to false.
|
|
|
|
|
std::map<std::string, std::string>::const_iterator it = secure_cookies.begin();
|
|
|
|
|
for (; it != secure_cookies.end(); ++it) {
|
|
|
|
|
BrowserCookie browser_cookie;
|
|
|
|
|
if (persistent_cookies.find(it->first) != persistent_cookies.end()) {
|
|
|
|
|
browser_cookie = persistent_cookies[it->first];
|
|
|
|
|
} else {
|
|
|
|
|
browser_cookie.set_name(it->first);
|
|
|
|
|
browser_cookie.set_value(it->second);
|
|
|
|
|
browser_cookie.set_is_httponly(scriptable_cookies.find(it->first) == scriptable_cookies.end());
|
|
|
|
|
browser_cookie.set_is_secure(insecure_cookies.find(it->first) == insecure_cookies.end());
|
|
|
|
|
}
|
|
|
|
|
all_cookies->push_back(browser_cookie);
|
2015-06-23 18:18:18 -04:00
|
|
|
}
|
|
|
|
|
}
|
2015-08-11 15:17:10 -07:00
|
|
|
return WD_SUCCESS;
|
2015-06-23 18:18:18 -04:00
|
|
|
}
|
|
|
|
|
|
2015-07-06 18:12:46 -04:00
|
|
|
bool CookieManager::DeleteCookie(const std::string& url,
|
2015-07-07 16:15:26 -04:00
|
|
|
const BrowserCookie& cookie) {
|
2015-07-06 18:12:46 -04:00
|
|
|
std::wstring wide_url = StringUtilities::ToWString(url);
|
|
|
|
|
CComPtr<IUri> uri_pointer;
|
|
|
|
|
::CreateUri(wide_url.c_str(), Uri_CREATE_ALLOW_RELATIVE, 0, &uri_pointer);
|
|
|
|
|
|
|
|
|
|
CComBSTR host_bstr;
|
|
|
|
|
uri_pointer->GetHost(&host_bstr);
|
|
|
|
|
std::wstring wide_domain = host_bstr;
|
|
|
|
|
|
|
|
|
|
CComBSTR path_bstr;
|
|
|
|
|
uri_pointer->GetPath(&path_bstr);
|
|
|
|
|
std::wstring wide_path = path_bstr;
|
|
|
|
|
|
|
|
|
|
std::string domain = StringUtilities::ToString(wide_domain);
|
|
|
|
|
std::string path = StringUtilities::ToString(wide_path);
|
2015-08-11 15:17:10 -07:00
|
|
|
|
|
|
|
|
// N.B., We can hard-code the value and expiration time, since
|
|
|
|
|
// we are deleting the cookie. So the value will be "deleted",
|
|
|
|
|
// and the expiration time will be 1000 milliseconds after the
|
|
|
|
|
// zero date (or Thu 1 Jan 1970 00:00:01 GMT).
|
|
|
|
|
BrowserCookie recursive_cookie = cookie.Copy();
|
|
|
|
|
recursive_cookie.set_domain(domain);
|
|
|
|
|
recursive_cookie.set_path(path);
|
|
|
|
|
recursive_cookie.set_value("deleted");
|
|
|
|
|
recursive_cookie.set_expiration_time(1000);
|
|
|
|
|
return this->RecursivelyDeleteCookie(url, recursive_cookie);
|
2015-07-06 18:12:46 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CookieManager::RecursivelyDeleteCookie(const std::string& url,
|
2015-08-11 15:17:10 -07:00
|
|
|
const BrowserCookie& cookie) {
|
2015-07-06 18:12:46 -04:00
|
|
|
// TODO: Optimize this path from the recursive to only
|
|
|
|
|
// call setting the cookie as often as needed.
|
2015-08-11 15:17:10 -07:00
|
|
|
BrowserCookie recursive_cookie = cookie.Copy();
|
|
|
|
|
recursive_cookie.set_domain("." + cookie.domain());
|
|
|
|
|
return this->RecurseCookiePath(url, recursive_cookie);
|
2015-07-06 18:12:46 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CookieManager::RecurseCookiePath(const std::string& url,
|
2015-08-11 15:17:10 -07:00
|
|
|
const BrowserCookie& cookie) {
|
2015-07-06 18:12:46 -04:00
|
|
|
size_t number_of_characters = 0;
|
2015-08-11 15:17:10 -07:00
|
|
|
size_t slash_index = cookie.path().find_last_of('/');
|
|
|
|
|
size_t final_index = cookie.path().size() - 1;
|
2015-07-07 16:15:26 -04:00
|
|
|
if (slash_index == final_index) {
|
2015-07-06 18:12:46 -04:00
|
|
|
number_of_characters = slash_index;
|
2015-08-11 15:17:10 -07:00
|
|
|
}
|
|
|
|
|
else {
|
2015-07-07 16:15:26 -04:00
|
|
|
number_of_characters = slash_index + 1;
|
2015-07-06 18:12:46 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (slash_index != std::string::npos) {
|
2015-08-11 15:17:10 -07:00
|
|
|
BrowserCookie path_cookie = cookie.Copy();
|
|
|
|
|
path_cookie.set_path(cookie.path().substr(0, number_of_characters));
|
|
|
|
|
bool deleted = this->RecurseCookiePath(url, path_cookie);
|
2015-07-06 18:12:46 -04:00
|
|
|
}
|
2015-08-11 15:17:10 -07:00
|
|
|
return this->RecurseCookieDomain(url, cookie);
|
2015-07-06 18:12:46 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CookieManager::RecurseCookieDomain(const std::string& url,
|
2015-08-11 15:17:10 -07:00
|
|
|
const BrowserCookie& cookie) {
|
|
|
|
|
int status = this->SetCookie(url, cookie);
|
|
|
|
|
|
|
|
|
|
size_t dot_index = cookie.domain().find_first_of('.');
|
2015-07-07 19:10:36 -04:00
|
|
|
if (dot_index == 0) {
|
2015-08-11 15:17:10 -07:00
|
|
|
BrowserCookie first_dot_cookie = cookie.Copy();
|
|
|
|
|
first_dot_cookie.set_domain(cookie.domain().substr(1));
|
|
|
|
|
return this->RecurseCookieDomain(url, first_dot_cookie);
|
2015-07-07 19:10:36 -04:00
|
|
|
} else if (dot_index != std::string::npos) {
|
2015-08-11 15:17:10 -07:00
|
|
|
BrowserCookie no_dot_cookie = cookie.Copy();
|
|
|
|
|
no_dot_cookie.set_domain(cookie.domain().substr(dot_index));
|
|
|
|
|
return this->RecurseCookieDomain(url, no_dot_cookie);
|
2015-07-06 18:12:46 -04:00
|
|
|
}
|
|
|
|
|
|
2015-08-11 15:17:10 -07:00
|
|
|
BrowserCookie no_domain_cookie = cookie.Copy();
|
|
|
|
|
no_domain_cookie.set_domain("");
|
|
|
|
|
status = this->SetCookie(url, no_domain_cookie);
|
|
|
|
|
return status == WD_SUCCESS;
|
2015-07-06 18:12:46 -04:00
|
|
|
}
|
|
|
|
|
|
2018-03-04 13:15:36 -08:00
|
|
|
std::string CookieManager::ReadCookieFile(const std::wstring& file_name) {
|
|
|
|
|
LOG(TRACE) << "Entering CookieManager::ReadCookieFile";
|
2015-06-23 18:18:18 -04:00
|
|
|
HANDLE file_handle = ::CreateFile(file_name.c_str(),
|
|
|
|
|
GENERIC_READ,
|
|
|
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
|
|
|
NULL,
|
|
|
|
|
OPEN_EXISTING,
|
|
|
|
|
0,
|
|
|
|
|
NULL);
|
|
|
|
|
// Read the cookie file. Hopefully, we will never have a 2GB cookie file.
|
|
|
|
|
DWORD file_size_high = 0;
|
|
|
|
|
DWORD file_size_low = ::GetFileSize(file_handle, &file_size_high);
|
|
|
|
|
std::vector<char> file_content(file_size_low + 1);
|
|
|
|
|
DWORD bytes_read = 0;
|
|
|
|
|
::ReadFile(file_handle, &file_content[0], file_size_low, &bytes_read, NULL);
|
|
|
|
|
::CloseHandle(file_handle);
|
|
|
|
|
|
|
|
|
|
// Null-terminate and convert to a string for easier manipulation.
|
|
|
|
|
file_content[bytes_read - 1] = '\0';
|
|
|
|
|
std::string cookie_file_contents = &file_content[0];
|
2018-03-04 13:15:36 -08:00
|
|
|
return cookie_file_contents;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CookieManager::ParseCookieList(const std::string& cookie_file_contents,
|
|
|
|
|
const bool include_secure_cookies,
|
|
|
|
|
std::map<std::string, BrowserCookie>* cookies) {
|
|
|
|
|
LOG(TRACE) << "Entering CookieManager::ParseCookieList";
|
2015-06-23 18:18:18 -04:00
|
|
|
|
|
|
|
|
// Each cookie in the file is a record structure separated by
|
|
|
|
|
// a line containing a single asterisk ('*'). Split the file
|
|
|
|
|
// content on this delimiter, and parse each record.
|
|
|
|
|
std::vector<std::string> persistent_cookie_strings;
|
2015-06-29 13:42:37 -04:00
|
|
|
StringUtilities::Split(cookie_file_contents,
|
|
|
|
|
"\n*\n",
|
|
|
|
|
&persistent_cookie_strings);
|
2018-03-04 13:15:36 -08:00
|
|
|
std::vector<std::string>::const_iterator cookie_string_iterator;
|
|
|
|
|
for (cookie_string_iterator = persistent_cookie_strings.begin();
|
2015-06-29 13:42:37 -04:00
|
|
|
cookie_string_iterator != persistent_cookie_strings.end();
|
|
|
|
|
++cookie_string_iterator) {
|
|
|
|
|
BrowserCookie persistent_cookie =
|
2018-03-04 13:15:36 -08:00
|
|
|
this->ParseSingleCookie(*cookie_string_iterator);
|
2015-06-29 13:42:37 -04:00
|
|
|
if (include_secure_cookies || !persistent_cookie.is_secure()) {
|
|
|
|
|
// Omit the cookie if it's 'secure' flag is set and we are *not*
|
|
|
|
|
// browsing using SSL.
|
|
|
|
|
cookies->insert(
|
|
|
|
|
std::pair<std::string, BrowserCookie>(persistent_cookie.name(),
|
|
|
|
|
persistent_cookie));
|
|
|
|
|
}
|
2015-06-23 18:18:18 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-04 13:15:36 -08:00
|
|
|
BrowserCookie CookieManager::ParseSingleCookie(const std::string& cookie) {
|
2015-06-23 18:18:18 -04:00
|
|
|
LOG(TRACE) << "Entering CookieManager::ParsePersistentCookieInfo";
|
2018-03-04 13:15:36 -08:00
|
|
|
// Cookies represented by a structured string record type.
|
|
|
|
|
// This structure is modeled after how some versions of IE
|
|
|
|
|
// stored perisitent cookeis as files on disk. Each cookie
|
|
|
|
|
// is represented by 8 lines in the file separated by line
|
|
|
|
|
// feed (0xA) characters, with the following format:
|
2015-06-23 18:18:18 -04:00
|
|
|
//
|
|
|
|
|
// cookie_name
|
|
|
|
|
// cookie_value
|
|
|
|
|
// cookie.domain.value/cookie/path/value/
|
|
|
|
|
// <integer representing cookie flags>
|
|
|
|
|
// <unsigned long representing the low 32 bits of expiration time>
|
|
|
|
|
// <unsigned long representing the high 32 bits of expiration time>
|
|
|
|
|
// <unsigned long representing the low 32 bits of last-modified time>
|
|
|
|
|
// <unsigned long representing the high 32 bits of last-modified time>
|
|
|
|
|
//
|
|
|
|
|
// Read each of these lines and set the appropriate values
|
|
|
|
|
// in the resulting cookie object.
|
|
|
|
|
std::vector<std::string> cookie_parts;
|
|
|
|
|
StringUtilities::Split(cookie, "\n", &cookie_parts);
|
|
|
|
|
|
|
|
|
|
BrowserCookie cookie_to_return;
|
|
|
|
|
cookie_to_return.set_name(cookie_parts[0]);
|
|
|
|
|
cookie_to_return.set_value(cookie_parts[1]);
|
|
|
|
|
|
|
|
|
|
size_t position = cookie_parts[2].find_first_of("/");
|
|
|
|
|
cookie_to_return.set_domain(cookie_parts[2].substr(0, position));
|
|
|
|
|
cookie_to_return.set_path(cookie_parts[2].substr(position));
|
|
|
|
|
|
|
|
|
|
int flags = atoi(cookie_parts[3].c_str());
|
|
|
|
|
cookie_to_return.set_is_secure(INTERNET_COOKIE_IS_SECURE == (INTERNET_COOKIE_IS_SECURE & flags));
|
|
|
|
|
cookie_to_return.set_is_httponly(INTERNET_COOKIE_HTTPONLY == (INTERNET_COOKIE_HTTPONLY & flags));
|
|
|
|
|
|
2018-03-04 13:15:36 -08:00
|
|
|
if (cookie_parts[4].size() > 0 && cookie_parts[5].size() > 0) {
|
|
|
|
|
unsigned long expiry_time_low = strtoul(cookie_parts[4].c_str(), NULL, 10);
|
|
|
|
|
unsigned long expiry_time_high = strtoul(cookie_parts[5].c_str(), NULL, 10);
|
|
|
|
|
unsigned long long expiration_time = (expiry_time_high * static_cast<long long>(pow(2.0, 32))) + expiry_time_low;
|
|
|
|
|
|
|
|
|
|
// Cookie expiration time is stored in the file as the number
|
|
|
|
|
// of 100-nanosecond ticks since 1 January 1601 12:00:00 AM GMT.
|
|
|
|
|
// We need the number of seconds since 1 January 1970 12:00:00 AM GMT.
|
|
|
|
|
// This is the conversion.
|
|
|
|
|
unsigned long cookie_expiration_time = static_cast<unsigned long>((expiration_time / TICKS_PER_SECOND) - UNIX_TIME_OFFSET_SECONDS);
|
|
|
|
|
cookie_to_return.set_expiration_time(cookie_expiration_time);
|
|
|
|
|
}
|
2015-06-23 18:18:18 -04:00
|
|
|
return cookie_to_return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CookieManager::ParseCookieString(const std::wstring& cookie_string,
|
|
|
|
|
std::map<std::string, std::string>* cookies) {
|
|
|
|
|
LOG(TRACE) << "Entering CookieManager::ParseCookieString";
|
|
|
|
|
std::wstring cookie_string_copy = cookie_string;
|
|
|
|
|
while (cookie_string_copy.size() > 0) {
|
|
|
|
|
size_t cookie_delimiter_pos = cookie_string_copy.find(L"; ");
|
|
|
|
|
std::wstring cookie = cookie_string_copy.substr(0, cookie_delimiter_pos);
|
|
|
|
|
if (cookie_delimiter_pos == std::wstring::npos) {
|
|
|
|
|
cookie_string_copy = L"";
|
|
|
|
|
} else {
|
|
|
|
|
cookie_string_copy = cookie_string_copy.substr(cookie_delimiter_pos + 2);
|
|
|
|
|
}
|
|
|
|
|
size_t cookie_separator_pos(cookie.find_first_of(L"="));
|
|
|
|
|
std::string cookie_name(StringUtilities::ToString(cookie.substr(0, cookie_separator_pos)));
|
|
|
|
|
std::string cookie_value(StringUtilities::ToString(cookie.substr(cookie_separator_pos + 1)));
|
|
|
|
|
cookies->insert(std::pair<std::string, std::string>(cookie_name, cookie_value));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::wstring CookieManager::SendGetCookieMessage(const std::wstring& url,
|
|
|
|
|
const unsigned int message,
|
|
|
|
|
HookProcessor* hook) {
|
|
|
|
|
LOG(TRACE) << "Entering CookieManager::SendGetCookieMessage";
|
|
|
|
|
hook->PushData(url);
|
|
|
|
|
|
|
|
|
|
// Since the named pipe server has to wait for the named pipe client
|
|
|
|
|
// injected into the browser to connect to it before reading the data,
|
|
|
|
|
// and since SendMessage is synchronous, we need to send the message
|
|
|
|
|
// from a different thread to avoid a deadlock.
|
|
|
|
|
CookieSendMessageInfo info;
|
|
|
|
|
info.window_handle = this->window_handle_;
|
|
|
|
|
info.message = message;
|
|
|
|
|
unsigned int thread_id = 0;
|
|
|
|
|
HANDLE thread_handle = reinterpret_cast<HANDLE>(_beginthreadex(NULL,
|
|
|
|
|
0,
|
|
|
|
|
&CookieManager::ThreadProc,
|
|
|
|
|
reinterpret_cast<void*>(&info),
|
|
|
|
|
0,
|
|
|
|
|
&thread_id));
|
|
|
|
|
if (thread_handle != NULL) {
|
|
|
|
|
::CloseHandle(thread_handle);
|
|
|
|
|
} else {
|
|
|
|
|
LOGERR(DEBUG) << "Unable to create thread";
|
|
|
|
|
}
|
|
|
|
|
std::vector<char> buffer(0);
|
|
|
|
|
int bytes = hook->PullData(&buffer);
|
|
|
|
|
std::wstring cookies = reinterpret_cast<const wchar_t*>(&buffer[0]);
|
|
|
|
|
return cookies;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned int WINAPI CookieManager::ThreadProc(LPVOID lpParameter) {
|
|
|
|
|
LOG(TRACE) << "Entering CookieManager::ThreadProc";
|
|
|
|
|
|
|
|
|
|
CookieSendMessageInfo* info = reinterpret_cast<CookieSendMessageInfo*>(lpParameter);
|
|
|
|
|
DWORD process_id = ::GetCurrentProcessId();
|
|
|
|
|
LRESULT result = ::SendMessage(info->window_handle,
|
|
|
|
|
info->message,
|
|
|
|
|
process_id,
|
|
|
|
|
NULL);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace webdriver
|
|
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
extern "C" {
|
|
|
|
|
#endif
|
|
|
|
|
|
2018-03-13 14:28:35 -07:00
|
|
|
// In order to run the IE driver against versions of IE that do not include
|
|
|
|
|
// a version of WinINet.dll that supports the InternetGetCookiesEx2 API,
|
|
|
|
|
// we must access the API in a way that does not import it into our DLL.
|
|
|
|
|
// To that end, we duplicate the INTERNET_COOKIE2 structure here, and will
|
|
|
|
|
// call the API (if it exists) via GetModuleHandle and GetProcAddress.
|
|
|
|
|
typedef struct {
|
|
|
|
|
PWSTR pwszName;
|
|
|
|
|
PWSTR pwszValue;
|
|
|
|
|
PWSTR pwszDomain;
|
|
|
|
|
PWSTR pwszPath;
|
|
|
|
|
DWORD dwFlags;
|
|
|
|
|
FILETIME ftExpires;
|
|
|
|
|
BOOL fExpiresSet;
|
|
|
|
|
} INTERNETCOOKIE2;
|
|
|
|
|
|
|
|
|
|
typedef void* (__stdcall *InternetFreeCookiesProc)(INTERNETCOOKIE2*, DWORD);
|
|
|
|
|
typedef DWORD(__stdcall *InternetGetCookieEx2Proc)(PCWSTR, PCWSTR, DWORD, INTERNETCOOKIE2**, PDWORD);
|
|
|
|
|
|
2015-06-23 18:18:18 -04:00
|
|
|
LRESULT CALLBACK CookieWndProc(int nCode, WPARAM wParam, LPARAM lParam) {
|
|
|
|
|
CWPSTRUCT* call_window_proc_struct = reinterpret_cast<CWPSTRUCT*>(lParam);
|
|
|
|
|
if (WM_COPYDATA == call_window_proc_struct->message) {
|
|
|
|
|
COPYDATASTRUCT* data = reinterpret_cast<COPYDATASTRUCT*>(call_window_proc_struct->lParam);
|
|
|
|
|
webdriver::HookProcessor::CopyDataToBuffer(data->cbData, data->lpData);
|
2018-03-04 13:15:36 -08:00
|
|
|
} else if (WD_GET_ALL_COOKIES == call_window_proc_struct->message) {
|
|
|
|
|
std::wstring url = webdriver::HookProcessor::CopyWStringFromBuffer();
|
|
|
|
|
int driver_process_id = static_cast<int>(call_window_proc_struct->wParam);
|
|
|
|
|
|
|
|
|
|
CComPtr<IUri> uri_pointer;
|
|
|
|
|
HRESULT hr = ::CreateUri(url.c_str(), Uri_CREATE_ALLOW_RELATIVE, 0, &uri_pointer);
|
|
|
|
|
DWORD scheme = 0;
|
|
|
|
|
uri_pointer->GetScheme(&scheme);
|
|
|
|
|
CComBSTR scheme_bstr;
|
|
|
|
|
uri_pointer->GetSchemeName(&scheme_bstr);
|
|
|
|
|
CComBSTR host_bstr;
|
|
|
|
|
uri_pointer->GetHost(&host_bstr);
|
|
|
|
|
CComBSTR path_bstr;
|
|
|
|
|
uri_pointer->GetPath(&path_bstr);
|
|
|
|
|
|
2018-03-13 14:28:35 -07:00
|
|
|
std::wstring parsed_uri = scheme_bstr;
|
2018-03-04 13:15:36 -08:00
|
|
|
parsed_uri.append(L"://");
|
|
|
|
|
parsed_uri.append(host_bstr);
|
|
|
|
|
parsed_uri.append(path_bstr);
|
|
|
|
|
|
2018-03-13 14:28:35 -07:00
|
|
|
InternetGetCookieEx2Proc get_cookie_proc = NULL;
|
|
|
|
|
InternetFreeCookiesProc free_cookies_proc = NULL;
|
|
|
|
|
HMODULE wininet_handle = ::GetModuleHandle(L"wininet");
|
|
|
|
|
if (wininet_handle) {
|
|
|
|
|
get_cookie_proc = reinterpret_cast<InternetGetCookieEx2Proc>(::GetProcAddress(wininet_handle, "InternetGetCookieEx2"));
|
|
|
|
|
free_cookies_proc = reinterpret_cast<InternetFreeCookiesProc>(::GetProcAddress(wininet_handle, "InternetFreeCookies"));
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-04 13:15:36 -08:00
|
|
|
DWORD cookie_count = 0;
|
2018-03-13 14:28:35 -07:00
|
|
|
INTERNETCOOKIE2* cookie_pointer = NULL;
|
|
|
|
|
DWORD success = 1;
|
|
|
|
|
if (get_cookie_proc) {
|
|
|
|
|
success = get_cookie_proc(parsed_uri.c_str(),
|
|
|
|
|
NULL,
|
|
|
|
|
INTERNET_COOKIE_NON_SCRIPT,
|
|
|
|
|
&cookie_pointer,
|
|
|
|
|
&cookie_count);
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-04 13:15:36 -08:00
|
|
|
if (success == 0) {
|
|
|
|
|
// Mimic the format of the old persistent cookie files for ease of
|
|
|
|
|
// transmission back to the driver and parsing.
|
|
|
|
|
std::wstring all_cookies = L"";
|
2018-03-06 06:40:09 -08:00
|
|
|
for (DWORD cookie_index = 0; cookie_index < cookie_count; ++cookie_index) {
|
2018-03-04 13:15:36 -08:00
|
|
|
if (all_cookies.size() > 0) {
|
|
|
|
|
all_cookies.append(L"\n*\n");
|
|
|
|
|
}
|
2018-03-13 14:28:35 -07:00
|
|
|
INTERNETCOOKIE2* current_cookie = cookie_pointer + cookie_index;
|
2023-10-07 11:13:19 -04:00
|
|
|
std::wstring cookie_name = L"";
|
|
|
|
|
if (current_cookie->pwszName) {
|
|
|
|
|
// Note that the spec appears to allow "nameless" cookies,
|
|
|
|
|
// which clients like Selenium may not support.
|
|
|
|
|
cookie_name = current_cookie->pwszName;
|
|
|
|
|
}
|
2018-08-08 10:28:52 -07:00
|
|
|
std::wstring cookie_value = L"";
|
|
|
|
|
if (current_cookie->pwszValue) {
|
|
|
|
|
cookie_value = current_cookie->pwszValue;
|
|
|
|
|
}
|
2023-10-07 11:13:19 -04:00
|
|
|
|
|
|
|
|
// TODO: The spec does not allow a cookie with an empty name
|
|
|
|
|
// and value. It's unclear what the driver could do in this
|
|
|
|
|
// case, but we should probably handle it somehow in the off
|
|
|
|
|
// chance it ever comes up.
|
2018-08-08 10:28:52 -07:00
|
|
|
std::wstring cookie_domain = L"";
|
|
|
|
|
if (current_cookie->pwszDomain) {
|
|
|
|
|
cookie_domain = current_cookie->pwszDomain;
|
|
|
|
|
}
|
|
|
|
|
std::wstring cookie_path = L"";
|
|
|
|
|
if (current_cookie->pwszPath) {
|
|
|
|
|
cookie_path = current_cookie->pwszPath;
|
|
|
|
|
}
|
2018-03-04 13:15:36 -08:00
|
|
|
DWORD flags = current_cookie->dwFlags;
|
|
|
|
|
FILETIME expires = current_cookie->ftExpires;
|
|
|
|
|
all_cookies.append(cookie_name).append(L"\n");
|
|
|
|
|
all_cookies.append(cookie_value).append(L"\n");
|
|
|
|
|
all_cookies.append(cookie_domain).append(L"/").append(cookie_path).append(L"\n");
|
|
|
|
|
all_cookies.append(std::to_wstring(flags)).append(L"\n");
|
|
|
|
|
// If the expiration time is set, add it to the string for the cookie.
|
|
|
|
|
// If not, append empty fields to the record so subsequent parsing
|
|
|
|
|
// of the string will still work.
|
|
|
|
|
if (current_cookie->fExpiresSet) {
|
|
|
|
|
all_cookies.append(std::to_wstring(expires.dwLowDateTime)).append(L"\n");
|
|
|
|
|
all_cookies.append(std::to_wstring(expires.dwHighDateTime)).append(L"\n");
|
|
|
|
|
} else {
|
|
|
|
|
all_cookies.append(L"\n\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-03-13 14:28:35 -07:00
|
|
|
free_cookies_proc(cookie_pointer, cookie_count);
|
2018-03-04 13:15:36 -08:00
|
|
|
webdriver::HookProcessor::CopyWStringToBuffer(all_cookies);
|
|
|
|
|
} else {
|
|
|
|
|
webdriver::HookProcessor::SetDataBufferSize(sizeof(wchar_t));
|
|
|
|
|
}
|
|
|
|
|
webdriver::HookProcessor::WriteBufferToPipe(driver_process_id);
|
2015-06-23 18:18:18 -04:00
|
|
|
} else if (WD_GET_HTTPONLY_COOKIES == call_window_proc_struct->message ||
|
2015-06-29 13:42:37 -04:00
|
|
|
WD_GET_SCRIPTABLE_COOKIES == call_window_proc_struct->message ||
|
|
|
|
|
WD_GET_SECURE_COOKIES == call_window_proc_struct->message) {
|
2015-06-23 18:18:18 -04:00
|
|
|
std::wstring url = webdriver::HookProcessor::CopyWStringFromBuffer();
|
|
|
|
|
int driver_process_id = static_cast<int>(call_window_proc_struct->wParam);
|
2015-06-29 13:42:37 -04:00
|
|
|
|
2015-06-23 18:18:18 -04:00
|
|
|
DWORD get_cookie_flags = 0;
|
2015-06-29 13:42:37 -04:00
|
|
|
if (WD_GET_HTTPONLY_COOKIES == call_window_proc_struct->message ||
|
2018-03-04 13:15:36 -08:00
|
|
|
WD_GET_SECURE_COOKIES == call_window_proc_struct->message) {
|
2015-06-23 18:18:18 -04:00
|
|
|
get_cookie_flags = INTERNET_COOKIE_HTTPONLY;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-29 13:42:37 -04:00
|
|
|
CComPtr<IUri> uri_pointer;
|
|
|
|
|
HRESULT hr = ::CreateUri(url.c_str(), Uri_CREATE_ALLOW_RELATIVE, 0, &uri_pointer);
|
|
|
|
|
DWORD scheme = 0;
|
|
|
|
|
uri_pointer->GetScheme(&scheme);
|
|
|
|
|
CComBSTR scheme_bstr;
|
|
|
|
|
uri_pointer->GetSchemeName(&scheme_bstr);
|
|
|
|
|
CComBSTR host_bstr;
|
|
|
|
|
uri_pointer->GetHost(&host_bstr);
|
|
|
|
|
CComBSTR path_bstr;
|
|
|
|
|
uri_pointer->GetPath(&path_bstr);
|
2018-03-04 13:15:36 -08:00
|
|
|
|
2015-06-29 13:42:37 -04:00
|
|
|
// Get only the cookies for the base URL, omitting port, if there is one.
|
|
|
|
|
// N.B., we only return cookies secure cookies when browsing a site using
|
|
|
|
|
// SSL. The browser won't see cookies with the 'secure' flag for sites
|
|
|
|
|
// visited using plain http.
|
|
|
|
|
std::wstring parsed_uri = L"http";
|
|
|
|
|
if ((WD_GET_SECURE_COOKIES == call_window_proc_struct->message ||
|
2018-03-04 13:15:36 -08:00
|
|
|
WD_GET_SCRIPTABLE_COOKIES == call_window_proc_struct->message) &&
|
2015-06-29 13:42:37 -04:00
|
|
|
URL_SCHEME_HTTPS == scheme) {
|
|
|
|
|
parsed_uri.append(L"s");
|
|
|
|
|
}
|
|
|
|
|
parsed_uri.append(L"://");
|
|
|
|
|
parsed_uri.append(host_bstr);
|
|
|
|
|
parsed_uri.append(path_bstr);
|
|
|
|
|
|
2015-06-23 18:18:18 -04:00
|
|
|
// Call InternetGetCookieEx once to get the size of the buffer needed,
|
|
|
|
|
// then call again with the appropriately sized buffer allocated.
|
|
|
|
|
DWORD buffer_size = 0;
|
2015-06-29 13:42:37 -04:00
|
|
|
BOOL success = ::InternetGetCookieEx(parsed_uri.c_str(),
|
2015-06-23 18:18:18 -04:00
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
&buffer_size,
|
|
|
|
|
get_cookie_flags,
|
|
|
|
|
NULL);
|
|
|
|
|
if (success) {
|
2015-06-24 18:07:58 -04:00
|
|
|
webdriver::HookProcessor::SetDataBufferSize(buffer_size);
|
2015-06-29 13:42:37 -04:00
|
|
|
::InternetGetCookieEx(parsed_uri.c_str(),
|
2015-06-23 18:18:18 -04:00
|
|
|
NULL,
|
2015-06-24 18:07:58 -04:00
|
|
|
reinterpret_cast<LPTSTR>(webdriver::HookProcessor::GetDataBufferAddress()),
|
2015-06-23 18:18:18 -04:00
|
|
|
&buffer_size,
|
|
|
|
|
get_cookie_flags,
|
|
|
|
|
NULL);
|
|
|
|
|
|
2015-06-24 18:07:58 -04:00
|
|
|
webdriver::HookProcessor::WriteBufferToPipe(driver_process_id);
|
2015-06-23 18:18:18 -04:00
|
|
|
} else {
|
|
|
|
|
if (ERROR_NO_MORE_ITEMS == ::GetLastError()) {
|
2015-06-24 18:07:58 -04:00
|
|
|
webdriver::HookProcessor::SetDataBufferSize(sizeof(wchar_t));
|
|
|
|
|
webdriver::HookProcessor::WriteBufferToPipe(driver_process_id);
|
2015-06-23 18:18:18 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (WD_GET_COOKIE_CACHE_FILES == call_window_proc_struct->message) {
|
|
|
|
|
int driver_process_id = static_cast<int>(call_window_proc_struct->wParam);
|
|
|
|
|
std::wstring file_list = L"";
|
|
|
|
|
std::wstring url = webdriver::HookProcessor::CopyWStringFromBuffer();
|
|
|
|
|
|
|
|
|
|
// We need to remove the port to find the entry in the cache.
|
|
|
|
|
CComPtr<IUri> uri_pointer;
|
|
|
|
|
HRESULT hr = ::CreateUri(url.c_str(), Uri_CREATE_ALLOW_RELATIVE, 0, &uri_pointer);
|
|
|
|
|
CComBSTR host_bstr;
|
|
|
|
|
uri_pointer->GetHost(&host_bstr);
|
|
|
|
|
CComBSTR path_bstr;
|
|
|
|
|
uri_pointer->GetPath(&path_bstr);
|
|
|
|
|
std::wstring parsed_uri = host_bstr;
|
|
|
|
|
parsed_uri.append(path_bstr);
|
|
|
|
|
|
|
|
|
|
// A 2048-byte buffer should be large enough to handle cookie
|
|
|
|
|
// cache entries in all but the most extreme cases.
|
|
|
|
|
HANDLE cache_enum_handle = NULL;
|
|
|
|
|
DWORD entry_size = 2048;
|
|
|
|
|
LPINTERNET_CACHE_ENTRY_INFO entry = NULL;
|
|
|
|
|
std::vector<char> entry_buffer(entry_size);
|
|
|
|
|
entry = reinterpret_cast<INTERNET_CACHE_ENTRY_INFO*>(&entry_buffer[0]);
|
|
|
|
|
cache_enum_handle = ::FindFirstUrlCacheEntry(L"cookie:",
|
|
|
|
|
entry,
|
|
|
|
|
&entry_size);
|
|
|
|
|
if (cache_enum_handle == NULL &&
|
|
|
|
|
ERROR_INSUFFICIENT_BUFFER == ::GetLastError()) {
|
|
|
|
|
entry_buffer.resize(entry_size);
|
|
|
|
|
entry = reinterpret_cast<INTERNET_CACHE_ENTRY_INFO*>(&entry_buffer[0]);
|
|
|
|
|
cache_enum_handle = ::FindFirstUrlCacheEntry(L"cookie:",
|
|
|
|
|
entry,
|
|
|
|
|
&entry_size);
|
|
|
|
|
}
|
|
|
|
|
while (cache_enum_handle != NULL) {
|
|
|
|
|
if (COOKIE_CACHE_ENTRY == (entry->CacheEntryType & COOKIE_CACHE_ENTRY)) {
|
|
|
|
|
std::wstring name = entry->lpszSourceUrlName;
|
|
|
|
|
size_t name_separator_pos(name.find_first_of(L"@"));
|
|
|
|
|
std::wstring domain = name.substr(name_separator_pos + 1);
|
|
|
|
|
if (parsed_uri.find(domain) != std::wstring::npos) {
|
|
|
|
|
if (file_list.size() > 0) {
|
|
|
|
|
file_list.append(L"|");
|
|
|
|
|
}
|
|
|
|
|
file_list.append(entry->lpszLocalFileName);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
BOOL success = ::FindNextUrlCacheEntry(cache_enum_handle,
|
|
|
|
|
entry,
|
|
|
|
|
&entry_size);
|
|
|
|
|
if (!success) {
|
|
|
|
|
DWORD error = ::GetLastError();
|
|
|
|
|
if (ERROR_INSUFFICIENT_BUFFER == error) {
|
|
|
|
|
entry_buffer.resize(entry_size);
|
|
|
|
|
BOOL other_success = ::FindNextUrlCacheEntry(cache_enum_handle,
|
|
|
|
|
entry,
|
|
|
|
|
&entry_size);
|
|
|
|
|
} else if (ERROR_NO_MORE_ITEMS == error) {
|
|
|
|
|
::FindCloseUrlCache(cache_enum_handle);
|
|
|
|
|
cache_enum_handle = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-06-24 18:07:58 -04:00
|
|
|
webdriver::HookProcessor::CopyWStringToBuffer(file_list);
|
|
|
|
|
webdriver::HookProcessor::WriteBufferToPipe(driver_process_id);
|
2015-06-23 18:18:18 -04:00
|
|
|
} else if (WD_SET_COOKIE == call_window_proc_struct->message) {
|
2015-07-07 16:15:26 -04:00
|
|
|
DWORD set_cookie_flags = static_cast<DWORD>(call_window_proc_struct->wParam);
|
2015-06-23 18:18:18 -04:00
|
|
|
std::wstring cookie_data = webdriver::HookProcessor::CopyWStringFromBuffer();
|
|
|
|
|
size_t url_separator_pos = cookie_data.find_first_of(L"|");
|
|
|
|
|
std::wstring url = cookie_data.substr(0, url_separator_pos);
|
|
|
|
|
std::wstring cookie = cookie_data.substr(url_separator_pos + 1);
|
|
|
|
|
|
|
|
|
|
CComPtr<IUri> uri_pointer;
|
|
|
|
|
HRESULT hr = ::CreateUri(url.c_str(), Uri_CREATE_ALLOW_RELATIVE, 0, &uri_pointer);
|
|
|
|
|
CComBSTR scheme_bstr;
|
|
|
|
|
uri_pointer->GetSchemeName(&scheme_bstr);
|
|
|
|
|
CComBSTR host_bstr;
|
|
|
|
|
uri_pointer->GetHost(&host_bstr);
|
|
|
|
|
std::wstring parsed_uri = scheme_bstr;
|
|
|
|
|
parsed_uri.append(L"://");
|
|
|
|
|
parsed_uri.append(host_bstr);
|
|
|
|
|
|
2015-06-24 18:07:58 -04:00
|
|
|
// Leverage the shared data buffer size to return the error code
|
|
|
|
|
// back to the driver, if necessary.
|
2015-07-07 16:15:26 -04:00
|
|
|
DWORD cookie_set = ::InternetSetCookieEx(parsed_uri.c_str(),
|
|
|
|
|
NULL,
|
|
|
|
|
cookie.c_str(),
|
|
|
|
|
set_cookie_flags,
|
|
|
|
|
NULL);
|
2015-06-23 18:18:18 -04:00
|
|
|
if (cookie_set) {
|
|
|
|
|
webdriver::HookProcessor::SetDataBufferSize(0);
|
|
|
|
|
} else {
|
|
|
|
|
DWORD error = ::GetLastError();
|
|
|
|
|
webdriver::HookProcessor::SetDataBufferSize(error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ::CallNextHookEx(NULL, nCode, wParam, lParam);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
}
|
|
|
|
|
#endif
|