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/>.
18 * Contain all generic part to handle REST/API
22 #include <microhttpd.h>
24 #include "../include/local-def.h"
26 // proto missing from GCC
27 char *strcasestr(const char *haystack, const char *needle);
30 // Because of POST call multiple time requestApi we need to free POST handle here
31 STATIC void endRequest(void *cls, struct MHD_Connection *connection, void **con_cls, enum MHD_RequestTerminationCode toe) {
32 AFB_HttpPost *posthandle = *con_cls;
34 // if post handle was used let's free everything
36 if (verbose) fprintf(stderr, "End Post Request UID=%d\n", posthandle->uid);
37 free(posthandle->data);
43 PUBLIC json_object* pingSample (AFB_plugin *plugin, AFB_session *session, AFB_request *post) {
45 json_object *response;
46 response = jsonNewMessage(AFB_SUCCESS, "Ping Binder Daemon %d", pingcount++);
47 if (verbose) fprintf(stderr, "%d: \n", pingcount);
51 // Check of apiurl is declare in this plugin and call it
52 STATIC json_object * callPluginApi (AFB_plugin *plugin, AFB_session *session, AFB_request *request) {
53 json_object *response;
56 // If a plugin hold this urlpath call its callback
57 for (idx=0; plugin->apis[idx].callback != NULL; idx++) {
58 if (!strcmp (plugin->apis[idx].name, request->api)) {
59 response = plugin->apis[idx].callback (session, request);
60 if (response != NULL) {
61 json_object_object_add (response, "jtype" ,plugin->jtype);
70 // process rest API query
71 PUBLIC int doRestApi(struct MHD_Connection *connection, AFB_session *session, const char *method, const char* url) {
73 char *baseurl, *baseapi, *urlcpy;
74 json_object *jsonResponse, *errMessage;
75 struct MHD_Response *webResponse;
76 const char *serialized, parsedurl;
80 // Extract plugin urlpath from request
82 baseurl = strsep(&urlcpy, "/");
83 if (baseurl == NULL) {
84 errMessage = jsonNewMessage(AFB_FATAL, "Invalid Plugin/API call url=%s", url);
88 baseapi = strsep(&urlcpy, "/");
89 if (baseapi == NULL) {
90 errMessage = jsonNewMessage(AFB_FATAL, "Invalid Plugin/API call url=%s/%s", baseurl, url);
94 // build request structure
95 memset (&request, 0, sizeof (request));
96 request.connection = connection;
98 request.plugin = baseurl;
99 request.api = baseapi;
101 // if post wait as data may come in multiple calls
102 if (0 == strcmp (method, MHD_HTTP_METHOD_POST)) {
104 request.post="TO Be DONE";
109 // Search for a plugin with this urlpath
110 for (idx=0; session->plugins[idx] != NULL; idx++) {
111 if (!strcmp (session->plugins[idx]->prefix, baseurl)) {
112 jsonResponse = callPluginApi (session->plugins[idx], session, &request );
116 errMessage = jsonNewMessage(AFB_FATAL, "No Plugin for %s", baseurl);
122 // plugin callback did not return a valid Json Object
123 if (jsonResponse == NULL) {
124 errMessage = jsonNewMessage(AFB_FATAL, "No Plugin/API for %s/%s", baseurl, baseapi);
128 serialized = json_object_to_json_string(jsonResponse);
129 webResponse = MHD_create_response_from_buffer(strlen(serialized), (void*) serialized, MHD_RESPMEM_MUST_COPY);
131 ret = MHD_queue_response(connection, MHD_HTTP_OK, webResponse);
132 MHD_destroy_response(webResponse);
133 json_object_put(jsonResponse); // decrease reference rqtcount to free the json object
137 serialized = json_object_to_json_string(errMessage);
138 webResponse = MHD_create_response_from_buffer(strlen(serialized), (void*) serialized, MHD_RESPMEM_MUST_COPY);
139 ret = MHD_queue_response(connection, MHD_HTTP_BAD_REQUEST, webResponse);
140 MHD_destroy_response(webResponse);
141 json_object_put(errMessage); // decrease reference rqtcount to free the json object
145 // Helper to retreive argument from connection
146 PUBLIC const char* getQueryValue (AFB_request * request, char *name) {
149 value=MHD_lookup_connection_value(request->connection, MHD_GET_ARGUMENT_KIND, name);
154 void *initPlugins (AFB_session *session) {
155 static AFB_plugin *plugins[10]; // no more than 10 plugins !!!
159 // simulate dynamic library load for plugins
160 // need to implement mods argument to activate only requested mods
163 // Minimal check before accepting a new plugin
164 plugin = afsvRegister (session);
165 if (plugin->type != AFB_PLUGIN) {
166 fprintf (stderr, "ERROR: AFSV plugin invalid type=%d!=%d\n", plugin->type, AFB_PLUGIN);
168 // Prepare Plugin name to be added to API response
169 plugin->jtype = json_object_new_string (plugin->prefix);
170 json_object_get (plugin->jtype); // increase reference count to make it permanent
171 plugins[idx++]= plugin;
174 session->plugins= plugins;