Post File Working in Most cases
authorFulup Ar Foll <fulup@iot.bzh>
Mon, 21 Dec 2015 01:10:20 +0000 (02:10 +0100)
committerFulup Ar Foll <fulup@iot.bzh>
Mon, 21 Dec 2015 01:10:20 +0000 (02:10 +0100)
include/proto-def.h
nbproject/configurations.xml
nbproject/private/configurations.xml
plugins/CMakeLists.txt
plugins/samples/HelloWorld.c
plugins/samples/SamplePost.c
src/rest-api.c

index 4241b4b..315cecf 100644 (file)
@@ -29,6 +29,7 @@ PUBLIC int getQueryAll(AFB_request * request, char *query, size_t len);
 PUBLIC void endPostRequest(AFB_PostHandle *posthandle); 
 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);
+PUBLIC AFB_PostHandle* getPostHandle (AFB_request *request);
 
 void initPlugins (AFB_session *session);
 
@@ -37,6 +38,7 @@ PUBLIC  AFB_plugin* tokenRegister ();
 PUBLIC  AFB_plugin* audioRegister ();
 PUBLIC  AFB_plugin* helloWorldRegister ();
 PUBLIC  AFB_plugin* radioRegister ();
+PUBLIC  AFB_plugin* samplePostRegister ();
 
 // Session handling
 PUBLIC AFB_error sessionCheckdir     (AFB_session *session);
index ae317b8..522e7a7 100644 (file)
@@ -13,6 +13,7 @@
         </df>
         <df name="samples">
           <in>HelloWorld.c</in>
+          <in>SamplePost.c</in>
         </df>
         <df name="session">
           <in>token-api.c</in>
@@ -90,8 +91,6 @@
             <pElem>/usr/include/json-c</pElem>
             <pElem>/usr/include/uuid</pElem>
             <pElem>/usr/include/alsa</pElem>
-            <pElem>/usr/include/libusb-1.0</pElem>
-            <pElem>build/plugins</pElem>
           </incDir>
         </cTool>
       </folder>
       <folder path="0/plugins/radio">
         <cTool>
           <incDir>
+            <pElem>/usr/include/libusb-1.0</pElem>
+            <pElem>build/plugins</pElem>
             <pElem>plugins/radio</pElem>
+            <pElem>plugins/audio</pElem>
           </incDir>
         </cTool>
       </folder>
         <cTool>
           <incDir>
             <pElem>plugins/samples</pElem>
+            <pElem>build/plugins</pElem>
           </incDir>
         </cTool>
       </folder>
         <cTool>
           <incDir>
             <pElem>plugins/session</pElem>
+            <pElem>build/plugins</pElem>
           </incDir>
-          <preprocessorList>
-            <Elem>__PIC__=2</Elem>
-            <Elem>__REGISTER_PREFIX__=</Elem>
-            <Elem>__USER_LABEL_PREFIX__=</Elem>
-            <Elem>__pic__=2</Elem>
-          </preprocessorList>
         </cTool>
       </folder>
       <item path="plugins/audio/audio-alsa.c" ex="false" tool="0" flavor2="2">
       </item>
       <item path="plugins/radio/radio-api.c" ex="false" tool="0" flavor2="2">
         <cTool flags="1">
-          <incDir>
-            <pElem>/usr/include/json-c</pElem>
-            <pElem>include</pElem>
-            <pElem>plugins/audio</pElem>
-            <pElem>/usr/include/uuid</pElem>
-            <pElem>build/plugins</pElem>
-          </incDir>
         </cTool>
       </item>
       <item path="plugins/radio/radio-rtlsdr.c" ex="false" tool="0" flavor2="2">
         <cTool flags="1">
-          <incDir>
-            <pElem>plugins/audio</pElem>
-            <pElem>include</pElem>
-            <pElem>/usr/include/json-c</pElem>
-            <pElem>/usr/include/uuid</pElem>
-            <pElem>build/plugins</pElem>
-          </incDir>
         </cTool>
       </item>
       <item path="plugins/samples/HelloWorld.c" ex="false" tool="0" flavor2="2">
         <cTool flags="1">
         </cTool>
       </item>
