blob: 348d6a6eef369245c6d74d63b2eb554aaa5daff2 [file] [log] [blame]
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ATTESTATION_PCA_AGENT_SERVER_PCA_REQUEST_H_
#define ATTESTATION_PCA_AGENT_SERVER_PCA_REQUEST_H_
#include "attestation/pca_agent/server/pca_agent_service.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <attestation/proto_bindings/interface.pb.h>
#include <base/bind.h>
#include <base/logging.h>
#include <base/memory/ref_counted.h>
#include <brillo/dbus/dbus_method_response.h>
#include <brillo/http/http_request.h>
#include <dbus/bus.h>
#include "attestation/pca_agent/server/default_transport_factory.h"
#include "attestation/pca_agent/server/pca_http_utils.h"
namespace attestation {
namespace pca_agent {
// A class that is designed for handling the pca response. To achieve its
// purpose, this class implements 2 functions, |OnError| and |OnSuccess|, to
// handle the situations as their names suggest respectively.
// Note that this class is |base::RefCounted| so the caller can bind them into 2
// callbacks at the same time.
template <typename ReplyType>
class PcaRequest final : public base::RefCounted<PcaRequest<ReplyType>>,
private DefaultTransportFactory,
private PcaHttpUtils {
using DBusResponseType = brillo::dbus_utils::DBusMethodResponse<ReplyType>;
public:
// Constructs a new instance with |name| as its name, and |response| as the
// dbus response callback. |url| and |request| represents what their names
// suggest. It is intended that this constructor takes ownership of what
// |response| has.
PcaRequest(const std::string& name,
const std::string& url,
const std::string& request,
std::unique_ptr<DBusResponseType> response);
// Not copyable or movable.
PcaRequest(const PcaRequest&) = delete;
PcaRequest(PcaRequest&&) = delete;
PcaRequest& operator=(const PcaRequest&) = delete;
PcaRequest& operator=(PcaRequest&&) = delete;
// Sends |request_| to the PCA server at |url_|. The detailed flows are as
// follows:
// 1. Gets the proxy information from Chrome. If failed, continues assuming no
// proxy server, i.e., "direct://" would be the only attempt we are gonna try.
// 2. Gets the first proxy server from the list and pop it. Sends |request_|
// to |url_| with the popped proxy server.
// 3. In case of connection error or bad HTTP status code, goes back to 2.
// until running out of all proxy options.
// Despite of the flow described above, the processes are broken down to
// tasks and invoked in async manner.
void SendRequest();
void set_transport_factory_for_testing(TransportFactory* factory) {
transport_factory_ = factory;
}
void set_pca_http_utils_for_testing(PcaHttpUtils* utils) {
http_utils_ = utils;
}
private:
// The name of the response it is handling; used for logging.
const std::string name_;
// The URL of the PCA server.
const std::string url_;
// The request to be sent to |url_|
const std::string request_;
// A |TransportFactory| used to create |brillo::http::Transport| instance;
// alternated during unittest for testability.
TransportFactory* transport_factory_{this};
// The list of proxy servers used to try to send the request with.
std::vector<std::string> proxy_servers_;
//
// The dbus response callback, which is called when either |OnError| or
// |OnSuccess| is called.
std::unique_ptr<DBusResponseType> response_;
// The callback of |GetChromeProxyServersAsync|; triggers
// |SendRequestWithProxySetting| after storing the proxy servers into
// |proxy_servers_|. In case of |!success|, inserts an identifier of direct
// connection.
void OnGetProxyServers(bool success, const std::vector<std::string>& servers);
// Reads and pops a proxy server from |proxy_servers_| and sends |request_| to
// |url_| with that proxy server. In case of error/success, invokes |OnError|
// and |Onsuccess|, respectively.
bool SendRequestWithProxySetting();
// Logs the error and tries sends the request with next proxy server if any;
// otherwise, invokes |response_| with a proper status code. Designed to be
// called when errors occur during sending HTTP request.
void OnError(brillo::http::RequestID /*not used*/, const brillo::Error* err);
// Invokes |response_| if the HTTP status code is successful; in case of
// unsupported successful status code, e.g., "Partial", the returned status is
// set to |STATUS_NOT_SUPPORT|. In case of unsuccessful HTTP status code,
// sends the request with next proxy server if any; otherwise, invokes
// |response_| with a proper status code. Designed to be called when sending
// HTTP request successfully.
void OnSuccess(brillo::http::RequestID,
std::unique_ptr<brillo::http::Response> pca_response);
// |PcaRequestHttpUtils| overrides.
void GetChromeProxyServersAsync(
const std::string& url,
const brillo::http::GetChromeProxyServersCallback& callback) override;
// A |PcaRequestHttpUtils| used to perform HTTP related functions;
// alternated during unittest for testability.
PcaHttpUtils* http_utils_{this};
// Used to retrieve proxy servers from Chrome.
scoped_refptr<dbus::Bus> bus_;
};
} // namespace pca_agent
} // namespace attestation
#endif // ATTESTATION_PCA_AGENT_SERVER_PCA_REQUEST_H_