Skip to content

Commit

Permalink
Enabling fast failure for cookie manipulation in IE
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jimevans committed Aug 11, 2015
1 parent e7c2fa9 commit 79ea708
Show file tree
Hide file tree
Showing 13 changed files with 229 additions and 305 deletions.
70 changes: 69 additions & 1 deletion cpp/iedriver/BrowserCookie.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
// limitations under the License.

#include "BrowserCookie.h"
#include <ctime>
#include "json.h"

namespace webdriver {
Expand All @@ -24,14 +25,69 @@ 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;
}

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<time_t>(this->expiration_time_);
std::vector<char> 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_;
Expand All @@ -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;
}

}
10 changes: 7 additions & 3 deletions cpp/iedriver/BrowserCookie.h
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand All @@ -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;
}

Expand All @@ -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_;
};
Expand Down
130 changes: 17 additions & 113 deletions cpp/iedriver/CommandHandlers/AddCookieCommandHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <ctime>
Expand All @@ -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<time_t>(expiry.asDouble());
LOG(INFO) << "Received expiration time: " << expiration_time;
std::vector<char> 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);
Expand All @@ -101,76 +54,27 @@ 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;
}

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
Expand Down
8 changes: 6 additions & 2 deletions cpp/iedriver/CommandHandlers/DeleteAllCookiesCommandHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,14 @@ class DeleteAllCookiesCommandHandler : public IECommandHandler {
}

std::vector<BrowserCookie> cookies;
browser_wrapper->GetCookies(&cookies);
browser_wrapper->cookie_manager()->GetCookies(
browser_wrapper->GetCurrentUrl(),
&cookies);
std::vector<BrowserCookie>::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() + "'");
Expand Down
5 changes: 4 additions & 1 deletion cpp/iedriver/CommandHandlers/DeleteCookieCommandHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
13 changes: 12 additions & 1 deletion cpp/iedriver/CommandHandlers/GetAllCookiesCommandHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,18 @@ class GetAllCookiesCommandHandler : public IECommandHandler {
}

std::vector<BrowserCookie> 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<BrowserCookie>::iterator it = cookies.begin();
for (; it != cookies.end(); ++it) {
response_value.append(it->ToJson());
Expand Down
Loading

0 comments on commit 79ea708

Please sign in to comment.