Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jansson: Add en-/decode to/from xavp #2513

Merged
merged 1 commit into from Oct 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
38 changes: 38 additions & 0 deletions src/modules/jansson/doc/jansson_admin.xml
Expand Up @@ -206,6 +206,44 @@ while($var(count) < $var(appendme_size)) {
jansson_append('int', "", $var(tmp), "$var(appendme)");
$var(count) = $var(count) + 1;
}
...
</programlisting>
</example>
</section>
<section id="jansson.f.jansson_xdecode">
<title>
<function moreinfo="none">jansson_xdecode(json, xavp)</function>
</title>
<para>
Parse a JSON string in 'json' and store the elements in xapv 'xavp'.
Top-level JSON must be an object or an array of objects.
Nested arrays and objects are not decoded but stored as string.
</para>
<example>
<title><function>jansson_xdecode</function> usage</title>
<programlisting format="linespecific">
...
jansson_xdecode('{"foo":"bar"}', "js");
xlog("foo is $xavp(js=>foo)");
...
</programlisting>
</example>
</section>
<section id="jansson.f.jansson_xencode">
<title>
<function moreinfo="none">jansson_xencode(xavp, pv)</function>
</title>
<para>
Encode the items in the xavp 'xavp' as JSON and store the result in a pv.
Nested xavps's are not supported.
</para>
<example>
<title><function>jansson_xencode</function> usage</title>
<programlisting format="linespecific">
...
$xavp(a=>foo) = "bar";
jansson_xencode("a", "$var(js)");
# $var(js) = '{"foo":"bar"}'
...
</programlisting>
</example>
Expand Down
191 changes: 191 additions & 0 deletions src/modules/jansson/jansson_funcs.c
Expand Up @@ -27,6 +27,7 @@
#include "../../core/mod_fix.h"
#include "../../core/lvalue.h"
#include "../../core/str.h"
#include "../../core/xavp.h"

#include "jansson_path.h"
#include "jansson_funcs.h"
Expand Down Expand Up @@ -297,3 +298,193 @@ int janssonmod_array_size(struct sip_msg* msg, char* path_in, char* src_in, char
json_decref(json);
return -1;
}


static int jansson_object2xavp(json_t* obj, str *xavp)
{
const char *key;
json_t *value;
sr_xavp_t *row = NULL;
sr_xval_t val;

json_object_foreach(obj, key, value) {
str name;
char* freeme = NULL;

if(jansson_to_xval(&val, &freeme, value)<0) {
ERR("failed to convert json object member value to xavp for key: %s\n", key);
if(freeme!=NULL) {
free(freeme);
}
return -1;
}

name.s = (char*)key;
name.len = strlen(name.s);

xavp_add_value(&name, &val, &row);

if(freeme!=NULL) {
free(freeme);
}
}

/* Add row to result xavp */
val.type = SR_XTYPE_XAVP;
val.v.xavp = row;
LM_DBG("Adding row\n");
xavp_add_value(xavp, &val, NULL);
return 1;
}


int jansson_xdecode(struct sip_msg* msg, char* src_in, char* xavp_in) {
str src_s;
str xavp_s;
json_t* json = NULL;
json_error_t parsing_error;

if (fixup_get_svalue(msg, (gparam_p)src_in, &src_s) != 0) {
ERR("cannot get json string value\n");
return -1;
}

if (fixup_get_svalue(msg, (gparam_p)xavp_in, &xavp_s) != 0) {
ERR("cannot get xavp string value\n");
return -1;
}

LM_DBG("decoding '%.*s' into '%.*s'\n", src_s.len, src_s.s, xavp_s.len, xavp_s.s);
json = json_loads(src_s.s, JSON_REJECT_DUPLICATES, &parsing_error);

if(!json) {
ERR("failed to parse json: %.*s\n", src_s.len, src_s.s);
ERR("json error at line %d, col %d: %s\n",
parsing_error.line, parsing_error.column, parsing_error.text);
return -1;
}

if (json_is_object(json)) {
if (jansson_object2xavp(json, &xavp_s) < 0) {
goto fail;
}
} else if (json_is_array(json)) {
size_t i;
json_t *value;

json_array_foreach(json, i, value) {
if (jansson_object2xavp(value, &xavp_s) < 0) {
goto fail;
}
}
} else {
LM_ERR("json root is not an object or array\n");
goto fail;
}

json_decref(json);
return 1;
fail:
json_decref(json);
return -1;
}

