| // Copyright 2017 The Chromium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #ifndef COMPONENTS_OMNIBOX_BROWSER_REMOTE_SUGGESTIONS_SERVICE_H_ | 
 | #define COMPONENTS_OMNIBOX_BROWSER_REMOTE_SUGGESTIONS_SERVICE_H_ | 
 |  | 
 | #include <map> | 
 | #include <memory> | 
 | #include <optional> | 
 | #include <string> | 
 |  | 
 | #include "base/functional/callback_forward.h" | 
 | #include "base/memory/scoped_refptr.h" | 
 | #include "base/memory/weak_ptr.h" | 
 | #include "base/observer_list.h" | 
 | #include "base/observer_list_types.h" | 
 | #include "base/time/time.h" | 
 | #include "base/timer/elapsed_timer.h" | 
 | #include "base/unguessable_token.h" | 
 | #include "components/keyed_service/core/keyed_service.h" | 
 | #include "components/omnibox/browser/autocomplete_input.h" | 
 | #include "components/omnibox/browser/autocomplete_match.h" | 
 | #include "components/omnibox/browser/enterprise_search_aggregator_suggestions_service.h" | 
 | #include "components/search_engines/template_url.h" | 
 | #include "net/traffic_annotation/network_traffic_annotation.h" | 
 | #include "url/gurl.h" | 
 |  | 
 | class DocumentSuggestionsService; | 
 | class EnterpriseSearchAggregatorSuggestionsService; | 
 |  | 
 | using EnterpriseSearchAggregatorSuggestionType = | 
 |     AutocompleteMatch::EnterpriseSearchAggregatorType; | 
 |  | 
 | namespace network { | 
 | class SharedURLLoaderFactory; | 
 | class SimpleURLLoader; | 
 | struct ResourceRequest; | 
 | }  // namespace network | 
 |  | 
 | // The types of requests for remote suggestions. | 
 | // These values are written to logs. New enum values can be added, but existing | 
 | // enums must never be renumbered or deleted and reused. | 
 | // Must be kept in sync with RemoteRequestType enum and variant. | 
 | // LINT.IfChange(RemoteRequestType) | 
 | enum class RemoteRequestType { | 
 |   // Search suggestion requests. | 
 |   kSearch = 0, | 
 |   // Search suggestion warm-up requests. | 
 |   kSearchWarmup = 1, | 
 |   // Search suggestion requests to obtain images. | 
 |   kImages = 2, | 
 |   // Zero-prefix suggestion requests. | 
 |   kZeroSuggest = 3, | 
 |   // Zero-prefix suggestion prefetching requests. | 
 |   kZeroSuggestPrefetch = 4, | 
 |   // Document suggestion requests. | 
 |   kDocumentSuggest = 5, | 
 |   // Suggestion deletion requests. | 
 |   kDeletion = 6, | 
 |   // Enterprise Search Aggregator suggestion requests. | 
 |   kEnterpriseSearchAggregatorSuggest = 7, | 
 |   kMaxValue = kEnterpriseSearchAggregatorSuggest, | 
 | }; | 
 | // LINT.ThenChange( | 
 | //     //tools/metrics/histograms/metadata/omnibox/enums.xml:RemoteRequestType, | 
 | //     //tools/metrics/histograms/metadata/omnibox/histograms.xml:RemoteRequestType | 
 | // ) | 
 |  | 
 | // The event types recorded by the providers for remote suggestions. Each event | 
 | // must be logged at most once from when the provider is started until it is | 
 | // stopped. | 
 | // These values are written to logs. New enum values can be added, but existing | 
 | // enums must never be renumbered or deleted and reused. | 
 | enum class RemoteRequestEvent { | 
 |   // Cached response was synchronously converted to displayed matches. | 
 |   // Recorded for non-prefetch requests only. | 
 |   kCachedResponseConvertedToMatches = 0, | 
 |   // Request was sent. | 
 |   kRequestSent = 1, | 
 |   // Request was invalidated. | 
 |   kRequestInvalidated = 2, | 
 |   // Response was received asynchronously. | 
 |   kResponseReceived = 3, | 
 |   // Response was cached. | 
 |   kResponseCached = 4, | 
 |   // Response ended up being converted to displayed matches. This may happen due | 
 |   // to an empty displayed result set or an empty remote result set. | 
 |   // Recorded for non-prefetch requests only. | 
 |   kResponseConvertedToMatches = 5, | 
 |   kMaxValue = kResponseConvertedToMatches, | 
 | }; | 
 |  | 
 | // A service to fetch suggestions from a search provider's suggest endpoint. | 
 | // Used by ZeroSuggestProvider, SearchProvider, DocumentProvider, and | 
 | // ImageService. | 
 | // | 
 | // This service is always sent the user's authentication state, so the | 
 | // suggestions always can be personalized. This service is also sometimes sent | 
 | // the user's current URL, so the suggestions are sometimes also contextual. | 
 | class RemoteSuggestionsService : public KeyedService { | 
 |  public: | 
 |   class Observer : public base::CheckedObserver { | 
 |    public: | 
 |     // Called when the request has been created. `request_id` identifies the | 
 |     // request. `request` is deleted after this call once the transfer starts. | 
 |     virtual void OnRequestCreated(const base::UnguessableToken& request_id, | 
 |                                   const network::ResourceRequest* request) {} | 
 |     // Called when the transfer has started. `request_id` identifies the | 
 |     // request. `request_body` is the HTTP POST upload body, if applicable. | 
 |     virtual void OnRequestStarted(const base::UnguessableToken& request_id, | 
 |                                   network::SimpleURLLoader* loader, | 
 |                                   const std::string& request_body) {} | 
 |     // Called when the transfer is done. `request_id` identifies the request. | 
 |     // `response_code` is the response status code. A status code of 200 | 
 |     // indicates that the request has succeeded and `response_body` is | 
 |     // populated. | 
 |     virtual void OnRequestCompleted( | 
 |         const base::UnguessableToken& request_id, | 
 |         const int response_code, | 
 |         const std::unique_ptr<std::string>& response_body) {} | 
 |   }; | 
 |  | 
 |   // Called when the transfer has started asynchronously, e.g., after obtaining | 
 |   // an OAuth token. | 
 |   using StartCallback = base::OnceCallback<void( | 
 |       std::unique_ptr<network::SimpleURLLoader> loader)>; | 
 |   // Called when the transfer is done. `response_code` is the response status | 
 |   // code. A status code of 200 indicates that the request has succeeded and | 
 |   // `response_body` is populated. | 
 |   using CompletionCallback = | 
 |       base::OnceCallback<void(const network::SimpleURLLoader* source, | 
 |                               const int response_code, | 
 |                               std::unique_ptr<std::string> response_body)>; | 
 |   // Same as `StartCallback` but for requests that are associated with a | 
 |   // `request_index`. | 
 |   using IndexedStartCallback = base::RepeatingCallback<void( | 
 |       const int request_index, | 
 |       std::unique_ptr<network::SimpleURLLoader> loader)>; | 
 |   // Same as `CompletionCallback` but for requests that are associated with a | 
 |   // `request_index`. | 
 |   using IndexedCompletionCallback = | 
 |       base::RepeatingCallback<void(const int request_index, | 
 |                                    const network::SimpleURLLoader* source, | 
 |                                    const int response_code, | 
 |                                    std::unique_ptr<std::string> response_body)>; | 
 |  | 
 |   class Delegate { | 
 |    public: | 
 |     Delegate(); | 
 |     virtual ~Delegate(); | 
 |     Delegate(const Delegate&) = delete; | 
 |     Delegate& operator=(const Delegate&) = delete; | 
 |  | 
 |     // Called when the transfer is done. Delegates invocation of | 
 |     // `completion_callback` | 
 |     virtual void OnRequestCompleted(const network::SimpleURLLoader* source, | 
 |                                     const int response_code, | 
 |                                     std::unique_ptr<std::string> response_body, | 
 |                                     CompletionCallback completion_callback) = 0; | 
 |  | 
 |     virtual void OnIndexedRequestCompleted( | 
 |         const int request_index, | 
 |         const network::SimpleURLLoader* source, | 
 |         const int response_code, | 
 |         std::unique_ptr<std::string> response_body, | 
 |         IndexedCompletionCallback completion_callback) = 0; | 
 |  | 
 |    protected: | 
 |     base::WeakPtrFactory<Delegate> weak_ptr_factory_{this}; | 
 |   }; | 
 |  | 
 |   RemoteSuggestionsService( | 
 |       DocumentSuggestionsService* document_suggestions_service, | 
 |       EnterpriseSearchAggregatorSuggestionsService* | 
 |           enterprise_search_aggregator_suggestions_service, | 
 |       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory); | 
 |   ~RemoteSuggestionsService() override; | 
 |   RemoteSuggestionsService(const RemoteSuggestionsService&) = delete; | 
 |   RemoteSuggestionsService& operator=(const RemoteSuggestionsService&) = delete; | 
 |  | 
 |   // Helper to set the time request of type `request_type` has started in | 
 |   // `time_request_sent_`. | 
 |   void SetTimeRequestSent(RemoteRequestType request_type, base::TimeTicks time); | 
 |  | 
 |   // Returns the suggest endpoint URL for `template_url`. | 
 |   // `search_terms_args` is used to build the endpoint URL. | 
 |   // `search_terms_data` is used to build the endpoint URL. | 
 |   static GURL EndpointUrl( | 
 |       const TemplateURL& template_url, | 
 |       const TemplateURLRef::SearchTermsArgs& search_terms_args, | 
 |       const SearchTermsData& search_terms_data); | 
 |  | 
 |   // Creates and returns a loader for remote suggestions for `template_url`. | 
 |   // It uses a number of signals to create the loader, including field trial | 
 |   // parameters. | 
 |   // | 
 |   // `template_url` must not be nullptr. | 
 |   // `search_terms_args` is used to build the endpoint URL. | 
 |   // `search_terms_data` is used to build the endpoint URL. | 
 |   // `completion_callback` will be invoked when the transfer is done. | 
 |   std::unique_ptr<network::SimpleURLLoader> StartSuggestionsRequest( | 
 |       RemoteRequestType request_type, | 
 |       bool is_off_the_record, | 
 |       const TemplateURL* template_url, | 
 |       TemplateURLRef::SearchTermsArgs search_terms_args, | 
 |       const SearchTermsData& search_terms_data, | 
 |       CompletionCallback completion_callback); | 
 |  | 
 |   // Creates and returns a loader for remote zero-prefix suggestions for | 
 |   // `template_url`. It uses a number of signals to create the loader, including | 
 |   // field trial parameters. | 
 |   // | 
 |   // `template_url` must not be nullptr. | 
 |   // `search_terms_args` is used to build the endpoint URL. | 
 |   // `search_terms_data` is used to build the endpoint URL. | 
 |   // `completion_callback` will be invoked when the transfer is done. | 
 |   std::unique_ptr<network::SimpleURLLoader> StartZeroPrefixSuggestionsRequest( | 
 |       RemoteRequestType request_type, | 
 |       bool is_off_the_record, | 
 |       const TemplateURL* template_url, | 
 |       TemplateURLRef::SearchTermsArgs search_terms_args, | 
 |       const SearchTermsData& search_terms_data, | 
 |       CompletionCallback completion_callback); | 
 |  | 
 |   // Creates and starts a document suggestion request for `query` asynchronously | 
 |   // after obtaining an OAuth2 token for the signed-in users. | 
 |   void CreateDocumentSuggestionsRequest( | 
 |       const std::u16string& query, | 
 |       bool is_off_the_record, | 
 |       metrics::OmniboxEventProto::PageClassification page_classification, | 
 |       StartCallback start_callback, | 
 |       CompletionCallback completion_callback); | 
 |  | 
 |   // Stops creating the request. Already created requests aren't affected. | 
 |   void StopCreatingDocumentSuggestionsRequest(); | 
 |  | 
 |   // Creates and starts an enterprise search aggregator suggestion request using | 
 |   //  `suggest_url` and `response_body` asynchronously after obtaining an OAuth2 | 
 |   //  token for signed-in enterprise users. | 
 |   void CreateEnterpriseSearchAggregatorSuggestionsRequest( | 
 |       const std::u16string& query, | 
 |       const GURL& suggest_url, | 
 |       metrics::OmniboxEventProto::PageClassification page_classification, | 
 |       std::vector<int> callback_indexes, | 
 |       std::vector<std::vector<int>> suggestion_types, | 
 |       IndexedStartCallback start_callback, | 
 |       IndexedCompletionCallback completion_callback); | 
 |  | 
 |   // Stops creating the request. Already created requests aren't affected. | 
 |   void StopCreatingEnterpriseSearchAggregatorSuggestionsRequest(); | 
 |  | 
 |   // Creates and returns a loader to delete personalized suggestions. | 
 |   // | 
 |   // `deletion_url` must be a valid URL. | 
 |   // `completion_callback` will be invoked when the transfer is done. | 
 |   std::unique_ptr<network::SimpleURLLoader> StartDeletionRequest( | 
 |       const std::string& deletion_url, | 
 |       bool is_off_the_record, | 
 |       CompletionCallback completion_callback); | 
 |  | 
 |   void AddObserver(Observer* observer); | 
 |   void RemoveObserver(Observer* observer); | 
 |  | 
 |   void SetDelegate(base::WeakPtr<Delegate> delegate); | 
 |  | 
 |   // Exposed for testing. | 
 |   void set_url_loader_factory_for_testing( | 
 |       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory); | 
 |  | 
 |  private: | 
 |   // Called when the request has been created, before the transfer has started. | 
 |   // Notifies `observers_`. | 
 |   void OnRequestCreated(const base::UnguessableToken& request_id, | 
 |                         network::ResourceRequest* request); | 
 |   // Called when the transfer has started. Notifies `observers_`. | 
 |   void OnRequestStarted( | 
 |       const base::UnguessableToken& request_id, | 
 |       RemoteRequestType request_type, | 
 |       metrics::OmniboxEventProto::PageClassification page_classification, | 
 |       network::SimpleURLLoader* loader, | 
 |       const std::string& request_body); | 
 |   // Called when the transfer has started asynchronously, e.g., after obtaining | 
 |   // an OAuth token. Notifies `observers_` and calls `start_callback` to | 
 |   // transfer the ownership of `loader` to the caller. | 
 |   void OnRequestStartedAsync( | 
 |       const base::UnguessableToken& request_id, | 
 |       RemoteRequestType request_type, | 
 |       metrics::OmniboxEventProto::PageClassification page_classification, | 
 |       StartCallback start_callback, | 
 |       std::unique_ptr<network::SimpleURLLoader> loader, | 
 |       const std::string& request_body); | 
 |   void OnIndexedRequestStartedAsync( | 
 |       const base::UnguessableToken& request_id, | 
 |       RemoteRequestType request_type, | 
 |       metrics::OmniboxEventProto::PageClassification page_classification, | 
 |       IndexedStartCallback start_callback, | 
 |       int request_index, | 
 |       std::unique_ptr<network::SimpleURLLoader> loader, | 
 |       const std::string& request_body); | 
 |   // Called when the transfer is done. Notifies `observers_` and calls | 
 |   // `completion_callback` passing the response to the caller. | 
 |   void OnRequestCompleted( | 
 |       const base::UnguessableToken& request_id, | 
 |       RemoteRequestType request_type, | 
 |       base::ElapsedTimer request_timer, | 
 |       metrics::OmniboxEventProto::PageClassification page_classification, | 
 |       CompletionCallback completion_callback, | 
 |       const network::SimpleURLLoader* source, | 
 |       std::unique_ptr<std::string> response_body); | 
 |  | 
 |   void OnIndexedRequestCompleted( | 
 |       const base::UnguessableToken& request_id, | 
 |       RemoteRequestType request_type, | 
 |       metrics::OmniboxEventProto::PageClassification page_classification, | 
 |       base::TimeTicks start_time, | 
 |       IndexedCompletionCallback completion_callback, | 
 |       const network::SimpleURLLoader* source, | 
 |       int request_index, | 
 |       std::unique_ptr<std::string> response_body); | 
 |  | 
 |   // May be nullptr in OTR profiles. Otherwise guaranteed to outlive this due to | 
 |   // the factories' dependency. | 
 |   raw_ptr<DocumentSuggestionsService> document_suggestions_service_; | 
 |   // May be nullptr in OTR profiles. Otherwise guaranteed to outlive this due to | 
 |   // the factories' dependency. | 
 |   raw_ptr<EnterpriseSearchAggregatorSuggestionsService> | 
 |       enterprise_search_aggregator_suggestions_service_; | 
 |   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; | 
 |   // Time request sent for each RemoteRequestType. Used for histogram logging. | 
 |   std::map<RemoteRequestType, base::TimeTicks> time_request_sent_; | 
 |   // Observers being notified of request start and completion events. | 
 |   base::ObserverList<Observer> observers_; | 
 |   // Delegate to which invocation of completion callback is delegated. | 
 |   base::WeakPtr<Delegate> delegate_; | 
 |   // Used to bind `OnURLLoadComplete` to the network loader's callback as the | 
 |   // loader is no longer owned by `this` once returned. | 
 |   base::WeakPtrFactory<RemoteSuggestionsService> weak_ptr_factory_{this}; | 
 | }; | 
 |  | 
 | #endif  // COMPONENTS_OMNIBOX_BROWSER_REMOTE_SUGGESTIONS_SERVICE_H_ |