Allow CustomProxyConfig to apply to non-idempotent methods

It is a property of the Data Reduction Proxy that requests using
non-idempotent methods must never be proxied.  Other CustomProxyConfig
providers should be allowed to assume the proxy handles the
non-idempotent case correctly.

Change-Id: I3b31e3c9567e10ccd746541f2f1d46312356f14a
Reviewed-on: https://chromium-review.googlesource.com/c/1385145
Reviewed-by: Eric Roman <eroman@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Wojciech Dzier┼╝anowski <wdzierzanowski@opera.com>
Cr-Commit-Position: refs/heads/master@{#626033}
diff --git a/services/network/network_service_proxy_delegate.cc b/services/network/network_service_proxy_delegate.cc
index 17f643a..0cc4c39 100644
--- a/services/network/network_service_proxy_delegate.cc
+++ b/services/network/network_service_proxy_delegate.cc
@@ -255,7 +255,9 @@
     const GURL& url,
     const std::string& method) const {
   return proxy_info.is_direct() && proxy_info.proxy_list().size() == 1 &&
-         MayProxyURL(url) && net::HttpUtil::IsMethodIdempotent(method);
+         MayProxyURL(url) &&
+         (proxy_config_->allow_non_idempotent_methods ||
+          net::HttpUtil::IsMethodIdempotent(method));
 }
 
 net::ProxyConfig::ProxyRules NetworkServiceProxyDelegate::GetProxyRulesForURL(
diff --git a/services/network/network_service_proxy_delegate_unittest.cc b/services/network/network_service_proxy_delegate_unittest.cc
index f0397b6..81ba245 100644
--- a/services/network/network_service_proxy_delegate_unittest.cc
+++ b/services/network/network_service_proxy_delegate_unittest.cc
@@ -336,6 +336,24 @@
   EXPECT_FALSE(result.alternative_proxy().is_valid());
 }
 
+TEST_F(NetworkServiceProxyDelegateTest,
+       OnResolveProxyNonIdempotentMethodAllowed) {
+  auto config = mojom::CustomProxyConfig::New();
+  config->rules.ParseFromString("http=foo");
+  config->allow_non_idempotent_methods = true;
+  auto delegate = CreateDelegate(std::move(config));
+
+  net::ProxyInfo result;
+  result.UseDirect();
+  delegate->OnResolveProxy(GURL(kHttpUrl), "POST", net::ProxyRetryInfoMap(),
+                           &result);
+
+  net::ProxyList expected_proxy_list;
+  expected_proxy_list.AddProxyServer(
+      net::ProxyServer::FromPacString("PROXY foo"));
+  EXPECT_TRUE(result.proxy_list().Equals(expected_proxy_list));
+}
+
 TEST_F(NetworkServiceProxyDelegateTest, OnResolveProxyWebsocketScheme) {
   auto config = mojom::CustomProxyConfig::New();
   config->rules.ParseFromString("http=foo");
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index bb94cec..5afbf1c 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -51,6 +51,11 @@
   // ResourceRequest::custom_proxy_use_alternate_proxy_list is set.
   ProxyList alternate_proxy_list;
 
+  // Whether the custom proxy config should apply to requests using
+  // non-idempotent methods. Can be true if the proxy is known to handle this
+  // case properly.
+  bool allow_non_idempotent_methods = false;
+
   // The custom proxy can set these headers in this config which will be added
   // to all requests using the proxy. This allows setting headers that may be
   // privacy/security sensitive which we don't want to send to the renderer.