afm-main-plugin: update utils-jbus
[src/app-framework-binder.git] / src / http-svc.c
index e8f2c0e..71e0a08 100644 (file)
    POST https://www.gnu.org/software/libmicrohttpd/manual/html_node/microhttpd_002dpost.html#microhttpd_002dpost
  */
 
+#define _GNU_SOURCE
 
 #include <microhttpd.h>
 
+#include <poll.h>
 #include <sys/stat.h>
 #include "../include/local-def.h"
 
 // let's compute fixed URL length only once
-static apiUrlLen=0;
-static baseUrlLen=0;
-static rootUrlLen=0;
-
-// proto missing from GCC
-char *strcasestr(const char *haystack, const char *needle);
-
-static int rqtcount = 0;  // dummy request rqtcount to make each message be different
-static int postcount = 0;
+static size_t apiUrlLen=0;
+static size_t baseUrlLen=0;
+static size_t rootUrlLen=0;
 
 // try to open libmagic to handle mime types
 static AFB_error initLibMagic (AFB_session *session) {
@@ -70,30 +66,25 @@ static AFB_error initLibMagic (AFB_session *session) {
 
 // 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;
+  AFB_PostHandle *posthandle = *con_cls;
 
   // if post handle was used let's free everything
-  if (posthandle) {
-     if (verbose) fprintf (stderr, "End Post Request UID=%d\n", posthandle->uid);
-     free (posthandle->data);
-     free (posthandle);
-  }
+  if (posthandle != NULL) endPostRequest (posthandle);
 }
 
 
 // Create check etag value
-STATIC void computeEtag(char *etag, int maxlen, struct stat *sbuf) {
-    int time;
+STATIC void computeEtag(char *etag, size_t maxlen, struct stat *sbuf) {
+    long time;
     time = sbuf->st_mtim.tv_sec;
-    snprintf(etag, maxlen, "%d", time);
+    snprintf(etag, maxlen, "%ld", time);
 }
 
 STATIC int servFile (struct MHD_Connection *connection, AFB_session *session, const char *url, AFB_staticfile *staticfile) {
     const char *etagCache, *mimetype; 
     char etagValue[15];
-    struct MHD_Response *response;
+    struct MHD_Response *response = NULL;
     struct stat sbuf; 
-    int ret;
 
     if (fstat (staticfile->fd, &sbuf) != 0) {
         fprintf(stderr, "Fail to stat file: [%s] error:%s\n", staticfile->path, strerror(errno));
@@ -107,6 +98,7 @@ STATIC int servFile (struct MHD_Connection *connection, AFB_session *session, co
         // 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);
+            strncpy(staticfile->path, url, sizeof (staticfile->path));
             strncat(staticfile->path, "/", sizeof (staticfile->path));
             MHD_add_response_header (response, "Location", staticfile->path);
             MHD_queue_response (connection, MHD_HTTP_MOVED_PERMANENTLY, response);
@@ -118,7 +110,7 @@ STATIC int servFile (struct MHD_Connection *connection, AFB_session *session, co
         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;  
-        }      
+        } 
     } else 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);
@@ -149,7 +141,7 @@ STATIC int servFile (struct MHD_Connection *connection, AFB_session *session, co
         if (session->magic) {          
            mimetype= magic_descriptor(session->magic, staticfile->fd);
            if (mimetype != NULL)  MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_TYPE, mimetype);
-        } else mimetype="Unknown";
+        } else mimetype="application/unknown";
         
         if (verbose) fprintf(stderr, "Serving: [%s] mime=%s\n", staticfile->path, mimetype);
         response = MHD_create_response_from_fd(sbuf.st_size, staticfile->fd);
@@ -170,8 +162,6 @@ abortRequest:
 // 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;
 
@@ -189,7 +179,7 @@ STATIC int redirectHTML5(struct MHD_Connection *connection, AFB_session *session
 
 // 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, ret, idx;
+    int ret, idx;
     AFB_staticfile staticfile;
     char *requestdir, *requesturl;
    
@@ -252,7 +242,7 @@ STATIC int newRequest(void *cls,
     }
 
      // Nothing respond to this request Files, API, Angular Base
-    const char *errorstr = "<html><body>Alsa-Json-Gateway Unknown or Not readable file</body></html>";
+    const char *errorstr = "<html><body>AFB-Daemon File Not Find file</body></html>";
     response = MHD_create_response_from_buffer(strlen(errorstr), (void*)errorstr, MHD_RESPMEM_PERSISTENT);
     ret = MHD_queue_response(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, response);
     return (MHD_YES);
@@ -265,14 +255,17 @@ STATIC int newClient(void *cls, const struct sockaddr * addr, socklen_t addrlen)
 
 
 PUBLIC AFB_error httpdStart(AFB_session *session) {
-    
+
     // compute fixed URL length at startup time
     apiUrlLen = strlen (session->config->rootapi);
     baseUrlLen= strlen (session->config->rootbase);
     rootUrlLen= strlen (session->config->rootdir);
+    
+    // Initialise Client Session Hash Table
+    ctxStoreInit (CTX_NBCLIENTS);
      
-    // TBD open libmagic cache [fail to pass EFENCE check]
-    // initLibMagic (session);
+    //TBD open libmagic cache [fail to pass EFENCE check (allocating 0 bytes)]
+    //initLibMagic (session);
     
     
     if (verbose) {
@@ -281,12 +274,16 @@ PUBLIC AFB_error httpdStart(AFB_session *session) {
     }
 
     session->httpd = (void*) MHD_start_daemon(
-            MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, // use request and not threads
-            session->config->httpdPort, // port
+                MHD_USE_EPOLL_LINUX_ONLY
+                | MHD_USE_TCP_FASTOPEN
+                | MHD_USE_DEBUG
+              ,
+            (uint16_t)session->config->httpdPort, // port
             &newClient, NULL, // Tcp Accept call back + extra attribute
             &newRequest, session, // Http Request Call back + extra attribute
             MHD_OPTION_NOTIFY_COMPLETED, &endRequest, NULL,
-            MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 15, MHD_OPTION_END); // 15s + options-end
+            MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 15, // 15 seconds
+            MHD_OPTION_END); // options-end
     // TBD: MHD_OPTION_SOCK_ADDR
 
     if (session->httpd == NULL) {
@@ -298,22 +295,27 @@ PUBLIC AFB_error httpdStart(AFB_session *session) {
 
 // infinite loop
 PUBLIC AFB_error httpdLoop(AFB_session *session) {
-    static int  count = 0;
+    int count = 0;
+    const union MHD_DaemonInfo *info;
+    struct pollfd pfd;
+
+    info = MHD_get_daemon_info(session->httpd,
+                               MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
+    if (info == NULL) {
+        printf("Error: httpLoop no pollfd");
+        goto error;
+    }
+    pfd.fd = info->listen_fd;
+    pfd.events = POLLIN;
 
     if (verbose) fprintf(stderr, "AFB:notice entering httpd waiting loop\n");
-    if (session->foreground) {
-
-        while (TRUE) {
-            fprintf(stderr, "AFB:notice Use Ctrl-C to quit\n");
-            (void) getc(stdin);
-        }
-    } else {
-        while (TRUE) {
-            sleep(3600);
-            if (verbose) fprintf(stderr, "AFB:notice httpd alive [%d]\n", count++);
-        }
+    while (TRUE) {
+        if (verbose) fprintf(stderr, "AFB:notice httpd alive [%d]\n", count++);
+        poll(&pfd, 1, 15000); // 15 seconds (as above timeout when starting)
+        MHD_run(session->httpd);
     }
 
+error:
     // should never return from here
     return AFB_FATAL;
 }