mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-16 00:00:07 +01:00

1) update the logos to svg 2) add svg icon for strict security policy where used 3) define new vhost option flag to enforce sending CSP headers with the result code 4) add vhost option flag to minimal examples to enforce sending CSP where applicable 5) Go through all the affecting examples confirming they still work 6) add LWS_RECOMMENDED_MIN_HEADER_SPACE constant (currently 2048) to clarify when we need a buffer to hold headers... with CSP the headers have become potentially a lot larger.
425 lines
10 KiB
C
425 lines
10 KiB
C
/*
|
|
* lws-minimal-http-server-eventlib-foreign
|
|
*
|
|
* Copyright (C) 2018 Andy Green <andy@warmcat.com>
|
|
*
|
|
* This file is made available under the Creative Commons CC0 1.0
|
|
* Universal Public Domain Dedication.
|
|
*
|
|
* This demonstrates the most minimal http server you can make with lws that
|
|
* uses a libuv event loop created outside lws. It shows how lws can
|
|
* participate in someone else's event loop and clean up after itself.
|
|
*
|
|
* You choose the event loop to work with at runtime, by giving the
|
|
* --uv, --event or --ev switch. Lws has to have been configured to build the
|
|
* selected event lib support.
|
|
*
|
|
* To keep it simple, it serves stuff from the subdirectory
|
|
* "./mount-origin" of the directory it was started in.
|
|
* You can change that by changing mount.origin below.
|
|
*/
|
|
|
|
#include <libwebsockets.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
|
|
struct lws_context_creation_info info;
|
|
static struct lws_context *context;
|
|
static int lifetime = 5, reported;
|
|
|
|
static void foreign_timer_service(void *foreign_loop);
|
|
|
|
enum {
|
|
TEST_STATE_CREATE_LWS_CONTEXT,
|
|
TEST_STATE_DESTROY_LWS_CONTEXT,
|
|
TEST_STATE_EXIT
|
|
};
|
|
|
|
static int sequence = TEST_STATE_CREATE_LWS_CONTEXT;
|
|
|
|
static const struct lws_http_mount mount = {
|
|
/* .mount_next */ NULL, /* linked-list "next" */
|
|
/* .mountpoint */ "/", /* mountpoint URL */
|
|
/* .origin */ "./mount-origin", /* serve from dir */
|
|
/* .def */ "index.html", /* default filename */
|
|
/* .protocol */ NULL,
|
|
/* .cgienv */ NULL,
|
|
/* .extra_mimetypes */ NULL,
|
|
/* .interpret */ NULL,
|
|
/* .cgi_timeout */ 0,
|
|
/* .cache_max_age */ 0,
|
|
/* .auth_mask */ 0,
|
|
/* .cache_reusable */ 0,
|
|
/* .cache_revalidate */ 0,
|
|
/* .cache_intermediaries */ 0,
|
|
/* .origin_protocol */ LWSMPRO_FILE, /* files in a dir */
|
|
/* .mountpoint_len */ 1, /* char count */
|
|
/* .basic_auth_login_file */ NULL,
|
|
};
|
|
|
|
static void
|
|
signal_cb(int signum)
|
|
{
|
|
lwsl_notice("Signal %d caught, exiting...\n", signum);
|
|
|
|
switch (signum) {
|
|
case SIGTERM:
|
|
case SIGINT:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
lws_context_destroy(context);
|
|
}
|
|
|
|
/*
|
|
* The event-loop specific foreign loop code, one set for each event loop lib
|
|
*
|
|
* Only the code in this section is specific to the event library used.
|
|
*/
|
|
|
|
#if defined(LWS_WITH_LIBUV)
|
|
|
|
static uv_loop_t loop_uv;
|
|
static uv_timer_t timer_outer_uv;
|
|
static uv_signal_t sighandler_uv;
|
|
|
|
static void
|
|
timer_cb_uv(uv_timer_t *t)
|
|
{
|
|
foreign_timer_service(&loop_uv);
|
|
}
|
|
|
|
static void
|
|
signal_cb_uv(uv_signal_t *watcher, int signum)
|
|
{
|
|
signal_cb(signum);
|
|
}
|
|
|
|
static void
|
|
foreign_event_loop_init_and_run_libuv(void)
|
|
{
|
|
/* we create and start our "foreign loop" */
|
|
|
|
#if (UV_VERSION_MAJOR > 0) // Travis...
|
|
uv_loop_init(&loop_uv);
|
|
#endif
|
|
uv_signal_init(&loop_uv, &sighandler_uv);
|
|
uv_signal_start(&sighandler_uv, signal_cb_uv, SIGINT);
|
|
|
|
uv_timer_init(&loop_uv, &timer_outer_uv);
|
|
#if (UV_VERSION_MAJOR > 0) // Travis...
|
|
uv_timer_start(&timer_outer_uv, timer_cb_uv, 0, 1000);
|
|
#else
|
|
(void)timer_cb_uv;
|
|
#endif
|
|
|
|
uv_run(&loop_uv, UV_RUN_DEFAULT);
|
|
}
|
|
|
|
static void
|
|
foreign_event_loop_stop_libuv(void)
|
|
{
|
|
uv_stop(&loop_uv);
|
|
}
|
|
|
|
static void
|
|
foreign_event_loop_cleanup_libuv(void)
|
|
{
|
|
/* cleanup the foreign loop assets */
|
|
|
|
uv_timer_stop(&timer_outer_uv);
|
|
uv_close((uv_handle_t*)&timer_outer_uv, NULL);
|
|
uv_signal_stop(&sighandler_uv);
|
|
uv_close((uv_handle_t *)&sighandler_uv, NULL);
|
|
|
|
uv_run(&loop_uv, UV_RUN_DEFAULT);
|
|
#if (UV_VERSION_MAJOR > 0) // Travis...
|
|
uv_loop_close(&loop_uv);
|
|
#endif
|
|
}
|
|
|
|
#endif
|
|
|
|
#if defined(LWS_WITH_LIBEVENT)
|
|
|
|
static struct event_base *loop_event;
|
|
static struct event *timer_outer_event;
|
|
static struct event *sighandler_event;
|
|
|
|
static void
|
|
timer_cb_event(int fd, short event, void *arg)
|
|
{
|
|
foreign_timer_service(loop_event);
|
|
}
|
|
|
|
static void
|
|
signal_cb_event(int fd, short event, void *arg)
|
|
{
|
|
signal_cb((int)(lws_intptr_t)arg);
|
|
}
|
|
|
|
static void
|
|
foreign_event_loop_init_and_run_libevent(void)
|
|
{
|
|
struct timeval tv;
|
|
|
|
/* we create and start our "foreign loop" */
|
|
|
|
tv.tv_sec = 1;
|
|
tv.tv_usec = 0;
|
|
|
|
loop_event = event_base_new();
|
|
|
|
sighandler_event = evsignal_new(loop_event, SIGINT, signal_cb_event,
|
|
(void*)SIGINT);
|
|
|
|
timer_outer_event = event_new(loop_event, -1, EV_PERSIST,
|
|
timer_cb_event, NULL);
|
|
//evtimer_new(loop_event, timer_cb_event, NULL);
|
|
evtimer_add(timer_outer_event, &tv);
|
|
|
|
event_base_loop(loop_event, 0);
|
|
}
|
|
|
|
static void
|
|
foreign_event_loop_stop_libevent(void)
|
|
{
|
|
event_base_loopexit(loop_event, NULL);
|
|
}
|
|
|
|
static void
|
|
foreign_event_loop_cleanup_libevent(void)
|
|
{
|
|
/* cleanup the foreign loop assets */
|
|
|
|
evtimer_del(timer_outer_event);
|
|
event_free(timer_outer_event);
|
|
evsignal_del(sighandler_event);
|
|
event_free(sighandler_event);
|
|
|
|
event_base_loop(loop_event, 0);
|
|
event_base_free(loop_event);
|
|
}
|
|
|
|
#endif
|
|
|
|
#if defined(LWS_WITH_LIBEV)
|
|
|
|
static struct ev_loop *loop_ev;
|
|
static struct ev_timer timer_outer_ev;
|
|
static struct ev_signal sighandler_ev;
|
|
|
|
static void
|
|
timer_cb_ev(struct ev_loop *loop, struct ev_timer *watcher, int revents)
|
|
{
|
|
foreign_timer_service(loop_ev);
|
|
}
|
|
|
|
static void
|
|
signal_cb_ev(struct ev_loop *loop, struct ev_signal *watcher, int revents)
|
|
{
|
|
signal_cb(watcher->signum);
|
|
}
|
|
|
|
static void
|
|
foreign_event_loop_init_and_run_libev(void)
|
|
{
|
|
/* we create and start our "foreign loop" */
|
|
|
|
loop_ev = ev_loop_new(0);
|
|
|
|
ev_signal_init(&sighandler_ev, signal_cb_ev, SIGINT);
|
|
ev_signal_start(loop_ev, &sighandler_ev);
|
|
|
|
ev_timer_init(&timer_outer_ev, timer_cb_ev, 0, 1);
|
|
ev_timer_start(loop_ev, &timer_outer_ev);
|
|
|
|
ev_run(loop_ev, 0);
|
|
}
|
|
|
|
static void
|
|
foreign_event_loop_stop_libev(void)
|
|
{
|
|
ev_break(loop_ev, EVBREAK_ALL);
|
|
}
|
|
|
|
static void
|
|
foreign_event_loop_cleanup_libev(void)
|
|
{
|
|
/* cleanup the foreign loop assets */
|
|
|
|
ev_timer_stop(loop_ev, &timer_outer_ev);
|
|
ev_signal_stop(loop_ev, &sighandler_ev);
|
|
|
|
ev_run(loop_ev, UV_RUN_DEFAULT);
|
|
ev_loop_destroy(loop_ev);
|
|
}
|
|
|
|
#endif
|
|
|
|
/* this is called at 1Hz using a foreign loop timer */
|
|
|
|
static void
|
|
foreign_timer_service(void *foreign_loop)
|
|
{
|
|
void *foreign_loops[1];
|
|
|
|
lwsl_user("Foreign 1Hz timer\n");
|
|
|
|
if (sequence == TEST_STATE_EXIT && !context && !reported) {
|
|
/*
|
|
* at this point the lws_context_destroy() we did earlier
|
|
* has completed and the entire context is wholly destroyed
|
|
*/
|
|
lwsl_user("lws_destroy_context() done, continuing for 5s\n");
|
|
reported = 1;
|
|
}
|
|
|
|
if (--lifetime)
|
|
return;
|
|
|
|
switch (sequence++) {
|
|
case TEST_STATE_CREATE_LWS_CONTEXT:
|
|
/* this only has to exist for the duration of create context */
|
|
foreign_loops[0] = foreign_loop;
|
|
info.foreign_loops = foreign_loops;
|
|
|
|
context = lws_create_context(&info);
|
|
if (!context) {
|
|
lwsl_err("lws init failed\n");
|
|
return;
|
|
}
|
|
lwsl_user("LWS Context created and will be active for 10s\n");
|
|
lifetime = 11;
|
|
break;
|
|
|
|
case TEST_STATE_DESTROY_LWS_CONTEXT:
|
|
/* cleanup the lws part */
|
|
lwsl_user("Destroying lws context and continuing loop for 5s\n");
|
|
lws_context_destroy(context);
|
|
lifetime = 6;
|
|
break;
|
|
|
|
case TEST_STATE_EXIT:
|
|
lwsl_user("Deciding to exit foreign loop too\n");
|
|
#if defined(LWS_WITH_LIBUV)
|
|
if (info.options & LWS_SERVER_OPTION_LIBUV)
|
|
foreign_event_loop_stop_libuv();
|
|
#endif
|
|
#if defined(LWS_WITH_LIBEVENT)
|
|
if (info.options & LWS_SERVER_OPTION_LIBEVENT)
|
|
foreign_event_loop_stop_libevent();
|
|
#endif
|
|
#if defined(LWS_WITH_LIBEV)
|
|
if (info.options & LWS_SERVER_OPTION_LIBEV)
|
|
foreign_event_loop_stop_libev();
|
|
#endif
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
int main(int argc, const char **argv)
|
|
{
|
|
const char *p;
|
|
int logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
|
|
/* for LLL_ verbosity above NOTICE to be built into lws,
|
|
* lws must have been configured and built with
|
|
* -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
|
|
/* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
|
|
/* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
|
|
/* | LLL_DEBUG */;
|
|
|
|
if ((p = lws_cmdline_option(argc, argv, "-d")))
|
|
logs = atoi(p);
|
|
|
|
lws_set_log_level(logs, NULL);
|
|
lwsl_user("LWS minimal http server eventlib + foreign loop |"
|
|
" visit http://localhost:7681\n");
|
|
|
|
/*
|
|
* We prepare the info here, but don't use it until later in the
|
|
* timer callback, to demonstrate the independence of the foreign loop
|
|
* and lws.
|
|
*/
|
|
|
|
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
|
|
info.port = 7681;
|
|
info.mounts = &mount;
|
|
info.error_document_404 = "/404.html";
|
|
info.pcontext = &context;
|
|
info.options =
|
|
LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
|
|
|
|
if (lws_cmdline_option(argc, argv, "-s")) {
|
|
info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
|
info.ssl_cert_filepath = "localhost-100y.cert";
|
|
info.ssl_private_key_filepath = "localhost-100y.key";
|
|
}
|
|
|
|
if (lws_cmdline_option(argc, argv, "--uv"))
|
|
info.options |= LWS_SERVER_OPTION_LIBUV;
|
|
else
|
|
if (lws_cmdline_option(argc, argv, "--event"))
|
|
info.options |= LWS_SERVER_OPTION_LIBEVENT;
|
|
else
|
|
if (lws_cmdline_option(argc, argv, "--ev"))
|
|
info.options |= LWS_SERVER_OPTION_LIBEV;
|
|
else {
|
|
lwsl_err("This app only makes sense when used\n");
|
|
lwsl_err(" with a foreign loop, --uv, --event, or --ev\n");
|
|
|
|
return 1;
|
|
}
|
|
|
|
lwsl_user(" This app creates a foreign event loop with a timer +\n");
|
|
lwsl_user(" signalhandler, and performs a test in three phases:\n");
|
|
lwsl_user("\n");
|
|
lwsl_user(" 1) 5s: Runs the loop with just the timer\n");
|
|
lwsl_user(" 2) 10s: create an lws context serving on localhost:7681\n");
|
|
lwsl_user(" using the same foreign loop. Destroy it after 10s.\n");
|
|
lwsl_user(" 3) 5s: Run the loop again with just the timer\n");
|
|
lwsl_user("\n");
|
|
lwsl_user(" Finally close only the timer and signalhandler and\n");
|
|
lwsl_user(" exit the loop cleanly\n");
|
|
lwsl_user("\n");
|
|
|
|
/* foreign loop specific startup and run */
|
|
|
|
#if defined(LWS_WITH_LIBUV)
|
|
if (info.options & LWS_SERVER_OPTION_LIBUV)
|
|
foreign_event_loop_init_and_run_libuv();
|
|
#endif
|
|
#if defined(LWS_WITH_LIBEVENT)
|
|
if (info.options & LWS_SERVER_OPTION_LIBEVENT)
|
|
foreign_event_loop_init_and_run_libevent();
|
|
#endif
|
|
#if defined(LWS_WITH_LIBEV)
|
|
if (info.options & LWS_SERVER_OPTION_LIBEV)
|
|
foreign_event_loop_init_and_run_libev();
|
|
#endif
|
|
|
|
lws_context_destroy(context);
|
|
|
|
/* foreign loop specific cleanup and exit */
|
|
|
|
#if defined(LWS_WITH_LIBUV)
|
|
if (info.options & LWS_SERVER_OPTION_LIBUV)
|
|
foreign_event_loop_cleanup_libuv();
|
|
#endif
|
|
#if defined(LWS_WITH_LIBEVENT)
|
|
if (info.options & LWS_SERVER_OPTION_LIBEVENT)
|
|
foreign_event_loop_cleanup_libevent();
|
|
#endif
|
|
#if defined(LWS_WITH_LIBEV)
|
|
if (info.options & LWS_SERVER_OPTION_LIBEV)
|
|
foreign_event_loop_cleanup_libev();
|
|
#endif
|
|
|
|
lwsl_user("%s: exiting...\n", __func__);
|
|
|
|
return 0;
|
|
}
|