2 * Copyright (C) 2015 "IoT.bzh"
3 * Author "Fulup Ar Foll"
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "local-def.h"
23 // In this case or handle is quite basic
30 // With content-type=json data are directly avaliable in request->post->data
31 STATIC json_object* GetJsonByPost (AFB_request *request) {
36 // check if we have some post data
37 if (request->post == NULL) request->post->data="NoData";
39 // Get all query string [Note real app should probably use value=getQueryValue(request,"key")]
40 len = getQueryAll (request, query, sizeof(query));
41 if (len == 0) strncpy (query, "NoSearchQueryList", sizeof(query));
43 // for debug/test return response to caller
44 jresp = jsonNewMessage(AFB_SUCCESS, "GetJsonByPost query={%s} PostData: [%s]", query, request->post->data);
49 // This function is call when PostForm processing is completed
50 STATIC void DonePostForm (AFB_request *request) {
52 // Retrieve PostHandle Context from request
53 AFB_PostHandle *postHandle = getPostHandle(request);
54 appPostCtx *appCtx= (appPostCtx*) postHandle->ctx;
56 if (verbose) fprintf (stderr, "DonePostForm file=[%s]upload done\n", appCtx->path);
62 // PostForm callback is called multiple times (one or each key within form, or once per file buffer)
63 // When processing POST_FORM request->data holds a PostHandle and not data directly as for POST_JSON
64 // When file has been fully uploaded call is call with item==NULL it is application responsibility to free appPostCtx
65 STATIC json_object* UploadFile (AFB_request *request, AFB_PostItem *item) {
67 AFB_PostHandle *postHandle = getPostHandle(request);
72 // This is called after PostForm and then after DonePostForm
75 appCtx = (appPostCtx*) postHandle->ctx;
77 // No Post Application Context [something really bad happen]
79 request->errcode = MHD_HTTP_EXPECTATION_FAILED;
80 return(jsonNewMessage(AFB_FAIL,"Error: PostForm no PostContext to free\n"));
83 // We have a context but last Xform iteration fail.
84 if (appCtx->jerror != NULL) {
85 request->errcode = MHD_HTTP_EXPECTATION_FAILED;
86 jresp = appCtx->jerror; // retrieve previous error from postCtx
87 } else jresp = jsonNewMessage(AFB_FAIL,"UploadFile Post Request file=[%s] done", appCtx->path);
89 // Error or not let's free all resources
96 // Make sure it's a valid PostForm request
97 if (!request->post && request->post->type != AFB_POST_FORM) {
98 appCtx->jerror= jsonNewMessage(AFB_FAIL,"This is not a valid PostForm request\n");
102 // Check this is a file element
103 if (item->filename == NULL) {
104 appCtx->jerror= jsonNewMessage(AFB_FAIL,"No Filename attached to key=%s\n", item->key);
108 // Check we got something in buffer
109 if (item->len <= 0) {
110 appCtx->jerror= jsonNewMessage(AFB_FAIL,"Buffer size NULL key=%s]\n", item->key);
114 // Extract Application Context from posthandle [NULL == 1st iteration]
115 appCtx = (appPostCtx*) postHandle->ctx;
117 // This is the 1st Item iteration let's open output file and allocate necessary resources
118 if (appCtx == NULL) {
119 // Create an application specific context
120 appCtx = calloc (1, sizeof(appPostCtx)); // May place anything here until post->completeCB handle resources liberation
121 appCtx->path = strdup (filepath);
123 // attach application to postHandle
124 postHandle->ctx = (void*) appCtx; // May place anything here until post->completeCB handle resources liberation
126 // Allocate an application specific handle to this post
127 strncpy (filepath, request->config->sessiondir, sizeof(filepath));
128 strncat (filepath, "/", sizeof(filepath));
129 strncat (filepath, item->filename, sizeof(filepath));
131 if((appCtx->fd = open(filepath, O_RDWR |O_CREAT, S_IRWXU|S_IRGRP)) < 0) {
132 appCtx->jerror= jsonNewMessage(AFB_FAIL,"Fail to Create destination=[%s] error=%s\n", filepath, strerror(errno));
136 // reuse existing application context
137 appCtx = (appPostCtx*) postHandle->ctx;
140 // Check we successfully wrote full buffer
141 len = write (appCtx->fd, item->data, item->len);
142 if (item->len != len) {
143 appCtx->jerror= jsonNewMessage(AFB_FAIL,"Fail to write file [%s] at [%s] error=\n", item->filename, strerror(errno));
147 // every intermediary iteration should return Success & NULL
148 request->errcode = MHD_HTTP_OK;
152 request->errcode = MHD_HTTP_EXPECTATION_FAILED;
157 // NOTE: this sample does not use session to keep test a basic as possible
158 // in real application upload-xxx should be protected with AFB_SESSION_CHECK
159 STATIC AFB_restapi pluginApis[]= {
160 {"ping" , AFB_SESSION_NONE , (AFB_apiCB)apiPingTest ,"Ping Rest Test Service"},
161 {"upload-json" , AFB_SESSION_NONE , (AFB_apiCB)GetJsonByPost ,"Demo for Json Buffer on Post"},
162 {"upload-image" , AFB_SESSION_NONE , (AFB_apiCB)UploadFile ,"Demo for file upload"},
163 {"upload-music" , AFB_SESSION_NONE , (AFB_apiCB)UploadFile ,"Demo for file upload"},
164 {"upload-appli" , AFB_SESSION_NONE , (AFB_apiCB)UploadFile ,"Demo for file upload"},
168 PUBLIC AFB_plugin *pluginRegister () {
169 AFB_plugin *plugin = malloc (sizeof (AFB_plugin));
170 plugin->type = AFB_PLUGIN_JSON;
171 plugin->info = "Application Framework Binder Service";
172 plugin->prefix= "post"; // url base
173 plugin->apis = pluginApis;
174 plugin->handle= (void*) "What ever you want";