CCF/include/ccf/rpc_context.h

196 строки
7.4 KiB
C++

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the Apache 2.0 License.
#pragma once
#include "ccf/claims_digest.h"
#include "ccf/frame_format.h"
#include "ccf/http_consts.h"
#include "ccf/http_header_map.h"
#include "ccf/odata_error.h"
#include "ccf/rest_verb.h"
#include "ccf/service/signed_req.h"
#include "ccf/tx_id.h"
#include <vector>
namespace ccf
{
static constexpr size_t InvalidSessionId = std::numeric_limits<size_t>::max();
using ListenInterfaceID = std::string;
struct SessionContext
{
size_t client_session_id = InvalidSessionId;
// Usually a DER certificate, may be a PEM on forwardee
std::vector<uint8_t> caller_cert = {};
bool is_forwarding = false;
// Only set for RPC sessions (i.e. non-forwarded and non-internal)
std::optional<ListenInterfaceID> interface_id = std::nullopt;
// Only set in the case of a forwarded RPC
bool is_forwarded = false;
SessionContext(
size_t client_session_id_,
const std::vector<uint8_t>& caller_cert_,
const std::optional<ListenInterfaceID>& interface_id_ = std::nullopt) :
client_session_id(client_session_id_),
caller_cert(caller_cert_),
interface_id(interface_id_)
{}
};
using PathParams = std::map<std::string, std::string, std::less<>>;
/// Describes the currently executing RPC.
class RpcContext
{
public:
virtual ~RpcContext() = default;
/// \defgroup Access request
/// Methods to access fields of the received request. Describes fields
/// parsed from HTTP, but aims to generalise across other request protocols.
///@{
/// Return information about the persistent session which this request was
/// received on. Allows correlation between multiple requests coming from
/// the same long-lived session.
virtual std::shared_ptr<SessionContext> get_session_context() const = 0;
// Set user data that will be available in the post-local-commit handler.
// This is useful to avoid the serialisation/deserialisation cost.
virtual void set_user_data(std::shared_ptr<void> data) = 0;
// Get the user data that was previously set.
virtual void* get_user_data() const = 0;
virtual const std::vector<uint8_t>& get_request_body() const = 0;
virtual const std::string& get_request_query() const = 0;
virtual const ccf::RESTVerb& get_request_verb() const = 0;
virtual std::string get_request_path() const = 0;
virtual std::string get_method() const = 0;
/// Returns a map of all PathParams parsed out of the original query path.
/// For instance if this endpoint was installed at `/foo/{name}/{age}`, and
/// the request path `/foo/bob/42`, this would return the map:
/// {"name": "bob", "age": "42"}
virtual const PathParams& get_request_path_params() = 0;
/// Decodes the path before returning a map of all PathParams.
/// For example, if the endpoint was installed at `/foo/{name}/{age}`, and
/// for the request path `/foo/bob%3A/42`, this would return the map:
/// {"name": "bob:", "age": "42"}
virtual const PathParams& get_decoded_request_path_params() = 0;
/// Returns map of all headers found in the request.
virtual const http::HeaderMap& get_request_headers() const = 0;
/// Returns value associated with named header, or nullopt of this header
/// was not present.
virtual std::optional<std::string> get_request_header(
const std::string_view& name) = 0;
/// Returns full URL provided in request, rather than split into path +
/// query.
virtual const std::string& get_request_url() const = 0;
/// Returns frame format describing the protocol that the request was
/// received over.
virtual ccf::FrameFormat frame_format() const = 0;
///@}
/// \defgroup Construct response
/// Methods to set sections of response, which will be serialised and
/// transmitted to client.
///@{
/// Sets the main body or payload of the response.
virtual void set_response_body(const std::vector<uint8_t>& body) = 0;
/// Sets the main body or payload of the response.
virtual void set_response_body(std::vector<uint8_t>&& body) = 0;
/// Sets the main body or payload of the response.
virtual void set_response_body(std::string&& body) = 0;
virtual const std::vector<uint8_t>& get_response_body() const = 0;
/// Sets initial status code summarising result of RPC.
virtual void set_response_status(int status) = 0;
virtual int get_response_status() const = 0;
virtual void set_response_header(
const std::string_view& name, const std::string_view& value) = 0;
virtual void set_response_header(const std::string_view& name, size_t n)
{
set_response_header(name, std::to_string(n));
}
virtual void set_response_trailer(
const std::string_view& name, const std::string_view& value) = 0;
virtual void set_response_trailer(const std::string_view& name, size_t n)
{
set_response_trailer(name, std::to_string(n));
}
/// Construct OData-formatted response to capture multiple error details
virtual void set_error(
http_status status,
const std::string& code,
std::string&& msg,
std::vector<ccf::ODataErrorDetails>& details)
{
nlohmann::json body =
ccf::ODataErrorResponse{ccf::ODataError{code, std::move(msg), details}};
set_response(body, status);
}
/// Construct OData-formatted error response.
virtual void set_error(
http_status status, const std::string& code, std::string&& msg)
{
set_error(ccf::ErrorDetails{status, code, std::move(msg)});
}
/// Construct OData-formatted error response.
virtual void set_error(ccf::ErrorDetails&& error)
{
nlohmann::json body = ccf::ODataErrorResponse{
ccf::ODataError{std::move(error.code), std::move(error.msg)}};
set_response(body, error.status);
}
virtual void set_response(nlohmann::json& body, http_status status)
{
// Set error_handler to replace, to avoid throwing if the error message
// contains non-UTF8 characters. Other args are default values
const auto s =
body.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace);
set_response_status(status);
set_response_body(std::vector<uint8_t>(s.begin(), s.end()));
set_response_header(
http::headers::CONTENT_TYPE, http::headervalues::contenttype::JSON);
}
///@}
/// \defgroup Framework metadata
/// Methods which affect how the framework processes this transaction.
///@{
/// Tells the framework to apply or not apply this transaction.
/// By default that decision is based on the response status, with successes
/// applied and errors producing no persistent writes. This value will
/// override, allowing changes to be persisted/dropped regardless of
/// response type.
virtual void set_apply_writes(bool apply) = 0;
/// Sets the application claims digest associated with this transaction.
/// This digest is used to construct the Merkle tree leaf representing this
/// transaction. This allows a transaction to make specific,
/// separately-revealable claims in each transaction, without being bound to
/// the transaction serialisation format or what is stored in the KV.
/// The digest will be included in receipts issued for that transaction.
virtual void set_claims_digest(ccf::ClaimsDigest::Digest&& digest) = 0;
///@}
};
}