/*
- * Copyright (C) 2016, 2017 "IoT.bzh"
+ * Copyright (C) 2016-2019 "IoT.bzh"
* Author: José Bollo <jose.bollo@iot.bzh>
*
* Licensed under the Apache License, Version 2.0 (the "License");
#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>
#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"
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
};
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);
}
}
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
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) {
}
afb_context_disconnect(&hreq->xreq.context);
json_object_put(hreq->json);
- free((char*)hreq->xreq.api);
- free((char*)hreq->xreq.verb);
+ free((char*)hreq->xreq.request.called_api);
+ free((char*)hreq->xreq.request.called_verb);
afb_cred_unref(hreq->xreq.cred);
free(hreq);
}
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.api = strndup(api, lenapi);
- hreq->xreq.verb = strndup(verb, lenverb);
- if (hreq->xreq.api == NULL || hreq->xreq.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) {