Home | History | Annotate | Download | only in spdyproxy
      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