Ver Fonte

jansson: new module for json doc handling using jansson library

- alternative to existing json module, but with support for json-path
  expressions
- rescued from branch mgw/json
Daniel-Constantin Mierla há 10 anos atrás
pai
commit
2e6af40ed0

+ 22 - 0
modules/jansson/Makefile

@@ -0,0 +1,22 @@
+#
+# jansson module makefile
+#
+# 
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=jansson.so
+
+BUILDER = $(shell which pkg-config)
+ifeq ($(BUILDER),)
+	DEFS+=-I$(LOCALBASE)/include \
+	LIBS+=-L$(SYSBASE)/include/lib -L$(LOCALBASE)/lib -ljansson
+else
+	DEFS+= $(shell pkg-config --cflags jansson)
+	LIBS+= $(shell pkg-config --libs jansson)
+endif
+DEFS+=-DOPENSER_MOD_INTERFACE
+
+SERLIBPATH=../../lib
+include ../../Makefile.modules

+ 236 - 0
modules/jansson/README

@@ -0,0 +1,236 @@
+JANSSON Module
+
+Joe Hillenbrand
+
+   <[email protected]>
+
+Edited by
+
+Matthew Williams
+
+   <[email protected]>
+
+   Copyright © 2013 Flowroute LLC (flowroute.com)
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Dependencies
+
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
+
+        3. Parameters
+
+              3.1.
+
+        4. Functions
+
+              4.1. jansson_get(key/path, src, dst)
+              4.2. jansson_set(type, key/path, value, result)
+              4.3. jansson_append(type, key/path, value, result)
+              4.4. jansson_array_size(key/path, src, dst)
+              4.5. jansson_get_field(src, field_name, dst)
+
+   List of Examples
+
+   1.1. jansson_get usage
+   1.2. jansson_set usage
+   1.3. jansson_append usage
+   1.4. jansson_array_size usage
+   1.5. array concatination
+   1.6. jansson_get_field usage
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Parameters
+
+        3.1.
+
+   4. Functions
+
+        4.1. jansson_get(key/path, src, dst)
+        4.2. jansson_set(type, key/path, value, result)
+        4.3. jansson_append(type, key/path, value, result)
+        4.4. jansson_array_size(key/path, src, dst)
+        4.5. jansson_get_field(src, field_name, dst)
+
+1. Overview
+
+   This module provides operations on JSON strings using JANSSON library.
+   It has support for JSON-PATH operations.
+
+2. Dependencies
+
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
+
+2.1. Kamailio Modules
+
+   The following modules must be loaded before this module:
+     * None
+
+2.2. External Libraries or Applications
+
+   The following libraries or applications must be installed before
+   running Kamailio with this module loaded:
+     * jansson (http://www.digip.org/jansson/), tested with: 2.2+
+
+3. Parameters
+
+   3.1.
+
+   None
+
+4. Functions
+
+   4.1. jansson_get(key/path, src, dst)
+   4.2. jansson_set(type, key/path, value, result)
+   4.3. jansson_append(type, key/path, value, result)
+   4.4. jansson_array_size(key/path, src, dst)
+   4.5. jansson_get_field(src, field_name, dst)
+
+4.1. jansson_get(key/path, src, dst)
+
+   Copy the value at the location 'path' from the json object 'src' and
+   store it in pvar 'dst'.
+
+   The path string supports dot delimited notation (e.g. foo.bar.baz),
+   array notation (e.g. [0]), or a combination of the two (e.g.
+   foo.bar[0][1].baz).
+
+   The function can put a string, integer, null, or new json string into
+   destination.
+
+   Example 1.1. jansson_get usage
+...
+jansson_get("inner.deep.list[3]", $var(myjson), "$var(n)");
+xlog("foo is $var(n)");
+...
+
+4.2. jansson_set(type, key/path, value, result)
+
+   Insert 'value' as 'type' at location 'path' into 'result'.
+
+   The path string works the same as in jansson_get.
+
+   Valid 'type' parameters are 'integer', 'real', 'string', 'object',
+   'array', 'true', 'false', and 'null' as well as abbriviated names such
+   as 'int', 'str', and 'obj'. 'value' is ignored when type is 'true',
+   'false', or 'null'.
+
+   Example 1.2. jansson_set usage
+...
+# create a new json object and put a string in it at key "mystr"
+jansson_set("string", "mystr", "my input string", "$var(myjson)");
+# $var(myjson) =='{"mystr":"my input string"}'
+
+# add other values
+jansson_set("integer", "count", 9000, "$var(myjson)");
+jansson_set("true", "mybool", 0, "$var(myjson)");
+jansson_set("real", "pi", "3.14159", "$var(myjson)");
+# $var(myjson) == '{"mystr":"my input string", "count":9000, "mybool":true, "pi"
+:3.14159}'
+
+# add a nested object
+jansson_set("obj", "myobj", '{"foo":"bar"}', "$var(myjson)");
+# $var(myjson) =='{"mystr":"my input string", "count":9000, "mybool":true, "pi":
+3.14159, "myobj":{"foo":"bar"}}'
+
+# change the nested object
+jansson_set("str", "myobj.foo", "baz", "$var(myjson)");
+# $var(myjson) == '{"mystr":"my input string", "count":9000, "mybool":true, "pi"
+:3.14159, "myobj":{"foo":"baz"}}'
+...
+
+4.3. jansson_append(type, key/path, value, result)
+
+   Like jansson_set but can be used to append to arrays. It can also be
+   used to combine two json objects.
+
+   Note that when appending a json object to another json object, if there
+   is a key that is shared between the two objects, that value will be
+   overwritten by the new object.
+
+   Example 1.3. jansson_append usage
+...
+# create a new json array and append values to it
+$var(myarray) = '[]';
+jansson_append("int", "", 0, "$var(myarray)");
+jansson_append("int", "", 1, "$var(myarray)");
+jansson_append("int", "", 2, "$var(myarray)");
+jansson_append("int", "", 3, "$var(myarray)");
+jansson_append("int", "", 4, "$var(myarray)");
+# $var(myarray) == '[0,1,2,3,4]'
+
+# add that array to an object
+jansson_set("array", "list", $var(myarray), "$var(myjson)");
+# $var(myjson) == '{"list":[0,1,2,3,4]}'
+
+# append another value to the list
+jansson_append("int", "list", 5, "$var(myjson)");
+# $var(myjson) == '{"list":[0,1,2,3,4,5]}'
+
+# combining two json objects
+$var(newobj) = '{"b":2, "c":3}';
+jansson_append('obj', "", '{"a":1, "b":100}', "$var(newobj)");
+# $var(newobj) == '{"a":1,"b":100","c":3}';
+...
+
+4.4. jansson_array_size(key/path, src, dst)
+
+   Puts the size of the array in 'src' at location 'path' into the pvar
+   'dst'.
+
+   This is particularly useful for looping through an array. See example.
+
+   Example 1.4. jansson_array_size usage
+...
+$var(array) = "{\"loopme\":[0,1,2,3,4,5]}";
+$var(count) = 0;
+jansson_array_size("loopme", $var(array), "$var(size)");
+while($var(count) < $var(size)) {
+    jansson_get("loopme[$var(count)]", $var(array), "$var(v)");
+    xlog("loopme[$var(count)] == $var(v)\n");
+    $var(count) = $var(count) + 1;
+}
+...
+
+   Example 1.5. array concatination
+...
+$var(count) = 0;
+$var(appendme) = '[0,1]';
+$var(mylist) = '[2,3,4,5]';
+jansson_array_size("", $var(mylist), "$var(appendme_size)");
+while($var(count) < $var(appendme_size)) {
+    jansson_get("[$var(count)]", $var(mylist), "$var(tmp)");
+    jansson_append('int', "", $var(tmp), "$var(appendme)");
+    $var(count) = $var(count) + 1;
+}
+...
+
+4.5. jansson_get_field(src, field_name, dst)
+
+   Copy field 'field_name' from json object 'src' and store it in pvar
+   'dst'.
+
+   This function is deprecated but kept for backwards compatibility. Right
+   now it is just a wrapper around jansson_get, and its functionality is
+   the same.
+
+   Example 1.6. jansson_get_field usage
+...
+jansson_get_field("{'foo':'bar'}", "foo", "$var(foo)");
+xlog("foo is $var(foo)");
+...

