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