static int jansson_xavp2object(json_t *json, sr_xavp_t **head) {
sr_xavp_t *avp = NULL;
json_t *it = NULL;

if(json==NULL)
return -1;

avp = *head;
if (avp->val.type != SR_XTYPE_XAVP) {
LM_ERR("cannot iterate xavp members\n");
return -1;
}
avp = avp->val.v.xavp;
while(avp)
{
switch(avp->val.type) {
case SR_XTYPE_NULL:
it = json_null();
break;
case SR_XTYPE_INT:
it = json_integer(avp->val.v.i);
break;
case SR_XTYPE_STR:
it = json_stringn(avp->val.v.s.s, avp->val.v.s.len);
break;
case SR_XTYPE_TIME:
it = json_integer((json_int_t)avp->val.v.t);
break;
case SR_XTYPE_LONG:
it = json_integer((json_int_t)avp->val.v.l);
break;
case SR_XTYPE_LLONG:
it = json_integer((json_int_t)avp->val.v.ll);
break;
case SR_XTYPE_XAVP:
it = json_string("<<xavp>>");
break;
case SR_XTYPE_DATA:
it = json_string("<<data>>");
break;
default:
LM_ERR("unknown xavp type: %d\n", avp->val.type);
return -1;
}
if (it == NULL) {
LM_ERR("failed to create json value\n");
return -1;
}
if (json_object_set_new(json, avp->name.s, it) < 0) {
LM_ERR("failed to add member to object\n");
return -1;
}
avp = avp->next;
}
return 1;
}

int jansson_xencode(struct sip_msg* msg, char* xavp, char* dst) {
str xavp_s;
json_t *json;
pv_spec_t *dst_pv;
pv_value_t dst_val;
sr_xavp_t *avp = NULL;
int ret = 1;

if (fixup_get_svalue(msg, (gparam_p)xavp, &xavp_s) != 0) {
LM_ERR("cannot get field string value\n");
return -1;
}

LM_DBG("encoding '%.*s' into '%p'\n", xavp_s.len, xavp_s.s, dst);

avp = xavp_get(&xavp_s, NULL);
if(avp==NULL || avp->val.type!=SR_XTYPE_XAVP) {
return -1;
}

json = json_object();
if (json == NULL) {
LM_ERR("could not obtain json handle\n");
return -1;
}
ret = jansson_xavp2object(json, &avp);
if (ret > 0) {
dst_val.rs.s = json_dumps(json, 0);
dst_val.rs.len = strlen(dst_val.rs.s);
dst_val.flags = PV_VAL_STR;
dst_pv = (pv_spec_t *)dst;
if (dst_pv->setf(msg, &dst_pv->pvp, (int)EQ_T, &dst_val) < 0) {
ret = -1;
}
free(dst_val.rs.s);
} else {
LM_ERR("json encoding failed\n");
}

json_decref(json);
return ret;
}
2 changes: 2 additions & 0 deletions src/modules/jansson/jansson_funcs.h
Expand Up @@ -33,5 +33,7 @@ int janssonmod_array_size(struct sip_msg* msg, char* json_in,
char* path_in, char* dst);
int janssonmod_get_helper(sip_msg_t* msg, str *path_s, str *src_s,
pv_spec_t *dst_pv);
int jansson_xdecode(struct sip_msg* msg, char* src_in, char* xavp_in);
int jansson_xencode(struct sip_msg* msg, char* xavp, char* dst);

#endif
44 changes: 44 additions & 0 deletions src/modules/jansson/jansson_mod.c
Expand Up @@ -38,6 +38,8 @@ static int fixup_get_params(void** param, int param_no);
static int fixup_get_params_free(void** param, int param_no);
static int fixup_set_params(void** param, int param_no);
static int fixup_set_params_free(void** param, int param_no);
static int fixup_xencode(void** param, int param_no);
static int fixup_xencode_free(void** param, int param_no);


