1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.h" 6 7 #include "base/android/build_info.h" 8 #include "base/android/jni_android.h" 9 #include "base/android/jni_string.h" 10 #include "base/base64.h" 11 #include "base/bind.h" 12 #include "base/command_line.h" 13 #include "base/metrics/histogram.h" 14 #include "base/prefs/pref_member.h" 15 #include "base/prefs/pref_service.h" 16 #include "base/prefs/scoped_user_pref_update.h" 17 #include "base/strings/string_number_conversions.h" 18 #include "base/strings/string_util.h" 19 #include "base/strings/stringprintf.h" 20 #include "base/strings/utf_string_conversions.h" 21 #include "chrome/browser/browser_process.h" 22 #include "chrome/browser/prefs/proxy_prefs.h" 23 #include "chrome/browser/profiles/profile.h" 24 #include "chrome/browser/profiles/profile_manager.h" 25 #include "chrome/common/chrome_switches.h" 26 #include "chrome/common/pref_names.h" 27 #include "jni/DataReductionProxySettings_jni.h" 28 #include "net/base/auth.h" 29 #include "net/base/host_port_pair.h" 30 #include "net/base/load_flags.h" 31 #include "net/base/net_errors.h" 32 #include "net/url_request/url_fetcher.h" 33 #include "net/url_request/url_fetcher_delegate.h" 34 #include "net/url_request/url_request_status.h" 35 #include "url/gurl.h" 36 37 using base::android::CheckException; 38 using base::android::ConvertJavaStringToUTF8; 39 using base::android::ConvertUTF16ToJavaString; 40 using base::android::ConvertUTF8ToJavaString; 41 using base::android::ScopedJavaLocalRef; 42 using base::StringPrintf; 43 44 namespace { 45 46 // The C++ definition of enum SpdyProxyAuthState defined in 47 // tools/histograms/histograms.xml. 48 // New values should be added at the end before |NUM_SPDY_PROXY_AUTH_STATE|. 49 enum { 50 CHROME_STARTUP, 51 SPDY_PROXY_AUTH_ON_AT_STARTUP, 52 SPDY_PROXY_AUTH_ON_BY_USER, 53 SPDY_PROXY_AUTH_OFF_BY_USER, 54 // Used by UMA histograms and should always be the last value. 55 NUM_SPDY_PROXY_AUTH_STATE 56 }; 57 58 // Generates a PAC proxy string component, including trailing semicolon and 59 // space, for |origin|. Eg: 60 // "http://foo.com/" -> "PROXY foo.com:80; " 61 // "https://bar.com:10443" -> "HTTPS bar.coom:10443; " 62 // The returned strings are suitable for concatenating into a PAC string. 63 // If |origin| is empty, returns an empty string. 64 std::string ProtocolAndHostForPACString(const std::string& origin) { 65 if (origin.empty()) { 66 return std::string(); 67 } 68 GURL url = GURL(origin); 69 std::string protocol = url.SchemeIsSecure() ? "HTTPS " : "PROXY "; 70 return protocol + net::HostPortPair::FromURL(url).ToString() + "; "; 71 } 72 73 } // namespace 74 75 DataReductionProxySettingsAndroid::DataReductionProxySettingsAndroid( 76 JNIEnv* env, jobject obj): DataReductionProxySettings() { 77 } 78 79 DataReductionProxySettingsAndroid::DataReductionProxySettingsAndroid() {} 80 81 DataReductionProxySettingsAndroid::~DataReductionProxySettingsAndroid() {} 82 83 void DataReductionProxySettingsAndroid::InitDataReductionProxySettings( 84 JNIEnv* env, 85 jobject obj) { 86 DataReductionProxySettings::InitDataReductionProxySettings(); 87 } 88 89 void DataReductionProxySettingsAndroid::BypassHostPattern( 90 JNIEnv* env, jobject obj, jstring pattern) { 91 DataReductionProxySettings::AddHostPatternToBypass( 92 ConvertJavaStringToUTF8(env, pattern)); 93 } 94 void DataReductionProxySettingsAndroid::BypassURLPattern( 95 JNIEnv* env, jobject obj, jstring pattern) { 96 AddURLPatternToBypass(ConvertJavaStringToUTF8(env, pattern)); 97 } 98 99 void DataReductionProxySettingsAndroid::AddURLPatternToBypass( 100 const std::string& pattern) { 101 pac_bypass_rules_.push_back( 102 StringPrintf("shExpMatch(%s, '%s')", "url", pattern.c_str())); 103 } 104 105 jboolean DataReductionProxySettingsAndroid::IsDataReductionProxyAllowed( 106 JNIEnv* env, jobject obj) { 107 return DataReductionProxySettings::IsDataReductionProxyAllowed(); 108 } 109 110 jboolean DataReductionProxySettingsAndroid::IsDataReductionProxyPromoAllowed( 111 JNIEnv* env, jobject obj) { 112 return DataReductionProxySettings::IsDataReductionProxyPromoAllowed(); 113 } 114 115 ScopedJavaLocalRef<jstring> 116 DataReductionProxySettingsAndroid::GetDataReductionProxyOrigin( 117 JNIEnv* env, jobject obj) { 118 return ConvertUTF8ToJavaString( 119 env, DataReductionProxySettings::GetDataReductionProxyOrigin()); 120 } 121 122 jboolean DataReductionProxySettingsAndroid::IsDataReductionProxyEnabled( 123 JNIEnv* env, jobject obj) { 124 return DataReductionProxySettings::IsDataReductionProxyEnabled(); 125 } 126 127 jboolean DataReductionProxySettingsAndroid::IsDataReductionProxyManaged( 128 JNIEnv* env, jobject obj) { 129 return DataReductionProxySettings::IsDataReductionProxyManaged(); 130 } 131 132 void DataReductionProxySettingsAndroid::SetDataReductionProxyEnabled( 133 JNIEnv* env, 134 jobject obj, 135 jboolean enabled) { 136 DataReductionProxySettings::SetDataReductionProxyEnabled(enabled); 137 } 138 139 jlong DataReductionProxySettingsAndroid::GetDataReductionLastUpdateTime( 140 JNIEnv* env, jobject obj) { 141 return DataReductionProxySettings::GetDataReductionLastUpdateTime(); 142 } 143 144 base::android::ScopedJavaLocalRef<jobject> 145 DataReductionProxySettingsAndroid::GetContentLengths(JNIEnv* env, 146 jobject obj) { 147 int64 original_content_length; 148 int64 received_content_length; 149 int64 last_update_internal; 150 DataReductionProxySettings::GetContentLengths( 151 spdyproxy::kNumDaysInHistorySummary, 152 &original_content_length, 153 &received_content_length, 154 &last_update_internal); 155 156 return Java_ContentLengths_create(env, 157 original_content_length, 158 received_content_length); 159 } 160 161 jboolean DataReductionProxySettingsAndroid::IsAcceptableAuthChallenge( 162 JNIEnv* env, 163 jobject obj, 164 jstring host, 165 jstring realm) { 166 scoped_refptr<net::AuthChallengeInfo> auth_info(new net::AuthChallengeInfo); 167 auth_info->realm = ConvertJavaStringToUTF8(env, realm); 168 auth_info->challenger = 169 net::HostPortPair::FromString(ConvertJavaStringToUTF8(env, host)); 170 return DataReductionProxySettings::IsAcceptableAuthChallenge(auth_info.get()); 171 } 172 173 ScopedJavaLocalRef<jstring> 174 DataReductionProxySettingsAndroid::GetTokenForAuthChallenge(JNIEnv* env, 175 jobject obj, 176 jstring host, 177 jstring realm) { 178 scoped_refptr<net::AuthChallengeInfo> auth_info(new net::AuthChallengeInfo); 179 auth_info->realm = ConvertJavaStringToUTF8(env, realm); 180 auth_info->challenger = 181 net::HostPortPair::FromString(ConvertJavaStringToUTF8(env, host)); 182 183 // If an empty string != null in Java, then here we should test for the 184 // token being empty and return a java null. 185 return ConvertUTF16ToJavaString(env, 186 DataReductionProxySettings::GetTokenForAuthChallenge(auth_info.get())); 187 } 188 189 ScopedJavaLocalRef<jlongArray> 190 DataReductionProxySettingsAndroid::GetDailyOriginalContentLengths( 191 JNIEnv* env, jobject obj) { 192 return GetDailyContentLengths(env, prefs::kDailyHttpOriginalContentLength); 193 } 194 195 ScopedJavaLocalRef<jlongArray> 196 DataReductionProxySettingsAndroid::GetDailyReceivedContentLengths( 197 JNIEnv* env, jobject obj) { 198 return GetDailyContentLengths(env, prefs::kDailyHttpReceivedContentLength); 199 } 200 201 // static 202 bool DataReductionProxySettingsAndroid::Register(JNIEnv* env) { 203 bool register_natives_impl_result = RegisterNativesImpl(env); 204 return register_natives_impl_result; 205 } 206 207 void DataReductionProxySettingsAndroid::AddDefaultProxyBypassRules() { 208 DataReductionProxySettings::AddDefaultProxyBypassRules(); 209 210 // TODO(bengr): See http://crbug.com/169959. For some reason the data 211 // reduction proxy is breaking the omnibox SearchProvider. Remove this rule 212 // when this is fixed. 213 AddURLPatternToBypass("http://www.google.com/complete/search*"); 214 // Chrome cannot authenticate with the data reduction proxy when fetching URLs 215 // from the settings menu. 216 AddURLPatternToBypass("http://www.google.com/policies/privacy*"); 217 } 218 219 void DataReductionProxySettingsAndroid::SetProxyConfigs(bool enabled, 220 bool restricted, 221 bool at_startup) { 222 // Sanity check: If there's no fallback proxy, we can't do a restricted mode. 223 std::string fallback = GetDataReductionProxyFallback(); 224 if (fallback.empty() && enabled && restricted) 225 enabled = false; 226 227 // Keys duplicated from proxy_config_dictionary.cc 228 // TODO(bengr): Move these to proxy_config_dictionary.h and reuse them here. 229 const char kProxyMode[] = "mode"; 230 const char kProxyPacURL[] = "pac_url"; 231 const char kProxyBypassList[] = "bypass_list"; 232 233 LogProxyState(enabled, restricted, at_startup); 234 235 PrefService* prefs = GetOriginalProfilePrefs(); 236 DCHECK(prefs); 237 DictionaryPrefUpdate update(prefs, prefs::kProxy); 238 base::DictionaryValue* dict = update.Get(); 239 if (enabled) { 240 // Convert to a data URI and update the PAC settings. 241 std::string base64_pac; 242 base::Base64Encode(GetProxyPacScript(restricted), &base64_pac); 243 244 dict->SetString(kProxyPacURL, 245 "data:application/x-ns-proxy-autoconfig;base64," + 246 base64_pac); 247 dict->SetString(kProxyMode, 248 ProxyModeToString(ProxyPrefs::MODE_PAC_SCRIPT)); 249 dict->SetString(kProxyBypassList, JoinString(BypassRules(), ", ")); 250 251 } else { 252 dict->SetString(kProxyMode, ProxyModeToString(ProxyPrefs::MODE_SYSTEM)); 253 dict->SetString(kProxyPacURL, ""); 254 dict->SetString(kProxyBypassList, ""); 255 } 256 } 257 258 ScopedJavaLocalRef<jlongArray> 259 DataReductionProxySettingsAndroid::GetDailyContentLengths( 260 JNIEnv* env, const char* pref_name) { 261 jlongArray result = env->NewLongArray(spdyproxy::kNumDaysInHistory); 262 263 DataReductionProxySettings::ContentLengthList lengths = 264 DataReductionProxySettings::GetDailyContentLengths(pref_name); 265 266 if (!lengths.empty()) { 267 DCHECK_EQ(lengths.size(), spdyproxy::kNumDaysInHistory); 268 env->SetLongArrayRegion(result, 0, lengths.size(), &lengths[0]); 269 return ScopedJavaLocalRef<jlongArray>(env, result); 270 } 271 272 return ScopedJavaLocalRef<jlongArray>(env, result); 273 } 274 275 // TODO(bengr): Replace with our own ProxyResolver. 276 std::string DataReductionProxySettingsAndroid::GetProxyPacScript( 277 bool restricted) { 278 // Compose the PAC-only bypass code; these will be URL patterns that 279 // are matched by regular expression. Host bypasses are handled outside 280 // of the PAC file using the regular proxy bypass list configs. 281 std::string bypass_clause = 282 "(" + JoinString(pac_bypass_rules_, ") || (") + ")"; 283 284 // Generate a proxy PAC that falls back to direct loading when the proxy is 285 // unavailable and only process HTTP traffic. 286 287 std::string proxy_host = ProtocolAndHostForPACString( 288 DataReductionProxySettings::GetDataReductionProxyOrigin()); 289 std::string fallback_host = ProtocolAndHostForPACString( 290 DataReductionProxySettings::GetDataReductionProxyFallback()); 291 std::string hosts = restricted ? fallback_host : proxy_host + fallback_host; 292 std::string pac = "function FindProxyForURL(url, host) {" 293 " if (" + bypass_clause + ") {" 294 " return 'DIRECT';" 295 " } " 296 " if (url.substring(0, 5) == 'http:') {" 297 " return '" + hosts + "DIRECT';" 298 " }" 299 " return 'DIRECT';" 300 "}"; 301 return pac; 302 } 303 304 // Used by generated jni code. 305 static jlong Init(JNIEnv* env, jobject obj) { 306 DataReductionProxySettingsAndroid* settings = 307 new DataReductionProxySettingsAndroid(env, obj); 308 return reinterpret_cast<intptr_t>(settings); 309 } 310