+      <item path="plugins/samples/SamplePost.c" ex="false" tool="0" flavor2="2">
+        <cTool flags="1">
+        </cTool>
+      </item>
       <item path="plugins/session/token-api.c" ex="false" tool="0" flavor2="2">
         <cTool flags="1">
         </cTool>
           </incDir>
           <preprocessorList>
             <Elem>HAVE_AUDIO_PLUGIN=1</Elem>
-            <Elem>HAVE_RADIO_PLUGIN=1</Elem>
             <Elem>__PIC__=2</Elem>
             <Elem>__REGISTER_PREFIX__=</Elem>
             <Elem>__USER_LABEL_PREFIX__=</Elem>
           </incDir>
           <preprocessorList>
             <Elem>HAVE_AUDIO_PLUGIN=1</Elem>
-            <Elem>HAVE_RADIO_PLUGIN=1</Elem>
             <Elem>__PIC__=2</Elem>
             <Elem>__REGISTER_PREFIX__=</Elem>
             <Elem>__USER_LABEL_PREFIX__=</Elem>
           </incDir>
           <preprocessorList>
             <Elem>HAVE_AUDIO_PLUGIN=1</Elem>
-            <Elem>HAVE_RADIO_PLUGIN=1</Elem>
             <Elem>__PIC__=2</Elem>
             <Elem>__REGISTER_PREFIX__=</Elem>
             <Elem>__USER_LABEL_PREFIX__=</Elem>
           </incDir>
           <preprocessorList>
             <Elem>HAVE_AUDIO_PLUGIN=1</Elem>
-            <Elem>HAVE_RADIO_PLUGIN=1</Elem>
             <Elem>__PIC__=2</Elem>
             <Elem>__REGISTER_PREFIX__=</Elem>
             <Elem>__USER_LABEL_PREFIX__=</Elem>
           </incDir>
           <preprocessorList>
             <Elem>HAVE_AUDIO_PLUGIN=1</Elem>
-            <Elem>HAVE_RADIO_PLUGIN=1</Elem>
             <Elem>__PIC__=2</Elem>
             <Elem>__REGISTER_PREFIX__=</Elem>
             <Elem>__USER_LABEL_PREFIX__=</Elem>
index 9a82aa6..b9de233 100644 (file)
@@ -20,8 +20,6 @@
             <df name="plugins.dir">
               <df name="audio">
               </df>
-              <df name="radio">
-              </df>
               <df name="samples">
               </df>
               <df name="session">
@@ -96,8 +94,6 @@
             <df name="plugins.dir">
               <df name="audio">
               </df>
-              <df name="radio">
-              </df>
               <df name="samples">
               </df>
               <df name="session">
index 7696938..7e3e080 100644 (file)
@@ -1,5 +1,6 @@
 SET(SESSION_PLUGIN session/token-api.c)
-SET(SAMPLE_PLUGINS samples/HelloWorld.c)
+SET(HELLOWORLD_PLUGINS samples/HelloWorld.c)
+SET(SAMPLEPOST_PLUGINS samples/SamplePost.c)
 IF(alsa_FOUND)
   SET(AUDIO_PLUGIN audio/audio-api.c audio/audio-alsa.c)
 ENDIF(alsa_FOUND)
@@ -7,7 +8,7 @@ IF(librtlsdr_FOUND)
   SET(RADIO_PLUGIN radio/radio-api.c radio/radio-rtlsdr.c)
 ENDIF(librtlsdr_FOUND)
 
-SET(PLUGINS_SOURCES ${SESSION_PLUGIN} ${SAMPLE_PLUGINS} ${AUDIO_PLUGIN} ${RADIO_PLUGIN})
+SET(PLUGINS_SOURCES ${SESSION_PLUGIN} ${HELLOWORLD_PLUGINS} ${SAMPLEPOST_PLUGINS} ${AUDIO_PLUGIN} ${RADIO_PLUGIN})
 
 ADD_LIBRARY(plugins OBJECT ${PLUGINS_SOURCES})
 INCLUDE_DIRECTORIES(${include_dirs})
index 619c075..4117c26 100644 (file)
@@ -73,7 +73,8 @@ STATIC json_object* pingJson (AFB_session *session, AFB_request *request) {
     return jresp;
 }
 
