blob: a22100b2aa3029d85f5a0df9698d3e027e24fc0e [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 "chrome/browser/federated_learning/floc_remote_permission_service.h"
#include <memory>
#include <utility>
#include "base/bind.h"
#include "base/json/json_reader.h"
#include "base/values.h"
#include "net/base/isolation_info.h"
#include "net/base/load_flags.h"
#include "net/http/http_status_code.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "url/gurl.h"
namespace federated_learning {
namespace {
const char kQueryFlocPermissionUrl[] =
"https://adservice.google.com/settings/do_ad_settings_allow_floc_poc";
// The maximum number of retries for the SimpleURLLoader requests.
const size_t kMaxRetries = 1;
class RequestImpl : public FlocRemotePermissionService::Request {
public:
RequestImpl(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const GURL& url,
FlocRemotePermissionService::CreateRequestCallback callback,
const net::PartialNetworkTrafficAnnotationTag& partial_traffic_annotation)
: url_loader_factory_(std::move(url_loader_factory)),
url_(url),
response_code_(0),
callback_(std::move(callback)),
partial_traffic_annotation_(partial_traffic_annotation) {
DCHECK(url_loader_factory_);
}
~RequestImpl() override = default;
// Returns the response code received from the server, which will only be
// valid if the request succeeded.
int GetResponseCode() override { return response_code_; }
// Returns the contents of the response body received from the server.
const std::string& GetResponseBody() override { return response_body_; }
private:
void Start() override {
auto resource_request = std::make_unique<network::ResourceRequest>();
resource_request->url = url_;
resource_request->site_for_cookies = net::SiteForCookies::FromUrl(url_);
resource_request->trusted_params =
network::ResourceRequest::TrustedParams();
resource_request->trusted_params->isolation_info =
net::IsolationInfo::CreateForInternalRequest(url::Origin::Create(url_));
resource_request->method = "GET";
DCHECK(resource_request->SendsCookies());
net::NetworkTrafficAnnotationTag traffic_annotation =
net::CompleteNetworkTrafficAnnotation("floc_remote_permission_service",
partial_traffic_annotation_,
R"(
semantics {
sender: "Federated Learning of Cohorts Remote Permission Service"
destination: GOOGLE_OWNED_SERVICE
}
policy {
cookies_allowed: YES
cookies_store: "user"
chrome_policy {
SyncDisabled {
SyncDisabled: true
}
}
})");
simple_url_loader_ = network::SimpleURLLoader::Create(
std::move(resource_request), traffic_annotation);
simple_url_loader_->SetRetryOptions(kMaxRetries,
network::SimpleURLLoader::RETRY_ON_5XX);
simple_url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
url_loader_factory_.get(),
base::BindOnce(&RequestImpl::OnSimpleLoaderComplete,
base::Unretained(this)));
}
void OnSimpleLoaderComplete(std::unique_ptr<std::string> response_body) {
response_code_ = -1;
if (simple_url_loader_->ResponseInfo() &&
simple_url_loader_->ResponseInfo()->headers) {
response_code_ =
simple_url_loader_->ResponseInfo()->headers->response_code();
}
simple_url_loader_.reset();
if (response_body) {
response_body_ = std::move(*response_body);
} else {
response_body_.clear();
}
std::move(callback_).Run(this);
// It is valid for the callback to delete |this|, so do not access any
// members below here.
}
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
// The URL of the API endpoint.
const GURL url_;
// Handles the actual request to |url_| (the API endpoint).
std::unique_ptr<network::SimpleURLLoader> simple_url_loader_;
// Holds the response code received from the server.
int response_code_;
// Holds the response body received from the server.
std::string response_body_;
// The callback to execute when the query is complete.
FlocRemotePermissionService::CreateRequestCallback callback_;
// Partial Network traffic annotation used to create SimpleURLLoader for this
// request.
const net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation_;
};
std::unique_ptr<base::ListValue> ReadResponseAsList(
FlocRemotePermissionService::Request* request) {
std::unique_ptr<base::ListValue> result;
if (request->GetResponseCode() == net::HTTP_OK) {
std::unique_ptr<base::Value> value =
base::JSONReader::ReadDeprecated(request->GetResponseBody());
if (value && value->is_list())
result.reset(static_cast<base::ListValue*>(value.release()));
else
DLOG(WARNING) << "Non-JSON-Array response received from the server.";
}
return result;
}
} // namespace
FlocRemotePermissionService::Request::Request() = default;
FlocRemotePermissionService::Request::~Request() = default;
FlocRemotePermissionService::FlocRemotePermissionService(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
: url_loader_factory_(std::move(url_loader_factory)) {}
FlocRemotePermissionService::~FlocRemotePermissionService() = default;
std::unique_ptr<FlocRemotePermissionService::Request>
FlocRemotePermissionService::CreateRequest(
const GURL& url,
CreateRequestCallback callback,
const net::PartialNetworkTrafficAnnotationTag& partial_traffic_annotation) {
return std::make_unique<RequestImpl>(url_loader_factory_, url,
std::move(callback),
partial_traffic_annotation);
}
GURL FlocRemotePermissionService::GetQueryFlocPermissionUrl() const {
return GURL(kQueryFlocPermissionUrl);
}
void FlocRemotePermissionService::QueryFlocPermission(
QueryFlocPermissionCallback callback,
const net::PartialNetworkTrafficAnnotationTag& partial_traffic_annotation) {
// Wrap the original callback into a generic CreateRequestCallback.
CreateRequestCallback create_request_callback = base::BindOnce(
&FlocRemotePermissionService::QueryFlocPermissionCompletionCallback,
weak_ptr_factory_.GetWeakPtr(), std::move(callback));
GURL url = GetQueryFlocPermissionUrl();
std::unique_ptr<Request> request = CreateRequest(
url, std::move(create_request_callback), partial_traffic_annotation);
Request* request_raw_ptr = request.get();
pending_floc_permission_requests_[request_raw_ptr] = std::move(request);
request_raw_ptr->Start();
}
void FlocRemotePermissionService::QueryFlocPermissionCompletionCallback(
FlocRemotePermissionService::QueryFlocPermissionCallback callback,
FlocRemotePermissionService::Request* request) {
std::unique_ptr<Request> request_ptr =
std::move(pending_floc_permission_requests_[request]);
pending_floc_permission_requests_.erase(request);
std::unique_ptr<base::ListValue> response_value;
bool swaa = false;
bool nac = false;
bool account_type = false;
response_value = ReadResponseAsList(request);
if (response_value) {
base::Value::ListView l = response_value->GetList();
if (l.size() == 3) {
if (l[0].is_bool())
swaa = l[0].GetBool();
if (l[1].is_bool())
nac = l[1].GetBool();
if (l[2].is_bool())
account_type = l[2].GetBool();
}
}
std::move(callback).Run(swaa && nac && account_type);
}
} // namespace federated_learning