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