Skip to content

Commit 79ea708

Browse files
committed
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.
1 parent e7c2fa9 commit 79ea708

13 files changed

+229
-305
lines changed

Diff for: cpp/iedriver/BrowserCookie.cpp

+69-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
// limitations under the License.
1616

1717
#include "BrowserCookie.h"
18+
#include <ctime>
1819
#include "json.h"
1920

2021
namespace webdriver {
@@ -24,14 +25,69 @@ BrowserCookie::BrowserCookie(void) {
2425
this->value_ = "";
2526
this->domain_ = "";
2627
this->path_ = "";
27-
this->expiration_time_ = 0L;
28+
this->expiration_time_ = 0.0;
2829
this->is_secure_ = false;
2930
this->is_httponly_ = false;
3031
}
3132

3233
BrowserCookie::~BrowserCookie(void) {
3334
}
3435

36+
BrowserCookie BrowserCookie::FromJson(const Json::Value& json_cookie) {
37+
BrowserCookie cookie;
38+
cookie.name_ = json_cookie["name"].asString();
39+
cookie.value_ = json_cookie["value"].asString();
40+
cookie.is_secure_ = json_cookie["secure"].asBool();
41+
42+
Json::Value expiry = json_cookie.get("expiry", Json::Value::null);
43+
if (!expiry.isNull()) {
44+
if (expiry.isNumeric()) {
45+
cookie.expiration_time_ = expiry.asDouble();
46+
}
47+
}
48+
49+
Json::Value domain = json_cookie.get("domain", Json::Value::null);
50+
if (!domain.isNull() && domain.isString() && domain.asString() != "") {
51+
cookie.domain_ = domain.asString();
52+
}
53+
54+
Json::Value path = json_cookie.get("path", Json::Value::null);
55+
if (!path.isNull() && path.isString() && path.asString() != "") {
56+
cookie.path_ = path.asString();
57+
}
58+
return cookie;
59+
}
60+
61+
std::string BrowserCookie::ToString() const {
62+
std::string cookie_string(this->name_ +
63+
"=" +
64+
this->value_ +
65+
"; ");
66+
67+
if (this->is_secure_) {
68+
cookie_string += "secure; ";
69+
}
70+
71+
if (this->expiration_time_ > 0) {
72+
time_t expiration_time = static_cast<time_t>(this->expiration_time_);
73+
std::vector<char> raw_formatted_time(30);
74+
tm time_info;
75+
gmtime_s(&time_info, &expiration_time);
76+
std::string format_string = "%a, %d %b %Y %H:%M:%S GMT";
77+
strftime(&raw_formatted_time[0], 30, format_string.c_str(), &time_info);
78+
std::string formatted_time(&raw_formatted_time[0]);
79+
cookie_string += "expires=" + formatted_time + "; ";
80+
}
81+
82+
if (this->domain_.size() > 0) {
83+
cookie_string += "domain=" + this->domain_ + "; ";
84+
}
85+
if (this->path_.size() > 0) {
86+
cookie_string += "path=" + this->path_ + "; ";
87+
}
88+
return cookie_string;
89+
}
90+
3591
Json::Value BrowserCookie::ToJson() {
3692
Json::Value cookie;
3793
cookie["name"] = this->name_;
@@ -50,4 +106,16 @@ Json::Value BrowserCookie::ToJson() {
50106
return cookie;
51107
}
52108

109+
BrowserCookie BrowserCookie::Copy(void) const {
110+
BrowserCookie destination_cookie;
111+
destination_cookie.set_name(this->name_);
112+
destination_cookie.set_value(this->value_);
113+
destination_cookie.set_domain(this->domain_);
114+
destination_cookie.set_path(this->path_);
115+
destination_cookie.set_is_secure(this->is_secure_);
116+
destination_cookie.set_is_httponly(this->is_httponly_);
117+
destination_cookie.set_expiration_time(this->expiration_time_);
118+
return destination_cookie;
119+
}
120+
53121
}

Diff for: cpp/iedriver/BrowserCookie.h

+7-3
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,11 @@ class BrowserCookie
2929
BrowserCookie(void);
3030
virtual ~BrowserCookie(void);
3131

32+
static BrowserCookie FromJson(const Json::Value& json_cookie);
33+
3234
Json::Value ToJson(void);
35+
std::string ToString(void) const;
36+
BrowserCookie Copy(void) const;
3337

3438
std::string name(void) const { return this->name_; }
3539
void set_name(const std::string& name) { this->name_ = name; }
@@ -51,8 +55,8 @@ class BrowserCookie
5155
this->is_httponly_ = is_httponly;
5256
}
5357

