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 );
117 // No plugin was found
118 if (session->plugins[idx] == NULL) {
119 errMessage = jsonNewMessage(AFB_FATAL, "No Plugin for %s", baseurl);
124 // plugin callback did not return a valid Json Object
125 if (jsonResponse == NULL) {
126 errMessage = jsonNewMessage(AFB_FATAL, "No Plugin/API for %s/%s", baseurl, baseapi);
130 serialized = json_object_to_json_string(jsonResponse);
131 webResponse = MHD_create_response_from_buffer(strlen(serialized), (void*) serialized, MHD_RESPMEM_MUST_COPY);
133 ret = MHD_queue_response(connection, MHD_HTTP_OK, webResponse);
134 MHD_destroy_response(webResponse);
135 json_object_put(jsonResponse); // decrease reference rqtcount to free the json object
139 serialized = json_object_to_json_string(errMessage);
140 webResponse = MHD_create_response_from_buffer(strlen(serialized), (void*) serialized, MHD_RESPMEM_MUST_COPY);
141 ret = MHD_queue_response(connection, MHD_HTTP_BAD_REQUEST, webResponse);
142 MHD_destroy_response(webResponse);
143 json_object_put(errMessage); // decrease reference rqtcount to free the json object
147 // Helper to retreive argument from connection
148 PUBLIC const char* getQueryValue (AFB_request * request, char *name) {
151 value=MHD_lookup_connection_value(request->connection, MHD_GET_ARGUMENT_KIND, name);
155 // Loop on plugins. Check that they have the right type, prepare a JSON object with prefix
156 STATIC AFB_plugin ** RegisterPlugins(AFB_plugin **plugins) {
159 for (idx=0; plugins[idx] != NULL; idx++) {
160 if (plugins[idx]->type != AFB_PLUGIN) {
161 fprintf (stderr, "ERROR: AFSV plugin[%d] invalid type=%d != %d\n", idx, AFB_PLUGIN, plugins[idx]->type);
163 // some sanity controls
164 if ((plugins[idx]->prefix == NULL) || (plugins[idx]->info == NULL) || (plugins[idx]->apis == NULL)){
165 if (plugins[idx]->prefix == NULL) plugins[idx]->prefix = "No URL prefix for APIs";
166 if (plugins[idx]->info == NULL) plugins[idx]->info = "No Info describing plugin APIs";
167 fprintf (stderr, "ERROR: plugin[%d] invalid prefix=%s info=%s", idx,plugins[idx]->prefix, plugins[idx]->info);
171 if (verbose) fprintf (stderr, "Loading plugin[%d] prefix=[%s] info=%s\n", idx, plugins[idx]->prefix, plugins[idx]->info);
173 // Prepare Plugin name to be added into each API response
174 plugins[idx]->jtype = json_object_new_string (plugins[idx]->prefix);
175 json_object_get (plugins[idx]->jtype); // increase reference count to make it permanent
177 // compute urlprefix lenght
178 plugins[idx]->prefixlen = strlen (plugins[idx]->prefix);
184 void initPlugins (AFB_session *session) {
185 static AFB_plugin *plugins[10];
187 plugins[0]= afsvRegister (session),
188 plugins[1]= dbusRegister (session),
189 plugins[2]= alsaRegister (session),
192 // complete plugins and save them within current sessions
193 session->plugins= RegisterPlugins (plugins);