Skip to content

Commit 39f4349

Browse files
peckato1troglobit
authored andcommitted
restconf: add internal RPC handler dispatcher
This code adds a new internal RPC handler dispatcher that checks if user is authorized to call the RPC (we are bypassing sysrepo, so we have to check this manually) and then calls the RPC handler. So far, there are no RPCs processed, but support for the ietf-subscribed-notifications:establish-subscription RPC is coming soon. Change-Id: I99121a511011229e4098f95e91601b39d333444a Signed-off-by: Mattias Walström <lazzer@gmail.com>
1 parent 91e8e41 commit 39f4349

2 files changed

Lines changed: 38 additions & 4 deletions

File tree

src/restconf/Server.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -438,10 +438,26 @@ libyang::CreatedNodes createEditForPutAndPatch(libyang::Context& ctx, const std:
438438
return {editNode, replacementNode};
439439
}
440440

441-
std::optional<libyang::DataNode> processInternalRPC(sysrepo::Session&, const libyang::DataNode&)
441+
std::optional<libyang::DataNode> processInternalRPC(sysrepo::Session& sess, const libyang::DataNode& rpcInput, const libyang::DataFormat requestEncoding)
442442
{
443-
// TODO: Implement internal RPCs
444-
throw ErrorResponse(501, "application", "operation-not-supported", "Internal RPCs are not yet supported.");
443+
using InternalRPCHandler = std::function<void(sysrepo::Session&, const libyang::DataFormat, const libyang::DataNode&, libyang::DataNode&)>;
444+
const std::map<std::string, InternalRPCHandler> handlers;
445+
446+
const auto rpcPath = rpcInput.path();
447+
448+
// Is the user authorized to call the operation?
449+
auto [parent, rpcNode] = sess.getContext().newPath2(rpcPath, std::nullopt);
450+
if (!sess.checkNacmOperation(*rpcNode)) {
451+
throw ErrorResponse(403, "application", "access-denied", "Access denied.", rpcNode->path());
452+
}
453+
454+
if (auto it = handlers.find(rpcPath); it != handlers.end()) {
455+
auto [parent, rpcOutput] = sess.getContext().newPath2(rpcPath, std::nullopt);
456+
it->second(sess, requestEncoding, rpcInput, *rpcOutput);
457+
return *parent;
458+
}
459+
460+
throw ErrorResponse(501, "application", "operation-not-supported", "Unsupported RPC call to " + rpcPath, rpcPath);
445461
}
446462

447463
void processActionOrRPC(std::shared_ptr<RequestContext> requestCtx, const std::chrono::milliseconds timeout)
@@ -478,7 +494,7 @@ void processActionOrRPC(std::shared_ptr<RequestContext> requestCtx, const std::c
478494
if (requestCtx->restconfRequest.type == RestconfRequest::Type::Execute) {
479495
rpcReply = requestCtx->sess.sendRPC(*rpcNode, timeout);
480496
} else if (requestCtx->restconfRequest.type == RestconfRequest::Type::ExecuteInternal) {
481-
rpcReply = processInternalRPC(requestCtx->sess, *rpcNode);
497+
rpcReply = processInternalRPC(requestCtx->sess, *rpcNode, *requestCtx->dataFormat.request);
482498
}
483499

484500
if (!rpcReply || rpcReply->immediateChildren().empty()) {

tests/restconf-rpc.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,4 +420,22 @@ TEST_CASE("invoking actions and rpcs")
420420
)"});
421421
}
422422
}
423+
424+
SECTION("Internal RPC handlers")
425+
{
426+
// check NACM access
427+
REQUIRE(post(RESTCONF_OPER_ROOT "/ietf-subscribed-notifications:kill-subscription", {CONTENT_TYPE_JSON}, R"({"ietf-subscribed-notifications:input": {}})") == Response{403, jsonHeaders, R"({
428+
"ietf-restconf:errors": {
429+
"error": [
430+
{
431+
"error-type": "application",
432+
"error-tag": "access-denied",
433+
"error-path": "/ietf-subscribed-notifications:kill-subscription",
434+
"error-message": "Access denied."
435+
}
436+
]
437+
}
438+
}
439+
)"});
440+
}
423441
}

0 commit comments

Comments
 (0)