Skip to content

Commit

Permalink
[release/2.x] Cherry pick: Add a method that decodes path parameters (#…
Browse files Browse the repository at this point in the history
…4126) (#4129)

* Add a method that decodes path parameters (#4126)

(cherry picked from commit 856df5b)

# Conflicts:
#	CHANGELOG.md

* Update CHANGELOG.md
  • Loading branch information
MahatiC authored Aug 15, 2022
1 parent 4a52012 commit e5d5768
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 3 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## Unreleased

### Added

- Added a new method `get_decoded_request_path_params` that returns a map of decoded path parameters (#4126)

## [2.0.5]

### Fixed
Expand Down
6 changes: 6 additions & 0 deletions include/ccf/rpc_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
5 changes: 4 additions & 1 deletion src/endpoints/endpoint_registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -240,7 +241,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())
{
Expand Down Expand Up @@ -279,14 +279,17 @@ 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)
{
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;
}
}

Expand Down
6 changes: 6 additions & 0 deletions src/node/rpc/rpc_context_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
47 changes: 45 additions & 2 deletions src/node/rpc/test/frontend_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,23 @@ class TestTemplatedPaths : public BaseTestFrontend
}
};

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:
Expand Down Expand Up @@ -1059,15 +1076,15 @@ 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);
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["foo"] = "fin%3A";
expected_mapping["bar"] = "fang";
expected_mapping["baz"] = "foom";

Expand Down Expand Up @@ -1097,6 +1114,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;
Expand Down

0 comments on commit e5d5768

Please sign in to comment.