Skip to content

Commit ba34ed3

Browse files
committed
Correcting IE driver logic for http-only and secure cookies.
Cookies now behave in IE as expected. The driver will properly return 'secure' or 'httpOnly' flags as set on the cookie itself. Note carefully that 'secure' cookies will only be retrieved when browsing a page using SSL (https), as this is the only environment where the cookies are used by the browser. This behavior is consistent with the behavior of the Chrome driver, and with the W3C specification behavior for cookies. Firefox, it should be noted, returns secure cookies regardless of whether the page in question is being browsed via SSL or not. This is a bug in the Firefox driver.
1 parent 07bf0ac commit ba34ed3

File tree

7 files changed

+109
-31
lines changed

7 files changed

+109
-31
lines changed

Diff for: cpp/iedriver/CookieManager.cpp

+92-29
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,16 @@ bool CookieManager::SetCookie(std::string url, std::string cookie_data) {
6464
return true;
6565
}
6666

67-
int CookieManager::GetCookies(std::string url, std::vector<BrowserCookie>* all_cookies) {
67+
int CookieManager::GetCookies(std::string url,
68+
std::vector<BrowserCookie>* all_cookies) {
6869
LOG(TRACE) << "Entering CookieManager::GetCookies";
70+
std::wstring wide_url = StringUtilities::ToWString(url);
71+
CComPtr<IUri> parsed_url;
72+
::CreateUri(wide_url.c_str(), Uri_CREATE_ALLOW_RELATIVE, 0, &parsed_url);
73+
DWORD url_scheme = 0;
74+
parsed_url->GetScheme(&url_scheme);
75+
bool is_secure_url = URL_SCHEME_HTTPS == url_scheme;
76+
6977
HookSettings hook_settings;
7078
hook_settings.hook_procedure_name = "CookieWndProc";
7179
hook_settings.hook_procedure_type = WH_CALLWNDPROC;
@@ -77,24 +85,34 @@ int CookieManager::GetCookies(std::string url, std::vector<BrowserCookie>* all_c
7785

7886
// Get all cookies for the current URL visible to JavaScript.
7987
std::wstring scriptable_cookie_string =
80-
this->SendGetCookieMessage(StringUtilities::ToWString(url),
81-
WD_GET_SCRIPTABLE_COOKIES,
82-
&hook);
88+
this->SendGetCookieMessage(wide_url,
89+
WD_GET_SCRIPTABLE_COOKIES,
90+
&hook);
8391
std::map<std::string, std::string> scriptable_cookies;
8492
this->ParseCookieString(scriptable_cookie_string, &scriptable_cookies);
8593

86-
// Get all cookies for the current URL, including HttpOnly cookies.
87-
std::wstring httponly_cookie_string =
88-
this->SendGetCookieMessage(StringUtilities::ToWString(url),
94+
// Get all cookies for the insecure version of the current URL,
95+
// which will include HttpOnly cookies.
96+
std::wstring insecure_cookie_string =
97+
this->SendGetCookieMessage(wide_url,
8998
WD_GET_HTTPONLY_COOKIES,
9099
&hook);
91-
std::map<std::string, std::string> httponly_cookies;
92-
this->ParseCookieString(httponly_cookie_string, &httponly_cookies);
100+
std::map<std::string, std::string> insecure_cookies;
101+
this->ParseCookieString(insecure_cookie_string, &insecure_cookies);
102+
103+
// Get all cookies for the current secure URL. This will include
104+
// HttpOnly cookies.
105+
std::wstring secure_cookie_string =
106+
this->SendGetCookieMessage(wide_url,
107+
WD_GET_SECURE_COOKIES,
108+
&hook);
109+
std::map<std::string, std::string> secure_cookies;
110+
this->ParseCookieString(secure_cookie_string, &secure_cookies);
93111

94112
// Get all of the persistent cookie files in the cache for the
95113
// URL currently being browsed.
96114
std::wstring file_list = this->SendGetCookieMessage(
97-
StringUtilities::ToWString(url),
115+
wide_url,
98116
WD_GET_COOKIE_CACHE_FILES,
99117
&hook);
100118
std::vector<std::wstring> files;
@@ -106,28 +124,35 @@ int CookieManager::GetCookies(std::string url, std::vector<BrowserCookie>* all_c
106124
for (std::vector<std::wstring>::const_iterator file_iterator = files.begin();
107125
file_iterator != files.end();
108126
++file_iterator) {
109-
this->ReadPersistentCookieFile(*file_iterator, &persistent_cookies);
127+
this->ReadPersistentCookieFile(*file_iterator,
128+
is_secure_url,
129+
&persistent_cookies);
110130
}
111131

112-
// Loop through the entire list of cookies, including HttpOnly cookies.
113-
// If the cookie exists as a persistent cookie, use its data from the
114-
// cache. If the cookie is found in the list of cookies visible to
115-
// JavaScript, set the HttpOnly property of the cookie to false.
116-
std::map<std::string, std::string>::const_iterator it = httponly_cookies.begin();
117-
for (; it != httponly_cookies.end(); ++it) {
132+
// Loop through the entire list of cookies, including HttpOnly and secure
133+
// cookies. If the cookie exists as a persistent cookie, use its data from
134+
// the cache. If the cookie is found in the list of cookies visible to
135+
// JavaScript, set the HttpOnly property of the cookie to false. If the
136+
// cookie is found in the list of cookies set on the insecure version of
137+
// the URL, set the Secure property of the cookie to false.
138+
std::map<std::string, std::string>::const_iterator it = secure_cookies.begin();
139+
for (; it != secure_cookies.end(); ++it) {
118140
BrowserCookie browser_cookie;
119141
if (persistent_cookies.find(it->first) != persistent_cookies.end()) {
120142
browser_cookie = persistent_cookies[it->first];
143+
} else {
144+
browser_cookie.set_name(it->first);
145+
browser_cookie.set_value(it->second);
146+
browser_cookie.set_is_httponly(scriptable_cookies.find(it->first) == scriptable_cookies.end());
147+
browser_cookie.set_is_secure(insecure_cookies.find(it->first) == insecure_cookies.end());
121148
}
122-
browser_cookie.set_name(it->first);
123-
browser_cookie.set_value(it->second);
124-
browser_cookie.set_is_httponly(scriptable_cookies.find(it->first) == scriptable_cookies.end());
125149
all_cookies->push_back(browser_cookie);
126150
}
127151
return 0;
128152
}
129153

130154
void CookieManager::ReadPersistentCookieFile(const std::wstring& file_name,
155+
const bool include_secure_cookies,
131156
std::map<std::string, BrowserCookie>* cookies) {
132157
LOG(TRACE) << "Entering CookieManager::ReadPersistentCookieFile";
133158
HANDLE file_handle = ::CreateFile(file_name.c_str(),
@@ -153,11 +178,22 @@ void CookieManager::ReadPersistentCookieFile(const std::wstring& file_name,
153178
// a line containing a single asterisk ('*'). Split the file
154179
// content on this delimiter, and parse each record.
155180
std::vector<std::string> persistent_cookie_strings;
156-
StringUtilities::Split(cookie_file_contents, "\n*\n", &persistent_cookie_strings);
181+
StringUtilities::Split(cookie_file_contents,
182+
"\n*\n",
183+
&persistent_cookie_strings);
157184
std::vector<std::string>::const_iterator cookie_string_iterator = persistent_cookie_strings.begin();
158-
for (; cookie_string_iterator != persistent_cookie_strings.end(); ++cookie_string_iterator) {
159-
BrowserCookie persistent_cookie = this->ParsePersistentCookieInfo(*cookie_string_iterator);
160-
cookies->insert(std::pair<std::string, BrowserCookie>(persistent_cookie.name(), persistent_cookie));
185+
for (;
186+
cookie_string_iterator != persistent_cookie_strings.end();
187+
++cookie_string_iterator) {
188+
BrowserCookie persistent_cookie =
189+
this->ParsePersistentCookieInfo(*cookie_string_iterator);
190+
if (include_secure_cookies || !persistent_cookie.is_secure()) {
191+
// Omit the cookie if it's 'secure' flag is set and we are *not*
192+
// browsing using SSL.
193+
cookies->insert(
194+
std::pair<std::string, BrowserCookie>(persistent_cookie.name(),
195+
persistent_cookie));
196+
}
161197
}
162198
}
163199

@@ -281,27 +317,54 @@ LRESULT CALLBACK CookieWndProc(int nCode, WPARAM wParam, LPARAM lParam) {
281317
COPYDATASTRUCT* data = reinterpret_cast<COPYDATASTRUCT*>(call_window_proc_struct->lParam);
282318
webdriver::HookProcessor::CopyDataToBuffer(data->cbData, data->lpData);
283319
} else if (WD_GET_HTTPONLY_COOKIES == call_window_proc_struct->message ||
284-
WD_GET_SCRIPTABLE_COOKIES == call_window_proc_struct->message) {
320+
WD_GET_SCRIPTABLE_COOKIES == call_window_proc_struct->message ||
321+
WD_GET_SECURE_COOKIES == call_window_proc_struct->message) {
285322
std::wstring url = webdriver::HookProcessor::CopyWStringFromBuffer();
286323
int driver_process_id = static_cast<int>(call_window_proc_struct->wParam);
287-
DWORD get_cookie_error = 0;
324+
288325
DWORD get_cookie_flags = 0;
289-
if (WD_GET_HTTPONLY_COOKIES == call_window_proc_struct->message) {
326+
if (WD_GET_HTTPONLY_COOKIES == call_window_proc_struct->message ||
327+
WD_GET_SECURE_COOKIES == call_window_proc_struct->message) {
290328
get_cookie_flags = INTERNET_COOKIE_HTTPONLY;
291329
}
292330

331+
CComPtr<IUri> uri_pointer;
332+
HRESULT hr = ::CreateUri(url.c_str(), Uri_CREATE_ALLOW_RELATIVE, 0, &uri_pointer);
333+
DWORD scheme = 0;
334+
uri_pointer->GetScheme(&scheme);
335+
CComBSTR scheme_bstr;
336+
uri_pointer->GetSchemeName(&scheme_bstr);
337+
CComBSTR host_bstr;
338+
uri_pointer->GetHost(&host_bstr);
339+
CComBSTR path_bstr;
340+
uri_pointer->GetPath(&path_bstr);
341+
342+
// Get only the cookies for the base URL, omitting port, if there is one.
343+
// N.B., we only return cookies secure cookies when browsing a site using
344+
// SSL. The browser won't see cookies with the 'secure' flag for sites
345+
// visited using plain http.
346+
std::wstring parsed_uri = L"http";
347+
if ((WD_GET_SECURE_COOKIES == call_window_proc_struct->message ||
348+
WD_GET_SCRIPTABLE_COOKIES == call_window_proc_struct->message) &&
349+
URL_SCHEME_HTTPS == scheme) {
350+
parsed_uri.append(L"s");
351+
}
352+
parsed_uri.append(L"://");
353+
parsed_uri.append(host_bstr);
354+
parsed_uri.append(path_bstr);
355+
293356
// Call InternetGetCookieEx once to get the size of the buffer needed,
294357
// then call again with the appropriately sized buffer allocated.
295358
DWORD buffer_size = 0;
296-
BOOL success = ::InternetGetCookieEx(url.c_str(),
359+
BOOL success = ::InternetGetCookieEx(parsed_uri.c_str(),
297360
NULL,
298361
NULL,
299362
&buffer_size,
300363
get_cookie_flags,
301364
NULL);
302365
if (success) {
303366
webdriver::HookProcessor::SetDataBufferSize(buffer_size);
304-
::InternetGetCookieEx(url.c_str(),
367+
::InternetGetCookieEx(parsed_uri.c_str(),
305368
NULL,
306369
reinterpret_cast<LPTSTR>(webdriver::HookProcessor::GetDataBufferAddress()),
307370
&buffer_size,

Diff for: cpp/iedriver/CookieManager.h

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class CookieManager {
4545
std::map<std::string, std::string>* cookies);
4646
BrowserCookie ParsePersistentCookieInfo(const std::string& cookie);
4747
void ReadPersistentCookieFile(const std::wstring& file_name,
48+
const bool include_secure_cookies,
4849
std::map<std::string, BrowserCookie>* cookies);
4950

5051
HWND window_handle_;

Diff for: cpp/iedriver/messages.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,6 @@
4040

4141
#define WD_GET_SCRIPTABLE_COOKIES WM_APP + 22
4242
#define WD_GET_HTTPONLY_COOKIES WM_APP + 23
43-
#define WD_GET_COOKIE_CACHE_FILES WM_APP + 24
44-
#define WD_SET_COOKIE WM_APP + 25
43+
#define WD_GET_SECURE_COOKIES WM_APP + 24
44+
#define WD_GET_COOKIE_CACHE_FILES WM_APP + 25
45+
#define WD_SET_COOKIE WM_APP + 26

Diff for: cpp/iedriverserver/CHANGELOG

+13
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,19 @@ available via the project downloads page. Changes in "revision" field indicate
99
private releases checked into the prebuilts directory of the source tree, but
1010
not made generally available on the downloads page.
1111

12+
v2.46.0.4
13+
=========
14+
* Corrected logic for http-only and secure cookies. Cookies now behave
15+
in IE as expected. The driver will properly return 'secure' or
16+
'httpOnly' flags as set on the cookie itself. Note carefully that
17+
'secure' cookies will only be retrieved when browsing a page using
18+
SSL (https), as this is the only environment where the cookies are
19+
used by the browser. This behavior is consistent with the behavior
20+
of the Chrome driver, and with the W3C specification behavior for
21+
cookies. Firefox, it should be noted, returns secure cookies regardless
22+
of whether the page in question is being browsed via SSL or not.
23+
This is a bug in the Firefox driver.
24+
1225
v2.46.0.3
1326
=========
1427
* Fixed IE cookie handling for down-level operating systems.

Diff for: cpp/iedriverserver/IEDriverServer.rc

0 Bytes
Binary file not shown.

Diff for: cpp/prebuilt/Win32/Release/IEDriverServer.exe

1.5 KB
Binary file not shown.

Diff for: cpp/prebuilt/x64/Release/IEDriverServer.exe

2 KB
Binary file not shown.

0 commit comments

Comments
 (0)