+ 4 - 0
modules/jansson/doc/Makefile

@@ -0,0 +1,4 @@
+docs = jansson.xml
+
+docbook_dir = ../../../docbook
+include $(docbook_dir)/Makefile.module

+ 37 - 0
modules/jansson/doc/jansson.xml

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+    <bookinfo>
+	<title>JANSSON Module</title>
+	<productname class="trade">kamailio.org</productname>
+	<authorgroup>
+	    <author>
+		<firstname>Joe</firstname>
+		<surname>Hillenbrand</surname>
+		<email>[email protected]</email>
+	    </author>
+	    <editor>
+			<firstname>Matthew</firstname>
+			<surname>Williams</surname>
+			<email>[email protected]</email>
+	    </editor>
+	</authorgroup>
+	<copyright>
+	    <year>2013</year>
+	    <holder>Flowroute LLC (flowroute.com)</holder>
+	</copyright>
+    </bookinfo>
+    <toc></toc>
+    
+    <xi:include href="jansson_admin.xml"/>
+    
+    
+</book>

+ 230 - 0
modules/jansson/doc/jansson_admin.xml

@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+<!-- Module User's Guide -->
+
+<chapter>
+
+    <title>&adminguide;</title>
+
+    <section>
+    <title>Overview</title>
+    <para>
+		This module provides operations on JSON strings using JANSSON
+		library. It has support for JSON-PATH operations.
+    </para>
+    </section>
+
+    <section>
+    <title>Dependencies</title>
+    <section>
+        <title>&kamailio; Modules</title>
+        <para>
+        The following modules must be loaded before this module:
+            <itemizedlist>
+            <listitem>
+            <para>
+                <emphasis>None</emphasis>
+            </para>
+            </listitem>
+            </itemizedlist>
+        </para>
+    </section>
+    <section>
+        <title>External Libraries or Applications</title>
+        <para>
+        The following libraries or applications must be installed before running
+        &kamailio; with this module loaded:
+            <itemizedlist>
+            <listitem>
+            <para>
+                <emphasis>jansson (http://www.digip.org/jansson/)</emphasis>, tested with: 2.2+
+            </para>
+            </listitem>
+            </itemizedlist>
+        </para>
+    </section>
+    </section>
+    <section>
+    <title>Parameters</title>
+    <section>
+        <para>
+            <emphasis>None</emphasis>
+        </para>
+    </section>
+    </section>
+
+    <section>
+    <title>Functions</title>
+    <section>
+        <title>
+            <function moreinfo="none">jansson_get(key/path, src, dst)</function>
+        </title>
+        <para>
+            Copy the value at the location 'path' from the json object 'src' and store it in pvar 'dst'.
+        </para>
+        <para>
+            The path string supports dot delimited notation (e.g. foo.bar.baz), array notation (e.g. [0]), or a combination of the two (e.g. foo.bar[0][1].baz).
+        </para>
+        <para>
+            The function can put a string, integer, null, or new json string into destination.
+        </para>
+        <example>
+        <title><function>jansson_get</function> usage</title>
+        <programlisting format="linespecific">
+...
+jansson_get("inner.deep.list[3]", $var(myjson), "$var(n)");
+xlog("foo is $var(n)");
+...
+        </programlisting>
+        </example>
+    </section>
+    <section>
+        <title>
+            <function moreinfo="none">jansson_set(type, key/path, value, result)</function>
+        </title>
+        <para>
+            Insert 'value' as 'type' at location 'path' into 'result'.
+        </para>
+        <para>
+            The path string works the same as in jansson_get.
+        </para>
+        <para>
+            Valid 'type' parameters are 'integer', 'real', 'string', 'object', 'array', 'true', 'false', and 'null'  as well as
+            abbriviated names such as 'int', 'str', and 'obj'. 'value' is ignored when type is 'true', 'false', or 'null'.
+        </para>
+        <example>
+        <title><function>jansson_set</function> usage</title>
+        <programlisting format="linespecific">
+...
+# create a new json object and put a string in it at key "mystr"
+jansson_set("string", "mystr", "my input string", "$var(myjson)");
+# $var(myjson) =='{"mystr":"my input string"}'
+
+# add other values
+jansson_set("integer", "count", 9000, "$var(myjson)");
+jansson_set("true", "mybool", 0, "$var(myjson)");
+jansson_set("real", "pi", "3.14159", "$var(myjson)");
+# $var(myjson) == '{"mystr":"my input string", "count":9000, "mybool":true, "pi":3.14159}'
+
+# add a nested object
+jansson_set("obj", "myobj", '{"foo":"bar"}', "$var(myjson)");
+# $var(myjson) =='{"mystr":"my input string", "count":9000, "mybool":true, "pi":3.14159, "myobj":{"foo":"bar"}}'
+
+# change the nested object
+jansson_set("str", "myobj.foo", "baz", "$var(myjson)");
+# $var(myjson) == '{"mystr":"my input string", "count":9000, "mybool":true, "pi":3.14159, "myobj":{"foo":"baz"}}'
+...
+        </programlisting>
+        </example>
+    </section>
+    <section>
+        <title>
+            <function moreinfo="none">jansson_append(type, key/path, value, result)</function>
+        </title>
+        <para>
+            Like jansson_set but can be used to append to arrays. It can also be used to combine two json objects.
+        </para>
+        <para>
+            Note that when appending a json object to another json object, if there is a key that is shared between the two objects, that value will be overwritten by the new object.
+        </para>
+        <example>
+        <title><function>jansson_append</function> usage</title>
+        <programlisting format="linespecific">
+...
+# create a new json array and append values to it
+$var(myarray) = '[]';
+jansson_append("int", "", 0, "$var(myarray)");
+jansson_append("int", "", 1, "$var(myarray)");
+jansson_append("int", "", 2, "$var(myarray)");
+jansson_append("int", "", 3, "$var(myarray)");
+jansson_append("int", "", 4, "$var(myarray)");
+# $var(myarray) == '[0,1,2,3,4]'
+
+# add that array to an object
+jansson_set("array", "list", $var(myarray), "$var(myjson)");
+# $var(myjson) == '{"list":[0,1,2,3,4]}'
+
+# append another value to the list
+jansson_append("int", "list", 5, "$var(myjson)");
+# $var(myjson) == '{"list":[0,1,2,3,4,5]}'
+
+# combining two json objects
+$var(newobj) = '{"b":2, "c":3}';
+jansson_append('obj', "", '{"a":1, "b":100}', "$var(newobj)");
+# $var(newobj) == '{"a":1,"b":100","c":3}';
+...
+        </programlisting>
+        </example>
+    </section>
+    <section>
+        <title>
+            <function moreinfo="none">jansson_array_size(key/path, src, dst)</function>
+        </title>
+        <para>
+            Puts the size of the array in 'src' at location 'path' into the pvar 'dst'.
+        </para>
+        <para>
+            This is particularly useful for looping through an array. See example.
+        </para>
+        <example>
+        <title><function>jansson_array_size</function> usage</title>
+        <programlisting format="linespecific">
+...
+$var(array) = "{\"loopme\":[0,1,2,3,4,5]}";
+$var(count) = 0;
+jansson_array_size("loopme", $var(array), "$var(size)");
+while($var(count) &lt; $var(size)) {
+    jansson_get("loopme[$var(count)]", $var(array), "$var(v)");
+    xlog("loopme[$var(count)] == $var(v)\n");
+    $var(count) = $var(count) + 1;
+}
+...
+        </programlisting>
+        </example>
+        <example>
+        <title>array concatination</title>
+        <programlisting format="linespecific">
+...
+$var(count) = 0;
+$var(appendme) = '[0,1]';
+$var(mylist) = '[2,3,4,5]';
+jansson_array_size("", $var(mylist), "$var(appendme_size)");
+while($var(count) &lt; $var(appendme_size)) {
+    jansson_get("[$var(count)]", $var(mylist), "$var(tmp)");
+    jansson_append('int', "", $var(tmp), "$var(appendme)");
+    $var(count) = $var(count) + 1;
+}
+...
+        </programlisting>
+        </example>
+    </section>
+    <section>
+        <title>
+            <function moreinfo="none">jansson_get_field(src, field_name, dst)</function>
+        </title>
+        <para>
+            Copy field 'field_name' from json object 'src' and store it in pvar 'dst'.
+        </para>
+        <para>
+            <emphasis>This function is deprecated</emphasis> but kept for backwards compatibility. Right now it is just a wrapper around <function>jansson_get</function>, and its functionality is the same.
+        </para>
+        <example>
+        <title><function>jansson_get_field</function> usage</title>
+        <programlisting format="linespecific">
+...
+jansson_get_field("{'foo':'bar'}", "foo", "$var(foo)");
+xlog("foo is $var(foo)");
+...
+        </programlisting>
+        </example>
+    </section>
+    </section>
+</chapter>
+

+ 293 - 0
modules/jansson/jansson_funcs.c

@@ -0,0 +1,293 @@
+/**
+ * Copyright (C) 2013 Flowroute LLC (flowroute.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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
+ *
+ *
+ * This file 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
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <jansson.h>
+
+#include "../../mod_fix.h"
+#include "../../lvalue.h"
+
+#include "jansson_path.h"
+#include "jansson_funcs.h"
+#include "jansson_utils.h"
+
+int janssonmod_get(struct sip_msg* msg, char* path_in, char* src_in, char* dst)
+{
+	str src_s;
+	str path_s;
+	pv_spec_t *dst_pv;
+	pv_value_t dst_val;
+
+	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)path_in, &path_s) != 0) {
+		ERR("cannot get path string value\n");
+		return -1;
+	}
+
+	dst_pv = (pv_spec_t *)dst;
+
+	json_t* json = NULL;
+	json_error_t parsing_error;
+
+	json = json_loads(src_s.s, JSON_REJECT_DUPLICATES, &parsing_error);
+
+	if(!json) {
+		ERR("failed to parse: %.*s\n", src_s.len, src_s.s);
+		ERR("json error at line %d: %s\n",
+				parsing_error.line, parsing_error.text);
+		goto fail;
+	}
+
+	char* path = path_s.s;
+
+	json_t* v = json_path_get(json, path);
+	if(!v) {
+		goto fail;
+	}
+
+	char* freeme = NULL;
+
+	if(jansson_to_val(&dst_val, &freeme, v)<0) goto fail;
+
+	dst_pv->setf(msg, &dst_pv->pvp, (int)EQ_T, &dst_val);
+
+	if(freeme!=NULL) {
+		free(freeme);
+	}
+
+	json_decref(json);
+	return 1;
+
+fail:
+	json_decref(json);
+	return -1;
+}
+
+#define STR_EQ_STATIC(a,b) ((a.len == sizeof(b)-1) && (strncmp(a.s, b, sizeof(b)-1)==0))
+
+int janssonmod_set(unsigned int append, struct sip_msg* msg, char* type_in,
+		 char* path_in, char* value_in, char* result_in)
+{
+	str type_s;
+	str value_s;
+	str path_s;
+
+	pv_spec_t* result_pv;
+	pv_value_t result_val;
+
+	if (fixup_get_svalue(msg, (gparam_p)type_in, &type_s) != 0){
+		ERR("cannot get type string value\n");
+		return -1;
+	}
+
+	if (fixup_get_svalue(msg, (gparam_p)value_in, &value_s) != 0){
+		ERR("cannot get value string\n");
+		return -1;
+	}
+
+	if (fixup_get_svalue(msg, (gparam_p)path_in, &path_s) != 0){
+		ERR("cannot get path string value\n");
+		return -1;
+	}
+
+	result_pv = (pv_spec_t *)result_in;
+
+	if(pv_get_spec_value(msg, result_pv, &result_val)!=0
+			|| result_val.flags != PV_VAL_STR) {
+		result_val.flags = PV_VAL_STR;
+		result_val.rs.s = "{}";
+		result_val.rs.len = strlen("{}");
+	}
+
+/*
+	ALERT("type is: %.*s\n", type_s.len, type_s.s);
+	ALERT("path is: %.*s\n", path_s.len, path_s.s);
+	ALERT("value is: %.*s\n", value_s.len, value_s.s);
+	ALERT("result is: %.*s\n", result_val.rs.len, result_val.rs.s);
+*/
+
+	char* result = result_val.rs.s;
+
+	json_t* result_json = NULL;
+	json_t* value = NULL;
+	char* freeme = NULL;
+	json_error_t parsing_error;
+	char* endptr;
+
+	/* check the type */
+	if(STR_EQ_STATIC(type_s, "object") || STR_EQ_STATIC(type_s, "obj")){
+		value = json_loads(value_s.s, JSON_REJECT_DUPLICATES, &parsing_error);
+		if(value && !json_is_object(value)) {
+			ERR("value to add is not an object\n");
+			goto fail;
+		}
+
+	}else if(STR_EQ_STATIC(type_s, "array")) {
+		value = json_loads(value_s.s, JSON_REJECT_DUPLICATES, &parsing_error);
+		if(value && !json_is_array(value)) {
+			ERR("value to add is not an array\n");
+			goto fail;
+		}
+
+	}else if(STR_EQ_STATIC(type_s, "string")
+				|| STR_EQ_STATIC(type_s, "str")) {
+		value = json_string(value_s.s);
+		if(!value || !json_is_string(value)) {
+			ERR("value to add is not a string\n");
+			goto fail;
+		}
+
+	}else if(STR_EQ_STATIC(type_s, "integer")
+				|| STR_EQ_STATIC(type_s, "int")) {
+		int i = strtol(value_s.s, &endptr, 10);
+		if(*endptr != '\0') {
+			ERR("parsing int failed for \"%s\"\n", value_s.s);
+			goto fail;
+		}
+		value = json_integer(i);
+		if(!value || !json_is_integer(value)) {
+			ERR("value to add is not an integer\n");
+			goto fail;
+		}
+
+	}else if(STR_EQ_STATIC(type_s, "real")) {
+		double d = strtod(value_s.s, &endptr);
+		if(*endptr != '\0') {
+			ERR("parsing real failed for \"%s\"\n", value_s.s);
+			goto fail;
+		}
+		value = json_real(d);
+		if(!value || !json_is_real(value)) {
+			ERR("value to add is not a real\n");
+			goto fail;
+		}
+
+	}else if(STR_EQ_STATIC(type_s, "true")) {
+		value = json_true();
+
+	}else if(STR_EQ_STATIC(type_s, "false")) {
+		value = json_false();
+
+	}else if(STR_EQ_STATIC(type_s, "null")) {
+		value = json_null();
+
+	} else {
+		ERR("unrecognized input type\n");
+		goto fail;
+	}
+
+	if(!value) {
+		ERR("parsing failed for \"%s\"\n", value_s.s);
+		ERR("value error at line %d: %s\n",
+				parsing_error.line, parsing_error.text);
+		goto fail;
+	}
+
+	char* path = path_s.s;
+
+	result_json = json_loads(result, JSON_REJECT_DUPLICATES, &parsing_error);
+
+	if(!result_json) {
+		ERR("result has json error at line %d: %s\n",
+				parsing_error.line, parsing_error.text);
+		goto fail;
+	}
+
+	if(json_path_set(result_json, path, value, append)<0) {
+		goto fail;
+	}
+
+	if(jansson_to_val(&result_val, &freeme, result_json)<0) goto fail;
+
+	result_pv->setf(msg, &result_pv->pvp, (int)EQ_T, &result_val);
+
+	if(freeme) free(freeme);
+	json_decref(result_json);
+	return 1;
+
+fail:
+	if(freeme) free(freeme);
+	json_decref(result_json);
+	return -1;
+}
+
+int janssonmod_array_size(struct sip_msg* msg, char* path_in, char* src_in, char* dst)
+{
+	str src_s;
+	str path_s;
+	pv_spec_t *dst_pv;
+	pv_value_t dst_val;
+
+	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)path_in, &path_s) != 0) {
+		ERR("cannot get path string value\n");
+		return -1;
+	}
+
+	dst_pv = (pv_spec_t *)dst;
+
+	json_t* json = NULL;
+	json_error_t parsing_error;
+
+	json = json_loads(src_s.s, JSON_REJECT_DUPLICATES, &parsing_error);
+
+	if(!json) {
+		ERR("json error at line %d: %s\n",
+				parsing_error.line, parsing_error.text);
+		goto fail;
+	}
+
+	char* path = path_s.s;
+
+	json_t* v = json_path_get(json, path);
+	if(!v) {
+		ERR("failed to find %s in json\n", path);
+		goto fail;
+	}
+
+	if(!json_is_array(v)) {
+		ERR("value at %s is not an array\n", path);
+		goto fail;
+	}
+
+	int size = json_array_size(v);
+	dst_val.ri = size;
+	dst_val.flags = PV_TYPE_INT|PV_VAL_INT;
+
+	dst_pv->setf(msg, &dst_pv->pvp, (int)EQ_T, &dst_val);
+
+	json_decref(json);
+	return 1;
+
+fail:
+	json_decref(json);
+	return -1;
+}

