1 /*
2 * Copyright (c) 2023, Emna Rekik
3 * Copyright (c) 2024 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <errno.h>
9 #include <stdbool.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <strings.h>
14
15 #include <zephyr/fs/fs.h>
16 #include <zephyr/fs/fs_interface.h>
17 #include <zephyr/kernel.h>
18 #include <zephyr/logging/log.h>
19 #include <zephyr/net/http/service.h>
20 #include <zephyr/net/net_ip.h>
21 #include <zephyr/net/socket.h>
22 #include <zephyr/net/tls_credentials.h>
23 #include <zephyr/posix/sys/eventfd.h>
24 #include <zephyr/posix/fnmatch.h>
25
26 LOG_MODULE_REGISTER(net_http_server, CONFIG_NET_HTTP_SERVER_LOG_LEVEL);
27
28 #include "../../ip/net_private.h"
29 #include "headers/server_internal.h"
30
31 #if defined(CONFIG_NET_TC_THREAD_COOPERATIVE)
32 /* Lowest priority cooperative thread */
33 #define THREAD_PRIORITY K_PRIO_COOP(CONFIG_NUM_COOP_PRIORITIES - 1)
34 #else
35 #define THREAD_PRIORITY K_PRIO_PREEMPT(CONFIG_NUM_PREEMPT_PRIORITIES - 1)
36 #endif
37
38 #define INVALID_SOCK -1
39 #define INACTIVITY_TIMEOUT K_SECONDS(CONFIG_HTTP_SERVER_CLIENT_INACTIVITY_TIMEOUT)
40
41 #define HTTP_SERVER_MAX_SERVICES CONFIG_HTTP_SERVER_NUM_SERVICES
42 #define HTTP_SERVER_MAX_CLIENTS CONFIG_HTTP_SERVER_MAX_CLIENTS
43 #define HTTP_SERVER_SOCK_COUNT (1 + HTTP_SERVER_MAX_SERVICES + HTTP_SERVER_MAX_CLIENTS)
44
45 struct http_server_ctx {
46 int num_clients;
47 int listen_fds; /* max value of 1 + MAX_SERVICES */
48
49 /* First pollfd is eventfd that can be used to stop the server,
50 * then we have the server listen sockets,
51 * and then the accepted sockets.
52 */
53 struct zsock_pollfd fds[HTTP_SERVER_SOCK_COUNT];
54 struct http_client_ctx clients[HTTP_SERVER_MAX_CLIENTS];
55 };
56
57 static struct http_server_ctx server_ctx;
58 static K_SEM_DEFINE(server_start, 0, 1);
59 static bool server_running;
60
61 #if defined(CONFIG_HTTP_SERVER_TLS_USE_ALPN)
62 static const char *const alpn_list[] = {"h2", "http/1.1"};
63 #endif
64
65 static void close_client_connection(struct http_client_ctx *client);
66
67 HTTP_SERVER_CONTENT_TYPE(html, "text/html")
68 HTTP_SERVER_CONTENT_TYPE(css, "text/css")
69 HTTP_SERVER_CONTENT_TYPE(js, "text/javascript")
70 HTTP_SERVER_CONTENT_TYPE(jpg, "image/jpeg")
71 HTTP_SERVER_CONTENT_TYPE(png, "image/png")
72 HTTP_SERVER_CONTENT_TYPE(svg, "image/svg+xml")
73
http_server_init(struct http_server_ctx * ctx)74 int http_server_init(struct http_server_ctx *ctx)
75 {
76 int proto;
77 int failed = 0, count = 0;
78 int svc_count;
79 socklen_t len;
80 int fd, af, i;
81 struct sockaddr_storage addr_storage;
82 const union {
83 struct sockaddr *addr;
84 struct sockaddr_in *addr4;
85 struct sockaddr_in6 *addr6;
86 } addr = {
87 .addr = (struct sockaddr *)&addr_storage
88 };
89
90 HTTP_SERVICE_COUNT(&svc_count);
91
92 /* Initialize fds */
93 memset(ctx->fds, 0, sizeof(ctx->fds));
94 memset(ctx->clients, 0, sizeof(ctx->clients));
95
96 for (i = 0; i < ARRAY_SIZE(ctx->fds); i++) {
97 ctx->fds[i].fd = INVALID_SOCK;
98 }
99
100 /* Create an eventfd that can be used to trigger events during polling */
101 fd = eventfd(0, 0);
102 if (fd < 0) {
103 fd = -errno;
104 LOG_ERR("eventfd failed (%d)", fd);
105 return fd;
106 }
107
108 ctx->fds[count].fd = fd;
109 ctx->fds[count].events = ZSOCK_POLLIN;
110 count++;
111
112 HTTP_SERVICE_FOREACH(svc) {
113 /* set the default address (in6addr_any / INADDR_ANY are all 0) */
114 memset(&addr_storage, 0, sizeof(struct sockaddr_storage));
115
116 /* Set up the server address struct according to address family */
117 if (IS_ENABLED(CONFIG_NET_IPV6) && svc->host != NULL &&
118 zsock_inet_pton(AF_INET6, svc->host, &addr.addr6->sin6_addr) == 1) {
119 af = AF_INET6;
120 len = sizeof(*addr.addr6);
121
122 addr.addr6->sin6_family = AF_INET6;
123 addr.addr6->sin6_port = htons(*svc->port);
124 } else if (IS_ENABLED(CONFIG_NET_IPV4) && svc->host != NULL &&
125 zsock_inet_pton(AF_INET, svc->host, &addr.addr4->sin_addr) == 1) {
126 af = AF_INET;
127 len = sizeof(*addr.addr4);
128
129 addr.addr4->sin_family = AF_INET;
130 addr.addr4->sin_port = htons(*svc->port);
131 } else if (IS_ENABLED(CONFIG_NET_IPV6)) {
132 /* prefer IPv6 if both IPv6 and IPv4 are supported */
133 af = AF_INET6;
134 len = sizeof(*addr.addr6);
135
136 addr.addr6->sin6_family = AF_INET6;
137 addr.addr6->sin6_port = htons(*svc->port);
138 } else if (IS_ENABLED(CONFIG_NET_IPV4)) {
139 af = AF_INET;
140 len = sizeof(*addr.addr4);
141
142 addr.addr4->sin_family = AF_INET;
143 addr.addr4->sin_port = htons(*svc->port);
144 } else {
145 LOG_ERR("Neither IPv4 nor IPv6 is enabled");
146 failed++;
147 break;
148 }
149
150 /* Create a socket */
151 if (COND_CODE_1(CONFIG_NET_SOCKETS_SOCKOPT_TLS,
152 (svc->sec_tag_list != NULL),
153 (0))) {
154 proto = IPPROTO_TLS_1_2;
155 } else {
156 proto = IPPROTO_TCP;
157 }
158
159 fd = zsock_socket(af, SOCK_STREAM, proto);
160 if (fd < 0) {
161 LOG_ERR("socket: %d", errno);
162 failed++;
163 continue;
164 }
165
166 /* If IPv4-to-IPv6 mapping is enabled, then turn off V6ONLY option
167 * so that IPv6 socket can serve IPv4 connections.
168 */
169 if (IS_ENABLED(CONFIG_NET_IPV4_MAPPING_TO_IPV6)) {
170 int optval = 0;
171
172 (void)zsock_setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
173 sizeof(optval));
174 }
175
176 #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
177 if (svc->sec_tag_list != NULL) {
178 if (zsock_setsockopt(fd, SOL_TLS, TLS_SEC_TAG_LIST,
179 svc->sec_tag_list,
180 svc->sec_tag_list_size) < 0) {
181 LOG_ERR("setsockopt: %d", errno);
182 zsock_close(fd);
183 continue;
184 }
185
186 if (zsock_setsockopt(fd, SOL_TLS, TLS_HOSTNAME, "localhost",
187 sizeof("localhost")) < 0) {
188 LOG_ERR("setsockopt: %d", errno);
189 zsock_close(fd);
190 continue;
191 }
192
193 #if defined(CONFIG_HTTP_SERVER_TLS_USE_ALPN)
194 if (zsock_setsockopt(fd, SOL_TLS, TLS_ALPN_LIST, alpn_list,
195 sizeof(alpn_list)) < 0) {
196 LOG_ERR("setsockopt: %d", errno);
197 zsock_close(fd);
198 continue;
199 }
200 #endif /* defined(CONFIG_HTTP_SERVER_TLS_USE_ALPN) */
201 }
202 #endif /* defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) */
203
204 if (zsock_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){1},
205 sizeof(int)) < 0) {
206 LOG_ERR("setsockopt: %d", errno);
207 zsock_close(fd);
208 continue;
209 }
210
211 if (zsock_bind(fd, addr.addr, len) < 0) {
212 LOG_ERR("bind: %d", errno);
213 failed++;
214 zsock_close(fd);
215 continue;
216 }
217
218 if (*svc->port == 0) {
219 /* ephemeral port - read back the port number */
220 len = sizeof(addr_storage);
221 if (zsock_getsockname(fd, addr.addr, &len) < 0) {
222 LOG_ERR("getsockname: %d", errno);
223 zsock_close(fd);
224 continue;
225 }
226
227 *svc->port = ntohs(addr.addr4->sin_port);
228 }
229
230 if (zsock_listen(fd, HTTP_SERVER_MAX_CLIENTS) < 0) {
231 LOG_ERR("listen: %d", errno);
232 failed++;
233 zsock_close(fd);
234 continue;
235 }
236
237 LOG_DBG("Initialized HTTP Service %s:%u",
238 svc->host ? svc->host : "<any>", *svc->port);
239
240 ctx->fds[count].fd = fd;
241 ctx->fds[count].events = ZSOCK_POLLIN;
242 count++;
243 }
244
245 if (failed >= svc_count) {
246 LOG_ERR("All services failed (%d)", failed);
247 /* Close eventfd socket */
248 zsock_close(ctx->fds[0].fd);
249 return -ESRCH;
250 }
251
252 ctx->listen_fds = count;
253 ctx->num_clients = 0;
254
255 return 0;
256 }
257
accept_new_client(int server_fd)258 static int accept_new_client(int server_fd)
259 {
260 int new_socket;
261 socklen_t addrlen;
262 struct sockaddr_storage sa;
263
264 memset(&sa, 0, sizeof(sa));
265 addrlen = sizeof(sa);
266
267 new_socket = zsock_accept(server_fd, (struct sockaddr *)&sa, &addrlen);
268 if (new_socket < 0) {
269 new_socket = -errno;
270 LOG_DBG("[%d] accept failed (%d)", server_fd, new_socket);
271 return new_socket;
272 }
273
274 LOG_DBG("New client from %s:%d",
275 net_sprint_addr(sa.ss_family, &net_sin((struct sockaddr *)&sa)->sin_addr),
276 ntohs(net_sin((struct sockaddr *)&sa)->sin_port));
277
278 return new_socket;
279 }
280
close_all_sockets(struct http_server_ctx * ctx)281 static void close_all_sockets(struct http_server_ctx *ctx)
282 {
283 zsock_close(ctx->fds[0].fd); /* close eventfd */
284 ctx->fds[0].fd = -1;
285
286 for (int i = 1; i < ARRAY_SIZE(ctx->fds); i++) {
287 if (ctx->fds[i].fd < 0) {
288 continue;
289 }
290
291 if (i < ctx->listen_fds) {
292 zsock_close(ctx->fds[i].fd);
293 } else {
294 struct http_client_ctx *client =
295 &server_ctx.clients[i - ctx->listen_fds];
296
297 close_client_connection(client);
298 }
299
300 ctx->fds[i].fd = -1;
301 }
302 }
303
client_release_resources(struct http_client_ctx * client)304 static void client_release_resources(struct http_client_ctx *client)
305 {
306 struct http_resource_detail *detail;
307 struct http_resource_detail_dynamic *dynamic_detail;
308 struct http_request_ctx request_ctx;
309 struct http_response_ctx response_ctx;
310
311 HTTP_SERVICE_FOREACH(service) {
312 HTTP_SERVICE_FOREACH_RESOURCE(service, resource) {
313 detail = resource->detail;
314
315 if (detail->type != HTTP_RESOURCE_TYPE_DYNAMIC) {
316 continue;
317 }
318
319 dynamic_detail = (struct http_resource_detail_dynamic *)detail;
320
321 if (dynamic_detail->holder != client) {
322 continue;
323 }
324
325 /* If the client still holds the resource at this point,
326 * it means the transaction was not complete. Release
327 * the resource and notify application.
328 */
329 dynamic_detail->holder = NULL;
330
331 if (dynamic_detail->cb == NULL) {
332 continue;
333 }
334
335 populate_request_ctx(&request_ctx, NULL, 0, NULL);
336
337 dynamic_detail->cb(client, HTTP_SERVER_DATA_ABORTED, &request_ctx,
338 &response_ctx, dynamic_detail->user_data);
339 }
340 }
341 }
342
http_server_release_client(struct http_client_ctx * client)343 void http_server_release_client(struct http_client_ctx *client)
344 {
345 int i;
346 struct k_work_sync sync;
347
348 __ASSERT_NO_MSG(IS_ARRAY_ELEMENT(server_ctx.clients, client));
349
350 k_work_cancel_delayable_sync(&client->inactivity_timer, &sync);
351 client_release_resources(client);
352
353 server_ctx.num_clients--;
354
355 for (i = server_ctx.listen_fds; i < ARRAY_SIZE(server_ctx.fds); i++) {
356 if (server_ctx.fds[i].fd == client->fd) {
357 server_ctx.fds[i].fd = INVALID_SOCK;
358 break;
359 }
360 }
361
362 memset(client, 0, sizeof(struct http_client_ctx));
363 client->fd = INVALID_SOCK;
364 }
365
close_client_connection(struct http_client_ctx * client)366 static void close_client_connection(struct http_client_ctx *client)
367 {
368 int fd = client->fd;
369
370 http_server_release_client(client);
371
372 (void)zsock_close(fd);
373 }
374
client_timeout(struct k_work * work)375 static void client_timeout(struct k_work *work)
376 {
377 struct k_work_delayable *dwork = k_work_delayable_from_work(work);
378 struct http_client_ctx *client =
379 CONTAINER_OF(dwork, struct http_client_ctx, inactivity_timer);
380
381 LOG_DBG("Client %p timeout", client);
382
383 /* Shutdown the socket. This will be detected by poll() and a proper
384 * cleanup will proceed.
385 */
386 (void)zsock_shutdown(client->fd, ZSOCK_SHUT_RD);
387 }
388
http_client_timer_restart(struct http_client_ctx * client)389 void http_client_timer_restart(struct http_client_ctx *client)
390 {
391 __ASSERT_NO_MSG(IS_ARRAY_ELEMENT(server_ctx.clients, client));
392
393 k_work_reschedule(&client->inactivity_timer, INACTIVITY_TIMEOUT);
394 }
395
init_client_ctx(struct http_client_ctx * client,int new_socket)396 static void init_client_ctx(struct http_client_ctx *client, int new_socket)
397 {
398 client->fd = new_socket;
399 client->data_len = 0;
400 client->server_state = HTTP_SERVER_PREFACE_STATE;
401 client->has_upgrade_header = false;
402 client->preface_sent = false;
403 client->window_size = HTTP_SERVER_INITIAL_WINDOW_SIZE;
404
405 memset(client->buffer, 0, sizeof(client->buffer));
406 memset(client->url_buffer, 0, sizeof(client->url_buffer));
407 k_work_init_delayable(&client->inactivity_timer, client_timeout);
408 http_client_timer_restart(client);
409
410 ARRAY_FOR_EACH(client->streams, i) {
411 client->streams[i].stream_state = HTTP2_STREAM_IDLE;
412 client->streams[i].stream_id = 0;
413 }
414
415 client->current_stream = NULL;
416 }
417
handle_http_preface(struct http_client_ctx * client)418 static int handle_http_preface(struct http_client_ctx *client)
419 {
420 LOG_DBG("HTTP_SERVER_PREFACE_STATE.");
421
422 if (client->data_len < sizeof(HTTP2_PREFACE) - 1) {
423 /* We don't have full preface yet, get more data. */
424 return -EAGAIN;
425 }
426
427 if (IS_ENABLED(CONFIG_HTTP_SERVER_CAPTURE_HEADERS)) {
428 client->header_capture_ctx.count = 0;
429 client->header_capture_ctx.cursor = 0;
430 client->header_capture_ctx.status = HTTP_HEADER_STATUS_OK;
431 }
432
433 if (strncmp(client->cursor, HTTP2_PREFACE, sizeof(HTTP2_PREFACE) - 1) != 0) {
434 return enter_http1_request(client);
435 }
436
437 return enter_http2_request(client);
438 }
439
handle_http_done(struct http_client_ctx * client)440 static int handle_http_done(struct http_client_ctx *client)
441 {
442 LOG_DBG("HTTP_SERVER_DONE_STATE");
443
444 close_client_connection(client);
445
446 return -EAGAIN;
447 }
448
enter_http_done_state(struct http_client_ctx * client)449 int enter_http_done_state(struct http_client_ctx *client)
450 {
451 close_client_connection(client);
452
453 client->server_state = HTTP_SERVER_DONE_STATE;
454
455 return -EAGAIN;
456 }
457
handle_http_request(struct http_client_ctx * client)458 static int handle_http_request(struct http_client_ctx *client)
459 {
460 int ret = -EINVAL;
461
462 client->cursor = client->buffer;
463
464 do {
465 switch (client->server_state) {
466 case HTTP_SERVER_FRAME_DATA_STATE:
467 ret = handle_http_frame_data(client);
468 break;
469 case HTTP_SERVER_PREFACE_STATE:
470 ret = handle_http_preface(client);
471 break;
472 case HTTP_SERVER_REQUEST_STATE:
473 ret = handle_http1_request(client);
474 break;
475 case HTTP_SERVER_FRAME_HEADER_STATE:
476 ret = handle_http_frame_header(client);
477 break;
478 case HTTP_SERVER_FRAME_HEADERS_STATE:
479 ret = handle_http_frame_headers(client);
480 break;
481 case HTTP_SERVER_FRAME_CONTINUATION_STATE:
482 ret = handle_http_frame_continuation(client);
483 break;
484 case HTTP_SERVER_FRAME_SETTINGS_STATE:
485 ret = handle_http_frame_settings(client);
486 break;
487 case HTTP_SERVER_FRAME_WINDOW_UPDATE_STATE:
488 ret = handle_http_frame_window_update(client);
489 break;
490 case HTTP_SERVER_FRAME_RST_STREAM_STATE:
491 ret = handle_http_frame_rst_stream(client);
492 break;
493 case HTTP_SERVER_FRAME_GOAWAY_STATE:
494 ret = handle_http_frame_goaway(client);
495 break;
496 case HTTP_SERVER_FRAME_PRIORITY_STATE:
497 ret = handle_http_frame_priority(client);
498 break;
499 case HTTP_SERVER_FRAME_PADDING_STATE:
500 ret = handle_http_frame_padding(client);
501 break;
502 case HTTP_SERVER_DONE_STATE:
503 ret = handle_http_done(client);
504 break;
505 default:
506 ret = handle_http_done(client);
507 break;
508 }
509 } while (ret >= 0 && client->data_len > 0);
510
511 if (ret < 0 && ret != -EAGAIN) {
512 return ret;
513 }
514
515 if (client->data_len > 0) {
516 /* Move any remaining data in the buffer. */
517 memmove(client->buffer, client->cursor, client->data_len);
518 }
519
520 return 0;
521 }
522
http_server_run(struct http_server_ctx * ctx)523 static int http_server_run(struct http_server_ctx *ctx)
524 {
525 struct http_client_ctx *client;
526 eventfd_t value;
527 bool found_slot;
528 int new_socket;
529 int ret, i, j;
530 int sock_error;
531 socklen_t optlen = sizeof(int);
532
533 value = 0;
534
535 while (1) {
536 ret = zsock_poll(ctx->fds, HTTP_SERVER_SOCK_COUNT, -1);
537 if (ret < 0) {
538 ret = -errno;
539 LOG_DBG("poll failed (%d)", ret);
540 goto closing;
541 }
542
543 if (ret == 0) {
544 /* should not happen because timeout is -1 */
545 break;
546 }
547
548 if (ret == 1 && ctx->fds[0].revents) {
549 eventfd_read(ctx->fds[0].fd, &value);
550 LOG_DBG("Received stop event. exiting ..");
551 ret = 0;
552 goto closing;
553 }
554
555 for (i = 1; i < ARRAY_SIZE(ctx->fds); i++) {
556 if (ctx->fds[i].fd < 0) {
557 continue;
558 }
559
560 if (ctx->fds[i].revents & ZSOCK_POLLHUP) {
561 if (i >= ctx->listen_fds) {
562 LOG_DBG("Client #%d has disconnected",
563 i - ctx->listen_fds);
564
565 client = &ctx->clients[i - ctx->listen_fds];
566 close_client_connection(client);
567 }
568
569 continue;
570 }
571
572 if (ctx->fds[i].revents & ZSOCK_POLLERR) {
573 (void)zsock_getsockopt(ctx->fds[i].fd, SOL_SOCKET,
574 SO_ERROR, &sock_error, &optlen);
575 LOG_DBG("Error on fd %d %d", ctx->fds[i].fd, sock_error);
576
577 if (i >= ctx->listen_fds) {
578 client = &ctx->clients[i - ctx->listen_fds];
579 close_client_connection(client);
580 continue;
581 }
582
583 /* Listening socket error, abort. */
584 LOG_ERR("Listening socket error, aborting.");
585 ret = -sock_error;
586 goto closing;
587
588 }
589
590 if (!(ctx->fds[i].revents & ZSOCK_POLLIN)) {
591 continue;
592 }
593
594 /* First check if we have something to accept */
595 if (i < ctx->listen_fds) {
596 new_socket = accept_new_client(ctx->fds[i].fd);
597 if (new_socket < 0) {
598 ret = -errno;
599 LOG_DBG("accept: %d", ret);
600 continue;
601 }
602
603 found_slot = false;
604
605 for (j = ctx->listen_fds; j < ARRAY_SIZE(ctx->fds); j++) {
606 if (ctx->fds[j].fd != INVALID_SOCK) {
607 continue;
608 }
609
610 ctx->fds[j].fd = new_socket;
611 ctx->fds[j].events = ZSOCK_POLLIN;
612 ctx->fds[j].revents = 0;
613
614 ctx->num_clients++;
615
616 LOG_DBG("Init client #%d", j - ctx->listen_fds);
617
618 init_client_ctx(&ctx->clients[j - ctx->listen_fds],
619 new_socket);
620 found_slot = true;
621 break;
622 }
623
624 if (!found_slot) {
625 LOG_DBG("No free slot found.");
626 zsock_close(new_socket);
627 }
628
629 continue;
630 }
631
632 /* Client sock */
633 client = &ctx->clients[i - ctx->listen_fds];
634
635 ret = zsock_recv(client->fd, client->buffer + client->data_len,
636 sizeof(client->buffer) - client->data_len, 0);
637 if (ret <= 0) {
638 if (ret == 0) {
639 LOG_DBG("Connection closed by peer for client #%d",
640 i - ctx->listen_fds);
641 } else {
642 ret = -errno;
643 LOG_DBG("ERROR reading from socket (%d)", ret);
644 }
645
646 close_client_connection(client);
647 continue;
648 }
649
650 client->data_len += ret;
651
652 http_client_timer_restart(client);
653
654 ret = handle_http_request(client);
655 if (ret < 0 && ret != -EAGAIN) {
656 if (ret == -ENOTCONN) {
657 LOG_DBG("Client closed connection while handling request");
658 } else {
659 LOG_ERR("HTTP request handling error (%d)", ret);
660 }
661 close_client_connection(client);
662 } else if (client->data_len == sizeof(client->buffer)) {
663 /* If the RX buffer is still full after parsing,
664 * it means we won't be able to handle this request
665 * with the current buffer size.
666 */
667 LOG_ERR("RX buffer too small to handle request");
668 close_client_connection(client);
669 }
670 }
671 }
672
673 return 0;
674
675 closing:
676 /* Close all client connections and the server socket */
677 close_all_sockets(ctx);
678 return ret;
679 }
680
681 /* Compare two strings where the terminator is either "\0" or "?" */
compare_strings(const char * s1,const char * s2)682 static int compare_strings(const char *s1, const char *s2)
683 {
684 while ((*s1 && *s2) && (*s1 == *s2) && (*s1 != '?')) {
685 s1++;
686 s2++;
687 }
688
689 /* Check if both strings have reached their terminators or '?' */
690 if ((*s1 == '\0' || *s1 == '?') && (*s2 == '\0' || *s2 == '?')) {
691 return 0; /* Strings are equal */
692 }
693
694 return 1; /* Strings are not equal */
695 }
696
skip_this(struct http_resource_desc * resource,bool is_websocket)697 static bool skip_this(struct http_resource_desc *resource, bool is_websocket)
698 {
699 struct http_resource_detail *detail;
700
701 detail = (struct http_resource_detail *)resource->detail;
702
703 if (is_websocket) {
704 if (detail->type != HTTP_RESOURCE_TYPE_WEBSOCKET) {
705 return true;
706 }
707 } else {
708 if (detail->type == HTTP_RESOURCE_TYPE_WEBSOCKET) {
709 return true;
710 }
711 }
712
713 return false;
714 }
715
get_resource_detail(const char * path,int * path_len,bool is_websocket)716 struct http_resource_detail *get_resource_detail(const char *path,
717 int *path_len,
718 bool is_websocket)
719 {
720 HTTP_SERVICE_FOREACH(service) {
721 HTTP_SERVICE_FOREACH_RESOURCE(service, resource) {
722 if (skip_this(resource, is_websocket)) {
723 continue;
724 }
725
726 if (IS_ENABLED(CONFIG_HTTP_SERVER_RESOURCE_WILDCARD)) {
727 int ret;
728
729 ret = fnmatch(resource->resource, path,
730 (FNM_PATHNAME | FNM_LEADING_DIR));
731 if (ret == 0) {
732 *path_len = strlen(resource->resource);
733 return resource->detail;
734 }
735 }
736
737 if (compare_strings(path, resource->resource) == 0) {
738 NET_DBG("Got match for %s", resource->resource);
739
740 *path_len = strlen(resource->resource);
741 return resource->detail;
742 }
743 }
744 }
745
746 NET_DBG("No match for %s", path);
747
748 return NULL;
749 }
750
http_server_find_file(char * fname,size_t fname_size,size_t * file_size,bool * gzipped)751 int http_server_find_file(char *fname, size_t fname_size, size_t *file_size, bool *gzipped)
752 {
753 struct fs_dirent dirent;
754 size_t len;
755 int ret;
756
757 ret = fs_stat(fname, &dirent);
758 if (ret < 0) {
759 len = strlen(fname);
760 snprintk(fname + len, fname_size - len, ".gz");
761 ret = fs_stat(fname, &dirent);
762 *gzipped = (ret == 0);
763 }
764
765 if (ret == 0) {
766 *file_size = dirent.size;
767 return ret;
768 }
769
770 return -ENOENT;
771 }
772
http_server_get_content_type_from_extension(char * url,char * content_type,size_t content_type_size)773 void http_server_get_content_type_from_extension(char *url, char *content_type,
774 size_t content_type_size)
775 {
776 size_t url_len = strlen(url);
777
778 HTTP_SERVER_CONTENT_TYPE_FOREACH(ct) {
779 char *ext;
780
781 if (url_len <= ct->extension_len) {
782 continue;
783 }
784
785 ext = &url[url_len - ct->extension_len];
786
787 if (strncmp(ext, ct->extension, ct->extension_len) == 0) {
788 strncpy(content_type, ct->content_type, content_type_size);
789 return;
790 }
791 }
792 }
793
http_server_sendall(struct http_client_ctx * client,const void * buf,size_t len)794 int http_server_sendall(struct http_client_ctx *client, const void *buf, size_t len)
795 {
796 while (len) {
797 ssize_t out_len = zsock_send(client->fd, buf, len, 0);
798
799 if (out_len < 0) {
800 return -errno;
801 }
802
803 buf = (const char *)buf + out_len;
804 len -= out_len;
805
806 http_client_timer_restart(client);
807 }
808
809 return 0;
810 }
811
http_response_is_final(struct http_response_ctx * rsp,enum http_data_status status)812 bool http_response_is_final(struct http_response_ctx *rsp, enum http_data_status status)
813 {
814 if (status != HTTP_SERVER_DATA_FINAL) {
815 return false;
816 }
817
818 if (rsp->final_chunk ||
819 (rsp->status == 0 && rsp->header_count == 0 && rsp->body_len == 0)) {
820 return true;
821 }
822
823 return false;
824 }
825
http_response_is_provided(struct http_response_ctx * rsp)826 bool http_response_is_provided(struct http_response_ctx *rsp)
827 {
828 if (rsp->status != 0 || rsp->header_count > 0 || rsp->body_len > 0) {
829 return true;
830 }
831
832 return false;
833 }
834
populate_request_ctx(struct http_request_ctx * req_ctx,uint8_t * data,size_t len,struct http_header_capture_ctx * header_ctx)835 void populate_request_ctx(struct http_request_ctx *req_ctx, uint8_t *data, size_t len,
836 struct http_header_capture_ctx *header_ctx)
837 {
838 req_ctx->data = data;
839 req_ctx->data_len = len;
840
841 if (NULL == header_ctx || header_ctx->status == HTTP_HEADER_STATUS_NONE) {
842 req_ctx->headers = NULL;
843 req_ctx->header_count = 0;
844 req_ctx->headers_status = HTTP_HEADER_STATUS_NONE;
845 } else {
846 req_ctx->headers = header_ctx->headers;
847 req_ctx->header_count = header_ctx->count;
848 req_ctx->headers_status = header_ctx->status;
849 }
850 }
851
http_server_start(void)852 int http_server_start(void)
853 {
854 if (server_running) {
855 LOG_DBG("HTTP server already started");
856 return -EALREADY;
857 }
858
859 server_running = true;
860 k_sem_give(&server_start);
861
862 LOG_DBG("Starting HTTP server");
863
864 return 0;
865 }
866
http_server_stop(void)867 int http_server_stop(void)
868 {
869 if (!server_running) {
870 LOG_DBG("HTTP server already stopped");
871 return -EALREADY;
872 }
873
874 server_running = false;
875 k_sem_reset(&server_start);
876 eventfd_write(server_ctx.fds[0].fd, 1);
877
878 LOG_DBG("Stopping HTTP server");
879
880 return 0;
881 }
882
http_server_thread(void * p1,void * p2,void * p3)883 static void http_server_thread(void *p1, void *p2, void *p3)
884 {
885 int ret;
886
887 ARG_UNUSED(p1);
888 ARG_UNUSED(p2);
889 ARG_UNUSED(p3);
890
891 while (true) {
892 k_sem_take(&server_start, K_FOREVER);
893
894 while (server_running) {
895 ret = http_server_init(&server_ctx);
896 if (ret < 0) {
897 LOG_ERR("Failed to initialize HTTP2 server");
898 goto again;
899 }
900
901 ret = http_server_run(&server_ctx);
902 if (!server_running) {
903 continue;
904 }
905
906 again:
907 LOG_INF("Re-starting server (%d)", ret);
908 k_sleep(K_MSEC(CONFIG_HTTP_SERVER_RESTART_DELAY));
909 }
910 }
911 }
912
913 K_THREAD_DEFINE(http_server_tid, CONFIG_HTTP_SERVER_STACK_SIZE,
914 http_server_thread, NULL, NULL, NULL, THREAD_PRIORITY, 0, 0);
915