Fedora 30 packaging fix issu
[src/app-framework-binder.git] / src / afb-hreq.c
index cdc9f23..495bf06 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016, 2017 "IoT.bzh"
+ * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
  * Author: José Bollo <jose.bollo@iot.bzh>
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,6 +27,9 @@
 
 #include <microhttpd.h>
 #include <json-c/json.h>
+#if !defined(JSON_C_TO_STRING_NOSLASHESCAPE)
+#define JSON_C_TO_STRING_NOSLASHESCAPE 0
+#endif
 
 #if defined(USE_MAGIC_MIME_TYPE)
 #include <magic.h>
@@ -36,6 +39,7 @@
 #include "afb-msg-json.h"
 #include "afb-context.h"
 #include "afb-hreq.h"
+#include "afb-hsrv.h"
 #include "afb-session.h"
 #include "afb-cred.h"
 #include "verbose.h"
@@ -73,15 +77,13 @@ struct hreq_data {
 
 static struct json_object *req_json(struct afb_xreq *xreq);
 static struct afb_arg req_get(struct afb_xreq *xreq, const char *name);
-static void req_fail(struct afb_xreq *xreq, const char *status, const char *info);
-static void req_success(struct afb_xreq *xreq, json_object *obj, const char *info);
+static void req_reply(struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info);
 static void req_destroy(struct afb_xreq *xreq);
 
 const struct afb_xreq_query_itf afb_hreq_xreq_query_itf = {
        .json = req_json,
        .get = req_get,
-       .success = req_success,
-       .fail = req_fail,
+       .reply = req_reply,
        .unref = req_destroy
 };
 
@@ -170,10 +172,9 @@ static void afb_hreq_reply_v(struct afb_hreq *hreq, unsigned status, struct MHD_
 
        hreq->replied = 1;
        if (hreq->suspended != 0) {
-               extern void run_micro_httpd(struct afb_hsrv *hsrv);
                MHD_resume_connection (hreq->connection);
                hreq->suspended = 0;
-               run_micro_httpd(hreq->hsrv);
+               afb_hsrv_run(hreq->hsrv);
        }
 }
 
@@ -271,22 +272,38 @@ static const char *mimetype_fd_name(int fd, const char *filename)
        const char *extension = strrchr(filename, '.');
        if (extension) {
                static const char *const known[][2] = {
-                       { ".js",   "text/javascript" },
-                       { ".html", "text/html" },
-                       { ".css",  "text/css" },
-                       { ".ico",  "image/x-icon"},
-                       { ".png",  "image/png" },
-                       { ".svg",  "image/svg+xml" },
-                       { ".ttf",  "application/x-font-ttf"},
-                       { NULL, NULL }
+                       /* keep it sorted for dichotomic search */
+                       { ".css",       "text/css" },
+                       { ".gif",       "image/gif" },
+                       { ".html",      "text/html" },
+                       { ".htm",       "text/html" },
+                       { ".ico",       "image/x-icon"},
+                       { ".jpeg",      "image/jpeg" },
+                       { ".jpg",       "image/jpeg" },
+                       { ".js",        "text/javascript" },
+                       { ".json",      "application/json" },
+                       { ".mp3",       "audio/mpeg" },
+                       { ".png",       "image/png" },
+                       { ".svg",       "image/svg+xml" },
+                       { ".ttf",       "application/x-font-ttf"},
+                       { ".txt",       "text/plain" },
+                       { ".wav",       "audio/x-wav" },
+                       { ".xht",       "application/xhtml+xml" },
+                       { ".xhtml",     "application/xhtml+xml" },
+                       { ".xml",       "application/xml" }
                };
-               int i = 0;
-               while (known[i][0]) {
-                       if (!strcasecmp(extension, known[i][0])) {
+               int i, c, l = 0, u = sizeof known / sizeof *known;
+               while (l < u) {
+                       i = (l + u) >> 1;
+                       c = strcasecmp(extension, known[i][0]);
+                       if (!c) {
                                result = known[i][1];
                                break;
                        }
-                       i++;
+                       if (c < 0)
+                               u = i;
+                       else
+                               l = i + 1;
                }
        }
 #endif
@@ -304,6 +321,9 @@ static void req_destroy(struct afb_xreq *xreq)
 
        if (hreq->postform != NULL)
                MHD_destroy_post_processor(hreq->postform);
+       if (hreq->tokener != NULL)
+               json_tokener_free(hreq->tokener);
+
        for (data = hreq->data; data; data = hreq->data) {
                hreq->data = data->next;
                if (data->path) {
@@ -316,8 +336,8 @@ static void req_destroy(struct afb_xreq *xreq)
        }
        afb_context_disconnect(&hreq->xreq.context);
        json_object_put(hreq->json);
-       free((char*)hreq->xreq.request.api);
-       free((char*)hreq->xreq.request.verb);
+       free((char*)hreq->xreq.request.called_api);
+       free((char*)hreq->xreq.request.called_verb);
        afb_cred_unref(hreq->xreq.cred);
        free(hreq);
 }
@@ -880,43 +900,36 @@ static struct json_object *req_json(struct afb_xreq *xreq)
 
 static ssize_t send_json_cb(json_object *obj, uint64_t pos, char *buf, size_t max)
 {
-       ssize_t len = stpncpy(buf, json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PLAIN)+pos, max) - buf;
+       ssize_t len = stpncpy(buf, json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PLAIN|JSON_C_TO_STRING_NOSLASHESCAPE)+pos, max) - buf;
        return len ? : (ssize_t)MHD_CONTENT_READER_END_OF_STREAM;
 }
 
-static void req_reply(struct afb_hreq *hreq, unsigned retcode, const char *status, const char *info, json_object *resp)
+static void req_reply(struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info)
 {
-       struct json_object *reply;
+       struct afb_hreq *hreq = CONTAINER_OF_XREQ(struct afb_hreq, xreq);
+       struct json_object *sub, *reply;
        const char *reqid;
        struct MHD_Response *response;
 
+       /* create the reply */
+       reply = afb_msg_json_reply(object, error, info, &xreq->context);
+
+       /* append the req id on need */
        reqid = afb_hreq_get_argument(hreq, long_key_for_reqid);
        if (reqid == NULL)
                reqid = afb_hreq_get_argument(hreq, short_key_for_reqid);
+       if (reqid != NULL && json_object_object_get_ex(reply, "request", &sub))
+               json_object_object_add(sub, "reqid", json_object_new_string(reqid));
 
-       reply = afb_msg_json_reply(status, info, resp, &hreq->xreq.context, reqid);
-
-       response = MHD_create_response_from_callback((uint64_t)strlen(json_object_to_json_string_ext(reply, JSON_C_TO_STRING_PLAIN)), SIZE_RESPONSE_BUFFER, (void*)send_json_cb, reply, (void*)json_object_put);
-       afb_hreq_reply(hreq, retcode, response, NULL);
-}
-
-static void req_fail(struct afb_xreq *xreq, const char *status, const char *info)
-{
-       struct afb_hreq *hreq = CONTAINER_OF_XREQ(struct afb_hreq, xreq);
-       req_reply(hreq, MHD_HTTP_OK, status, info, NULL);
-}
-
-static void req_success(struct afb_xreq *xreq, json_object *obj, const char *info)
-{
-       struct afb_hreq *hreq = CONTAINER_OF_XREQ(struct afb_hreq, xreq);
-       req_reply(hreq, MHD_HTTP_OK, "success", info, obj);
+       response = MHD_create_response_from_callback((uint64_t)strlen(json_object_to_json_string_ext(reply, JSON_C_TO_STRING_PLAIN|JSON_C_TO_STRING_NOSLASHESCAPE)), SIZE_RESPONSE_BUFFER, (void*)send_json_cb, reply, (void*)json_object_put);
+       afb_hreq_reply(hreq, MHD_HTTP_OK, response, NULL);
 }
 
 void afb_hreq_call(struct afb_hreq *hreq, struct afb_apiset *apiset, const char *api, size_t lenapi, const char *verb, size_t lenverb)
 {
-       hreq->xreq.request.api = strndup(api, lenapi);
-       hreq->xreq.request.verb = strndup(verb, lenverb);
-       if (hreq->xreq.request.api == NULL || hreq->xreq.request.verb == NULL) {
+       hreq->xreq.request.called_api = strndup(api, lenapi);
+       hreq->xreq.request.called_verb = strndup(verb, lenverb);
+       if (hreq->xreq.request.called_api == NULL || hreq->xreq.request.called_verb == NULL) {
                ERROR("Out of memory");
                afb_hreq_reply_error(hreq, MHD_HTTP_INTERNAL_SERVER_ERROR);
        } else if (afb_hreq_init_context(hreq) < 0) {