| Index: net/socket/ssl_client_socket_nss.cc | 
| diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc | 
| index a715d06388fe483560708c4b263f0f4b0527470f..e0ed410fffc1d86cebbd9bb18420488b1e782a7b 100644 | 
| --- a/net/socket/ssl_client_socket_nss.cc | 
| +++ b/net/socket/ssl_client_socket_nss.cc | 
| @@ -466,6 +466,7 @@ SSLClientSocketNSS::SSLClientSocketNSS(ClientSocketHandle* transport_socket, | 
| net_log_(transport_socket->socket()->NetLog()), | 
| ssl_host_info_(ssl_host_info), | 
| dns_cert_checker_(context.dns_cert_checker), | 
| +      next_proto_status_(kNextProtoUnsupported), | 
| valid_thread_id_(base::kInvalidThreadId) { | 
| EnterFunction(""); | 
| } | 
| @@ -553,38 +554,8 @@ int SSLClientSocketNSS::ExportKeyingMaterial(const base::StringPiece& label, | 
|  | 
| SSLClientSocket::NextProtoStatus | 
| SSLClientSocketNSS::GetNextProto(std::string* proto) { | 
| -#if defined(SSL_NEXT_PROTO_NEGOTIATED) | 
| -  unsigned char buf[255]; | 
| -  int state; | 
| -  unsigned len; | 
| -  SECStatus rv = SSL_GetNextProto(nss_fd_, &state, buf, &len, sizeof(buf)); | 
| -  if (rv != SECSuccess) { | 
| -    NOTREACHED() << "Error return from SSL_GetNextProto: " << rv; | 
| -    proto->clear(); | 
| -    return kNextProtoUnsupported; | 
| -  } | 
| -  // We don't check for truncation because sizeof(buf) is large enough to hold | 
| -  // the maximum protocol size. | 
| -  switch (state) { | 
| -    case SSL_NEXT_PROTO_NO_SUPPORT: | 
| -      proto->clear(); | 
| -      return kNextProtoUnsupported; | 
| -    case SSL_NEXT_PROTO_NEGOTIATED: | 
| -      *proto = std::string(reinterpret_cast<char*>(buf), len); | 
| -      return kNextProtoNegotiated; | 
| -    case SSL_NEXT_PROTO_NO_OVERLAP: | 
| -      *proto = std::string(reinterpret_cast<char*>(buf), len); | 
| -      return kNextProtoNoOverlap; | 
| -    default: | 
| -      NOTREACHED() << "Unknown status from SSL_GetNextProto: " << state; | 
| -      proto->clear(); | 
| -      return kNextProtoUnsupported; | 
| -  } | 
| -#else | 
| -  // No NPN support in the libssl that we are building with. | 
| -  proto->clear(); | 
| -  return kNextProtoUnsupported; | 
| -#endif | 
| +  *proto = next_proto_; | 
| +  return next_proto_status_; | 
| } | 
|  | 
| int SSLClientSocketNSS::Connect(OldCompletionCallback* callback) { | 
| @@ -966,12 +937,10 @@ int SSLClientSocketNSS::InitializeSSLOptions() { | 
|  | 
| #ifdef SSL_NEXT_PROTO_NEGOTIATED | 
| if (!ssl_config_.next_protos.empty()) { | 
| -    rv = SSL_SetNextProtoNego( | 
| -       nss_fd_, | 
| -       reinterpret_cast<const unsigned char *>(ssl_config_.next_protos.data()), | 
| -       ssl_config_.next_protos.size()); | 
| +    rv = SSL_SetNextProtoCallback( | 
| +        nss_fd_, SSLClientSocketNSS::NextProtoCallback, this); | 
| if (rv != SECSuccess) | 
| -      LogFailedNSSFunction(net_log_, "SSL_SetNextProtoNego", ""); | 
| +      LogFailedNSSFunction(net_log_, "SSL_SetNextProtoCallback", ""); | 
| } | 
| #endif | 
|  | 
| @@ -2564,6 +2533,58 @@ void SSLClientSocketNSS::HandshakeCallback(PRFileDesc* socket, | 
| that->UpdateConnectionStatus(); | 
| } | 
|  | 
| +// NextProtoCallback is called by NSS during the handshake, if the server | 
| +// supports NPN, to select a protocol from the list that the server offered. | 
| +// See the comment in net/third_party/nss/ssl/ssl.h for the meanings of the | 
| +// arguments. | 
| +// static | 
| +SECStatus | 
| +SSLClientSocketNSS::NextProtoCallback(void* arg, | 
| +                                      PRFileDesc* nss_fd, | 
| +                                      const unsigned char* protos, | 
| +                                      unsigned int protos_len, | 
| +                                      unsigned char* proto_out, | 
| +                                      unsigned int* proto_out_len) { | 
| +  SSLClientSocketNSS* that = reinterpret_cast<SSLClientSocketNSS*>(arg); | 
| + | 
| +  // For each protocol in server preference, see if we support it. | 
| +  for (unsigned int i = 0; i < protos_len; ) { | 
| +    const size_t len = protos[i]; | 
| +    for (std::vector<std::string>::const_iterator | 
| +         j = that->ssl_config_.next_protos.begin(); | 
| +         j != that->ssl_config_.next_protos.end(); j++) { | 
| +      // Having very long elements in the |next_protos| vector isn't a disaster | 
| +      // because they'll never be selected, but it does indicate an error | 
| +      // somewhere. | 
| +      DCHECK_LT(j->size(), 256u); | 
| + | 
| +      if (j->size() == len && | 
| +          memcmp(&protos[i + 1], j->data(), len) == 0) { | 
| +        that->next_proto_status_ = kNextProtoNegotiated; | 
| +        that->next_proto_ = *j; | 
| +        break; | 
| +      } | 
| +    } | 
| + | 
| +    if (that->next_proto_status_ == kNextProtoNegotiated) | 
| +      break; | 
| + | 
| +    // NSS checks that the data in |protos| is well formed, so we know that | 
| +    // this doesn't cause us to jump off the end of the buffer. | 
| +    i += len + 1; | 
| +  } | 
| + | 
| +  // If we didn't find a protocol, we select the first one from our list. | 
| +  if (that->next_proto_status_ != kNextProtoNegotiated) { | 
| +    that->next_proto_status_ = kNextProtoNoOverlap; | 
| +    that->next_proto_ = that->ssl_config_.next_protos[0]; | 
| +  } | 
| + | 
| +  memcpy(proto_out, that->next_proto_.data(), that->next_proto_.size()); | 
| +  *proto_out_len = that->next_proto_.size(); | 
| +  return SECSuccess; | 
| +} | 
| + | 
| void SSLClientSocketNSS::EnsureThreadIdAssigned() const { | 
| base::AutoLock auto_lock(lock_); | 
| if (valid_thread_id_ != base::kInvalidThreadId) | 
|  |