Expose CONNECT headers to ProxyDelegate

This brings back (slightly refreshed versions of) the
OnBeforeTunnelRequest(), OnTunnelHeadersReceived() hooks that were
removed in
https://chromium-review.googlesource.com/c/chromium/src/+/846261/.

These hooks are not used by the Data Reduction Proxy, because it
doesn't proxy https:// URLs.  They are restored for the benefit of those
downstream embedders (Opera) that use CONNECT tunnels to proxy HTTPS
requests.

Bug: 915659
Change-Id: Id0e120882a22a66c72802087a1775daeef661984
TBR: rockot@google.com
Reviewed-on: https://chromium-review.googlesource.com/c/1379766
Commit-Queue: Wojciech Dzierżanowski <wdzierzanowski@opera.com>
Reviewed-by: Matt Menke <mmenke@chromium.org>
Reviewed-by: Tarun Bansal <tbansal@chromium.org>
Reviewed-by: mark a. foltz <mfoltz@chromium.org>
Reviewed-by: Eric Roman <eroman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#624075}
diff --git a/chrome/browser/extensions/api/socket/tcp_socket_unittest.cc b/chrome/browser/extensions/api/socket/tcp_socket_unittest.cc
index ab214b9..e20bfa4 100644
--- a/chrome/browser/extensions/api/socket/tcp_socket_unittest.cc
+++ b/chrome/browser/extensions/api/socket/tcp_socket_unittest.cc
@@ -522,10 +522,12 @@
       std::unique_ptr<net::ClientSocketHandle> transport_socket,
       const std::string& user_agent,
       const net::HostPortPair& endpoint,
+      const net::ProxyServer& proxy_server,
       net::HttpAuthController* http_auth_controller,
       bool tunnel,
       bool using_spdy,
       net::NextProto negotiated_protocol,
+      net::ProxyDelegate* proxy_delegate,
       bool is_https_proxy,
       const net::NetworkTrafficAnnotationTag& traffic_annotation) override {
     NOTIMPLEMENTED();
diff --git a/components/cast_channel/cast_socket_unittest.cc b/components/cast_channel/cast_socket_unittest.cc
index 0132597..6e6fc7a4 100644
--- a/components/cast_channel/cast_socket_unittest.cc
+++ b/components/cast_channel/cast_socket_unittest.cc
@@ -340,10 +340,12 @@
       std::unique_ptr<net::ClientSocketHandle> transport_socket,
       const std::string& user_agent,
       const net::HostPortPair& endpoint,
+      const net::ProxyServer& proxy_server,
       net::HttpAuthController* http_auth_controller,
       bool tunnel,
       bool using_spdy,
       net::NextProto negotiated_protocol,
+      net::ProxyDelegate* proxy_delegate,
       bool is_https_proxy,
       const net::NetworkTrafficAnnotationTag& traffic_annotation) override {
     NOTIMPLEMENTED();
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
index 761aabf0..5e799f1 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
@@ -153,6 +153,12 @@
     bypass_stats_->OnProxyFallback(bad_proxy, net_error);
 }
 
+net::Error DataReductionProxyDelegate::OnTunnelHeadersReceived(
+    const net::ProxyServer& proxy_server,
+    const net::HttpResponseHeaders& response_headers) {
+  return net::OK;
+}
+
 void DataReductionProxyDelegate::GetAlternativeProxy(
     const GURL& url,
     const net::ProxyRetryInfoMap& proxy_retry_info,
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h
index fae9be5..d759678a 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h
@@ -44,6 +44,11 @@
                       const net::ProxyRetryInfoMap& proxy_retry_info,
                       net::ProxyInfo* result) override;
   void OnFallback(const net::ProxyServer& bad_proxy, int net_error) override;
+  void OnBeforeTunnelRequest(const net::ProxyServer& proxy_server,
+                             net::HttpRequestHeaders* extra_headers) override {}
+  net::Error OnTunnelHeadersReceived(
+      const net::ProxyServer& proxy_server,
+      const net::HttpResponseHeaders& response_headers) override;
 
  protected:
   // Protected so that it can be overridden during testing.
diff --git a/net/base/proxy_delegate.h b/net/base/proxy_delegate.h
index 7a8c419..6731e64a 100644
--- a/net/base/proxy_delegate.h
+++ b/net/base/proxy_delegate.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/macros.h"
+#include "net/base/net_errors.h"
 #include "net/base/net_export.h"
 #include "net/proxy_resolution/proxy_retry_info.h"
 
@@ -15,6 +16,8 @@
 
 namespace net {
 
+class HttpRequestHeaders;
+class HttpResponseHeaders;
 class ProxyInfo;
 class ProxyServer;
 
@@ -44,6 +47,20 @@
   virtual void OnFallback(const ProxyServer& bad_proxy,
                           int net_error) = 0;
 
+  // Called immediately before a proxy tunnel request is sent.
+  // Provides the embedder an opportunity to add extra request headers.
+  virtual void OnBeforeTunnelRequest(const ProxyServer& proxy_server,
+                                     HttpRequestHeaders* extra_headers) = 0;
+
+  // Called when the response headers for the proxy tunnel request have been
+  // received. Allows the delegate to override the net error code of the tunnel
+  // request. Returning OK causes the standard tunnel response handling to be
+  // performed. Implementations should make sure they can trust |proxy_server|
+  // before making decisions based on |response_headers|.
+  virtual Error OnTunnelHeadersReceived(
+      const ProxyServer& proxy_server,
+      const HttpResponseHeaders& response_headers) = 0;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(ProxyDelegate);
 };
diff --git a/net/base/test_proxy_delegate.cc b/net/base/test_proxy_delegate.cc
index 5ac1dbea..407e11f 100644
--- a/net/base/test_proxy_delegate.cc
+++ b/net/base/test_proxy_delegate.cc
@@ -4,6 +4,9 @@
 
 #include "net/base/test_proxy_delegate.h"
 
+#include "net/base/net_errors.h"
+#include "net/http/http_request_headers.h"
+#include "net/http/http_response_headers.h"
 #include "net/proxy_resolution/proxy_info.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -14,6 +17,16 @@
 
 TestProxyDelegate::~TestProxyDelegate() = default;
 
+void TestProxyDelegate::VerifyOnTunnelHeadersReceived(
+    const ProxyServer& proxy_server,
+    const std::string& response_header_name,
+    const std::string& response_header_value) const {
+  EXPECT_EQ(proxy_server, on_tunnel_headers_received_proxy_server_);
+  ASSERT_NE(on_tunnel_headers_received_headers_.get(), nullptr);
+  EXPECT_TRUE(on_tunnel_headers_received_headers_->HasHeaderValue(
+      response_header_name, response_header_value));
+}
+
 void TestProxyDelegate::OnResolveProxy(
     const GURL& url,
     const std::string& method,
@@ -48,4 +61,23 @@
 void TestProxyDelegate::OnFallback(const ProxyServer& bad_proxy,
                                    int net_error) {}
 
+void TestProxyDelegate::OnBeforeTunnelRequest(
+    const ProxyServer& proxy_server,
+    HttpRequestHeaders* extra_headers) {
+  on_before_tunnel_request_called_ = true;
+  if (extra_headers)
+    extra_headers->SetHeader("Foo", proxy_server.ToURI());
+}
+
+Error TestProxyDelegate::OnTunnelHeadersReceived(
+    const ProxyServer& proxy_server,
+    const HttpResponseHeaders& response_headers) {
+  EXPECT_EQ(on_tunnel_headers_received_headers_.get(), nullptr);
+  on_tunnel_headers_received_headers_ =
+      base::MakeRefCounted<HttpResponseHeaders>(response_headers.raw_headers());
+
+  on_tunnel_headers_received_proxy_server_ = proxy_server;
+  return OK;
+}
+
 }  // namespace net
diff --git a/net/base/test_proxy_delegate.h b/net/base/test_proxy_delegate.h
index fae7feb..e966994 100644
--- a/net/base/test_proxy_delegate.h
+++ b/net/base/test_proxy_delegate.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/memory/ref_counted.h"
 #include "net/base/proxy_delegate.h"
 #include "net/base/proxy_server.h"
 
