summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFulup Ar Foll <fulup@iot.bzh>2015-12-09 01:27:23 +0100
committerFulup Ar Foll <fulup@iot.bzh>2015-12-09 01:27:23 +0100
commitb55efc33fb8df8b0518570b2584b6da9abb3221b (patch)
treeef09396c903355a7d61d57e029f13af90f3ffa3e
parent6458b6eb67426974e9a3b8eed1f5620f0de0efc5 (diff)
Added POST, Plugin API signal protection, refactor HTML5 rewrite
-rw-r--r--.gitignore8
-rw-r--r--include/local-def.h10
-rw-r--r--include/proto-def.h10
-rw-r--r--nbproject/Makefile-Debug.mk26
-rw-r--r--nbproject/Makefile-Release.mk8
-rw-r--r--nbproject/Makefile-impl.mk2
-rw-r--r--nbproject/Makefile-variables.mk16
-rw-r--r--nbproject/Package-Debug.bash12
-rw-r--r--nbproject/Package-Release.bash12
-rw-r--r--nbproject/configurations.xml2
-rw-r--r--nbproject/project.xml2
-rw-r--r--src/afbs-api.c38
-rw-r--r--src/alsa-api.c43
-rw-r--r--src/config.c13
-rw-r--r--src/dbus-api.c30
-rw-r--r--src/http-svc.c134
-rw-r--r--src/main.c7
-rw-r--r--src/rest-api.c299
18 files changed, 446 insertions, 226 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..6e3b026e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+/nbproject/private/
+amixer
+autom4te.cache
+config.log
+build/**
+dist/**
+!.gitignore
+.dep.inc \ No newline at end of file
diff --git a/include/local-def.h b/include/local-def.h
index 3f0a26a0..72c51dea 100644
--- a/include/local-def.h
+++ b/include/local-def.h
@@ -40,6 +40,10 @@
/* 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
diff --git a/include/proto-def.h b/include/proto-def.h
index d1b0c3fb..3e1d1c38 100644
--- a/include/proto-def.h
+++ b/include/proto-def.h
@@ -21,9 +21,15 @@
*/
// 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);
diff --git a/nbproject/Makefile-Debug.mk b/nbproject/Makefile-Debug.mk
index 1866ff18..39692f38 100644
--- a/nbproject/Makefile-Debug.mk
+++ b/nbproject/Makefile-Debug.mk
@@ -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:
diff --git a/nbproject/Makefile-Release.mk b/nbproject/Makefile-Release.mk
index 6df0bda6..7cbdfe86 100644
--- a/nbproject/Makefile-Release.mk
+++ b/nbproject/Makefile-Release.mk
@@ -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:
diff --git a/nbproject/Makefile-impl.mk b/nbproject/Makefile-impl.mk
index 185e4af2..a2d5e848 100644
--- a/nbproject/Makefile-impl.mk
+++ b/nbproject/Makefile-impl.mk
@@ -24,7 +24,7 @@ CLEAN_SUBPROJECTS=${CLEAN_SUBPROJECTS_${SUBPROJECTS}}
# Project Name
-PROJECTNAME=AppFrameworkBinder
+PROJECTNAME=afb-daemon
# Active Configuration
DEFAULTCONF=Debug
diff --git a/nbproject/Makefile-variables.mk b/nbproject/Makefile-variables.mk
index 4e44a219..60514673 100644
--- a/nbproject/Makefile-variables.mk
+++ b/nbproject/Makefile-variables.mk
@@ -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
#
diff --git a/nbproject/Package-Debug.bash b/nbproject/Package-Debug.bash
index 26359837..b7d25543 100644
--- a/nbproject/Package-Debug.bash
+++ b/nbproject/Package-Debug.bash
@@ -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
diff --git a/nbproject/Package-Release.bash b/nbproject/Package-Release.bash
index 4ef9af39..627cc4c8 100644
--- a/nbproject/Package-Release.bash
+++ b/nbproject/Package-Release.bash
@@ -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
diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml
index c0793702..ce722f75 100644
--- a/nbproject/configurations.xml
+++ b/nbproject/configurations.xml
@@ -46,12 +46,14 @@
<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>
diff --git a/nbproject/project.xml b/nbproject/project.xml
index 394601fb..91920333 100644
--- a/nbproject/project.xml
+++ b/nbproject/project.xml
@@ -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/>
diff --git a/src/afbs-api.c b/src/afbs-api.c
index 40e89d02..b55ebf60 100644
--- a/src/afbs-api.c
+++ b/src/afbs-api.c
@@ -19,31 +19,35 @@
#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}
};
diff --git a/src/alsa-api.c b/src/alsa-api.c
index ab7dced3..01341ce0 100644
--- a/src/alsa-api.c
+++ b/src/alsa-api.c
@@ -19,24 +19,43 @@
#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}
};
diff --git a/src/config.c b/src/config.c
index 6691ca03..ae1830d1 100644
--- a/src/config.c
+++ b/src/config.c
@@ -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
diff --git a/src/dbus-api.c b/src/dbus-api.c
index 9d34e436..1f81bb2f 100644
--- a/src/dbus-api.c
+++ b/src/dbus-api.c
@@ -19,22 +19,38 @@
#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;
diff --git a/src/http-svc.c b/src/http-svc.c
index 836915a7..cd488961 100644
--- a/src/http-svc.c
+++ b/src/http-svc.c
@@ -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 {
diff --git a/src/main.c b/src/main.c
index a86de1c5..9586bb56 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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;
diff --git a/src/rest-api.c b/src/rest-api.c
index 74237adc..39a7286d 100644
--- a/src/rest-api.c
+++ b/src/rest-api.c
@@ -18,16 +18,69 @@
* 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