+ va_list args;
+ va_start(args, buffer);
+ afb_hreq_reply_v(hreq, status, MHD_create_response_from_buffer((unsigned)size, buffer, MHD_RESPMEM_MUST_FREE), args);
+ va_end(args);
+}
+
+#if defined(USE_MAGIC_MIME_TYPE)
+
+#if !defined(MAGIC_DB)
+#define MAGIC_DB "/usr/share/misc/magic.mgc"
+#endif
+
+static magic_t lazy_libmagic()
+{
+ static int done = 0;
+ static magic_t result = NULL;
+
+ if (!done) {
+ done = 1;
+ /* MAGIC_MIME tells magic to return a mime of the file,
+ but you can specify different things */
+ INFO("Loading mimetype default magic database");
+ result = magic_open(MAGIC_MIME_TYPE);
+ if (result == NULL) {
+ ERROR("unable to initialize magic library");
+ }
+ /* Warning: should not use NULL for DB
+ [libmagic bug wont pass efence check] */
+ else if (magic_load(result, MAGIC_DB) != 0) {
+ ERROR("cannot load magic database: %s", magic_error(result));
+ magic_close(result);
+ result = NULL;
+ }
+ }
+
+ return result;
+}
+
+static const char *magic_mimetype_fd(int fd)
+{
+ magic_t lib = lazy_libmagic();
+ return lib ? magic_descriptor(lib, fd) : NULL;
+}
+
+#endif
+
+static const char *mimetype_fd_name(int fd, const char *filename)
+{
+ const char *result = NULL;
+
+#if defined(INFER_EXTENSION)
+ /*
+ * Set some well-known extensions
+ * Note that it is mandatory for example for css files in order to provide
+ * right mimetype that must be text/css (otherwise chrome browser will not
+ * load correctly css file) while libmagic returns text/plain.
+ */
+ const char *extension = strrchr(filename, '.');
+ if (extension) {
+ static const char *const known[][2] = {
+ /* 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, 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;
+ }
+ if (c < 0)
+ u = i;
+ else
+ l = i + 1;
+ }
+ }
+#endif
+#if defined(USE_MAGIC_MIME_TYPE)
+ if (result == NULL)
+ result = magic_mimetype_fd(fd);
+#endif
+ return result;
+}
+
+static void req_destroy(struct afb_xreq *xreq)
+{
+ struct afb_hreq *hreq = CONTAINER_OF_XREQ(struct afb_hreq, xreq);