Chromium Code Reviews| Index: net/quic/quic_stream_factory.cc |
| diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc |
| index 832cf909eb8a9ff21ccacd572ab8e25feb7eac82..94b83603a267d3b1e2696de72fe8d8b50d3ef97c 100644 |
| --- a/net/quic/quic_stream_factory.cc |
| +++ b/net/quic/quic_stream_factory.cc |
| @@ -34,6 +34,7 @@ |
| #include "net/http/bidirectional_stream_impl.h" |
| #include "net/quic/bidirectional_stream_quic_impl.h" |
| #include "net/quic/crypto/channel_id_chromium.h" |
| +#include "net/quic/crypto/proof_verifier.h" |
| #include "net/quic/crypto/proof_verifier_chromium.h" |
| #include "net/quic/crypto/properties_based_quic_server_info.h" |
| #include "net/quic/crypto/quic_random.h" |
| @@ -167,6 +168,83 @@ QuicConfig InitializeQuicConfig(const QuicTagVector& connection_options, |
| } // namespace |
| +class QuicStreamFactory::CertVerifierJob { |
|
Ryan Hamilton
2016/07/07 21:36:12
nit: comment, please.
ramant (doing other things)
2016/07/07 22:18:27
My fault.
Done.
|
| + public: |
| + class ProofVerifierCallbackImpl : public ProofVerifierCallback { |
| + public: |
| + explicit ProofVerifierCallbackImpl(CertVerifierJob* job) : job_(job) {} |
| + |
| + ~ProofVerifierCallbackImpl() override {} |
| + |
| + void Run(bool ok, |
| + const std::string& error_details, |
| + std::unique_ptr<ProofVerifyDetails>* details) override { |
| + if (job_ == nullptr) |
| + return; |
| + job_->verify_callback_ = nullptr; |
| + job_->OnComplete(); |
| + } |
| + |
| + void Cancel() { job_ = nullptr; } |
| + |
| + private: |
| + CertVerifierJob* job_; |
| + }; |
| + |
| + CertVerifierJob(const QuicServerId& server_id, |
| + int cert_verify_flags, |
| + const BoundNetLog& net_log) |
| + : server_id_(server_id), |
| + verify_callback_(nullptr), |
| + verify_context_(base::WrapUnique( |
| + new ProofVerifyContextChromium(cert_verify_flags, net_log))), |
| + net_log_(net_log), |
| + weak_factory_(this) {} |
| + |
| + ~CertVerifierJob() { |
| + if (verify_callback_) |
| + verify_callback_->Cancel(); |
| + } |
| + |
| + QuicAsyncStatus Run(QuicCryptoClientConfig* crypto_config, |
| + const CompletionCallback& callback) { |
| + QuicCryptoClientConfig::CachedState* cached = |
| + crypto_config->LookupOrCreate(server_id_); |
| + ProofVerifierCallbackImpl* verify_callback = |
| + new ProofVerifierCallbackImpl(this); |
| + QuicAsyncStatus status = crypto_config->proof_verifier()->VerifyCertChain( |
| + server_id_.host(), server_id_.port(), cached->certs(), |
| + verify_context_.get(), &verify_error_details_, &verify_details_, |
| + verify_callback); |
| + if (status == QUIC_PENDING) { |
| + verify_callback_ = verify_callback; |
| + callback_ = callback; |
| + } else { |
| + delete verify_callback; |
| + } |
| + return status; |
| + } |
| + |
| + void OnComplete() { |
| + if (!callback_.is_null()) |
| + callback_.Run(OK); |
| + } |
| + |
| + const QuicServerId& server_id() const { return server_id_; } |
| + |
| + private: |
| + QuicServerId server_id_; |
| + ProofVerifierCallbackImpl* verify_callback_; |
| + std::unique_ptr<ProofVerifyContext> verify_context_; |
| + std::unique_ptr<ProofVerifyDetails> verify_details_; |
| + std::string verify_error_details_; |
| + const BoundNetLog net_log_; |
| + CompletionCallback callback_; |
| + base::WeakPtrFactory<CertVerifierJob> weak_factory_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(CertVerifierJob); |
| +}; |
| + |
| // Responsible for creating a new QUIC session to the specified server, and |
| // for notifying any associated requests when complete. |
| class QuicStreamFactory::Job { |
| @@ -632,6 +710,7 @@ QuicStreamFactory::QuicStreamFactory( |
| int idle_connection_timeout_seconds, |
| bool migrate_sessions_on_network_change, |
| bool migrate_sessions_early, |
| + bool race_cert_verification, |
| const QuicTagVector& connection_options, |
| bool enable_token_binding) |
| : require_confirmation_(true), |
| @@ -685,6 +764,7 @@ QuicStreamFactory::QuicStreamFactory( |
| NetworkChangeNotifier::AreNetworkHandlesSupported()), |
| migrate_sessions_early_(migrate_sessions_early && |
| migrate_sessions_on_network_change_), |
| + race_cert_verification_(race_cert_verification), |
| port_seed_(random_generator_->RandUint64()), |
| check_persisted_supports_quic_(true), |
| has_initialized_data_(false), |
| @@ -752,6 +832,8 @@ QuicStreamFactory::~QuicStreamFactory() { |
| STLDeleteElements(&(active_jobs_[server_id])); |
| active_jobs_.erase(server_id); |
| } |
| + while (!active_cert_verifier_jobs_.empty()) |
| + active_cert_verifier_jobs_.erase(active_cert_verifier_jobs_.begin()); |
| if (ssl_config_service_.get()) |
| ssl_config_service_->RemoveObserver(this); |
| if (migrate_sessions_on_network_change_) { |
| @@ -888,6 +970,8 @@ int QuicStreamFactory::Create(const QuicServerId& server_id, |
| } |
| } |
| + StartCertVerifyJob(server_id, cert_verify_flags, net_log); |
| + |
| QuicSessionKey key(destination, server_id); |
| std::unique_ptr<Job> job( |
| new Job(this, host_resolver_, key, WasQuicRecentlyBroken(server_id), |
| @@ -1020,6 +1104,10 @@ void QuicStreamFactory::OnJobComplete(Job* job, int rv) { |
| job_requests_map_.erase(server_id); |
| } |
| +void QuicStreamFactory::OnCertVerifyJobComplete(CertVerifierJob* job, int rv) { |
| + active_cert_verifier_jobs_.erase(job->server_id()); |
| +} |
| + |
| std::unique_ptr<QuicHttpStream> QuicStreamFactory::CreateFromSession( |
| QuicChromiumClientSession* session) { |
| return std::unique_ptr<QuicHttpStream>( |
| @@ -1548,6 +1636,11 @@ bool QuicStreamFactory::HasActiveJob(const QuicServerId& server_id) const { |
| return ContainsKey(active_jobs_, server_id); |
| } |
| +bool QuicStreamFactory::HasActiveCertVerifierJob( |
| + const QuicServerId& server_id) const { |
| + return ContainsKey(active_cert_verifier_jobs_, server_id); |
| +} |
| + |
| int QuicStreamFactory::ConfigureSocket(DatagramClientSocket* socket, |
| IPEndPoint addr, |
| NetworkHandle network) { |
| @@ -1755,6 +1848,27 @@ bool QuicStreamFactory::CryptoConfigCacheIsEmpty( |
| return cached->IsEmpty(); |
| } |
| +void QuicStreamFactory::StartCertVerifyJob(const QuicServerId& server_id, |
| + int cert_verify_flags, |
| + const BoundNetLog& net_log) { |
| + if (!race_cert_verification_) |
| + return; |
| + QuicCryptoClientConfig::CachedState* cached = |
| + crypto_config_.LookupOrCreate(server_id); |
| + if (!cached || cached->certs().empty() || |
| + HasActiveCertVerifierJob(server_id)) { |
| + return; |
| + } |
| + std::unique_ptr<CertVerifierJob> cert_verifier_job( |
| + new CertVerifierJob(server_id, cert_verify_flags, net_log)); |
| + QuicAsyncStatus status = cert_verifier_job->Run( |
| + &crypto_config_, |
| + base::Bind(&QuicStreamFactory::OnCertVerifyJobComplete, |
| + base::Unretained(this), cert_verifier_job.get())); |
| + if (status == QUIC_PENDING) |
| + active_cert_verifier_jobs_[server_id] = std::move(cert_verifier_job); |
| +} |
| + |
| void QuicStreamFactory::InitializeCachedStateInCryptoConfig( |
| const QuicServerId& server_id, |
| const std::unique_ptr<QuicServerInfo>& server_info, |