client session BUGFIX accepting non-standard capabilities
Except that also if some capability module fails to load,
the data of it are ignored.
Fixes #18
diff --git a/src/session_client.c b/src/session_client.c
index 8ac22f3..dfc4a36 100644
--- a/src/session_client.c
+++ b/src/session_client.c
@@ -65,19 +65,15 @@
/* SCHEMAS_DIR not used (implicitly) */
static int
-ctx_check_and_load_model(struct nc_session *session, const char *cpblt)
+ctx_check_and_load_model(struct nc_session *session, const char *module_cpblt)
{
const struct lys_module *module;
char *ptr, *ptr2;
char *model_name, *revision = NULL, *features = NULL;
- /* parse module */
- ptr = strstr(cpblt, "module=");
- if (!ptr) {
- ERR("Unknown capability \"%s\" could not be parsed.", cpblt);
- return -1;
- }
- ptr += 7;
+ assert(!strncmp(module_cpblt, "module=", 7));
+
+ ptr = (char *)module_cpblt + 7;
ptr2 = strchr(ptr, '&');
if (!ptr2) {
ptr2 = ptr + strlen(ptr);
@@ -85,7 +81,7 @@
model_name = strndup(ptr, ptr2 - ptr);
/* parse revision */
- ptr = strstr(cpblt, "revision=");
+ ptr = strstr(module_cpblt, "revision=");
if (ptr) {
ptr += 9;
ptr2 = strchr(ptr, '&');
@@ -110,7 +106,7 @@
free(model_name);
/* parse features */
- ptr = strstr(cpblt, "features=");
+ ptr = strstr(module_cpblt, "features=");
if (ptr) {
ptr += 9;
ptr2 = strchr(ptr, '&');
@@ -293,6 +289,7 @@
int
nc_ctx_check_and_fill(struct nc_session *session)
{
+ const char *module_cpblt;
int i, get_schema_support = 0, ret = 0, r;
ly_module_clb old_clb = NULL;
void *old_data = NULL;
@@ -328,42 +325,41 @@
/* load all other models */
for (i = 0; session->cpblts[i]; ++i) {
- if (!strncmp(session->cpblts[i], "urn:ietf:params:netconf:capability", 34)
- || !strncmp(session->cpblts[i], "urn:ietf:params:netconf:base", 28)) {
- continue;
- }
-
- r = ctx_check_and_load_model(session, session->cpblts[i]);
- if (r == -1) {
- ret = -1;
- break;
- }
-
- /* failed to load schema, but let's try to find it using user callback (or locally, if not set),
- * if it was using get-schema */
- if (r == 1) {
- if (get_schema_support) {
- VRB("Trying to load the schema from a different source.");
- /* works even if old_clb is NULL */
- ly_ctx_set_module_clb(session->ctx, old_clb, old_data);
- r = ctx_check_and_load_model(session, session->cpblts[i]);
+ module_cpblt = strstr(session->cpblts[i], "module=");
+ /* this capability requires a module */
+ if (module_cpblt) {
+ r = ctx_check_and_load_model(session, module_cpblt);
+ if (r == -1) {
+ ret = -1;
+ break;
}
- /* fail again (or no other way to try), too bad */
- if (r) {
- ret = 1;
- }
+ /* failed to load schema, but let's try to find it using user callback (or locally, if not set),
+ * if it was using get-schema */
+ if (r == 1) {
+ if (get_schema_support) {
+ VRB("Trying to load the schema from a different source.");
+ /* works even if old_clb is NULL */
+ ly_ctx_set_module_clb(session->ctx, old_clb, old_data);
+ r = ctx_check_and_load_model(session, module_cpblt);
+ }
- /* set get-schema callback back */
- ly_ctx_set_module_clb(session->ctx, &libyang_module_clb, session);
+ /* fail again (or no other way to try), too bad */
+ if (r) {
+ session->flags |= NC_SESSION_CLIENT_NOT_STRICT;
+ }
+
+ /* set get-schema callback back */
+ ly_ctx_set_module_clb(session->ctx, &libyang_module_clb, session);
+ }
}
}
if (old_clb) {
ly_ctx_set_module_clb(session->ctx, old_clb, old_data);
}
- if (ret == 1) {
- WRN("Some models failed to be loaded, any data from these models will be ignored.");
+ if (session->flags & NC_SESSION_CLIENT_NOT_STRICT) {
+ WRN("Some models failed to be loaded, any data from these models (and any other unknown) will be ignored.");
}
return ret;
}
@@ -1143,6 +1139,9 @@
return NC_MSG_ERROR;
}
parseroptions &= ~(LYD_OPT_DESTRUCT | LYD_OPT_NOSIBLINGS);
+ if (!(session->flags & NC_SESSION_CLIENT_NOT_STRICT)) {
+ parseroptions &= LYD_OPT_STRICT;
+ }
*reply = NULL;
msgtype = get_msg(session, timeout, msgid, &xml);
@@ -1200,7 +1199,8 @@
}
/* notification body */
- (*notif)->tree = lyd_parse_xml(session->ctx, &xml->child, LYD_OPT_NOTIF | LYD_OPT_DESTRUCT, NULL);
+ (*notif)->tree = lyd_parse_xml(session->ctx, &xml->child, LYD_OPT_NOTIF | LYD_OPT_DESTRUCT
+ | (session->flags & NC_SESSION_CLIENT_NOT_STRICT ? 0 : LYD_OPT_STRICT), NULL);
lyxml_free(session->ctx, xml);
xml = NULL;
if (!(*notif)->tree) {
@@ -1357,7 +1357,8 @@
if (rpc_gen->has_data) {
data = rpc_gen->content.data;
} else {
- data = lyd_parse_mem(session->ctx, rpc_gen->content.xml_str, LYD_XML, LYD_OPT_RPC | LYD_OPT_STRICT, NULL);
+ data = lyd_parse_mem(session->ctx, rpc_gen->content.xml_str, LYD_XML, LYD_OPT_RPC
+ | (session->flags & NC_SESSION_CLIENT_NOT_STRICT ? 0 : LYD_OPT_STRICT), NULL);
}
break;
@@ -1777,7 +1778,7 @@
return NC_MSG_ERROR;
}
- if (lyd_validate(&data, LYD_OPT_RPC | LYD_OPT_STRICT, NULL)) {
+ if (lyd_validate(&data, LYD_OPT_RPC | (session->flags & NC_SESSION_CLIENT_NOT_STRICT ? 0 : LYD_OPT_STRICT), NULL)) {
lyd_free(data);
return NC_MSG_ERROR;
}
diff --git a/src/session_p.h b/src/session_p.h
index bb662ae..061690d 100644
--- a/src/session_p.h
+++ b/src/session_p.h
@@ -267,9 +267,13 @@
struct nc_msg_cont *replies; /**< queue for RPC replies received instead of notifications */
struct nc_msg_cont *notifs; /**< queue for notifications received instead of RPC reply */
+ /* some server modules failed to load so the data from them will be ignored - not use strict flag for parsing */
+# define NC_SESSION_CLIENT_NOT_STRICT 0x40
+
/* server side only data */
time_t session_start; /**< time the session was created */
time_t last_rpc; /**< time the last RPC was received on this session */
+
#ifdef NC_ENABLED_SSH
/* SSH session authenticated */
# define NC_SESSION_SSH_AUTHENTICATED 0x04