Clean up NPN/ALPN-related SSLClientSocket bits.

A follow-up will unvirtual and disentangle the other virtual functions there.
Have SSLClientSocket implement ALPN-related methods internally using
GetNextProto rather than rely on SSLConnectJob to do it.

The SPDY-related bit is removed and moved up to callers. Also clean up the
MockSSLClientSocket overrides of these functions now that the setters are never
called outside of the SSLClientSocket implementation. Instead,
SSLSocketDataProvider supplies the input to MockSSLClientSocket::GetNextProto
and then the usual logic computes everything else from there.

BUG=477847

Review URL: https://codereview.chromium.org/1097773003

Cr-Commit-Position: refs/heads/master@{#327066}
diff --git a/net/socket/next_proto.cc b/net/socket/next_proto.cc
index 4632e97..cfc65782 100644
--- a/net/socket/next_proto.cc
+++ b/net/socket/next_proto.cc
@@ -37,4 +37,9 @@
   return next_protos;
 }
 
+bool NextProtoIsSPDY(NextProto next_proto) {
+  return next_proto >= kProtoSPDYMinimumVersion &&
+         next_proto <= kProtoSPDYMaximumVersion;
+}
+
 }  // namespace net
diff --git a/net/socket/next_proto.h b/net/socket/next_proto.h
index b4b1d72..72ee0bb 100644
--- a/net/socket/next_proto.h
+++ b/net/socket/next_proto.h
@@ -57,6 +57,9 @@
 NET_EXPORT NextProtoVector NextProtosWithSpdyAndQuic(bool spdy_enabled,
                                                      bool quic_enabled);
 
+// Returns true if |next_proto| is a version of SPDY or HTTP/2.
+bool NextProtoIsSPDY(NextProto next_proto);
+
 }  // namespace net
 
 #endif  // NET_SOCKET_NEXT_PROTO_H_
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc
index 79b7a34..7d82384 100644
--- a/net/socket/socket_test_util.cc
+++ b/net/socket/socket_test_util.cc
@@ -284,8 +284,6 @@
 SSLSocketDataProvider::SSLSocketDataProvider(IoMode mode, int result)
     : connect(mode, result),
       next_proto_status(SSLClientSocket::kNextProtoUnsupported),
-      was_npn_negotiated(false),
-      protocol_negotiated(kProtoUnknown),
       client_cert_sent(false),
       cert_request_info(NULL),
       channel_id_sent(false),
@@ -300,9 +298,7 @@
 }
 
 void SSLSocketDataProvider::SetNextProto(NextProto proto) {
-  was_npn_negotiated = true;
   next_proto_status = SSLClientSocket::kNextProtoNegotiated;
-  protocol_negotiated = proto;
   next_proto = SSLClientSocket::NextProtoToString(proto);
 }
 
@@ -1024,8 +1020,8 @@
   return NULL;
 }
 
-SSLClientSocket::NextProtoStatus
-MockClientSocket::GetNextProto(std::string* proto) {
+SSLClientSocket::NextProtoStatus MockClientSocket::GetNextProto(
+    std::string* proto) const {
   proto->clear();
   return SSLClientSocket::kNextProtoUnsupported;
 }
@@ -1581,11 +1577,7 @@
           // tests.
           transport_socket->socket()->NetLog()),
       transport_(transport_socket.Pass()),
-      data_(data),
-      is_npn_state_set_(false),
-      new_npn_value_(false),
-      is_protocol_negotiated_set_(false),
-      protocol_negotiated_(kProtoUnknown) {
+      data_(data) {
   DCHECK(data_);
   peer_addr_ = data->connect.peer_addr;
 }
@@ -1663,34 +1655,11 @@
 }
 
 SSLClientSocket::NextProtoStatus MockSSLClientSocket::GetNextProto(
-    std::string* proto) {
+    std::string* proto) const {
   *proto = data_->next_proto;
   return data_->next_proto_status;
 }
 
-bool MockSSLClientSocket::set_was_npn_negotiated(bool negotiated) {
-  is_npn_state_set_ = true;
-  return new_npn_value_ = negotiated;
-}
-
-bool MockSSLClientSocket::WasNpnNegotiated() const {
-  if (is_npn_state_set_)
-    return new_npn_value_;
-  return data_->was_npn_negotiated;
-}
-
-NextProto MockSSLClientSocket::GetNegotiatedProtocol() const {
-  if (is_protocol_negotiated_set_)
-    return protocol_negotiated_;
-  return data_->protocol_negotiated;
-}
-
-void MockSSLClientSocket::set_protocol_negotiated(
-    NextProto protocol_negotiated) {
-  is_protocol_negotiated_set_ = true;
-  protocol_negotiated_ = protocol_negotiated;
-}
-
 bool MockSSLClientSocket::WasChannelIDSent() const {
   return data_->channel_id_sent;
 }
diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h
index 1baefb7..0a6e569 100644
--- a/net/socket/socket_test_util.h
+++ b/net/socket/socket_test_util.h
@@ -361,8 +361,6 @@
   MockConnect connect;
   SSLClientSocket::NextProtoStatus next_proto_status;
   std::string next_proto;
-  bool was_npn_negotiated;
-  NextProto protocol_negotiated;
   NextProtoVector next_protos_expected_in_ssl_config;
   bool client_cert_sent;
   SSLCertRequestInfo* cert_request_info;
@@ -790,7 +788,7 @@
                            unsigned char* out,
                            unsigned int outlen) override;
   int GetTLSUniqueChannelBinding(std::string* out) override;
-  NextProtoStatus GetNextProto(std::string* proto) override;
+  NextProtoStatus GetNextProto(std::string* proto) const override;
   ChannelIDService* GetChannelIDService() const override;
 
  protected:
@@ -1040,15 +1038,11 @@
   bool WasEverUsed() const override;
   bool UsingTCPFastOpen() const override;
   int GetPeerAddress(IPEndPoint* address) const override;
-  bool WasNpnNegotiated() const override;
   bool GetSSLInfo(SSLInfo* ssl_info) override;
 
   // SSLClientSocket implementation.
   void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override;
-  NextProtoStatus GetNextProto(std::string* proto) override;
-  bool set_was_npn_negotiated(bool negotiated) override;
-  void set_protocol_negotiated(NextProto protocol_negotiated) override;
-  NextProto GetNegotiatedProtocol() const override;
+  NextProtoStatus GetNextProto(std::string* proto) const override;
 
   // This MockSocket does not implement the manual async IO feature.
   void OnReadComplete(const MockRead& data) override;
@@ -1066,10 +1060,6 @@
 
   scoped_ptr<ClientSocketHandle> transport_;
   SSLSocketDataProvider* data_;
-  bool is_npn_state_set_;
-  bool new_npn_value_;
-  bool is_protocol_negotiated_set_;
-  NextProto protocol_negotiated_;
 
   DISALLOW_COPY_AND_ASSIGN(MockSSLClientSocket);
 };
diff --git a/net/socket/ssl_client_socket.cc b/net/socket/ssl_client_socket.cc
index f333cb8e..0be72d2a 100644
--- a/net/socket/ssl_client_socket.cc
+++ b/net/socket/ssl_client_socket.cc
@@ -18,9 +18,7 @@
 namespace net {
 
 SSLClientSocket::SSLClientSocket()
-    : was_npn_negotiated_(false),
-      was_spdy_negotiated_(false),
-      protocol_negotiated_(kProtoUnknown),
+    : protocol_negotiated_(kProtoUnknown),
       channel_id_sent_(false),
       signed_cert_timestamps_received_(false),
       stapled_ocsp_response_received_(false),
@@ -91,11 +89,15 @@
 }
 
 bool SSLClientSocket::WasNpnNegotiated() const {
-  return was_npn_negotiated_;
+  std::string unused_proto;
+  return GetNextProto(&unused_proto) == kNextProtoNegotiated;
 }
 
 NextProto SSLClientSocket::GetNegotiatedProtocol() const {
-  return protocol_negotiated_;
+  std::string proto;
+  if (GetNextProto(&proto) != kNextProtoNegotiated)
+    return kProtoUnknown;
+  return NextProtoFromString(proto);
 }
 
 bool SSLClientSocket::IgnoreCertError(int error, int load_flags) {
@@ -105,22 +107,6 @@
          IsCertificateError(error);
 }
 
-bool SSLClientSocket::set_was_npn_negotiated(bool negotiated) {
-  return was_npn_negotiated_ = negotiated;
-}
-
-bool SSLClientSocket::was_spdy_negotiated() const {
-  return was_spdy_negotiated_;
-}
-
-bool SSLClientSocket::set_was_spdy_negotiated(bool negotiated) {
-  return was_spdy_negotiated_ = negotiated;
-}
-
-void SSLClientSocket::set_protocol_negotiated(NextProto protocol_negotiated) {
-  protocol_negotiated_ = protocol_negotiated;
-}
-
 void SSLClientSocket::set_negotiation_extension(
     SSLNegotiationExtension negotiation_extension) {
   negotiation_extension_ = negotiation_extension;
@@ -144,6 +130,32 @@
   stapled_ocsp_response_received_ = stapled_ocsp_response_received;
 }
 