@@ -21,16 +22,30 @@
   TestProxyDelegate();
   ~TestProxyDelegate() override;
 
+  bool on_before_tunnel_request_called() const {
+    return on_before_tunnel_request_called_;
+  }
+
   void set_trusted_spdy_proxy(const ProxyServer& proxy_server) {
     trusted_spdy_proxy_ = proxy_server;
   }
 
+  void VerifyOnTunnelHeadersReceived(
+      const ProxyServer& proxy_server,
+      const std::string& response_header_name,
+      const std::string& response_header_value) const;
+
   // ProxyDelegate implementation:
   void OnResolveProxy(const GURL& url,
                       const std::string& method,
                       const ProxyRetryInfoMap& proxy_retry_info,
                       ProxyInfo* result) override;
   void OnFallback(const ProxyServer& bad_proxy, int net_error) override;
+  void OnBeforeTunnelRequest(const ProxyServer& proxy_server,
+                             HttpRequestHeaders* extra_headers) override;
+  Error OnTunnelHeadersReceived(
+      const ProxyServer& proxy_server,
+      const HttpResponseHeaders& response_headers) override;
 
   void set_alternative_proxy_server(
       const ProxyServer& alternative_proxy_server) {
@@ -41,6 +56,9 @@
   }
 
  private:
+  bool on_before_tunnel_request_called_ = false;
+  ProxyServer on_tunnel_headers_received_proxy_server_;
+  scoped_refptr<HttpResponseHeaders> on_tunnel_headers_received_headers_;
   ProxyServer trusted_spdy_proxy_;
   ProxyServer alternative_proxy_server_;
 };
diff --git a/net/dns/address_sorter_posix_unittest.cc b/net/dns/address_sorter_posix_unittest.cc
index bdf2f0c..b16213c 100644
--- a/net/dns/address_sorter_posix_unittest.cc
+++ b/net/dns/address_sorter_posix_unittest.cc
@@ -170,10 +170,12 @@
       std::unique_ptr<ClientSocketHandle> transport_socket,
       const std::string& user_agent,
       const HostPortPair& endpoint,
+      const ProxyServer& proxy_server,
       HttpAuthController* http_auth_controller,
       bool tunnel,
       bool using_spdy,
       NextProto negotiated_protocol,
+      ProxyDelegate* proxy_delegate,
       bool is_https_proxy,
       const NetworkTrafficAnnotationTag& traffic_annotation) override {
     NOTIMPLEMENTED();
diff --git a/net/dns/dns_session_unittest.cc b/net/dns/dns_session_unittest.cc
index 1e75390..9c3e4646 100644
--- a/net/dns/dns_session_unittest.cc
+++ b/net/dns/dns_session_unittest.cc
@@ -57,10 +57,12 @@
       std::unique_ptr<ClientSocketHandle> transport_socket,
       const std::string& user_agent,
       const HostPortPair& endpoint,
+      const ProxyServer& proxy_server,
       HttpAuthController* http_auth_controller,
       bool tunnel,
       bool using_spdy,
       NextProto negotiated_protocol,
+      ProxyDelegate* proxy_delegate,
       bool is_https_proxy,
       const NetworkTrafficAnnotationTag& traffic_annotation) override {
     NOTIMPLEMENTED();
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index 8ca3e33..b71a6eb 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -59,7 +59,8 @@
       context.cert_verifier, context.channel_id_service,
       context.transport_security_state, context.cert_transparency_verifier,
       context.ct_policy_enforcer, ssl_session_cache_shard,
-      context.ssl_config_service, websocket_endpoint_lock_manager, pool_type);
+      context.ssl_config_service, websocket_endpoint_lock_manager,
+      context.proxy_delegate, pool_type);
 }
 
 }  // unnamed namespace
@@ -160,6 +161,7 @@
       cert_transparency_verifier(nullptr),
       ct_policy_enforcer(nullptr),
       proxy_resolution_service(nullptr),
+      proxy_delegate(nullptr),
       ssl_config_service(nullptr),
       http_auth_handler_factory(nullptr),
       net_log(nullptr),
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index 3fe77b2..6833a7b4 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -67,6 +67,7 @@
 class NetworkErrorLoggingService;
 #endif
 class NetworkQualityEstimator;
+class ProxyDelegate;
 class ProxyResolutionService;
 class ProxyServer;
 class QuicCryptoClientStreamFactory;
@@ -252,6 +253,7 @@
     CTVerifier* cert_transparency_verifier;
     CTPolicyEnforcer* ct_policy_enforcer;
     ProxyResolutionService* proxy_resolution_service;
+    ProxyDelegate* proxy_delegate;
     SSLConfigService* ssl_config_service;
     HttpAuthHandlerFactory* http_auth_handler_factory;
     HttpServerProperties* http_server_properties;
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 1fc70b8a..f0403a9 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -698,7 +698,7 @@
 CaptureGroupNameHttpProxySocketPool::CaptureGroupNameSocketPool(
     HostResolver* /* host_resolver */,
     CertVerifier* /* cert_verifier */)