54-
long expiration_time(void) const { return this->expiration_time_; }
55-
void set_expiration_time(const long expiration_time) {
58+
double expiration_time(void) const { return this->expiration_time_; }
59+
void set_expiration_time(const double expiration_time) {
5660
this->expiration_time_ = expiration_time;
5761
}
5862

@@ -61,7 +65,7 @@ class BrowserCookie
6165
std::string value_;
6266
std::string domain_;
6367
std::string path_;
64-
long expiration_time_;
68+
double expiration_time_;
6569
bool is_secure_;
6670
bool is_httponly_;
6771
};

Diff for: cpp/iedriver/CommandHandlers/AddCookieCommandHandler.h

+17-113
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#define WEBDRIVER_IE_ADDCOOKIECOMMANDHANDLER_H_
1919

2020
#include "../Browser.h"
21+
#include "../BrowserCookie.h"
22+
#include "../CookieManager.h"
2123
#include "../IECommandHandler.h"
2224
#include "../IECommandExecutor.h"
2325
#include <ctime>
@@ -43,56 +45,7 @@ class AddCookieCommandHandler : public IECommandHandler {
4345
}
4446

4547
Json::Value cookie_value = cookie_parameter_iterator->second;
46-
std::string cookie_string(cookie_value["name"].asString() +
47-
"=" +
48-
cookie_value["value"].asString() +
49-
"; ");
50-
cookie_value.removeMember("name");
51-
cookie_value.removeMember("value");
52-
53-
bool is_secure = cookie_value["secure"].asBool();
54-
if (is_secure) {
55-
cookie_string += "secure; ";
56-
}
57-
cookie_value.removeMember("secure");
58-
59-
Json::Value expiry = cookie_value.get("expiry", Json::Value::null);
60-
if (!expiry.isNull()) {
61-
cookie_value.removeMember("expiry");
62-
if (expiry.isNumeric()) {
63-
time_t expiration_time = static_cast<time_t>(expiry.asDouble());
64-
LOG(INFO) << "Received expiration time: " << expiration_time;
65-
std::vector<char> raw_formatted_time(30);
66-
tm time_info;
67-
gmtime_s(&time_info, &expiration_time);
68-
std::string month = this->GetMonthName(time_info.tm_mon);
69-
std::string weekday = this->GetWeekdayName(time_info.tm_wday);
70-
std::string format_string = weekday + ", %d " + month + " %Y %H:%M:%S GMT";
71-
strftime(&raw_formatted_time[0], 30 , format_string.c_str(), &time_info);
72-
std::string formatted_time(&raw_formatted_time[0]);
73-
LOG(INFO) << "Formated expiration time: " << formatted_time;
74-
cookie_string += "expires=" + formatted_time + "; ";
75-
}
76-
77-
// If a test sends both "expiry" and "expires", remove "expires"
78-
// from the cookie so that it doesn't get added when the string
79-
// properties of the JSON object are processed.
80-
Json::Value expires_value = cookie_value.get("expires",
81-
Json::Value::null);
82-
if (!expires_value.isNull()) {
83-
cookie_value.removeMember("expires");
84-
}
85-
}
86-
87-
Json::Value domain = cookie_value.get("domain", Json::Value::null);
88-
if (!domain.isNull() && domain.isString() && domain.asString() != "") {
89-
cookie_string += "domain=" + domain.asString() + "; ";
90-
}
91-
92-
Json::Value path = cookie_value.get("path", Json::Value::null);
93-
if (!path.isNull() && path.isString() && path.asString() != "") {
94-
cookie_string += "path=" + path.asString() + "; ";
95-
}
48+
BrowserCookie cookie = BrowserCookie::FromJson(cookie_value);
9649

9750
BrowserHandle browser_wrapper;
9851
int status_code = executor.GetCurrentBrowser(&browser_wrapper);
@@ -101,76 +54,27 @@ class AddCookieCommandHandler : public IECommandHandler {
10154
return;
10255
}
10356

104-
status_code = browser_wrapper->AddCookie(
105-
cookie_string,
106-
executor.validate_cookie_document_type());
107-
108-
if (status_code != WD_SUCCESS) {
57+
status_code = browser_wrapper->cookie_manager()->SetCookie(
58+
browser_wrapper->GetCurrentUrl(),
59+
cookie);
60+
61+
if (status_code == EUNHANDLEDERROR) {
62+
std::string error = "Could not set cookie. The most common cause ";
63+
error.append("of this error is a mismatch in the bitness between the ");
64+
error.append("driver and browser. In particular, be sure you are not ");
65+
error.append("attempting to use a 64-bit IEDriverServer.exe against ");
66+
error.append("IE 10 or 11, even on 64-bit Windows.");
67+
response->SetErrorResponse(status_code, error);
68+
return;
69+
}
70+
else if (status_code != WD_SUCCESS) {
10971
response->SetErrorResponse(status_code, "Unable to add cookie to page");
11072
return;
11173
}
11274

11375
response->SetSuccessResponse(Json::Value::null);
11476
}
11577

