blob: 7d66b30b6a535f1a98d3b2183099682fcb2dbb73 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PRELOADING_PREFETCH_SEARCH_PREFETCH_SEARCH_PREFETCH_REQUEST_H_
#define CHROME_BROWSER_PRELOADING_PREFETCH_SEARCH_PREFETCH_SEARCH_PREFETCH_REQUEST_H_
#include <memory>
#include "base/functional/callback.h"
#include "chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_url_loader.h"
#include "services/network/public/cpp/resource_request.h"
#include "url/gurl.h"
class PrerenderManager;
class Profile;
class StreamingSearchPrefetchURLLoader;
namespace content {
class PreloadingAttempt;
enum class PreloadingTriggeringOutcome;
enum class PreloadingFailureReason;
} // namespace content
namespace net {
struct NetworkTrafficAnnotationTag;
} // namespace net
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
// Any updates to this class need to be propagated to enums.xml.
enum class SearchPrefetchStatus {
// The request has not started yet. This status should ideally never be
// recorded as Start() should be called on the same stack as creating the
// fetcher (as of now).
kNotStarted = 0,
// The request is on the network and may move to any other state. Removed
// after https://crbug.com/40217275 is implemented.
// kInFlight = 1,
// The request can be served to the navigation stack, but may still encounter
// errors and move to |kRequestFailed| or it may complete and move to
// |kComplete|.
kCanBeServed = 2,
// Obsolete: After updating the cancellation logic, we no longer need this
// status to prevent a clicked prefetch from being deleted.
// kCanBeServedAndUserClicked = 3,
// The request can be served to the navigation stack, and has fully streamed
// the response with no errors.
kComplete = 4,
// The request hit an error and cannot be served.
kRequestFailed = 5,
// Obsolete: After updating the cancellation logic, we no longer cancel
// in-flight prefetch requests on autocomplete result changed.
// kRequestCancelled = 6,
kPrefetchServedForRealNavigation = 7,
// Obsolete: Now search prefetch requests are reusable, i.e., can be served to
// both real navigation and prerender navigation, so we no longer track these
// statuses.
// kPrerendered = 8,
// kPrerenderedAndClicked = 9,
// kPrerenderActivated = 10,
kMaxValue = kPrefetchServedForRealNavigation,
};
// A class representing a prefetch used by the Search Prefetch Service.
// It plays the following roles to support search preloading.
// - Preparing a resource request to prefetch a search page.
// - Starting prerendering upon the request succeeding to upgrade prefetch to
// prerender after the Search Prefetch Service tells it that the prefetched
// term is prerenderable.
// - A container for a StreamingSearchPrefetchURLLoader, to support
// |TakeSearchPrefetchURLLoader()|
// more easily.
class SearchPrefetchRequest {
public:
SearchPrefetchRequest(const GURL& canonical_search_url,
const GURL& prefetch_url,
bool navigation_prefetch,
content::PreloadingAttempt* prefetch_preloading_attempt,
base::OnceCallback<void(bool)> report_error_callback);
~SearchPrefetchRequest();
SearchPrefetchRequest(const SearchPrefetchRequest&) = delete;
SearchPrefetchRequest& operator=(const SearchPrefetchRequest&) = delete;
// The NTA for any search prefetch request.
static net::NetworkTrafficAnnotationTag NetworkAnnotationForPrefetch();
// Starts the network request to prefetch `prefetch_url_`. Sets various fields
// on a resource request. Returns `false` if the request is not started (i.e.,
// it would be deferred by throttles).
bool StartPrefetchRequest(Profile* profile);
// Called when SearchPrefetchService receives the hint that this prefetch
// request can be upgraded to a prerender attempt.
void MaybeStartPrerenderSearchResult(PrerenderManager& prerender_manager,
const GURL& prerender_url,
content::PreloadingAttempt& attempt);
// Called when the prefetch encounters an error.
void ErrorEncountered();
// Called on the URL loader receives servable response.
void OnServableResponseCodeReceived();
// Update the status when the request is complete.
void MarkPrefetchAsComplete();
// Update the status when the request is actually served to the navigation
// stack of a real navigation request.
void MarkPrefetchAsServed();
// Called when AutocompleteMatches changes. It resets PrerenderUpgrader.
// And if the AutocompleteMatches suggests to prerender a search result,
// `MaybeStartPrerenderSearchResult` will be called soon.
void ResetPrerenderUpgrader();
// Record the time at which the user clicked a suggestion matching this
// prefetch.
void RecordClickTime();
// Takes ownership of underlying data/objects needed to serve the response.
scoped_refptr<StreamingSearchPrefetchURLLoader> TakeSearchPrefetchURLLoader();
// Instead of completely letting a navigation stack own the prefetch loader,
// creates a copy of the prefetched response so that it can be shared among
// different clients.
// Note: This method should be called after the response reader received
// response headers.
SearchPrefetchURLLoader::RequestHandler CreateResponseReader();
// Whether the request was started as a navigation prefetch (as opposed to a
// suggestion prefetch).
bool navigation_prefetch() const { return navigation_prefetch_; }
SearchPrefetchStatus current_status() const { return current_status_; }
const GURL& prefetch_url() const { return prefetch_url_; }
// Sets `prefetch_preloading_attempt_` PreloadingFailureReason to `reason` if
// exists.
void SetPrefetchAttemptFailureReason(content::PreloadingFailureReason reason);
// Tells StreamingSearchPrefetchURLLoader to run the callback upon
// destruction.
void SetLoaderDestructionCallbackForTesting(
base::OnceClosure streaming_url_loader_destruction_callback);
private:
// Stops the on-going prefetch and should mark |current_status_|
// appropriately.
void StopPrefetch();
// Cancels ongoing and pending prerender.
void StopPrerender();
// Updates the `current_status_` to status.
void SetSearchPrefetchStatus(SearchPrefetchStatus status);
// Sets the PreloadingTriggeringOutcome for `prefetch_preloading_attempt_` to
// `outcome`.
void SetPrefetchAttemptTriggeringOutcome(
content::PreloadingTriggeringOutcome outcome);
// Whether the request has received a servable response. See
// `CanServePrefetchRequest` in ./streaming_search_prefetch_url_loader.cc for
// the definition of servable response.
bool servable_response_code_received_ = false;
SearchPrefetchStatus current_status_ = SearchPrefetchStatus::kNotStarted;
// The canonical representation of the search suggestion including query,
// intent, and extra parameters that can alter the Search page.
const GURL canonical_search_url_;
// The URL to prefetch the search terms from.
GURL prefetch_url_;
// The URL to prerender the search terms from.
// `prerender_url_` can be different from `prefetch_url_`. The latter is used
// to send network requests, so it may contain a special parameter for the
// server to recognize that it is a prefetch request, but the former does not
// send network requests, i.e. this parameter is not required.
GURL prerender_url_;
// Whether this is for a navigation-time prefetch.
bool navigation_prefetch_;
// The ongoing prefetch request. Null before and after the fetch.
scoped_refptr<StreamingSearchPrefetchURLLoader> streaming_url_loader_;
// Once set, this is used to log the metrics corresponding to the prefetch
// attempt. Please note this is different from `prerender_preloading_attempt_`
// which is for corresponding prerender attempt. We store the WeakPtr because
// it is possible that the PreloadingAttempt can be deleted (on navigation) or
// not created (when no WebContents is present) before search prefetch uses
// it.
base::WeakPtr<content::PreloadingAttempt> prefetch_preloading_attempt_;
// Called when there is a network/server error on the prefetch request.
base::OnceCallback<void(bool)> report_error_callback_;
base::TimeTicks time_start_prefetch_request_;
// The time at which the prefetched URL was clicked in the Omnibox.
base::TimeTicks time_clicked_;
// Once set, this request will trigger search prerender upon receiving success
// response.
base::WeakPtr<PrerenderManager> prerender_manager_;
// Once set, this PreloadingAttempt corresponding to prerender attempt will be
// passed to log various metrics. We store WeakPtr as prerender can be deleted
// before we receive a prefetch response or the prerender is not created.
base::WeakPtr<content::PreloadingAttempt> prerender_preloading_attempt_;
};
// Used when DCHECK_STATE_TRANSITION triggers.
std::ostream& operator<<(std::ostream& o, const SearchPrefetchStatus& s);
#endif // CHROME_BROWSER_PRELOADING_PREFETCH_SEARCH_PREFETCH_SEARCH_PREFETCH_REQUEST_H_