+void SSLClientSocket::RecordNegotiationExtension() {
+  if (negotiation_extension_ == kExtensionUnknown)
+    return;
+  std::string proto;
+  SSLClientSocket::NextProtoStatus status = GetNextProto(&proto);
+  if (status == kNextProtoUnsupported)
+    return;
+  // Convert protocol into numerical value for histogram.
+  NextProto protocol_negotiated = SSLClientSocket::NextProtoFromString(proto);
+  base::HistogramBase::Sample sample =
+      static_cast<base::HistogramBase::Sample>(protocol_negotiated);
+  // In addition to the protocol negotiated, we want to record which TLS
+  // extension was used, and in case of NPN, whether there was overlap between
+  // server and client list of supported protocols.
+  if (negotiation_extension_ == kExtensionNPN) {
+    if (status == kNextProtoNoOverlap) {
+      sample += 1000;
+    } else {
+      sample += 500;
+    }
+  } else {
+    DCHECK_EQ(kExtensionALPN, negotiation_extension_);
+  }
+  UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLProtocolNegotiation", sample);
+}
+
 // static
 void SSLClientSocket::RecordChannelIDSupport(
     ChannelIDService* channel_id_service,
@@ -242,30 +254,4 @@
   return wire_protos;
 }
 
-void SSLClientSocket::RecordNegotiationExtension() {
-  if (negotiation_extension_ == kExtensionUnknown)
-    return;
-  std::string proto;
-  SSLClientSocket::NextProtoStatus status = GetNextProto(&proto);
-  if (status == kNextProtoUnsupported)
-    return;
-  // Convert protocol into numerical value for histogram.
-  NextProto protocol_negotiated = SSLClientSocket::NextProtoFromString(proto);
-  base::HistogramBase::Sample sample =
-      static_cast<base::HistogramBase::Sample>(protocol_negotiated);
-  // In addition to the protocol negotiated, we want to record which TLS
-  // extension was used, and in case of NPN, whether there was overlap between
-  // server and client list of supported protocols.
-  if (negotiation_extension_ == kExtensionNPN) {
-    if (status == kNextProtoNoOverlap) {
-      sample += 1000;
-    } else {
-      sample += 500;
-    }
-  } else {
-    DCHECK_EQ(kExtensionALPN, negotiation_extension_);
-  }
-  UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLProtocolNegotiation", sample);
-}
-
 }  // namespace net
diff --git a/net/socket/ssl_client_socket.h b/net/socket/ssl_client_socket.h
index 357f0d3..6ee2ece 100644
--- a/net/socket/ssl_client_socket.h
+++ b/net/socket/ssl_client_socket.h
@@ -105,7 +105,7 @@
   //   kNextProtoNegotiated:  *proto is set to the negotiated protocol.
   //   kNextProtoNoOverlap:   *proto is set to the first protocol in the
   //                          supported list.
-  virtual NextProtoStatus GetNextProto(std::string* proto) = 0;
+  virtual NextProtoStatus GetNextProto(std::string* proto) const = 0;
 
   static NextProto NextProtoFromString(const std::string& proto_string);
 
@@ -125,14 +125,6 @@
   // cryptographic implementation.
   static uint16 GetMaxSupportedSSLVersion();
 
-  virtual bool set_was_npn_negotiated(bool negotiated);
-
-  virtual bool was_spdy_negotiated() const;
-
-  virtual bool set_was_spdy_negotiated(bool negotiated);
-
-  virtual void set_protocol_negotiated(NextProto protocol_negotiated);
-
   void set_negotiation_extension(SSLNegotiationExtension negotiation_extension);
 
   // Returns the ChannelIDService used by this socket, or NULL if
@@ -147,10 +139,6 @@
   // Public for ssl_client_socket_openssl_unittest.cc.
   virtual bool WasChannelIDSent() const;
 
-  // Record which TLS extension was used to negotiate protocol and protocol
-  // chosen in a UMA histogram.
-  void RecordNegotiationExtension();
-
  protected:
   virtual void set_channel_id_sent(bool channel_id_sent);
 
@@ -160,6 +148,10 @@
   virtual void set_stapled_ocsp_response_received(
       bool stapled_ocsp_response_received);
 
+  // Record which TLS extension was used to negotiate protocol and protocol
+  // chosen in a UMA histogram.
+  void RecordNegotiationExtension();
+
   // Records histograms for channel id support during full handshakes - resumed
   // handshakes are ignored.
   static void RecordChannelIDSupport(
@@ -210,10 +202,6 @@
   FRIEND_TEST_ALL_PREFIXES(SSLClientSocketTest,
                            VerifyServerChainProperlyOrdered);
 
-  // True if NPN was responded to, independent of selecting SPDY or HTTP.
-  bool was_npn_negotiated_;
-  // True if NPN successfully negotiated SPDY.
-  bool was_spdy_negotiated_;
   // Protocol that we negotiated with the server.
   NextProto protocol_negotiated_;
   // True if a channel ID was sent.
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index 43614c86..ae1c427 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -2569,8 +2569,8 @@
   return OK;
 }
 