116-
private:
117-
std::string GetMonthName(int month_name) {
118-
// NOTE: can cookie dates used with put_cookie be localized?
119-
// If so, this function is not needed and a simple call to
120-
// strftime() will suffice.
121-
switch (month_name) {
122-
case 0:
123-
return "Jan";
124-
case 1:
125-
return "Feb";
126-
case 2:
127-
return "Mar";
128-
case 3:
129-
return "Apr";
130-
case 4:
131-
return "May";
132-
case 5:
133-
return "Jun";
134-
case 6:
135-
return "Jul";
136-
case 7:
137-
return "Aug";
138-
case 8:
139-
return "Sep";
140-
case 9:
141-
return "Oct";
142-
case 10:
143-
return "Nov";
144-
case 11:
145-
return "Dec";
146-
}
147-
148-
return "";
149-
}
150-
151-
std::string GetWeekdayName(int weekday_name) {
152-
// NOTE: can cookie dates used with put_cookie be localized?
153-
// If so, this function is not needed and a simple call to
154-
// strftime() will suffice.
155-
switch (weekday_name) {
156-
case 0:
157-
return "Sun";
158-
case 1:
159-
return "Mon";
160-
case 2:
161-
return "Tue";
162-
case 3:
163-
return "Wed";
164-
case 4:
165-
return "Thu";
166-
case 5:
167-
return "Fri";
168-
case 6:
169-
return "Sat";
170-
}
171-
172-
return "";
173-
}
17478
};
17579

17680
} // namespace webdriver

Diff for: cpp/iedriver/CommandHandlers/DeleteAllCookiesCommandHandler.h

+6-2
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,14 @@ class DeleteAllCookiesCommandHandler : public IECommandHandler {
4444
}
4545

4646
std::vector<BrowserCookie> cookies;
47-
browser_wrapper->GetCookies(&cookies);
47+
browser_wrapper->cookie_manager()->GetCookies(
48+
browser_wrapper->GetCurrentUrl(),
49+
&cookies);
4850
std::vector<BrowserCookie>::const_iterator it = cookies.begin();
4951
for (; it != cookies.end(); ++it) {
50-
status_code = browser_wrapper->DeleteCookie(*it);
52+
browser_wrapper->cookie_manager()->DeleteCookie(
53+
browser_wrapper->GetCurrentUrl(),
54+
*it);
5155
if (status_code != WD_SUCCESS) {
5256
response->SetErrorResponse(status_code,
5357
"Unable to delete cookie with name '" + it->name() + "'");

Diff for: cpp/iedriver/CommandHandlers/DeleteCookieCommandHandler.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,12 @@ class DeleteCookieCommandHandler : public IECommandHandler {
4848
response->SetErrorResponse(status_code, "Unable to get browser");
4949
return;
5050
}
51+
5152
BrowserCookie cookie;
5253
cookie.set_name(cookie_name);
53-
status_code = browser_wrapper->DeleteCookie(cookie);
54+
browser_wrapper->cookie_manager()->DeleteCookie(
55+
browser_wrapper->GetCurrentUrl(),
56+
cookie);
5457
if (status_code != WD_SUCCESS) {
5558
response->SetErrorResponse(status_code, "Unable to delete cookie");
5659
return;

Diff for: cpp/iedriver/CommandHandlers/GetAllCookiesCommandHandler.h

+12-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,18 @@ class GetAllCookiesCommandHandler : public IECommandHandler {
4545
}
4646

4747
std::vector<BrowserCookie> cookies;
48-
browser_wrapper->GetCookies(&cookies);
48+
status_code = browser_wrapper->cookie_manager()->GetCookies(
49+
browser_wrapper->GetCurrentUrl(),
50+
&cookies);
51+
if (status_code == EUNHANDLEDERROR) {
52+
std::string error = "Could not retrieve cookies. The most common cause ";
53+
error.append("of this error is a mismatch in the bitness between the ");
54+
error.append("driver and browser. In particular, be sure you are not ");
55+
error.append("attempting to use a 64-bit IEDriverServer.exe against ");
56+
error.append("IE 10 or 11, even on 64-bit Windows.");
57+
response->SetErrorResponse(status_code, error);
58+
return;
59+
}
4960
std::vector<BrowserCookie>::iterator it = cookies.begin();
5061
for (; it != cookies.end(); ++it) {
5162
response_value.append(it->ToJson());

0 commit comments

Comments
 (0)