-    : HttpProxyClientSocketPool(0, 0, NULL, NULL, NULL, NULL) {}
+    : HttpProxyClientSocketPool(0, 0, NULL, NULL, NULL, NULL, NULL) {}
 
 template <>
 CaptureGroupNameSSLSocketPool::CaptureGroupNameSocketPool(
diff --git a/net/http/http_proxy_client_socket.cc b/net/http/http_proxy_client_socket.cc
index e55a99d..12cfb3d 100644
--- a/net/http/http_proxy_client_socket.cc
+++ b/net/http/http_proxy_client_socket.cc
@@ -14,6 +14,7 @@
 #include "net/base/auth.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/io_buffer.h"
+#include "net/base/proxy_delegate.h"
 #include "net/http/http_basic_stream.h"
 #include "net/http/http_network_session.h"
 #include "net/http/http_request_info.h"
@@ -33,10 +34,12 @@
     std::unique_ptr<ClientSocketHandle> transport_socket,
     const std::string& user_agent,
     const HostPortPair& endpoint,
+    const ProxyServer& proxy_server,
     HttpAuthController* http_auth_controller,
     bool tunnel,
     bool using_spdy,
     NextProto negotiated_protocol,
+    ProxyDelegate* proxy_delegate,
     bool is_https_proxy,
     const NetworkTrafficAnnotationTag& traffic_annotation)
     : io_callback_(base::BindRepeating(&HttpProxyClientSocket::OnIOComplete,
@@ -50,6 +53,8 @@
       negotiated_protocol_(negotiated_protocol),
       is_https_proxy_(is_https_proxy),
       redirect_has_load_timing_info_(false),
+      proxy_server_(proxy_server),
+      proxy_delegate_(proxy_delegate),
       traffic_annotation_(traffic_annotation),
       net_log_(transport_->socket()->NetLog()) {
   // Synthesize the bits of a request that we actually use.
@@ -382,16 +387,25 @@
   // we have proxy info available.
   if (request_line_.empty()) {
     DCHECK(request_headers_.IsEmpty());
-    HttpRequestHeaders authorization_headers;
+
+    HttpRequestHeaders extra_headers;
     if (auth_->HaveAuth())
-      auth_->AddAuthorizationHeader(&authorization_headers);
+      auth_->AddAuthorizationHeader(&extra_headers);
+
+    if (proxy_delegate_) {
+      HttpRequestHeaders proxy_delegate_headers;
+      proxy_delegate_->OnBeforeTunnelRequest(proxy_server_,
+                                             &proxy_delegate_headers);
+      extra_headers.MergeFrom(proxy_delegate_headers);
+    }
+
     std::string user_agent;
     if (!request_.extra_headers.GetHeader(HttpRequestHeaders::kUserAgent,
                                           &user_agent)) {
       user_agent.clear();
     }
-    BuildTunnelRequest(endpoint_, authorization_headers, user_agent,
-                       &request_line_, &request_headers_);
+    BuildTunnelRequest(endpoint_, extra_headers, user_agent, &request_line_,
+                       &request_headers_);
 
     net_log_.AddEvent(
         NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
@@ -432,6 +446,15 @@
       NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
       base::Bind(&HttpResponseHeaders::NetLogCallback, response_.headers));
 
+  if (proxy_delegate_) {
+    int rv = proxy_delegate_->OnTunnelHeadersReceived(proxy_server_,
+                                                      *response_.headers);
+    if (rv != OK) {
+      DCHECK_NE(ERR_IO_PENDING, rv);
+      return rv;
+    }
+  }
+
   switch (response_.headers->response_code()) {
     case 200:  // OK
       if (http_stream_parser_->IsMoreDataBuffered())
diff --git a/net/http/http_proxy_client_socket.h b/net/http/http_proxy_client_socket.h
index 38c65bf8..45a4130 100644
--- a/net/http/http_proxy_client_socket.h
+++ b/net/http/http_proxy_client_socket.h
@@ -18,6 +18,7 @@
 #include "net/base/host_port_pair.h"
 #include "net/base/load_timing_info.h"
 #include "net/base/net_export.h"
+#include "net/base/proxy_server.h"
 #include "net/http/http_auth_controller.h"
 #include "net/http/http_request_headers.h"
 #include "net/http/http_request_info.h"
@@ -34,6 +35,7 @@
 class HttpStream;
 class HttpStreamParser;
 class IOBuffer;
+class ProxyDelegate;
 
 class NET_EXPORT_PRIVATE HttpProxyClientSocket : public ProxyClientSocket {
  public:
@@ -43,10 +45,12 @@
   HttpProxyClientSocket(std::unique_ptr<ClientSocketHandle> transport_socket,
                         const std::string& user_agent,
                         const HostPortPair& endpoint,
+                        const ProxyServer& proxy_server,
                         HttpAuthController* http_auth_controller,
                         bool tunnel,
                         bool using_spdy,
                         NextProto negotiated_protocol,
+                        ProxyDelegate* proxy_delegate,
                         bool is_https_proxy,
                         const NetworkTrafficAnnotationTag& traffic_annotation);
 
@@ -167,6 +171,11 @@
   bool redirect_has_load_timing_info_;
   LoadTimingInfo redirect_load_timing_info_;
 
+  const ProxyServer proxy_server_;
+
+  // This delegate must outlive this proxy client socket.
+  ProxyDelegate* proxy_delegate_;
+
   // Network traffic annotation for handshaking and setup.
   const NetworkTrafficAnnotationTag traffic_annotation_;
 
diff --git a/net/http/http_proxy_client_socket_fuzzer.cc b/net/http/http_proxy_client_socket_fuzzer.cc
index e74ef30..af12e96 100644
--- a/net/http/http_proxy_client_socket_fuzzer.cc
+++ b/net/http/http_proxy_client_socket_fuzzer.cc
@@ -66,8 +66,11 @@
   bool is_https_proxy = data_provider.ConsumeBool();
   net::HttpProxyClientSocket socket(
       std::move(socket_handle), "Bond/007", net::HostPortPair("foo", 80),
+      net::ProxyServer(net::ProxyServer::SCHEME_HTTP,
+                       net::HostPortPair("proxy", 42)),
       auth_controller.get(), true /* tunnel */, false /* using_spdy */,
-      net::kProtoUnknown, is_https_proxy, TRAFFIC_ANNOTATION_FOR_TESTS);
+      net::kProtoUnknown, nullptr /* proxy_delegate */, is_https_proxy,
+      TRAFFIC_ANNOTATION_FOR_TESTS);
   int result = socket.Connect(callback.callback());
   result = callback.GetResult(result);
 
diff --git a/net/http/http_proxy_client_socket_pool.cc b/net/http/http_proxy_client_socket_pool.cc
index d10c8d1..21ace98a 100644
--- a/net/http/http_proxy_client_socket_pool.cc
+++ b/net/http/http_proxy_client_socket_pool.cc
@@ -173,6 +173,7 @@
     const SocketTag& socket_tag,
     ClientSocketPool::RespectLimits respect_limits,
     const scoped_refptr<HttpProxySocketParams>& params,
+    ProxyDelegate* proxy_delegate,
     TransportClientSocketPool* transport_pool,
     SSLClientSocketPool* ssl_pool,
     NetworkQualityEstimator* network_quality_estimator,
@@ -207,6 +208,7 @@
           params->quic_stream_factory(),
           params->is_trusted_proxy(),
           params->tunnel(),
+          proxy_delegate,
           params->traffic_annotation(),
           this->net_log())) {}
 
@@ -301,10 +303,12 @@
     HttpProxyConnectJobFactory(
         TransportClientSocketPool* transport_pool,
         SSLClientSocketPool* ssl_pool,
+        ProxyDelegate* proxy_delegate,
         NetworkQualityEstimator* network_quality_estimator,
         NetLog* net_log)
     : transport_pool_(transport_pool),
       ssl_pool_(ssl_pool),
+      proxy_delegate_(proxy_delegate),
       network_quality_estimator_(network_quality_estimator),
       net_log_(net_log) {}
 
@@ -315,8 +319,9 @@
     ConnectJob::Delegate* delegate) const {
   return std::make_unique<HttpProxyConnectJob>(
       group_name, request.priority(), request.socket_tag(),
-      request.respect_limits(), request.params(), transport_pool_, ssl_pool_,
-      network_quality_estimator_, delegate, net_log_);
+      request.respect_limits(), request.params(), proxy_delegate_,
+      transport_pool_, ssl_pool_, network_quality_estimator_, delegate,
+      net_log_);
 }
 
 HttpProxyClientSocketPool::HttpProxyClientSocketPool(
@@ -324,6 +329,7 @@
     int max_sockets_per_group,
     TransportClientSocketPool* transport_pool,
     SSLClientSocketPool* ssl_pool,
+    ProxyDelegate* proxy_delegate,
     NetworkQualityEstimator* network_quality_estimator,
     NetLog* net_log)
     : transport_pool_(transport_pool),
@@ -335,6 +341,7 @@
             ClientSocketPool::used_idle_socket_timeout(),
             new HttpProxyConnectJobFactory(transport_pool,
                                            ssl_pool,
+                                           proxy_delegate,
                                            network_quality_estimator,
                                            net_log)) {
   // We should always have a |transport_pool_| except in unit tests.
diff --git a/net/http/http_proxy_client_socket_pool.h b/net/http/http_proxy_client_socket_pool.h
index 69e1f4d..a869631 100644
--- a/net/http/http_proxy_client_socket_pool.h
+++ b/net/http/http_proxy_client_socket_pool.h
@@ -33,6 +33,7 @@
 class HttpProxyClientSocketWrapper;
 class NetLog;
 class NetworkQualityEstimator;
+class ProxyDelegate;
 class QuicStreamFactory;
 class SSLClientSocketPool;
 class SSLSocketParams;
@@ -116,6 +117,7 @@
                       const SocketTag& socket_tag,
                       ClientSocketPool::RespectLimits respect_limits,
                       const scoped_refptr<HttpProxySocketParams>& params,
+                      ProxyDelegate* proxy_delegate,
                       TransportClientSocketPool* transport_pool,
                       SSLClientSocketPool* ssl_pool,
                       NetworkQualityEstimator* network_quality_estimator,
@@ -170,6 +172,7 @@
                             int max_sockets_per_group,
                             TransportClientSocketPool* transport_pool,
                             SSLClientSocketPool* ssl_pool,
+                            ProxyDelegate* proxy_delegate,
                             NetworkQualityEstimator* network_quality_estimator,
                             NetLog* net_log);
 
@@ -241,6 +244,7 @@
     HttpProxyConnectJobFactory(
         TransportClientSocketPool* transport_pool,
         SSLClientSocketPool* ssl_pool,
+        ProxyDelegate* proxy_delegate,
         NetworkQualityEstimator* network_quality_estimator,
         NetLog* net_log);
 
@@ -256,6 +260,7 @@
 
     TransportClientSocketPool* const transport_pool_;
     SSLClientSocketPool* const ssl_pool_;
+    ProxyDelegate* const proxy_delegate_;
     NetworkQualityEstimator* const network_quality_estimator_;
 
     NetLog* net_log_;
diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc
index 10f8be28..c333199 100644
--- a/net/http/http_proxy_client_socket_pool_unittest.cc
+++ b/net/http/http_proxy_client_socket_pool_unittest.cc
@@ -21,6 +21,7 @@
 #include "build/build_config.h"
 #include "net/base/net_errors.h"
 #include "net/base/test_completion_callback.h"
+#include "net/base/test_proxy_delegate.h"
 #include "net/http/http_network_session.h"
 #include "net/http/http_proxy_client_socket.h"
 #include "net/http/http_response_headers.h"
@@ -93,6 +94,7 @@
                                                         kMaxSocketsPerGroup,
                                                         &transport_socket_pool_,
                                                         &ssl_socket_pool_,
+                                                        nullptr,
                                                         &estimator_,
                                                         nullptr)) {
     session_ = CreateNetworkSession();
@@ -135,6 +137,12 @@
     HttpProxyConnectJob::UpdateFieldTrialParametersForTesting();
   }
 
+  void InitPoolWithProxyDelegate(ProxyDelegate* proxy_delegate) {
+    pool_ = std::make_unique<HttpProxyClientSocketPool>(
+        kMaxSockets, kMaxSocketsPerGroup, &transport_socket_pool_,
+        &ssl_socket_pool_, proxy_delegate, &estimator_, nullptr);
+  }
+
   void AddAuthToCache() {
     const base::string16 kFoo(base::ASCIIToUTF16("foo"));
     const base::string16 kBar(base::ASCIIToUTF16("bar"));
@@ -274,6 +282,9 @@
                         ::testing::Values(HTTP, HTTPS, SPDY));
 
 TEST_P(HttpProxyClientSocketPoolTest, NoTunnel) {
+  TestProxyDelegate proxy_delegate;
+  InitPoolWithProxyDelegate(&proxy_delegate);
+
   Initialize(base::span<MockRead>(), base::span<MockWrite>(),
              base::span<MockRead>(), base::span<MockWrite>());
 
@@ -285,6 +296,7 @@
   EXPECT_TRUE(handle_.is_initialized());
   ASSERT_TRUE(handle_.socket());
   EXPECT_TRUE(handle_.socket()->IsConnected());
+  EXPECT_FALSE(proxy_delegate.on_before_tunnel_request_called());
 
   bool is_secure_proxy = GetParam() == HTTPS || GetParam() == SPDY;
   histogram_tester().ExpectTotalCount(
@@ -293,6 +305,49 @@
       "Net.HttpProxy.ConnectLatency.Secure.Success", is_secure_proxy ? 1 : 0);
 }
 
