Do not ignore proxy bypass settings

Bug: 18312952

Cherry pick upstream change https://codereview.chromium.org/421493002/
to fix the proxy bypass bug. Without this fix chrome net stack will
ignore proxy bypass settings.

Change-Id: I1d3ed05bc737cc49fe0e6a1c249b65525f418506
diff --git a/net/android/java/src/org/chromium/net/ProxyChangeListener.java b/net/android/java/src/org/chromium/net/ProxyChangeListener.java
index 51b6714..be09be4 100644
--- a/net/android/java/src/org/chromium/net/ProxyChangeListener.java
+++ b/net/android/java/src/org/chromium/net/ProxyChangeListener.java
@@ -36,16 +36,21 @@
     private Delegate mDelegate;
 
     private static class ProxyConfig {
-        public ProxyConfig(String host, int port, String pacUrl) {
+        public ProxyConfig(String host, int port, String pacUrl, String[] exclusionList) {
             mHost = host;
             mPort = port;
             mPacUrl = pacUrl;
+            mExclusionList = exclusionList;
         }
         public final String mHost;
         public final int mPort;
         public final String mPacUrl;
+        public final String[] mExclusionList;
     }
 
+    /**
+     * The delegate for ProxyChangeListener. Use for testing.
+     */
     public interface Delegate {
         public void proxySettingsChanged();
     }
@@ -104,6 +109,7 @@
                 final String getHostName = "getHost";
                 final String getPortName = "getPort";
                 final String getPacFileUrl = "getPacFileUrl";
+                final String getExclusionList = "getExclusionList";
                 String className;
                 String proxyInfo;
                 if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
@@ -122,27 +128,35 @@
                 Class<?> cls = Class.forName(className);
                 Method getHostMethod = cls.getDeclaredMethod(getHostName);
                 Method getPortMethod = cls.getDeclaredMethod(getPortName);
+                Method getExclusionListMethod = cls.getDeclaredMethod(getExclusionList);
 
                 String host = (String) getHostMethod.invoke(props);
                 int port = (Integer) getPortMethod.invoke(props);
 
+                String[] exclusionList;
+                if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
+                    String s = (String) getExclusionListMethod.invoke(props);
+                    exclusionList = s.split(",");
+                } else {
+                    exclusionList = (String[]) getExclusionListMethod.invoke(props);
+                }
                 // TODO(xunjieli): rewrite this once the API is public.
                 if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
                     Method getPacFileUrlMethod =
                         cls.getDeclaredMethod(getPacFileUrl);
                     String pacFileUrl = (String) getPacFileUrlMethod.invoke(props);
                     if (!TextUtils.isEmpty(pacFileUrl)) {
-                       return new ProxyConfig(host, port, pacFileUrl);
+                       return new ProxyConfig(host, port, pacFileUrl, exclusionList);
                     }
                 } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
                     Method getPacFileUrlMethod =
                         cls.getDeclaredMethod(getPacFileUrl);
                     Uri pacFileUrl = (Uri) getPacFileUrlMethod.invoke(props);
                     if (!Uri.EMPTY.equals(pacFileUrl)) {
-                      return new ProxyConfig(host, port, pacFileUrl.toString());
+                      return new ProxyConfig(host, port, pacFileUrl.toString(), exclusionList);
                     }
                 }
-                return new ProxyConfig(host, port, null);
+                return new ProxyConfig(host, port, null, exclusionList);
             } catch (ClassNotFoundException ex) {
                 Log.e(TAG, "Using no proxy configuration due to exception:" + ex);
                 return null;
@@ -175,7 +189,8 @@
         // Note that this code currently runs on a MESSAGE_LOOP_UI thread, but
         // the C++ code must run the callbacks on the network thread.
         if (cfg != null) {
-            nativeProxySettingsChangedTo(mNativePtr, cfg.mHost, cfg.mPort, cfg.mPacUrl);
+            nativeProxySettingsChangedTo(mNativePtr, cfg.mHost, cfg.mPort, cfg.mPacUrl,
+                    cfg.mExclusionList);
         } else {
             nativeProxySettingsChanged(mNativePtr);
         }
@@ -206,8 +221,8 @@
     private native void nativeProxySettingsChangedTo(long nativePtr,
                                                      String host,
                                                      int port,
-                                                     String pacUrl);
-
+                                                     String pacUrl,
+                                                     String[] exclusionList);
     @NativeClassQualifiedName("ProxyConfigServiceAndroid::JNIDelegate")
     private native void nativeProxySettingsChanged(long nativePtr);
 }