-SSLClientSocket::NextProtoStatus
-SSLClientSocketNSS::GetNextProto(std::string* proto) {
+SSLClientSocket::NextProtoStatus SSLClientSocketNSS::GetNextProto(
+    std::string* proto) const {
   *proto = core_->state().next_proto;
   return core_->state().next_proto_status;
 }
@@ -3048,6 +3048,8 @@
       return ERR_SSL_FALLBACK_BEYOND_MINIMUM_VERSION;
     }
 
+    RecordNegotiationExtension();
+
     // SSL handshake is completed. Let's verify the certificate.
     GotoState(STATE_VERIFY_CERT);
     // Done!
diff --git a/net/socket/ssl_client_socket_nss.h b/net/socket/ssl_client_socket_nss.h
index a4964d3..e348ebc9 100644
--- a/net/socket/ssl_client_socket_nss.h
+++ b/net/socket/ssl_client_socket_nss.h
@@ -69,7 +69,7 @@
 
   // SSLClientSocket implementation.
   void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override;
-  NextProtoStatus GetNextProto(std::string* proto) override;
+  NextProtoStatus GetNextProto(std::string* proto) const override;
 
   // SSLSocket implementation.
   int ExportKeyingMaterial(const base::StringPiece& label,
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc
index fb739f4..0b3e1c2 100644
--- a/net/socket/ssl_client_socket_openssl.cc
+++ b/net/socket/ssl_client_socket_openssl.cc
@@ -404,7 +404,7 @@
 }
 
 SSLClientSocket::NextProtoStatus SSLClientSocketOpenSSL::GetNextProto(
-    std::string* proto) {
+    std::string* proto) const {
   *proto = npn_proto_;
   return npn_status_;
 }
@@ -940,6 +940,7 @@
       }
     }
 
+    RecordNegotiationExtension();
     RecordChannelIDSupport(channel_id_service_,
                            channel_id_xtn_negotiated_,
                            ssl_config_.channel_id_enabled,
diff --git a/net/socket/ssl_client_socket_openssl.h b/net/socket/ssl_client_socket_openssl.h
index dc9c7e90..a166c97 100644
--- a/net/socket/ssl_client_socket_openssl.h
+++ b/net/socket/ssl_client_socket_openssl.h
@@ -61,7 +61,7 @@
 
   // SSLClientSocket implementation.
   void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override;
-  NextProtoStatus GetNextProto(std::string* proto) override;
+  NextProtoStatus GetNextProto(std::string* proto) const override;
   ChannelIDService* GetChannelIDService() const override;
 
   // SSLSocket implementation.
diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc
index e6c770c..3426622 100644
--- a/net/socket/ssl_client_socket_pool.cc
+++ b/net/socket/ssl_client_socket_pool.cc
@@ -329,33 +329,11 @@
 
   connect_timing_.ssl_end = base::TimeTicks::Now();
 
-  SSLClientSocket::NextProtoStatus status =
-      SSLClientSocket::kNextProtoUnsupported;
-  std::string proto;
-  // GetNextProto will fail and and trigger a NOTREACHED if we pass in a socket
-  // that hasn't had SSL_ImportFD called on it. If we get a certificate error
-  // here, then we know that we called SSL_ImportFD.
-  if (result == OK || IsCertificateError(result)) {
-    status = ssl_socket_->GetNextProto(&proto);
-    ssl_socket_->RecordNegotiationExtension();
-  }
-
-  // If we want spdy over npn, make sure it succeeded.
-  if (status == SSLClientSocket::kNextProtoNegotiated) {
-    ssl_socket_->set_was_npn_negotiated(true);
-    NextProto protocol_negotiated =
-        SSLClientSocket::NextProtoFromString(proto);
-    ssl_socket_->set_protocol_negotiated(protocol_negotiated);
-    // If we negotiated a SPDY version, it must have been present in
-    // SSLConfig::next_protos.
-    // TODO(mbelshe): Verify this.
-    if (protocol_negotiated >= kProtoSPDYMinimumVersion &&
-        protocol_negotiated <= kProtoSPDYMaximumVersion) {
-      ssl_socket_->set_was_spdy_negotiated(true);
-    }
-  }
-  if (params_->want_spdy_over_npn() && !ssl_socket_->was_spdy_negotiated())
+  // If we want SPDY over ALPN/NPN, make sure it succeeded.
+  if (params_->want_spdy_over_npn() &&
+      !NextProtoIsSPDY(ssl_socket_->GetNegotiatedProtocol())) {
     return ERR_NPN_NEGOTIATION_FAILED;
+  }
 
   if (result == OK ||
       ssl_socket_->IgnoreCertError(result, params_->load_flags())) {