blob: 6d6b0731656787fce37e29b08d9052a2c533ad3f [file] [log] [blame]
// 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 "services/network/trust_tokens/trust_token_key_commitment_controller.h"
#include <memory>
#include <vector>
#include "base/bind.h"
#include "base/optional.h"
#include "base/strings/string_util.h"
#include "net/base/load_flags.h"
#include "net/http/http_request_headers.h"
#include "net/url_request/url_request.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "services/network/public/mojom/trust_tokens.mojom.h"
#include "services/network/public/mojom/url_loader.mojom.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "services/network/trust_tokens/trust_token_parameterization.h"
#include "url/gurl.h"
namespace network {
namespace internal {
std::unique_ptr<ResourceRequest> CreateTrustTokenKeyCommitmentRequest(
const net::URLRequest& request,
const url::Origin& top_level_origin) {
auto key_commitment_request = std::make_unique<ResourceRequest>();
key_commitment_request->url =
request.url().Resolve(kTrustTokenKeyCommitmentWellKnownPath);
key_commitment_request->method = net::HttpRequestHeaders::kGetMethod;
key_commitment_request->priority = request.priority();
key_commitment_request->credentials_mode = mojom::CredentialsMode::kOmit;
key_commitment_request->load_flags =
net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE;
key_commitment_request->request_initiator = request.initiator();
key_commitment_request->headers.SetHeader(net::HttpRequestHeaders::kOrigin,
top_level_origin.Serialize());
return key_commitment_request;
}
} // namespace internal
TrustTokenKeyCommitmentController::TrustTokenKeyCommitmentController(
base::OnceCallback<void(Status status,
mojom::TrustTokenKeyCommitmentResultPtr result)>
completion_callback,
const net::URLRequest& request,
const url::Origin& top_level_origin,
const net::NetworkTrafficAnnotationTag& traffic_annotation,
mojom::URLLoaderFactory* loader_factory,
std::unique_ptr<Parser> parser)
: parser_(std::move(parser)),
completion_callback_(std::move(completion_callback)) {
url_loader_ = SimpleURLLoader::Create(
internal::CreateTrustTokenKeyCommitmentRequest(request, top_level_origin),
traffic_annotation);
StartRequest(loader_factory);
}
TrustTokenKeyCommitmentController::~TrustTokenKeyCommitmentController() =
default;
void TrustTokenKeyCommitmentController::StartRequest(
mojom::URLLoaderFactory* loader_factory) {
DCHECK(url_loader_);
// It's safe to use base::Unretained here because this class
// owns the URLLoader: when |this| is destroyed, |url_loader_| will be, too,
// so the callbacks won't be called.
url_loader_->SetOnRedirectCallback(
base::BindRepeating(&TrustTokenKeyCommitmentController::HandleRedirect,
base::Unretained(this)));
static_assert(
kTrustTokenKeyCommitmentRegistryMaxSizeBytes <
SimpleURLLoader::kMaxBoundedStringDownloadSize,
"If the key commitment record maxium size exceeds ~5MB, the key "
"commitment fetching implementation should be changed to no longer use "
"SimpleURLLoader::DownloadToString (see the method's function comment).");
url_loader_->DownloadToString(
loader_factory,
base::BindOnce(&TrustTokenKeyCommitmentController::HandleResponseBody,
base::Unretained(this)),
/*max_body_size=*/kTrustTokenKeyCommitmentRegistryMaxSizeBytes);
}
void TrustTokenKeyCommitmentController::HandleRedirect(
const net::RedirectInfo& redirect_info,
const network::mojom::URLResponseHead& response_head,
std::vector<std::string>* to_be_removed_headers) {
// At least preliminarily, we don't allow redirects in key commitment fetches
// because of a lack of compelling reason to do so (and the attendant
// performance downsides of being redirected en route to getting the
// commitments).
// Free |url_loader_| now to abort handling the request, in case there's a
// delay before the client deletes this object.
url_loader_.reset();
std::move(completion_callback_)
.Run({.value = Status::Value::kGotRedirected}, /*result=*/nullptr);
// |this| may be deleted here.
}
void TrustTokenKeyCommitmentController::HandleResponseBody(
std::unique_ptr<std::string> response_body) {
DCHECK(parser_);
int error = url_loader_->NetError();
if (!response_body) {
DCHECK_NE(error, net::OK);
std::move(completion_callback_)
.Run({Status::Value::kNetworkError, error}, /*result=*/nullptr);
return;
}
mojom::TrustTokenKeyCommitmentResultPtr result =
parser_->Parse(*response_body);
if (!result) {
std::move(completion_callback_)
.Run({.value = Status::Value::kCouldntParse}, /*result=*/nullptr);
return;
}
std::move(completion_callback_)
.Run({.value = Status::Value::kOk}, std::move(result));
// |this| may be deleted here.
}
} // namespace network