int janssonmod_set_replace(struct sip_msg* msg, char* type_in, char* path_in,
Expand All @@ -64,11 +66,16 @@ static cmd_export_t cmds[]={
fixup_set_params, fixup_set_params_free, ANY_ROUTE},
{"jansson_append", (cmd_function)janssonmod_set_append, 4,
fixup_set_params, fixup_set_params_free, ANY_ROUTE},
{"jansson_xdecode", (cmd_function)jansson_xdecode, 2,
fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE},
{"jansson_xencode", (cmd_function)jansson_xencode, 2,
fixup_xencode, fixup_xencode_free, ANY_ROUTE},
/* for backwards compatibility */
{"jansson_get_field", (cmd_function)janssonmod_get_field, 3,
fixup_get_params, fixup_get_params_free, ANY_ROUTE},
/* non-script functions */
{"jansson_to_val", (cmd_function)jansson_to_val, 0, 0, 0, 0},

{0, 0, 0, 0, 0, 0}
};

Expand Down Expand Up @@ -142,6 +149,43 @@ static int fixup_set_params_free(void** param, int param_no)
return -1;
}

static int fixup_xencode(void** param, int param_no)
{
if (param_no == 1) {
return fixup_spve_null(param, 1);
}

if (param_no == 2) {
if (fixup_pvar_null(param, 1) != 0) {
LM_ERR("failed to fixup result pvar\n");
return -1;
}
if (((pv_spec_t *)(*param))->setf == NULL) {
LM_ERR("result pvar is not writeble\n");
return -1;
}
return 0;
}

LM_ERR("invalid parameter number <%d>\n", param_no);
return -1;
}

static int fixup_xencode_free(void** param, int param_no)
{
if (param_no == 1) {
fixup_free_spve_null(param, 1);
return 0;
}

if (param_no == 2) {
return fixup_free_pvar_null(param, 1);
}

LM_ERR("invalid parameter number <%d>\n", param_no);
return -1;
}

/* just used for unit testing */
static int mod_init(void) {
return 0;
Expand Down
51 changes: 51 additions & 0 deletions src/modules/jansson/jansson_utils.c
Expand Up @@ -26,6 +26,7 @@
#include <limits.h>

#include "../../core/lvalue.h"
#include "../../core/xavp.h"

#include "jansson_utils.h"

Expand Down Expand Up @@ -81,3 +82,53 @@ int jansson_to_val(pv_value_t* val, char** freeme, json_t* v) {
}
return 0;
}

int jansson_to_xval(sr_xval_t *val, char** freeme, json_t* v) {
if(json_is_object(v) || json_is_array(v)) {
const char* value = json_dumps(v, JSON_COMPACT|JSON_PRESERVE_ORDER);
*freeme = (char*)value;
val->type = SR_XTYPE_STR;
val->v.s.s = (char*)value;
val->v.s.len = strlen(value);
}else if(json_is_string(v)) {
const char* value = json_string_value(v);
val->type = SR_XTYPE_STR;
val->v.s.s = (char*)value;
val->v.s.len = strlen(value);
}else if(json_is_boolean(v)) {
val->type = SR_XTYPE_INT;
val->v.i = json_is_true(v) ? 0 : 1;
}else if(json_is_real(v)) {
char* value = NULL;
if(asprintf(&value, "%.15g", json_real_value(v))<0) {
ERR("asprintf failed\n");
return -1;
}
*freeme = value;
val->type = SR_XTYPE_STR;
val->v.s.s = value;
val->v.s.len = strlen(value);
}else if(json_is_integer(v)) {
long long value = json_integer_value(v);
if ((value > INT_MAX) || (value < INT_MIN)) {
char* svalue = NULL;
if (asprintf(&svalue, "%"JSON_INTEGER_FORMAT, value) < 0) {
ERR("asprintf failed\n");
return -1;
}
*freeme = svalue;
val->type = SR_XTYPE_STR;
val->v.s.s = svalue;
val->v.s.len = strlen(svalue);
} else {
val->type = SR_XTYPE_INT;
val->v.i = (int)value;
}
}else if(json_is_null(v)) {
val->type = SR_XTYPE_NULL;
}else {
ERR("unrecognized json type: %d\n", json_typeof(v));
return -1;
}
return 0;
}
2 changes: 2 additions & 0 deletions src/modules/jansson/jansson_utils.h
Expand Up @@ -27,8 +27,10 @@

#include "../../core/sr_module.h"
#include "../../core/lvalue.h"
#include "../../core/xavp.h"

typedef int (*jansson_to_val_f)(pv_value_t* val, char** freeme, json_t* v);
int jansson_to_val(pv_value_t* val, char** freeme, json_t* v);
int jansson_to_xval(sr_xval_t *val, char** freeme, json_t* v);

#endif