-
+// NOTE: this sample does not use session to keep test a basic as possible
+//       in real application most APIs should be protected with AFB_SESSION_CHECK
 STATIC  AFB_restapi pluginApis[]= {
   {"ping"     , AFB_SESSION_NONE, (AFB_apiCB)pingSample  , "Ping Application Framework"},
   {"pingnull" , AFB_SESSION_NONE, (AFB_apiCB)pingFail    , "Return NULL"},
index c4b9bc2..8548501 100644 (file)
 
 // In this case or handle is quite basic
 typedef struct {
-   int fd; 
+   int   fd; 
+   char *path; 
+   json_object* jerror;
 } appPostCtx;
 
+// With content-type=json data are directly avaliable in request->post->data
+STATIC json_object* GetJsonByPost (AFB_request *request) {
+    json_object* jresp;
+    char query [256];
+    int  len;
+    
+    // check if we have some post data
+    if (request->post == NULL)  request->post->data="NoData"; 
+    
+    // Get all query string [Note real app should probably use value=getQueryValue(request,"key")]
+    len = getQueryAll (request, query, sizeof(query));
+    if (len == 0) strncpy (query, "NoSearchQueryList", sizeof(query));
+    
+    // for debug/test return response to caller
+    jresp = jsonNewMessage(AFB_SUCCESS, "GetJsonByPost query={%s} PostData: [%s]", query, request->post->data);
+    
+    return (jresp);    
+}
+
 // This function is call when PostForm processing is completed
-STATIC void DonePostForm (AFB_request *request) {
-    AFB_PostHandle  *postHandle = (AFB_PostHandle*)request->post->data;
-    appPostCtx *appCtx= postHandle->ctx;
+STATIC void DonePostForm (AFB_request *request) { 
     
-    // Close upload file ID
-    close (appCtx->fd);
+    // Retrieve PostHandle Context from request
+    AFB_PostHandle *postHandle = getPostHandle(request);
+    appPostCtx *appCtx= (appPostCtx*) postHandle->ctx;
 
-    // Free application specific handle
-    free (postHandle->ctx);
+    if (verbose) fprintf (stderr, "DonePostForm file=[%s]upload done\n", appCtx->path);
     
-    if (verbose) fprintf (stderr, "DonePostForm upload done\n");
+
 }
 
 
-// WARNING: PostForm callback are call multiple time (one or each key within form)
-// When processing POST_JSON request->data hold a PostHandle and not data directly as for POST_JSON
-STATIC json_object* ProcessPostForm (AFB_request *request, AFB_PostItem *item) {
+// PostForm callback is called multiple times (one or each key within form, or once per file buffer)
+// When processing POST_FORM request->data holds a PostHandle and not data directly as for POST_JSON
+// When file has been fully uploaded call is call with item==NULL it is application responsibility to free appPostCtx
+STATIC json_object* UploadFile (AFB_request *request, AFB_PostItem *item) {
 
-    AFB_PostHandle  *postHandle;
+    AFB_PostHandle *postHandle = getPostHandle(request);
     appPostCtx *appCtx;
     char filepath[512];
+    int len;
             
-    // When Post is fully processed the same callback is call with a item==NULL
+    // This is called after PostForm and then after DonePostForm
     if (item == NULL) {
-        // Close file, Free handle
+        json_object* jresp;
+        appCtx = (appPostCtx*) postHandle->ctx;
         
-        request->errcode = MHD_HTTP_OK;
-        return(jsonNewMessage(AFB_SUCCESS,"File [%s] uploaded at [%s] error=\n", item->filename, request->config->sessiondir));  
+        // No Post Application Context [something really bad happen]
+        if (appCtx == NULL) {
+            request->errcode = MHD_HTTP_EXPECTATION_FAILED;
+            return(jsonNewMessage(AFB_FAIL,"Error: PostForm no PostContext to free\n"));          
+        }
+        
+        // We have a context but last Xform iteration fail.
+        if (appCtx->jerror != NULL) {
+            request->errcode = MHD_HTTP_EXPECTATION_FAILED;
+            jresp = appCtx->jerror;  // retrieve previous error from postCtx
+        } else jresp = jsonNewMessage(AFB_FAIL,"UploadFile Post Request file=[%s] done", appCtx->path);
+        
+        // Error or not let's free all resources
+        close(appCtx->fd);
+        free (appCtx->path);
+        free (appCtx);
+        return (jresp);  
     }
     
-    // Let's make sure this is a valid PostForm request
+    // Make sure it's a valid PostForm request
     if (!request->post && request->post->type != AFB_POST_FORM) {
-        request->errcode = MHD_HTTP_FORBIDDEN;
-        return(jsonNewMessage(AFB_FAIL,"This is not a valid PostForm request\n"));          
-    } else {
-        // In AFB_POST_FORM case post->data is a PostForm handle
-        postHandle = (AFB_PostHandle*) request->post->data;
-        appCtx = (appPostCtx*) postHandle->ctx;
-    }
-
+        appCtx->jerror= jsonNewMessage(AFB_FAIL,"This is not a valid PostForm request\n");
+        goto ExitOnError;
+    } 
+    
     // Check this is a file element
-    if (0 != strcmp (item->key, "file")) {
-        request->errcode = MHD_HTTP_FORBIDDEN;
-        return (jsonNewMessage(AFB_FAIL,"No File within element key=%s\n", item->key));
+    if (item->filename == NULL) {
+        appCtx->jerror= jsonNewMessage(AFB_FAIL,"No Filename attached to key=%s\n", item->key);
+        goto ExitOnError;
+    }
+    
+    // Check we got something in buffer
+    if (item->len <= 0) {       
+        appCtx->jerror= jsonNewMessage(AFB_FAIL,"Buffer size NULL key=%s]\n", item->key);
+        goto ExitOnError;
     }
 
-    // This is the 1st Item iteration let's open output file and allocate necessary resources
-    if (postHandle->ctx == NULL)  {
-        int fd;
-        
-        strncpy (filepath, request->config->sessiondir, sizeof(filepath));
-        strncat (filepath, "/", sizeof(filepath));
-        strncat (filepath, item->filename, sizeof(filepath));  
-
-        if((fd = open(request->config->sessiondir, O_RDONLY)) < 0) {
-            request->errcode = MHD_HTTP_FORBIDDEN;
-            return (jsonNewMessage(AFB_FAIL,"Fail to Upload file [%s] at [%s] error=\n", item->filename, request->config->sessiondir, strerror(errno)));
-        };            
+    // Extract Application Context from posthandle [NULL == 1st iteration]    
+    appCtx = (appPostCtx*) postHandle->ctx;
 
+    // This is the 1st Item iteration let's open output file and allocate necessary resources
+    if (appCtx == NULL)  {
         // Create an application specific context
-        appCtx = malloc (sizeof(appPostCtx)); // May place anything here until post->completeCB handle resources liberation
-        appCtx->fd = fd;
+        appCtx = calloc (1, sizeof(appPostCtx)); // May place anything here until post->completeCB handle resources liberation
+        appCtx->path = strdup (filepath);
         
         // attach application to postHandle
-        postHandle->ctx = (void*) appCtx;   // May place anything here until post->completeCB handle resources liberation        
-        postHandle->completeCB = (AFB_apiCB)DonePostForm; // CallBack when Form Processing is finished
+        postHandle->ctx = (void*) appCtx;   // May place anything here until post->completeCB handle resources liberation  
         
-    } else {
-        // this is not the call, FD is already open
-        appCtx = (appPostCtx*) postHandle->ctx;
-    }
+        // Allocate an application specific handle to this post
+        strncpy (filepath, request->config->sessiondir, sizeof(filepath));
+        strncat (filepath, "/", sizeof(filepath));
+        strncat (filepath, item->filename, sizeof(filepath));  
 
-    // We have something to write
-    if (item->len > 0) {
-        
-        if (!write (appCtx->fd, item->data, item->len)) {
-            request->errcode = MHD_HTTP_FORBIDDEN;
-            return (jsonNewMessage(AFB_FAIL,"Fail to write file [%s] at [%s] error=\n", item->filename, strerror(errno)));
-        }
+        if((appCtx->fd = open(filepath, O_RDWR |O_CREAT, S_IRWXU|S_IRGRP)) < 0) {
+            appCtx->jerror= jsonNewMessage(AFB_FAIL,"Fail to Create destination=[%s] error=%s\n", filepath, strerror(errno));
+            goto ExitOnError;
+        } 
+    } else {     
+        // reuse existing application context
+        appCtx = (appPostCtx*) postHandle->ctx;  
+    } 
+
+    // Check we successfully wrote full buffer
+    len = write (appCtx->fd, item->data, item->len);
+    if (item->len != len) {
+        appCtx->jerror= jsonNewMessage(AFB_FAIL,"Fail to write file [%s] at [%s] error=\n", item->filename, strerror(errno));
+        goto ExitOnError;
     }
   
-    // every event should return Sucess or Form processing stop
+    // every intermediary iteration should return Success & NULL
     request->errcode = MHD_HTTP_OK;
     return NULL;
+    
+ExitOnError:    
+    request->errcode = MHD_HTTP_EXPECTATION_FAILED;
+    return NULL;
 }
 
-// This function is call when Client Session Context is removed
-// Note: when freeCtxCB==NULL standard free/malloc is called
-STATIC void clientContextFree(AFB_clientCtx *client) {
-    fprintf (stderr,"Plugin[%s] Closing Session uuid=[%s]\n", client->plugin->prefix, client->uuid);
-    free (client->ctx);
-}
 
+// NOTE: this sample does not use session to keep test a basic as possible
+//       in real application upload-xxx should be protected with AFB_SESSION_CHECK
 STATIC  AFB_restapi pluginApis[]= {
-  {"ping"   , AFB_SESSION_NONE  , (AFB_apiCB)apiPingTest         ,"Ping Rest Test Service"},
-  {"upload" , AFB_SESSION_NONE  , (AFB_apiCB)ProcessPostForm     ,"Demo for file upload"},
+  {"ping"         , AFB_SESSION_NONE  , (AFB_apiCB)apiPingTest    ,"Ping Rest Test Service"},
+  {"upload-json"  , AFB_SESSION_NONE  , (AFB_apiCB)GetJsonByPost  ,"Demo for Json Buffer on Post"},
+  {"upload-image" , AFB_SESSION_NONE  , (AFB_apiCB)UploadFile     ,"Demo for file upload"},
+  {"upload-music" , AFB_SESSION_NONE  , (AFB_apiCB)UploadFile     ,"Demo for file upload"},
+  {"upload-appli" , AFB_SESSION_NONE  , (AFB_apiCB)UploadFile     ,"Demo for file upload"},
   {NULL}
 };
 
-PUBLIC AFB_plugin *afsvRegister () {
+PUBLIC AFB_plugin *samplePostRegister () {
     AFB_plugin *plugin = malloc (sizeof (AFB_plugin));
     plugin->type  = AFB_PLUGIN_JSON; 
     plugin->info  = "Application Framework Binder Service";
     plugin->prefix= "post";  // url base
     plugin->apis  = pluginApis;
     plugin->handle= (void*) "What ever you want";
-    plugin->freeCtxCB= (void*) clientContextFree;
     
     return (plugin);
 };
\ No newline at end of file
index c8a5029..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,7 +92,15 @@ 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) {
@@ -99,13 +108,7 @@ PUBLIC void endPostRequest(AFB_PostHandle *postHandle) {
     }
 
     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);
@@ -256,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);                    
@@ -281,8 +287,7 @@ STATIC AFB_error callPluginApi(AFB_plugin *plugin, AFB_request *request, void *c
             }       
             return (AFB_DONE);
         }
-    }
-    
+    }   
     return (AFB_FAIL);
 }
 
@@ -305,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);
@@ -336,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;
@@ -355,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;
   
@@ -430,7 +432,6 @@ 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);
@@ -454,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");
@@ -485,8 +487,7 @@ PUBLIC int doRestApi(struct MHD_Connection *connection, AFB_session *session, co
             } 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;                
             }   
         }
 
@@ -496,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);
-
                 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
@@ -518,7 +519,13 @@ 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);
@@ -626,10 +633,11 @@ void initPlugins(AFB_session *session) {
     afbJsonType = json_object_new_string (AFB_MSG_JTYPE);
     int i = 0;
 
-    plugins[i++] = tokenRegister(session),
-    plugins[i++] = helloWorldRegister(session),
+    plugins[i++] = tokenRegister(session);
+    plugins[i++] = helloWorldRegister(session);
+    plugins[i++] = samplePostRegister(session);
 #ifdef HAVE_AUDIO_PLUGIN
-    plugins[i++] = audioRegister(session),
+    plugins[i++] = audioRegister(session);
 #endif
 #ifdef HAVE_RADIO_PLUGIN
     plugins[i++] = radioRegister(session),