1 // Copyright 2019 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 "content/renderer/loader/resource_load_stats.h"
6
7 #include "base/bind.h"
8 #include "base/metrics/histogram_macros.h"
9 #include "content/common/net/record_load_histograms.h"
10 #include "content/renderer/render_frame_impl.h"
11 #include "content/renderer/render_thread_impl.h"
12 #include "net/base/ip_endpoint.h"
13 #include "net/url_request/redirect_info.h"
14 #include "services/network/public/cpp/url_loader_completion_status.h"
15 #include "services/network/public/mojom/fetch_api.mojom.h"
16 #include "services/network/public/mojom/url_response_head.mojom.h"
17 #include "third_party/blink/public/common/loader/resource_type_util.h"
18 #include "third_party/blink/public/mojom/loader/resource_load_info.mojom.h"
19
20 namespace content {
21
22 namespace {
23
24 // Returns true if the headers indicate that this resource should always be
25 // revalidated or not cached.
AlwaysAccessNetwork(const scoped_refptr<net::HttpResponseHeaders> & headers)26 bool AlwaysAccessNetwork(
27 const scoped_refptr<net::HttpResponseHeaders>& headers) {
28 if (!headers)
29 return false;
30
31 // RFC 2616, section 14.9.
32 return headers->HasHeaderValue("cache-control", "no-cache") ||
33 headers->HasHeaderValue("cache-control", "no-store") ||
34 headers->HasHeaderValue("pragma", "no-cache") ||
35 headers->HasHeaderValue("vary", "*");
36 }
37
38 #if defined(OS_ANDROID)
UpdateUserGestureCarryoverInfo(int render_frame_id)39 void UpdateUserGestureCarryoverInfo(int render_frame_id) {
40 RenderFrameImpl* frame = RenderFrameImpl::FromRoutingID(render_frame_id);
41 if (frame)
42 frame->GetFrameHost()->UpdateUserGestureCarryoverInfo();
43 }
44 #endif
45
ResourceResponseReceived(int render_frame_id,int request_id,const GURL & response_url,network::mojom::URLResponseHeadPtr response_head,network::mojom::RequestDestination destination,PreviewsState previews_state)46 void ResourceResponseReceived(int render_frame_id,
47 int request_id,
48 const GURL& response_url,
49 network::mojom::URLResponseHeadPtr response_head,
50 network::mojom::RequestDestination destination,
51 PreviewsState previews_state) {
52 RenderFrameImpl* frame = RenderFrameImpl::FromRoutingID(render_frame_id);
53 if (!frame)
54 return;
55 if (!blink::IsRequestDestinationFrame(destination)) {
56 frame->GetFrameHost()->SubresourceResponseStarted(
57 response_url, response_head->cert_status);
58 }
59 frame->DidStartResponse(response_url, request_id, std::move(response_head),
60 destination, previews_state);
61 }
62
ResourceTransferSizeUpdated(int render_frame_id,int request_id,int transfer_size_diff)63 void ResourceTransferSizeUpdated(int render_frame_id,
64 int request_id,
65 int transfer_size_diff) {
66 RenderFrameImpl* frame = RenderFrameImpl::FromRoutingID(render_frame_id);
67 if (frame)
68 frame->DidReceiveTransferSizeUpdate(request_id, transfer_size_diff);
69 }
70
ResourceLoadCompleted(int render_frame_id,blink::mojom::ResourceLoadInfoPtr resource_load_info,const network::URLLoaderCompletionStatus & status)71 void ResourceLoadCompleted(int render_frame_id,
72 blink::mojom::ResourceLoadInfoPtr resource_load_info,
73 const network::URLLoaderCompletionStatus& status) {
74 RenderFrameImpl* frame = RenderFrameImpl::FromRoutingID(render_frame_id);
75 if (!frame)
76 return;
77 frame->DidCompleteResponse(resource_load_info->request_id, status);
78 frame->GetFrameHost()->ResourceLoadComplete(std::move(resource_load_info));
79 }
80
ResourceLoadCanceled(int render_frame_id,int request_id)81 void ResourceLoadCanceled(int render_frame_id, int request_id) {
82 RenderFrameImpl* frame = RenderFrameImpl::FromRoutingID(render_frame_id);
83 if (frame)
84 frame->DidCancelResponse(request_id);
85 }
86
87 } // namespace
88
89 #if defined(OS_ANDROID)
NotifyUpdateUserGestureCarryoverInfo(int render_frame_id)90 void NotifyUpdateUserGestureCarryoverInfo(int render_frame_id) {
91 auto task_runner = RenderThreadImpl::DeprecatedGetMainTaskRunner();
92 if (!task_runner)
93 return;
94 if (task_runner->BelongsToCurrentThread()) {
95 UpdateUserGestureCarryoverInfo(render_frame_id);
96 return;
97 }
98 task_runner->PostTask(
99 FROM_HERE,
100 base::BindOnce(UpdateUserGestureCarryoverInfo, render_frame_id));
101 }
102 #endif
103
NotifyResourceLoadInitiated(int render_frame_id,int request_id,const GURL & request_url,const std::string & http_method,const GURL & referrer,network::mojom::RequestDestination request_destination,net::RequestPriority request_priority)104 blink::mojom::ResourceLoadInfoPtr NotifyResourceLoadInitiated(
105 int render_frame_id,
106 int request_id,
107 const GURL& request_url,
108 const std::string& http_method,
109 const GURL& referrer,
110 network::mojom::RequestDestination request_destination,
111 net::RequestPriority request_priority) {
112 auto resource_load_info = blink::mojom::ResourceLoadInfo::New();
113 resource_load_info->method = http_method;
114 resource_load_info->original_url = request_url;
115 resource_load_info->final_url = request_url;
116 resource_load_info->request_destination = request_destination;
117 resource_load_info->request_id = request_id;
118 resource_load_info->referrer = referrer;
119 resource_load_info->network_info = blink::mojom::CommonNetworkInfo::New();
120 resource_load_info->request_priority = request_priority;
121 return resource_load_info;
122 }
123
NotifyResourceRedirectReceived(int render_frame_id,blink::mojom::ResourceLoadInfo * resource_load_info,const net::RedirectInfo & redirect_info,network::mojom::URLResponseHeadPtr redirect_response)124 void NotifyResourceRedirectReceived(
125 int render_frame_id,
126 blink::mojom::ResourceLoadInfo* resource_load_info,
127 const net::RedirectInfo& redirect_info,
128 network::mojom::URLResponseHeadPtr redirect_response) {
129 resource_load_info->final_url = redirect_info.new_url;
130 resource_load_info->method = redirect_info.new_method;
131 resource_load_info->referrer = GURL(redirect_info.new_referrer);
132 blink::mojom::RedirectInfoPtr net_redirect_info =
133 blink::mojom::RedirectInfo::New();
134 net_redirect_info->origin_of_new_url =
135 url::Origin::Create(redirect_info.new_url);
136 net_redirect_info->network_info = blink::mojom::CommonNetworkInfo::New();
137 net_redirect_info->network_info->network_accessed =
138 redirect_response->network_accessed;
139 net_redirect_info->network_info->always_access_network =
140 AlwaysAccessNetwork(redirect_response->headers);
141 net_redirect_info->network_info->remote_endpoint =
142 redirect_response->remote_endpoint;
143 resource_load_info->redirect_info_chain.push_back(
144 std::move(net_redirect_info));
145 }
146
NotifyResourceResponseReceived(int render_frame_id,blink::mojom::ResourceLoadInfo * resource_load_info,network::mojom::URLResponseHeadPtr response_head,PreviewsState previews_state)147 void NotifyResourceResponseReceived(
148 int render_frame_id,
149 blink::mojom::ResourceLoadInfo* resource_load_info,
150 network::mojom::URLResponseHeadPtr response_head,
151 PreviewsState previews_state) {
152 if (response_head->network_accessed) {
153 if (resource_load_info->request_destination ==
154 network::mojom::RequestDestination::kDocument) {
155 UMA_HISTOGRAM_ENUMERATION("Net.ConnectionInfo.MainFrame",
156 response_head->connection_info,
157 net::HttpResponseInfo::NUM_OF_CONNECTION_INFOS);
158 } else {
159 UMA_HISTOGRAM_ENUMERATION("Net.ConnectionInfo.SubResource",
160 response_head->connection_info,
161 net::HttpResponseInfo::NUM_OF_CONNECTION_INFOS);
162 }
163 }
164
165 resource_load_info->mime_type = response_head->mime_type;
166 resource_load_info->load_timing_info = response_head->load_timing;
167 resource_load_info->network_info->network_accessed =
168 response_head->network_accessed;
169 resource_load_info->network_info->always_access_network =
170 AlwaysAccessNetwork(response_head->headers);
171 resource_load_info->network_info->remote_endpoint =
172 response_head->remote_endpoint;
173
174 auto task_runner = RenderThreadImpl::DeprecatedGetMainTaskRunner();
175 if (!task_runner)
176 return;
177 if (task_runner->BelongsToCurrentThread()) {
178 ResourceResponseReceived(
179 render_frame_id, resource_load_info->request_id,
180 resource_load_info->final_url, std::move(response_head),
181 resource_load_info->request_destination, previews_state);
182 return;
183 }
184
185 // Make a deep copy of URLResponseHead before passing it cross-thread.
186 if (response_head->headers) {
187 response_head->headers =
188 new net::HttpResponseHeaders(response_head->headers->raw_headers());
189 }
190 task_runner->PostTask(
191 FROM_HERE,
192 base::BindOnce(ResourceResponseReceived, render_frame_id,
193 resource_load_info->request_id,
194 resource_load_info->final_url, std::move(response_head),
195 resource_load_info->request_destination, previews_state));
196 }
197
NotifyResourceTransferSizeUpdated(int render_frame_id,blink::mojom::ResourceLoadInfo * resource_load_info,int transfer_size_diff)198 void NotifyResourceTransferSizeUpdated(
199 int render_frame_id,
200 blink::mojom::ResourceLoadInfo* resource_load_info,
201 int transfer_size_diff) {
202 auto task_runner = RenderThreadImpl::DeprecatedGetMainTaskRunner();
203 if (!task_runner)
204 return;
205 if (task_runner->BelongsToCurrentThread()) {
206 ResourceTransferSizeUpdated(render_frame_id, resource_load_info->request_id,
207 transfer_size_diff);
208 return;
209 }
210 task_runner->PostTask(
211 FROM_HERE,
212 base::BindOnce(ResourceTransferSizeUpdated, render_frame_id,
213 resource_load_info->request_id, transfer_size_diff));
214 }
215
NotifyResourceLoadCompleted(int render_frame_id,blink::mojom::ResourceLoadInfoPtr resource_load_info,const network::URLLoaderCompletionStatus & status)216 void NotifyResourceLoadCompleted(
217 int render_frame_id,
218 blink::mojom::ResourceLoadInfoPtr resource_load_info,
219 const network::URLLoaderCompletionStatus& status) {
220 RecordLoadHistograms(url::Origin::Create(resource_load_info->final_url),
221 resource_load_info->request_destination,
222 status.error_code);
223
224 resource_load_info->was_cached = status.exists_in_cache;
225 resource_load_info->net_error = status.error_code;
226 resource_load_info->total_received_bytes = status.encoded_data_length;
227 resource_load_info->raw_body_bytes = status.encoded_body_length;
228
229 auto task_runner = RenderThreadImpl::DeprecatedGetMainTaskRunner();
230 if (!task_runner)
231 return;
232 if (task_runner->BelongsToCurrentThread()) {
233 ResourceLoadCompleted(render_frame_id, std::move(resource_load_info),
234 status);
235 return;
236 }
237 task_runner->PostTask(FROM_HERE,
238 base::BindOnce(ResourceLoadCompleted, render_frame_id,
239 std::move(resource_load_info), status));
240 }
241
NotifyResourceLoadCanceled(int render_frame_id,blink::mojom::ResourceLoadInfoPtr resource_load_info,int net_error)242 void NotifyResourceLoadCanceled(
243 int render_frame_id,
244 blink::mojom::ResourceLoadInfoPtr resource_load_info,
245 int net_error) {
246 RecordLoadHistograms(url::Origin::Create(resource_load_info->final_url),
247 resource_load_info->request_destination, net_error);
248
249 auto task_runner = RenderThreadImpl::DeprecatedGetMainTaskRunner();
250 if (!task_runner)
251 return;
252 if (task_runner->BelongsToCurrentThread()) {
253 ResourceLoadCanceled(render_frame_id, resource_load_info->request_id);
254 return;
255 }
256 task_runner->PostTask(FROM_HERE,
257 base::BindOnce(ResourceLoadCanceled, render_frame_id,
258 resource_load_info->request_id));
259 }
260
261 } // namespace content
262