+ 35 - 0
modules/jansson/jansson_funcs.h

@@ -0,0 +1,35 @@
+/**
+ * Copyright (C) 2011 Flowroute LLC (flowroute.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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
+ *
+ *
+ * This file 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
+ *
+ */
+
+#ifndef _JANSSON_FUNCS_H_
+#define _JANSSON_FUNCS_H_
+
+#include "../../parser/msg_parser.h"
+
+int janssonmod_get(struct sip_msg* msg, char* path_in, char* json_in,
+		char* result);
+int janssonmod_set(unsigned int append, struct sip_msg* msg, char* type_in,
+		char* path_in, char* value_in, char* result);
+int janssonmod_array_size(struct sip_msg* msg, char* json_in,
+		char* path_in, char* dst);
+
+#endif

+ 149 - 0
modules/jansson/jansson_mod.c

@@ -0,0 +1,149 @@
+/**
+ * Copyright (C) 2011 Flowroute LLC (flowroute.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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
+ *
+ *
+ * This file 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
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "../../mod_fix.h"
+#include "../../sr_module.h"
+
+#include "jansson_funcs.h"
+#include "jansson_utils.h"
+
+MODULE_VERSION
+
+/* module functions */
+static int mod_init(void);
+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);
+
+
+int janssonmod_set_replace(struct sip_msg* msg, char* type_in, char* path_in,
+		char* value_in, char* result){
+	return janssonmod_set(0, msg, type_in, path_in, value_in, result);
+}
+
+int janssonmod_set_append(struct sip_msg* msg, char* type_in, char* path_in,
+		char* value_in, char* result) {
+	return janssonmod_set(1, msg, type_in, path_in, value_in, result);
+}
+int janssonmod_get_field(struct sip_msg* msg, char* jansson_in, char* path_in,
+		char* result) {
+	return janssonmod_get(msg, path_in, jansson_in, result);
+}
+
+/* Exported functions */
+static cmd_export_t cmds[]={
+	{"jansson_get", (cmd_function)janssonmod_get, 3,
+		fixup_get_params, fixup_get_params_free, ANY_ROUTE},
+	{"jansson_array_size", (cmd_function)janssonmod_array_size, 3,
+		fixup_get_params, fixup_get_params_free, ANY_ROUTE},
+	{"jansson_set", (cmd_function)janssonmod_set_replace, 4,
+		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},
+	/* 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}
+};
+
+struct module_exports exports = {
+		"jansson",
+		DEFAULT_DLFLAGS,	/* dlopen flags */
+		cmds,				/* Exported functions */
+		0,					/* Exported parameters */
+		0,					/* exported statistics */
+		0,					/* exported MI functions */
+		0,					/* exported pseudo-variables */
+		0,					/* extra processes */
+		mod_init,			/* module initialization function */
+		0,					/* response function*/
+		0,					/* destroy function */
+		0					/* per-child init function */
+};
+
+
+static int fixup_get_params(void** param, int param_no)
+{
+	if (param_no <= 2) {
+		return fixup_spve_null(param, 1);
+	}
+
+	if (param_no == 3) {
+		return fixup_pvar_null(param, 1);
+	}
+
+	ERR("invalid parameter number <%d>\n", param_no);
+	return -1;
+}
+
+static int fixup_get_params_free(void** param, int param_no)
+{
+	if (param_no <= 2) {
+		return fixup_free_spve_null(param, 1);
+	}
+
+	if (param_no == 3) {
+		return fixup_free_pvar_null(param, 1);
+	}
+
+	ERR("invalid parameter number <%d>\n", param_no);
+	return -1;
+}
+
+static int fixup_set_params(void** param, int param_no)
+{
+	if(param_no <= 3) {
+		return fixup_spve_null(param, 1);
+	}
+
+	if (param_no == 4) {
+		return fixup_pvar_null(param, 1);
+	}
+
+	ERR("invalid parameter number <%d>\n", param_no);
+	return -1;
+}
+
+static int fixup_set_params_free(void** param, int param_no)
+{
+	if (param_no <= 3) {
+		return fixup_free_spve_null(param, 1);
+	}
+
+	if (param_no == 4) {
+		return fixup_free_pvar_null(param, 1);
+	}
+
+	ERR("invalid parameter number <%d>\n", param_no);
+	return -1;
+}
+
+/* just used for unit testing */
+static int mod_init(void) {
+	return 0;
+}

+ 279 - 0
modules/jansson/jansson_path.c

@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2009-2012 Petri Lehtinen <[email protected]>
+ * Copyright (c) 2011-2012 Basile Starynkevitch <[email protected]>
+ * Copyright (c) 2012 Rogerz Zhang <[email protected]>
+ * Copyright (c) 2013 Flowroute LLC (flowroute.com)
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license.
+ *
+ * Pulled from https://github.com/rogerz/jansson/blob/json_path/src/path.c
+ */
+
+#include <string.h>
+#include <assert.h>
+
+#include <jansson.h>
+
+#include "../../mod_fix.h"
+
+/* jansson private helper functions */
+void *jsonp_malloc(size_t size);
+void jsonp_free(void *ptr);
+char *jsonp_strdup(const char *str);
+
+static json_malloc_t do_malloc = malloc;
+static json_free_t do_free = free;
+
+json_t *json_path_get(const json_t *json, const char *path)
+{
+	static const char array_open = '[';
+	static const char *path_delims = ".[", *array_close = "]";
+	const json_t *cursor;
+	char *token, *buf, *peek, *endptr, delim = '\0';
+	const char *expect;
+
+	if (!json || !path)
+		return NULL;
+	else
+		buf = jsonp_strdup(path);
+
+	peek = buf;
+	token = buf;
+	cursor = json;
+	expect = path_delims;
+
+	if (*token == array_open) {
+		expect = array_close;
+		token++;
+	}
+
+	while (peek && *peek && cursor)
+	{
+		char *last_peek = peek;
+		peek = strpbrk(peek, expect);
+		if (peek) {
+			if (!token && peek != last_peek)
+				goto fail;
+			delim = *peek;
+			*peek++ = '\0';
+		} else if (expect != path_delims || !token) {
+			goto fail;
+		}
+
+		if (expect == path_delims) {
+			if (token) {
+				cursor = json_object_get(cursor, token);
+			}
+			expect = (delim == array_open ? array_close : path_delims);
+			token = peek;
+		} else if (expect == array_close) {
+			size_t index = strtol(token, &endptr, 0);
+			if (*endptr)
+				goto fail;
+			cursor = json_array_get(cursor, index);
+			token = NULL;
+			expect = path_delims;
+		} else {
+			goto fail;
+		}
+	}
+
+	jsonp_free(buf);
+	return (json_t *)cursor;
+fail:
+	jsonp_free(buf);
+	return NULL;
+}
+
+int json_path_set(json_t *json, const char *path, json_t *value,
+		unsigned int append)
+{
+	static const char array_open = '[';
+	static const char object_delim = '.';
+	static const char *path_delims = ".[";
+	static const char *array_close = "]";
+
+	json_t *cursor, *parent = NULL;
+	char *token, *buf = NULL, *peek, delim = '\0';
+	const char *expect;
+	int index_saved = -1;
+
+	if (!json || !path || !value) {
+		ERR("invalid arguments\n");
+		goto fail;
+	} else {
+		buf = jsonp_strdup(path);
+	}
+
+	peek = buf;
+	token = buf;
+	cursor = json;
+	expect = path_delims;
+
+	if (*token == array_open) {
+		expect = array_close;
+		token++;
+	}
+
+	while (peek && *peek && cursor)
+	{
+		char *last_peek = peek;
+		peek = strpbrk(last_peek, expect);
+
+		if (peek) {
+			if (!token && peek != last_peek) {
+				ERR("unexpected trailing chars in JSON path at pos %zu\n",
+						last_peek - buf);
+				goto fail;
+			}
+			delim = *peek;
+			*peek++ = '\0';
+		} else { // end of path
+			if (expect == path_delims) {
+				break;
+			} else {
+				ERR("missing ']' at pos %zu\n", peek - buf);
+				goto fail;
+			}
+		}
+
+		if (expect == path_delims) {
+			if (token) {
+				if (token[0] == '\0') {
+					ERR("empty token at pos %zu\n", peek - buf);
+					goto fail;
+				}
+
+				parent = cursor;
+				cursor = json_object_get(parent, token);
+
+				if (!cursor) {
+					if (!json_is_object(parent)) {
+						ERR("object expected at pos %zu\n", peek - buf);
+						goto fail;
+					}
+					if (delim == object_delim) {
+						cursor = json_object();
+						json_object_set_new(parent, token, cursor);
+					} else {
+						ERR("new array is not allowed at pos %zu\n", peek - buf);
+						goto fail;
+					}
+				}
+			}
+			expect = (delim == array_open ? array_close : path_delims);
+			token = peek;
+		} else if (expect == array_close) {
+			char *endptr;
+			size_t index;
+
+			parent = cursor;
+			if (!json_is_array(parent)) {
+				ERR("array expected at pos %zu\n", peek - buf);
+				goto fail;
+			}
+
+			index = strtol(token, &endptr, 0);
+			if (*endptr) {
+				ERR("invalid array index at pos %zu\n", peek - buf);
+				goto fail;
+			}
+
+			cursor = json_array_get(parent, index);
+			if (!cursor) {
+				ERR("array index out of bound at pos %zu\n", peek - buf);
+				goto fail;
+			}
+
+			index_saved = index;
+			token = NULL;
+			expect = path_delims;
+
+		} else {
+			ERR("fatal JSON error at pos %zu\n", peek - buf);
+			goto fail;
+		}
+	}
+
+	if (token && append) {
+
+		if(strlen(token) > 0) {
+			json_t* tmp  = json_object_get(cursor, token);
+			if(json_is_array(tmp)) {
+				json_array_append(tmp, value);
+				json_object_set(cursor, token, tmp);
+			} else if(json_is_object(tmp) && json_is_object(value) ) {
+				json_object_update(tmp, value);
+				json_object_set(cursor, token, tmp);
+			} else {
+				ERR("JSON array or object expected at pos %zu\n", peek - buf);
+				goto fail;
+			}
+		} else if(json_is_array(cursor)) {
+			json_array_append(cursor, value);
+
+		} else if(json_is_object(cursor) && json_is_object(value)) {
+			json_object_update(cursor, value);
+
+		} else {
+			ERR("JSON array or object expected at pos %zu\n", peek - buf);
+			goto fail;
+		}
+
+	} else if (token && strlen(token) != 0 ) {
+
+		if (json_is_object(cursor)) {
+			json_object_set(cursor, token, value);
+
+		} else {
+			ERR("JSON object expected at pos %zu\n", peek - buf);
+			goto fail;
+		}
+
+		cursor = json_object_get(cursor, token);
+	} else if (index_saved != -1 && json_is_array(parent)) {
+		json_array_set(parent, index_saved, value);
+		cursor = json_array_get(parent, index_saved);
+
+	} else {
+		ERR("invalid JSON path at pos %zu\n", peek - buf);
+		goto fail;
+	}
+
+	json_decref(value);
+	jsonp_free(buf);
+	return 0;
+
+fail:
+	json_decref(value);
+	jsonp_free(buf);
+	return -1;
+}
+
+/* jansson private helper functions */
+void *jsonp_malloc(size_t size) {
+	if(!size)
+		return NULL;
+
+	return (*do_malloc)(size);
+}
+
+void jsonp_free(void *ptr) {
+	if(!ptr)
+		return;
+
+	(*do_free)(ptr);
+}
+
+char *jsonp_strdup(const char *str) {
+	char *new_str;
+
+	new_str = jsonp_malloc(strlen(str) + 1); 
+	if(!new_str)
+		return NULL;
+
+	strcpy(new_str, str);
+	return new_str;
+}
+/* end jansson private helpers */

+ 17 - 0
modules/jansson/jansson_path.h

@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2012 Rogerz Zhang <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. 
+ */
+
+
+#ifndef _JANSSON_FUNCS_H_
+#define _JANSSON_FUNCS_H_
+#include <jansson.h>
+
+json_t *json_path_get(const json_t *json, const char *path);
+int json_path_set(json_t *json, const char *path, json_t *value, unsigned int append);
+
+#endif
+

+ 70 - 0
modules/jansson/jansson_utils.c

@@ -0,0 +1,70 @@
+/**
+ * Copyright (C) 2013 Flowroute LLC (flowroute.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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
+ *
+ *
+ * This file 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
+ *
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <jansson.h>
+
+#include "../../lvalue.h"
+
+#include "jansson_utils.h"
+
+int jansson_to_val(pv_value_t* val, char** freeme, json_t* v) {
+
+	val->flags = 0;
+
+	if(json_is_object(v) || json_is_array(v)) {
+		const char* value = json_dumps(v, JSON_COMPACT);
+		*freeme = (char*)value;
+		val->rs.s = (char*)value;
+		val->rs.len = strlen(value);
+		val->flags = PV_VAL_STR;
+	}else if(json_is_string(v)) {
+		const char* value = json_string_value(v);
+		val->rs.s = (char*)value;
+		val->rs.len = strlen(value);
+		val->flags = PV_VAL_STR;
+	}else if(json_is_boolean(v)) {
+		val->ri = json_is_true(v) ? 0 : 1;
+		val->flags = PV_TYPE_INT|PV_VAL_INT;
+	}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->rs.s = value;
+		val->rs.len = strlen(value);
+		val->flags = PV_VAL_STR;
+	}else if(json_is_integer(v)) {
+		int value = json_integer_value(v);
+		val->ri = value;
+		val->flags = PV_TYPE_INT|PV_VAL_INT;
+	}else if(json_is_null(v)) {
+		val->flags = PV_VAL_NULL;
+	}else {
+		ERR("unrecognized json type: %d\n", json_typeof(v));
+		return -1;
+	}
+	return 0;
+}

+ 34 - 0
modules/jansson/jansson_utils.h

@@ -0,0 +1,34 @@
+/**
+ * Copyright (C) 2013 Flowroute LLC (flowroute.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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
+ *
+ *
+ * This file 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
+ *
+ */
+
+#ifndef _JANSSON_UTILS_H_
+#define _JANSSON_UTILS_H_
+
+#include <jansson.h>
+
+#include "../../sr_module.h"
+#include "../../lvalue.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);
+
+#endif