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