diff --git a/net/proxy/proxy_config_service_android.cc b/net/proxy/proxy_config_service_android.cc
index d27bc5a..2dcffdc 100644
--- a/net/proxy/proxy_config_service_android.cc
+++ b/net/proxy/proxy_config_service_android.cc
@@ -6,6 +6,7 @@
 
 #include <sys/system_properties.h>
 
+#include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
 #include "base/basictypes.h"
 #include "base/bind.h"
@@ -162,6 +163,7 @@
 void CreateStaticProxyConfig(const std::string& host,
                              int port,
                              const std::string& pac_url,
+                             const std::vector<std::string>& exclusion_list,
                              ProxyConfig* config) {
   if (!pac_url.empty()) {
     config->set_pac_url(GURL(pac_url));
@@ -169,6 +171,16 @@
   } else if (port != 0) {
     std::string rules = base::StringPrintf("%s:%d", host.c_str(), port);
     config->proxy_rules().ParseFromString(rules);
+    config->proxy_rules().bypass_rules.Clear();
+
+    std::vector<std::string>::const_iterator it;
+    for (it = exclusion_list.begin(); it != exclusion_list.end(); ++it) {
+      std::string pattern;
+      base::TrimWhitespaceASCII(*it, base::TRIM_ALL, &pattern);
+      if (pattern.empty())
+          continue;
+      config->proxy_rules().bypass_rules.AddRuleForHostname("", pattern, -1);
+    }
   } else {
     *config = ProxyConfig::CreateDirect();
   }
@@ -255,10 +267,11 @@
   // Called on the JNI thread.
   void ProxySettingsChangedTo(const std::string& host,
                               int port,
-                              const std::string& pac_url) {
+                              const std::string& pac_url,
+                              const std::vector<std::string>& exclusion_list) {
     DCHECK(OnJNIThread());
     ProxyConfig proxy_config;
-    CreateStaticProxyConfig(host, port, pac_url, &proxy_config);
+    CreateStaticProxyConfig(host, port, pac_url, exclusion_list, &proxy_config);
     network_task_runner_->PostTask(
         FROM_HERE,
         base::Bind(
@@ -277,12 +290,16 @@
                                         jobject jself,
                                         jstring jhost,
                                         jint jport,
-                                        jstring jpac_url) OVERRIDE {
+                                        jstring jpac_url,
+                                        jobjectArray jexclusion_list) OVERRIDE {
       std::string host = ConvertJavaStringToUTF8(env, jhost);
       std::string pac_url;
       if (jpac_url)
         ConvertJavaStringToUTF8(env, jpac_url, &pac_url);
-      delegate_->ProxySettingsChangedTo(host, jport, pac_url);
+      std::vector<std::string> exclusion_list;
+      base::android::AppendJavaStringArrayToStringVector(
+          env, jexclusion_list, &exclusion_list);
+      delegate_->ProxySettingsChangedTo(host, jport, pac_url, exclusion_list);
     }
 
     virtual void ProxySettingsChanged(JNIEnv* env, jobject self) OVERRIDE {
diff --git a/net/proxy/proxy_config_service_android.h b/net/proxy/proxy_config_service_android.h
index ee54b94..bb8b592 100644
--- a/net/proxy/proxy_config_service_android.h
+++ b/net/proxy/proxy_config_service_android.h
@@ -42,11 +42,13 @@
     // changed. The string and int arguments (the host/port pair for the proxy)
     // are either a host/port pair or ("", 0) to indicate "no proxy".
     // The third argument indicates the PAC url.
+    // The fourth argument is the proxy exclusion list.
     virtual void ProxySettingsChangedTo(JNIEnv*,
                                         jobject,
                                         jstring,
                                         jint,
-                                        jstring) = 0;
+                                        jstring,
+                                        jobjectArray) = 0;
 
     // Called from Java (on JNI thread) to signal that the proxy settings have
     // changed. New proxy settings are fetched from the system property store.