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 #undef _POSIX_C_SOURCE
9 #define _POSIX_C_SOURCE 200809L /* Required for strnlen() */
10 
11 #include <errno.h>
12 #include <stdbool.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <strings.h>
17 
18 #include <zephyr/fs/fs.h>
19 #include <zephyr/kernel.h>
20 #include <zephyr/logging/log.h>
21 #include <zephyr/net/http/service.h>
22 #include <zephyr/net/http/server.h>
23 
24 LOG_MODULE_DECLARE(net_http_server, CONFIG_NET_HTTP_SERVER_LOG_LEVEL);
25 
26 #include "headers/server_internal.h"
27 
28 #define TEMP_BUF_LEN 64
29 
30 static const char not_found_response[] = "HTTP/1.1 404 Not Found\r\n"
31 					 "Content-Length: 9\r\n\r\n"
32 					 "Not Found";
33 static const char not_allowed_response[] = "HTTP/1.1 405 Method Not Allowed\r\n"
34 					   "Content-Length: 18\r\n\r\n"
35 					   "Method Not Allowed";
36 static const char conflict_response[] = "HTTP/1.1 409 Conflict\r\n\r\n";
37 
38 static const char final_chunk[] = "0\r\n\r\n";
39 static const char *crlf = &final_chunk[3];
40 
send_http1_error_common(struct http_client_ctx * client,const char * response,size_t len)41 static int send_http1_error_common(struct http_client_ctx *client,
42 				   const char *response, size_t len)
43 {
44 	int ret;
45 
46 	ret = http_server_sendall(client, response, len);
47 	if (ret < 0) {
48 		LOG_DBG("Cannot write to socket (%d)", ret);
49 		return ret;
50 	}
51 
52 	client->http1_headers_sent = true;
53 
54 	return 0;
55 }
56 
send_http1_404(struct http_client_ctx * client)57 static int send_http1_404(struct http_client_ctx *client)
58 {
59 	return send_http1_error_common(client, not_found_response,
60 				       sizeof(not_found_response) - 1);
61 }
62 
send_http1_405(struct http_client_ctx * client)63 static int send_http1_405(struct http_client_ctx *client)
64 {
65 	return send_http1_error_common(client, not_allowed_response,
66 				       sizeof(not_allowed_response) - 1);
67 }
68 
send_http1_409(struct http_client_ctx * client)69 static int send_http1_409(struct http_client_ctx *client)
70 {
71 	return send_http1_error_common(client, conflict_response,
72 				       sizeof(conflict_response) - 1);
73 }
74 
send_http1_500(struct http_client_ctx * client,int error_code)75 static void send_http1_500(struct http_client_ctx *client, int error_code)
76 {
77 #define HTTP_500_RESPONSE_TEMPLATE			\
78 	"HTTP/1.1 500 Internal Server Error\r\n"	\
79 	"Content-Type: text/plain\r\n"			\
80 	"Content-Length: %d\r\n\r\n"			\
81 	"Internal Server Error%s%s\r\n"
82 #define MAX_ERROR_DESC_LEN 32
83 
84 	/* Placeholder for the error description. */
85 	char error_str[] = "xxx";
86 	char http_response[sizeof(HTTP_500_RESPONSE_TEMPLATE) +
87 			   sizeof("xx") + /* Content-Length */
88 			   MAX_ERROR_DESC_LEN + 1]; /* For the error description */
89 	const char *error_desc;
90 	const char *desc_separator;
91 	int desc_len;
92 
93 	if (IS_ENABLED(CONFIG_HTTP_SERVER_REPORT_FAILURE_REASON)) {
94 		/* Try to fetch error description, fallback to error number if
95 		 * not available
96 		 */
97 		error_desc = strerror(error_code);
98 		if (strlen(error_desc) == 0) {
99 			/* Cast error value to uint8_t to avoid truncation warnings. */
100 			(void)snprintk(error_str, sizeof(error_str), "%u",
101 				       (uint8_t)error_code);
102 			error_desc = error_str;
103 		}
104 		desc_separator = ": ";
105 		desc_len = MIN(MAX_ERROR_DESC_LEN, strlen(error_desc));
106 		desc_len += 2; /* For ": " */
107 	} else {
108 		error_desc = "";
109 		desc_separator = "";
110 		desc_len = 0;
111 	}
112 
113 	(void)snprintk(http_response, sizeof(http_response),
114 		       HTTP_500_RESPONSE_TEMPLATE,
115 		       (int)sizeof("Internal Server Error\r\n") - 1 + desc_len,
116 		       desc_separator, error_desc);
117 	(void)http_server_sendall(client, http_response, strlen(http_response));
118 }
119 
handle_http1_static_resource(struct http_resource_detail_static * static_detail,struct http_client_ctx * client)120 static int handle_http1_static_resource(
121 	struct http_resource_detail_static *static_detail,
122 	struct http_client_ctx *client)
123 {
124 #define RESPONSE_TEMPLATE			\
125 	"HTTP/1.1 200 OK\r\n"			\
126 	"%s%s\r\n"				\
127 	"Content-Length: %d\r\n"
128 
129 	/* Add couple of bytes to total response */
130 	char http_response[sizeof(RESPONSE_TEMPLATE) +
131 			   sizeof("Content-Encoding: 01234567890123456789\r\n") +
132 			   sizeof("Content-Type: \r\n") + HTTP_SERVER_MAX_CONTENT_TYPE_LEN +
133 			   sizeof("xxxx") +
134 			   sizeof("\r\n")];
135 	const char *data;
136 	int len;
137 	int ret;
138 
139 	if (client->method != HTTP_GET) {
140 		return send_http1_405(client);
141 	}
142 
143 	data = static_detail->static_data;
144 	len = static_detail->static_data_len;
145 
146 	if (static_detail->common.content_encoding != NULL &&
147 	    static_detail->common.content_encoding[0] != '\0') {
148 		snprintk(http_response, sizeof(http_response),
149 			 RESPONSE_TEMPLATE "Content-Encoding: %s\r\n\r\n",
150 			 "Content-Type: ",
151 			 static_detail->common.content_type == NULL ?
152 			 "text/html" : static_detail->common.content_type,
153 			 len, static_detail->common.content_encoding);
154 	} else {
155 		snprintk(http_response, sizeof(http_response),
156 			 RESPONSE_TEMPLATE "\r\n",
157 			 "Content-Type: ",
158 			 static_detail->common.content_type == NULL ?
159 			 "text/html" : static_detail->common.content_type,
160 			 len);
161 	}
162 
163 	ret = http_server_sendall(client, http_response, strlen(http_response));
164 	if (ret < 0) {
165 		return ret;
166 	}
167 
168 	client->http1_headers_sent = true;
169 
170 	ret = http_server_sendall(client, data, len);
171 	if (ret < 0) {
172 		return ret;
173 	}
174 
175 	return 0;
176 }
177 
178 #define RESPONSE_TEMPLATE_DYNAMIC			\
179 	"HTTP/1.1 200 OK\r\n"				\
180 	"%s%s\r\n\r\n"
181 
182 #define SEND_RESPONSE(_template, _content_type)	({			\
183 	char http_response[sizeof(_template) +				\
184 			   sizeof("Content-Type: \r\n") +		\
185 			   HTTP_SERVER_MAX_CONTENT_TYPE_LEN +		\
186 			   sizeof("xxxx") +				\
187 			   sizeof("\r\n")];				\
188 	snprintk(http_response, sizeof(http_response),			\
189 		 _template,						\
190 		 "Content-Type: ",					\
191 		 _content_type == NULL ?				\
192 		 "text/html" : _content_type);				\
193 	ret = http_server_sendall(client, http_response,		\
194 				  strnlen(http_response,		\
195 					  sizeof(http_response) - 1));	\
196 	ret; })
197 
198 #define RESPONSE_TEMPLATE_DYNAMIC_PART1                                                            \
199 	"HTTP/1.1 %d\r\n"                                                                          \
200 	"Transfer-Encoding: chunked\r\n"
201 
http1_send_headers(struct http_client_ctx * client,enum http_status status,const struct http_header * headers,size_t header_count,struct http_resource_detail_dynamic * dynamic_detail)202 static int http1_send_headers(struct http_client_ctx *client, enum http_status status,
203 			      const struct http_header *headers, size_t header_count,
204 			      struct http_resource_detail_dynamic *dynamic_detail)
205 {
206 	int ret;
207 	bool content_type_sent = false;
208 	char http_response[MAX(sizeof(RESPONSE_TEMPLATE_DYNAMIC_PART1) + sizeof("xxx"),
209 			       CONFIG_HTTP_SERVER_MAX_HEADER_LEN + 2)];
210 
211 	if (status < HTTP_100_CONTINUE || status > HTTP_511_NETWORK_AUTHENTICATION_REQUIRED) {
212 		LOG_DBG("Invalid HTTP status code: %d", status);
213 		return -EINVAL;
214 	}
215 
216 	if (headers == NULL && header_count > 0) {
217 		LOG_DBG("NULL headers, but count is > 0");
218 		return -EINVAL;
219 	}
220 
221 	/* Send response code and transfer encoding */
222 	snprintk(http_response, sizeof(http_response), RESPONSE_TEMPLATE_DYNAMIC_PART1, status);
223 
224 	ret = http_server_sendall(client, http_response,
225 				  strnlen(http_response, sizeof(http_response) - 1));
226 	if (ret < 0) {
227 		LOG_DBG("Failed to send HTTP headers part 1");
228 		return ret;
229 	}
230 
231 	/* Send user-defined headers */
232 	for (size_t i = 0; i < header_count; i++) {
233 		const struct http_header *hdr = &headers[i];
234 
235 		if (strcasecmp(hdr->name, "Transfer-Encoding") == 0) {
236 			LOG_DBG("Application is not permitted to change Transfer-Encoding header");
237 			return -EACCES;
238 		}
239 
240 		if (strcasecmp(hdr->name, "Content-Type") == 0) {
241 			content_type_sent = true;
242 		}
243 
244 		snprintk(http_response, sizeof(http_response), "%s: ", hdr->name);
245 
246 		ret = http_server_sendall(client, http_response,
247 					  strnlen(http_response, sizeof(http_response) - 1));
248 		if (ret < 0) {
249 			LOG_DBG("Failed to send HTTP header name");
250 			return ret;
251 		}
252 
253 		ret = http_server_sendall(client, hdr->value, strlen(hdr->value));
254 		if (ret < 0) {
255 			LOG_DBG("Failed to send HTTP header value");
256 			return ret;
257 		}
258 
259 		ret = http_server_sendall(client, crlf, 2);
260 		if (ret < 0) {
261 			LOG_DBG("Failed to send CRLF");
262 			return ret;
263 		}
264 	}
265 
266 	/* Send content-type header if it was not already sent */
267 	if (!content_type_sent) {
268 		const char *content_type = NULL;
269 
270 		if (dynamic_detail != NULL) {
271 			content_type = dynamic_detail->common.content_type;
272 		}
273 
274 		snprintk(http_response, sizeof(http_response), "Content-Type: %s\r\n",
275 			 content_type == NULL ? "text/html" : content_type);
276 
277 		ret = http_server_sendall(client, http_response,
278 					  strnlen(http_response, sizeof(http_response) - 1));
279 		if (ret < 0) {
280 			LOG_DBG("Failed to send Content-Type");
281 			return ret;
282 		}
283 	}
284 
285 	/* Send final CRLF */
286 	ret = http_server_sendall(client, crlf, 2);
287 	if (ret < 0) {
288 		LOG_DBG("Failed to send CRLF");
289 		return ret;
290 	}
291 
292 	return ret;
293 }
294 
http1_dynamic_response(struct http_client_ctx * client,struct http_response_ctx * rsp,struct http_resource_detail_dynamic * dynamic_detail)295 static int http1_dynamic_response(struct http_client_ctx *client, struct http_response_ctx *rsp,
296 				  struct http_resource_detail_dynamic *dynamic_detail)
297 {
298 	int ret;
299 	char tmp[TEMP_BUF_LEN];
300 
301 	if (client->http1_headers_sent && (rsp->header_count > 0 || rsp->status != 0)) {
302 		LOG_WRN("Already sent headers, dropping new headers and/or response code");
303 	}
304 
305 	/* Send headers and response code if not already sent */
306 	if (!client->http1_headers_sent) {
307 		/* Use '200 OK' status if not specified by application */
308 		if (rsp->status == 0) {
309 			rsp->status = 200;
310 		}
311 
312 		ret = http1_send_headers(client, rsp->status, rsp->headers, rsp->header_count,
313 					 dynamic_detail);
314 		if (ret < 0) {
315 			return ret;
316 		}
317 
318 		client->http1_headers_sent = true;
319 	}
320 
321 	/* Send body data if provided */
322 	if (rsp->body != NULL && rsp->body_len > 0) {
323 		ret = snprintk(tmp, sizeof(tmp), "%zx\r\n", rsp->body_len);
324 		ret = http_server_sendall(client, tmp, ret);
325 		if (ret < 0) {
326 			return ret;
327 		}
328 
329 		ret = http_server_sendall(client, rsp->body, rsp->body_len);
330 		if (ret < 0) {
331 			return ret;
332 		}
333 
334 		(void)http_server_sendall(client, crlf, 2);
335 	}
336 
337 	return 0;
338 }
339 
dynamic_get_del_req(struct http_resource_detail_dynamic * dynamic_detail,struct http_client_ctx * client)340 static int dynamic_get_del_req(struct http_resource_detail_dynamic *dynamic_detail,
341 			       struct http_client_ctx *client)
342 {
343 	int ret, len;
344 	char *ptr;
345 	enum http_data_status status;
346 	struct http_request_ctx request_ctx;
347 	struct http_response_ctx response_ctx;
348 
349 	/* Start of GET params */
350 	ptr = &client->url_buffer[dynamic_detail->common.path_len];
351 	len = strlen(ptr);
352 	status = HTTP_SERVER_DATA_FINAL;
353 
354 	do {
355 		memset(&response_ctx, 0, sizeof(response_ctx));
356 		populate_request_ctx(&request_ctx, ptr, len, &client->header_capture_ctx);
357 
358 		ret = dynamic_detail->cb(client, status, &request_ctx, &response_ctx,
359 					 dynamic_detail->user_data);
360 		if (ret < 0) {
361 			return ret;
362 		}
363 
364 		ret = http1_dynamic_response(client, &response_ctx, dynamic_detail);
365 		if (ret < 0) {
366 			return ret;
367 		}
368 
369 		/* URL params are passed in the first cb only */
370 		len = 0;
371 	} while (!http_response_is_final(&response_ctx, status));
372 
373 	dynamic_detail->holder = NULL;
374 
375 	ret = http_server_sendall(client, final_chunk,
376 				  sizeof(final_chunk) - 1);
377 	if (ret < 0) {
378 		return ret;
379 	}
380 
381 	return 0;
382 }
383 
dynamic_post_put_req(struct http_resource_detail_dynamic * dynamic_detail,struct http_client_ctx * client)384 static int dynamic_post_put_req(struct http_resource_detail_dynamic *dynamic_detail,
385 				struct http_client_ctx *client)
386 {
387 	int ret;
388 	char *ptr = client->cursor;
389 	enum http_data_status status;
390 	struct http_request_ctx request_ctx;
391 	struct http_response_ctx response_ctx;
392 
393 	if (ptr == NULL) {
394 		return -ENOENT;
395 	}
396 
397 	if (client->parser_state == HTTP1_MESSAGE_COMPLETE_STATE) {
398 		status = HTTP_SERVER_DATA_FINAL;
399 	} else {
400 		status = HTTP_SERVER_DATA_MORE;
401 	}
402 
403 	memset(&response_ctx, 0, sizeof(response_ctx));
404 	populate_request_ctx(&request_ctx, ptr, client->data_len, &client->header_capture_ctx);
405 
406 	ret = dynamic_detail->cb(client, status, &request_ctx, &response_ctx,
407 				 dynamic_detail->user_data);
408 	if (ret < 0) {
409 		return ret;
410 	}
411 
412 	/* Only send request headers in first callback to application. This is not strictly
413 	 * necessary for http1, but is done for consistency with the http2 behaviour.
414 	 */
415 	client->header_capture_ctx.status = HTTP_HEADER_STATUS_NONE;
416 
417 	/* For POST the application might not send a response until all data has been received.
418 	 * Don't send a default response until the application has had a chance to respond.
419 	 */
420 	if (http_response_is_provided(&response_ctx)) {
421 		ret = http1_dynamic_response(client, &response_ctx, dynamic_detail);
422 		if (ret < 0) {
423 			return ret;
424 		}
425 	}
426 
427 	/* Once all data is transferred to application, repeat cb until response is complete */
428 	while (!http_response_is_final(&response_ctx, status) && status == HTTP_SERVER_DATA_FINAL) {
429 		memset(&response_ctx, 0, sizeof(response_ctx));
430 		populate_request_ctx(&request_ctx, ptr, 0, &client->header_capture_ctx);
431 
432 		ret = dynamic_detail->cb(client, status, &request_ctx, &response_ctx,
433 					 dynamic_detail->user_data);
434 		if (ret < 0) {
435 			return ret;
436 		}
437 
438 		ret = http1_dynamic_response(client, &response_ctx, dynamic_detail);
439 		if (ret < 0) {
440 			return ret;
441 		}
442 	}
443 
444 	/* At end of message, ensure response is sent and terminated */
445 	if (client->parser_state == HTTP1_MESSAGE_COMPLETE_STATE) {
446 		if (!client->http1_headers_sent) {
447 			memset(&response_ctx, 0, sizeof(response_ctx));
448 			response_ctx.final_chunk = true;
449 			ret = http1_dynamic_response(client, &response_ctx, dynamic_detail);
450 			if (ret < 0) {
451 				return ret;
452 			}
453 		}
454 
455 		ret = http_server_sendall(client, final_chunk,
456 					sizeof(final_chunk) - 1);
457 		if (ret < 0) {
458 			return ret;
459 		}
460 
461 		dynamic_detail->holder = NULL;
462 	}
463 
464 	return 0;
465 }
466 
467 #if defined(CONFIG_FILE_SYSTEM)
468 
handle_http1_static_fs_resource(struct http_resource_detail_static_fs * static_fs_detail,struct http_client_ctx * client)469 int handle_http1_static_fs_resource(struct http_resource_detail_static_fs *static_fs_detail,
470 				    struct http_client_ctx *client)
471 {
472 #define RESPONSE_TEMPLATE_STATIC_FS                                                                \
473 	"HTTP/1.1 200 OK\r\n"                                                                      \
474 	"Content-Length: %zd\r\n"                                                                  \
475 	"Content-Type: %s%s%s\r\n\r\n"
476 #define CONTENT_ENCODING_HEADER "\r\nContent-Encoding: "
477 /* Add couple of bytes to response template size to have space
478  * for the content type and encoding
479  */
480 #define STATIC_FS_RESPONSE_BASE_SIZE                                                               \
481 	sizeof(RESPONSE_TEMPLATE_STATIC_FS) + HTTP_SERVER_MAX_CONTENT_TYPE_LEN +                   \
482 		sizeof("Content-Length: 01234567890123456789\r\n")
483 #define CONTENT_ENCODING_HEADER_SIZE                                                               \
484 	sizeof(CONTENT_ENCODING_HEADER) + HTTP_COMPRESSION_MAX_STRING_LEN + sizeof("\r\n")
485 #define STATIC_FS_RESPONSE_SIZE                                                                    \
486 	COND_CODE_1(                                                                               \
487 		IS_ENABLED(CONFIG_HTTP_SERVER_COMPRESSION),                                        \
488 		(STATIC_FS_RESPONSE_BASE_SIZE + CONTENT_ENCODING_HEADER_SIZE),                     \
489 		(STATIC_FS_RESPONSE_BASE_SIZE))
490 
491 	enum http_compression chosen_compression = 0;
492 	int len;
493 	int remaining;
494 	int ret;
495 	size_t file_size;
496 	struct fs_file_t file;
497 	char fname[HTTP_SERVER_MAX_URL_LENGTH];
498 	char content_type[HTTP_SERVER_MAX_CONTENT_TYPE_LEN] = "text/html";
499 	char http_response[STATIC_FS_RESPONSE_SIZE];
500 
501 	if (client->method != HTTP_GET) {
502 		return send_http1_405(client);
503 	}
504 
505 	/* get filename and content-type from url */
506 	len = strlen(client->url_buffer);
507 	if (len == 1) {
508 		/* url is just the leading slash, use index.html as filename */
509 		snprintk(fname, sizeof(fname), "%s/index.html", static_fs_detail->fs_path);
510 	} else {
511 		http_server_get_content_type_from_extension(client->url_buffer, content_type,
512 							    sizeof(content_type));
513 		snprintk(fname, sizeof(fname), "%s%s", static_fs_detail->fs_path,
514 			 client->url_buffer);
515 	}
516 
517 	/* open file, if it exists */
518 #ifdef CONFIG_HTTP_SERVER_COMPRESSION
519 	ret = http_server_find_file(fname, sizeof(fname), &file_size, client->supported_compression,
520 			    &chosen_compression);
521 #else
522 	ret = http_server_find_file(fname, sizeof(fname), &file_size, 0, NULL);
523 #endif /* CONFIG_HTTP_SERVER_COMPRESSION */
524 	if (ret < 0) {
525 		LOG_ERR("fs_stat %s: %d", fname, ret);
526 		return send_http1_404(client);
527 	}
528 	fs_file_t_init(&file);
529 	ret = fs_open(&file, fname, FS_O_READ);
530 	if (ret < 0) {
531 		LOG_ERR("fs_open %s: %d", fname, ret);
532 		if (ret < 0) {
533 			return ret;
534 		}
535 	}
536 
537 	LOG_DBG("found %s, file size: %zu", fname, file_size);
538 
539 	/* send HTTP header */
540 	if (IS_ENABLED(CONFIG_HTTP_SERVER_COMPRESSION) &&
541 	    http_compression_text(chosen_compression)[0] != 0) {
542 		len = snprintk(http_response, sizeof(http_response), RESPONSE_TEMPLATE_STATIC_FS,
543 			       file_size, content_type, CONTENT_ENCODING_HEADER,
544 			       http_compression_text(chosen_compression));
545 	} else {
546 		len = snprintk(http_response, sizeof(http_response), RESPONSE_TEMPLATE_STATIC_FS,
547 			       file_size, content_type, "", "");
548 	}
549 	ret = http_server_sendall(client, http_response, len);
550 	if (ret < 0) {
551 		goto close;
552 	}
553 
554 	client->http1_headers_sent = true;
555 
556 	/* read and send file */
557 	remaining = file_size;
558 	while (remaining > 0) {
559 		len = fs_read(&file, http_response, sizeof(http_response));
560 		if (len < 0) {
561 			LOG_ERR("Filesystem read error (%d)", len);
562 			goto close;
563 		}
564 
565 		ret = http_server_sendall(client, http_response, len);
566 		if (ret < 0) {
567 			goto close;
568 		}
569 		remaining -= len;
570 	}
571 	ret = http_server_sendall(client, "\r\n\r\n", 4);
572 
573 close:
574 	/* close file */
575 	fs_close(&file);
576 
577 	return ret;
578 }
579 #endif
580 
handle_http1_dynamic_resource(struct http_resource_detail_dynamic * dynamic_detail,struct http_client_ctx * client)581 static int handle_http1_dynamic_resource(
582 	struct http_resource_detail_dynamic *dynamic_detail,
583 	struct http_client_ctx *client)
584 {
585 	uint32_t user_method;
586 	int ret;
587 
588 	if (dynamic_detail->cb == NULL) {
589 		return -ESRCH;
590 	}
591 
592 	user_method = dynamic_detail->common.bitmask_of_supported_http_methods;
593 
594 	if (!(BIT(client->method) & user_method)) {
595 		return send_http1_405(client);
596 	}
597 
598 	if (dynamic_detail->holder != NULL && dynamic_detail->holder != client) {
599 		ret = send_http1_409(client);
600 		if (ret < 0) {
601 			return ret;
602 		}
603 
604 		return enter_http_done_state(client);
605 	}
606 
607 	dynamic_detail->holder = client;
608 
609 	switch (client->method) {
610 	case HTTP_HEAD:
611 		if (user_method & BIT(HTTP_HEAD)) {
612 			ret = SEND_RESPONSE(RESPONSE_TEMPLATE_DYNAMIC,
613 					    dynamic_detail->common.content_type);
614 			if (ret < 0) {
615 				return ret;
616 			}
617 
618 			client->http1_headers_sent = true;
619 			dynamic_detail->holder = NULL;
620 
621 			return 0;
622 		}
623 
624 	case HTTP_GET:
625 	case HTTP_DELETE:
626 		/* For GET/DELETE request, we do not pass any data to the app
627 		 * but let the app send data to the peer.
628 		 */
629 		if (user_method & BIT(client->method)) {
630 			return dynamic_get_del_req(dynamic_detail, client);
631 		}
632 
633 		goto not_supported;
634 
635 	case HTTP_POST:
636 	case HTTP_PUT:
637 	case HTTP_PATCH:
638 		if (user_method & BIT(client->method)) {
639 			return dynamic_post_put_req(dynamic_detail, client);
640 		}
641 
642 		goto not_supported;
643 
644 not_supported:
645 	default:
646 		LOG_DBG("HTTP method %s (%d) not supported.",
647 			http_method_str(client->method),
648 			client->method);
649 
650 		return -ENOTSUP;
651 	}
652 
653 	return 0;
654 }
655 
check_user_request_headers(struct http_header_capture_ctx * ctx,const char * buf)656 static void check_user_request_headers(struct http_header_capture_ctx *ctx, const char *buf)
657 {
658 	size_t header_len;
659 	char *dest = &ctx->buffer[ctx->cursor];
660 	size_t remaining = sizeof(ctx->buffer) - ctx->cursor;
661 
662 	ctx->store_next_value = false;
663 
664 	STRUCT_SECTION_FOREACH(http_header_name, header) {
665 		header_len = strlen(header->name);
666 
667 		if (strcasecmp(buf, header->name) == 0) {
668 			if (ctx->count == ARRAY_SIZE(ctx->headers)) {
669 				LOG_DBG("Header '%s' dropped: not enough slots", header->name);
670 				ctx->status = HTTP_HEADER_STATUS_DROPPED;
671 				break;
672 			}
673 
674 			if (remaining < header_len + 1) {
675 				LOG_DBG("Header '%s' dropped: buffer too small for name",
676 					header->name);
677 				ctx->status = HTTP_HEADER_STATUS_DROPPED;
678 				break;
679 			}
680 
681 			strcpy(dest, header->name);
682 
683 			ctx->headers[ctx->count].name = dest;
684 			ctx->cursor += (header_len + 1);
685 			ctx->store_next_value = true;
686 			break;
687 		}
688 	}
689 }
690 
on_header_field(struct http_parser * parser,const char * at,size_t length)691 static int on_header_field(struct http_parser *parser, const char *at,
692 			   size_t length)
693 {
694 	struct http_client_ctx *ctx = CONTAINER_OF(parser,
695 						   struct http_client_ctx,
696 						   parser);
697 	size_t offset = strnlen(ctx->header_buffer, sizeof(ctx->header_buffer));
698 
699 	if (offset + length > sizeof(ctx->header_buffer) - 1U) {
700 		LOG_DBG("Header %s too long (by %zu bytes)", "field",
701 			offset + length - sizeof(ctx->header_buffer) - 1U);
702 		ctx->header_buffer[0] = '\0';
703 	} else {
704 		memcpy(ctx->header_buffer + offset, at, length);
705 		offset += length;
706 		ctx->header_buffer[offset] = '\0';
707 
708 		if (parser->state == s_header_value_discard_ws) {
709 			/* This means that the header field is fully parsed,
710 			 * and we can use it directly.
711 			 */
712 			if (IS_ENABLED(CONFIG_HTTP_SERVER_CAPTURE_HEADERS)) {
713 				check_user_request_headers(&ctx->header_capture_ctx,
714 							   ctx->header_buffer);
715 			}
716 
717 			if (strcasecmp(ctx->header_buffer, "Upgrade") == 0) {
718 				ctx->has_upgrade_header = true;
719 			} else if (strcasecmp(ctx->header_buffer, "Sec-WebSocket-Key") == 0) {
720 				ctx->websocket_sec_key_next = true;
721 			}
722 #ifdef CONFIG_HTTP_SERVER_COMPRESSION
723 			else if (strcasecmp(ctx->header_buffer, "Accept-Encoding") == 0) {
724 				ctx->accept_encoding_next = true;
725 			}
726 #endif /* CONFIG_HTTP_SERVER_COMPRESSION */
727 
728 			ctx->header_buffer[0] = '\0';
729 		}
730 	}
731 
732 	ctx->parser_state = HTTP1_RECEIVING_HEADER_STATE;
733 
734 	return 0;
735 }
736 
populate_user_request_header(struct http_header_capture_ctx * ctx,const char * buf)737 static void populate_user_request_header(struct http_header_capture_ctx *ctx, const char *buf)
738 {
739 	char *dest;
740 	size_t value_len;
741 	size_t remaining;
742 
743 	if (ctx->store_next_value == false) {
744 		return;
745 	}
746 
747 	ctx->store_next_value = false;
748 	value_len = strlen(buf);
749 	remaining = sizeof(ctx->buffer) - ctx->cursor;
750 
751 	if (value_len + 1 >= remaining) {
752 		LOG_DBG("Header '%s' dropped: buffer too small for value",
753 			ctx->headers[ctx->count].name);
754 		ctx->status = HTTP_HEADER_STATUS_DROPPED;
755 		return;
756 	}
757 
758 	dest = &ctx->buffer[ctx->cursor];
759 	strcpy(dest, buf);
760 	ctx->cursor += (value_len + 1);
761 
762 	ctx->headers[ctx->count].value = dest;
763 	ctx->count++;
764 }
765 
on_header_value(struct http_parser * parser,const char * at,size_t length)766 static int on_header_value(struct http_parser *parser,
767 			   const char *at, size_t length)
768 {
769 	struct http_client_ctx *ctx = CONTAINER_OF(parser,
770 						   struct http_client_ctx,
771 						   parser);
772 	size_t offset = strnlen(ctx->header_buffer, sizeof(ctx->header_buffer));
773 
774 	if (offset + length > sizeof(ctx->header_buffer) - 1U) {
775 		LOG_DBG("Header %s too long (by %zu bytes)", "value",
776 			offset + length - sizeof(ctx->header_buffer) - 1U);
777 		ctx->header_buffer[0] = '\0';
778 
779 		if (IS_ENABLED(CONFIG_HTTP_SERVER_CAPTURE_HEADERS) &&
780 		    ctx->header_capture_ctx.store_next_value) {
781 			ctx->header_capture_ctx.store_next_value = false;
782 			ctx->header_capture_ctx.status = HTTP_HEADER_STATUS_DROPPED;
783 		}
784 	} else {
785 		memcpy(ctx->header_buffer + offset, at, length);
786 		offset += length;
787 		ctx->header_buffer[offset] = '\0';
788 
789 		if (parser->state == s_header_almost_done) {
790 			if (IS_ENABLED(CONFIG_HTTP_SERVER_CAPTURE_HEADERS)) {
791 				populate_user_request_header(&ctx->header_capture_ctx,
792 							     ctx->header_buffer);
793 			}
794 
795 			if (ctx->has_upgrade_header) {
796 				if (strcasecmp(ctx->header_buffer, "h2c") == 0) {
797 					ctx->http2_upgrade = true;
798 				} else if (strcasecmp(ctx->header_buffer, "websocket") == 0) {
799 					ctx->websocket_upgrade = true;
800 				}
801 
802 				ctx->has_upgrade_header = false;
803 			}
804 
805 			if (ctx->websocket_sec_key_next) {
806 #if defined(CONFIG_WEBSOCKET)
807 				strncpy(ctx->ws_sec_key, ctx->header_buffer,
808 					MIN(sizeof(ctx->ws_sec_key), offset));
809 #endif
810 				ctx->websocket_sec_key_next = false;
811 			}
812 #ifdef CONFIG_HTTP_SERVER_COMPRESSION
813 			if (ctx->accept_encoding_next) {
814 				http_compression_parse_accept_encoding(ctx->header_buffer, offset,
815 								       &ctx->supported_compression);
816 				ctx->accept_encoding_next = false;
817 			}
818 #endif /* CONFIG_HTTP_SERVER_COMPRESSION */
819 
820 			ctx->header_buffer[0] = '\0';
821 		}
822 	}
823 
824 	return 0;
825 }
826 
on_headers_complete(struct http_parser * parser)827 static int on_headers_complete(struct http_parser *parser)
828 {
829 	struct http_client_ctx *ctx = CONTAINER_OF(parser,
830 						   struct http_client_ctx,
831 						   parser);
832 
833 	ctx->parser_state = HTTP1_RECEIVED_HEADER_STATE;
834 
835 	return 0;
836 }
837 
on_url(struct http_parser * parser,const char * at,size_t length)838 static int on_url(struct http_parser *parser, const char *at, size_t length)
839 {
840 	struct http_client_ctx *ctx = CONTAINER_OF(parser,
841 						   struct http_client_ctx,
842 						   parser);
843 	size_t offset = strlen(ctx->url_buffer);
844 
845 	ctx->parser_state = HTTP1_WAITING_HEADER_STATE;
846 
847 	if (offset + length > sizeof(ctx->url_buffer) - 1) {
848 		LOG_DBG("URL too long to handle");
849 		return -EMSGSIZE;
850 	}
851 
852 	memcpy(ctx->url_buffer + offset, at, length);
853 	offset += length;
854 	ctx->url_buffer[offset] = '\0';
855 
856 	return 0;
857 }
858 
on_body(struct http_parser * parser,const char * at,size_t length)859 static int on_body(struct http_parser *parser, const char *at, size_t length)
860 {
861 	struct http_client_ctx *ctx = CONTAINER_OF(parser,
862 						   struct http_client_ctx,
863 						   parser);
864 
865 	ctx->parser_state = HTTP1_RECEIVING_DATA_STATE;
866 
867 	ctx->http1_frag_data_len += length;
868 
869 	return 0;
870 }
871 
on_message_complete(struct http_parser * parser)872 static int on_message_complete(struct http_parser *parser)
873 {
874 	struct http_client_ctx *ctx = CONTAINER_OF(parser,
875 						   struct http_client_ctx,
876 						   parser);
877 
878 	ctx->parser_state = HTTP1_MESSAGE_COMPLETE_STATE;
879 
880 	return 0;
881 }
882 
enter_http1_request(struct http_client_ctx * client)883 int enter_http1_request(struct http_client_ctx *client)
884 {
885 	client->server_state = HTTP_SERVER_REQUEST_STATE;
886 
887 	http_parser_init(&client->parser, HTTP_REQUEST);
888 	http_parser_settings_init(&client->parser_settings);
889 
890 	client->parser_settings.on_header_field = on_header_field;
891 	client->parser_settings.on_header_value = on_header_value;
892 	client->parser_settings.on_headers_complete = on_headers_complete;
893 	client->parser_settings.on_url = on_url;
894 	client->parser_settings.on_body = on_body;
895 	client->parser_settings.on_message_complete = on_message_complete;
896 	client->parser_state = HTTP1_INIT_HEADER_STATE;
897 	client->http1_headers_sent = false;
898 
899 	if (IS_ENABLED(CONFIG_HTTP_SERVER_CAPTURE_HEADERS)) {
900 		client->header_capture_ctx.store_next_value = false;
901 	}
902 
903 	memset(client->header_buffer, 0, sizeof(client->header_buffer));
904 	memset(client->url_buffer, 0, sizeof(client->url_buffer));
905 
906 	return 0;
907 }
908 
handle_http1_request(struct http_client_ctx * client)909 int handle_http1_request(struct http_client_ctx *client)
910 {
911 	int ret, path_len = 0;
912 	struct http_resource_detail *detail;
913 	bool skip_headers = (client->parser_state < HTTP1_RECEIVING_DATA_STATE);
914 	size_t parsed;
915 
916 	LOG_DBG("HTTP_SERVER_REQUEST");
917 
918 	client->http1_frag_data_len = 0;
919 
920 	parsed = http_parser_execute(&client->parser, &client->parser_settings,
921 				     client->cursor, client->data_len);
922 
923 	if (parsed > client->data_len) {
924 		LOG_ERR("HTTP/1 parser error, too much data consumed");
925 		ret = -EBADMSG;
926 		goto error;
927 	}
928 
929 	if (client->parser.http_errno != HPE_OK) {
930 		LOG_ERR("HTTP/1 parsing error, %d", client->parser.http_errno);
931 		ret = -EBADMSG;
932 		goto error;
933 	}
934 
935 	if (client->parser_state < HTTP1_RECEIVED_HEADER_STATE) {
936 		client->cursor += parsed;
937 		client->data_len -= parsed;
938 
939 		return 0;
940 	}
941 
942 	client->method = client->parser.method;
943 	client->has_upgrade_header = client->parser.upgrade;
944 
945 	if (skip_headers) {
946 		LOG_DBG("Requested URL: %s", client->url_buffer);
947 
948 		size_t frag_headers_len;
949 
950 		if (parsed < client->http1_frag_data_len) {
951 			ret = -EBADMSG;
952 			goto error;
953 		}
954 
955 		frag_headers_len = parsed - client->http1_frag_data_len;
956 		parsed -= frag_headers_len;
957 
958 		client->cursor += frag_headers_len;
959 		client->data_len -= frag_headers_len;
960 	}
961 
962 	if (client->has_upgrade_header) {
963 		static const char upgrade_required[] =
964 			"HTTP/1.1 426 Upgrade required\r\n"
965 			"Upgrade: ";
966 		static const char upgrade_msg[] =
967 			"Content-Length: 13\r\n\r\n"
968 			"Wrong upgrade";
969 		const char *needed_upgrade = "h2c\r\n";
970 
971 		if (client->websocket_upgrade) {
972 			if (IS_ENABLED(CONFIG_HTTP_SERVER_WEBSOCKET)) {
973 				detail = get_resource_detail(client->service, client->url_buffer,
974 							     &path_len, true);
975 				if (detail == NULL) {
976 					goto not_found;
977 				}
978 
979 				detail->path_len = path_len;
980 				client->current_detail = detail;
981 
982 				ret = handle_http1_to_websocket_upgrade(client);
983 				if (ret < 0) {
984 					goto error;
985 				}
986 
987 				return 0;
988 			}
989 
990 			goto upgrade_not_found;
991 		}
992 
993 		if (client->http2_upgrade) {
994 			ret = handle_http1_to_http2_upgrade(client);
995 			if (ret < 0) {
996 				goto error;
997 			}
998 
999 			return 0;
1000 		}
1001 
1002 upgrade_not_found:
1003 		ret = http_server_sendall(client, upgrade_required,
1004 					  sizeof(upgrade_required) - 1);
1005 		if (ret < 0) {
1006 			LOG_DBG("Cannot write to socket (%d)", ret);
1007 			goto error;
1008 		}
1009 
1010 		client->http1_headers_sent = true;
1011 
1012 		ret = http_server_sendall(client, needed_upgrade,
1013 					  strlen(needed_upgrade));
1014 		if (ret < 0) {
1015 			LOG_DBG("Cannot write to socket (%d)", ret);
1016 			goto error;
1017 		}
1018 
1019 		ret = http_server_sendall(client, upgrade_msg,
1020 					  sizeof(upgrade_msg) - 1);
1021 		if (ret < 0) {
1022 			LOG_DBG("Cannot write to socket (%d)", ret);
1023 			goto error;
1024 		}
1025 	}
1026 
1027 	detail = get_resource_detail(client->service, client->url_buffer, &path_len, false);
1028 	if (detail != NULL) {
1029 		detail->path_len = path_len;
1030 
1031 		if (detail->type == HTTP_RESOURCE_TYPE_STATIC) {
1032 			ret = handle_http1_static_resource(
1033 				(struct http_resource_detail_static *)detail,
1034 				client);
1035 			if (ret < 0) {
1036 				goto error;
1037 			}
1038 #if defined(CONFIG_FILE_SYSTEM)
1039 		} else if (detail->type == HTTP_RESOURCE_TYPE_STATIC_FS) {
1040 			ret = handle_http1_static_fs_resource(
1041 				(struct http_resource_detail_static_fs *)detail, client);
1042 			if (ret < 0) {
1043 				goto error;
1044 			}
1045 #endif
1046 		} else if (detail->type == HTTP_RESOURCE_TYPE_DYNAMIC) {
1047 			ret = handle_http1_dynamic_resource(
1048 				(struct http_resource_detail_dynamic *)detail,
1049 				client);
1050 			if (ret < 0) {
1051 				goto error;
1052 			}
1053 		}
1054 	} else {
1055 not_found: ; /* Add extra semicolon to make clang to compile when using label */
1056 		ret = send_http1_404(client);
1057 		if (ret < 0) {
1058 			goto error;
1059 		}
1060 
1061 		client->http1_headers_sent = true;
1062 	}
1063 
1064 	client->cursor += parsed;
1065 	client->data_len -= parsed;
1066 
1067 	if (client->parser_state == HTTP1_MESSAGE_COMPLETE_STATE) {
1068 		if ((client->parser.flags & F_CONNECTION_CLOSE) == 0) {
1069 			LOG_DBG("Waiting for another request, client %p", client);
1070 			client->server_state = HTTP_SERVER_PREFACE_STATE;
1071 		} else {
1072 			LOG_DBG("Connection closed, client %p", client);
1073 			enter_http_done_state(client);
1074 		}
1075 	}
1076 
1077 	return 0;
1078 
1079 error:
1080 	/* Best effort try to send HTTP 500 Internal Server Error response in
1081 	 * case of errors. This can only be done however if we haven't sent
1082 	 * response header elsewhere (i. e. can't send another reply if the
1083 	 * error ocurred amid resource processing).
1084 	 */
1085 	if (ret != -EAGAIN && !client->http1_headers_sent) {
1086 		send_http1_500(client, -ret);
1087 	}
1088 
1089 	return ret;
1090 }
1091