+TEST_P(HttpProxyClientSocketPoolTest, ProxyDelegateExtraHeaders) {
+  // It's pretty much impossible to make the SPDY case behave synchronously
+  // so we skip this test for SPDY.
+  if (GetParam() == SPDY)
+    return;
+
+  TestProxyDelegate proxy_delegate;
+  InitPoolWithProxyDelegate(&proxy_delegate);
+
+  const ProxyServer proxy_server(
+      GetParam() == HTTP ? ProxyServer::SCHEME_HTTP : ProxyServer::SCHEME_HTTPS,
+      HostPortPair(GetParam() == HTTP ? kHttpProxyHost : kHttpsProxyHost,
+                   GetParam() == HTTP ? 80 : 443));
+  const std::string request =
+      "CONNECT www.google.com:443 HTTP/1.1\r\n"
+      "Host: www.google.com:443\r\n"
+      "Proxy-Connection: keep-alive\r\n"
+      "Foo: " +
+      proxy_server.ToURI() + "\r\n\r\n";
+  MockWrite writes[] = {
+      MockWrite(SYNCHRONOUS, 0, request.c_str()),
+  };
+
+  const std::string response_header_name = "Foo";
+  const std::string response_header_value = "Response";
+  const std::string response = "HTTP/1.1 200 Connection Established\r\n" +
+                               response_header_name + ": " +
+                               response_header_value + "\r\n\r\n";
+  MockRead reads[] = {
+      MockRead(SYNCHRONOUS, 1, response.c_str()),
+  };
+
+  Initialize(reads, writes, base::span<MockRead>(), base::span<MockWrite>());
+
+  int rv = handle_.Init("a", CreateTunnelParams(), LOW, SocketTag(),
+                        ClientSocketPool::RespectLimits::ENABLED,
+                        callback_.callback(), pool_.get(), NetLogWithSource());
+  EXPECT_THAT(rv, IsOk());
+
+  proxy_delegate.VerifyOnTunnelHeadersReceived(
+      proxy_server, response_header_name, response_header_value);
+}
+
 // Make sure that HttpProxyConnectJob passes on its priority to its
 // (non-SSL) socket request on Init.
 TEST_P(HttpProxyClientSocketPoolTest, SetSocketRequestPriorityOnInit) {
@@ -384,13 +439,12 @@
   // so we skip this test for SPDY
   if (GetParam() == SPDY)
     return;
-  std::string request =
-      "CONNECT www.google.com:443 HTTP/1.1\r\n"
-      "Host: www.google.com:443\r\n"
-      "Proxy-Connection: keep-alive\r\n"
-      "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n";
   MockWrite writes[] = {
-    MockWrite(SYNCHRONOUS, 0, request.c_str()),
+      MockWrite(SYNCHRONOUS, 0,
+                "CONNECT www.google.com:443 HTTP/1.1\r\n"
+                "Host: www.google.com:443\r\n"
+                "Proxy-Connection: keep-alive\r\n"
+                "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
   };
   MockRead reads[] = {
     MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Connection Established\r\n\r\n"),
@@ -409,13 +463,12 @@
 }
 
 TEST_P(HttpProxyClientSocketPoolTest, AsyncHaveAuth) {
-  std::string request =
-      "CONNECT www.google.com:443 HTTP/1.1\r\n"
-      "Host: www.google.com:443\r\n"
-      "Proxy-Connection: keep-alive\r\n"
-      "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n";
   MockWrite writes[] = {
-    MockWrite(ASYNC, 0, request.c_str()),
+      MockWrite(ASYNC, 0,
+                "CONNECT www.google.com:443 HTTP/1.1\r\n"
+                "Host: www.google.com:443\r\n"
+                "Proxy-Connection: keep-alive\r\n"
+                "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
   };
   MockRead reads[] = {
     MockRead(ASYNC, 1, "HTTP/1.1 200 Connection Established\r\n\r\n"),
@@ -867,7 +920,8 @@
       false, kSecureMultiplier, kNonSecureMultiplier, kMinTimeout, kMaxTimeout);
 
   HttpProxyClientSocketPool::HttpProxyConnectJobFactory job_factory(
-      transport_socket_pool(), ssl_socket_pool(), estimator(), nullptr);
+      transport_socket_pool(), ssl_socket_pool(), nullptr, estimator(),
+      nullptr);
 
   const base::TimeDelta kRttEstimate = base::TimeDelta::FromSeconds(2);
   estimator()->SetStartTimeNullHttpRtt(kRttEstimate);
diff --git a/net/http/http_proxy_client_socket_unittest.cc b/net/http/http_proxy_client_socket_unittest.cc
index 6b97067..d4d11b99 100644
--- a/net/http/http_proxy_client_socket_unittest.cc
+++ b/net/http/http_proxy_client_socket_unittest.cc
@@ -7,6 +7,7 @@
 #include "build/build_config.h"
 #include "net/base/address_list.h"
 #include "net/base/host_port_pair.h"
+#include "net/base/proxy_server.h"
 #include "net/log/test_net_log.h"
 #include "net/socket/next_proto.h"
 #include "net/socket/socket_tag.h"
@@ -29,9 +30,9 @@
   // |connection| takes ownership of |tagging_sock|, but keep a
   // non-owning pointer to it.
   connection->SetSocket(std::unique_ptr<StreamSocket>(tagging_sock));
-  HttpProxyClientSocket socket(std::move(connection), "", HostPortPair(),
-                               nullptr, false, false, NextProto(), false,
-                               TRAFFIC_ANNOTATION_FOR_TESTS);
+  HttpProxyClientSocket socket(
+      std::move(connection), "", HostPortPair(), ProxyServer(), nullptr, false,
+      false, NextProto(), nullptr, false, TRAFFIC_ANNOTATION_FOR_TESTS);
 
   EXPECT_EQ(tagging_sock->tag(), SocketTag());
 #if defined(OS_ANDROID)
diff --git a/net/http/http_proxy_client_socket_wrapper.cc b/net/http/http_proxy_client_socket_wrapper.cc
index fcfb57b..dcc9c6a 100644
--- a/net/http/http_proxy_client_socket_wrapper.cc
+++ b/net/http/http_proxy_client_socket_wrapper.cc
@@ -12,6 +12,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/values.h"
+#include "net/base/proxy_delegate.h"
 #include "net/http/http_proxy_client_socket.h"
 #include "net/http/http_response_info.h"
 #include "net/log/net_log_event_type.h"
@@ -54,6 +55,7 @@
     QuicStreamFactory* quic_stream_factory,
     bool is_trusted_proxy,
     bool tunnel,
+    ProxyDelegate* proxy_delegate,
     const NetworkTrafficAnnotationTag& traffic_annotation,
     const NetLogWithSource& net_log)
     : next_state_(STATE_NONE),
@@ -73,6 +75,7 @@
       spdy_session_pool_(spdy_session_pool),
       has_restarted_(false),
       tunnel_(tunnel),
+      proxy_delegate_(proxy_delegate),
       using_spdy_(false),
       is_trusted_proxy_(is_trusted_proxy),
       quic_stream_factory_(quic_stream_factory),
@@ -394,6 +397,16 @@
   return ERR_SOCKET_NOT_CONNECTED;
 }
 
+ProxyServer::Scheme HttpProxyClientSocketWrapper::GetProxyServerScheme() const {
+  if (quic_version_ != quic::QUIC_VERSION_UNSUPPORTED)
+    return ProxyServer::SCHEME_QUIC;
+
+  if (transport_params_)
+    return ProxyServer::SCHEME_HTTP;
+
+  return ProxyServer::SCHEME_HTTPS;
+}
+
 void HttpProxyClientSocketWrapper::OnIOComplete(int result) {
   int rv = DoLoop(result);
   if (rv != ERR_IO_PENDING) {
@@ -473,12 +486,18 @@
 int HttpProxyClientSocketWrapper::DoBeginConnect() {
   connect_start_time_ = base::TimeTicks::Now();
   SetConnectTimer(connect_timeout_duration_);
-  if (quic_version_ != quic::QUIC_VERSION_UNSUPPORTED) {
-    next_state_ = STATE_QUIC_PROXY_CREATE_SESSION;
-  } else if (transport_params_) {
-    next_state_ = STATE_TCP_CONNECT;
-  } else {
-    next_state_ = STATE_SSL_CONNECT;
+  switch (GetProxyServerScheme()) {
+    case ProxyServer::SCHEME_QUIC:
+      next_state_ = STATE_QUIC_PROXY_CREATE_SESSION;
+      break;
+    case ProxyServer::SCHEME_HTTP:
+      next_state_ = STATE_TCP_CONNECT;
+      break;
+    case ProxyServer::SCHEME_HTTPS:
+      next_state_ = STATE_SSL_CONNECT;
+      break;
+    default:
+      NOTREACHED();
   }
   return OK;
 }
@@ -617,8 +636,10 @@
   transport_socket_ =
       transport_pool_->client_socket_factory()->CreateProxyClientSocket(
           std::move(transport_socket_handle_), user_agent_, endpoint_,
+          ProxyServer(GetProxyServerScheme(),
+                      GetDestination().host_port_pair()),
           http_auth_controller_.get(), tunnel_, using_spdy_,
-          negotiated_protocol_, ssl_params_.get() != nullptr,
+          negotiated_protocol_, proxy_delegate_, ssl_params_.get() != nullptr,
           traffic_annotation_);
   return transport_socket_->Connect(base::Bind(
       &HttpProxyClientSocketWrapper::OnIOComplete, base::Unretained(this)));
diff --git a/net/http/http_proxy_client_socket_wrapper.h b/net/http/http_proxy_client_socket_wrapper.h
index 8b49097d..a28efa3 100644
--- a/net/http/http_proxy_client_socket_wrapper.h
+++ b/net/http/http_proxy_client_socket_wrapper.h
@@ -18,6 +18,7 @@
 #include "net/base/completion_once_callback.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/load_timing_info.h"
+#include "net/base/proxy_server.h"
 #include "net/http/http_auth_controller.h"
 #include "net/http/proxy_client_socket.h"
 #include "net/log/net_log_with_source.h"
@@ -36,6 +37,7 @@
 class HttpResponseInfo;
 class HttpStream;
 class IOBuffer;
+class ProxyDelegate;
 class SpdySessionPool;
 class SSLClientSocketPool;
 class TransportClientSocketPool;
@@ -75,6 +77,7 @@
       QuicStreamFactory* quic_stream_factory,
       bool is_trusted_proxy,
       bool tunnel,
+      ProxyDelegate* proxy_delegate,
       const NetworkTrafficAnnotationTag& traffic_annotation,
       const NetLogWithSource& net_log);
 
@@ -151,6 +154,8 @@
     STATE_NONE,
   };
 
+  ProxyServer::Scheme GetProxyServerScheme() const;
+
   void OnIOComplete(int result);
 
   // Runs the state transition loop.
@@ -205,6 +210,7 @@
 
   bool has_restarted_;
   const bool tunnel_;
+  ProxyDelegate* const proxy_delegate_;
 
   bool using_spdy_;
   bool is_trusted_proxy_;
diff --git a/net/http/http_proxy_client_socket_wrapper_unittest.cc b/net/http/http_proxy_client_socket_wrapper_unittest.cc
index 5d256d7..40f235c 100644
--- a/net/http/http_proxy_client_socket_wrapper_unittest.cc
+++ b/net/http/http_proxy_client_socket_wrapper_unittest.cc
@@ -293,8 +293,8 @@
       /*transport_params=*/nullptr, ssl_params, quic_version_, kUserAgent,
       endpoint_host_port_, &http_auth_cache_, http_auth_handler_factory_.get(),
       /*spdy_session_pool=*/nullptr, quic_stream_factory_.get(),
-      /*is_trusted_proxy=*/false, /*tunnel=*/true, TRAFFIC_ANNOTATION_FOR_TESTS,
-      net_log_));
+      /*is_trusted_proxy=*/false, /*tunnel=*/true, /*proxy_delegate=*/nullptr,
+      TRAFFIC_ANNOTATION_FOR_TESTS, net_log_));
 
   TestCompletionCallback callback;
   client_socket_wrapper_->Connect(callback.callback());
@@ -351,8 +351,8 @@
       /*transport_params=*/nullptr, ssl_params, quic_version_, kUserAgent,
       endpoint_host_port_, &http_auth_cache_, http_auth_handler_factory_.get(),
       /*spdy_session_pool=*/nullptr, quic_stream_factory_.get(),
-      /*is_trusted_proxy=*/false, /*tunnel=*/true, TRAFFIC_ANNOTATION_FOR_TESTS,
-      net_log_));
+      /*is_trusted_proxy=*/false, /*tunnel=*/true, /*proxy_delegate=*/nullptr,
+      TRAFFIC_ANNOTATION_FOR_TESTS, net_log_));
 
   TestCompletionCallback callback;
   client_socket_wrapper_->Connect(callback.callback());
diff --git a/net/http/http_stream_factory_unittest.cc b/net/http/http_stream_factory_unittest.cc
index 5faf10b..3d68939 100644
--- a/net/http/http_stream_factory_unittest.cc
+++ b/net/http/http_stream_factory_unittest.cc
@@ -462,7 +462,13 @@
     TransportSecurityState*,
     CTVerifier*,
     CTPolicyEnforcer*)
-    : HttpProxyClientSocketPool(0, 0, nullptr, nullptr, nullptr, nullptr),
+    : HttpProxyClientSocketPool(0,
+                                0,
+                                nullptr,
+                                nullptr,
+                                nullptr,
+                                nullptr,
+                                nullptr),
       last_num_streams_(-1) {}
 
 template <>
