Add NO_PROXY environment variable support to downloader

Check the no_proxy and NO_PROXY environment variables for a list of URLs that
should not use a proxy. If the requested URL matches the no_proxy list, don't
proxy the download.

Fixes #4299

Closes #4307.

PiperOrigin-RevId: 184149118
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/ProxyHelper.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/ProxyHelper.java
index 1ae265b..c757dee 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/ProxyHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/ProxyHelper.java
@@ -51,6 +51,28 @@
    */
   public Proxy createProxyIfNeeded(URL requestedUrl) throws IOException {
     String proxyAddress = null;
+    String noProxyUrl = env.get("no_proxy");
+    if (Strings.isNullOrEmpty(noProxyUrl)) {
+      noProxyUrl = env.get("NO_PROXY");
+    }
+    if (!Strings.isNullOrEmpty(noProxyUrl)) {
+      String[] noProxyUrlArray = noProxyUrl.split(",");
+      String requestedHost = requestedUrl.getHost();
+      for (int i = 0; i < noProxyUrlArray.length; i++) {
+        if (noProxyUrlArray[i].startsWith(".")) {
+          // This entry applies to sub-domains only.
+          if (requestedHost.endsWith(noProxyUrlArray[i])) {
+            return Proxy.NO_PROXY;
+          }
+        } else {
+          // This entry applies to the literal hostname and sub-domains.
+          if (requestedHost.equals(noProxyUrlArray[i])
+              || requestedHost.endsWith("." + noProxyUrlArray[i])) {
+            return Proxy.NO_PROXY;
+          }
+        }
+      }
+    }
     if (HttpUtils.isProtocol(requestedUrl, "https")) {
       proxyAddress = env.get("https_proxy");
       if (Strings.isNullOrEmpty(proxyAddress)) {
diff --git a/src/test/java/com/google/devtools/build/lib/bazel/repository/downloader/ProxyHelperTest.java b/src/test/java/com/google/devtools/build/lib/bazel/repository/downloader/ProxyHelperTest.java
index 5aa7d10..49e38a3 100644
--- a/src/test/java/com/google/devtools/build/lib/bazel/repository/downloader/ProxyHelperTest.java
+++ b/src/test/java/com/google/devtools/build/lib/bazel/repository/downloader/ProxyHelperTest.java
@@ -61,6 +61,97 @@
   }
 
   @Test
+  public void testCreateIfNeededNoProxyLowerCase() throws Exception {
+    ProxyHelper helper =
+        new ProxyHelper(
+            ImmutableMap.of(
+                "no_proxy",
+                "something.com,example.com,localhost",
+                "HTTPS_PROXY",
+                "https://my.example.com"));
+    Proxy proxy = helper.createProxyIfNeeded(new URL("https://www.example.com"));
+    assertThat(proxy).isEqualTo(Proxy.NO_PROXY);
+  }
+
+  @Test
+  public void testCreateIfNeededNoProxyUpperCase() throws Exception {
+    ProxyHelper helper =
+        new ProxyHelper(
+            ImmutableMap.of(
+                "NO_PROXY",
+                "something.com,example.com,localhost",
+                "HTTPS_PROXY",
+                "https://my.example.com"));
+    Proxy proxy = helper.createProxyIfNeeded(new URL("https://www.example.com"));
+    assertThat(proxy).isEqualTo(Proxy.NO_PROXY);
+  }
+
+  @Test
+  public void testCreateIfNeededMultipleNoProxyLowerCase() throws Exception {
+    ProxyHelper helper =
+        new ProxyHelper(
+            ImmutableMap.of(
+                "no_proxy",
+                "something.com,example.com,localhost",
+                "HTTPS_PROXY",
+                "https://my.example.com"));
+    Proxy proxy = helper.createProxyIfNeeded(new URL("https://www.example.com"));
+    assertThat(proxy).isEqualTo(Proxy.NO_PROXY);
+  }
+
+  @Test
+  public void testCreateIfNeededMultipleNoProxyUpperCase() throws Exception {
+    ProxyHelper helper =
+        new ProxyHelper(
+            ImmutableMap.of(
+                "NO_PROXY",
+                "something.com,example.com,localhost",
+                "HTTPS_PROXY",
+                "https://my.example.com"));
+    Proxy proxy = helper.createProxyIfNeeded(new URL("https://www.example.com"));
+    assertThat(proxy).isEqualTo(Proxy.NO_PROXY);
+  }
+
+  @Test
+  public void testCreateIfNeededNoProxyNoMatchSubstring() throws Exception {
+    ProxyHelper helper =
+        new ProxyHelper(
+            ImmutableMap.of(
+                "NO_PROXY",
+                "something.com,example.com,localhost",
+                "HTTPS_PROXY",
+                "https://my.example.com"));
+    Proxy proxy = helper.createProxyIfNeeded(new URL("https://www.not-example.com"));
+    assertThat(proxy.toString()).endsWith("my.example.com:443");
+  }
+
+  @Test
+  public void testCreateIfNeededNoProxyMatchSubdomainInNoProxy() throws Exception {
+    ProxyHelper helper =
+        new ProxyHelper(
+            ImmutableMap.of(
+                "NO_PROXY",
+                ".something.com,example.com,localhost",
+                "HTTPS_PROXY",
+                "https://my.example.com"));
+    Proxy proxy = helper.createProxyIfNeeded(new URL("https://www.my.something.com"));
+    assertThat(proxy).isEqualTo(Proxy.NO_PROXY);
+  }
+
+  @Test
+  public void testCreateIfNeededNoProxyMatchSubdomainInURL() throws Exception {
+    ProxyHelper helper =
+        new ProxyHelper(
+            ImmutableMap.of(
+                "NO_PROXY",
+                "something.com,example.com,localhost",
+                "HTTPS_PROXY",
+                "https://my.example.com"));
+    Proxy proxy = helper.createProxyIfNeeded(new URL("https://www.my.subdomain.something.com"));
+    assertThat(proxy).isEqualTo(Proxy.NO_PROXY);
+  }
+
+  @Test
   public void testNoProxy() throws Exception {
     // Empty address.
     Proxy proxy = ProxyHelper.createProxy(null);