From 12f6992bfaf833179f826033102054ad984f22e1 Mon Sep 17 00:00:00 2001 From: Emmanuel Schmidbauer Date: Fri, 19 Jan 2018 14:01:24 -0700 Subject: [PATCH] json: add transformation --- src/modules/json/doc/json_admin.xml | 26 ++ src/modules/json/json_funcs.c | 283 +++++++++++++++++ src/modules/json/json_funcs.h | 27 ++ src/modules/json/json_mod.c | 40 ++- src/modules/json/json_trans.c | 451 ++++++++++++++++++++++++++++ src/modules/json/json_trans.h | 51 ++++ 6 files changed, 866 insertions(+), 12 deletions(-) create mode 100644 src/modules/json/json_trans.c create mode 100644 src/modules/json/json_trans.h diff --git a/src/modules/json/doc/json_admin.xml b/src/modules/json/doc/json_admin.xml index 2a96304647f..85b3e03e670 100644 --- a/src/modules/json/doc/json_admin.xml +++ b/src/modules/json/doc/json_admin.xml @@ -74,5 +74,31 @@ xlog("foo is $var(foo)"); + +
+ Transformations + You can use the transformation to extract values from the json structured pseudo-variables + + + + json + + + + <function>json.parse</function> usage + + + ... + # extract value of "Custom-Data" from $rb pseudo-variable and set it to $var(Custom-Data) + $var(Custom-Data) = $(rb{json.parse,Custom-Data}); + if($var(Custom-Data) != $null) { xlog("L_INFO", "$ci|log|custom data: $var(Custom-Data) from Request: $rb"); + } + ... + + + + +
+ diff --git a/src/modules/json/json_funcs.c b/src/modules/json/json_funcs.c index 2de892154bc..ae036ac1f1d 100644 --- a/src/modules/json/json_funcs.c +++ b/src/modules/json/json_funcs.c @@ -76,3 +76,286 @@ int json_get_field(struct sip_msg* msg, char* json, char* field, char* dst) json_object_put(j); return ret; } + +#define json_foreach_key(obj, key) \ + char *key; \ + struct lh_entry *entry##key; \ + struct lh_entry *entry_next##key = NULL; \ + for(entry##key = json_object_get_object(obj)->head; \ + (entry##key ? (key = (char *)entry##key->k, \ + entry_next##key = entry##key->next, entry##key) \ + : 0); \ + entry##key = entry_next##key) + + +static str json_pv_str_empty = {"", 0}; + +char **str_split(char *a_str, const char a_delim) +{ + char **result = 0; + size_t count = 0; + char *tmp = a_str; + char *last_comma = 0; + char delim[2]; + delim[0] = a_delim; + delim[1] = 0; + int len = 0; + + /* Count how many elements will be extracted. */ + while(*tmp) { + if(a_delim == *tmp) { + count++; + last_comma = tmp; + } + tmp++; + } + + /* Add space for trailing token. */ + count += last_comma < (a_str + strlen(a_str) - 1); + + /* Add space for terminating null string so caller + knows where the list of returned strings ends. */ + count++; + + result = pkg_malloc(sizeof(char *) * count); + + if(result) { + size_t idx = 0; + char *token = strtok(a_str, delim); + + while(token) { + assert(idx < count); + len = strlen(token); + char *ptr = pkg_malloc((len + 1) * sizeof(char)); + *(result + idx) = ptr; + memcpy(ptr, token, len); + ptr[len] = '\0'; + int i = 0; + while(i < len) { + if(ptr[i] == tr_json_escape_char) + ptr[i] = '.'; + i++; + } + token = strtok(0, delim); + idx++; + } + assert(idx == count - 1); + *(result + idx) = 0; + } + + return result; +} + +struct json_object *tr_json_get_field_object(str *json, str *field) +{ + char **tokens; + char *dup; + char f1[25], f2[25]; //, f3[25]; + int i; + + dup = pkg_malloc(json->len + 1); + memcpy(dup, json->s, json->len); + dup[json->len] = '\0'; + struct json_object *j = json_tokener_parse(dup); + pkg_free(dup); + + if(is_error(j)) { + LM_ERR("empty or invalid JSON\n"); + return NULL; + } + + struct json_object *jtree = NULL; + struct json_object *ret = NULL; + + LM_DBG("getting json %.*s\n", field->len, field->s); + + dup = pkg_malloc(field->len + 1); + memcpy(dup, field->s, field->len); + dup[field->len] = '\0'; + tokens = str_split(dup, '.'); + pkg_free(dup); + + if(tokens) { + jtree = j; + for(i = 0; *(tokens + i); i++) { + if(jtree != NULL) { + str field = str_init(*(tokens + i)); + // check for idx [] + int sresult = sscanf(field.s, "%[^[][%[^]]]", f1, f2); //, f3); + LM_DBG("CHECK IDX %d - %s , %s, %s\n", sresult, field.s, f1, + (sresult > 1 ? f2 : "(null)")); + + jtree = json_get_object(jtree, f1); + if(jtree != NULL) { + char *value = (char *)json_object_get_string(jtree); + LM_DBG("JTREE OK %s\n", value); + } + if(jtree != NULL && sresult > 1 + && json_object_is_type(jtree, json_type_array)) { + int idx = atoi(f2); + jtree = json_object_array_get_idx(jtree, idx); + if(jtree != NULL) { + char *value = (char *)json_object_get_string(jtree); + LM_DBG("JTREE IDX OK %s\n", value); + } + } + } + pkg_free(*(tokens + i)); + } + pkg_free(tokens); + } + + + if(jtree != NULL) + ret = json_object_get(jtree); + + json_object_put(j); + + return ret; +} + + +int tr_json_get_field_ex(str *json, str *field, pv_value_p dst_val) +{ + struct json_object *jtree = tr_json_get_field_object(json, field); + + + if(jtree != NULL) { + char *value = (char *)json_object_get_string(jtree); + int len = strlen(value); + dst_val->rs.s = pkg_malloc(len + 1); + memcpy(dst_val->rs.s, value, len); + dst_val->rs.s[len] = '\0'; + dst_val->rs.len = len; + dst_val->flags = PV_VAL_STR | PV_VAL_PKG; + dst_val->ri = 0; + json_object_put(jtree); + } else { + dst_val->flags = PV_VAL_NULL; + dst_val->rs = json_pv_str_empty; + dst_val->ri = 0; + } + return 1; +} + + +int tr_json_get_field(struct sip_msg *msg, char *json, char *field, char *dst) +{ + str json_s; + str field_s; + pv_spec_t *dst_pv; + pv_value_t dst_val; + + if(fixup_get_svalue(msg, (gparam_p)json, &json_s) != 0) { + LM_ERR("cannot get json string value\n"); + return -1; + } + + if(fixup_get_svalue(msg, (gparam_p)field, &field_s) != 0) { + LM_ERR("cannot get field string value\n"); + return -1; + } + + if(tr_json_get_field_ex(&json_s, &field_s, &dst_val) != 1) + return -1; + + dst_pv = (pv_spec_t *)dst; + dst_pv->setf(msg, &dst_pv->pvp, (int)EQ_T, &dst_val); + if(dst_val.flags & PV_VAL_PKG) { + pkg_free(dst_val.rs.s); + } else if(dst_val.flags & PV_VAL_SHM) { + shm_free(dst_val.rs.s); + } + + return 1; +} + +struct json_object *json_parse(const char *str) +{ + struct json_tokener *tok; + struct json_object *obj; + + tok = json_tokener_new(); + if(!tok) { + LM_ERR("Error parsing json: could not allocate tokener\n"); + return NULL; + } + + obj = json_tokener_parse_ex(tok, str, -1); + if(tok->err != json_tokener_success) { + LM_ERR("Error parsing json: %s\n", json_tokener_error_desc(tok->err)); + LM_ERR("%s\n", str); + if(obj != NULL) { + json_object_put(obj); + } + obj = NULL; + } + + json_tokener_free(tok); + return obj; +} + +struct json_object *json_get_object( + struct json_object *jso, const char *key) +{ + struct json_object *result = NULL; + json_object_object_get_ex(jso, key, &result); + return result; +} + +int tr_json_get_keys(struct sip_msg *msg, char *json, char *field, char *dst) +{ + str json_s; + str field_s; + int_str keys_avp_name; + unsigned short keys_avp_type; + pv_spec_t *avp_spec; + + if(fixup_get_svalue(msg, (gparam_p)json, &json_s) != 0) { + LM_ERR("cannot get json string value\n"); + return -1; + } + + if(fixup_get_svalue(msg, (gparam_p)field, &field_s) != 0) { + LM_ERR("cannot get field string value\n"); + return -1; + } + + if(dst == NULL) { + LM_ERR("avp spec is null\n"); + return -1; + } + + avp_spec = (pv_spec_t *)dst; + + if(avp_spec->type != PVT_AVP) { + LM_ERR("invalid avp spec\n"); + return -1; + } + + if(pv_get_avp_name(0, &avp_spec->pvp, &keys_avp_name, &keys_avp_type) + != 0) { + LM_ERR("invalid AVP definition\n"); + return -1; + } + + struct json_object *jtree = tr_json_get_field_object(&json_s, &field_s); + + if(jtree != NULL) { + json_foreach_key(jtree, k) + { + LM_DBG("ITERATING KEY %s\n", k); + int_str v1; + v1.s.s = k; + v1.s.len = strlen(k); + if(add_avp(AVP_VAL_STR | keys_avp_type, keys_avp_name, v1) < 0) { + LM_ERR("failed to create AVP\n"); + json_object_put(jtree); + return -1; + } + } + json_object_put(jtree); + } + + return 1; +} diff --git a/src/modules/json/json_funcs.h b/src/modules/json/json_funcs.h index 6c4067d1933..331d1e3df8b 100644 --- a/src/modules/json/json_funcs.h +++ b/src/modules/json/json_funcs.h @@ -25,7 +25,34 @@ #define _JSON_FUNCS_H_ #include "../../core/parser/msg_parser.h" +#include int json_get_field(struct sip_msg* msg, char* json, char* field, char* dst); +#define json_extract_field(json_name, field) \ + do { \ + struct json_object *obj = json_get_object(json_obj, json_name); \ + field.s = (char *)json_object_get_string(obj); \ + if(field.s == NULL) { \ + LM_DBG("Json-c error - failed to extract field [%s]\n", \ + json_name); \ + field.s = ""; \ + } else { \ + field.len = strlen(field.s); \ + } \ + LM_DBG("%s: [%s]\n", json_name, field.s ? field.s : "Empty"); \ + } while(0); + + +extern char tr_json_escape_char; +extern str json_event_key; +extern str json_event_sub_key; + +int tr_json_get_field(struct sip_msg *msg, char *json, char *field, char *dst); +int tr_json_get_keys(struct sip_msg *msg, char *json, char *field, char *dst); + +struct json_object *json_parse(const char *str); +struct json_object *json_get_object( + struct json_object *jso, const char *key); + #endif diff --git a/src/modules/json/json_mod.c b/src/modules/json/json_mod.c index 9b8c6bdbba3..4ab9ab18295 100644 --- a/src/modules/json/json_mod.c +++ b/src/modules/json/json_mod.c @@ -28,34 +28,50 @@ #include "../../core/sr_module.h" #include "json_funcs.h" +#include "json_trans.h" MODULE_VERSION static int fixup_get_field(void** param, int param_no); static int fixup_get_field_free(void** param, int param_no); +str tr_json_escape_str = str_init("%"); +char tr_json_escape_char = '%'; /* Exported functions */ +static tr_export_t mod_trans[] = { + {{"json", sizeof("json") - 1}, json_tr_parse}, {{0, 0}, 0}}; + static cmd_export_t cmds[]={ {"json_get_field", (cmd_function)json_get_field, 3, fixup_get_field, fixup_get_field_free, ANY_ROUTE}, {0, 0, 0, 0, 0, 0} }; +static param_export_t params[] = { + {"json_escape_char", PARAM_STR, &tr_json_escape_str}, {0, 0, 0}}; + struct module_exports exports = { - "json", - DEFAULT_DLFLAGS, /* dlopen flags */ - cmds, /* Exported functions */ - 0, /* Exported parameters */ - 0, /* exported statistics */ - 0, /* exported MI functions */ - 0, /* exported pseudo-variables */ - 0, /* extra processes */ - 0, /* module initialization function */ - 0, /* response function*/ - 0, /* destroy function */ - 0 /* per-child init function */ + "json", DEFAULT_DLFLAGS, /* dlopen flags */ + cmds, /* Exported functions */ + params, /* Exported parameters */ + 0, /* exported statistics */ + 0, /* exported MI functions */ + 0, /* exported pseudo-variables */ + 0, /* extra processes */ + 0, /* module initialization function */ + 0, /* response function*/ + 0, /* destroy function */ + 0 /* per-child init function */ }; +int mod_register(char *path, int *dlflags, void *p1, void *p2) +{ + if(json_tr_init_buffers() < 0) { + LM_ERR("failed to initialize transformations buffers\n"); + return -1; + } + return register_trans_mod(path, mod_trans); +} static int fixup_get_field(void** param, int param_no) { diff --git a/src/modules/json/json_trans.c b/src/modules/json/json_trans.c new file mode 100644 index 00000000000..4287d692a3f --- /dev/null +++ b/src/modules/json/json_trans.c @@ -0,0 +1,451 @@ +/* + * JSON module interface + * + * Copyright (C) 2010-2014 2600Hz + * + * This file is part of Kamailio, a free SIP server. + * + * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Contributor(s): + * Emmanuel Schmidbauer + * + */ + +#include "../../core/trim.h" +#include "../../core/mod_fix.h" + +#include "json_trans.h" + +/*! transformation buffer size */ +#define JSON_TR_BUFFER_SIZE 65536 +#define JSON_TR_BUFFER_SLOTS 4 + +/*! transformation buffer */ +static char **_json_tr_buffer_list = NULL; + +static char *_json_tr_buffer = NULL; + +static int _json_tr_buffer_idx = 0; + +#define JSON_TR_ALLOC_PARSE_SIZE 2048 + +static pv_spec_t **_json_parse_specs = NULL; +static tr_param_t **_json_parse_params = NULL; +static int _json_tr_parse_spec = 0; +static int _json_tr_parse_params = 0; + + +/*! + * + */ +int json_tr_init_buffers(void) +{ + int i; + + _json_tr_buffer_list = (char **)malloc(JSON_TR_BUFFER_SLOTS * sizeof(char *)); + + if(_json_tr_buffer_list == NULL) + return -1; + for(i = 0; i < JSON_TR_BUFFER_SLOTS; i++) { + _json_tr_buffer_list[i] = (char *)malloc(JSON_TR_BUFFER_SIZE); + if(_json_tr_buffer_list[i] == NULL) + return -1; + } + + _json_parse_specs = + (pv_spec_t **)malloc(JSON_TR_ALLOC_PARSE_SIZE * sizeof(pv_spec_t *)); + for(i = 0; i < JSON_TR_ALLOC_PARSE_SIZE; i++) + _json_parse_specs[i] = NULL; + + _json_parse_params = (tr_param_t **)malloc( + JSON_TR_ALLOC_PARSE_SIZE * sizeof(tr_param_t *)); + for(i = 0; i < JSON_TR_ALLOC_PARSE_SIZE; i++) + _json_parse_params[i] = NULL; + + return 0; +} + +void json_tr_clear_buffers(void) +{ + int i; + if(_json_tr_buffer_list != NULL) { + for(i = 0; i < JSON_TR_BUFFER_SLOTS; i++) { + if(_json_tr_buffer_list[i] != NULL) { + free(_json_tr_buffer_list[i]); + _json_tr_buffer_list[i] = NULL; + } + } + free(_json_tr_buffer_list); + _json_tr_buffer_list = NULL; + } + + if(_json_parse_specs != NULL) { + for(i = 0; i < JSON_TR_ALLOC_PARSE_SIZE; i++) { + if(_json_parse_specs[i] != NULL) { + free(_json_parse_specs[i]); + _json_parse_specs[i] = NULL; + } + } + free(_json_parse_specs); + _json_parse_specs = NULL; + } + + if(_json_parse_params != NULL) { + for(i = 0; i < JSON_TR_ALLOC_PARSE_SIZE; i++) { + if(_json_parse_params[i] != NULL) { + free(_json_parse_params[i]); + _json_parse_params[i] = NULL; + } + } + free(_json_parse_params); + _json_parse_params = NULL; + } +} + +char *json_tr_set_crt_buffer(void) +{ + _json_tr_buffer = _json_tr_buffer_list[_json_tr_buffer_idx]; + _json_tr_buffer_idx = (_json_tr_buffer_idx + 1) % JSON_TR_BUFFER_SLOTS; + return _json_tr_buffer; +} + +#define json_tr_string_clone_result \ + do { \ + if(val->rs.len > JSON_TR_BUFFER_SIZE - 1) { \ + LM_ERR("result is too big\n"); \ + return -1; \ + } \ + strncpy(_json_tr_buffer, val->rs.s, val->rs.len); \ + val->rs.s = _json_tr_buffer; \ + } while(0); + +void json_destroy_pv_value(pv_value_t *val) +{ + if(val->flags & PV_VAL_PKG) + pkg_free(val->rs.s); + else if(val->flags & PV_VAL_SHM) + shm_free(val->rs.s); + pkg_free(val); +} + +void json_free_pv_value(pv_value_t *val) +{ + if(val->flags & PV_VAL_PKG) + pkg_free(val->rs.s); + else if(val->flags & PV_VAL_SHM) + shm_free(val->rs.s); +} + +pv_value_t *json_alloc_pv_value() +{ + pv_value_t *v = (pv_value_t *)pkg_malloc(sizeof(pv_value_t)); + if(v != NULL) + memset(v, 0, sizeof(pv_value_t)); + return v; +} + +#define KEY_SAFE(C) \ + ((C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z') \ + || (C >= '0' && C <= '9') || (C == '-' || C == '~' || C == '_')) + +#define HI4(C) (C >> 4) +#define LO4(C) (C & 0x0F) + +#define hexint(C) (C < 10 ? ('0' + C) : ('A' + C - 10)) + +char *json_util_encode(const str *key, char *dest) +{ + if((key->len == 1) && (key->s[0] == '#' || key->s[0] == '*')) { + *dest++ = key->s[0]; + return dest; + } + char *p, *end; + for(p = key->s, end = key->s + key->len; p < end; p++) { + if(KEY_SAFE(*p)) { + *dest++ = *p; + } else if(*p == '.') { + memcpy(dest, "\%2E", 3); + dest += 3; + } else if(*p == ' ') { + *dest++ = '+'; + } else { + *dest++ = '%'; + sprintf(dest, "%c%c", hexint(HI4(*p)), hexint(LO4(*p))); + dest += 2; + } + } + *dest = '\0'; + return dest; +} + +int json_encode_ex(str *unencoded, pv_value_p dst_val) +{ + char routing_key_buff[256]; + memset(routing_key_buff, 0, sizeof(routing_key_buff)); + json_util_encode(unencoded, routing_key_buff); + + int len = strlen(routing_key_buff); + dst_val->rs.s = pkg_malloc(len + 1); + memcpy(dst_val->rs.s, routing_key_buff, len); + dst_val->rs.s[len] = '\0'; + dst_val->rs.len = len; + dst_val->flags = PV_VAL_STR | PV_VAL_PKG; + + return 1; +} + +/*! + * \brief Evaluate JSON transformations + * \param msg SIP message + * \param tp transformation + * \param subtype transformation type + * \param val pseudo-variable + * \return 0 on success, -1 on error + */ +int json_tr_eval( + struct sip_msg *msg, tr_param_t *tp, int subtype, pv_value_t *val) +{ + + str sv; + pv_value_t *pv; + pv_value_t v; + str v2 = {0, 0}; + void *v1 = NULL; + + if(val == NULL || (val->flags & PV_VAL_NULL)) + return -1; + + + json_tr_set_crt_buffer(); + + switch(subtype) { + case TR_JSON_ENCODE: + if(!(val->flags & PV_VAL_STR)) + return -1; + + pv = json_alloc_pv_value(); + if(pv == NULL) { + LM_ERR("JSON encode transform : no more private memory\n"); + return -1; + } + + if(json_encode_ex(&val->rs, pv) != 1) { + LM_ERR("error encoding value\n"); + json_destroy_pv_value(pv); + return -1; + } + + strncpy(_json_tr_buffer, pv->rs.s, pv->rs.len); + _json_tr_buffer[pv->rs.len] = '\0'; + + val->flags = PV_VAL_STR; + val->ri = 0; + val->rs.s = _json_tr_buffer; + val->rs.len = pv->rs.len; + + json_destroy_pv_value(pv); + json_free_pv_value(val); + + break; + case TR_JSON_PARSE: + if(!(val->flags & PV_VAL_STR)) + return -1; + + if(tp == NULL) { + LM_ERR("JSON json transform invalid parameter\n"); + return -1; + } + + pv = json_alloc_pv_value(); + if(pv == NULL) { + LM_ERR("JSON encode transform : no more private memory\n"); + return -1; + } + + + if(tp->type == TR_PARAM_STRING) { + v1 = tp->v.s.s; + if(fixup_spve_null(&v1, 1) != 0) { + LM_ERR("cannot get spve_value from TR_PARAM_STRING : " + "%.*s\n", + tp->v.s.len, tp->v.s.s); + return -1; + } + if(fixup_get_svalue(msg, (gparam_p)v1, &v2) != 0) { + LM_ERR("cannot get value from TR_PARAM_STRING\n"); + fixup_free_spve_null(&v1, 1); + return -1; + } + fixup_free_spve_null(&v1, 1); + sv = v2; + } else { + if(pv_get_spec_value(msg, (pv_spec_p)tp->v.data, &v) != 0 + || (!(v.flags & PV_VAL_STR)) || v.rs.len <= 0) { + LM_ERR("value cannot get spec value in json transform\n"); + json_destroy_pv_value(pv); + return -1; + } + sv = v.rs; + } + + + if(tr_json_get_field_ex(&val->rs, &sv, pv) != 1) { + LM_ERR("error getting json\n"); + json_destroy_pv_value(pv); + return -1; + } + + strncpy(_json_tr_buffer, pv->rs.s, pv->rs.len); + _json_tr_buffer[pv->rs.len] = '\0'; + + val->flags = PV_VAL_STR; + val->ri = 0; + val->rs.s = _json_tr_buffer; + val->rs.len = pv->rs.len; + + json_destroy_pv_value(pv); + json_free_pv_value(val); + + break; + + default: + LM_ERR("unknown JSON transformation subtype %d\n", subtype); + return -1; + } + return 0; +} + +#define _json_tr_parse_sparam(_p, _p0, _tp, _spec, _ps, _in, _s) \ + while(is_in_str(_p, _in) && (*_p == ' ' || *_p == '\t' || *_p == '\n')) \ + _p++; \ + if(*_p == PV_MARKER) { /* pseudo-variable */ \ + _spec = (pv_spec_t *)malloc(sizeof(pv_spec_t)); \ + if(_spec == NULL) { \ + LM_ERR("no more private memory!\n"); \ + goto error; \ + } \ + _s.s = _p; \ + _s.len = _in->s + _in->len - _p; \ + _p0 = pv_parse_spec(&_s, _spec); \ + if(_p0 == NULL) { \ + LM_ERR("invalid spec in substr transformation: %.*s!\n", _in->len, \ + _in->s); \ + goto error; \ + } \ + _p = _p0; \ + _tp = (tr_param_t *)malloc(sizeof(tr_param_t)); \ + if(_tp == NULL) { \ + LM_ERR("no more private memory!\n"); \ + goto error; \ + } \ + memset(_tp, 0, sizeof(tr_param_t)); \ + _tp->type = TR_PARAM_SPEC; \ + _tp->v.data = (void *)_spec; \ + _json_parse_specs[_json_tr_parse_spec++] = _spec; \ + _json_parse_params[_json_tr_parse_params++] = _tp; \ + } else { /* string */ \ + _ps = _p; \ + while(is_in_str(_p, _in) && *_p != '\t' && *_p != '\n' \ + && *_p != TR_PARAM_MARKER && *_p != TR_RBRACKET) \ + _p++; \ + if(*_p == '\0') { \ + LM_ERR("invalid param in transformation: %.*s!!\n", _in->len, \ + _in->s); \ + goto error; \ + } \ + _tp = (tr_param_t *)malloc(sizeof(tr_param_t)); \ + if(_tp == NULL) { \ + LM_ERR("no more private memory!\n"); \ + goto error; \ + } \ + memset(_tp, 0, sizeof(tr_param_t)); \ + _tp->type = TR_PARAM_STRING; \ + _tp->v.s.len = _p - _ps; \ + _tp->v.s.s = (char *)malloc((tp->v.s.len + 1) * sizeof(char)); \ + strncpy(_tp->v.s.s, _ps, tp->v.s.len); \ + _tp->v.s.s[tp->v.s.len] = '\0'; \ + _json_parse_params[_json_tr_parse_params++] = _tp; \ + } + + +/*! + * \brief Helper fuction to parse a JSON transformation + * \param in parsed string + * \param t transformation + * \return pointer to the end of the transformation in the string - '}', null on error + */ +char *json_tr_parse(str *in, trans_t *t) +{ + char *p; + char *p0; + char *ps; + str name; + str s; + pv_spec_t *spec = NULL; + tr_param_t *tp = NULL; + + if(in == NULL || t == NULL) + return NULL; + + p = in->s; + name.s = in->s; + t->type = TR_JSON; + t->trf = json_tr_eval; + + /* find next token */ + while(is_in_str(p, in) && *p != TR_PARAM_MARKER && *p != TR_RBRACKET) + p++; + if(*p == '\0') { + LM_ERR("invalid transformation: %.*s\n", in->len, in->s); + goto error; + } + name.len = p - name.s; + trim(&name); + + if(name.len == 5 && strncasecmp(name.s, "encode", 6) == 0) { + t->subtype = TR_JSON_ENCODE; + goto done; + } else if(name.len == 5 && strncasecmp(name.s, "parse", 5) == 0) { + t->subtype = TR_JSON_PARSE; + if(*p != TR_PARAM_MARKER) { + LM_ERR("invalid json transformation: %.*s!\n", in->len, in->s); + goto error; + } + p++; + _json_tr_parse_sparam(p, p0, tp, spec, ps, in, s); + t->params = tp; + tp = 0; + while(*p && (*p == ' ' || *p == '\t' || *p == '\n')) + p++; + if(*p != TR_RBRACKET) { + LM_ERR("invalid json transformation: %.*s!!\n", in->len, in->s); + goto error; + } + goto done; + } + + LM_ERR("unknown JSON transformation: %.*s/%.*s/%d!\n", in->len, in->s, + name.len, name.s, name.len); +error: + if(tp) + free(tp); + if(spec) + free(spec); + return NULL; +done: + t->name = name; + return p; +} diff --git a/src/modules/json/json_trans.h b/src/modules/json/json_trans.h new file mode 100644 index 00000000000..c222afe6877 --- /dev/null +++ b/src/modules/json/json_trans.h @@ -0,0 +1,51 @@ +/* + * JSON module interface + * + * Copyright (C) 2010-2014 2600Hz + * + * This file is part of Kamailio, a free SIP server. + * + * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Contributor(s): + * Emmanuel Schmidbauer + * + */ + +#ifndef _JSON_TRANS_H_ +#define _JSON_TRANS_H_ + +#include "../../core/pvar.h" + +enum _json_tr_type +{ + TR_NONE = 0, + TR_JSON +}; +enum _json_tr_subtype +{ + TR_JSON_NONE = 0, + TR_JSON_ENCODE, + TR_JSON_PARSE +}; + +char *json_tr_parse(str *in, trans_t *tr); +int tr_json_get_field_ex(str *json, str *field, pv_value_p dst_val); + +int json_tr_init_buffers(void); +void json_tr_clear_buffers(void); + + +#endif