diff --git a/net/http/proxy_client_socket.cc b/net/http/proxy_client_socket.cc
index e646fe1e..6dde1d5 100644
--- a/net/http/proxy_client_socket.cc
+++ b/net/http/proxy_client_socket.cc
@@ -24,7 +24,7 @@
 // static
 void ProxyClientSocket::BuildTunnelRequest(
     const HostPortPair& endpoint,
-    const HttpRequestHeaders& auth_headers,
+    const HttpRequestHeaders& extra_headers,
     const std::string& user_agent,
     std::string* request_line,
     HttpRequestHeaders* request_headers) {
@@ -41,7 +41,7 @@
   if (!user_agent.empty())
     request_headers->SetHeader(HttpRequestHeaders::kUserAgent, user_agent);
 
-  request_headers->MergeFrom(auth_headers);
+  request_headers->MergeFrom(extra_headers);
 }
 
 // static
diff --git a/net/http/proxy_client_socket.h b/net/http/proxy_client_socket.h
index 639ac30..1d3f2a8 100644
--- a/net/http/proxy_client_socket.h
+++ b/net/http/proxy_client_socket.h
@@ -67,7 +67,7 @@
   // in draft-luotonen-web-proxy-tunneling-01.txt and RFC 2817, Sections 5.2
   // and 5.3.
   static void BuildTunnelRequest(const HostPortPair& endpoint,
-                                 const HttpRequestHeaders& auth_headers,
+                                 const HttpRequestHeaders& extra_headers,
                                  const std::string& user_agent,
                                  std::string* request_line,
                                  HttpRequestHeaders* request_headers);
diff --git a/net/proxy_resolution/pac_library_unittest.cc b/net/proxy_resolution/pac_library_unittest.cc
index 87c12c0..67642c02 100644
--- a/net/proxy_resolution/pac_library_unittest.cc
+++ b/net/proxy_resolution/pac_library_unittest.cc
@@ -265,10 +265,12 @@
       std::unique_ptr<ClientSocketHandle> transport_socket,
       const std::string& user_agent,
       const HostPortPair& endpoint,
+      const ProxyServer& proxy_server,
       HttpAuthController* http_auth_controller,
       bool tunnel,
       bool using_spdy,
       NextProto negotiated_protocol,
+      ProxyDelegate* proxy_delegate,
       bool is_https_proxy,
       const NetworkTrafficAnnotationTag& traffic_annotation) override {
     ADD_FAILURE() << "Called CreateProxyClientSocket()";
diff --git a/net/proxy_resolution/proxy_resolution_service_unittest.cc b/net/proxy_resolution/proxy_resolution_service_unittest.cc
index 8bf71e4..439477f 100644
--- a/net/proxy_resolution/proxy_resolution_service_unittest.cc
+++ b/net/proxy_resolution/proxy_resolution_service_unittest.cc
@@ -220,6 +220,15 @@
 
   void OnFallback(const ProxyServer& bad_proxy, int net_error) override {}
 
+  void OnBeforeTunnelRequest(const ProxyServer& proxy_server,
+                             HttpRequestHeaders* extra_headers) override {}
+
+  Error OnTunnelHeadersReceived(
+      const ProxyServer& proxy_server,
+      const HttpResponseHeaders& response_headers) override {
+    return OK;
+  }
+
  private:
   int num_resolve_proxy_called_ = 0;
   bool add_proxy_ = false;
@@ -236,12 +245,22 @@
                       const std::string& method,
                       const ProxyRetryInfoMap& proxy_retry_info,
                       ProxyInfo* result) override {}
+
   void OnFallback(const ProxyServer& bad_proxy, int net_error) override {
     proxy_server_ = bad_proxy;
     last_proxy_fallback_net_error_ = net_error;
     num_proxy_fallback_called_++;
   }
 
+  void OnBeforeTunnelRequest(const ProxyServer& proxy_server,
+                             HttpRequestHeaders* extra_headers) override {}
+
+  Error OnTunnelHeadersReceived(
+      const ProxyServer& proxy_server,
+      const HttpResponseHeaders& response_headers) override {
+    return OK;
+  }
+
   bool num_proxy_fallback_called() const { return num_proxy_fallback_called_; }
 
   const ProxyServer& proxy_server() const {
diff --git a/net/socket/client_socket_factory.cc b/net/socket/client_socket_factory.cc
index 2ddce22..de98df3 100644
--- a/net/socket/client_socket_factory.cc
+++ b/net/socket/client_socket_factory.cc
@@ -69,16 +69,18 @@
       std::unique_ptr<ClientSocketHandle> transport_socket,
       const std::string& user_agent,
       const HostPortPair& endpoint,
+      const ProxyServer& proxy_server,
       HttpAuthController* http_auth_controller,
       bool tunnel,
       bool using_spdy,
       NextProto negotiated_protocol,
+      ProxyDelegate* proxy_delegate,
       bool is_https_proxy,
       const NetworkTrafficAnnotationTag& traffic_annotation) override {
     return std::make_unique<HttpProxyClientSocket>(
-        std::move(transport_socket), user_agent, endpoint, http_auth_controller,
-        tunnel, using_spdy, negotiated_protocol, is_https_proxy,
-        traffic_annotation);
+        std::move(transport_socket), user_agent, endpoint, proxy_server,
+        http_auth_controller, tunnel, using_spdy, negotiated_protocol,
+        proxy_delegate, is_https_proxy, traffic_annotation);
   }
 
   void ClearSSLSessionCache() override { SSLClientSocket::ClearSessionCache(); }
diff --git a/net/socket/client_socket_factory.h b/net/socket/client_socket_factory.h
index 009c4e12..6123167 100644
--- a/net/socket/client_socket_factory.h
+++ b/net/socket/client_socket_factory.h
@@ -27,6 +27,8 @@
 struct SSLClientSocketContext;
 struct SSLConfig;
 class ProxyClientSocket;
+class ProxyDelegate;
+class ProxyServer;
 class HttpAuthController;
 
 // An interface used to instantiate StreamSocket objects.  Used to facilitate
@@ -61,10 +63,12 @@
       std::unique_ptr<ClientSocketHandle> transport_socket,
       const std::string& user_agent,
       const HostPortPair& endpoint,
+      const ProxyServer& proxy_server,
       HttpAuthController* http_auth_controller,
       bool tunnel,
       bool using_spdy,
       NextProto negotiated_protocol,
+      ProxyDelegate* proxy_delegate,
       bool is_https_proxy,
       const NetworkTrafficAnnotationTag& traffic_annotation) = 0;
 
diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc
index 26a784c..be7e7df 100644
--- a/net/socket/client_socket_pool_base_unittest.cc
+++ b/net/socket/client_socket_pool_base_unittest.cc
@@ -244,10 +244,12 @@
       std::unique_ptr<ClientSocketHandle> transport_socket,
       const std::string& user_agent,
       const HostPortPair& endpoint,
+      const ProxyServer& proxy_server,
       HttpAuthController* http_auth_controller,
       bool tunnel,
       bool using_spdy,
       NextProto negotiated_protocol,
+      ProxyDelegate* proxy_delegate,
       bool is_https_proxy,
       const NetworkTrafficAnnotationTag& traffic_annotation) override {
     NOTIMPLEMENTED();
diff --git a/net/socket/client_socket_pool_manager_impl.cc b/net/socket/client_socket_pool_manager_impl.cc
index 44ae320..11b2821 100644
--- a/net/socket/client_socket_pool_manager_impl.cc
+++ b/net/socket/client_socket_pool_manager_impl.cc
@@ -52,6 +52,7 @@
     const std::string& ssl_session_cache_shard,
     SSLConfigService* ssl_config_service,
     WebSocketEndpointLockManager* websocket_endpoint_lock_manager,
+    ProxyDelegate* proxy_delegate,
     HttpNetworkSession::SocketPoolType pool_type)
     : net_log_(net_log),
       socket_factory_(socket_factory),
@@ -65,6 +66,7 @@
       ct_policy_enforcer_(ct_policy_enforcer),
       ssl_session_cache_shard_(ssl_session_cache_shard),
       ssl_config_service_(ssl_config_service),
