зеркало из https://github.com/microsoft/CCF.git
Add a method that decodes path parameters (#4126)
This commit is contained in:
Родитель
66b537a9a1
Коммит
856df5be72
|
@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|||
### Added
|
||||
|
||||
- New `GET /node/network/removable_nodes` and `DELETE /node/network/nodes/{node_id}` exposed to allow operator to decide which nodes can be safely shut down after retirement, and clear their state from the Key-Value Store.
|
||||
- Added a new method `get_decoded_request_path_params` that returns a map of decoded path parameters (#4126)
|
||||
|
||||
### Fixed
|
||||
|
||||
|
|
|
@ -72,6 +72,12 @@ namespace ccf
|
|||
/// {"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;
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "ccf/endpoint_registry.h"
|
||||
|
||||
#include "ccf/common_auth_policies.h"
|
||||
#include "http/http_parser.h"
|
||||
#include "node/rpc/rpc_context_impl.h"
|
||||
|
||||
namespace ccf::endpoints
|
||||
|
@ -279,7 +280,6 @@ namespace ccf::endpoints
|
|||
kv::Tx&, ccf::RpcContext& rpc_ctx)
|
||||
{
|
||||
auto method = rpc_ctx.get_method();
|
||||
|
||||
auto endpoints_for_exact_method = fully_qualified_endpoints.find(method);
|
||||
if (endpoints_for_exact_method != fully_qualified_endpoints.end())
|
||||
{
|
||||
|
@ -318,6 +318,7 @@ namespace ccf::endpoints
|
|||
throw std::logic_error("Unexpected type of RpcContext");
|
||||
}
|
||||
auto& path_params = ctx_impl->path_params;
|
||||
auto& decoded_path_params = ctx_impl->decoded_path_params;
|
||||
for (size_t i = 0;
|
||||
i < endpoint->spec.template_component_names.size();
|
||||
++i)
|
||||
|
@ -325,7 +326,9 @@ namespace ccf::endpoints
|
|||
const auto& template_name =
|
||||
endpoint->spec.template_component_names[i];
|
||||
const auto& template_value = match[i + 1].str();
|
||||
auto decoded_value = http::url_decode(template_value);
|
||||
path_params[template_name] = template_value;
|
||||
decoded_path_params[template_name] = decoded_value;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,12 @@ namespace ccf
|
|||
return path_params;
|
||||
}
|
||||
|
||||
ccf::PathParams decoded_path_params = {};
|
||||
virtual const ccf::PathParams& get_decoded_request_path_params() override
|
||||
{
|
||||
return decoded_path_params;
|
||||
}
|
||||
|
||||
bool is_create_request = false;
|
||||
bool execute_on_node = false;
|
||||
|
||||
|
|
|
@ -255,6 +255,23 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class TestDecodedTemplatedPaths : public BaseTestFrontend
|
||||
{
|
||||
public:
|
||||
TestDecodedTemplatedPaths(kv::Store& tables) : BaseTestFrontend(tables)
|
||||
{
|
||||
open();
|
||||
|
||||
auto endpoint = [this](auto& ctx) {
|
||||
nlohmann::json response_body =
|
||||
ctx.rpc_ctx->get_decoded_request_path_params();
|
||||
ctx.rpc_ctx->set_response_body(response_body.dump(2));
|
||||
ctx.rpc_ctx->set_response_status(HTTP_STATUS_OK);
|
||||
};
|
||||
make_endpoint("/{foo}/{bar}/{baz}", HTTP_POST, endpoint).install();
|
||||
}
|
||||
};
|
||||
|
||||
class TestMemberFrontend : public MemberRpcFrontend
|
||||
{
|
||||
public:
|
||||
|
@ -1060,7 +1077,7 @@ TEST_CASE("Templated paths")
|
|||
TestTemplatedPaths frontend(*network.tables);
|
||||
|
||||
{
|
||||
auto request = create_simple_request("/fin/fang/foom");
|
||||
auto request = create_simple_request("/fin%3A/fang/foom");
|
||||
const auto serialized_request = request.build_request();
|
||||
|
||||
auto rpc_ctx = ccf::make_rpc_context(user_session, serialized_request);
|
||||
|
@ -1068,7 +1085,7 @@ TEST_CASE("Templated paths")
|
|||
CHECK(response.status == HTTP_STATUS_OK);
|
||||
|
||||
std::map<std::string, std::string> expected_mapping;
|
||||
expected_mapping["foo"] = "fin";
|
||||
expected_mapping["foo"] = "fin%3A";
|
||||
expected_mapping["bar"] = "fang";
|
||||
expected_mapping["baz"] = "foom";
|
||||
|
||||
|
@ -1098,6 +1115,32 @@ TEST_CASE("Templated paths")
|
|||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Decoded Templated paths")
|
||||
{
|
||||
NetworkState network;
|
||||
prepare_callers(network);
|
||||
TestDecodedTemplatedPaths frontend(*network.tables);
|
||||
|
||||
{
|
||||
auto request = create_simple_request("/fin%3A/fang%2F/foom");
|
||||
const auto serialized_request = request.build_request();
|
||||
|
||||
auto rpc_ctx = ccf::make_rpc_context(user_session, serialized_request);
|
||||
auto response = parse_response(frontend.process(rpc_ctx).value());
|
||||
CHECK(response.status == HTTP_STATUS_OK);
|
||||
|
||||
std::map<std::string, std::string> expected_mapping;
|
||||
expected_mapping["foo"] = "fin:";
|
||||
expected_mapping["bar"] = "fang/";
|
||||
expected_mapping["baz"] = "foom";
|
||||
|
||||
const auto response_json = nlohmann::json::parse(response.body);
|
||||
const auto actual_mapping = response_json.get<decltype(expected_mapping)>();
|
||||
|
||||
CHECK(expected_mapping == actual_mapping);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Signed read requests can be executed on backup")
|
||||
{
|
||||
NetworkState network;
|
||||
|
|
Загрузка…
Ссылка в новой задаче