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 #include "chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_url_loader.h"
6
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/location.h"
10 #include "base/task/post_task.h"
11 #include "base/task/task_traits.h"
12 #include "base/threading/thread_task_runner_handle.h"
13 #include "content/public/browser/browser_task_traits.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/web_contents.h"
16 #include "net/base/load_flags.h"
17 #include "net/http/http_response_headers.h"
18 #include "net/http/http_util.h"
19 #include "net/traffic_annotation/network_traffic_annotation.h"
20 #include "services/network/public/cpp/resource_request.h"
21
PrefetchProxyURLLoader(const network::ResourceRequest & unused_request,const scoped_refptr<network::SharedURLLoaderFactory> & network_loader_factory,int32_t routing_id,int32_t request_id)22 PrefetchProxyURLLoader::PrefetchProxyURLLoader(
23 const network::ResourceRequest& unused_request,
24 const scoped_refptr<network::SharedURLLoaderFactory>&
25 network_loader_factory,
26 int32_t routing_id,
27 int32_t request_id)
28 : network_loader_factory_(network_loader_factory),
29 routing_id_(routing_id),
30 request_id_(request_id) {
31 // |unused_request| is not used since it has not been acted on by
32 // URLLoaderThrottles yet.
33 }
34
35 PrefetchProxyURLLoader::~PrefetchProxyURLLoader() = default;
36
37 PrefetchProxyURLLoader::RequestHandler
ServingResponseHandler()38 PrefetchProxyURLLoader::ServingResponseHandler() {
39 return base::BindOnce(&PrefetchProxyURLLoader::BindAndStart,
40 weak_ptr_factory_.GetWeakPtr());
41 }
42
BindAndStart(const network::ResourceRequest & request,mojo::PendingReceiver<network::mojom::URLLoader> receiver,mojo::PendingRemote<network::mojom::URLLoaderClient> forwarding_client)43 void PrefetchProxyURLLoader::BindAndStart(
44 const network::ResourceRequest& request,
45 mojo::PendingReceiver<network::mojom::URLLoader> receiver,
46 mojo::PendingRemote<network::mojom::URLLoaderClient> forwarding_client) {
47 // Bind to the underlying URLLoader.
48 DCHECK(!receiver_.is_bound());
49 receiver_.Bind(std::move(receiver));
50 receiver_.set_disconnect_handler(
51 base::BindOnce(&PrefetchProxyURLLoader::OnConnectionError,
52 weak_ptr_factory_.GetWeakPtr()));
53 forwarding_client_.Bind(std::move(forwarding_client));
54
55 network::ResourceRequest isolated_request = request;
56 // TODO(crbug/1023485): Set NIK, otherwise the loading initiated here will
57 // share the network stack with other browser-initiated loading.
58 isolated_request.load_flags = isolated_request.load_flags |
59 net::LOAD_DISABLE_CACHE | net::LOAD_PREFETCH;
60 isolated_request.credentials_mode = network::mojom::CredentialsMode::kOmit;
61
62 network_loader_factory_->CreateLoaderAndStart(
63 network_loader_.BindNewPipeAndPassReceiver(), routing_id_, request_id_,
64 network::mojom::kURLLoadOptionNone, isolated_request,
65 network_loader_client_.BindNewPipeAndPassRemote(
66 base::ThreadTaskRunnerHandle::Get()),
67 net::MutableNetworkTrafficAnnotationTag(
68 net::DefineNetworkTrafficAnnotation("prefetch_proxy_loader", R"(
69 semantics {
70 sender: "Prefetch Proxy Loader"
71 description:
72 "Loads a webpage resource during a proxied prefetch. This is a "
73 "prefetcher which is done in total isolation from other user "
74 "browsing data like cookies or cache state. Such prefetches "
75 "will be used to prefetch render-blocking content before being "
76 "navigated by the user without impacting privacy."
77 trigger:
78 "Used for sites off of Google SRPs (Search Result Pages) only "
79 "for Lite mode users when the feature is enabled."
80 data: "None."
81 destination: WEBSITE
82 }
83 policy {
84 cookies_allowed: YES
85 cookies_store: "An ephemeral cookie jar used for only 1 page load."
86 setting:
87 "Users can control Lite mode on Android via the settings menu. "
88 "Lite mode is not available on iOS, and on desktop only for "
89 "developer testing."
90 policy_exception_justification: "Not implemented."
91 })")));
92
93 network_loader_client_.set_disconnect_handler(base::BindOnce(
94 &PrefetchProxyURLLoader::OnConnectionError, base::Unretained(this)));
95 }
96
OnReceiveResponse(network::mojom::URLResponseHeadPtr head)97 void PrefetchProxyURLLoader::OnReceiveResponse(
98 network::mojom::URLResponseHeadPtr head) {
99 forwarding_client_->OnReceiveResponse(std::move(head));
100 }
101
OnReceiveRedirect(const net::RedirectInfo & redirect_info,network::mojom::URLResponseHeadPtr head)102 void PrefetchProxyURLLoader::OnReceiveRedirect(
103 const net::RedirectInfo& redirect_info,
104 network::mojom::URLResponseHeadPtr head) {
105 forwarding_client_->OnReceiveRedirect(redirect_info, std::move(head));
106 }
107
OnUploadProgress(int64_t current_position,int64_t total_size,OnUploadProgressCallback callback)108 void PrefetchProxyURLLoader::OnUploadProgress(
109 int64_t current_position,
110 int64_t total_size,
111 OnUploadProgressCallback callback) {
112 forwarding_client_->OnUploadProgress(current_position, total_size,
113 std::move(callback));
114 }
115
OnReceiveCachedMetadata(mojo_base::BigBuffer data)116 void PrefetchProxyURLLoader::OnReceiveCachedMetadata(
117 mojo_base::BigBuffer data) {
118 forwarding_client_->OnReceiveCachedMetadata(std::move(data));
119 }
120
OnTransferSizeUpdated(int32_t transfer_size_diff)121 void PrefetchProxyURLLoader::OnTransferSizeUpdated(int32_t transfer_size_diff) {
122 forwarding_client_->OnTransferSizeUpdated(transfer_size_diff);
123 }
124
OnStartLoadingResponseBody(mojo::ScopedDataPipeConsumerHandle body)125 void PrefetchProxyURLLoader::OnStartLoadingResponseBody(
126 mojo::ScopedDataPipeConsumerHandle body) {
127 forwarding_client_->OnStartLoadingResponseBody(std::move(body));
128 }
129
OnComplete(const network::URLLoaderCompletionStatus & status)130 void PrefetchProxyURLLoader::OnComplete(
131 const network::URLLoaderCompletionStatus& status) {
132 forwarding_client_->OnComplete(status);
133 }
134
FollowRedirect(const std::vector<std::string> & removed_headers,const net::HttpRequestHeaders & modified_headers,const net::HttpRequestHeaders & modified_cors_exempt_headers,const base::Optional<GURL> & new_url)135 void PrefetchProxyURLLoader::FollowRedirect(
136 const std::vector<std::string>& removed_headers,
137 const net::HttpRequestHeaders& modified_headers,
138 const net::HttpRequestHeaders& modified_cors_exempt_headers,
139 const base::Optional<GURL>& new_url) {
140 network_loader_->FollowRedirect(removed_headers, modified_headers,
141 modified_cors_exempt_headers, new_url);
142 }
143
SetPriority(net::RequestPriority priority,int32_t intra_priority_value)144 void PrefetchProxyURLLoader::SetPriority(net::RequestPriority priority,
145 int32_t intra_priority_value) {
146 network_loader_->SetPriority(priority, intra_priority_value);
147 }
148
PauseReadingBodyFromNet()149 void PrefetchProxyURLLoader::PauseReadingBodyFromNet() {
150 network_loader_->PauseReadingBodyFromNet();
151 }
152
ResumeReadingBodyFromNet()153 void PrefetchProxyURLLoader::ResumeReadingBodyFromNet() {
154 network_loader_->ResumeReadingBodyFromNet();
155 }
156
OnConnectionError()157 void PrefetchProxyURLLoader::OnConnectionError() {
158 network_loader_.reset();
159 network_loader_client_.reset();
160 receiver_.reset();
161 forwarding_client_.reset();
162 delete this;
163 }
164