+      proxy_delegate_(proxy_delegate),
       pool_type_(pool_type),
       transport_socket_pool_(pool_type ==
                                      HttpNetworkSession::WEBSOCKET_SOCKET_POOL
@@ -308,7 +310,7 @@
           http_proxy, std::make_unique<HttpProxyClientSocketPool>(
                           sockets_per_proxy_server, sockets_per_group,
                           tcp_http_ret.first->second.get(),
-                          ssl_https_ret.first->second.get(),
+                          ssl_https_ret.first->second.get(), proxy_delegate_,
                           network_quality_estimator_, net_log_)));
 
   return ret.first->second.get();
diff --git a/net/socket/client_socket_pool_manager_impl.h b/net/socket/client_socket_pool_manager_impl.h
index 2706d93e..5f500dd 100644
--- a/net/socket/client_socket_pool_manager_impl.h
+++ b/net/socket/client_socket_pool_manager_impl.h
@@ -35,6 +35,7 @@
 class HostResolver;
 class NetLog;
 class NetworkQualityEstimator;
+class ProxyDelegate;
 class ProxyServer;
 class SocketPerformanceWatcherFactory;
 class SOCKSClientSocketPool;
@@ -62,6 +63,7 @@
       const std::string& ssl_session_cache_shard,
       SSLConfigService* ssl_config_service,
       WebSocketEndpointLockManager* websocket_endpoint_lock_manager,
+      ProxyDelegate* proxy_delegate,
       HttpNetworkSession::SocketPoolType pool_type);
   ~ClientSocketPoolManagerImpl() override;
 
@@ -113,6 +115,7 @@
   CTPolicyEnforcer* const ct_policy_enforcer_;
   const std::string ssl_session_cache_shard_;
   SSLConfigService* const ssl_config_service_;
+  ProxyDelegate* const proxy_delegate_;
   const HttpNetworkSession::SocketPoolType pool_type_;
 
   // Note: this ordering is important.
diff --git a/net/socket/fuzzed_socket_factory.cc b/net/socket/fuzzed_socket_factory.cc
index 57449da..136072c 100644
--- a/net/socket/fuzzed_socket_factory.cc
+++ b/net/socket/fuzzed_socket_factory.cc
@@ -156,10 +156,12 @@
     std::unique_ptr<ClientSocketHandle> transport_socket,
     const std::string& user_agent,
     const HostPortPair& endpoint,
+    const ProxyServer& proxy_server,
     HttpAuthController* http_auth_controller,
     bool tunnel,
     bool using_spdy,
     NextProto negotiated_protocol,
+    ProxyDelegate* proxy_delegate,
     bool is_https_proxy,
     const NetworkTrafficAnnotationTag& traffic_annotation) {
   NOTIMPLEMENTED();
diff --git a/net/socket/fuzzed_socket_factory.h b/net/socket/fuzzed_socket_factory.h
index fad788a..46153a7 100644
--- a/net/socket/fuzzed_socket_factory.h
+++ b/net/socket/fuzzed_socket_factory.h
@@ -56,10 +56,12 @@
       std::unique_ptr<ClientSocketHandle> transport_socket,
       const std::string& user_agent,
       const HostPortPair& endpoint,
+      const ProxyServer& proxy_server,
       HttpAuthController* http_auth_controller,
       bool tunnel,
       bool using_spdy,
       NextProto negotiated_protocol,
+      ProxyDelegate* proxy_delegate,
       bool is_https_proxy,
       const NetworkTrafficAnnotationTag& traffic_annotation) override;
 
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc
index 68617d63..14d7608 100644
--- a/net/socket/socket_test_util.cc
+++ b/net/socket/socket_test_util.cc
@@ -796,10 +796,12 @@
     std::unique_ptr<ClientSocketHandle> transport_socket,
     const std::string& user_agent,
     const HostPortPair& endpoint,
+    const ProxyServer& proxy_server,
     HttpAuthController* http_auth_controller,
     bool tunnel,
     bool using_spdy,
     NextProto negotiated_protocol,
+    ProxyDelegate* proxy_delegate,
     bool is_https_proxy,
     const NetworkTrafficAnnotationTag& traffic_annotation) {
   if (use_mock_proxy_client_sockets_) {
@@ -808,9 +810,9 @@
         std::move(transport_socket), http_auth_controller, next_proxy_data);
   } else {
     return GetDefaultFactory()->CreateProxyClientSocket(
-        std::move(transport_socket), user_agent, endpoint, http_auth_controller,
-        tunnel, using_spdy, negotiated_protocol, is_https_proxy,
-        traffic_annotation);
+        std::move(transport_socket), user_agent, endpoint, proxy_server,
+        http_auth_controller, tunnel, using_spdy, negotiated_protocol,
+        proxy_delegate, is_https_proxy, traffic_annotation);
   }
 }
 
diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h
index b2237ad..36e4346d 100644
--- a/net/socket/socket_test_util.h
+++ b/net/socket/socket_test_util.h
@@ -631,10 +631,12 @@
       std::unique_ptr<ClientSocketHandle> transport_socket,
       const std::string& user_agent,
       const HostPortPair& endpoint,
+      const ProxyServer& proxy_server,
       HttpAuthController* http_auth_controller,
       bool tunnel,
       bool using_spdy,
       NextProto negotiated_protocol,
+      ProxyDelegate* proxy_delegate,
       bool is_https_proxy,
       const NetworkTrafficAnnotationTag& traffic_annotation) override;
   void ClearSSLSessionCache() override;
diff --git a/net/socket/ssl_client_socket_pool_unittest.cc b/net/socket/ssl_client_socket_pool_unittest.cc
index 07fa615..f930b1a 100644
--- a/net/socket/ssl_client_socket_pool_unittest.cc
+++ b/net/socket/ssl_client_socket_pool_unittest.cc
@@ -140,6 +140,7 @@
                                 &transport_socket_pool_,
                                 NULL,
                                 NULL,
+                                NULL,
                                 NULL) {
     ssl_config_service_->GetSSLConfig(&ssl_config_);
   }
diff --git a/net/socket/transport_client_socket_pool_test_util.cc b/net/socket/transport_client_socket_pool_test_util.cc
index 3eb3420..1213991 100644
--- a/net/socket/transport_client_socket_pool_test_util.cc
+++ b/net/socket/transport_client_socket_pool_test_util.cc
@@ -456,10 +456,12 @@
     std::unique_ptr<ClientSocketHandle> transport_socket,
     const std::string& user_agent,
     const HostPortPair& endpoint,
+    const ProxyServer& proxy_server,
     HttpAuthController* http_auth_controller,
     bool tunnel,
     bool using_spdy,
     NextProto negotiated_protocol,
+    ProxyDelegate* proxy_delegate,
     bool is_https_proxy,
     const NetworkTrafficAnnotationTag& traffic_annotation) {
   NOTIMPLEMENTED();
diff --git a/net/socket/transport_client_socket_pool_test_util.h b/net/socket/transport_client_socket_pool_test_util.h
index b341963..e4213ea5 100644
--- a/net/socket/transport_client_socket_pool_test_util.h
+++ b/net/socket/transport_client_socket_pool_test_util.h
@@ -95,10 +95,12 @@
       std::unique_ptr<ClientSocketHandle> transport_socket,
       const std::string& user_agent,
       const HostPortPair& endpoint,
+      const ProxyServer& proxy_server,
       HttpAuthController* http_auth_controller,
       bool tunnel,
       bool using_spdy,
       NextProto negotiated_protocol,
+      ProxyDelegate* proxy_delegate,
       bool is_https_proxy,
       const NetworkTrafficAnnotationTag& traffic_annotation) override;
 
diff --git a/net/url_request/url_request_context.cc b/net/url_request/url_request_context.cc
index ee4850a..74d2c25 100644
--- a/net/url_request/url_request_context.cc
+++ b/net/url_request/url_request_context.cc
@@ -35,6 +35,7 @@
       channel_id_service_(nullptr),
       http_auth_handler_factory_(nullptr),
       proxy_resolution_service_(nullptr),
