d9a1f31ab56689287f0650ce101d1459ea856734
[platform/upstream/libwebsockets.git] /
1 /*
2  * lws-minimal-http-server-custom-headers
3  *
4  * Written in 2010-2019 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 a minimal http server that can produce dynamic http
10  * content as well as static content.
11  *
12  * To keep it simple, it serves the static stuff from the subdirectory
13  * "./mount-origin" of the directory it was started in.
14  *
15  * You can change that by changing mount.origin below.
16  */
17
18 #include <libwebsockets.h>
19 #include <string.h>
20 #include <signal.h>
21 #include <time.h>
22
23 static int interrupted;
24
25 struct pss {
26         char result[128 + LWS_PRE];
27         int len;
28 };
29
30 /*
31  * This just lets us override LWS_CALLBACK_HTTP handling before passing it
32  * and everything else to the default handler.
33  */
34
35 static int
36 callback_http(struct lws *wsi, enum lws_callback_reasons reason,
37               void *user, void *in, size_t len)
38 {
39         uint8_t buf[LWS_PRE + 2048], *start = &buf[LWS_PRE], *p = start,
40                 *end = &buf[sizeof(buf) - LWS_PRE - 1];
41         struct pss *pss = (struct pss *)user;
42         char value[32], *pr = &pss->result[LWS_PRE];
43         size_t e = sizeof(pss->result) - LWS_PRE;
44         int n;
45
46         switch (reason) {
47         case LWS_CALLBACK_HTTP:
48                 /*
49                  * LWS doesn't have the "DNT" header built-in.  But we can
50                  * query it using the "custom" versions of the header apis.
51                  *
52                  * You can set your modern browser to issue DNT, look in the
53                  * privacy settings of your browser.
54                  */
55
56                 pss->len = 0;
57                 n = lws_hdr_custom_length(wsi, "dnt:", 4);
58                 if (n < 0)
59                         pss->len = lws_snprintf(pr, e,
60                                         "%s: DNT header not found\n", __func__);
61                 else {
62
63                         pss->len = lws_snprintf(pr, e,
64                                         "%s: DNT length %d<br>", __func__, n);
65                         n = lws_hdr_custom_copy(wsi, value, sizeof(value), "dnt:", 4);
66                         if (n < 0)
67                                 pss->len += lws_snprintf(pr + pss->len, e - (unsigned int)pss->len,
68                                         "%s: unable to get DNT value\n", __func__);
69                         else
70
71                                 pss->len += lws_snprintf(pr + pss->len , e - (unsigned int)pss->len,
72                                         "%s: DNT value '%s'\n", __func__, value);
73                 }
74
75                 lwsl_user("%s\n", pr);
76
77                 if (lws_add_http_common_headers(wsi, HTTP_STATUS_OK,
78                                 "text/html", (lws_filepos_t)pss->len, &p, end))
79                         return 1;
80
81                 if (lws_finalize_write_http_header(wsi, start, &p, end))
82                         return 1;
83
84
85                 /* write the body separately */
86                 lws_callback_on_writable(wsi);
87                 return 0;
88
89         case LWS_CALLBACK_HTTP_WRITEABLE:
90
91                 strcpy((char *)start, "hello");
92
93                 if (lws_write(wsi, (uint8_t *)pr, (unsigned int)pss->len, LWS_WRITE_HTTP_FINAL) != pss->len)
94                         return 1;
95
96                 if (lws_http_transaction_completed(wsi))
97                         return -1;
98                 return 0;
99
100         default:
101                 break;
102         }
103
104         return lws_callback_http_dummy(wsi, reason, user, in, len);
105 }
106
107 static struct lws_protocols protocols[] = {
108         { "http", callback_http, sizeof(struct pss), 0, 0, NULL, 0 },
109         LWS_PROTOCOL_LIST_TERM
110 };
111
112 static const struct lws_http_mount mount_dyn = {
113         /* .mount_next */               NULL,           /* linked-list "next" */
114         /* .mountpoint */               "/dyn",         /* mountpoint URL */
115         /* .origin */                   NULL,   /* protocol */
116         /* .def */                      NULL,
117         /* .protocol */                 "http",
118         /* .cgienv */                   NULL,
119         /* .extra_mimetypes */          NULL,
120         /* .interpret */                NULL,
121         /* .cgi_timeout */              0,
122         /* .cache_max_age */            0,
123         /* .auth_mask */                0,
124         /* .cache_reusable */           0,
125         /* .cache_revalidate */         0,
126         /* .cache_intermediaries */     0,
127         /* .origin_protocol */          LWSMPRO_CALLBACK, /* dynamic */
128         /* .mountpoint_len */           4,              /* char count */
129         /* .basic_auth_login_file */    NULL,
130 };
131
132 /* default mount serves the URL space from ./mount-origin */
133
134 static const struct lws_http_mount mount = {
135         /* .mount_next */               &mount_dyn,             /* linked-list "next" */
136         /* .mountpoint */               "/",            /* mountpoint URL */
137         /* .origin */           "./mount-origin",       /* serve from dir */
138         /* .def */                      "index.html",   /* default filename */
139         /* .protocol */                 NULL,
140         /* .cgienv */                   NULL,
141         /* .extra_mimetypes */          NULL,
142         /* .interpret */                NULL,
143         /* .cgi_timeout */              0,
144         /* .cache_max_age */            0,
145         /* .auth_mask */                0,
146         /* .cache_reusable */           0,
147         /* .cache_revalidate */         0,
148         /* .cache_intermediaries */     0,
149         /* .origin_protocol */          LWSMPRO_FILE,   /* files in a dir */
150         /* .mountpoint_len */           1,              /* char count */
151         /* .basic_auth_login_file */    NULL,
152 };
153
154 void sigint_handler(int sig)
155 {
156         interrupted = 1;
157 }
158
159 int main(int argc, const char **argv)
160 {
161         struct lws_context_creation_info info;
162         struct lws_context *context;
163         const char *p;
164         int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
165
166         signal(SIGINT, sigint_handler);
167
168         if ((p = lws_cmdline_option(argc, argv, "-d")))
169                 logs = atoi(p);
170
171         lws_set_log_level(logs, NULL);
172         lwsl_user("LWS minimal http server custom headers | visit http://localhost:7681\n");
173
174         memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
175         info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
176                        LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
177                 LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
178
179         /* for testing ah queue, not useful in real world */
180         if (lws_cmdline_option(argc, argv, "--ah1"))
181                 info.max_http_header_pool = 1;
182
183         context = lws_create_context(&info);
184         if (!context) {
185                 lwsl_err("lws init failed\n");
186                 return 1;
187         }
188
189         /* http on 7681 */
190
191         info.port = 7681;
192         info.protocols = protocols;
193         info.mounts = &mount;
194         info.vhost_name = "http";
195
196         if (!lws_create_vhost(context, &info)) {
197                 lwsl_err("Failed to create tls vhost\n");
198                 goto bail;
199         }
200
201         /* https on 7682 */
202
203         info.port = 7682;
204         info.error_document_404 = "/404.html";
205 #if defined(LWS_WITH_TLS)
206         info.ssl_cert_filepath = "localhost-100y.cert";
207         info.ssl_private_key_filepath = "localhost-100y.key";
208 #endif
209         info.vhost_name = "https";
210
211         if (!lws_create_vhost(context, &info)) {
212                 lwsl_err("Failed to create tls vhost\n");
213                 goto bail;
214         }
215
216         while (n >= 0 && !interrupted)
217                 n = lws_service(context, 0);
218
219 bail:
220         lws_context_destroy(context);
221
222         return 0;
223 }