1/*
2 * lws-minimal-http-server-deaddrop
3 *
4 * Written in 2010-2020 by Andy Green <andy@warmcat.com>
5 *
6 * This file is made available under the Creative Commons CC0 1.0
7 * Universal Public Domain Dedication.
8 *
9 * This demonstrates how you can leverage the lws deaddrop plugin to make a
10 * secure, modern html5 file upload and sharing application.
11 *
12 * Because the guts are in a plugin, you can avoid all this setup by using the
13 * plugin from lwsws and do the config in JSON.
14 */
15
16#include <libwebsockets.h>
17#include <string.h>
18#include <signal.h>
19#include <time.h>
20
21#define LWS_PLUGIN_STATIC
22#include "../plugins/deaddrop/protocol_lws_deaddrop.c"
23
24static struct lws_protocols protocols[] = {
25       LWS_PLUGIN_PROTOCOL_DEADDROP,
26       LWS_PROTOCOL_LIST_TERM
27};
28
29
30static int interrupted;
31
32/*
33 * teach the /get mount how to present various filetypes to the client...
34 * lws won't serve files it doesn't know the mimetype for as a security
35 * measure.
36 */
37
38static struct lws_protocol_vhost_options em3 = {
39        NULL, NULL, ".zip", "application/zip"
40}, em2 = {
41	&em3, NULL, ".pdf", "application/pdf"
42}, extra_mimetypes = {
43	&em2, NULL, ".tar.gz", "application/x-gzip"
44};
45
46/* wire up /upload URLs to the plugin (protected by basic auth) */
47
48static const struct lws_http_mount mount_upload = {
49	/* .mount_next */		NULL,
50	/* .mountpoint */		"/upload",	/* mountpoint URL */
51	/* .origin */			"lws-deaddrop",
52	/* .def */			"",
53	/* .protocol */			NULL,
54	/* .cgienv */			NULL,
55	/* .extra_mimetypes */		NULL,
56	/* .interpret */		NULL,
57	/* .cgi_timeout */		0,
58	/* .cache_max_age */		0,
59	/* .auth_mask */		0,
60	/* .cache_reusable */		0,
61	/* .cache_revalidate */		0,
62	/* .cache_intermediaries */	0,
63	/* .origin_protocol */		LWSMPRO_CALLBACK,
64	/* .mountpoint_len */		7,		/* char count */
65	/* .basic_auth_login_file */	"./ba-passwords",
66};
67
68/* wire up /get URLs to the upload directory (protected by basic auth) */
69
70static const struct lws_http_mount mount_get = {
71	/* .mount_next */		&mount_upload,	/* linked-list "next" */
72	/* .mountpoint */		"/get",	/* mountpoint URL */
73	/* .origin */			"./uploads",
74	/* .def */			"",
75	/* .protocol */			NULL,
76	/* .cgienv */			NULL,
77	/* .extra_mimetypes */		&extra_mimetypes,
78	/* .interpret */		NULL,
79	/* .cgi_timeout */		0,
80	/* .cache_max_age */		0,
81	/* .auth_mask */		0,
82	/* .cache_reusable */		0,
83	/* .cache_revalidate */		0,
84	/* .cache_intermediaries */	0,
85	/* .origin_protocol */		LWSMPRO_FILE, /* dynamic */
86	/* .mountpoint_len */		4,		/* char count */
87	/* .basic_auth_login_file */	"./ba-passwords",
88};
89
90/* wire up / to serve from ./mount-origin (protected by basic auth) */
91
92static const struct lws_http_mount mount = {
93	/* .mount_next */		&mount_get,	/* linked-list "next" */
94	/* .mountpoint */		"/",		/* mountpoint URL */
95	/* .origin */			"./mount-origin", /* serve from dir */
96	/* .def */			"index.html",	/* default filename */
97	/* .protocol */			NULL,
98	/* .cgienv */			NULL,
99	/* .extra_mimetypes */		NULL,
100	/* .interpret */		NULL,
101	/* .cgi_timeout */		0,
102	/* .cache_max_age */		0,
103	/* .auth_mask */		0,
104	/* .cache_reusable */		0,
105	/* .cache_revalidate */		0,
106	/* .cache_intermediaries */	0,
107	/* .origin_protocol */		LWSMPRO_FILE,	/* files in a dir */
108	/* .mountpoint_len */		1,		/* char count */
109	/* .basic_auth_login_file */	"./ba-passwords",
110};
111
112/* pass config options to the deaddrop plugin using pvos */
113
114static struct lws_protocol_vhost_options pvo3 = {
115	/* make the wss also require to pass basic auth */
116	NULL, NULL, "basic-auth", "./ba-passwords"
117}, pvo2 = {
118	&pvo3, NULL, "max-size", "10000000"
119}, pvo1 = {
120        &pvo2, NULL, "upload-dir", "./uploads" /* would be an absolute path */
121}, pvo = {
122        NULL,                  /* "next" pvo linked-list */
123        &pvo1,                 /* "child" pvo linked-list */
124        "lws-deaddrop",        /* protocol name we belong to on this vhost */
125        ""                     /* ignored */
126};
127
128void sigint_handler(int sig)
129{
130	interrupted = 1;
131}
132
133int main(int argc, const char **argv)
134{
135	struct lws_context_creation_info info;
136	struct lws_context *context;
137	const char *p;
138	int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
139
140	signal(SIGINT, sigint_handler);
141
142	if ((p = lws_cmdline_option(argc, argv, "-d")))
143		logs = atoi(p);
144
145	lws_set_log_level(logs, NULL);
146	lwsl_user("LWS minimal http server deaddrop | visit https://localhost:7681\n");
147
148	memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
149	info.port = 7681;
150	info.mounts = &mount;
151	info.pvo = &pvo;
152	info.protocols = protocols;
153	info.error_document_404 = "/404.html";
154	info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
155		LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
156#if defined(LWS_WITH_TLS)
157	info.ssl_cert_filepath = "localhost-100y.cert";
158	info.ssl_private_key_filepath = "localhost-100y.key";
159#endif
160
161	context = lws_create_context(&info);
162	if (!context) {
163		lwsl_err("lws init failed\n");
164		return 1;
165	}
166
167	while (n >= 0 && !interrupted)
168		n = lws_service(context, 0);
169
170	lws_context_destroy(context);
171
172	return 0;
173}
174