+      proxy_delegate_(nullptr),
       ssl_config_service_(nullptr),
       network_delegate_(nullptr),
       http_server_properties_(nullptr),
@@ -74,6 +75,7 @@
   set_channel_id_service(other->channel_id_service_);
   set_http_auth_handler_factory(other->http_auth_handler_factory_);
   set_proxy_resolution_service(other->proxy_resolution_service_);
+  set_proxy_delegate(other->proxy_delegate_);
   set_ssl_config_service(other->ssl_config_service_);
   set_network_delegate(other->network_delegate_);
   set_http_server_properties(other->http_server_properties_);
diff --git a/net/url_request/url_request_context.h b/net/url_request/url_request_context.h
index 2eddf63..4d51f78b 100644
--- a/net/url_request/url_request_context.h
+++ b/net/url_request/url_request_context.h
@@ -45,6 +45,7 @@
 class NetLog;
 class NetworkDelegate;
 class NetworkQualityEstimator;
+class ProxyDelegate;
 class ProxyResolutionService;
 class SSLConfigService;
 class URLRequest;
@@ -140,6 +141,11 @@
     proxy_resolution_service_ = proxy_resolution_service;
   }
 
+  ProxyDelegate* proxy_delegate() const { return proxy_delegate_; }
+  void set_proxy_delegate(ProxyDelegate* proxy_delegate) {
+    proxy_delegate_ = proxy_delegate;
+  }
+
   // Get the ssl config service for this context.
   SSLConfigService* ssl_config_service() const { return ssl_config_service_; }
   void set_ssl_config_service(SSLConfigService* service) {
@@ -303,6 +309,7 @@
   ChannelIDService* channel_id_service_;
   HttpAuthHandlerFactory* http_auth_handler_factory_;
   ProxyResolutionService* proxy_resolution_service_;
+  ProxyDelegate* proxy_delegate_;
   SSLConfigService* ssl_config_service_;
   NetworkDelegate* network_delegate_;
   HttpServerProperties* http_server_properties_;
diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc
index 91c1b7b..0033e7f 100644
--- a/net/url_request/url_request_context_builder.cc
+++ b/net/url_request/url_request_context_builder.cc
@@ -234,6 +234,7 @@
   session_context->ct_policy_enforcer = request_context->ct_policy_enforcer();
   session_context->proxy_resolution_service =
       request_context->proxy_resolution_service();
+  session_context->proxy_delegate = request_context->proxy_delegate();
   session_context->ssl_config_service = request_context->ssl_config_service();
   session_context->http_auth_handler_factory =
       request_context->http_auth_handler_factory();
@@ -565,9 +566,6 @@
   }
 #endif  // BUILDFLAG(ENABLE_REPORTING)
 
-  HttpNetworkSession::Context network_session_context;
-  SetHttpNetworkSessionComponents(context.get(), &network_session_context);
-
   if (proxy_delegate_) {
     DCHECK(!shared_proxy_delegate_);
     proxy_resolution_service->AssertNoProxyDelegate();
@@ -576,8 +574,12 @@
   } else if (shared_proxy_delegate_) {
     proxy_resolution_service->AssertNoProxyDelegate();
     proxy_resolution_service->SetProxyDelegate(shared_proxy_delegate_);
+    context->set_proxy_delegate(shared_proxy_delegate_);
   }
 
+  HttpNetworkSession::Context network_session_context;
+  SetHttpNetworkSessionComponents(context.get(), &network_session_context);
+
   storage->set_http_network_session(std::make_unique<HttpNetworkSession>(
       http_network_session_params_, network_session_context));
 
diff --git a/net/url_request/url_request_context_storage.cc b/net/url_request/url_request_context_storage.cc
index c84e776..ab7bb7c 100644
--- a/net/url_request/url_request_context_storage.cc
+++ b/net/url_request/url_request_context_storage.cc
@@ -70,6 +70,7 @@
 
 void URLRequestContextStorage::set_proxy_delegate(
     std::unique_ptr<ProxyDelegate> proxy_delegate) {
+  context_->set_proxy_delegate(proxy_delegate.get());
   proxy_delegate_ = std::move(proxy_delegate);
 }
 
diff --git a/net/websockets/websocket_basic_stream_adapters_test.cc b/net/websockets/websocket_basic_stream_adapters_test.cc
index d981f0c..892da3d 100644
--- a/net/websockets/websocket_basic_stream_adapters_test.cc
+++ b/net/websockets/websocket_basic_stream_adapters_test.cc
@@ -70,6 +70,7 @@
             "test_shard",
             nullptr,
             &websocket_endpoint_lock_manager_,
+            nullptr,
             HttpNetworkSession::NORMAL_SOCKET_POOL)),
         transport_params_(base::MakeRefCounted<TransportSocketParams>(
             host_port_pair_,
diff --git a/net/websockets/websocket_end_to_end_test.cc b/net/websockets/websocket_end_to_end_test.cc
index b720996f..fa0a84b 100644
--- a/net/websockets/websocket_end_to_end_test.cc
+++ b/net/websockets/websocket_end_to_end_test.cc
@@ -247,6 +247,15 @@
 
   void OnFallback(const ProxyServer& bad_proxy, int net_error) override {}
 
+  void OnBeforeTunnelRequest(const ProxyServer& proxy_server,
+                             HttpRequestHeaders* extra_headers) override {}
+
+  Error OnTunnelHeadersReceived(
+      const ProxyServer& proxy_server,
+      const HttpResponseHeaders& response_headers) override {
+    return OK;
+  }
+
  private:
   ResolvedProxyInfo resolved_proxy_info_;
 
diff --git a/services/network/network_service_proxy_delegate.cc b/services/network/network_service_proxy_delegate.cc
index ffc1aed..17f643a 100644
--- a/services/network/network_service_proxy_delegate.cc
+++ b/services/network/network_service_proxy_delegate.cc
@@ -165,6 +165,16 @@
 void NetworkServiceProxyDelegate::OnFallback(const net::ProxyServer& bad_proxy,
                                              int net_error) {}
 
+void NetworkServiceProxyDelegate::OnBeforeTunnelRequest(
+    const net::ProxyServer& proxy_server,
+    net::HttpRequestHeaders* extra_headers) {}
+
+net::Error NetworkServiceProxyDelegate::OnTunnelHeadersReceived(
+    const net::ProxyServer& proxy_server,
+    const net::HttpResponseHeaders& response_headers) {
+  return net::OK;
+}
+
 void NetworkServiceProxyDelegate::OnCustomProxyConfigUpdated(
     mojom::CustomProxyConfigPtr proxy_config) {
   DCHECK(proxy_config->rules.empty() ||
diff --git a/services/network/network_service_proxy_delegate.h b/services/network/network_service_proxy_delegate.h
index 6d36748..b69173e 100644
--- a/services/network/network_service_proxy_delegate.h
+++ b/services/network/network_service_proxy_delegate.h
@@ -52,6 +52,11 @@
                       const net::ProxyRetryInfoMap& proxy_retry_info,
                       net::ProxyInfo* result) override;
   void OnFallback(const net::ProxyServer& bad_proxy, int net_error) override;
+  void OnBeforeTunnelRequest(const net::ProxyServer& proxy_server,
+                             net::HttpRequestHeaders* extra_headers) override;
+  net::Error OnTunnelHeadersReceived(
+      const net::ProxyServer& proxy_server,
+      const net::HttpResponseHeaders& response_headers) override;
 
  private:
   // Checks whether |proxy_server| is present in the current proxy config.
diff --git a/services/network/proxy_resolving_client_socket_factory.cc b/services/network/proxy_resolving_client_socket_factory.cc
index f146c2e..2c24dcac 100644
--- a/services/network/proxy_resolving_client_socket_factory.cc
+++ b/services/network/proxy_resolving_client_socket_factory.cc
@@ -36,6 +36,7 @@
   session_context.channel_id_service = NULL;
   session_context.proxy_resolution_service =
       request_context->proxy_resolution_service();
+  session_context.proxy_delegate = request_context->proxy_delegate();
   session_context.ssl_config_service = request_context->ssl_config_service();
   session_context.http_auth_handler_factory =
       request_context->http_auth_handler_factory();