Skip to content

Commit

Permalink
Adding support for SOCKS proxy in the IE driver
Browse files Browse the repository at this point in the history
Using a SOCKS proxy is not quite as straightforward for IE as it is for
other browser drivers. While the driver is now able to set the proxy
settings for a SOCKS proxy, using the ie.usePerProcessProxy capability
with a user name and password for a SOCKS proxy is problematic for the
driver. The Windows API does not provide any ability to set the user name
and password for a SOCKS proxy on a per-process basis. The driver attempts
to work around this limitation, but this combination will be largely
unsupported. Using the driver to temporarily set the global proxy settings
on the machine should work as normal.
  • Loading branch information
jimevans committed Jul 6, 2015
1 parent 92e0438 commit 931f51a
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 8 deletions.
12 changes: 11 additions & 1 deletion cpp/iedriver/CommandHandlers/NewSessionCommandHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class NewSessionCommandHandler : public IECommandHandler {
} else {
mutable_executor.set_enable_persistent_hover(enable_persistent_hover.asBool());
}
ProxySettings proxy_settings = { false, "", "", "", "" };
ProxySettings proxy_settings = { false, "", "", "", "", "", "", "", "" };
Json::Value proxy = it->second.get(PROXY_CAPABILITY, Json::nullValue);
if (!proxy.isNull()) {
// TODO(JimEvans): Validate the members of the proxy JSON object.
Expand All @@ -95,6 +95,16 @@ class NewSessionCommandHandler : public IECommandHandler {
proxy_settings.ftp_proxy = ftp_proxy;
std::string ssl_proxy = proxy.get("sslProxy", "").asString();
proxy_settings.ssl_proxy = ssl_proxy;
std::string socks_proxy = proxy.get("socksProxy", "").asString();
proxy_settings.socks_proxy = socks_proxy;
if (socks_proxy.length() > 0) {
// SOCKS proxy user name and password capabilities are ignored if the
// SOCKS proxy is unset.
std::string socks_user_name = proxy.get("socksUsername", "").asString();
proxy_settings.socks_user_name = socks_user_name;
std::string socks_password = proxy.get("socksPassword", "").asString();
proxy_settings.socks_password = socks_password;
}
std::string autoconfig_url = proxy.get("proxyAutoconfigUrl", "").asString();
proxy_settings.proxy_autoconfig_url = autoconfig_url;
Json::Value use_per_process_proxy = this->GetCapability(it->second, USE_PER_PROCESS_PROXY_CAPABILITY, Json::booleanValue, false);
Expand Down
105 changes: 99 additions & 6 deletions cpp/iedriver/ProxyManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,12 @@ void ProxyManager::Initialize(ProxySettings settings) {
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_autoconfigure_url_ = settings.proxy_autoconfig_url;
this->is_proxy_modified_ = false;
this->is_proxy_authorization_modified_ = false;
if (this->proxy_type_ == WD_PROXY_TYPE_SYSTEM ||
this->proxy_type_ == WD_PROXY_TYPE_DIRECT ||
this->proxy_type_ == WD_PROXY_TYPE_MANUAL) {
Expand All @@ -67,6 +71,8 @@ void ProxyManager::Initialize(ProxySettings settings) {
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"";
}
Expand Down Expand Up @@ -106,6 +112,15 @@ Json::Value ProxyManager::GetProxyAsJson() {
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_;
}
Expand All @@ -131,6 +146,12 @@ std::wstring ProxyManager::BuildProxySettingsString() {
}
proxy_string.append("https=").append(this->ssl_proxy_);
}
if (this->socks_proxy_.size() > 0) {
if (proxy_string.size() > 0) {
proxy_string.append(" ");
}
proxy_string.append("socks=").append(this->socks_proxy_);
}
} else if (this->proxy_type_ == WD_PROXY_TYPE_AUTOCONFIGURE) {
proxy_string = this->proxy_autoconfigure_url_;
} else {
Expand All @@ -142,6 +163,7 @@ std::wstring ProxyManager::BuildProxySettingsString() {

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);
Expand Down Expand Up @@ -181,12 +203,18 @@ void ProxyManager::RestoreProxySettings() {
if (!success) {
LOGERR(WARN) << "InternetSetOption failed setting INTERNET_OPTION_PER_CONNECTION_OPTION";
}
success = ::InternetSetOption(NULL,
INTERNET_OPTION_PROXY_SETTINGS_CHANGED,
NULL,
0);
this->is_proxy_modified_ = false;
if (!success) {
}
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";
}
}
Expand All @@ -209,7 +237,25 @@ void ProxyManager::SetPerProcessProxySettings(HWND browser_window_handle) {
WD_CHANGE_PROXY,
NULL,
NULL);
LOG(INFO) << "SendMessage result? " << result;

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() {
Expand Down Expand Up @@ -257,6 +303,16 @@ void ProxyManager::SetGlobalProxySettings() {
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,
Expand All @@ -266,6 +322,25 @@ void ProxyManager::SetGlobalProxySettings() {
}
}

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()),
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()),
password.size() + 1);
if (!success) {
LOGERR(WARN) << "InternetSetOption failed setting INTERNET_OPTION_PROXY_PASSWORD";
}
}

void ProxyManager::GetCurrentProxySettings() {
LOG(TRACE) << "ProxyManager::GetCurrentProxySettings";
this->GetCurrentProxyType();
Expand Down Expand Up @@ -308,6 +383,24 @@ void ProxyManager::GetCurrentProxySettings() {
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);
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);
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() {
Expand Down
12 changes: 11 additions & 1 deletion cpp/iedriver/ProxyManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ struct ProxySettings {
std::string http_proxy;
std::string ftp_proxy;
std::string ssl_proxy;
std::string socks_proxy;
std::string socks_user_name;
std::string socks_password;
std::string proxy_autoconfig_url;
};

Expand All @@ -51,8 +54,10 @@ class ProxyManager {
private:
void SetPerProcessProxySettings(HWND browser_window_handle);
void SetGlobalProxySettings(void);
void SetProxyAuthentication(const std::wstring& user_name, const std::wstring& password);
void GetCurrentProxySettings(void);
void GetCurrentProxyType(void);
void GetCurrentProxyAuthentication(void);
void RestoreProxySettings(void);

std::wstring BuildProxySettingsString(void);
Expand All @@ -65,15 +70,20 @@ class ProxyManager {
std::wstring current_autoconfig_url_;
std::wstring current_proxy_server_;
std::wstring current_proxy_bypass_list_;
std::wstring current_socks_user_name_;
std::wstring current_socks_password_;

//std::string proxy_settings_;
std::string proxy_type_;
std::string http_proxy_;
std::string ftp_proxy_;
std::string ssl_proxy_;
std::string socks_proxy_;
std::string socks_user_name_;
std::string socks_password_;
std::string proxy_autoconfigure_url_;
bool use_per_process_proxy_;
bool is_proxy_modified_;
bool is_proxy_authorization_modified_;
};

} // namespace webdriver
Expand Down

0 comments on commit 931f51a

Please sign in to comment.