blob: 749756ba9a27025275796012af58924a21415ec6 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/loader/resource_timing_utils.h"
#include <string>
#include <utility>
#include "base/containers/contains.h"
#include "net/http/http_response_info.h"
#include "third_party/blink/public/mojom/navigation/navigation_params.mojom.h"
#include "third_party/blink/public/mojom/timing/resource_timing.mojom.h"
#include "url/gurl.h"
#include "url/url_util.h"
namespace {
// Implements the TimingAllowOrigin check
// This logic is duplicated from Performance::AllowsTimingRedirect(). Ensure
// that any changes are synced between both copies.
bool IsCrossOriginResponseOrHasCrossOriginRedirects(
const url::Origin& parent_origin,
const blink::mojom::CommonNavigationParams& common_params,
const blink::mojom::CommitNavigationParams& commit_params) {
DCHECK_EQ(commit_params.redirect_infos.size(),
commit_params.redirect_response.size());
for (const auto& info : commit_params.redirect_infos) {
if (!parent_origin.IsSameOriginWith(info.new_url)) {
return true;
}
}
return !parent_origin.IsSameOriginWith(common_params.url);
}
} // namespace
namespace content {
// This logic is duplicated from blink::CreateResourceTimingInfo(). Ensure
// that any changes are synced between both copies.
blink::mojom::ResourceTimingInfoPtr GenerateResourceTimingForNavigation(
const url::Origin& parent_origin,
const blink::mojom::CommonNavigationParams& common_params,
const blink::mojom::CommitNavigationParams& commit_params,
const network::mojom::URLResponseHead& response_head) {
// TODO(dcheng): There should be a Blink helper for populating the timing info
// that's exposed in //third_party/blink/common. This would allow a lot of the
// boilerplate to be shared.
auto timing_info = blink::mojom::ResourceTimingInfo::New();
const GURL& initial_url = !commit_params.original_url.is_empty()
? commit_params.original_url
: common_params.url;
timing_info->name = initial_url.spec();
timing_info->start_time = common_params.navigation_start;
timing_info->allow_timing_details = response_head.timing_allow_passed;
// Only expose the response code when we are same origin and without
// cross-origin redirects
// https://fetch.spec.whatwg.org/#ref-for-concept-response-status%E2%91%A6
if (!IsCrossOriginResponseOrHasCrossOriginRedirects(
parent_origin, common_params, commit_params)) {
timing_info->response_status = commit_params.http_response_code;
}
// https://fetch.spec.whatwg.org/#create-an-opaque-timing-info
if (!timing_info->allow_timing_details) {
return timing_info;
}
timing_info->alpn_negotiated_protocol =
response_head.alpn_negotiated_protocol;
timing_info->connection_info = net::HttpResponseInfo::ConnectionInfoToString(
response_head.connection_info);
// If there's no received headers end time, don't set load timing. This is the
// case for non-HTTP requests, requests that don't go over the wire, and
// certain error cases.
// TODO(dcheng): Is it actually possible to hit this path if
// `response_head.headers` is populated?
if (!response_head.load_timing.receive_headers_end.is_null()) {
timing_info->timing = response_head.load_timing;
}
// `response_end` will be populated after loading the body.
DCHECK_EQ(commit_params.redirect_infos.size(),
commit_params.redirect_response.size());
if (!commit_params.redirect_infos.empty()) {
timing_info->last_redirect_end_time =
commit_params.redirect_response.back()->load_timing.receive_headers_end;
} else {
timing_info->last_redirect_end_time = base::TimeTicks();
}
// The final value for `encoded_body_size` and `decoded_body_size` will be
// populated after loading the body.
timing_info->did_reuse_connection = response_head.load_timing.socket_reused;
// Use url::Origin to handle cases like blob:https://.
timing_info->is_secure_transport = base::Contains(
url::GetSecureSchemes(), url::Origin::Create(common_params.url).scheme());
timing_info->allow_negative_values = false;
return timing_info;
}
} // namespace content