+ fprintf (stderr, "Oops:%s Plugin Api Timeout timeout\n", configTime());
+ longjmp (request->checkPluginCall, signum);
+ }
+
+
+ // 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)) {
+
+ // Request was found and at least partially executed
+ jreqt = json_object_new_object();
+ json_object_get (afbJsonType); // increate jsontype reference count
+ json_object_object_add (jreqt, "jtype", afbJsonType);
+
+ // prepare an object to store calling values
+ jcall=json_object_new_object();
+ json_object_object_add(jcall, "prefix", json_object_new_string (plugin->prefix));
+ json_object_object_add(jcall, "api" , json_object_new_string (plugin->apis[idx].name));
+
+ // save context before calling the API
+ status = setjmp (request->checkPluginCall);
+ if (status != 0) {
+
+ // Plugin aborted somewhere during its execution
+ json_object_object_add(jcall, "status", json_object_new_string ("abort"));
+ json_object_object_add(jcall, "info" , json_object_new_string ("Plugin broke during execution"));
+ json_object_object_add(jreqt, "request", jcall);
+
+ } else {
+
+ // If timeout protection==0 we are in debug and we do not apply signal protection
+ if (request->config->apiTimeout > 0) {
+ for (sig=0; signals[sig] != 0; sig++) {
+ if (signal (signals[sig], pluginError) == SIG_ERR) {
+ request->errcode = MHD_HTTP_UNPROCESSABLE_ENTITY;
+ json_object_object_add(jcall, "status", json_object_new_string ("fail"));
+ json_object_object_add(jcall, "info", json_object_new_string ("Setting Timeout Handler Failed"));
+ json_object_object_add(jreqt, "request", jcall);
+ return AFB_DONE;
+ }
+ }
+ // Trigger a timer to protect from unacceptable long time execution
+ alarm (request->config->apiTimeout);
+ }
+
+ // Out of SessionNone every call get a client context session
+ if (AFB_SESSION_NONE != plugin->apis[idx].session) {
+
+ // add client context to request
+ clientCtx = ctxClientGet(request, plugidx);
+ if (clientCtx == NULL) {
+ request->errcode=MHD_HTTP_INSUFFICIENT_STORAGE;
+ json_object_object_add(jcall, "status", json_object_new_string ("fail"));
+ json_object_object_add(jcall, "info", json_object_new_string ("Client Session Context Full !!!"));
+ json_object_object_add(jreqt, "request", jcall);
+ return (AFB_DONE);
+ };
+
+ if (verbose) fprintf(stderr, "Plugin=[%s] Api=[%s] Middleware=[%d] Client=[0x%x] Uuid=[%s] Token=[%s]\n"
+ , request->prefix, request->api, plugin->apis[idx].session, clientCtx, clientCtx->uuid, clientCtx->token);
+
+ switch(plugin->apis[idx].session) {
+
+ case AFB_SESSION_CREATE:
+ if (clientCtx->token[0] != '\0') {
+ request->errcode=MHD_HTTP_UNAUTHORIZED;
+ json_object_object_add(jcall, "status", json_object_new_string ("exist"));
+ json_object_object_add(jcall, "info", json_object_new_string ("AFB_SESSION_CREATE Session already exist"));
+ json_object_object_add(jreqt, "request", jcall);
+ return (AFB_DONE);
+ }
+
+ if (AFB_SUCCESS != ctxTokenCreate (clientCtx, request)) {
+ request->errcode=MHD_HTTP_UNAUTHORIZED;
+ json_object_object_add(jcall, "status", json_object_new_string ("fail"));
+ json_object_object_add(jcall, "info", json_object_new_string ("AFB_SESSION_CREATE Invalid Initial Token"));
+ json_object_object_add(jreqt, "request", jcall);
+ return (AFB_DONE);
+ } else {
+ json_object_object_add(jcall, "uuid", json_object_new_string (clientCtx->uuid));
+ json_object_object_add(jcall, "token", json_object_new_string (clientCtx->token));
+ json_object_object_add(jcall, "timeout", json_object_new_int (request->config->cntxTimeout));
+ }
+ break;
+
+
+ case AFB_SESSION_RENEW:
+ if (AFB_SUCCESS != ctxTokenRefresh (clientCtx, request)) {
+ request->errcode=MHD_HTTP_UNAUTHORIZED;
+ json_object_object_add(jcall, "status", json_object_new_string ("fail"));
+ json_object_object_add(jcall, "info", json_object_new_string ("AFB_SESSION_REFRESH Broken Exchange Token Chain"));
+ json_object_object_add(jreqt, "request", jcall);
+ return (AFB_DONE);
+ } else {
+ json_object_object_add(jcall, "uuid", json_object_new_string (clientCtx->uuid));
+ json_object_object_add(jcall, "token", json_object_new_string (clientCtx->token));
+ json_object_object_add(jcall, "timeout", json_object_new_int (request->config->cntxTimeout));
+ }
+ break;
+
+ case AFB_SESSION_CLOSE:
+ if (AFB_SUCCESS != ctxTokenCheck (clientCtx, request)) {
+ request->errcode=MHD_HTTP_UNAUTHORIZED;
+ json_object_object_add(jcall, "status", json_object_new_string ("empty"));
+ json_object_object_add(jcall, "info", json_object_new_string ("AFB_SESSION_CLOSE Not a Valid Access Token"));
+ json_object_object_add(jreqt, "request", jcall);
+ return (AFB_DONE);
+ } else {
+ json_object_object_add(jcall, "uuid", json_object_new_string (clientCtx->uuid));
+ }
+ break;
+
+ case AFB_SESSION_CHECK:
+ default:
+ // default action is check
+ if (AFB_SUCCESS != ctxTokenCheck (clientCtx, request)) {
+ request->errcode=MHD_HTTP_UNAUTHORIZED;
+ json_object_object_add(jcall, "status", json_object_new_string ("fail"));
+ json_object_object_add(jcall, "info", json_object_new_string ("AFB_SESSION_CHECK Invalid Active Token"));
+ json_object_object_add(jreqt, "request", jcall);
+ return (AFB_DONE);
+ }
+ break;
+ }
+ }
+
+ // Effectively CALL PLUGIN API with a subset of the context
+ jresp = plugin->apis[idx].callback(request, context);
+
+ // prefix response with request object;
+ request->jresp = jreqt;
+
+ // Store context in case it was updated by plugins
+ if (request->context != NULL) clientCtx->contexts[plugidx] = request->context;
+
+ // handle intermediary Post Iterates out of band
+ if ((jresp == NULL) && (request->errcode == MHD_HTTP_OK)) return (AFB_SUCCESS);
+
+ // Session close is done after the API call so API can still use session in closing API
+ if (AFB_SESSION_CLOSE == plugin->apis[idx].session) ctxTokenReset (clientCtx, request);
+
+ // API should return NULL of a valid Json Object
+ if (jresp == NULL) {
+ json_object_object_add(jcall, "status", json_object_new_string ("null"));
+ json_object_object_add(request->jresp, "request", jcall);
+ request->errcode = MHD_HTTP_NO_RESPONSE;
+
+ } else {
+ json_object_object_add(jcall, "status", json_object_new_string ("processed"));
+ json_object_object_add(request->jresp, "request", jcall);
+ json_object_object_add(request->jresp, "response", jresp);
+ }
+ // cancel timeout and plugin signal handle before next call
+ if (request->config->apiTimeout > 0) {
+ alarm (0);
+ for (sig=0; signals[sig] != 0; sig++) {
+ signal (signals[sig], SIG_DFL);
+ }
+ }
+ }
+ return (AFB_DONE);
+ }
+ }
+ return (AFB_FAIL);