1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef CHROME_BROWSER_PREFETCH_SEARCH_PREFETCH_SEARCH_PREFETCH_SERVICE_H_
6 #define CHROME_BROWSER_PREFETCH_SEARCH_PREFETCH_SEARCH_PREFETCH_SERVICE_H_
7 
8 #include <map>
9 
10 #include "base/callback.h"
11 #include "base/optional.h"
12 #include "base/scoped_observation.h"
13 #include "base/strings/string16.h"
14 #include "base/timer/timer.h"
15 #include "components/keyed_service/core/keyed_service.h"
16 #include "components/search_engines/template_url_data.h"
17 #include "components/search_engines/template_url_service.h"
18 #include "components/search_engines/template_url_service_observer.h"
19 #include "services/network/public/cpp/simple_url_loader.h"
20 #include "url/gurl.h"
21 
22 class Profile;
23 class GURL;
24 class PrefetchedResponseContainer;
25 
26 class AutocompleteController;
27 
28 enum class SearchPrefetchStatus {
29   // The request is on the network and may move to any other state.
30   kInFlight = 1,
31   // The request received all the data and is ready to serve.
32   kSuccessfullyCompleted = 2,
33   // The request hit an error and cannot be served.
34   kRequestFailed = 3,
35   // The request was cancelled before completion.
36   kRequestCancelled = 4,
37 };
38 
39 class SearchPrefetchService : public KeyedService,
40                               public TemplateURLServiceObserver {
41  public:
42   explicit SearchPrefetchService(Profile* profile);
43   ~SearchPrefetchService() override;
44 
45   SearchPrefetchService(const SearchPrefetchService&) = delete;
46   SearchPrefetchService& operator=(const SearchPrefetchService&) = delete;
47 
48   // KeyedService:
49   void Shutdown() override;
50 
51   // TemplateURLServiceObserver:
52   // Monitors changes to DSE. If a change occurs, clears prefetches.
53   void OnTemplateURLServiceChanged() override;
54 
55   // Called when |controller| has updated information.
56   void OnResultChanged(AutocompleteController* controller);
57 
58   // Returns whether the prefetch started or not.
59   bool MaybePrefetchURL(const GURL& url);
60 
61   // Clear all prefetches from the service.
62   void ClearPrefetches();
63 
64   // Takes the response from this object if |url| matches a prefetched URL.
65   std::unique_ptr<PrefetchedResponseContainer> TakePrefetchResponse(
66       const GURL& url);
67 
68   // Reports the status of a prefetch for a given search term.
69   base::Optional<SearchPrefetchStatus> GetSearchPrefetchStatusForTesting(
70       base::string16 search_terms);
71 
72  private:
73   // Removes the prefetch and prefetch timers associated with |search_terms|.
74   void DeletePrefetch(base::string16 search_terms);
75 
76   // Records the current time to prevent prefetches for a set duration.
77   void ReportError();
78 
79   // Internal class to represent an ongoing or completed prefetch.
80   class PrefetchRequest {
81    public:
82     // |service| must outlive this class and be able to manage this class's
83     // lifetime.
84     PrefetchRequest(const GURL& prefetch_url,
85                     base::OnceClosure report_error_callback);
86     ~PrefetchRequest();
87 
88     PrefetchRequest(const PrefetchRequest&) = delete;
89     PrefetchRequest& operator=(const PrefetchRequest&) = delete;
90 
91     // Starts the network request to prefetch |prefetch_url_|.
92     void StartPrefetchRequest(Profile* profile);
93 
94     // Cancels the on-going prefetch and marks the status appropriately.
95     void CancelPrefetch();
96 
current_status()97     SearchPrefetchStatus current_status() const { return current_status_; }
98 
prefetch_url()99     const GURL& prefetch_url() const { return prefetch_url_; }
100 
101     // Takes ownership of the prefetched data.
102     std::unique_ptr<PrefetchedResponseContainer> TakePrefetchResponse();
103 
104    private:
105     // Called as a callback when the prefetch request is complete. Stores the
106     // response and other metadata in |prefetch_response_container_|.
107     void LoadDone(std::unique_ptr<std::string> response_body);
108 
109     SearchPrefetchStatus current_status_ = SearchPrefetchStatus::kInFlight;
110 
111     // The URL to prefetch the search terms from.
112     const GURL prefetch_url_;
113 
114     // The ongoing prefetch request. Null before and after the fetch.
115     std::unique_ptr<network::SimpleURLLoader> simple_loader_;
116 
117     // Once a prefetch is completed successfully, the associated prefetch data
118     // and metadata about the request.
119     std::unique_ptr<PrefetchedResponseContainer> prefetch_response_container_;
120 
121     // Called when there is a network/server error on the prefetch request.
122     base::OnceClosure report_error_callback_;
123   };
124 
125   // Prefetches that are started are stored using search terms as a key. Only
126   // one prefetch should be started for a given search term until the old
127   // prefetch expires.
128   std::map<base::string16, std::unique_ptr<PrefetchRequest>> prefetches_;
129 
130   // A group of timers to expire |prefetches_| based on the same key.
131   std::map<base::string16, std::unique_ptr<base::OneShotTimer>>
132       prefetch_expiry_timers_;
133 
134   // The time of the last prefetch network/server error.
135   base::TimeTicks last_error_time_ticks_;
136 
137   // The current state of the DSE.
138   base::Optional<TemplateURLData> template_url_service_data_;
139 
140   base::ScopedObservation<TemplateURLService, TemplateURLServiceObserver>
141       observer_{this};
142 
143   Profile* profile_;
144 };
145 
146 #endif  // CHROME_BROWSER_PREFETCH_SEARCH_PREFETCH_SEARCH_PREFETCH_SERVICE_H_
147