Commit 2d9dc323 authored by Simon Zünd's avatar Simon Zünd Committed by Commit Bot

[devtools] Report Trust Token cache hits as successful requests

Trust Token Redemption can be short-circuited if a valid
Signed-Redemption-Record (SRR) already exists. In this case, the
network service aborts the request with a special error code.

In DevTools, this is repoted as a failed request, even though it was
technically a successful request served from cache. This CL handles
this case better and emits a loadingFinisehd event instead of a
loadingFailed event.

R=caseq@chromium.org, sigurds@chromium.org

Bug: chromium:1141652
Change-Id: Ie0408b7557928722ddb1964c1ad5d8bdf73aa831
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2516225Reviewed-by: default avatarNate Chapin <japhet@chromium.org>
Reviewed-by: default avatarSigurd Schneider <sigurds@chromium.org>
Reviewed-by: default avatarAndrey Kosyakov <caseq@chromium.org>
Commit-Queue: Simon Zünd <szuend@chromium.org>
Cr-Commit-Position: refs/heads/master@{#824778}
parent 93a10727
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/devtools/protocol/devtools_protocol_test_support.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
#include "content/test/trust_token_browsertest.h"
namespace content {
class DevToolsTrustTokenBrowsertest : public DevToolsProtocolTest,
public TrustTokenBrowsertest {
public:
void SetUpOnMainThread() override {
TrustTokenBrowsertest::SetUpOnMainThread();
DevToolsProtocolTest::SetUpOnMainThread();
}
void TearDownOnMainThread() override {
TrustTokenBrowsertest::TearDownOnMainThread();
DevToolsProtocolTest::TearDownOnMainThread();
}
};
// After a successful issuance and redemption, a subsequent redemption against
// the same issuer should hit the signed redemption record (SRR) cache.
IN_PROC_BROWSER_TEST_F(DevToolsTrustTokenBrowsertest,
RedemptionRecordCacheHitIsReportedAsLoadingFinished) {
ProvideRequestHandlerKeyCommitmentsToNetworkService({"a.test"});
// 1. Navigate to a test site, request and redeem a trust token.
ASSERT_TRUE(NavigateToURL(shell(), server_.GetURL("a.test", "/title1.html")));
EXPECT_EQ("Success",
EvalJs(shell(), JsReplace(R"(fetch($1,
{ trustToken: { type: 'token-request' } })
.then(()=>'Success'); )",
server_.GetURL("a.test", "/issue"))));
EXPECT_EQ("Success",
EvalJs(shell(), JsReplace(R"(fetch($1,
{ trustToken: { type: 'srr-token-redemption' } })
.then(()=>'Success'); )",
server_.GetURL("a.test", "/redeem"))));
// 2) Open DevTools and enable Network domain.
Attach();
SendCommand("Network.enable", std::make_unique<base::DictionaryValue>());
// Make sure there are no existing DevTools events in the queue.
EXPECT_EQ(notifications_.size(), 0ul);
// 3) Issue another redemption, and verify its served from cache.
EXPECT_EQ("NoModificationAllowedError",
EvalJs(shell(), JsReplace(R"(fetch($1,
{ trustToken: { type: 'srr-token-redemption' } })
.catch(err => err.name); )",
server_.GetURL("a.test", "/redeem"))));
// 4) Verify the request is marked as successful and not as failed.
WaitForNotification("Network.requestServedFromCache", true);
WaitForNotification("Network.loadingFinished", true);
}
} // namespace content
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
namespace content { namespace content {
class DevToolsProtocolTest : public ContentBrowserTest, class DevToolsProtocolTest : virtual public ContentBrowserTest,
public DevToolsAgentHostClient, public DevToolsAgentHostClient,
public WebContentsDelegate { public WebContentsDelegate {
public: public:
......
...@@ -999,6 +999,7 @@ test("content_browsertests") { ...@@ -999,6 +999,7 @@ test("content_browsertests") {
"../browser/database_browsertest.cc", "../browser/database_browsertest.cc",
"../browser/device_sensors/device_sensor_browsertest.cc", "../browser/device_sensors/device_sensor_browsertest.cc",
"../browser/devtools/devtools_issue_storage_browsertest.cc", "../browser/devtools/devtools_issue_storage_browsertest.cc",
"../browser/devtools/devtools_trust_token_browsertest.cc",
"../browser/devtools/devtools_video_consumer_browsertest.cc", "../browser/devtools/devtools_video_consumer_browsertest.cc",
"../browser/devtools/protocol/devtools_network_resource_loader_browsertest.cc", "../browser/devtools/protocol/devtools_network_resource_loader_browsertest.cc",
"../browser/devtools/protocol/devtools_protocol_browsertest.cc", "../browser/devtools/protocol/devtools_protocol_browsertest.cc",
......
...@@ -1379,6 +1379,18 @@ void InspectorNetworkAgent::DidFailLoading( ...@@ -1379,6 +1379,18 @@ void InspectorNetworkAgent::DidFailLoading(
const ResourceError& error, const ResourceError& error,
const base::UnguessableToken& devtools_frame_or_worker_token) { const base::UnguessableToken& devtools_frame_or_worker_token) {
String request_id = IdentifiersFactory::RequestId(loader, identifier); String request_id = IdentifiersFactory::RequestId(loader, identifier);
// A Trust Token redemption can be served from cache if a valid
// Signed-Redemption-Record is present. In this case the request is aborted
// with a special error code. Sementically, the request did succeed, so that
// is what we report to the frontend.
if (error.IsTrustTokenCacheHit()) {
GetFrontend()->requestServedFromCache(request_id);
GetFrontend()->loadingFinished(
request_id, base::TimeTicks::Now().since_origin().InSecondsF(), 0);
return;
}
bool canceled = error.IsCancellation(); bool canceled = error.IsCancellation();
base::Optional<ResourceRequestBlockedReason> resource_request_blocked_reason = base::Optional<ResourceRequestBlockedReason> resource_request_blocked_reason =
error.GetResourceRequestBlockedReason(); error.GetResourceRequestBlockedReason();
......
...@@ -179,8 +179,12 @@ bool ResourceError::IsCancellation() const { ...@@ -179,8 +179,12 @@ bool ResourceError::IsCancellation() const {
return error_code_ == net::ERR_ABORTED; return error_code_ == net::ERR_ABORTED;
} }
bool ResourceError::IsTrustTokenCacheHit() const {
return error_code_ == net::ERR_TRUST_TOKEN_OPERATION_CACHE_HIT;
}
bool ResourceError::IsUnactionableTrustTokensStatus() const { bool ResourceError::IsUnactionableTrustTokensStatus() const {
return error_code_ == net::ERR_TRUST_TOKEN_OPERATION_CACHE_HIT || return IsTrustTokenCacheHit() ||
(error_code_ == net::ERR_TRUST_TOKEN_OPERATION_FAILED && (error_code_ == net::ERR_TRUST_TOKEN_OPERATION_FAILED &&
trust_token_operation_error_ == trust_token_operation_error_ ==
network::mojom::TrustTokenOperationStatus::kUnavailable); network::mojom::TrustTokenOperationStatus::kUnavailable);
......
...@@ -80,6 +80,8 @@ class PLATFORM_EXPORT ResourceError final { ...@@ -80,6 +80,8 @@ class PLATFORM_EXPORT ResourceError final {
bool IsCancellation() const; bool IsCancellation() const;
bool IsTrustTokenCacheHit() const;
// Returns true if the error was the outcome of a Trust Tokens operation and // Returns true if the error was the outcome of a Trust Tokens operation and
// the error does *not* represent an actionable failure: // the error does *not* represent an actionable failure:
// - If the error was due to a Trust Tokens cache hit, the purpose of this // - If the error was due to a Trust Tokens cache hit, the purpose of this
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment