Added POST, Plugin API signal protection, refactor HTML5 rewrite
authorFulup Ar Foll <fulup@iot.bzh>
Wed, 9 Dec 2015 00:27:23 +0000 (01:27 +0100)
committerFulup Ar Foll <fulup@iot.bzh>
Wed, 9 Dec 2015 00:27:23 +0000 (01:27 +0100)
18 files changed:
.gitignore [new file with mode: 0644]
include/local-def.h
include/proto-def.h
nbproject/Makefile-Debug.mk
nbproject/Makefile-Release.mk
nbproject/Makefile-impl.mk
nbproject/Makefile-variables.mk
nbproject/Package-Debug.bash
nbproject/Package-Release.bash
nbproject/configurations.xml
nbproject/project.xml
src/afbs-api.c
src/alsa-api.c
src/config.c
src/dbus-api.c
src/http-svc.c
src/main.c
src/rest-api.c

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..6e3b026
--- /dev/null
@@ -0,0 +1,8 @@
+/nbproject/private/
+amixer
+autom4te.cache
+config.log 
+build/**
+dist/**
+!.gitignore
+.dep.inc
\ No newline at end of file
index 3f0a26a..72c51de 100644 (file)
 
 /* other definitions --------------------------------------------------- */
 
+// Note: because of a bug in libmagic MAGIC_DB NULL should not be used for default
+#define MAGIC_DB "/usr/share/misc/magic.mgc"
+#define OPA_INDEX "index.html"
+
 typedef int BOOL;
 #ifndef FALSE
   #define FALSE 0
@@ -97,8 +101,8 @@ typedef struct {
 } AFB_request;
 
 typedef struct {
-     char *msg;
-     int  len;
+     char    *msg;
+     size_t  len;
 } AFB_redirect_msg;
 
 // main config structure
@@ -117,6 +121,7 @@ typedef struct {
   char *configfile;        // where to store configuration on gateway exit
   uid_t setuid;
   int  cacheTimeout;
+  int  apiTimeout;
 } AFB_config;
 
 // Command line structure hold cli --command + help text
@@ -134,6 +139,7 @@ typedef struct {
   char *name;
   AFB_apiCB callback;
   char *info;
+  void * handle;
 } AFB_restapi;
 
 // Plugin definition
index d1b0c3f..3e1d1c3 100644 (file)
 */
 
 // Rest-api
-PUBLIC json_object* pingSample (AFB_plugin *plugin, AFB_session *session, AFB_request *post);
+
+PUBLIC json_object* apiPingTest(AFB_session *session, AFB_request *request, void* handle);
 PUBLIC const char* getQueryValue (AFB_request * request, char *name);
-PUBLIC int doRestApi(struct MHD_Connection *connection, AFB_session *session, const char *method, const char* url);
+PUBLIC const char* getQueryAll(AFB_request * request, char *query, size_t len);
+
+    
+PUBLIC int doRestApi(struct MHD_Connection *connection, AFB_session *session, const char* url, const char *method
+    , const char *upload_data, size_t *upload_data_size, void **con_cls);
+
 void initPlugins (AFB_session *session);
 
 typedef AFB_plugin* (*AFB_pluginCB)(AFB_session *session);
index 1866ff1..39692f3 100644 (file)
@@ -59,55 +59,55 @@ FFLAGS=
 ASFLAGS=
 
 # Link Libraries and Options
-LDLIBSOPTIONS=`pkg-config --libs libmicrohttpd` `pkg-config --libs json-c` -lmagic  
+LDLIBSOPTIONS=`pkg-config --libs libmicrohttpd` `pkg-config --libs json-c` -lefence -lmagic  
 
 # Build Targets
 .build-conf: ${BUILD_SUBPROJECTS}
-       "${MAKE}"  -f nbproject/Makefile-${CND_CONF}.mk ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/appframeworkbinder
+       "${MAKE}"  -f nbproject/Makefile-${CND_CONF}.mk ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/afb-daemon
 
-${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/appframeworkbinder: ${OBJECTFILES}
+${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/afb-daemon: ${OBJECTFILES}
        ${MKDIR} -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}
-       ${LINK.c} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/appframeworkbinder ${OBJECTFILES} ${LDLIBSOPTIONS}
+       ${LINK.c} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/afb-daemon ${OBJECTFILES} ${LDLIBSOPTIONS}
 
 ${OBJECTDIR}/src/afbs-api.o: src/afbs-api.c 
        ${MKDIR} -p ${OBJECTDIR}/src
        ${RM} "$@.d"
-       $(COMPILE.c) -g -I/usr/include/json-c -Iinclude `pkg-config --cflags libmicrohttpd` `pkg-config --cflags json-c`   -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/afbs-api.o src/afbs-api.c
+       $(COMPILE.c) -g -I/usr/include/json-c -Iinclude -I/opt/libmagic/include `pkg-config --cflags libmicrohttpd` `pkg-config --cflags json-c`   -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/afbs-api.o src/afbs-api.c
 
 ${OBJECTDIR}/src/alsa-api.o: src/alsa-api.c 
        ${MKDIR} -p ${OBJECTDIR}/src
        ${RM} "$@.d"
-       $(COMPILE.c) -g -I/usr/include/json-c -Iinclude `pkg-config --cflags libmicrohttpd` `pkg-config --cflags json-c`   -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/alsa-api.o src/alsa-api.c
+       $(COMPILE.c) -g -I/usr/include/json-c -Iinclude -I/opt/libmagic/include `pkg-config --cflags libmicrohttpd` `pkg-config --cflags json-c`   -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/alsa-api.o src/alsa-api.c
 
 ${OBJECTDIR}/src/config.o: src/config.c 
        ${MKDIR} -p ${OBJECTDIR}/src
        ${RM} "$@.d"
-       $(COMPILE.c) -g -I/usr/include/json-c -Iinclude `pkg-config --cflags libmicrohttpd` `pkg-config --cflags json-c`   -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/config.o src/config.c
+       $(COMPILE.c) -g -I/usr/include/json-c -Iinclude -I/opt/libmagic/include `pkg-config --cflags libmicrohttpd` `pkg-config --cflags json-c`   -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/config.o src/config.c
 
 ${OBJECTDIR}/src/dbus-api.o: src/dbus-api.c 
        ${MKDIR} -p ${OBJECTDIR}/src
        ${RM} "$@.d"
-       $(COMPILE.c) -g -I/usr/include/json-c -Iinclude `pkg-config --cflags libmicrohttpd` `pkg-config --cflags json-c`   -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/dbus-api.o src/dbus-api.c
+       $(COMPILE.c) -g -I/usr/include/json-c -Iinclude -I/opt/libmagic/include `pkg-config --cflags libmicrohttpd` `pkg-config --cflags json-c`   -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/dbus-api.o src/dbus-api.c
 
 ${OBJECTDIR}/src/http-svc.o: src/http-svc.c 
        ${MKDIR} -p ${OBJECTDIR}/src
        ${RM} "$@.d"
-       $(COMPILE.c) -g -I/usr/include/json-c -Iinclude `pkg-config --cflags libmicrohttpd` `pkg-config --cflags json-c`   -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/http-svc.o src/http-svc.c
+       $(COMPILE.c) -g -I/usr/include/json-c -Iinclude -I/opt/libmagic/include `pkg-config --cflags libmicrohttpd` `pkg-config --cflags json-c`   -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/http-svc.o src/http-svc.c
 
 ${OBJECTDIR}/src/main.o: src/main.c 
        ${MKDIR} -p ${OBJECTDIR}/src
        ${RM} "$@.d"
-       $(COMPILE.c) -g -I/usr/include/json-c -Iinclude `pkg-config --cflags libmicrohttpd` `pkg-config --cflags json-c`   -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/main.o src/main.c
+       $(COMPILE.c) -g -I/usr/include/json-c -Iinclude -I/opt/libmagic/include `pkg-config --cflags libmicrohttpd` `pkg-config --cflags json-c`   -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/main.o src/main.c
 
 ${OBJECTDIR}/src/rest-api.o: src/rest-api.c 
        ${MKDIR} -p ${OBJECTDIR}/src
        ${RM} "$@.d"
-       $(COMPILE.c) -g -I/usr/include/json-c -Iinclude `pkg-config --cflags libmicrohttpd` `pkg-config --cflags json-c`   -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/rest-api.o src/rest-api.c
+       $(COMPILE.c) -g -I/usr/include/json-c -Iinclude -I/opt/libmagic/include `pkg-config --cflags libmicrohttpd` `pkg-config --cflags json-c`   -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/rest-api.o src/rest-api.c
 
 ${OBJECTDIR}/src/session.o: src/session.c 
        ${MKDIR} -p ${OBJECTDIR}/src
        ${RM} "$@.d"
-       $(COMPILE.c) -g -I/usr/include/json-c -Iinclude `pkg-config --cflags libmicrohttpd` `pkg-config --cflags json-c`   -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/session.o src/session.c
+       $(COMPILE.c) -g -I/usr/include/json-c -Iinclude -I/opt/libmagic/include `pkg-config --cflags libmicrohttpd` `pkg-config --cflags json-c`   -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/session.o src/session.c
 
 # Subprojects
 .build-subprojects:
@@ -115,7 +115,7 @@ ${OBJECTDIR}/src/session.o: src/session.c
 # Clean Targets
 .clean-conf: ${CLEAN_SUBPROJECTS}
        ${RM} -r ${CND_BUILDDIR}/${CND_CONF}
-       ${RM} ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/appframeworkbinder
+       ${RM} ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/afb-daemon
 
 # Subprojects
 .clean-subprojects:
index 6df0bda..7cbdfe8 100644 (file)
@@ -63,11 +63,11 @@ LDLIBSOPTIONS=
 
 # Build Targets
 .build-conf: ${BUILD_SUBPROJECTS}
-       "${MAKE}"  -f nbproject/Makefile-${CND_CONF}.mk ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/appframeworkbinder
+       "${MAKE}"  -f nbproject/Makefile-${CND_CONF}.mk ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/afb-daemon
 
-${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/appframeworkbinder: ${OBJECTFILES}
+${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/afb-daemon: ${OBJECTFILES}
        ${MKDIR} -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}
-       ${LINK.c} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/appframeworkbinder ${OBJECTFILES} ${LDLIBSOPTIONS}
+       ${LINK.c} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/afb-daemon ${OBJECTFILES} ${LDLIBSOPTIONS}
 
 ${OBJECTDIR}/src/afbs-api.o: src/afbs-api.c 
        ${MKDIR} -p ${OBJECTDIR}/src
@@ -115,7 +115,7 @@ ${OBJECTDIR}/src/session.o: src/session.c
 # Clean Targets
 .clean-conf: ${CLEAN_SUBPROJECTS}
        ${RM} -r ${CND_BUILDDIR}/${CND_CONF}
-       ${RM} ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/appframeworkbinder
+       ${RM} ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/afb-daemon
 
 # Subprojects
 .clean-subprojects:
index 185e4af..a2d5e84 100644 (file)
@@ -24,7 +24,7 @@ CLEAN_SUBPROJECTS=${CLEAN_SUBPROJECTS_${SUBPROJECTS}}
 
 
 # Project Name
-PROJECTNAME=AppFrameworkBinder
+PROJECTNAME=afb-daemon
 
 # Active Configuration
 DEFAULTCONF=Debug
index 4e44a21..6051467 100644 (file)
@@ -9,19 +9,19 @@ CND_DISTDIR=dist
 # Debug configuration
 CND_PLATFORM_Debug=GNU-Linux
 CND_ARTIFACT_DIR_Debug=dist/Debug/GNU-Linux
-CND_ARTIFACT_NAME_Debug=appframeworkbinder
-CND_ARTIFACT_PATH_Debug=dist/Debug/GNU-Linux/appframeworkbinder
+CND_ARTIFACT_NAME_Debug=afb-daemon
+CND_ARTIFACT_PATH_Debug=dist/Debug/GNU-Linux/afb-daemon
 CND_PACKAGE_DIR_Debug=dist/Debug/GNU-Linux/package
-CND_PACKAGE_NAME_Debug=appframeworkbinder.tar
-CND_PACKAGE_PATH_Debug=dist/Debug/GNU-Linux/package/appframeworkbinder.tar
+CND_PACKAGE_NAME_Debug=afb-daemon.tar
+CND_PACKAGE_PATH_Debug=dist/Debug/GNU-Linux/package/afb-daemon.tar
 # Release configuration
 CND_PLATFORM_Release=GNU-Linux
 CND_ARTIFACT_DIR_Release=dist/Release/GNU-Linux
-CND_ARTIFACT_NAME_Release=appframeworkbinder
-CND_ARTIFACT_PATH_Release=dist/Release/GNU-Linux/appframeworkbinder
+CND_ARTIFACT_NAME_Release=afb-daemon
+CND_ARTIFACT_PATH_Release=dist/Release/GNU-Linux/afb-daemon
 CND_PACKAGE_DIR_Release=dist/Release/GNU-Linux/package
-CND_PACKAGE_NAME_Release=appframeworkbinder.tar
-CND_PACKAGE_PATH_Release=dist/Release/GNU-Linux/package/appframeworkbinder.tar
+CND_PACKAGE_NAME_Release=afb-daemon.tar
+CND_PACKAGE_PATH_Release=dist/Release/GNU-Linux/package/afb-daemon.tar
 #
 # include compiler specific variables
 #
index 2635983..b7d2554 100644 (file)
@@ -13,9 +13,9 @@ CND_BUILDDIR=build
 CND_DLIB_EXT=so
 NBTMPDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM}/tmp-packaging
 TMPDIRNAME=tmp-packaging
-OUTPUT_PATH=${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/appframeworkbinder
-OUTPUT_BASENAME=appframeworkbinder
-PACKAGE_TOP_DIR=appframeworkbinder/
+OUTPUT_PATH=${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/afb-daemon
+OUTPUT_BASENAME=afb-daemon
+PACKAGE_TOP_DIR=afb-daemon/
 
 # Functions
 function checkReturnCode
@@ -60,15 +60,15 @@ mkdir -p ${NBTMPDIR}
 
 # Copy files and create directories and links
 cd "${TOP}"
-makeDirectory "${NBTMPDIR}/appframeworkbinder/bin"
+makeDirectory "${NBTMPDIR}/afb-daemon/bin"
 copyFileToTmpDir "${OUTPUT_PATH}" "${NBTMPDIR}/${PACKAGE_TOP_DIR}bin/${OUTPUT_BASENAME}" 0755
 
 
 # Generate tar file
 cd "${TOP}"
-rm -f ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/appframeworkbinder.tar
+rm -f ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/afb-daemon.tar
 cd ${NBTMPDIR}
-tar -vcf ../../../../${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/appframeworkbinder.tar *
+tar -vcf ../../../../${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/afb-daemon.tar *
 checkReturnCode
 
 # Cleanup
index 4ef9af3..627cc4c 100644 (file)
@@ -13,9 +13,9 @@ CND_BUILDDIR=build
 CND_DLIB_EXT=so
 NBTMPDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM}/tmp-packaging
 TMPDIRNAME=tmp-packaging
-OUTPUT_PATH=${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/appframeworkbinder
-OUTPUT_BASENAME=appframeworkbinder
-PACKAGE_TOP_DIR=appframeworkbinder/
+OUTPUT_PATH=${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/afb-daemon
+OUTPUT_BASENAME=afb-daemon
+PACKAGE_TOP_DIR=afb-daemon/
 
 # Functions
 function checkReturnCode
@@ -60,15 +60,15 @@ mkdir -p ${NBTMPDIR}
 
 # Copy files and create directories and links
 cd "${TOP}"
-makeDirectory "${NBTMPDIR}/appframeworkbinder/bin"
+makeDirectory "${NBTMPDIR}/afb-daemon/bin"
 copyFileToTmpDir "${OUTPUT_PATH}" "${NBTMPDIR}/${PACKAGE_TOP_DIR}bin/${OUTPUT_BASENAME}" 0755
 
 
 # Generate tar file
 cd "${TOP}"
-rm -f ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/appframeworkbinder.tar
+rm -f ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/afb-daemon.tar
 cd ${NBTMPDIR}
-tar -vcf ../../../../${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/appframeworkbinder.tar *
+tar -vcf ../../../../${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/afb-daemon.tar *
 checkReturnCode
 
 # Cleanup
index c079370..ce722f7 100644 (file)
           <incDir>
             <pElem>/usr/include/json-c</pElem>
             <pElem>include</pElem>
+            <pElem>/opt/libmagic/include</pElem>
           </incDir>
         </cTool>
         <linkerTool>
           <linkerLibItems>
             <linkerOptionItem>`pkg-config --libs libmicrohttpd`</linkerOptionItem>
             <linkerOptionItem>`pkg-config --libs json-c`</linkerOptionItem>
+            <linkerLibLibItem>efence</linkerLibLibItem>
             <linkerLibLibItem>magic</linkerLibLibItem>
           </linkerLibItems>
         </linkerTool>
index 394601f..9192033 100644 (file)
@@ -3,7 +3,7 @@
     <type>org.netbeans.modules.cnd.makeproject</type>
     <configuration>
         <data xmlns="http://www.netbeans.org/ns/make-project/1">
-            <name>AppFrameworkBinder</name>
+            <name>afb-daemon</name>
             <c-extensions>c</c-extensions>
             <cpp-extensions/>
             <header-extensions/>
index 40e89d0..b55ebf6 100644 (file)
 
 #include "local-def.h"
 
-STATIC json_object* pingAfbs (AFB_session *session, AFB_request *request) {
-    static pingcount=0;
+
+STATIC json_object* pingSample (AFB_session *session, AFB_request *request, void* handle) {
+    static pingcount = 0;
     json_object *response;
-    const char * argval;
+    char query [512];
+
+    // request all query key/value
+    getQueryAll (request, query, sizeof(query)); 
     
-    argval=getQueryValue (request, "arg");
-    if (argval == NULL) {
-        argval="No present in query";
-    };
+    // check if we have some post data
+    if (request->post == NULL)  request->post="NoData";  
+        
+    // return response to caller
+    response = jsonNewMessage(AFB_SUCCESS, "Ping Binder Daemon %d query={%s} PostData: \'%s\' ", pingcount++, query, request->post);
     
-    response = jsonNewMessage(AFB_SUCCESS, "Ping Application Framework %d [arg=%s]", pingcount++, argval);
     if (verbose) fprintf(stderr, "%d: \n", pingcount);
     return (response);
-};
+}
 
 
 STATIC  AFB_restapi pluginApis[]= {
-  {"ping"     , (AFB_apiCB)pingSample ,"Ping Service"},
-  {"get-all"  , (AFB_apiCB)pingAfbs ,"Ping Application Framework"},
-  {"get-one"  , (AFB_apiCB)pingSample ,"Verbose Mode"},
-  {"start-one", (AFB_apiCB)pingSample ,"Verbose Mode"},
-  {"stop-one" , (AFB_apiCB)pingSample ,"Verbose Mode"},
-  {"probe-one", (AFB_apiCB)pingSample ,"Verbose Mode"},
-  {"ctx-store", (AFB_apiCB)pingSample ,"Verbose Mode"},
-  {"ctx-load" , (AFB_apiCB)pingSample ,"Verbose Mode"},
+  {"ping"     , (AFB_apiCB)pingSample ,"Ping Service", NULL},
+  {"get-all"  , (AFB_apiCB)pingSample ,"Ping Application Framework", NULL},
+  {"get-one"  , (AFB_apiCB)pingSample ,"Verbose Mode", NULL},
+  {"start-one", (AFB_apiCB)pingSample ,"Verbose Mode", NULL},
+  {"stop-one" , (AFB_apiCB)pingSample ,"Verbose Mode", NULL},
+  {"probe-one", (AFB_apiCB)pingSample ,"Verbose Mode", NULL},
+  {"ctx-store", (AFB_apiCB)pingSample ,"Verbose Mode", NULL},
+  {"ctx-load" , (AFB_apiCB)pingSample ,"Verbose Mode", NULL},
   {0,0,0}
 };
 
index ab7dced..01341ce 100644 (file)
 
 #include "local-def.h"
 
-STATIC json_object* pingAfbs (AFB_plugin *plugin, AFB_session *session, struct MHD_Connection *connection, AFB_request *request) {
-    static pingcount=0;
+STATIC json_object* wrongApi (AFB_session *session, AFB_request *request, void* handle) {
+    int zero=0;
+    int bug=1234;
+    int impossible;
+    
+    impossible=bug/zero;
+}
+
+STATIC json_object* pingSample (AFB_session *session, AFB_request *request, void* handle) {
+    static pingcount = 0;
     json_object *response;
-    response = jsonNewMessage(AFB_SUCCESS, "Ping Application Framework %d", pingcount++);
+    char query [512];
+
+    // request all query key/value
+    getQueryAll (request, query, sizeof(query)); 
+    
+    // check if we have some post data
+    if (request->post == NULL)  request->post="NoData";  
+        
+    // return response to caller
+    response = jsonNewMessage(AFB_SUCCESS, "Ping Binder Daemon %d query={%s} PostData: \'%s\' ", pingcount++, query, request->post);
+    
     if (verbose) fprintf(stderr, "%d: \n", pingcount);
     return (response);
-};
+}
+
+
+STATIC struct {
+    void * somedata;
+} handle;
 
 
 STATIC  AFB_restapi pluginApis[]= {
-  {"ping"     , (AFB_apiCB)pingSample ,"Ping Service"},
-  {"get-all"  , (AFB_apiCB)pingAfbs ,"Ping Application Framework"},
-  {"get-one"  , (AFB_apiCB)pingSample ,"Verbose Mode"},
-  {"start-one", (AFB_apiCB)pingSample ,"Verbose Mode"},
-  {"stop-one" , (AFB_apiCB)pingSample ,"Verbose Mode"},
-  {"probe-one", (AFB_apiCB)pingSample ,"Verbose Mode"},
-  {"ctx-store", (AFB_apiCB)pingSample ,"Verbose Mode"},
-  {"ctx-load" , (AFB_apiCB)pingSample ,"Verbose Mode"},
+  {"ping"     , (AFB_apiCB)pingSample , "Ping Application Framework", NULL},
+  {"error"    , (AFB_apiCB)wrongApi   , "Ping Application Framework", NULL},
+  {"ctx-store", (AFB_apiCB)pingSample , "Verbose Mode", NULL},
+  {"ctx-load" , (AFB_apiCB)pingSample , "Verbose Mode", NULL},
   {0,0,0}
 };
 
index 6691ca0..ae1830d 100644 (file)
@@ -64,6 +64,10 @@ PUBLIC AFB_error configLoadFile (AFB_session * session, AFB_config *cliconfig) {
    // default HTTP port
    if (cliconfig->httpdPort == 0) session->config->httpdPort=1234;
    else session->config->httpdPort=cliconfig->httpdPort;
+   
+   // default Plugin API timeout
+   if (cliconfig->apiTimeout == 0) session->config->apiTimeout=10;
+   else session->config->apiTimeout=cliconfig->apiTimeout;
 
    // cache timeout default one hour
    if (cliconfig->cacheTimeout == 0) session->config->cacheTimeout=3600;
@@ -206,9 +210,15 @@ PUBLIC AFB_error configLoadFile (AFB_session * session, AFB_config *cliconfig) {
    if (!cliconfig->cacheTimeout && json_object_object_get_ex (AFBConfig, "cachetimeout", &value)) {
       session->config->cacheTimeout = json_object_get_int (value);
    }
-   // cacheTimeout is an interger but HTTPd wants it as a string
+   
+   if (!cliconfig->apiTimeout && json_object_object_get_ex (AFBConfig, "apitimeout", &value)) {
+      session->config->apiTimeout = json_object_get_int (value);
+   }
+   
+   // cacheTimeout is an integer but HTTPd wants it as a string
    snprintf (cacheTimeout, sizeof (cacheTimeout),"%d", session->config->cacheTimeout);
    session->cacheTimeout = cacheTimeout; // httpd uses cacheTimeout string version
+   
    json_object_put   (AFBConfig);    // decrease reference count to free the json object
 
  
@@ -241,6 +251,7 @@ PUBLIC void configStoreFile (AFB_session * session) {
    json_object_object_add (AFBConfig, "setuid"        , json_object_new_int (session->config->setuid));
    json_object_object_add (AFBConfig, "localhostonly" , json_object_new_int (session->config->localhostOnly));
    json_object_object_add (AFBConfig, "cachetimeout"  , json_object_new_int (session->config->cacheTimeout));
+   json_object_object_add (AFBConfig, "apitimeout"    , json_object_new_int (session->config->apiTimeout));
 
    err = json_object_to_file (session->config->configfile, AFBConfig);
    json_object_put   (AFBConfig);    // decrease reference count to free the json object
index 9d34e43..1f81bb2 100644 (file)
 
 #include "local-def.h"
 
-STATIC json_object* pingAfbs (AFB_plugin *plugin, AFB_session *session, AFB_request *request) {
-    static pingcount=0;
+STATIC json_object* pingSample (AFB_session *session, AFB_request *request, void* handle) {
+    static pingcount = 0;
     json_object *response;
-    response = jsonNewMessage(AFB_SUCCESS, "Ping Application Framework %d", pingcount++);
+    char query [512];
+
+    // request all query key/value
+    getQueryAll (request, query, sizeof(query)); 
+    
+    // check if we have some post data
+    if (request->post == NULL)  request->post="NoData";  
+        
+    // return response to caller
+    response = jsonNewMessage(AFB_SUCCESS, "Ping Binder Daemon %d query={%s} PostData: \'%s\' ", pingcount++, query, request->post);
+    
     if (verbose) fprintf(stderr, "%d: \n", pingcount);
     return (response);
-};
+}
+
+
+STATIC struct {
+    void * somedata;
+} handle;
 
 
 STATIC  AFB_restapi pluginApis[]= {
-  {"ping"     , (AFB_apiCB)pingAfbs   ,"Ping Application Framework"},
-  {"ctx-store", (AFB_apiCB)pingSample ,"Verbose Mode"},
-  {"ctx-load" , (AFB_apiCB)pingSample ,"Verbose Mode"},
+  {"ping"     , (AFB_apiCB)pingSample , "Ping Application Framework", NULL},
+  {"ctx-store", (AFB_apiCB)pingSample , "Verbose Mode", NULL},
+  {"ctx-load" , (AFB_apiCB)pingSample , "Verbose Mode", NULL},
   {0,0,0}
 };
 
+
 PUBLIC AFB_plugin *dbusRegister (AFB_session *session) {
     AFB_plugin *plugin = malloc (sizeof (AFB_plugin));
     plugin->type  = AFB_PLUGIN;
index 836915a..cd48896 100644 (file)
@@ -47,25 +47,23 @@ static int postcount = 0;
 
 // try to open libmagic to handle mime types
 static AFB_error initLibMagic (AFB_session *session) {
-  const char *magic_full;
   
     /*MAGIC_MIME tells magic to return a mime of the file, but you can specify different things*/
     if (verbose) printf("Loading mimetype default magic database\n");
   
-    session->magic = magic_open(MAGIC_MIME);
+    session->magic = magic_open(MAGIC_MIME_TYPE);
     if (session->magic == NULL) {
         fprintf(stderr,"ERROR: unable to initialize magic library\n");
         return AFB_FAIL;
     }
-    if (magic_load(session->magic, NULL) != 0) {
+    
+    // Warning: should not use NULL for DB [libmagic bug wont pass efence check]
+    if (magic_load(session->magic, MAGIC_DB) != 0) {
         fprintf(stderr,"cannot load magic database - %s\n", magic_error(session->magic));
         magic_close(session->magic);
         return AFB_FAIL;
     }
-    
-    //usage
-    //magic_full = magic_file(magic_cookie, actual_file);
-    //printf("%s\n", magic_full);  
+
     return AFB_SUCCESS;
 }
 
@@ -98,30 +96,40 @@ STATIC int servFile (struct MHD_Connection *connection, AFB_session *session, co
 
     if (fstat (staticfile->fd, &sbuf) != 0) {
         fprintf(stderr, "Fail to stat file: [%s] error:%s\n", staticfile->path, strerror(errno));
-        return (FAILED);
+        goto abortRequest;
     }
     
-    // if url is a directory let's add index.html and redirect client
-    if (S_ISDIR (sbuf.st_mode)) {
-        if (url [strlen (url) -1] != '/') strncat (staticfile->path, "/", sizeof (staticfile->path));
-        strncat (staticfile->path, "index.html", sizeof (staticfile->path));
-        close (staticfile->fd); // close directory try to open index.html
-        if (-1 == (staticfile->fd = open(staticfile->path, O_RDONLY)) || (fstat (staticfile->fd, &sbuf) != 0)) {
-           fprintf(stderr, "No Index.html in direcory [%s]\n", staticfile->path);
-           return (FAILED);  
-        }
-            
-    } else  if (! S_ISREG (sbuf.st_mode)) { // only standard file any other one including symbolic links are refused.
-
+    if (! S_ISREG (sbuf.st_mode)) { // only standard file any other one including symbolic links are refused.
+        close (staticfile->fd); // nothing useful to do with this file
         fprintf (stderr, "Fail file: [%s] is not a regular file\n", staticfile->path);
         const char *errorstr = "<html><body>Alsa-Json-Gateway Invalid file type</body></html>";
         response = MHD_create_response_from_buffer (strlen (errorstr),
                      (void *) errorstr,         MHD_RESPMEM_PERSISTENT);
         MHD_queue_response (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, response);
-        goto finishJob;
-
+        goto sendRequest;
     } 
     
+    // if url is a directory let's add index.html and redirect client
+    if (S_ISDIR (sbuf.st_mode)) {
+        close (staticfile->fd); // close directory check for Index
+       
+        // No trailing '/'. Let's add one and redirect for relative paths to work
+        if (url [strlen (url) -1] != '/') {
+            response = MHD_create_response_from_buffer(0,"", MHD_RESPMEM_PERSISTENT);
+            strncat(staticfile->path, "/", sizeof (staticfile->path));
+            MHD_add_response_header (response, "Location", staticfile->path);
+            MHD_queue_response (connection, MHD_HTTP_MOVED_PERMANENTLY, response);
+            if (verbose) fprintf (stderr,"Adding trailing '/' [%s]\n",staticfile->path);      
+            goto sendRequest;
+        }
+        
+        strncat (staticfile->path, OPA_INDEX, sizeof (staticfile->path));
+        if (-1 == (staticfile->fd = open(staticfile->path, O_RDONLY)) || (fstat (staticfile->fd, &sbuf) != 0)) {
+           fprintf(stderr, "No Index.html in direcory [%s]\n", staticfile->path);
+           goto abortRequest;  
+        }      
+    }   
+    
     // https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=fr
     // ftp://ftp.heanet.ie/disk1/www.gnu.org/software/libmicrohttpd/doxygen/dc/d0c/microhttpd_8h.html
 
@@ -139,23 +147,47 @@ STATIC int servFile (struct MHD_Connection *connection, AFB_session *session, co
 
     } else { // it's a new file, we need to upload it to client
         // if we have magic let's try to guest mime type
-        if (session->magic) {
-           mimetype="Unknown";
+        if (session->magic) {          
            mimetype= magic_descriptor(session->magic, staticfile->fd);
            if (mimetype != NULL)  MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_TYPE, mimetype);
-        };
-        if (verbose) fprintf(stderr, "Serving: [%s] mine=%s\n", staticfile->path, mimetype);
+        } else mimetype="Unknown";
+        
+        if (verbose) fprintf(stderr, "Serving: [%s] mime=%s\n", staticfile->path, mimetype);
         response = MHD_create_response_from_fd(sbuf.st_size, staticfile->fd);
         MHD_add_response_header(response, MHD_HTTP_HEADER_CACHE_CONTROL, session->cacheTimeout); // default one hour cache
         MHD_add_response_header(response, MHD_HTTP_HEADER_ETAG, etagValue);
         MHD_queue_response(connection, MHD_HTTP_OK, response);
     }
     
-finishJob:    
+sendRequest:    
     MHD_destroy_response(response);
     return (MHD_YES);
+
+abortRequest:
+    return (FAILED);
+}
+
+
+// this function return either Index.htlm or a redirect to /#!route to make angular happy
+STATIC int redirectHTML5(struct MHD_Connection *connection, AFB_session *session, const char* url) {
+
+    int fd;
+    int ret;
+    struct MHD_Response *response;
+    AFB_staticfile staticfile;
+
+    // Url match /opa/xxxx should redirect to "/opa/#!page" to force index.html reload
+    strncpy(staticfile.path, session->config->rootbase, sizeof (staticfile.path));
+    strncat(staticfile.path, "/#!", sizeof (staticfile.path));
+    strncat(staticfile.path, &url[1], sizeof (staticfile.path));
+    response = MHD_create_response_from_buffer(0,"", MHD_RESPMEM_PERSISTENT);
+    MHD_add_response_header (response, "Location", staticfile.path);
+    MHD_queue_response (connection, MHD_HTTP_MOVED_PERMANENTLY, response);
+    if (verbose) fprintf (stderr,"checkHTML5 redirect to [%s]\n",staticfile.path);
+    return (MHD_YES);
 }
 
+
 // minimal httpd file server for static HTML,JS,CSS,etc...
 STATIC int requestFile(struct MHD_Connection *connection, AFB_session *session, const char* url) {
     int fd;
@@ -172,50 +204,12 @@ STATIC int requestFile(struct MHD_Connection *connection, AFB_session *session,
     if (-1 == (staticfile.fd = open(staticfile.path, O_RDONLY))) {
         fprintf(stderr, "Fail to open file: [%s] error:%s\n", staticfile.path, strerror(errno));
         return (FAILED);
-
     }
     // open file is OK let use it
     ret = servFile (connection, session, url, &staticfile);
     return ret;
 }
 
-// this function return either Index.htlm or a redirect to /#!route to make angular happy
-STATIC int checkHTML5(struct MHD_Connection *connection, AFB_session *session, const char* url) {
-
-    int fd;
-    int ret;
-    struct MHD_Response *response;
-    AFB_staticfile staticfile;
-
-    // Any URL prefixed with /rootbase is served with index.html ex: /opa,/opa/,/opa/#!xxxxxx
-    if ( url[0] == '\0' || url[1] == '\0' || url[1] == '#') {
-        strncpy(staticfile.path, session->config->rootdir, sizeof (staticfile.path));
-        strncat(staticfile.path, "/index.html", sizeof (staticfile.path));
-        // try to open file and get its size
-        if (-1 == (staticfile.fd = open(staticfile.path, O_RDONLY))) {
-            fprintf(stderr, "Fail to open file: [%s] error:%s\n", staticfile.path, strerror(errno));
-            // Nothing respond to this request Files, API, Angular Base
-            const char *errorstr = "<html><body>Application Framework OPA/index.html Not found</body></html>";
-            response = MHD_create_response_from_buffer(strlen(errorstr),(void *)errorstr, MHD_RESPMEM_PERSISTENT);
-            MHD_queue_response(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, response);
-            return (MHD_YES);
-       } else {
-            ret = servFile (connection, session, url, &staticfile);
-            return ret;
-       }
-    }
-
-    // Url match /opa/xxxx but not /opa#!xxxx we redirect the URL to /opa#!/xxxx to force index.html reload
-    strncpy(staticfile.path, session->config->rootbase, sizeof (staticfile.path));
-    strncat(staticfile.path, "#!", sizeof (staticfile.path));
-    strncat(staticfile.path, url, sizeof (staticfile.path));
-    response = MHD_create_response_from_buffer(0,"", MHD_RESPMEM_PERSISTENT);
-    MHD_add_response_header (response, "Location", staticfile.path);
-    MHD_queue_response (connection, MHD_HTTP_MOVED_PERMANENTLY, response);
-    if (verbose) fprintf (stderr,"checkHTML5 redirect to [%s]\n",staticfile.path);
-    return (MHD_YES);
-}
-
 // Check and Dispatch HTTP request
 STATIC int newRequest(void *cls,
         struct MHD_Connection *connection,
@@ -230,7 +224,7 @@ STATIC int newRequest(void *cls,
     
     // this is a REST API let's check for plugins
     if (0 == strncmp(url, session->config->rootapi, apiUrlLen)) {
-        ret = doRestApi(connection, session, method, &url[apiUrlLen+1]);
+        ret = doRestApi(connection, session, &url[apiUrlLen+1], method, upload_data, upload_data_size, con_cls);
         return ret;
     }
     
@@ -241,9 +235,9 @@ STATIC int newRequest(void *cls,
     ret = requestFile(connection, session, url);
     if (ret != FAILED) return ret;
     
-    // no static was served let check for Angular redirect
+    // no static was served let's try HTML5 OPA redirect
     if (0 == strncmp(url, session->config->rootbase, baseUrlLen)) {
-        ret = checkHTML5(connection, session, &url[baseUrlLen]);
+        ret = redirectHTML5(connection, session, &url[baseUrlLen]);
         return ret;
     }
 
@@ -267,7 +261,7 @@ PUBLIC AFB_error httpdStart(AFB_session *session) {
     baseUrlLen= strlen (session->config->rootbase);
     
     // open libmagic cache
-    initLibMagic (session);
+    // initLibMagic (session);
     
     
     if (verbose) {
@@ -299,7 +293,7 @@ PUBLIC AFB_error httpdLoop(AFB_session *session) {
     if (session->foreground) {
 
         while (TRUE) {
-            fprintf(stderr, "AFB:notice Use Ctrl-C to quit");
+            fprintf(stderr, "AFB:notice Use Ctrl-C to quit\n");
             (void) getc(stdin);
         }
     } else {
index a86de1c..9586bb5 100644 (file)
@@ -72,6 +72,7 @@ static sigjmp_buf restartpoint; // context save for set/longjmp
 
  #define SET_SMACK          140
  #define SET_PLUGINS        141
+ #define SET_APITIMEOUT     142
 
  #define DISPLAY_VERSION    150
  #define DISPLAY_HELP       151
@@ -90,6 +91,7 @@ static  AFB_options cliOptions [] = {
   {SET_ROOT_DIR     ,1,"rootdir"         , "HTTP Root Directory [default $HOME/.AFB"},
   {SET_ROOT_BASE    ,1,"rootbase"        , "Angular Base Root URL [default /opa"},
   {SET_ROOT_API     ,1,"rootapi"         , "HTML Root API URL [default /api"},
+  {SET_APITIMEOUT   ,1,"apitimeout"      , "Plugin API timeout in seconds [default 10]"},
 
   {SET_CACHE_TO     ,1,"cache-eol"       , "Client cache end of live [default 3600s]"},
   {SET_cardid       ,1,"setuid"          , "Change user id [default don't change]"},
@@ -301,6 +303,11 @@ int main(int argc, char *argv[])  {
        if (optarg == 0) goto needValueForOption;
        if (!sscanf (optarg, "%d", &cliconfig.httpdPort)) goto notAnInteger;
        break;
+       
+    case SET_APITIMEOUT:
+       if (optarg == 0) goto needValueForOption;
+       if (!sscanf (optarg, "%d", &cliconfig.apiTimeout)) goto notAnInteger;
+       break;
 
     case SET_ROOT_DIR:
        if (optarg == 0) goto needValueForOption;
index 74237ad..39a7286 100644 (file)
  * Contain all generic part to handle REST/API
  */
 
-
-#include <microhttpd.h>
-#include <sys/stat.h>
 #include "../include/local-def.h"
 
-// proto missing from GCC
-char *strcasestr(const char *haystack, const char *needle);
+#include <setjmp.h>
+#include <signal.h>
+
+// context save for timeout set/longjmp
+static sigjmp_buf checkPluginCall; 
+
+// handle to hold queryAll values
+typedef struct {
+     char    *msg;
+     int     idx;
+     size_t  len;
+} queryHandleT;
+
+
+// Helper to retrieve argument from  connection
+PUBLIC const char* getQueryValue(AFB_request * request, char *name) {
+    const char *value;
+
+    value = MHD_lookup_connection_value(request->connection, MHD_GET_ARGUMENT_KIND, name);
+    return (value);
+}
+
+STATIC int getQueryCB (void*handle, enum MHD_ValueKind kind, const char *key, const char *value) {
+    queryHandleT *query = (queryHandleT*)handle;
+        
+    query->idx += snprintf (&query->msg[query->idx],query->len," %s: \'%s\',", key, value);
+}
+
+// Helper to retrieve argument from  connection
+PUBLIC const char* getQueryAll(AFB_request * request, char *buffer, size_t len) {
+    queryHandleT query;
+    
+    query.msg= buffer;
+    query.len= len;
+    query.idx= 0;
+
+    MHD_get_connection_values (request->connection, MHD_GET_ARGUMENT_KIND, getQueryCB, &query);
+    return (query.msg);
+}
+
+
+// Sample Generic Ping Debug API
+PUBLIC json_object* apiPingTest(AFB_session *session, AFB_request *request, void* handle) {
+    static pingcount = 0;
+    json_object *response;
+    char query [512];
+
+    // request all query key/value
+    getQueryAll (request, query, sizeof(query)); 
+    
+    // check if we have some post data
+    if (request->post == NULL)  request->post="NoData";  
+        
+    // return response to caller
+    response = jsonNewMessage(AFB_SUCCESS, "Ping Binder Daemon %d query={%s} PostData: \'%s\' ", pingcount++, query, request->post);
+    return (response);
+}
 
 
 // Because of POST call multiple time requestApi we need to free POST handle here
+
 STATIC void endRequest(void *cls, struct MHD_Connection *connection, void **con_cls, enum MHD_RequestTerminationCode toe) {
     AFB_HttpPost *posthandle = *con_cls;
 
@@ -39,92 +92,192 @@ STATIC void endRequest(void *cls, struct MHD_Connection *connection, void **con_
     }
 }
 
+/*----------------------------------------------------------
+ | timeout signalQuit
+ +--------------------------------------------------------- */
+STATIC void pluginError (int signum) {
 
-PUBLIC json_object* pingSample (AFB_plugin *plugin, AFB_session *session, AFB_request *post) {
-    static pingcount=0;
-    json_object *response;
-    response = jsonNewMessage(AFB_SUCCESS, "Ping Binder Daemon %d", pingcount++);
-    if (verbose) fprintf(stderr, "%d: \n", pingcount);
-    return (response);
+  sigset_t sigset;
+
+  // unlock timeout signal to allow a new signal to come
+  sigemptyset (&sigset);
+  sigaddset   (&sigset, SIGALRM);
+  sigprocmask (SIG_UNBLOCK, &sigset, 0);
+
+  fprintf (stderr, "Oops:%s Plugin Api Timeout timeout\n", configTime());
+  longjmp (checkPluginCall, signum);
 }
 
+
 // Check of apiurl is declare in this plugin and call it
-STATIC json_object * callPluginApi (AFB_plugin *plugin, AFB_session *session,  AFB_request *request) {
+
+STATIC json_object * callPluginApi(AFB_plugin *plugin, AFB_session *session, AFB_request *request) {
     json_object *response;
-    int idx;
-    
+    int idx, status;
+
     // If a plugin hold this urlpath call its callback
-    for (idx=0; plugin->apis[idx].callback != NULL; idx++) {
-        if (!strcmp (plugin->apis[idx].name, request->api)) {
-           response = plugin->apis[idx].callback (session, request);
-           if (response != NULL) {
-               json_object_object_add (response, "jtype" ,plugin->jtype);
-           }
-           return (response);
-        }   
+    for (idx = 0; plugin->apis[idx].callback != NULL; idx++) {
+        if (!strcmp(plugin->apis[idx].name, request->api)) {
+            
+            // save context before calling the API
+            status = setjmp (checkPluginCall);
+            if (status != 0) {
+                response = jsonNewMessage(AFB_FATAL, "Plugin Call Fail prefix=%s api=%s info=%s", plugin->prefix, request->api, plugin->info);
+            } else {
+                if (signal (SIGALRM, pluginError) == SIG_ERR) {
+                    fprintf (stderr, "%s ERR: main no Signal/timeout handler installed.", configTime());
+                    return NULL;
+                }
+                
+                if (signal (SIGSEGV, pluginError) == SIG_ERR) {
+                    fprintf (stderr, "%s ERR: main no Signal/memory handler installed.", configTime());
+                    return NULL;
+                }
+                
+                if (signal (SIGFPE , pluginError) == SIG_ERR) {
+                    fprintf (stderr, "%s ERR: main no Signal/memory handler installed.", configTime());
+                    return NULL;
+                }
+
+                // protect plugin call with a timeout
+                alarm (session->config->apiTimeout);
+
+                response = plugin->apis[idx].callback(session, request, plugin->apis[idx].handle);
+                if (response != NULL) json_object_object_add(response, "jtype", plugin->jtype);
+
+                // cancel timeout and sleep before next aquisition
+                alarm (0);
+                signal(SIGALRM, SIG_DFL);
+                signal(SIGSEGV, SIG_DFL);
+                signal(SIGFPE , SIG_DFL);
+            }    
+            return (response);
+
+        }
     }
     return (NULL);
 }
 
 
 // process rest API query
-PUBLIC int doRestApi(struct MHD_Connection *connection, AFB_session *session, const char *method, const char* url) {
 
-    char *baseurl, *baseapi, *urlcpy;
+PUBLIC int doRestApi(struct MHD_Connection *connection, AFB_session *session, const char* url, const char *method
+    , const char *upload_data, size_t *upload_data_size, void **con_cls) {
+    
+    static int postcount = 0; // static counter to debug POST protocol
+    char *baseurl, *baseapi, *urlcpy1, *urlcpy2, *query;
     json_object *jsonResponse, *errMessage;
     struct MHD_Response *webResponse;
     const char *serialized, parsedurl;
     AFB_request request;
-    int  idx, ret;  
+    AFB_HttpPost *posthandle = *con_cls;
+    int idx, ret;
 
-    // Extract plugin urlpath from request
-    urlcpy=strdup (url);
-    baseurl = strsep(&urlcpy, "/");
+    // Extract plugin urlpath from request and make two copy because strsep overload copy
+    urlcpy1 = urlcpy2 = strdup(url);
+    baseurl = strsep(&urlcpy2, "/");
     if (baseurl == NULL) {
         errMessage = jsonNewMessage(AFB_FATAL, "Invalid Plugin/API call url=%s", url);
         goto ExitOnError;
     }
-    
-    baseapi = strsep(&urlcpy, "/");
+
+    baseapi = strsep(&urlcpy2, "/");
     if (baseapi == NULL) {
         errMessage = jsonNewMessage(AFB_FATAL, "Invalid Plugin/API call url=%s/%s", baseurl, url);
         goto ExitOnError;
     }
     
-    // build request structure
-    memset (&request, 0, sizeof (request));
-    request.connection = connection;
-    request.url        = url;
-    request.plugin     = baseurl;
-    request.api        = baseapi;
 
-    // if post wait as data may come in multiple calls
-    if (0 == strcmp (method, MHD_HTTP_METHOD_POST)) {
-   
-        request.post="TO Be DONE"; 
+    // if post data may come in multiple calls
+    if (0 == strcmp(method, MHD_HTTP_METHOD_POST)) {
+        const char *encoding, *param;
+        int contentlen = -1;
+        AFB_HttpPost *posthandle = *con_cls;
+
+        // Let make sure we have the right encoding and a valid length
+        encoding = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_CONTENT_TYPE);
+        param = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_CONTENT_LENGTH);
+        if (param) sscanf(param, "%i", &contentlen);
+
+        // POST datas may come in multiple chunk. Even when it never happen on AFB, we still have to handle the case
+        if (strcasestr(encoding, JSON_CONTENT) == 0) {
+            errMessage = jsonNewMessage(AFB_FATAL, "Post Date wrong type encoding=%s != %s", encoding, JSON_CONTENT);
+            goto ExitOnError;
+        }
+
+        if (contentlen > MAX_POST_SIZE) {
+            errMessage = jsonNewMessage(AFB_FATAL, "Post Date to big %d > %d", contentlen, MAX_POST_SIZE);
+            goto ExitOnError;
+        }
+
+        // In POST mode first libmicrohttp call only establishes POST handling.
+        if (posthandle == NULL) {
+            posthandle = malloc(sizeof (AFB_HttpPost)); // allocate application POST processor handle
+            posthandle->uid = postcount++; // build a UID for DEBUG
+            posthandle->len = 0; // effective length within POST handler
+            posthandle->data = malloc(contentlen + 1); // allocate memory for full POST data + 1 for '\0' enf of string
+            *con_cls = posthandle; // attache POST handle to current HTTP session
+
+            if (verbose) fprintf(stderr, "Create Post[%d] Size=%d\n", posthandle->uid, contentlen);
+            return MHD_YES;
+        }
+
+        // This time we receive partial/all Post data. Note that even if we get all POST data. We should nevertheless
+        // return MHD_YES and not process the request directly. Otherwise Libmicrohttpd is unhappy and fails with
+        // 'Internal application error, closing connection'.
+        if (*upload_data_size) {
+            if (verbose) fprintf(stderr, "Update Post[%d]\n", posthandle->uid);
+
+            memcpy(&posthandle->data[posthandle->len], upload_data, *upload_data_size);
+            posthandle->len = posthandle->len + *upload_data_size;
+            *upload_data_size = 0;
+            return MHD_YES;
+        }
+
+        // We should only start to process DATA after Libmicrohttpd call or application handler with *upload_data_size==0
+        // At this level we're may verify that we got everything and process DATA
+        if (posthandle->len != contentlen) {
+            errMessage = jsonNewMessage(AFB_FATAL, "Post Data Incomplete UID=%d Len %d != %s", posthandle->uid, contentlen, posthandle->len);
+            goto ExitOnError;
+        }
+
+        // Before processing data, make sure buffer string is properly ended
+        posthandle->data[posthandle->len] = '\0';
+        request.post = posthandle->data;
+
+        if (verbose) fprintf(stderr, "Close Post[%d] Buffer=%s\n", posthandle->uid, request.post);
+
     } else {
-        request.post=NULL;
+        request.post = NULL;
     };
+
+   
+    // build request structure
+    memset(&request, 0, sizeof (request));
+    request.connection = connection;
+    request.url = url;
+    request.plugin = baseurl;
+    request.api = baseapi;
     
     // Search for a plugin with this urlpath
-    for (idx=0; session->plugins[idx] != NULL; idx++) {
-        if (!strcmp (session->plugins[idx]->prefix, baseurl)) {
-           jsonResponse = callPluginApi (session->plugins[idx], session, &request );
-           // free (urlcpy);
-           break;
+    for (idx = 0; session->plugins[idx] != NULL; idx++) {
+        if (!strcmp(session->plugins[idx]->prefix, baseurl)) {
+            jsonResponse = callPluginApi(session->plugins[idx], session, &request);
+            free(urlcpy1);
+            break;
         }
     }
     // No plugin was found
     if (session->plugins[idx] == NULL) {
         errMessage = jsonNewMessage(AFB_FATAL, "No Plugin for %s", baseurl);
-        free (urlcpy);
+        free(urlcpy1);
         goto ExitOnError;
     }
 
     // plugin callback did not return a valid Json Object
     if (jsonResponse == NULL) {
-       errMessage = jsonNewMessage(AFB_FATAL, "No Plugin/API for %s/%s", baseurl, baseapi);
-       goto ExitOnError;
+        errMessage = jsonNewMessage(AFB_FATAL, "No Plugin/API for %s/%s", baseurl, baseapi);
+        goto ExitOnError;
     }
 
     serialized = json_object_to_json_string(jsonResponse);
@@ -144,51 +297,45 @@ ExitOnError:
     return ret;
 }
 
-// Helper to retreive argument from  connection
-PUBLIC const char* getQueryValue (AFB_request * request, char *name) {
-    const char *value;
-    
-    value=MHD_lookup_connection_value(request->connection, MHD_GET_ARGUMENT_KIND, name);
-    return (value);
-}
 
 // Loop on plugins. Check that they have the right type, prepare a JSON object with prefix
+
 STATIC AFB_plugin ** RegisterPlugins(AFB_plugin **plugins) {
     int idx;
-    
-    for (idx=0; plugins[idx] != NULL; idx++) {
+
+    for (idx = 0; plugins[idx] != NULL; idx++) {
         if (plugins[idx]->type != AFB_PLUGIN) {
-            fprintf (stderr, "ERROR: AFSV plugin[%d] invalid type=%d != %d\n", idx,  AFB_PLUGIN, plugins[idx]->type);
+            fprintf(stderr, "ERROR: AFSV plugin[%d] invalid type=%d != %d\n", idx, AFB_PLUGIN, plugins[idx]->type);
         } else {
             // some sanity controls
-            if ((plugins[idx]->prefix == NULL) || (plugins[idx]->info == NULL) || (plugins[idx]->apis == NULL)){
+            if ((plugins[idx]->prefix == NULL) || (plugins[idx]->info == NULL) || (plugins[idx]->apis == NULL)) {
                 if (plugins[idx]->prefix == NULL) plugins[idx]->prefix = "No URL prefix for APIs";
                 if (plugins[idx]->info == NULL) plugins[idx]->info = "No Info describing plugin APIs";
-                fprintf (stderr, "ERROR: plugin[%d] invalid prefix=%s info=%s", idx,plugins[idx]->prefix, plugins[idx]->info);
+                fprintf(stderr, "ERROR: plugin[%d] invalid prefix=%s info=%s", idx, plugins[idx]->prefix, plugins[idx]->info);
                 return NULL;
             }
-            
-            if (verbose) fprintf (stderr, "Loading plugin[%d] prefix=[%s] info=%s\n", idx, plugins[idx]->prefix, plugins[idx]->info);
-            
+
+            if (verbose) fprintf(stderr, "Loading plugin[%d] prefix=[%s] info=%s\n", idx, plugins[idx]->prefix, plugins[idx]->info);
+
             // Prepare Plugin name to be added into each API response
-            plugins[idx]->jtype = json_object_new_string (plugins[idx]->prefix);
-            json_object_get (plugins[idx]->jtype); // increase reference count to make it permanent
-            
+            plugins[idx]->jtype = json_object_new_string(plugins[idx]->prefix);
+            json_object_get(plugins[idx]->jtype); // increase reference count to make it permanent
+
             // compute urlprefix lenght
-            plugins[idx]->prefixlen = strlen (plugins[idx]->prefix);
-        }  
+            plugins[idx]->prefixlen = strlen(plugins[idx]->prefix);
+        }
     }
     return (plugins);
 }
 
-void initPlugins (AFB_session *session) {
-    static AFB_plugin *plugins[10];
+void initPlugins(AFB_session *session) {
+    static AFB_plugin * plugins[10];
 
-        plugins[0]= afsvRegister (session),
-        plugins[1]= dbusRegister (session),
-        plugins[2]= alsaRegister (session),
-        plugins[3]= NULL;
+    plugins[0] = afsvRegister(session),
+            plugins[1] = dbusRegister(session),
+            plugins[2] = alsaRegister(session),
+            plugins[3] = NULL;
 
     // complete plugins and save them within current sessions    
-    session->plugins=  RegisterPlugins (plugins);  
+    session->plugins = RegisterPlugins(plugins);
 }
\ No newline at end of file