From 79ea708e5064cb06f4e05c6cd544f4898f609bf1 Mon Sep 17 00:00:00 2001 From: Jim Evans Date: Tue, 11 Aug 2015 15:17:10 -0700 Subject: [PATCH] Enabling fast failure for cookie manipulation in IE The refactor of cookie handling for the IE driver introduces an incompatibility with the 64-bit IE driver and IE 10 and 11 running on 64-bit Windows. As is the case with sending keystrokes and creating screenshots, a Windows hook procedure is now used for getting and setting cookies in IE. That means that in IE 10 and 11 on 64-bit Windows, where the content rendering process is still 32-bit, you **must** use the 32-bit IEDriverServer.exe in order to manipulate cookies. This commit will now cause exceptions to be thrown if you attempt to set or get cookies using the 64-bit driver against a 32-bit version of IE (or vice versa), but in particular, this will affect users who mistakenly try to use the 64-bit executable on IE 10 or 11 in 64-bit Windows. --- cpp/iedriver/BrowserCookie.cpp | 70 +++++++++- cpp/iedriver/BrowserCookie.h | 10 +- .../CommandHandlers/AddCookieCommandHandler.h | 130 +++-------------- .../DeleteAllCookiesCommandHandler.h | 8 +- .../DeleteCookieCommandHandler.h | 5 +- .../GetAllCookiesCommandHandler.h | 13 +- cpp/iedriver/CookieManager.cpp | 131 ++++++++---------- cpp/iedriver/CookieManager.h | 28 +--- cpp/iedriver/DocumentHost.cpp | 78 ----------- cpp/iedriver/DocumentHost.h | 6 +- cpp/iedriver/HookProcessor.cpp | 50 +++++++ cpp/iedriver/HookProcessor.h | 2 + cpp/iedriver/InputManager.h | 3 - 13 files changed, 229 insertions(+), 305 deletions(-) diff --git a/cpp/iedriver/BrowserCookie.cpp b/cpp/iedriver/BrowserCookie.cpp index a811c244a31c2..ea18120d3e834 100644 --- a/cpp/iedriver/BrowserCookie.cpp +++ b/cpp/iedriver/BrowserCookie.cpp @@ -15,6 +15,7 @@ // limitations under the License. #include "BrowserCookie.h" +#include #include "json.h" namespace webdriver { @@ -24,7 +25,7 @@ BrowserCookie::BrowserCookie(void) { this->value_ = ""; this->domain_ = ""; this->path_ = ""; - this->expiration_time_ = 0L; + this->expiration_time_ = 0.0; this->is_secure_ = false; this->is_httponly_ = false; } @@ -32,6 +33,61 @@ BrowserCookie::BrowserCookie(void) { BrowserCookie::~BrowserCookie(void) { } +BrowserCookie BrowserCookie::FromJson(const Json::Value& json_cookie) { + BrowserCookie cookie; + cookie.name_ = json_cookie["name"].asString(); + cookie.value_ = json_cookie["value"].asString(); + cookie.is_secure_ = json_cookie["secure"].asBool(); + + Json::Value expiry = json_cookie.get("expiry", Json::Value::null); + if (!expiry.isNull()) { + if (expiry.isNumeric()) { + cookie.expiration_time_ = expiry.asDouble(); + } + } + + Json::Value domain = json_cookie.get("domain", Json::Value::null); + if (!domain.isNull() && domain.isString() && domain.asString() != "") { + cookie.domain_ = domain.asString(); + } + + Json::Value path = json_cookie.get("path", Json::Value::null); + if (!path.isNull() && path.isString() && path.asString() != "") { + cookie.path_ = path.asString(); + } + return cookie; +} + +std::string BrowserCookie::ToString() const { + std::string cookie_string(this->name_ + + "=" + + this->value_ + + "; "); + + if (this->is_secure_) { + cookie_string += "secure; "; + } + + if (this->expiration_time_ > 0) { + time_t expiration_time = static_cast(this->expiration_time_); + std::vector raw_formatted_time(30); + tm time_info; + gmtime_s(&time_info, &expiration_time); + std::string format_string = "%a, %d %b %Y %H:%M:%S GMT"; + strftime(&raw_formatted_time[0], 30, format_string.c_str(), &time_info); + std::string formatted_time(&raw_formatted_time[0]); + cookie_string += "expires=" + formatted_time + "; "; + } + + if (this->domain_.size() > 0) { + cookie_string += "domain=" + this->domain_ + "; "; + } + if (this->path_.size() > 0) { + cookie_string += "path=" + this->path_ + "; "; + } + return cookie_string; +} + Json::Value BrowserCookie::ToJson() { Json::Value cookie; cookie["name"] = this->name_; @@ -50,4 +106,16 @@ Json::Value BrowserCookie::ToJson() { return cookie; } +BrowserCookie BrowserCookie::Copy(void) const { + BrowserCookie destination_cookie; + destination_cookie.set_name(this->name_); + destination_cookie.set_value(this->value_); + destination_cookie.set_domain(this->domain_); + destination_cookie.set_path(this->path_); + destination_cookie.set_is_secure(this->is_secure_); + destination_cookie.set_is_httponly(this->is_httponly_); + destination_cookie.set_expiration_time(this->expiration_time_); + return destination_cookie; +} + } \ No newline at end of file diff --git a/cpp/iedriver/BrowserCookie.h b/cpp/iedriver/BrowserCookie.h index 75299a706a33a..b98e8948c1e35 100644 --- a/cpp/iedriver/BrowserCookie.h +++ b/cpp/iedriver/BrowserCookie.h @@ -29,7 +29,11 @@ class BrowserCookie BrowserCookie(void); virtual ~BrowserCookie(void); + static BrowserCookie FromJson(const Json::Value& json_cookie); + Json::Value ToJson(void); + std::string ToString(void) const; + BrowserCookie Copy(void) const; std::string name(void) const { return this->name_; } void set_name(const std::string& name) { this->name_ = name; } @@ -51,8 +55,8 @@ class BrowserCookie this->is_httponly_ = is_httponly; } - long expiration_time(void) const { return this->expiration_time_; } - void set_expiration_time(const long expiration_time) { + double expiration_time(void) const { return this->expiration_time_; } + void set_expiration_time(const double expiration_time) { this->expiration_time_ = expiration_time; } @@ -61,7 +65,7 @@ class BrowserCookie std::string value_; std::string domain_; std::string path_; - long expiration_time_; + double expiration_time_; bool is_secure_; bool is_httponly_; }; diff --git a/cpp/iedriver/CommandHandlers/AddCookieCommandHandler.h b/cpp/iedriver/CommandHandlers/AddCookieCommandHandler.h index bf3c8d634733b..9ee8450d93ab3 100644 --- a/cpp/iedriver/CommandHandlers/AddCookieCommandHandler.h +++ b/cpp/iedriver/CommandHandlers/AddCookieCommandHandler.h @@ -18,6 +18,8 @@ #define WEBDRIVER_IE_ADDCOOKIECOMMANDHANDLER_H_ #include "../Browser.h" +#include "../BrowserCookie.h" +#include "../CookieManager.h" #include "../IECommandHandler.h" #include "../IECommandExecutor.h" #include @@ -43,56 +45,7 @@ class AddCookieCommandHandler : public IECommandHandler { } Json::Value cookie_value = cookie_parameter_iterator->second; - std::string cookie_string(cookie_value["name"].asString() + - "=" + - cookie_value["value"].asString() + - "; "); - cookie_value.removeMember("name"); - cookie_value.removeMember("value"); - - bool is_secure = cookie_value["secure"].asBool(); - if (is_secure) { - cookie_string += "secure; "; - } - cookie_value.removeMember("secure"); - - Json::Value expiry = cookie_value.get("expiry", Json::Value::null); - if (!expiry.isNull()) { - cookie_value.removeMember("expiry"); - if (expiry.isNumeric()) { - time_t expiration_time = static_cast(expiry.asDouble()); - LOG(INFO) << "Received expiration time: " << expiration_time; - std::vector raw_formatted_time(30); - tm time_info; - gmtime_s(&time_info, &expiration_time); - std::string month = this->GetMonthName(time_info.tm_mon); - std::string weekday = this->GetWeekdayName(time_info.tm_wday); - std::string format_string = weekday + ", %d " + month + " %Y %H:%M:%S GMT"; - strftime(&raw_formatted_time[0], 30 , format_string.c_str(), &time_info); - std::string formatted_time(&raw_formatted_time[0]); - LOG(INFO) << "Formated expiration time: " << formatted_time; - cookie_string += "expires=" + formatted_time + "; "; - } - - // If a test sends both "expiry" and "expires", remove "expires" - // from the cookie so that it doesn't get added when the string - // properties of the JSON object are processed. - Json::Value expires_value = cookie_value.get("expires", - Json::Value::null); - if (!expires_value.isNull()) { - cookie_value.removeMember("expires"); - } - } - - Json::Value domain = cookie_value.get("domain", Json::Value::null); - if (!domain.isNull() && domain.isString() && domain.asString() != "") { - cookie_string += "domain=" + domain.asString() + "; "; - } - - Json::Value path = cookie_value.get("path", Json::Value::null); - if (!path.isNull() && path.isString() && path.asString() != "") { - cookie_string += "path=" + path.asString() + "; "; - } + BrowserCookie cookie = BrowserCookie::FromJson(cookie_value); BrowserHandle browser_wrapper; int status_code = executor.GetCurrentBrowser(&browser_wrapper); @@ -101,11 +54,20 @@ class AddCookieCommandHandler : public IECommandHandler { return; } - status_code = browser_wrapper->AddCookie( - cookie_string, - executor.validate_cookie_document_type()); - - if (status_code != WD_SUCCESS) { + status_code = browser_wrapper->cookie_manager()->SetCookie( + browser_wrapper->GetCurrentUrl(), + cookie); + + if (status_code == EUNHANDLEDERROR) { + std::string error = "Could not set cookie. The most common cause "; + error.append("of this error is a mismatch in the bitness between the "); + error.append("driver and browser. In particular, be sure you are not "); + error.append("attempting to use a 64-bit IEDriverServer.exe against "); + error.append("IE 10 or 11, even on 64-bit Windows."); + response->SetErrorResponse(status_code, error); + return; + } + else if (status_code != WD_SUCCESS) { response->SetErrorResponse(status_code, "Unable to add cookie to page"); return; } @@ -113,64 +75,6 @@ class AddCookieCommandHandler : public IECommandHandler { response->SetSuccessResponse(Json::Value::null); } - private: - std::string GetMonthName(int month_name) { - // NOTE: can cookie dates used with put_cookie be localized? - // If so, this function is not needed and a simple call to - // strftime() will suffice. - switch (month_name) { - case 0: - return "Jan"; - case 1: - return "Feb"; - case 2: - return "Mar"; - case 3: - return "Apr"; - case 4: - return "May"; - case 5: - return "Jun"; - case 6: - return "Jul"; - case 7: - return "Aug"; - case 8: - return "Sep"; - case 9: - return "Oct"; - case 10: - return "Nov"; - case 11: - return "Dec"; - } - - return ""; - } - - std::string GetWeekdayName(int weekday_name) { - // NOTE: can cookie dates used with put_cookie be localized? - // If so, this function is not needed and a simple call to - // strftime() will suffice. - switch (weekday_name) { - case 0: - return "Sun"; - case 1: - return "Mon"; - case 2: - return "Tue"; - case 3: - return "Wed"; - case 4: - return "Thu"; - case 5: - return "Fri"; - case 6: - return "Sat"; - } - - return ""; - } }; } // namespace webdriver diff --git a/cpp/iedriver/CommandHandlers/DeleteAllCookiesCommandHandler.h b/cpp/iedriver/CommandHandlers/DeleteAllCookiesCommandHandler.h index f59f5b6bd425a..c3a8704ab9582 100644 --- a/cpp/iedriver/CommandHandlers/DeleteAllCookiesCommandHandler.h +++ b/cpp/iedriver/CommandHandlers/DeleteAllCookiesCommandHandler.h @@ -44,10 +44,14 @@ class DeleteAllCookiesCommandHandler : public IECommandHandler { } std::vector cookies; - browser_wrapper->GetCookies(&cookies); + browser_wrapper->cookie_manager()->GetCookies( + browser_wrapper->GetCurrentUrl(), + &cookies); std::vector::const_iterator it = cookies.begin(); for (; it != cookies.end(); ++it) { - status_code = browser_wrapper->DeleteCookie(*it); + browser_wrapper->cookie_manager()->DeleteCookie( + browser_wrapper->GetCurrentUrl(), + *it); if (status_code != WD_SUCCESS) { response->SetErrorResponse(status_code, "Unable to delete cookie with name '" + it->name() + "'"); diff --git a/cpp/iedriver/CommandHandlers/DeleteCookieCommandHandler.h b/cpp/iedriver/CommandHandlers/DeleteCookieCommandHandler.h index 0232cc0d9c92b..46c956f71616d 100644 --- a/cpp/iedriver/CommandHandlers/DeleteCookieCommandHandler.h +++ b/cpp/iedriver/CommandHandlers/DeleteCookieCommandHandler.h @@ -48,9 +48,12 @@ class DeleteCookieCommandHandler : public IECommandHandler { response->SetErrorResponse(status_code, "Unable to get browser"); return; } + BrowserCookie cookie; cookie.set_name(cookie_name); - status_code = browser_wrapper->DeleteCookie(cookie); + browser_wrapper->cookie_manager()->DeleteCookie( + browser_wrapper->GetCurrentUrl(), + cookie); if (status_code != WD_SUCCESS) { response->SetErrorResponse(status_code, "Unable to delete cookie"); return; diff --git a/cpp/iedriver/CommandHandlers/GetAllCookiesCommandHandler.h b/cpp/iedriver/CommandHandlers/GetAllCookiesCommandHandler.h index 5645d50ce9e0e..0b2bf29dd3f03 100644 --- a/cpp/iedriver/CommandHandlers/GetAllCookiesCommandHandler.h +++ b/cpp/iedriver/CommandHandlers/GetAllCookiesCommandHandler.h @@ -45,7 +45,18 @@ class GetAllCookiesCommandHandler : public IECommandHandler { } std::vector cookies; - browser_wrapper->GetCookies(&cookies); + status_code = browser_wrapper->cookie_manager()->GetCookies( + browser_wrapper->GetCurrentUrl(), + &cookies); + if (status_code == EUNHANDLEDERROR) { + std::string error = "Could not retrieve cookies. The most common cause "; + error.append("of this error is a mismatch in the bitness between the "); + error.append("driver and browser. In particular, be sure you are not "); + error.append("attempting to use a 64-bit IEDriverServer.exe against "); + error.append("IE 10 or 11, even on 64-bit Windows."); + response->SetErrorResponse(status_code, error); + return; + } std::vector::iterator it = cookies.begin(); for (; it != cookies.end(); ++it) { response_value.append(it->ToJson()); diff --git a/cpp/iedriver/CookieManager.cpp b/cpp/iedriver/CookieManager.cpp index 012857366c91f..f2cbe79c0a3e0 100644 --- a/cpp/iedriver/CookieManager.cpp +++ b/cpp/iedriver/CookieManager.cpp @@ -19,6 +19,7 @@ #include #include #include "BrowserCookie.h" +#include "errorcodes.h" #include "HookProcessor.h" #include "logging.h" #include "messages.h" @@ -45,17 +46,11 @@ void CookieManager::Initialize(HWND window_handle) { this->window_handle_ = window_handle; } -bool CookieManager::SetCookie(const std::string& url, - const std::string& cookie_data) { - return this->SetCookie(url, cookie_data, false); -} - -bool CookieManager::SetCookie(const std::string& url, - const std::string& cookie_data, - const bool is_httponly) { - std::string full_data = url + "|" + cookie_data; +int CookieManager::SetCookie(const std::string& url, + const BrowserCookie& cookie) { + std::string full_data = url + "|" + cookie.ToString(); WPARAM set_flags = 0; - if (is_httponly) { + if (cookie.is_httponly()) { set_flags = INTERNET_COOKIE_HTTPONLY; } @@ -66,14 +61,20 @@ bool CookieManager::SetCookie(const std::string& url, hook_settings.communication_type = OneWay; HookProcessor hook; + if (!hook.CanSetWindowsHook(this->window_handle_)) { + LOG(WARN) << "Cannot set cookie because driver and browser are not the " + << "same bit-ness."; + return EUNHANDLEDERROR; + } hook.Initialize(hook_settings); hook.PushData(StringUtilities::ToWString(full_data)); ::SendMessage(this->window_handle_, WD_SET_COOKIE, set_flags, NULL); int status = HookProcessor::GetDataBufferSize(); if (status != 0) { - return false; + LOG(WARN) << "Setting cookie encountered error " << status; + return EINVALIDCOOKIEDOMAIN; } - return true; + return WD_SUCCESS; } int CookieManager::GetCookies(const std::string& url, @@ -93,6 +94,11 @@ int CookieManager::GetCookies(const std::string& url, hook_settings.communication_type = TwoWay; HookProcessor hook; + if (!hook.CanSetWindowsHook(this->window_handle_)) { + LOG(WARN) << "Cannot get cookies because driver and browser are not the " + << "same bit-ness."; + return EUNHANDLEDERROR; + } hook.Initialize(hook_settings); // Get all cookies for the current URL visible to JavaScript. @@ -160,7 +166,7 @@ int CookieManager::GetCookies(const std::string& url, } all_cookies->push_back(browser_cookie); } - return 0; + return WD_SUCCESS; } bool CookieManager::DeleteCookie(const std::string& url, @@ -179,90 +185,67 @@ bool CookieManager::DeleteCookie(const std::string& url, std::string domain = StringUtilities::ToString(wide_domain); std::string path = StringUtilities::ToString(wide_path); - return this->RecursivelyDeleteCookie(url, - cookie.name(), - domain, - path, - cookie.is_httponly()); + + // 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); } bool CookieManager::RecursivelyDeleteCookie(const std::string& url, - const std::string& name, - const std::string& domain, - const std::string& path, - const bool is_httponly) { + const BrowserCookie& cookie) { // TODO: Optimize this path from the recursive to only // call setting the cookie as often as needed. - return this->RecurseCookiePath(url, name, "." + domain, path, is_httponly); + BrowserCookie recursive_cookie = cookie.Copy(); + recursive_cookie.set_domain("." + cookie.domain()); + return this->RecurseCookiePath(url, recursive_cookie); } bool CookieManager::RecurseCookiePath(const std::string& url, - const std::string& name, - const std::string& domain, - const std::string& path, - const bool is_httponly) { + const BrowserCookie& cookie) { size_t number_of_characters = 0; - size_t slash_index = path.find_last_of('/'); - size_t final_index = path.size() - 1; + size_t slash_index = cookie.path().find_last_of('/'); + size_t final_index = cookie.path().size() - 1; if (slash_index == final_index) { number_of_characters = slash_index; - } else { + } + else { number_of_characters = slash_index + 1; } if (slash_index != std::string::npos) { - bool deleted = this->RecurseCookiePath(url, - name, - domain, - path.substr(0, number_of_characters), - is_httponly); + BrowserCookie path_cookie = cookie.Copy(); + path_cookie.set_path(cookie.path().substr(0, number_of_characters)); + bool deleted = this->RecurseCookiePath(url, path_cookie); } - return this->RecurseCookieDomain(url, name, domain, path, is_httponly); + return this->RecurseCookieDomain(url, cookie); } bool CookieManager::RecurseCookieDomain(const std::string& url, - const std::string& name, - const std::string& domain, - const std::string& path, - const bool is_httponly) { - bool deleted = this->DeleteCookie(url, name, domain, path, is_httponly); - size_t dot_index = domain.find_first_of('.'); + const BrowserCookie& cookie) { + int status = this->SetCookie(url, cookie); + + size_t dot_index = cookie.domain().find_first_of('.'); if (dot_index == 0) { - return this->RecurseCookieDomain(url, - name, - domain.substr(1), - path, - is_httponly); + BrowserCookie first_dot_cookie = cookie.Copy(); + first_dot_cookie.set_domain(cookie.domain().substr(1)); + return this->RecurseCookieDomain(url, first_dot_cookie); } else if (dot_index != std::string::npos) { - return this->RecurseCookieDomain(url, - name, - domain.substr(dot_index), - path, - is_httponly); + BrowserCookie no_dot_cookie = cookie.Copy(); + no_dot_cookie.set_domain(cookie.domain().substr(dot_index)); + return this->RecurseCookieDomain(url, no_dot_cookie); } - deleted = this->DeleteCookie(url, name, "", path, is_httponly); - return deleted; -} -bool CookieManager::DeleteCookie(const std::string& url, - const std::string& name, - const std::string& domain, - const std::string& path, - const bool is_httponly) { - // N.B., We can hard-code the value and expiration time, since - // we are deleting the cookie. - std::string cookie_data = name; - cookie_data.append("=deleted"); - if (domain.size() > 0) { - cookie_data.append("; domain="); - cookie_data.append(domain); - } - if (path.size() > 0) { - cookie_data.append("; path="); - cookie_data.append(path); - } - cookie_data.append("; expires=Thu 1 Jan 1970 00:00:01 GMT"); - return this->SetCookie(url, cookie_data, is_httponly); + BrowserCookie no_domain_cookie = cookie.Copy(); + no_domain_cookie.set_domain(""); + status = this->SetCookie(url, no_domain_cookie); + return status == WD_SUCCESS; } void CookieManager::ReadPersistentCookieFile(const std::wstring& file_name, diff --git a/cpp/iedriver/CookieManager.h b/cpp/iedriver/CookieManager.h index 808a87dae77d4..c94fadcebb0e3 100644 --- a/cpp/iedriver/CookieManager.h +++ b/cpp/iedriver/CookieManager.h @@ -35,7 +35,7 @@ class CookieManager { void Initialize(HWND window_handle); int GetCookies(const std::string& url, std::vector* all_cookies); - bool SetCookie(const std::string& url, const std::string& cookie_data); + int SetCookie(const std::string& url, const BrowserCookie& cookie); bool DeleteCookie(const std::string& url, const BrowserCookie& cookie); private: @@ -49,29 +49,9 @@ class CookieManager { const bool include_secure_cookies, std::map* cookies); - bool RecursivelyDeleteCookie(const std::string& url, - const std::string& name, - const std::string& domain, - const std::string& path, - const bool is_httponly); - bool RecurseCookiePath(const std::string& url, - const std::string& name, - const std::string& domain, - const std::string& path, - const bool is_httponly); - bool RecurseCookieDomain(const std::string& url, - const std::string& name, - const std::string& domain, - const std::string& path, - const bool is_httponly); - bool DeleteCookie(const std::string& url, - const std::string& name, - const std::string& domain, - const std::string& path, - const bool is_httponly); - bool SetCookie(const std::string& url, - const std::string& cookie_data, - const bool is_httponly); + bool RecursivelyDeleteCookie(const std::string& url, const BrowserCookie& cookie); + bool RecurseCookiePath(const std::string& url, const BrowserCookie& cookie); + bool RecurseCookieDomain(const std::string& url, const BrowserCookie& cookie); HWND window_handle_; }; diff --git a/cpp/iedriver/DocumentHost.cpp b/cpp/iedriver/DocumentHost.cpp index faf6304ff0922..dc1faba57fcb2 100644 --- a/cpp/iedriver/DocumentHost.cpp +++ b/cpp/iedriver/DocumentHost.cpp @@ -234,30 +234,6 @@ int DocumentHost::SetFocusedFrameByIdentifier(VARIANT frame_identifier) { return WD_SUCCESS; } -void DocumentHost::GetCookies(std::vector* cookies) { - LOG(TRACE) << "Entering DocumentHost::GetCookies"; - this->cookie_manager_->GetCookies(this->GetCurrentUrl(), cookies); -} - -int DocumentHost::AddCookie(const std::string& cookie, - const bool validate_document_type) { - LOG(TRACE) << "Entering DocumentHost::AddCookie"; - bool add_succeeded = this->cookie_manager_->SetCookie(this->GetCurrentUrl(), - cookie); - if (!add_succeeded) { - return EINVALIDCOOKIEDOMAIN; - } - return WD_SUCCESS; -} - -int DocumentHost::DeleteCookie(const BrowserCookie& cookie) { - LOG(TRACE) << "Entering DocumentHost::DeleteCookie"; - // TODO: Optimize and return legitimate error conditions. - bool deletesucceeded = this->cookie_manager_->DeleteCookie(this->GetCurrentUrl(), - cookie); - return WD_SUCCESS; -} - void DocumentHost::PostQuitMessage() { LOG(TRACE) << "Entering DocumentHost::PostQuitMessage"; @@ -271,60 +247,6 @@ void DocumentHost::PostQuitMessage() { reinterpret_cast(message_payload)); } -bool DocumentHost::IsHtmlPage(IHTMLDocument2* doc) { - LOG(TRACE) << "Entering DocumentHost::IsHtmlPage"; - - CComBSTR type; - HRESULT hr = doc->get_mimeType(&type); - if (FAILED(hr)) { - LOGHR(WARN, hr) << "Unable to get mime type for document, call to IHTMLDocument2::get_mimeType failed"; - return false; - } - - // Call once to get the required buffer size, then again to fill - // the buffer. - DWORD mime_type_name_buffer_size = 0; - hr = ::AssocQueryString(0, - ASSOCSTR_FRIENDLYDOCNAME, - L".htm", - NULL, - NULL, - &mime_type_name_buffer_size); - - std::vector mime_type_name_buffer(mime_type_name_buffer_size); - hr = ::AssocQueryString(0, - ASSOCSTR_FRIENDLYDOCNAME, - L".htm", - NULL, - &mime_type_name_buffer[0], - &mime_type_name_buffer_size); - - if (FAILED(hr)) { - LOGHR(WARN, hr) << "Call to AssocQueryString failed in getting friendly name of .htm documents"; - return false; - } - - std::wstring mime_type_name = &mime_type_name_buffer[0]; - std::wstring type_string = type; - if (type_string == mime_type_name) { - return true; - } - - // If the user set Firefox as a default browser at any point, the MIME type - // appears to be "sticky". This isn't elegant, but it appears to alleviate - // the worst symptoms. Tested by using both Safari and Opera as the default - // browser, even after setting IE as the default after Firefox (so the chain - // of defaults looks like (IE -> Firefox -> IE -> Opera) - - if (L"Firefox HTML Document" == mime_type_name) { - LOG(INFO) << "It looks like Firefox was once the default browser. " - << "Guessing the page type from mime type alone"; - return true; - } - - return false; -} - HWND DocumentHost::FindContentWindowHandle(HWND top_level_window_handle) { LOG(TRACE) << "Entering DocumentHost::FindContentWindowHandle"; diff --git a/cpp/iedriver/DocumentHost.h b/cpp/iedriver/DocumentHost.h index 9df3ea7d73137..75e1f166cc6f8 100644 --- a/cpp/iedriver/DocumentHost.h +++ b/cpp/iedriver/DocumentHost.h @@ -68,10 +68,6 @@ class DocumentHost { static bool IsStandardsMode(IHTMLDocument2* doc); static bool GetDocumentDimensions(IHTMLDocument2* doc, LocationInfo* info); - void GetCookies(std::vector* cookies); - int AddCookie(const std::string& cookie, const bool validate_document_type); - int DeleteCookie(const BrowserCookie& cookie); - int SetFocusedFrameByIndex(const int frame_index); int SetFocusedFrameByName(const std::string& frame_name); int SetFocusedFrameByElement(IHTMLElement* frame_element); @@ -84,6 +80,7 @@ class DocumentHost { std::string browser_id(void) const { return this->browser_id_; } HWND window_handle(void) const { return this->window_handle_; } + CookieManager* cookie_manager(void) { return this->cookie_manager_; } protected: void PostQuitMessage(void); @@ -102,7 +99,6 @@ class DocumentHost { } private: - bool IsHtmlPage(IHTMLDocument2* doc); int SetFocusedFrameByIdentifier(VARIANT frame_identifier); CookieManager* cookie_manager_; diff --git a/cpp/iedriver/HookProcessor.cpp b/cpp/iedriver/HookProcessor.cpp index 4b0cdbe4410b4..fca769416eb87 100644 --- a/cpp/iedriver/HookProcessor.cpp +++ b/cpp/iedriver/HookProcessor.cpp @@ -107,6 +107,56 @@ void HookProcessor::Initialize(const HookSettings& settings) { settings.hook_procedure_type); } +bool HookProcessor::CanSetWindowsHook(HWND window_handle) { + int driver_bitness = 32; + HANDLE driver_process_handle = ::GetCurrentProcess(); + if (Is64BitProcess(driver_process_handle)) { + driver_bitness = 64; + } + ::CloseHandle(driver_process_handle); + + DWORD process_id; + DWORD thread_id = ::GetWindowThreadProcessId(window_handle, &process_id); + HANDLE browser_process_handle = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, process_id); + int browser_bitness = 32; + if (Is64BitProcess(browser_process_handle)) { + browser_bitness = 64; + } + + if (driver_bitness != browser_bitness) { + LOG(WARN) << "Unable to set Windows hook procedure. Driver is a " + << driver_bitness << "-bit process, but browser is a " + << browser_bitness << "-bit process."; + } + return driver_bitness == browser_bitness; +} + +bool HookProcessor::Is64BitProcess(HANDLE process_handle) { + bool is_64_bit = false; + SYSTEM_INFO system_info; + ::GetNativeSystemInfo(&system_info); + if (system_info.wProcessorArchitecture == 0) { + // wProcessorArchitecture == 0 means processor architecture + // is "x86", and therefore 32-bit. A 64-bit process can + // never run on the 32-bit OS, so the process must be 32-bit. + return false; + } + + // If the processor architecture is not x86, the process could + // be 64-bit, or it could be 32-bit. We still need to determine + // that. + BOOL is_emulated; + ::IsWow64Process(process_handle, &is_emulated); + if (!is_emulated) { + return true; + } + + // The OS is 64-bit, but the process is running in the + // Windows-on-Windows (Wow64) subsystem, so it must be a 64-bit + // process. + return false; +} + bool HookProcessor::InstallWindowsHook(const std::string& hook_proc_name, const int hook_proc_type) { LOG(TRACE) << "Entering HookProcessor::InstallWindowsHook"; diff --git a/cpp/iedriver/HookProcessor.h b/cpp/iedriver/HookProcessor.h index 3f5110d0f65f6..04a320f746b50 100644 --- a/cpp/iedriver/HookProcessor.h +++ b/cpp/iedriver/HookProcessor.h @@ -47,6 +47,7 @@ class HookProcessor { static void WriteBufferToPipe(const int process_id); + bool CanSetWindowsHook(HWND window_handle); void Initialize(const HookSettings& settings); void Initialize(const std::string& hook_proc_name, const int hook_proc_type); void Dispose(void); @@ -65,6 +66,7 @@ class HookProcessor { bool InstallWindowsHook(const std::string& hook_proc_name, const int hook_proc_type); void UninstallWindowsHook(void); + bool Is64BitProcess(HANDLE process_handle); HookCommunicationType communication_type_; HWND window_handle_; diff --git a/cpp/iedriver/InputManager.h b/cpp/iedriver/InputManager.h index e1b0c361a4ee4..ad67ee71946c7 100644 --- a/cpp/iedriver/InputManager.h +++ b/cpp/iedriver/InputManager.h @@ -94,9 +94,6 @@ class InputManager { void AddMouseInput(HWND window_handle, long flag, int x, int y); void AddKeyboardInput(HWND window_handle, wchar_t character); - //void InstallInputEventHooks(void); - //void UninstallInputEventHooks(void); - //HHOOK InstallWindowsHook(std::string hook_procedure_name, int hook_type); bool WaitForInputEventProcessing(int input_count); bool use_native_events_;