| // 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 <stdint.h> | 
 |  | 
 | #include <map> | 
 | #include <memory> | 
 | #include <string> | 
 | #include <vector> | 
 |  | 
 | #include "base/macros.h" | 
 | #include "base/memory/weak_ptr.h" | 
 | #include "base/threading/non_thread_safe.h" | 
 | #include "base/time/time.h" | 
 | #include "net/base/completion_callback.h" | 
 | #include "net/base/net_export.h" | 
 | #include "net/ssl/channel_id_store.h" | 
 |  | 
 | namespace base { | 
 | class TaskRunner; | 
 | }  // namespace base | 
 |  | 
 | namespace crypto { | 
 | class ECPrivateKey; | 
 | }  // namespace crypto | 
 |  | 
 | namespace net { | 
 |  | 
 | class ChannelIDServiceJob; | 
 | class ChannelIDServiceWorker; | 
 |  | 
 | // A class for creating and fetching Channel IDs. | 
 |  | 
 | // Inherits from NonThreadSafe in order to use the function | 
 | // |CalledOnValidThread|. | 
 | class NET_EXPORT ChannelIDService | 
 |     : NON_EXPORTED_BASE(public base::NonThreadSafe) { | 
 |  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, | 
 |                         base::TimeTicks request_start, | 
 |                         const CompletionCallback& callback, | 
 |                         std::unique_ptr<crypto::ECPrivateKey>* key, | 
 |                         ChannelIDServiceJob* job); | 
 |  | 
 |     void Post(int error, std::unique_ptr<crypto::ECPrivateKey> key); | 
 |  | 
 |     ChannelIDService* service_; | 
 |     base::TimeTicks request_start_; | 
 |     CompletionCallback callback_; | 
 |     std::unique_ptr<crypto::ECPrivateKey>* key_; | 
 |     ChannelIDServiceJob* job_; | 
 |   }; | 
 |  | 
 |   // Password used on EncryptedPrivateKeyInfo data stored in EC private_key | 
 |   // values.  (This is not used to provide any security, but to workaround NSS | 
 |   // being unable to import unencrypted PrivateKeyInfo for EC keys.) | 
 |   static const char kEPKIPassword[]; | 
 |  | 
 |   // This object owns |channel_id_store|.  |task_runner| will | 
 |   // be used to post channel ID generation worker tasks.  The tasks are | 
 |   // safe for use with WorkerPool and SequencedWorkerPool::CONTINUE_ON_SHUTDOWN. | 
 |   ChannelIDService( | 
 |       ChannelIDStore* channel_id_store, | 
 |       const scoped_refptr<base::TaskRunner>& task_runner); | 
 |  | 
 |   ~ChannelIDService(); | 
 |  | 
 |   // 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<crypto::ECPrivateKey>* key, | 
 |                            const CompletionCallback& 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<crypto::ECPrivateKey>* key, | 
 |                    const CompletionCallback& 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<crypto::ECPrivateKey> key); | 
 |   void GeneratedChannelID( | 
 |       const std::string& server_identifier, | 
 |       int error, | 
 |       std::unique_ptr<ChannelIDStore::ChannelID> channel_id); | 
 |   void HandleResult(int error, | 
 |                     const std::string& server_identifier, | 
 |                     std::unique_ptr<crypto::ECPrivateKey> key); | 
 |  | 
 |   // Searches for an in-flight request for the same domain. If found, | 
 |   // attaches to the request and returns true. Returns false if no in-flight | 
 |   // request is found. | 
 |   bool JoinToInFlightRequest(const base::TimeTicks& request_start, | 
 |                              const std::string& domain, | 
 |                              std::unique_ptr<crypto::ECPrivateKey>* key, | 
 |                              bool create_if_missing, | 
 |                              const CompletionCallback& 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 network error code on | 
 |   // failure (including failure to find a channel ID of |domain|). | 
 |   int LookupChannelID(const base::TimeTicks& request_start, | 
 |                       const std::string& domain, | 
 |                       std::unique_ptr<crypto::ECPrivateKey>* key, | 
 |                       bool create_if_missing, | 
 |                       const CompletionCallback& callback, | 
 |                       Request* out_req); | 
 |  | 
 |   std::unique_ptr<ChannelIDStore> channel_id_store_; | 
 |   scoped_refptr<base::TaskRunner> task_runner_; | 
 |   const int id_; | 
 |  | 
 |   // inflight_ maps from a server to an active generation which is taking | 
 |   // place. | 
 |   std::map<std::string, ChannelIDServiceJob*> inflight_; | 
 |  | 
 |   uint64_t requests_; | 
 |   uint64_t key_store_hits_; | 
 |   uint64_t inflight_joins_; | 
 |   uint64_t workers_created_; | 
 |  | 
 |   base::WeakPtrFactory<ChannelIDService> weak_ptr_factory_; | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(ChannelIDService); | 
 | }; | 
 |  | 
 | }  // namespace net | 
 |  | 
 | #endif  // NET_SSL_CHANNEL_ID_SERVICE_H_ |