| // 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 "ProxyManager.h" |
| |
| #include <algorithm> |
| #include <vector> |
| |
| #include <wininet.h> |
| |
| #include "json.h" |
| #include "logging.h" |
| #include "messages.h" |
| |
| #include "HookProcessor.h" |
| #include "StringUtilities.h" |
| |
| #define WD_PROXY_TYPE_DIRECT "direct" |
| #define WD_PROXY_TYPE_SYSTEM "system" |
| #define WD_PROXY_TYPE_MANUAL "manual" |
| #define WD_PROXY_TYPE_AUTOCONFIGURE "pac" |
| #define WD_PROXY_TYPE_AUTODETECT "autodetect" |
| |
| #define HTTP_PROXY_MARKER "http=" |
| #define HTTPS_PROXY_MARKER "https=" |
| #define FTP_PROXY_MARKER "ftp=" |
| #define SOCKS_PROXY_MARKER "socks=" |
| #define BYPASS_PROXY_MARKER "|bypass=" |
| |
| namespace webdriver { |
| |
| ProxyManager::ProxyManager(void) { |
| this->proxy_type_ = ""; |
| this->http_proxy_ = ""; |
| this->ftp_proxy_ = ""; |
| this->ssl_proxy_ = ""; |
| this->socks_proxy_ = ""; |
| this->socks_user_name_ = ""; |
| this->socks_password_ = ""; |
| this->proxy_bypass_ = ""; |
| this->proxy_autoconfigure_url_ = ""; |
| this->is_proxy_modified_ = false; |
| this->is_proxy_authorization_modified_ = false; |
| this->use_per_process_proxy_ = false; |
| |
| this->current_autoconfig_url_ = L""; |
| this->current_proxy_auto_detect_flags_ = 0; |
| this->current_proxy_server_ = L""; |
| this->current_socks_user_name_ = L""; |
| this->current_socks_password_ = L""; |
| this->current_proxy_type_ = 0; |
| this->current_proxy_bypass_list_ = L""; |
| } |
| |
| ProxyManager::~ProxyManager(void) { |
| this->RestoreProxySettings(); |
| } |
| |
| void ProxyManager::Initialize(ProxySettings settings) { |
| LOG(TRACE) << "ProxyManager::Initialize"; |
| // The wire protocol specifies lower case for the proxy type, but |
| // language bindings have been sending upper case forever. Handle |
| // both cases, thus we will normalize to a lower-case string for |
| // proxy type. |
| this->proxy_type_ = settings.proxy_type; |
| std::transform(this->proxy_type_.begin(), |
| this->proxy_type_.end(), |
| this->proxy_type_.begin(), |
| ::tolower); |
| this->http_proxy_ = settings.http_proxy; |
| this->ftp_proxy_ = settings.ftp_proxy; |
| this->ssl_proxy_ = settings.ssl_proxy; |
| this->socks_proxy_ = settings.socks_proxy; |
| this->socks_user_name_ = settings.socks_user_name; |
| this->socks_password_ = settings.socks_password; |
| this->proxy_bypass_ = settings.proxy_bypass; |
| this->proxy_autoconfigure_url_ = settings.proxy_autoconfig_url; |
| if (this->proxy_type_ == WD_PROXY_TYPE_SYSTEM || |
| this->proxy_type_ == WD_PROXY_TYPE_DIRECT || |
| this->proxy_type_ == WD_PROXY_TYPE_MANUAL) { |
| this->use_per_process_proxy_ = settings.use_per_process_proxy; |
| } else { |
| // By definition, per-process proxy settings can only be used with the |
| // system proxy, direct connection, or with a manually specified proxy. |
| this->use_per_process_proxy_ = false; |
| } |
| } |
| |
| void ProxyManager::SetProxySettings(HWND browser_window_handle) { |
| LOG(TRACE) << "ProxyManager::SetProxySettings"; |
| if (this->proxy_type_.size() > 0 && this->proxy_type_ != WD_PROXY_TYPE_SYSTEM) { |
| if (this->use_per_process_proxy_) { |
| LOG(DEBUG) << "Setting proxy for individual IE instance."; |
| this->SetPerProcessProxySettings(browser_window_handle); |
| } else { |
| if (!this->is_proxy_modified_) { |
| LOG(DEBUG) << "Setting system proxy."; |
| this->GetCurrentProxySettings(); |
| this->SetGlobalProxySettings(); |
| } else { |
| LOG(DEBUG) << "Proxy settings already set by IE driver."; |
| } |
| } |
| this->is_proxy_modified_ = true; |
| } else { |
| LOG(DEBUG) << "Using existing system proxy settings."; |
| } |
| } |
| |
| Json::Value ProxyManager::GetProxyAsJson() { |
| LOG(TRACE) << "ProxyManager::GetProxyAsJson"; |
| Json::Value proxy_value; |
| proxy_value["proxyType"] = this->proxy_type_; |
| if (this->proxy_type_ == WD_PROXY_TYPE_MANUAL) { |
| if (this->http_proxy_.size() > 0) { |
| proxy_value["httpProxy"] = this->http_proxy_; |
| } |
| if (this->ftp_proxy_.size() > 0) { |
| proxy_value["ftpProxy"] = this->ftp_proxy_; |
| } |
| if (this->ssl_proxy_.size() > 0) { |
| proxy_value["sslProxy"] = this->ssl_proxy_; |
| } |
| if (this->socks_proxy_.size() > 0) { |
| proxy_value["socksProxy"] = this->socks_proxy_; |
| if (this->socks_user_name_.size() > 0) { |
| proxy_value["socksUsername"] = this->socks_user_name_; |
| } |
| if (this->socks_password_.size() > 0) { |
| proxy_value["socksPassword"] = this->socks_password_; |
| } |
| } |
| } else if (this->proxy_type_ == WD_PROXY_TYPE_AUTOCONFIGURE) { |
| proxy_value["proxyAutoconfigUrl"] = this->proxy_autoconfigure_url_; |
| } |
| return proxy_value; |
| } |
| |
| std::wstring ProxyManager::BuildProxySettingsString() { |
| LOG(TRACE) << "ProxyManager::BuildProxySettingsString"; |
| std::string proxy_string = ""; |
| if (this->proxy_type_ == WD_PROXY_TYPE_MANUAL) { |
| if (this->http_proxy_.size() > 0) { |
| proxy_string.append(HTTP_PROXY_MARKER).append(this->http_proxy_); |
| } |
| if (this->ftp_proxy_.size() > 0) { |
| if (proxy_string.size() > 0) { |
| proxy_string.append(" "); |
| } |
| proxy_string.append(FTP_PROXY_MARKER).append(this->ftp_proxy_); |
| } |
| if (this->ssl_proxy_.size() > 0) { |
| if (proxy_string.size() > 0) { |
| proxy_string.append(" "); |
| } |
| proxy_string.append(HTTPS_PROXY_MARKER).append(this->ssl_proxy_); |
| } |
| if (this->socks_proxy_.size() > 0) { |
| if (proxy_string.size() > 0) { |
| proxy_string.append(" "); |
| } |
| proxy_string.append(SOCKS_PROXY_MARKER).append(this->socks_proxy_); |
| } |
| if (this->proxy_bypass_.size() > 0) { |
| proxy_string.append(BYPASS_PROXY_MARKER).append(this->proxy_bypass_); |
| } |
| } else if (this->proxy_type_ == WD_PROXY_TYPE_AUTOCONFIGURE) { |
| proxy_string = this->proxy_autoconfigure_url_; |
| } else { |
| proxy_string = this->proxy_type_; |
| } |
| LOG(DEBUG) << "Built proxy settings string: '" << proxy_string << "'"; |
| return StringUtilities::ToWString(proxy_string); |
| } |
| |
| void ProxyManager::RestoreProxySettings() { |
| LOG(TRACE) << "ProxyManager::RestoreProxySettings"; |
| bool settings_restored = (!this->use_per_process_proxy_ && this->is_proxy_modified_) || this->is_proxy_authorization_modified_; |
| if (!this->use_per_process_proxy_ && this->is_proxy_modified_) { |
| INTERNET_PER_CONN_OPTION_LIST option_list; |
| std::vector<INTERNET_PER_CONN_OPTION> restore_options(5); |
| unsigned long list_size = sizeof(INTERNET_PER_CONN_OPTION_LIST); |
| |
| std::vector<wchar_t> autoconfig_url_buffer; |
| StringUtilities::ToBuffer(this->current_autoconfig_url_, &autoconfig_url_buffer); |
| restore_options[0].dwOption = INTERNET_PER_CONN_AUTOCONFIG_URL; |
| restore_options[0].Value.pszValue = &autoconfig_url_buffer[0]; |
| |
| restore_options[1].dwOption = INTERNET_PER_CONN_AUTODISCOVERY_FLAGS; |
| restore_options[1].Value.dwValue = this->current_proxy_auto_detect_flags_; |
| |
| restore_options[2].dwOption = INTERNET_PER_CONN_FLAGS; |
| restore_options[2].Value.dwValue = this->current_proxy_type_; |
| |
| std::vector<wchar_t> proxy_bypass_buffer; |
| StringUtilities::ToBuffer(this->current_proxy_bypass_list_, &proxy_bypass_buffer); |
| restore_options[3].dwOption = INTERNET_PER_CONN_PROXY_BYPASS; |
| restore_options[3].Value.pszValue = &proxy_bypass_buffer[0]; |
| |
| std::vector<wchar_t> proxy_server_buffer; |
| StringUtilities::ToBuffer(this->current_proxy_server_, &proxy_server_buffer); |
| restore_options[4].dwOption = INTERNET_PER_CONN_PROXY_SERVER; |
| restore_options[4].Value.pszValue = &proxy_server_buffer[0]; |
| |
| option_list.dwSize = sizeof(INTERNET_PER_CONN_OPTION_LIST); |
| option_list.pszConnection = NULL; |
| option_list.dwOptionCount = static_cast<int>(restore_options.size()); |
| option_list.dwOptionError = 0; |
| option_list.pOptions = &restore_options[0]; |
| |
| BOOL success = ::InternetSetOption(NULL, |
| INTERNET_OPTION_PER_CONNECTION_OPTION, |
| &option_list, |
| list_size); |
| if (!success) { |
| LOGERR(WARN) << "InternetSetOption failed setting INTERNET_OPTION_PER_CONNECTION_OPTION"; |
| } |
| this->is_proxy_modified_ = false; |
| } |
| if (this->is_proxy_authorization_modified_) { |
| this->SetProxyAuthentication(this->current_socks_user_name_, |
| this->current_socks_password_); |
| this->is_proxy_authorization_modified_ = false; |
| } |
| if (settings_restored) { |
| BOOL notify_success = ::InternetSetOption(NULL, |
| INTERNET_OPTION_PROXY_SETTINGS_CHANGED, |
| NULL, |
| 0); |
| if (!notify_success) { |
| LOGERR(WARN) << "InternetSetOption failed setting INTERNET_OPTION_PROXY_SETTINGS_CHANGED"; |
| } |
| } |
| } |
| |
| void ProxyManager::SetPerProcessProxySettings(HWND browser_window_handle) { |
| LOG(TRACE) << "ProxyManager::SetPerProcessProxySettings"; |
| std::wstring proxy = this->BuildProxySettingsString(); |
| |
| HookSettings hook_settings; |
| hook_settings.window_handle = browser_window_handle; |
| hook_settings.hook_procedure_name = "SetProxyWndProc"; |
| hook_settings.hook_procedure_type = WH_CALLWNDPROC; |
| hook_settings.communication_type = OneWay; |
| |
| HookProcessor hook; |
| if (!hook.CanSetWindowsHook(browser_window_handle)) { |
| LOG(WARN) << "Proxy will not be set! There is a mismatch in the " |
| << "bitness between the driver and browser. In particular, " |
| << "be sure you are not attempting to use a 64-bit " |
| << "IEDriverServer.exe against IE 10 or 11, even on 64-bit " |
| << "Windows."; |
| } |
| hook.Initialize(hook_settings); |
| hook.PushData(proxy); |
| LRESULT result = ::SendMessage(browser_window_handle, |
| WD_CHANGE_PROXY, |
| NULL, |
| NULL); |
| |
| if (this->socks_proxy_.size() > 0 && |
| (this->socks_user_name_.size() > 0 || this->socks_password_.size() > 0)) { |
| LOG(WARN) << "Windows APIs provide no way to set proxy user name and " |
| << "password on a per-process basis. Setting global setting."; |
| |
| this->SetProxyAuthentication(StringUtilities::ToWString(this->socks_user_name_), |
| StringUtilities::ToWString(this->socks_password_)); |
| this->is_proxy_authorization_modified_ = true; |
| |
| // Notify WinINet clients that the proxy options have changed. |
| BOOL success = ::InternetSetOption(NULL, |
| INTERNET_OPTION_PROXY_SETTINGS_CHANGED, |
| NULL, |
| 0); |
| if (!success) { |
| LOGERR(WARN) << "InternetSetOption failed setting INTERNET_OPTION_PROXY_SETTINGS_CHANGED"; |
| } |
| } |
| } |
| |
| void ProxyManager::SetGlobalProxySettings() { |
| LOG(TRACE) << "ProxyManager::SetGlobalProxySettings"; |
| std::wstring proxy_settings_string = this->BuildProxySettingsString(); |
| |
| std::vector<std::wstring> proxy_settings; |
| StringUtilities::Split(proxy_settings_string, |
| _TEXT(BYPASS_PROXY_MARKER), |
| &proxy_settings); |
| |
| std::wstring proxy = proxy_settings[0]; |
| std::wstring proxy_bypass = L""; |
| if (proxy_settings.size() > 1) { |
| proxy_bypass = proxy_settings[1]; |
| } |
| |
| INTERNET_PER_CONN_OPTION_LIST option_list; |
| unsigned long list_size = sizeof(INTERNET_PER_CONN_OPTION_LIST); |
| option_list.dwSize = sizeof(INTERNET_PER_CONN_OPTION_LIST); |
| |
| INTERNET_PER_CONN_OPTION proxy_options[3]; |
| if (this->proxy_type_ == WD_PROXY_TYPE_DIRECT) { |
| proxy_options[0].dwOption = INTERNET_PER_CONN_FLAGS; |
| proxy_options[0].Value.dwValue = PROXY_TYPE_DIRECT; |
| option_list.dwOptionCount = 1; |
| } else if (this->proxy_type_ == WD_PROXY_TYPE_AUTOCONFIGURE) { |
| proxy_options[0].dwOption = INTERNET_PER_CONN_AUTOCONFIG_URL; |
| proxy_options[0].Value.pszValue = const_cast<wchar_t*>(proxy.c_str()); |
| proxy_options[1].dwOption = INTERNET_PER_CONN_FLAGS; |
| proxy_options[1].Value.dwValue = PROXY_TYPE_AUTO_PROXY_URL; |
| option_list.dwOptionCount = 2; |
| } else if (this->proxy_type_ == WD_PROXY_TYPE_AUTODETECT) { |
| proxy_options[0].dwOption = INTERNET_PER_CONN_AUTODISCOVERY_FLAGS; |
| proxy_options[0].Value.dwValue = AUTO_PROXY_FLAG_ALWAYS_DETECT; |
| proxy_options[1].dwOption = INTERNET_PER_CONN_FLAGS; |
| proxy_options[1].Value.dwValue = PROXY_TYPE_AUTO_DETECT; |
| option_list.dwOptionCount = 2; |
| } else { |
| proxy_options[0].dwOption = INTERNET_PER_CONN_PROXY_SERVER; |
| proxy_options[0].Value.pszValue = const_cast<wchar_t*>(proxy.c_str()); |
| proxy_options[1].dwOption = INTERNET_PER_CONN_FLAGS; |
| proxy_options[1].Value.dwValue = PROXY_TYPE_PROXY | PROXY_TYPE_DIRECT; |
| proxy_options[2].dwOption = INTERNET_PER_CONN_PROXY_BYPASS; |
| proxy_options[2].Value.pszValue = const_cast<wchar_t*>(proxy_bypass.c_str());; |
| option_list.dwOptionCount = 3; |
| } |
| |
| option_list.pOptions = proxy_options; |
| option_list.pszConnection = NULL; |
| option_list.dwOptionError = 0; |
| BOOL success = ::InternetSetOption(NULL, |
| INTERNET_OPTION_PER_CONNECTION_OPTION, |
| &option_list, |
| list_size); |
| if (!success) { |
| LOGERR(WARN) << "InternetSetOption failed setting INTERNET_OPTION_PER_CONNECTION_OPTION"; |
| } |
| |
| // Only set proxy authentication for SOCKS proxies, and |
| // where the user name and password have been specified. |
| if (this->socks_proxy_.size() > 0 && |
| (this->socks_user_name_.size() > 0 || this->socks_password_.size() > 0)) { |
| this->SetProxyAuthentication(StringUtilities::ToWString(this->socks_user_name_), |
| StringUtilities::ToWString(this->socks_password_)); |
| this->is_proxy_authorization_modified_ = true; |
| } |
| |
| success = ::InternetSetOption(NULL, |
| INTERNET_OPTION_PROXY_SETTINGS_CHANGED, |
| NULL, |
| 0); |
| if (!success) { |
| LOGERR(WARN) << "InternetSetOption failed setting INTERNET_OPTION_PROXY_SETTINGS_CHANGED"; |
| } |
| } |
| |
| void ProxyManager::SetProxyAuthentication(const std::wstring& user_name, |
| const std::wstring& password) { |
| LOG(TRACE) << "ProxyManager::SetProxyAuthentication"; |
| BOOL success = ::InternetSetOption(NULL, |
| INTERNET_OPTION_PROXY_USERNAME, |
| const_cast<wchar_t*>(user_name.c_str()), |
| static_cast<int>(user_name.size()) + 1); |
| if (!success) { |
| LOGERR(WARN) << "InternetSetOption failed setting INTERNET_OPTION_PROXY_USERNAME"; |
| } |
| |
| success = ::InternetSetOption(NULL, |
| INTERNET_OPTION_PROXY_PASSWORD, |
| const_cast<wchar_t*>(password.c_str()), |
| static_cast<int>(password.size()) + 1); |
| if (!success) { |
| LOGERR(WARN) << "InternetSetOption failed setting INTERNET_OPTION_PROXY_PASSWORD"; |
| } |
| } |
| |
| void ProxyManager::GetCurrentProxySettings() { |
| LOG(TRACE) << "ProxyManager::GetCurrentProxySettings"; |
| this->GetCurrentProxyType(); |
| INTERNET_PER_CONN_OPTION_LIST option_list; |
| std::vector<INTERNET_PER_CONN_OPTION> options_to_get(4); |
| unsigned long list_size = sizeof(INTERNET_PER_CONN_OPTION_LIST); |
| |
| options_to_get[0].dwOption = INTERNET_PER_CONN_AUTOCONFIG_URL; |
| options_to_get[1].dwOption = INTERNET_PER_CONN_AUTODISCOVERY_FLAGS; |
| options_to_get[2].dwOption = INTERNET_PER_CONN_PROXY_BYPASS; |
| options_to_get[3].dwOption = INTERNET_PER_CONN_PROXY_SERVER; |
| |
| option_list.dwSize = sizeof(INTERNET_PER_CONN_OPTION_LIST); |
| option_list.pszConnection = NULL; |
| option_list.dwOptionCount = static_cast<int>(options_to_get.size()); |
| option_list.dwOptionError = 0; |
| option_list.pOptions = &options_to_get[0]; |
| |
| BOOL success = ::InternetQueryOption(NULL, |
| INTERNET_OPTION_PER_CONNECTION_OPTION, |
| &option_list, |
| &list_size); |
| if (!success) { |
| LOGERR(WARN) << "InternetQueryOption failed getting proxy settings"; |
| } |
| |
| if(options_to_get[0].Value.pszValue != NULL) { |
| this->current_autoconfig_url_ = options_to_get[0].Value.pszValue; |
| ::GlobalFree(options_to_get[0].Value.pszValue); |
| } |
| |
| this->current_proxy_auto_detect_flags_ = options_to_get[1].Value.dwValue; |
| |
| if(options_to_get[2].Value.pszValue != NULL) { |
| this->current_proxy_bypass_list_ = options_to_get[2].Value.pszValue; |
| ::GlobalFree(options_to_get[2].Value.pszValue); |
| } |
| |
| if(options_to_get[3].Value.pszValue != NULL) { |
| this->current_proxy_server_ = options_to_get[3].Value.pszValue; |
| ::GlobalFree(options_to_get[3].Value.pszValue); |
| } |
| |
| this->GetCurrentProxyAuthentication(); |
| } |
| |
| void ProxyManager::GetCurrentProxyAuthentication() { |
| LOG(TRACE) << "ProxyManager::GetCurrentProxyAuthentication"; |
| |
| DWORD user_name_length = 0; |
| BOOL success = ::InternetQueryOption(NULL, |
| INTERNET_OPTION_PROXY_USERNAME, |
| NULL, |
| &user_name_length); |
| if (user_name_length > 0) { |
| std::vector<wchar_t> user_name(user_name_length); |
| success = ::InternetQueryOption(NULL, |
| INTERNET_OPTION_PROXY_USERNAME, |
| &user_name[0], |
| &user_name_length); |
| this->current_socks_user_name_ = &user_name[0]; |
| } |
| |
| DWORD password_length = 0; |
| success = ::InternetQueryOption(NULL, |
| INTERNET_OPTION_PROXY_PASSWORD, |
| NULL, |
| &password_length); |
| if (password_length > 0) { |
| std::vector<wchar_t> password(password_length); |
| success = ::InternetQueryOption(NULL, |
| INTERNET_OPTION_PROXY_PASSWORD, |
| &password[0], |
| &password_length); |
| this->current_socks_password_ = &password[0]; |
| } |
| } |
| |
| void ProxyManager::GetCurrentProxyType() { |
| LOG(TRACE) << "ProxyManager::GetCurrentProxyType"; |
| INTERNET_PER_CONN_OPTION_LIST option_list; |
| std::vector<INTERNET_PER_CONN_OPTION> proxy_type_options(1); |
| unsigned long list_size = sizeof(INTERNET_PER_CONN_OPTION_LIST); |
| |
| proxy_type_options[0].dwOption = INTERNET_PER_CONN_FLAGS_UI; |
| |
| option_list.dwSize = sizeof(INTERNET_PER_CONN_OPTION_LIST); |
| option_list.pszConnection = NULL; |
| option_list.dwOptionCount = static_cast<int>(proxy_type_options.size()); |
| option_list.dwOptionError = 0; |
| option_list.pOptions = &proxy_type_options[0]; |
| |
| // First check for INTERNET_PER_CONN_FLAGS_UI, then if that fails |
| // check again using INTERNET_PER_CONN_FLAGS. This is documented at |
| // http://msdn.microsoft.com/en-us/library/windows/desktop/aa385145%28v=vs.85%29.aspx |
| BOOL success = ::InternetQueryOption(NULL, |
| INTERNET_OPTION_PER_CONNECTION_OPTION, |
| &option_list, |
| &list_size); |
| if (success) { |
| this->current_proxy_type_ = proxy_type_options[0].Value.dwValue; |
| return; |
| } |
| |
| proxy_type_options[0].dwOption = INTERNET_PER_CONN_FLAGS; |
| success = ::InternetQueryOption(NULL, |
| INTERNET_OPTION_PER_CONNECTION_OPTION, |
| &option_list, |
| &list_size); |
| if (success) { |
| this->current_proxy_type_ = proxy_type_options[0].Value.dwValue; |
| } |
| } |
| |
| } // namespace webdriver |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| LRESULT CALLBACK SetProxyWndProc(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); |
| } else if (WD_CHANGE_PROXY == call_window_proc_struct->message) { |
| // Allocate a buffer of the length of the data in the shared memory buffer, |
| // plus one extra wide char, to account for the null terminator. |
| int multibyte_buffer_size = webdriver::HookProcessor::GetDataBufferSize() + sizeof(wchar_t); |
| std::vector<char> multibyte_buffer(multibyte_buffer_size); |
| std::vector<char> multibyte_buffer_bypass(multibyte_buffer_size); |
| std::wstring proxy_settings = webdriver::HookProcessor::CopyWStringFromBuffer(); |
| std::wstring proxy = proxy_settings; |
| std::wstring proxy_bypass = L""; |
| |
| // Use the _TEXT macro to convert to a wstring literal |
| std::wstring bypass_marker = _TEXT(BYPASS_PROXY_MARKER); |
| size_t bypass_marker_index = proxy_settings.find(bypass_marker); |
| if (bypass_marker_index != std::wstring::npos) { |
| proxy = proxy_settings.substr(0, bypass_marker_index); |
| proxy_bypass = proxy_settings.substr(bypass_marker_index + bypass_marker.size()); |
| } |
| |
| INTERNET_PROXY_INFO proxy_info; |
| if (proxy == L"direct") { |
| proxy_info.dwAccessType = INTERNET_OPEN_TYPE_DIRECT; |
| proxy_info.lpszProxy = L""; |
| } else { |
| // UrlMkSetSessionOption only appears to work on either ASCII or |
| // multi-byte strings, not Unicode strings. Since the INTERNET_PROXY_INFO |
| // struct hard-codes to LPCTSTR, and that translates into LPCWSTR for the |
| // compiler settings we use, we must use the multi-byte version here. |
| // Note that for the count of input characters, we can use -1, since |
| // we've forced the string to be null-terminated. |
| ::WideCharToMultiByte(CP_UTF8, |
| 0, |
| proxy.c_str(), |
| -1, |
| &multibyte_buffer[0], |
| static_cast<int>(multibyte_buffer.size()), |
| NULL, |
| NULL); |
| proxy_info.dwAccessType = INTERNET_OPEN_TYPE_PROXY; |
| proxy_info.lpszProxy = reinterpret_cast<LPCTSTR>(&multibyte_buffer[0]); |
| } |
| |
| ::WideCharToMultiByte(CP_UTF8, |
| 0, |
| proxy_bypass.c_str(), |
| -1, |
| &multibyte_buffer_bypass[0], |
| static_cast<int>(multibyte_buffer_bypass.size()), |
| NULL, |
| NULL); |
| proxy_info.lpszProxyBypass = reinterpret_cast<LPCTSTR>(&multibyte_buffer_bypass[0]); |
| DWORD proxy_info_size = sizeof(proxy_info); |
| HRESULT hr = ::UrlMkSetSessionOption(INTERNET_OPTION_PROXY, |
| reinterpret_cast<void*>(&proxy_info), |
| proxy_info_size, |
| 0); |
| } |
| |
| return ::CallNextHookEx(NULL, nCode, wParam, lParam); |
| } |
| |
| #ifdef __cplusplus |
| } |
| #endif |