// 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 #include #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 CreateTrustTokenKeyCommitmentRequest( const net::URLRequest& request, const url::Origin& top_level_origin) { auto key_commitment_request = std::make_unique(); 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 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_(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* 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({Status::Value::kGotRedirected}, /*result=*/nullptr); // |this| may be deleted here. } void TrustTokenKeyCommitmentController::HandleResponseBody( std::unique_ptr 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({Status::Value::kCouldntParse}, /*result=*/nullptr); return; } std::move(completion_callback_) .Run({Status::Value::kOk}, std::move(result)); // |this| may be deleted here. } } // namespace network