#include "local-def.h"
#include "afb-method.h"
#include "afb-hreq.h"
+#include "afb-hsrv.h"
#include "afb-websock.h"
#include "afb-apis.h"
#include "afb-req-itf.h"
int dirfd;
};
-static struct upoll *upoll = NULL;
+struct afb_hsrv {
+ unsigned refcount;
+ struct afb_hsrv_handler *handlers;
+ struct MHD_Daemon *httpd;
+ struct upoll *upoll;
+ char *cache_to;
+};
-int afb_hreq_one_page_api_redirect(
- struct afb_hreq *hreq,
- void *data)
-{
- size_t plen;
- char *url;
- if (hreq->lentail >= 2 && hreq->tail[1] == '#')
- return 0;
- /*
- * Here we have for example:
- * url = "/pre/dir/page" lenurl = 13
- * tail = "/dir/page" lentail = 9
- *
- * We will produce "/pre/#!dir/page"
- *
- * Let compute plen that include the / at end (for "/pre/")
- */
- plen = hreq->lenurl - hreq->lentail + 1;
- url = alloca(hreq->lenurl + 3);
- memcpy(url, hreq->url, plen);
- url[plen++] = '#';
- url[plen++] = '!';
- memcpy(&url[plen], &hreq->tail[1], hreq->lentail);
- return afb_hreq_redirect_to(hreq, url);
-}
static struct afb_hsrv_handler *new_handler(
struct afb_hsrv_handler *head,
}
int afb_hsrv_add_handler(
- AFB_session * session,
+ struct afb_hsrv *hsrv,
const char *prefix,
int (*handler) (struct afb_hreq *, void *),
void *data,
{
struct afb_hsrv_handler *head;
- head = new_handler(session->handlers, prefix, handler, data, priority);
+ head = new_handler(hsrv->handlers, prefix, handler, data, priority);
if (head == NULL)
return 0;
- session->handlers = head;
+ hsrv->handlers = head;
return 1;
}
+int afb_hreq_one_page_api_redirect(
+ struct afb_hreq *hreq,
+ void *data)
+{
+ size_t plen;
+ char *url;
+
+ if (hreq->lentail >= 2 && hreq->tail[1] == '#')
+ return 0;
+ /*
+ * Here we have for example:
+ * url = "/pre/dir/page" lenurl = 13
+ * tail = "/dir/page" lentail = 9
+ *
+ * We will produce "/pre/#!dir/page"
+ *
+ * Let compute plen that include the / at end (for "/pre/")
+ */
+ plen = hreq->lenurl - hreq->lentail + 1;
+ url = alloca(hreq->lenurl + 3);
+ memcpy(url, hreq->url, plen);
+ url[plen++] = '#';
+ url[plen++] = '!';
+ memcpy(&url[plen], &hreq->tail[1], hreq->lentail);
+ return afb_hreq_redirect_to(hreq, url);
+}
+
static int afb_hreq_websocket_switch(struct afb_hreq *hreq, void *data)
{
int later;
return 0;
if (!later) {
- struct afb_websock *ws = afb_websock_create(hreq->connection);
- if (ws == NULL) {
- /* TODO */
- } else {
- /* TODO */
- }
+ struct afb_websock *ws = afb_websock_create(hreq);
+ if (ws != NULL)
+ hreq->upgrade = 1;
}
return 1;
}
return afb_hreq_reply_file(hreq, da->dirfd, &hreq->tail[1]);
}
-int afb_hsrv_add_alias(AFB_session * session, const char *prefix, const char *alias, int priority)
+int afb_hsrv_add_alias(struct afb_hsrv *hsrv, const char *prefix, const char *alias, int priority)
{
struct afb_diralias *da;
int dirfd;
da->directory = alias;
da->lendir = strlen(da->directory);
da->dirfd = dirfd;
- if (afb_hsrv_add_handler(session, prefix, handle_alias, da, priority))
+ if (afb_hsrv_add_handler(hsrv, prefix, handle_alias, da, priority))
return 1;
free(da);
}
return 0;
}
-void afb_hsrv_reply_error(struct MHD_Connection *connection, unsigned int status)
+static void reply_error(struct MHD_Connection *connection, unsigned int status)
{
char *buffer;
int length;
int rc;
struct afb_hreq *hreq;
enum afb_method method;
- AFB_session *session;
+ struct afb_hsrv *hsrv;
struct afb_hsrv_handler *iter;
const char *type;
- session = cls;
+ hsrv = cls;
hreq = *recordreq;
if (hreq == NULL) {
/* create the request */
goto bad_request;
/* init the request */
- hreq->session = cls;
+ hreq->cacheTimeout = hsrv->cache_to;
hreq->connection = connection;
hreq->method = method;
hreq->version = version;
hreq->postform = MHD_create_post_processor (connection, 65500, postproc, hreq);
if (hreq->postform == NULL)
goto internal_error;
+ return MHD_YES;
} else if (strcasestr(type, JSON_CONTENT) == NULL) {
- afb_hsrv_reply_error(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE);
+ reply_error(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE);
return MHD_YES;
}
}
}
/* flush the data */
- afb_hreq_post_end(hreq);
if (hreq->postform != NULL) {
rc = MHD_destroy_post_processor(hreq->postform);
hreq->postform = NULL;
}
/* search an handler for the request */
- iter = session->handlers;
+ iter = hsrv->handlers;
while (iter) {
if (afb_hreq_unprefix(hreq, iter->prefix, iter->length)) {
if (iter->handler(hreq, iter->data))
return MHD_YES;
bad_request:
- afb_hsrv_reply_error(connection, MHD_HTTP_BAD_REQUEST);
+ reply_error(connection, MHD_HTTP_BAD_REQUEST);
return MHD_YES;
internal_error:
- afb_hsrv_reply_error(connection, MHD_HTTP_INTERNAL_SERVER_ERROR);
+ reply_error(connection, MHD_HTTP_INTERNAL_SERVER_ERROR);
return MHD_YES;
}
struct afb_hreq *hreq;
hreq = *recordreq;
-
+ if (hreq->upgrade)
+ MHD_suspend_connection (connection);
afb_hreq_free(hreq);
}
return MHD_YES;
}
-#if defined(USE_MAGIC_MIME_TYPE)
+/* infinite loop */
+static void hsrv_handle_event(struct MHD_Daemon *httpd)
+{
+ MHD_run(httpd);
+}
+
+int afb_hsrv_set_cache_timeout(struct afb_hsrv *hsrv, int duration)
+{
+ int rc;
+ char *dur;
-#if !defined(MAGIC_DB)
-#define MAGIC_DB "/usr/share/misc/magic.mgc"
-#endif
+ rc = asprintf(&dur, "%d", duration);
+ if (rc < 0)
+ return 0;
-static int init_lib_magic (AFB_session *session)
+ free(hsrv->cache_to);
+ hsrv->cache_to = dur;
+ return 1;
+}
+
+int _afb_hsrv_start(struct afb_hsrv *hsrv, uint16_t port, unsigned int connection_timeout)
{
- /* MAGIC_MIME tells magic to return a mime of the file, but you can specify different things */
- if (verbosity)
- printf("Loading mimetype default magic database\n");
+ struct upoll *upoll;
+ struct MHD_Daemon *httpd;
+ const union MHD_DaemonInfo *info;
+
+ httpd = MHD_start_daemon(
+ MHD_USE_EPOLL_LINUX_ONLY | MHD_USE_TCP_FASTOPEN | MHD_USE_DEBUG | MHD_USE_SUSPEND_RESUME,
+ port, /* port */
+ new_client_handler, NULL, /* Tcp Accept call back + extra attribute */
+ access_handler, hsrv, /* Http Request Call back + extra attribute */
+ MHD_OPTION_NOTIFY_COMPLETED, end_handler, hsrv,
+ MHD_OPTION_CONNECTION_TIMEOUT, connection_timeout,
+ MHD_OPTION_END); /* options-end */
- session->magic = magic_open(MAGIC_MIME_TYPE);
- if (session->magic == NULL) {
- fprintf(stderr,"ERROR: unable to initialize magic library\n");
+ if (httpd == NULL) {
+ printf("Error: httpStart invalid httpd port: %d", (int)port);
+ return 0;
+ }
+
+ info = MHD_get_daemon_info(httpd, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
+ if (info == NULL) {
+ MHD_stop_daemon(httpd);
+ fprintf(stderr, "Error: httpStart no pollfd");
return 0;
}
- /* Warning: should not use NULL for DB [libmagic bug wont pass efence check] */
- if (magic_load(session->magic, MAGIC_DB) != 0) {
- fprintf(stderr,"cannot load magic database - %s\n", magic_error(session->magic));
- magic_close(session->magic);
- session->magic = NULL;
+ upoll = upoll_open(info->listen_fd, httpd);
+ if (upoll == NULL) {
+ MHD_stop_daemon(httpd);
+ fprintf(stderr, "Error: connection to upoll of httpd failed");
return 0;
}
+ upoll_on_readable(upoll, (void*)hsrv_handle_event);
+ hsrv->httpd = httpd;
+ hsrv->upoll = upoll;
return 1;
}
-#endif
-static int my_default_init(AFB_session * session)
+void _afb_hsrv_stop(struct afb_hsrv *hsrv)
+{
+ if (hsrv->upoll)
+ upoll_close(hsrv->upoll);
+ hsrv->upoll = NULL;
+ if (hsrv->httpd != NULL)
+ MHD_stop_daemon(hsrv->httpd);
+ hsrv->httpd = NULL;
+}
+
+struct afb_hsrv *afb_hsrv_create()
+{
+ struct afb_hsrv *result = calloc(1, sizeof(struct afb_hsrv));
+ if (result != NULL)
+ result->refcount = 1;
+ return result;
+}
+
+void afb_hsrv_put(struct afb_hsrv *hsrv)
+{
+ assert(hsrv->refcount != 0);
+ if (!--hsrv->refcount) {
+ _afb_hsrv_stop(hsrv);
+ free(hsrv);
+ }
+}
+
+static int my_default_init(struct afb_hsrv *hsrv, AFB_session * session)
{
int idx;
- if (!afb_hsrv_add_handler(session, session->config->rootapi, afb_hreq_websocket_switch, NULL, 20))
+ if (!afb_hsrv_add_handler(hsrv, session->config->rootapi, afb_hreq_websocket_switch, NULL, 20))
return 0;
- if (!afb_hsrv_add_handler(session, session->config->rootapi, afb_hreq_rest_api, NULL, 10))
+ if (!afb_hsrv_add_handler(hsrv, session->config->rootapi, afb_hreq_rest_api, NULL, 10))
return 0;
for (idx = 0; session->config->aliasdir[idx].url != NULL; idx++)
- if (!afb_hsrv_add_alias (session, session->config->aliasdir[idx].url, session->config->aliasdir[idx].path, 0))
+ if (!afb_hsrv_add_alias (hsrv, session->config->aliasdir[idx].url, session->config->aliasdir[idx].path, 0))
return 0;
- if (!afb_hsrv_add_alias(session, "", session->config->rootdir, -10))
+ if (!afb_hsrv_add_alias(hsrv, "", session->config->rootdir, -10))
return 0;
- if (!afb_hsrv_add_handler(session, session->config->rootbase, afb_hreq_one_page_api_redirect, NULL, -20))
+ if (!afb_hsrv_add_handler(hsrv, session->config->rootbase, afb_hreq_one_page_api_redirect, NULL, -20))
return 0;
-#if defined(USE_MAGIC_MIME_TYPE)
- /*TBD open libmagic cache [fail to pass EFENCE check (allocating 0 bytes)] */
- init_lib_magic (session);
-#endif
-
return 1;
}
-/* infinite loop */
-static void hsrv_handle_event(struct MHD_Daemon *httpd)
-{
- MHD_run(httpd);
-}
-
int afb_hsrv_start(AFB_session * session)
{
- struct MHD_Daemon *httpd;
- const union MHD_DaemonInfo *info;
+ int rc;
+ struct afb_hsrv *hsrv;
- if (!my_default_init(session)) {
+ hsrv = afb_hsrv_create();
+ if (hsrv == NULL) {
+ fprintf(stderr, "memory allocation failure\n");
+ return 0;
+ }
+
+ if (!afb_hsrv_set_cache_timeout(hsrv, session->config->cacheTimeout)
+ || !my_default_init(hsrv, session)) {
printf("Error: initialisation of httpd failed");
+ afb_hsrv_put(hsrv);
return 0;
}
printf("AFB:notice Browser URL= http:/*localhost:%d\n", session->config->httpdPort);
}
- httpd = MHD_start_daemon(
- MHD_USE_EPOLL_LINUX_ONLY | MHD_USE_TCP_FASTOPEN | MHD_USE_DEBUG | MHD_USE_SUSPEND_RESUME,
- (uint16_t) session->config->httpdPort, /* port */
- new_client_handler, NULL, /* Tcp Accept call back + extra attribute */
- access_handler, session, /* Http Request Call back + extra attribute */
- MHD_OPTION_NOTIFY_COMPLETED, end_handler, session,
- MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int)15, /* 15 seconds */
- MHD_OPTION_END); /* options-end */
-
- if (httpd == NULL) {
- printf("Error: httpStart invalid httpd port: %d", session->config->httpdPort);
+ rc = _afb_hsrv_start(hsrv, (uint16_t) session->config->httpdPort, 15);
+ if (!rc)
return 0;
- }
-
- info = MHD_get_daemon_info(httpd, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
- if (info == NULL) {
- MHD_stop_daemon(httpd);
- fprintf(stderr, "Error: httpStart no pollfd");
- return 0;
- }
-
- upoll = upoll_open(info->listen_fd, httpd);
- if (upoll == NULL) {
- MHD_stop_daemon(httpd);
- fprintf(stderr, "Error: connection to upoll of httpd failed");
- return 0;
- }
- upoll_on_readable(upoll, (void*)hsrv_handle_event);
- session->httpd = httpd;
+ session->hsrv = hsrv;
return 1;
}
void afb_hsrv_stop(AFB_session * session)
{
- if (upoll)
- upoll_close(upoll);
- upoll = NULL;
- if (session->httpd != NULL)
- MHD_stop_daemon(session->httpd);
- session->httpd = NULL;
+ _afb_hsrv_stop(session->hsrv);
}