Post File Working in Most cases
[src/app-framework-binder.git] / src / rest-api.c
index c1110c5..1635d44 100644 (file)
@@ -17,7 +17,7 @@
  * 
  * Contain all generic part to handle REST/API
  * 
- *  https://www.gnu.org/software/libmicrohttpd/tutorial.html [search 'FILE *fp']
+ *  https://www.gnu.org/software/libmicrohttpd/tutorial.html [search 'largepost.c']
  */
 
 #include "../include/local-def.h"
@@ -65,6 +65,7 @@ PUBLIC json_object* apiPingTest(AFB_request *request) {
     return (response);
 }
 
+
 // Helper to retrieve argument from  connection
 PUBLIC const char* getQueryValue(AFB_request * request, char *name) {
     const char *value;
@@ -91,21 +92,23 @@ PUBLIC int getQueryAll(AFB_request * request, char *buffer, size_t len) {
     return (len);
 }
 
+
+// Helper to retreive POST handle
+PUBLIC AFB_PostHandle* getPostHandle (AFB_request *request) {
+    if (request->post == NULL) return (NULL);
+    return ((AFB_PostHandle*) request->post->data);
+}
+
 // Because of POST call multiple time requestApi we need to free POST handle here
+// Note this method is called from http-svc just before closing session
 PUBLIC void endPostRequest(AFB_PostHandle *postHandle) {
 
     if (postHandle->type == AFB_POST_JSON) {
-        if (verbose) fprintf(stderr, "End PostJson Request UID=%d\n", postHandle->uid);
+        // if (verbose) fprintf(stderr, "End PostJson Request UID=%d\n", postHandle->uid);
     }
 
     if (postHandle->type == AFB_POST_FORM) {
-        AFB_PostHandle *postform = (AFB_PostHandle*) postHandle->private;
-        if (verbose) fprintf(stderr, "End PostForm Request UID=%d\n", postHandle->uid);
-
-        // call API termination callback
-        if (!postHandle->private) {
-            if (!postHandle->completeCB) postHandle->completeCB (postHandle->private);
-        }
+         if (verbose) fprintf(stderr, "End PostForm Request UID=%d\n", postHandle->uid);
     }
     free(postHandle->private);
     free(postHandle);
@@ -178,7 +181,13 @@ STATIC AFB_error callPluginApi(AFB_plugin *plugin, AFB_request *request, void *c
                 if (AFB_SESSION_NONE != plugin->apis[idx].session) {
                     
                     // add client context to request
-                    ctxClientGet(request, plugin);
+                    if (ctxClientGet(request, plugin) != AFB_SUCCESS) {
+                        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(request->jresp, "request", jcall);
+                        return (AFB_DONE);                              
+                    };
                     
                     if (verbose) fprintf(stderr, "Plugin=[%s] Api=[%s] Middleware=[%d] Client=[0x%x] Uuid=[%s] Token=[%s]\n"
                            , request->plugin, request->api, plugin->apis[idx].session, request->client, request->client->uuid, request->client->token);                        
@@ -203,6 +212,7 @@ STATIC AFB_error callPluginApi(AFB_plugin *plugin, AFB_request *request, void *c
                             } else {
                                 json_object_object_add(jcall, "uuid", json_object_new_string (request->client->uuid));                                
                                 json_object_object_add(jcall, "token", json_object_new_string (request->client->token));                                
+                                json_object_object_add(jcall, "timeout", json_object_new_int (request->config->cntxTimeout));                                
                             }
                             break;
 
@@ -217,6 +227,7 @@ STATIC AFB_error callPluginApi(AFB_plugin *plugin, AFB_request *request, void *c
                             } else {
                                 json_object_object_add(jcall, "uuid", json_object_new_string (request->client->uuid));                                
                                 json_object_object_add(jcall, "token", json_object_new_string (request->client->token));                                
+                                json_object_object_add(jcall, "timeout", json_object_new_int (request->config->cntxTimeout));                                
                             }
                             break;
 
@@ -248,6 +259,9 @@ STATIC AFB_error callPluginApi(AFB_plugin *plugin, AFB_request *request, void *c
                 
                 // Effectively call the API with a subset of the context
                 jresp = plugin->apis[idx].callback(request, context);
+                
+                // handle intemediatry 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 (request);                    
@@ -273,8 +287,7 @@ STATIC AFB_error callPluginApi(AFB_plugin *plugin, AFB_request *request, void *c
             }       
             return (AFB_DONE);
         }
-    }
-    
+    }   
     return (AFB_FAIL);
 }
 
@@ -297,13 +310,10 @@ STATIC AFB_error findAndCallApi (AFB_request *request, void *context) {
     }  
     
     // plugin callback did not return a valid Json Object
-    if (status != AFB_DONE) {
+    if (status == AFB_FAIL) {
         request->jresp = jsonNewMessage(AFB_FATAL, "No API=[%s] for Plugin=[%s]", request->api, request->plugin);
         goto ExitOnError;
     }
-
-
-
     
     // Everything look OK
     return (status);
@@ -328,6 +338,7 @@ doPostIterate (void *cls, enum MHD_ValueKind kind, const char *key,
   AFB_request *request = (AFB_request*)postHandle->private;
   AFB_PostRequest postRequest;
   
+  fprintf (stderr, "postHandle key=%s filename=%s len=%d mime=%s\n", key, filename, size, mimetype);
    
   // Create and Item value for Plugin API
   item.kind     = kind;
@@ -347,7 +358,6 @@ doPostIterate (void *cls, enum MHD_ValueKind kind, const char *key,
   
   // effectively call plugin API                 
   status = findAndCallApi (request, &item);
-  
   // when returning no processing of postform stop
   if (status != AFB_SUCCESS) return MHD_NO;
   
@@ -422,10 +432,15 @@ PUBLIC int doRestApi(struct MHD_Connection *connection, AFB_session *session, co
             // allocate application POST processor handle to zero
             postHandle = calloc(1, sizeof (AFB_PostHandle));
             postHandle->uid = postcount++; // build a UID for DEBUG
-            *con_cls = postHandle;         // attache POST handle to current HTTP request
             
             // 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);
+            
+            // We are facing an empty post let's process it as a get
+            if (encoding == NULL) {
+                request= createRequest (connection, session, url);
+                goto ProcessApiCall;
+            }
         
             // Form post is handle through a PostProcessor and call API once per form key
             if (strcasestr(encoding, FORM_CONTENT) != NULL) {
@@ -440,6 +455,7 @@ PUBLIC int doRestApi(struct MHD_Connection *connection, AFB_session *session, co
                 postHandle->type   = AFB_POST_FORM;
                 postHandle->pp     = MHD_create_post_processor (connection, MAX_POST_SIZE, doPostIterate, postHandle);
                 postHandle->private= (void*)request;
+                *con_cls = postHandle;  // update context with posthandle
                 
                 if (NULL == postHandle->pp) {
                     fprintf(stderr,"OOPS: Internal error fail to allocate MHD_create_post_processor\n");
@@ -465,14 +481,13 @@ PUBLIC int doRestApi(struct MHD_Connection *connection, AFB_session *session, co
                 postHandle->type = AFB_POST_JSON;
                 postHandle->private = malloc(contentlen + 1); // allocate memory for full POST data + 1 for '\0' enf of string
 
-                if (verbose) fprintf(stderr, "Create PostJson[uid=%d] Size=%d\n", postHandle->uid, contentlen);
+                // if (verbose) fprintf(stderr, "Create PostJson[uid=%d] Size=%d\n", postHandle->uid, contentlen);
                 return MHD_YES;
 
             } else {
                 // We only support Json and Form Post format
                 errMessage = jsonNewMessage(AFB_FATAL, "Post Date wrong type encoding=%s != %s", encoding, JSON_CONTENT);
-                goto ExitOnError;
-                
+                goto ExitOnError;                
             }   
         }
 
@@ -482,18 +497,18 @@ PUBLIC int doRestApi(struct MHD_Connection *connection, AFB_session *session, co
         if (*upload_data_size) {
     
             if (postHandle->type == AFB_POST_FORM) {
-                if (verbose) fprintf(stderr, "Processing PostForm[uid=%d]\n", postHandle->uid);
+                // if (verbose) fprintf(stderr, "Processing PostForm[uid=%d]\n", postHandle->uid);
                 MHD_post_process (postHandle->pp, upload_data, *upload_data_size);
             }
             
             // Process JsonPost request when buffer is completed let's call API    
             if (postHandle->type == AFB_POST_JSON) {
-                if (verbose) fprintf(stderr, "Updating PostJson[uid=%d]\n", postHandle->uid);
-
+                // if (verbose) fprintf(stderr, "Updating PostJson[uid=%d]\n", postHandle->uid);
                 memcpy(&postHandle->private[postHandle->len], upload_data, *upload_data_size);
                 postHandle->len = postHandle->len + *upload_data_size;
-                *upload_data_size = 0;
             }
+            
+            *upload_data_size = 0;
             return MHD_YES;
             
         } else {  // we have finish with Post reception let's finish the work
@@ -504,10 +519,16 @@ PUBLIC int doRestApi(struct MHD_Connection *connection, AFB_session *session, co
                 errMessage = request->jresp;
                 goto ExitOnError;
             }
-
+            
+            // Postform add application context handle to request
+            if (postHandle->type == AFB_POST_FORM) {
+               postRequest.data = (char*) postHandle;
+               postRequest.type = postHandle->type;
+               request->post = &postRequest;
+            }
             
             if (postHandle->type == AFB_POST_JSON) {
-                if (verbose) fprintf(stderr, "Processing PostJson[uid=%d]\n", postHandle->uid);
+                // if (verbose) fprintf(stderr, "Processing PostJson[uid=%d]\n", postHandle->uid);
 
                 param = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_CONTENT_LENGTH);
                 if (param) sscanf(param, "%i", &contentlen);
@@ -524,18 +545,18 @@ PUBLIC int doRestApi(struct MHD_Connection *connection, AFB_session *session, co
                 postRequest.type = postHandle->type;
                 request->post = &postRequest;
 
-                if (verbose) fprintf(stderr, "Close Post[%d] Buffer=%s\n", postHandle->uid, request->post->data);
+                // if (verbose) fprintf(stderr, "Close Post[%d] Buffer=%s\n", postHandle->uid, request->post->data);
             }
         }
     } else {
         // this is a get we only need a request
         request= createRequest (connection, session, url);
     };
-    
+
+ProcessApiCall:    
     // Request is ready let's call API without any extra handle
     status = findAndCallApi (request, NULL);
-    
-ExitOnResponse:
+
     serialized = json_object_to_json_string(request->jresp);
     webResponse = MHD_create_response_from_buffer(strlen(serialized), (void*) serialized, MHD_RESPMEM_MUST_COPY);
     
@@ -612,8 +633,12 @@ void initPlugins(AFB_session *session) {
     afbJsonType = json_object_new_string (AFB_MSG_JTYPE);
     int i = 0;
 
-    plugins[i++] = afsvRegister(session),
-    plugins[i++] = alsaRegister(session),
+    plugins[i++] = tokenRegister(session);
+    plugins[i++] = helloWorldRegister(session);
+    plugins[i++] = samplePostRegister(session);
+#ifdef HAVE_AUDIO_PLUGIN
+    plugins[i++] = audioRegister(session);
+#endif
 #ifdef HAVE_RADIO_PLUGIN
     plugins[i++] = radioRegister(session),
 #endif