New tree organization, update CMake req. to 2.8.8.
[src/app-framework-binder.git] / plugins / session / token-api.c
1 /*
2  * Copyright (C) 2015 "IoT.bzh"
3  * Author "Fulup Ar Foll"
4  *
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.
9  *
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.
14  *
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/>.
17  */
18
19
20 #include "local-def.h"
21
22 // Dummy sample of Client Application Context
23 typedef struct {
24   int  something;       
25   void *whateveryouwant;
26 } MyClientApplicationHandle;
27
28
29 // Request Creation of new context if it does not exist
30 STATIC json_object* clientContextCreate (AFB_request *request) {
31     json_object *jresp;
32
33     // add an application specific client context to session
34     request->client->ctx = malloc (sizeof (MyClientApplicationHandle));
35     
36     // Send response to UI
37     jresp = json_object_new_object();               
38     json_object_object_add(jresp, "token", json_object_new_string ("A New Token and Session Context Was Created"));
39
40     return (jresp);
41 }
42
43 // Before entering here token will be check and renew
44 STATIC json_object* clientContextRefresh (AFB_request *request) {
45     json_object *jresp;
46
47   
48     jresp = json_object_new_object();
49     json_object_object_add(jresp, "token", json_object_new_string ("Token was refreshed"));              
50     
51     return (jresp);
52 }
53
54
55 // Session token will we verified before entering here
56 STATIC json_object* clientContextCheck (AFB_request *request) {
57     
58     json_object *jresp = json_object_new_object();    
59     json_object_object_add(jresp, "isvalid", json_object_new_boolean (TRUE));       
60         
61     return (jresp); 
62 }
63
64
65 // Close and Free context
66 STATIC json_object* clientContextReset (AFB_request *request) {
67     json_object *jresp;
68    
69     jresp = json_object_new_object();
70     json_object_object_add(jresp, "uuid", json_object_new_string (request->client->uuid));              
71     
72     return (jresp); 
73 }
74
75 // In this case or handle is quite basic
76 typedef struct {
77    int fd; 
78 } appPostCtx;
79
80 // This function is call when PostForm processing is completed
81 STATIC void DonePostForm (AFB_request *request) {
82     AFB_PostHandle  *postHandle = (AFB_PostHandle*)request->post->data;
83     appPostCtx *appCtx= postHandle->ctx;
84     
85     // Close upload file ID
86     close (appCtx->fd);
87
88     // Free application specific handle
89     free (postHandle->ctx);
90     
91     if (verbose) fprintf (stderr, "DonePostForm upload done\n");
92 }
93
94
95 // WARNING: PostForm callback are call multiple time (one or each key within form)
96 // When processing POST_JSON request->data hold a PostHandle and not data directly as for POST_JSON
97 STATIC json_object* ProcessPostForm (AFB_request *request, AFB_PostItem *item) {
98
99     AFB_PostHandle  *postHandle;
100     appPostCtx *appCtx;
101     char filepath[512];
102             
103     // When Post is fully processed the same callback is call with a item==NULL
104     if (item == NULL) {
105         // Close file, Free handle
106         
107         request->errcode = MHD_HTTP_OK;
108         return(jsonNewMessage(AFB_SUCCESS,"File [%s] uploaded at [%s] error=\n", item->filename, request->config->sessiondir));  
109     }
110     
111     // Let's make sure this is a valid PostForm request
112     if (!request->post && request->post->type != AFB_POST_FORM) {
113         request->errcode = MHD_HTTP_FORBIDDEN;
114         return(jsonNewMessage(AFB_FAIL,"This is not a valid PostForm request\n"));          
115     } else {
116         // In AFB_POST_FORM case post->data is a PostForm handle
117         postHandle = (AFB_PostHandle*) request->post->data;
118         appCtx = (appPostCtx*) postHandle->ctx;
119     }
120
121     // Check this is a file element
122     if (0 != strcmp (item->key, "file")) {
123         request->errcode = MHD_HTTP_FORBIDDEN;
124         return (jsonNewMessage(AFB_FAIL,"No File within element key=%s\n", item->key));
125     }
126
127     // This is the 1st Item iteration let's open output file and allocate necessary resources
128     if (postHandle->ctx == NULL)  {
129         int fd;
130         
131         strncpy (filepath, request->config->sessiondir, sizeof(filepath));
132         strncat (filepath, "/", sizeof(filepath));
133         strncat (filepath, item->filename, sizeof(filepath));  
134
135         if((fd = open(request->config->sessiondir, O_RDONLY)) < 0) {
136             request->errcode = MHD_HTTP_FORBIDDEN;
137             return (jsonNewMessage(AFB_FAIL,"Fail to Upload file [%s] at [%s] error=\n", item->filename, request->config->sessiondir, strerror(errno)));
138         };            
139
140         // Create an application specific context
141         appCtx = malloc (sizeof(appPostCtx)); // May place anything here until post->completeCB handle resources liberation
142         appCtx->fd = fd;
143         
144         // attach application to postHandle
145         postHandle->ctx = (void*) appCtx;   // May place anything here until post->completeCB handle resources liberation        
146         postHandle->completeCB = (AFB_apiCB)DonePostForm; // CallBack when Form Processing is finished
147         
148     } else {
149         // this is not the call, FD is already open
150         appCtx = (appPostCtx*) postHandle->ctx;
151     }
152
153     // We have something to write
154     if (item->len > 0) {
155         
156         if (!write (appCtx->fd, item->data, item->len)) {
157             request->errcode = MHD_HTTP_FORBIDDEN;
158             return (jsonNewMessage(AFB_FAIL,"Fail to write file [%s] at [%s] error=\n", item->filename, strerror(errno)));
159         }
160     }
161   
162     // every event should return Sucess or Form processing stop
163     request->errcode = MHD_HTTP_OK;
164     return NULL;
165 }
166
167 // This function is call when Client Session Context is removed
168 // Note: when freeCtxCB==NULL standard free/malloc is called
169 STATIC void clientContextFree(AFB_clientCtx *client) {
170     fprintf (stderr,"Plugin[%s] Closing Session uuid=[%s]\n", client->plugin->prefix, client->uuid);
171     free (client->ctx);
172 }
173
174 STATIC  AFB_restapi pluginApis[]= {
175   {"ping"          , AFB_SESSION_NONE  , (AFB_apiCB)apiPingTest         ,"Ping Rest Test Service"},
176   {"token-create"  , AFB_SESSION_CREATE, (AFB_apiCB)clientContextCreate ,"Request Client Context Creation"},
177   {"token-refresh" , AFB_SESSION_RENEW , (AFB_apiCB)clientContextRefresh,"Refresh Client Context Token"},
178   {"token-check"   , AFB_SESSION_CHECK , (AFB_apiCB)clientContextCheck  ,"Check Client Context Token"},
179   {"token-reset"   , AFB_SESSION_CLOSE , (AFB_apiCB)clientContextReset  ,"Close Client Context and Free resources"},
180   {"file-upload"   , AFB_SESSION_NONE  , (AFB_apiCB)ProcessPostForm     ,"Demo for file upload"},
181   {NULL}
182 };
183
184 PUBLIC AFB_plugin *afsvRegister () {
185     AFB_plugin *plugin = malloc (sizeof (AFB_plugin));
186     plugin->type  = AFB_PLUGIN_JSON; 
187     plugin->info  = "Application Framework Binder Service";
188     plugin->prefix= "afbs";  // url base
189     plugin->apis  = pluginApis;
190     plugin->handle= (void*) "What ever you want";
191     plugin->freeCtxCB= (void*) clientContextFree;
192     
193     return (plugin);
194 };