// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef NET_SSL_CHANNEL_ID_SERVICE_H_ #define NET_SSL_CHANNEL_ID_SERVICE_H_ #include #include #include #include #include #include #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/task_runner.h" #include "base/threading/thread_checker.h" #include "net/base/completion_once_callback.h" #include "net/base/net_export.h" #include "net/ssl/channel_id_store.h" namespace crypto { class ECPrivateKey; } // namespace crypto namespace net { class ChannelIDServiceJob; // A class for creating and fetching Channel IDs. class NET_EXPORT ChannelIDService { public: class NET_EXPORT Request { public: Request(); ~Request(); // Cancel the request. Does nothing if the request finished or was already // cancelled. void Cancel(); bool is_active() const { return !callback_.is_null(); } private: friend class ChannelIDService; friend class ChannelIDServiceJob; void RequestStarted(ChannelIDService* service, CompletionOnceCallback callback, std::unique_ptr* key, ChannelIDServiceJob* job); void Post(int error, std::unique_ptr key); ChannelIDService* service_; CompletionOnceCallback callback_; std::unique_ptr* key_; ChannelIDServiceJob* job_; }; // This object owns |channel_id_store|. explicit ChannelIDService(ChannelIDStore* channel_id_store); ~ChannelIDService(); // Sets the TaskRunner to use for asynchronous operations. void set_task_runner_for_testing( scoped_refptr task_runner) { task_runner_ = std::move(task_runner); } // Returns the domain to be used for |host|. The domain is the // "registry controlled domain", or the "ETLD + 1" where one exists, or // the origin otherwise. static std::string GetDomainForHost(const std::string& host); // Fetches the channel ID for the specified host if one exists and // creates one otherwise. Returns OK if successful or an error code upon // failure. // // On successful completion, |key| holds the ECDSA keypair used for this // channel ID. // // |callback| must not be null. ERR_IO_PENDING is returned if the operation // could not be completed immediately, in which case the result code will // be passed to the callback when available. // // |*out_req| will be initialized with a handle to the async request. int GetOrCreateChannelID(const std::string& host, std::unique_ptr* key, CompletionOnceCallback callback, Request* out_req); // Fetches the channel ID for the specified host if one exists. // Returns OK if successful, ERR_FILE_NOT_FOUND if none exists, or an error // code upon failure. // // On successful completion, |key| holds the ECDSA keypair used for this // channel ID. // // |callback| must not be null. ERR_IO_PENDING is returned if the operation // could not be completed immediately, in which case the result code will // be passed to the callback when available. If an in-flight // GetChannelID is pending, and a new GetOrCreateChannelID // request arrives for the same domain, the GetChannelID request will // not complete until a new channel ID is created. // // |*out_req| will be initialized with a handle to the async request. int GetChannelID(const std::string& host, std::unique_ptr* key, CompletionOnceCallback callback, Request* out_req); // Returns the backing ChannelIDStore. ChannelIDStore* GetChannelIDStore(); // Returns an ID that is unique across all instances of ChannelIDService in // this process. TODO(nharper): remove this once crbug.com/548423 is resolved. int GetUniqueID() const { return id_; } // Public only for unit testing. int channel_id_count(); uint64_t requests() const { return requests_; } uint64_t key_store_hits() const { return key_store_hits_; } uint64_t inflight_joins() const { return inflight_joins_; } uint64_t workers_created() const { return workers_created_; } private: void GotChannelID(int err, const std::string& server_identifier, std::unique_ptr key); void GeneratedChannelID( const std::string& server_identifier, int error, std::unique_ptr channel_id); void HandleResult(int error, const std::string& server_identifier, std::unique_ptr key); // Searches for an in-flight request for the same domain. If found, attaches // to the request, consumes |*callback|, and returns true. Otherwise does not // consume |*callback| and returns false. bool JoinToInFlightRequest(const std::string& domain, std::unique_ptr* key, bool create_if_missing, CompletionOnceCallback* callback, Request* out_req); // Looks for the channel ID for |domain| in this service's store. Returns OK // if it can be found synchronously, ERR_IO_PENDING if the result cannot be // obtained synchronously, or a different network error code on failure // (including failure to find a channel ID of |domain|). Consumes |*callback| // if and only if ERR_IO_PENDING is returned. int LookupChannelID(const std::string& domain, std::unique_ptr* key, bool create_if_missing, CompletionOnceCallback* callback, Request* out_req); std::unique_ptr channel_id_store_; scoped_refptr task_runner_; const int id_; // inflight_ maps from a server to an active generation which is taking // place. std::map> inflight_; uint64_t requests_; uint64_t key_store_hits_; uint64_t inflight_joins_; uint64_t workers_created_; THREAD_CHECKER(thread_checker_); base::WeakPtrFactory weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(ChannelIDService); }; } // namespace net #endif // NET_SSL_CHANNEL_ID_SERVICE_H_