Index: chrome/browser/net/spdyproxy/data_reduction_proxy_settings.cc |
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings.cc |
index 4318d770545b5b7eb7818aaf49d33ad3db4b43d6..ddf2de9fc78f76100f745aab1dc0c8713e9555c6 100644 |
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings.cc |
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings.cc |
@@ -21,9 +21,14 @@ |
#include "chrome/browser/profiles/profile_manager.h" |
#include "chrome/common/chrome_switches.h" |
#include "chrome/common/pref_names.h" |
+#include "crypto/random.h" |
+#include "net/base/auth.h" |
#include "net/base/host_port_pair.h" |
#include "net/base/load_flags.h" |
#include "net/base/net_errors.h" |
+#include "net/http/http_auth.h" |
+#include "net/http/http_auth_cache.h" |
+#include "net/http/http_network_session.h" |
#include "net/url_request/url_fetcher.h" |
#include "net/url_request/url_fetcher_delegate.h" |
#include "net/url_request/url_request_status.h" |
@@ -47,6 +52,10 @@ enum ProxyStartupState { |
const char kEnabled[] = "Enabled"; |
+// TODO(marq): Factor this string out into a constant here and in |
+// http_auth_handler_spdyproxy. |
+const char kAuthenticationRealmName[] = "SpdyProxy"; |
+ |
int64 GetInt64PrefValue(const ListValue& list_value, size_t index) { |
int64 val = 0; |
std::string pref_value; |
@@ -59,6 +68,11 @@ int64 GetInt64PrefValue(const ListValue& list_value, size_t index) { |
return val; |
} |
+bool IsProxyOriginSetOnCommandLine() { |
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
+ return command_line.HasSwitch(switches::kSpdyProxyAuthOrigin); |
+} |
+ |
} // namespace |
DataReductionProxySettings::DataReductionProxySettings() |
@@ -107,6 +121,54 @@ void DataReductionProxySettings::InitDataReductionProxySettings() { |
} |
} |
+void DataReductionProxySettings::InitDataReductionProxySession( |
+ net::HttpNetworkSession* session) { |
+// This is a no-op unless the authentication parameters are compiled in. |
+// (even though values for them may be specified on the command line). |
+// Authentication will still work if the command line parameters are used, |
+// however there will be a round-trip overhead for each challenge/response |
+// (typically once per session). |
+#if defined(SPDY_PROXY_AUTH_ORIGIN) && defined(SPDY_PROXY_AUTH_VALUE) |
+ DCHECK(session); |
+ net::HttpAuthCache* auth_cache = session->http_auth_cache(); |
+ DCHECK(auth_cache); |
+ InitDataReductionAuthentication(auth_cache); |
+#endif // defined(SPDY_PROXY_AUTH_ORIGIN) && defined(SPDY_PROXY_AUTH_VALUE) |
+} |
+ |
+void DataReductionProxySettings::InitDataReductionAuthentication( |
+ net::HttpAuthCache* auth_cache) { |
+ DCHECK(auth_cache); |
+ int64 timestamp = |
+ (base::Time::Now() - base::Time::UnixEpoch()).InMilliseconds() / 1000; |
+ |
+ DataReductionProxyList proxies = GetDataReductionProxies(); |
+ for (DataReductionProxyList::iterator it = proxies.begin(); |
+ it != proxies.end(); ++it) { |
+ GURL auth_origin = (*it).GetOrigin(); |
+ int32 rand[3]; |
+ crypto::RandBytes(rand, 3 * sizeof(rand[0])); |
+ |
+ std::string realm = |
+ base::StringPrintf("%s%lld", kAuthenticationRealmName, timestamp); |
+ std::string challenge = base::StringPrintf( |
+ "%s realm=\"%s\", ps=\"%lld-%u-%u-%u\"", kAuthenticationRealmName, |
+ realm.data(), timestamp, rand[0], rand[1], rand[2]); |
+ base::string16 password = AuthHashForSalt(timestamp); |
+ |
+ DVLOG(1) << "origin: [" << auth_origin << "] realm: [" << realm |
+ << "] challenge: [" << challenge << "] password: [" << password << "]"; |
+ |
+ net::AuthCredentials credentials(base::string16(), password); |
+ auth_cache->Add(auth_origin, |
+ realm, |
+ net::HttpAuth::AUTH_SCHEME_SPDYPROXY, |
+ challenge, |
+ credentials, |
+ std::string()); // Proxy auth uses an empty path for lookup. |
+ } |
+} |
+ |
void DataReductionProxySettings::AddHostPatternToBypass( |
const std::string& pattern) { |
bypass_rules_.push_back(pattern); |
@@ -150,26 +212,58 @@ std::string DataReductionProxySettings::GetDataReductionProxyOrigin() { |
#endif |
} |
-std::string DataReductionProxySettings::GetDataReductionProxyAuth() { |
- if (!IsDataReductionProxyAllowed()) |
+std::string DataReductionProxySettings::GetDataReductionProxyFallback() { |
+ // Regardless of what else is defined, only return a value if the main proxy |
+ // origin is defined. |
+ if (GetDataReductionProxyOrigin().empty()) |
return std::string(); |
const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
- if (command_line.HasSwitch(switches::kSpdyProxyAuthOrigin)) { |
- // If an origin is provided via a switch, then only consider the value |
- // that is provided by a switch. Do not use the preprocessor constant. |
- // Don't expose SPDY_PROXY_AUTH_VALUE to a proxy passed in via the command |
- // line. |
- if (command_line.HasSwitch(switches::kSpdyProxyAuthValue)) |
- return command_line.GetSwitchValueASCII(switches::kSpdyProxyAuthValue); |
- return std::string(); |
- } |
-#if defined(SPDY_PROXY_AUTH_VALUE) |
- return SPDY_PROXY_AUTH_VALUE; |
+ if (command_line.HasSwitch(switches::kSpdyProxyAuthFallback)) |
+ return command_line.GetSwitchValueASCII(switches::kSpdyProxyAuthFallback); |
+#if defined(DATA_REDUCTION_FALLBACK_HOST) |
+ return DATA_REDUCTION_FALLBACK_HOST; |
#else |
return std::string(); |
#endif |
} |
+bool DataReductionProxySettings::IsAcceptableAuthChallenge( |
+ net::AuthChallengeInfo* auth_info) { |
+ // Challenge realm must start with the authentication realm name. |
+ std::string realm_prefix = |
+ auth_info->realm.substr(0, strlen(kAuthenticationRealmName)); |
+ if (realm_prefix != kAuthenticationRealmName) |
+ return false; |
+ |
+ // The challenger must be one of the configured proxies. |
+ DataReductionProxyList proxies = GetDataReductionProxies(); |
+ for (DataReductionProxyList::iterator it = proxies.begin(); |
+ it != proxies.end(); ++it) { |
+ net::HostPortPair origin_host = net::HostPortPair::FromURL(*it); |
+ if (origin_host.Equals(auth_info->challenger)) |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+base::string16 DataReductionProxySettings::GetTokenForAuthChallenge( |
+ net::AuthChallengeInfo* auth_info) { |
+ if (auth_info->realm.length() > strlen(kAuthenticationRealmName)) { |
+ int64 salt; |
+ std::string realm_suffix = |
+ auth_info->realm.substr(strlen(kAuthenticationRealmName)); |
+ if (base::StringToInt64(realm_suffix, &salt)) { |
+ return AuthHashForSalt(salt); |
+ } else { |
+ DVLOG(1) << "Unable to parse realm name " << auth_info->realm |
+ << "into an int for salting."; |
+ return base::string16(); |
+ } |
+ } else { |
+ return base::string16(); |
+ } |
+} |
+ |
bool DataReductionProxySettings::IsDataReductionProxyEnabled() { |
return spdy_proxy_auth_enabled_.GetValue(); |
} |
@@ -178,6 +272,24 @@ bool DataReductionProxySettings::IsDataReductionProxyManaged() { |
return spdy_proxy_auth_enabled_.IsManaged(); |
} |
+DataReductionProxySettings::DataReductionProxyList |
+DataReductionProxySettings::GetDataReductionProxies() { |
+ DataReductionProxyList proxies; |
+ std::string proxy = GetDataReductionProxyOrigin(); |
+ std::string fallback = GetDataReductionProxyFallback(); |
+ |
+ if (!proxy.empty()) |
+ proxies.push_back(GURL(proxy)); |
+ |
+ if (!fallback.empty()) { |
+ // Sanity check: fallback isn't the only proxy. |
+ DCHECK(!proxies.empty()); |
+ proxies.push_back(GURL(fallback)); |
+ } |
+ |
+ return proxies; |
+} |
+ |
void DataReductionProxySettings::SetDataReductionProxyEnabled(bool enabled) { |
// Prevent configuring the proxy when it is not allowed to be used. |
if (!IsDataReductionProxyAllowed()) |
@@ -195,12 +307,12 @@ int64 DataReductionProxySettings::GetDataReductionLastUpdateTime() { |
return static_cast<int64>(last_update.ToJsTime()); |
} |
-std::vector<long long> |
+DataReductionProxySettings::ContentLengthList |
DataReductionProxySettings::GetDailyOriginalContentLengths() { |
return GetDailyContentLengths(prefs::kDailyHttpOriginalContentLength); |
} |
-std::vector<long long> |
+DataReductionProxySettings::ContentLengthList |
DataReductionProxySettings::GetDailyReceivedContentLengths() { |
return GetDailyContentLengths(prefs::kDailyHttpReceivedContentLength); |
} |
@@ -237,17 +349,6 @@ void DataReductionProxySettings::OnURLFetchComplete( |
disabled_by_carrier_ = true; |
} |
-std::string DataReductionProxySettings::GetDataReductionProxyOriginHostPort() { |
- std::string spdy_proxy = GetDataReductionProxyOrigin(); |
- if (spdy_proxy.empty()) { |
- DLOG(ERROR) << "A SPDY proxy has not been set."; |
- return spdy_proxy; |
- } |
- // Remove a trailing slash from the proxy string if one exists as well as |
- // leading HTTPS scheme. |
- return net::HostPortPair::FromURL(GURL(spdy_proxy)).ToString(); |
-} |
- |
void DataReductionProxySettings::OnIPAddressChanged() { |
if (enabled_by_user_) { |
DCHECK(IsDataReductionProxyAllowed()); |
@@ -256,7 +357,7 @@ void DataReductionProxySettings::OnIPAddressChanged() { |
} |
void DataReductionProxySettings::OnProxyEnabledPrefChange() { |
- if (!IsDataReductionProxyAllowed()) |
+ if (!DataReductionProxySettings::IsDataReductionProxyAllowed()) |
return; |
MaybeActivateDataReductionProxy(false); |
} |
@@ -293,11 +394,6 @@ PrefService* DataReductionProxySettings::GetLocalStatePrefs() { |
return g_browser_process->local_state(); |
} |
-bool DataReductionProxySettings::IsProxyOriginSetOnCommandLine() { |
- const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
- return command_line.HasSwitch(switches::kSpdyProxyAuthOrigin); |
-} |
- |
void DataReductionProxySettings::ResetDataReductionStatistics() { |
PrefService* prefs = GetLocalStatePrefs(); |
if (!prefs) |
@@ -324,12 +420,10 @@ void DataReductionProxySettings::MaybeActivateDataReductionProxy( |
ResetDataReductionStatistics(); |
} |
- std::string spdy_proxy_origin = GetDataReductionProxyOriginHostPort(); |
- |
+ std::string proxy = GetDataReductionProxyOrigin(); |
// Configure use of the data reduction proxy if it is enabled and the proxy |
// origin is non-empty. |
- enabled_by_user_= |
- spdy_proxy_auth_enabled_.GetValue() && !spdy_proxy_origin.empty(); |
+ enabled_by_user_= spdy_proxy_auth_enabled_.GetValue() && !proxy.empty(); |
SetProxyConfigs(enabled_by_user_ && !disabled_by_carrier_, at_startup); |
// Check if the proxy has been disabled explicitly by the carrier. |
@@ -345,8 +439,11 @@ void DataReductionProxySettings::SetProxyConfigs(bool enabled, |
DictionaryPrefUpdate update(prefs, prefs::kProxy); |
base::DictionaryValue* dict = update.Get(); |
if (enabled) { |
+ std::string fallback = GetDataReductionProxyFallback(); |
std::string proxy_server_config = |
- "http=" + GetDataReductionProxyOrigin() + ",direct://;"; |
+ "http=" + GetDataReductionProxyOrigin() + |
+ (fallback.empty() ? "" : "," + fallback) + |
+ ",direct://;"; |
dict->SetString("server", proxy_server_config); |
dict->SetString("mode", |
ProxyModeToString(ProxyPrefs::MODE_FIXED_SERVERS)); |
@@ -436,6 +533,36 @@ std::string DataReductionProxySettings::GetProxyCheckURL() { |
#endif |
} |
+base::string16 DataReductionProxySettings::AuthHashForSalt(int64 salt) { |
+ if (!IsDataReductionProxyAllowed()) |
+ return base::string16(); |
+ |
+ std::string key; |
+ |
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
+ if (command_line.HasSwitch(switches::kSpdyProxyAuthOrigin)) { |
+ // If an origin is provided via a switch, then only consider the value |
+ // that is provided by a switch. Do not use the preprocessor constant. |
+ // Don't expose SPDY_PROXY_AUTH_VALUE to a proxy passed in via the command |
+ // line. |
+ if (!command_line.HasSwitch(switches::kSpdyProxyAuthValue)) |
+ return base::string16(); |
+ key = command_line.GetSwitchValueASCII(switches::kSpdyProxyAuthValue); |
+ } else { |
+#if defined(SPDY_PROXY_AUTH_VALUE) |
+ key = SPDY_PROXY_AUTH_VALUE; |
+#else |
+ return base::string16(); |
+#endif |
+ } |
+ |
+ DCHECK(!key.empty()); |
+ |
+ std::string salted_key = |
+ base::StringPrintf("%lld%s%lld", salt, key.c_str(), salt); |
+ return UTF8ToUTF16(base::MD5String(salted_key)); |
+} |
+ |
net::URLFetcher* DataReductionProxySettings::GetURLFetcher() { |
std::string url = GetProxyCheckURL(); |
if (url.empty()) |
@@ -443,8 +570,7 @@ net::URLFetcher* DataReductionProxySettings::GetURLFetcher() { |
net::URLFetcher* fetcher = net::URLFetcher::Create(GURL(url), |
net::URLFetcher::GET, |
this); |
- fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE); |
- fetcher->SetLoadFlags(net::LOAD_BYPASS_PROXY); |
+ fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE | net::LOAD_BYPASS_PROXY); |
Profile* profile = g_browser_process->profile_manager()-> |
GetDefaultProfile(); |
fetcher->SetRequestContext(profile->GetRequestContext()); |