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 
21 LOG_MODULE_DECLARE(net_http_server, CONFIG_NET_HTTP_SERVER_LOG_LEVEL);
22 
23 #include "headers/server_internal.h"
24 
25 static const char content_404[] = {
26 #ifdef INCLUDE_HTML_CONTENT
27 #include "not_found_page.html.gz.inc"
28 #endif
29 };
30 
is_header_flag_set(uint8_t flags,uint8_t mask)31 static bool is_header_flag_set(uint8_t flags, uint8_t mask)
32 {
33 	return (flags & mask) != 0;
34 }
35 
clear_header_flag(uint8_t * flags,uint8_t mask)36 static void clear_header_flag(uint8_t *flags, uint8_t mask)
37 {
38 	*flags &= ~mask;
39 }
40 
print_http_frames(struct http_client_ctx * client)41 static void print_http_frames(struct http_client_ctx *client)
42 {
43 #if defined(PRINT_COLOR)
44 	const char *bold = "\033[1m";
45 	const char *reset = "\033[0m";
46 	const char *green = "\033[32m";
47 	const char *blue = "\033[34m";
48 #else
49 	const char *bold = "";
50 	const char *reset = "";
51 	const char *green = "";
52 	const char *blue = "";
53 #endif
54 
55 	struct http2_frame *frame = &client->current_frame;
56 
57 	LOG_DBG("%s=====================================%s", green, reset);
58 	LOG_DBG("%sReceived %s Frame :%s", bold, get_frame_type_name(frame->type), reset);
59 	LOG_DBG("  %sLength:%s %u", blue, reset, frame->length);
60 	LOG_DBG("  %sType:%s %u (%s)", blue, reset, frame->type, get_frame_type_name(frame->type));
61 	LOG_DBG("  %sFlags:%s %u", blue, reset, frame->flags);
62 	LOG_DBG("  %sStream Identifier:%s %u", blue, reset, frame->stream_identifier);
63 	LOG_DBG("%s=====================================%s", green, reset);
64 }
65 
find_http_stream_context(struct http_client_ctx * client,uint32_t stream_id)66 static struct http2_stream_ctx *find_http_stream_context(
67 			struct http_client_ctx *client, uint32_t stream_id)
68 {
69 	ARRAY_FOR_EACH(client->streams, i) {
70 		if (client->streams[i].stream_id == stream_id) {
71 			return &client->streams[i];
72 		}
73 	}
74 
75 	return NULL;
76 }
77 
allocate_http_stream_context(struct http_client_ctx * client,uint32_t stream_id)78 static struct http2_stream_ctx *allocate_http_stream_context(
79 			struct http_client_ctx *client, uint32_t stream_id)
80 {
81 	ARRAY_FOR_EACH(client->streams, i) {
82 		if (client->streams[i].stream_state == HTTP2_STREAM_IDLE) {
83 			client->streams[i].stream_id = stream_id;
84 			client->streams[i].stream_state = HTTP2_STREAM_OPEN;
85 			client->streams[i].window_size =
86 				HTTP_SERVER_INITIAL_WINDOW_SIZE;
87 			client->streams[i].headers_sent = false;
88 			client->streams[i].end_stream_sent = false;
89 			return &client->streams[i];
90 		}
91 	}
92 
93 	return NULL;
94 }
95 
release_http_stream_context(struct http_client_ctx * client,uint32_t stream_id)96 static void release_http_stream_context(struct http_client_ctx *client,
97 					uint32_t stream_id)
98 {
99 	ARRAY_FOR_EACH(client->streams, i) {
100 		if (client->streams[i].stream_id == stream_id) {
101 			client->streams[i].stream_id = 0;
102 			client->streams[i].stream_state = HTTP2_STREAM_IDLE;
103 			client->streams[i].current_detail = NULL;
104 			break;
105 		}
106 	}
107 }
108 
add_header_field(struct http_client_ctx * client,uint8_t ** buf,size_t * buflen,const char * name,const char * value)109 static int add_header_field(struct http_client_ctx *client, uint8_t **buf,
110 			    size_t *buflen, const char *name, const char *value)
111 {
112 	int ret;
113 
114 	client->header_field.name = name;
115 	client->header_field.name_len = strlen(name);
116 	client->header_field.value = value;
117 	client->header_field.value_len = strlen(value);
118 
119 	ret = http_hpack_encode_header(*buf, *buflen, &client->header_field);
120 	if (ret < 0) {
121 		LOG_DBG("Failed to encode header, err %d", ret);
122 		return ret;
123 	}
124 
125 	*buf += ret;
126 	*buflen -= ret;
127 
128 	return 0;
129 }
130 
encode_frame_header(uint8_t * buf,uint32_t payload_len,enum http2_frame_type frame_type,uint8_t flags,uint32_t stream_id)131 static void encode_frame_header(uint8_t *buf, uint32_t payload_len,
132 				enum http2_frame_type frame_type,
133 				uint8_t flags, uint32_t stream_id)
134 {
135 	sys_put_be24(payload_len, &buf[HTTP2_FRAME_LENGTH_OFFSET]);
136 	buf[HTTP2_FRAME_TYPE_OFFSET] = frame_type;
137 	buf[HTTP2_FRAME_FLAGS_OFFSET] = flags;
138 	sys_put_be32(stream_id, &buf[HTTP2_FRAME_STREAM_ID_OFFSET]);
139 }
140 
send_headers_frame(struct http_client_ctx * client,enum http_status status,uint32_t stream_id,struct http_resource_detail * detail_common,uint8_t flags,const struct http_header * extra_headers,size_t extra_headers_count)141 static int send_headers_frame(struct http_client_ctx *client, enum http_status status,
142 			      uint32_t stream_id, struct http_resource_detail *detail_common,
143 			      uint8_t flags, const struct http_header *extra_headers,
144 			      size_t extra_headers_count)
145 {
146 	uint8_t headers_frame[CONFIG_HTTP_SERVER_HTTP2_MAX_HEADER_FRAME_LEN];
147 	uint8_t status_str[4];
148 	uint8_t *buf = headers_frame + HTTP2_FRAME_HEADER_SIZE;
149 	size_t buflen = sizeof(headers_frame) - HTTP2_FRAME_HEADER_SIZE;
150 	bool content_encoding_sent = false;
151 	bool content_type_sent = false;
152 	size_t payload_len;
153 	int ret;
154 
155 	ret = snprintf(status_str, sizeof(status_str), "%d", status);
156 	if (ret > sizeof(status_str) - 1) {
157 		return -EINVAL;
158 	}
159 
160 	ret = add_header_field(client, &buf, &buflen, ":status", status_str);
161 	if (ret < 0) {
162 		return ret;
163 	}
164 
165 	for (size_t i = 0; i < extra_headers_count; i++) {
166 		const struct http_header *hdr = &extra_headers[i];
167 
168 		if (strcasecmp(hdr->name, "content-encoding") == 0) {
169 			content_encoding_sent = true;
170 		}
171 
172 		if (strcasecmp(hdr->name, "content-type") == 0) {
173 			content_type_sent = true;
174 		}
175 
176 		ret = add_header_field(client, &buf, &buflen, hdr->name, hdr->value);
177 		if (ret < 0) {
178 			return ret;
179 		}
180 	}
181 
182 	if (!content_encoding_sent && detail_common && detail_common->content_encoding != NULL) {
183 		ret = add_header_field(client, &buf, &buflen, "content-encoding",
184 				       detail_common->content_encoding);
185 		if (ret < 0) {
186 			return ret;
187 		}
188 	}
189 
190 	if (!content_type_sent && detail_common && detail_common->content_type != NULL) {
191 		ret = add_header_field(client, &buf, &buflen, "content-type",
192 				       detail_common->content_type);
193 		if (ret < 0) {
194 			return ret;
195 		}
196 	}
197 
198 	payload_len = sizeof(headers_frame) - buflen - HTTP2_FRAME_HEADER_SIZE;
199 	flags |= HTTP2_FLAG_END_HEADERS;
200 
201 	encode_frame_header(headers_frame, payload_len, HTTP2_HEADERS_FRAME,
202 			    flags, stream_id);
203 
204 	ret = http_server_sendall(client, headers_frame,
205 				  payload_len + HTTP2_FRAME_HEADER_SIZE);
206 	if (ret < 0) {
207 		LOG_DBG("Cannot write to socket (%d)", ret);
208 		return ret;
209 	}
210 
211 	return 0;
212 }
213 
send_data_frame(struct http_client_ctx * client,const char * payload,size_t length,uint32_t stream_id,uint8_t flags)214 static int send_data_frame(struct http_client_ctx *client, const char *payload,
215 			   size_t length, uint32_t stream_id, uint8_t flags)
216 {
217 	uint8_t frame_header[HTTP2_FRAME_HEADER_SIZE];
218 	int ret;
219 
220 	encode_frame_header(frame_header, length, HTTP2_DATA_FRAME,
221 			    is_header_flag_set(flags, HTTP2_FLAG_END_STREAM) ?
222 			    HTTP2_FLAG_END_STREAM : 0,
223 			    stream_id);
224 
225 	ret = http_server_sendall(client, frame_header, sizeof(frame_header));
226 	if (ret < 0) {
227 		LOG_DBG("Cannot write to socket (%d)", ret);
228 	} else {
229 		if (payload != NULL && length > 0) {
230 			ret = http_server_sendall(client, payload, length);
231 			if (ret < 0) {
232 				LOG_DBG("Cannot write to socket (%d)", ret);
233 			}
234 		}
235 	}
236 
237 	return ret;
238 }
239 
send_settings_frame(struct http_client_ctx * client,bool ack)240 int send_settings_frame(struct http_client_ctx *client, bool ack)
241 {
242 	uint8_t settings_frame[HTTP2_FRAME_HEADER_SIZE +
243 			       2 * sizeof(struct http2_settings_field)];
244 	struct http2_settings_field *setting;
245 	size_t len;
246 	int ret;
247 
248 	if (ack) {
249 		encode_frame_header(settings_frame, 0,
250 				    HTTP2_SETTINGS_FRAME,
251 				    HTTP2_FLAG_SETTINGS_ACK, 0);
252 		len = HTTP2_FRAME_HEADER_SIZE;
253 	} else {
254 		encode_frame_header(settings_frame,
255 				    2 * sizeof(struct http2_settings_field),
256 				    HTTP2_SETTINGS_FRAME, 0, 0);
257 
258 		setting = (struct http2_settings_field *)
259 			(settings_frame + HTTP2_FRAME_HEADER_SIZE);
260 		UNALIGNED_PUT(htons(HTTP2_SETTINGS_HEADER_TABLE_SIZE),
261 			      &setting->id);
262 		UNALIGNED_PUT(0, &setting->value);
263 
264 		setting++;
265 		UNALIGNED_PUT(htons(HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS),
266 			      &setting->id);
267 		UNALIGNED_PUT(htonl(CONFIG_HTTP_SERVER_MAX_STREAMS),
268 			      &setting->value);
269 
270 		len = HTTP2_FRAME_HEADER_SIZE +
271 		      2 * sizeof(struct http2_settings_field);
272 	}
273 
274 	ret = http_server_sendall(client, settings_frame, len);
275 	if (ret < 0) {
276 		LOG_DBG("Cannot write to socket (%d)", ret);
277 		return ret;
278 	}
279 
280 	return 0;
281 }
282 
send_window_update_frame(struct http_client_ctx * client,struct http2_stream_ctx * stream)283 int send_window_update_frame(struct http_client_ctx *client,
284 			     struct http2_stream_ctx *stream)
285 {
286 	uint8_t window_update_frame[HTTP2_FRAME_HEADER_SIZE +
287 				    sizeof(uint32_t)];
288 	uint32_t window_update;
289 	uint32_t stream_id;
290 	int ret;
291 
292 	if (stream != NULL) {
293 		window_update = HTTP_SERVER_INITIAL_WINDOW_SIZE - stream->window_size;
294 		stream->window_size = HTTP_SERVER_INITIAL_WINDOW_SIZE;
295 		stream_id = stream->stream_id;
296 	} else {
297 		window_update = HTTP_SERVER_INITIAL_WINDOW_SIZE - client->window_size;
298 		client->window_size = HTTP_SERVER_INITIAL_WINDOW_SIZE;
299 		stream_id = 0;
300 	}
301 
302 	encode_frame_header(window_update_frame, sizeof(uint32_t),
303 			    HTTP2_WINDOW_UPDATE_FRAME,
304 			    0, stream_id);
305 	sys_put_be32(window_update,
306 		     window_update_frame + HTTP2_FRAME_HEADER_SIZE);
307 
308 	ret = http_server_sendall(client, window_update_frame,
309 				  sizeof(window_update_frame));
310 	if (ret < 0) {
311 		LOG_DBG("Cannot write to socket (%d)", ret);
312 		return ret;
313 	}
314 
315 	return 0;
316 }
317 
send_http2_404(struct http_client_ctx * client,struct http2_frame * frame)318 static int send_http2_404(struct http_client_ctx *client,
319 			  struct http2_frame *frame)
320 {
321 	int ret;
322 
323 	ret = send_headers_frame(client, HTTP_404_NOT_FOUND, frame->stream_identifier, NULL, 0,
324 				 NULL, 0);
325 	if (ret < 0) {
326 		LOG_DBG("Cannot write to socket (%d)", ret);
327 		return ret;
328 	}
329 
330 	ret = send_data_frame(client, content_404, sizeof(content_404),
331 			      frame->stream_identifier,
332 			      HTTP2_FLAG_END_STREAM);
333 	if (ret < 0) {
334 		LOG_DBG("Cannot write to socket (%d)", ret);
335 	}
336 
337 	return ret;
338 }
339 
send_http2_409(struct http_client_ctx * client,struct http2_frame * frame)340 static int send_http2_409(struct http_client_ctx *client,
341 			  struct http2_frame *frame)
342 {
343 	int ret;
344 
345 	ret = send_headers_frame(client, HTTP_409_CONFLICT, frame->stream_identifier, NULL,
346 				 HTTP2_FLAG_END_STREAM, NULL, 0);
347 	if (ret < 0) {
348 		LOG_DBG("Cannot write to socket (%d)", ret);
349 	}
350 
351 	return ret;
352 }
353 
handle_http2_static_resource(struct http_resource_detail_static * static_detail,struct http2_frame * frame,struct http_client_ctx * client)354 static int handle_http2_static_resource(
355 	struct http_resource_detail_static *static_detail,
356 	struct http2_frame *frame, struct http_client_ctx *client)
357 {
358 	const char *content_200;
359 	size_t content_len;
360 	int ret;
361 
362 	if (!(static_detail->common.bitmask_of_supported_http_methods & BIT(HTTP_GET))) {
363 		return -ENOTSUP;
364 	}
365 
366 	if (client->current_stream == NULL) {
367 		return -ENOENT;
368 	}
369 
370 	content_200 = static_detail->static_data;
371 	content_len = static_detail->static_data_len;
372 
373 	ret = send_headers_frame(client, HTTP_200_OK, frame->stream_identifier,
374 				 &static_detail->common, 0, NULL, 0);
375 	if (ret < 0) {
376 		LOG_DBG("Cannot write to socket (%d)", ret);
377 		goto out;
378 	}
379 
380 	client->current_stream->headers_sent = true;
381 
382 	ret = send_data_frame(client, content_200, content_len,
383 			      frame->stream_identifier,
384 			      HTTP2_FLAG_END_STREAM);
385 	if (ret < 0) {
386 		LOG_DBG("Cannot write to socket (%d)", ret);
387 		goto out;
388 	}
389 
390 	client->current_stream->end_stream_sent = true;
391 
392 out:
393 	return ret;
394 }
395 
handle_http2_static_fs_resource(struct http_resource_detail_static_fs * static_fs_detail,struct http2_frame * frame,struct http_client_ctx * client)396 static int handle_http2_static_fs_resource(struct http_resource_detail_static_fs *static_fs_detail,
397 					   struct http2_frame *frame,
398 					   struct http_client_ctx *client)
399 {
400 	int ret;
401 	struct fs_file_t file;
402 	char fname[HTTP_SERVER_MAX_URL_LENGTH];
403 	char content_type[HTTP_SERVER_MAX_CONTENT_TYPE_LEN] = "text/html";
404 	struct http_resource_detail res_detail = {
405 		.bitmask_of_supported_http_methods =
406 			static_fs_detail->common.bitmask_of_supported_http_methods,
407 		.content_type = content_type,
408 		.path_len = static_fs_detail->common.path_len,
409 		.type = static_fs_detail->common.type,
410 	};
411 	bool gzipped;
412 	int len;
413 	int remaining;
414 	char tmp[64];
415 
416 	if (!(static_fs_detail->common.bitmask_of_supported_http_methods & BIT(HTTP_GET))) {
417 		return -ENOTSUP;
418 	}
419 
420 	if (client->current_stream == NULL) {
421 		return -ENOENT;
422 	}
423 
424 	/* get filename and content-type from url */
425 	len = strlen(client->url_buffer);
426 	if (len == 1) {
427 		/* url is just the leading slash, use index.html as filename */
428 		snprintk(fname, sizeof(fname), "%s/index.html", static_fs_detail->fs_path);
429 	} else {
430 		http_server_get_content_type_from_extension(client->url_buffer, content_type,
431 							    sizeof(content_type));
432 		snprintk(fname, sizeof(fname), "%s%s", static_fs_detail->fs_path,
433 			 client->url_buffer);
434 	}
435 
436 	/* open file, if it exists */
437 	ret = http_server_find_file(fname, sizeof(fname), &client->data_len, &gzipped);
438 	if (ret < 0) {
439 		LOG_ERR("fs_stat %s: %d", fname, ret);
440 
441 		ret = send_headers_frame(client, HTTP_404_NOT_FOUND, frame->stream_identifier, NULL,
442 					 0, NULL, 0);
443 		if (ret < 0) {
444 			LOG_DBG("Cannot write to socket (%d)", ret);
445 		}
446 		return ret;
447 	}
448 	fs_file_t_init(&file);
449 	ret = fs_open(&file, fname, FS_O_READ);
450 	if (ret < 0) {
451 		LOG_ERR("fs_open %s: %d", fname, ret);
452 		if (ret < 0) {
453 			return ret;
454 		}
455 	}
456 
457 	/* send headers */
458 	if (gzipped) {
459 		res_detail.content_encoding = "gzip";
460 	}
461 	ret = send_headers_frame(client, HTTP_200_OK, frame->stream_identifier, &res_detail, 0,
462 				 NULL, 0);
463 	if (ret < 0) {
464 		LOG_DBG("Cannot write to socket (%d)", ret);
465 		goto out;
466 	}
467 
468 	client->current_stream->headers_sent = true;
469 
470 	/* read and send file */
471 	remaining = client->data_len;
472 	while (remaining > 0) {
473 		len = fs_read(&file, tmp, sizeof(tmp));
474 		if (len < 0) {
475 			LOG_ERR("Filesystem read error (%d)", len);
476 			goto out;
477 		}
478 
479 		remaining -= len;
480 		ret = send_data_frame(client, tmp, len, frame->stream_identifier,
481 				      (remaining > 0) ? 0 : HTTP2_FLAG_END_STREAM);
482 		if (ret < 0) {
483 			LOG_DBG("Cannot write to socket (%d)", ret);
484 			goto out;
485 		}
486 	}
487 
488 	client->current_stream->end_stream_sent = true;
489 
490 out:
491 	/* close file */
492 	fs_close(&file);
493 
494 	return ret;
495 }
496 
http2_dynamic_response(struct http_client_ctx * client,struct http2_frame * frame,struct http_response_ctx * rsp,enum http_data_status data_status,struct http_resource_detail_dynamic * dynamic_detail)497 static int http2_dynamic_response(struct http_client_ctx *client, struct http2_frame *frame,
498 				  struct http_response_ctx *rsp, enum http_data_status data_status,
499 				  struct http_resource_detail_dynamic *dynamic_detail)
500 {
501 	int ret;
502 	uint8_t flags = 0;
503 	bool final_response = http_response_is_final(rsp, data_status);
504 
505 	if (client->current_stream->headers_sent && (rsp->header_count > 0 || rsp->status != 0)) {
506 		LOG_WRN("Already sent headers, dropping new headers and/or response code");
507 	}
508 
509 	/* Send headers and response code if not already sent */
510 	if (!client->current_stream->headers_sent) {
511 		/* Use '200 OK' status if not specified by application */
512 		if (rsp->status == 0) {
513 			rsp->status = 200;
514 		}
515 
516 		if (rsp->status < HTTP_100_CONTINUE ||
517 		    rsp->status > HTTP_511_NETWORK_AUTHENTICATION_REQUIRED) {
518 			LOG_DBG("Invalid HTTP status code: %d", rsp->status);
519 			return -EINVAL;
520 		}
521 
522 		if (rsp->headers == NULL && rsp->header_count > 0) {
523 			LOG_DBG("NULL headers, but count is > 0");
524 			return -EINVAL;
525 		}
526 
527 		if (final_response && rsp->body_len == 0) {
528 			flags |= HTTP2_FLAG_END_STREAM;
529 			client->current_stream->end_stream_sent = true;
530 		}
531 
532 		ret = send_headers_frame(client, rsp->status, frame->stream_identifier,
533 					 (struct http_resource_detail *)dynamic_detail, flags,
534 					 rsp->headers, rsp->header_count);
535 		if (ret < 0) {
536 			return ret;
537 		}
538 
539 		client->current_stream->headers_sent = true;
540 	}
541 
542 	/* Send body data if provided */
543 	if (rsp->body != NULL && rsp->body_len > 0) {
544 		if (final_response) {
545 			flags |= HTTP2_FLAG_END_STREAM;
546 			client->current_stream->end_stream_sent = true;
547 		}
548 
549 		ret = send_data_frame(client, rsp->body, rsp->body_len, frame->stream_identifier,
550 				      flags);
551 		if (ret < 0) {
552 			return ret;
553 		}
554 	}
555 
556 	return 0;
557 }
558 
dynamic_get_del_req_v2(struct http_resource_detail_dynamic * dynamic_detail,struct http_client_ctx * client)559 static int dynamic_get_del_req_v2(struct http_resource_detail_dynamic *dynamic_detail,
560 				  struct http_client_ctx *client)
561 {
562 	int ret, len;
563 	char *ptr;
564 	struct http2_frame *frame = &client->current_frame;
565 	enum http_data_status status;
566 	struct http_request_ctx request_ctx;
567 	struct http_response_ctx response_ctx;
568 
569 	if (client->current_stream == NULL) {
570 		return -ENOENT;
571 	}
572 
573 	/* Start of GET params */
574 	ptr = &client->url_buffer[dynamic_detail->common.path_len];
575 	len = strlen(ptr);
576 	status = HTTP_SERVER_DATA_FINAL;
577 
578 	do {
579 		memset(&response_ctx, 0, sizeof(response_ctx));
580 		populate_request_ctx(&request_ctx, ptr, len, &client->header_capture_ctx);
581 
582 		ret = dynamic_detail->cb(client, status, &request_ctx, &response_ctx,
583 					 dynamic_detail->user_data);
584 		if (ret < 0) {
585 			return ret;
586 		}
587 
588 		ret = http2_dynamic_response(client, frame, &response_ctx, status, dynamic_detail);
589 		if (ret < 0) {
590 			return ret;
591 		}
592 
593 		/* URL params are passed in the first cb only */
594 		len = 0;
595 	} while (!http_response_is_final(&response_ctx, status));
596 
597 	if (!client->current_stream->end_stream_sent) {
598 		client->current_stream->end_stream_sent = true;
599 		ret = send_data_frame(client, NULL, 0, frame->stream_identifier,
600 				      HTTP2_FLAG_END_STREAM);
601 		if (ret < 0) {
602 			LOG_DBG("Cannot send last frame (%d)", ret);
603 		}
604 	}
605 
606 	dynamic_detail->holder = NULL;
607 
608 	return ret;
609 }
610 
dynamic_post_put_req_v2(struct http_resource_detail_dynamic * dynamic_detail,struct http_client_ctx * client,bool headers_only)611 static int dynamic_post_put_req_v2(struct http_resource_detail_dynamic *dynamic_detail,
612 				   struct http_client_ctx *client, bool headers_only)
613 {
614 	int ret = 0;
615 	char *ptr = client->cursor;
616 	size_t data_len;
617 	enum http_data_status status;
618 	struct http2_frame *frame = &client->current_frame;
619 	struct http_request_ctx request_ctx;
620 	struct http_response_ctx response_ctx;
621 	struct http_header_capture_ctx *request_headers_ctx =
622 		headers_only ? &client->header_capture_ctx : NULL;
623 
624 	if (dynamic_detail == NULL) {
625 		return -ENOENT;
626 	}
627 
628 	if (client->current_stream == NULL) {
629 		return -ENOENT;
630 	}
631 
632 	if (headers_only) {
633 		data_len = 0;
634 	} else {
635 		data_len = MIN(frame->length, client->data_len);
636 		frame->length -= data_len;
637 		client->cursor += data_len;
638 		client->data_len -= data_len;
639 	}
640 
641 	if (frame->length == 0 && is_header_flag_set(frame->flags, HTTP2_FLAG_END_STREAM) &&
642 	    !headers_only) {
643 		status = HTTP_SERVER_DATA_FINAL;
644 	} else {
645 		status = HTTP_SERVER_DATA_MORE;
646 	}
647 
648 	memset(&response_ctx, 0, sizeof(response_ctx));
649 	populate_request_ctx(&request_ctx, ptr, data_len, request_headers_ctx);
650 
651 	ret = dynamic_detail->cb(client, status, &request_ctx, &response_ctx,
652 				 dynamic_detail->user_data);
653 	if (ret < 0) {
654 		return ret;
655 	}
656 
657 	/* For POST the application might not send a response until all data has been received.
658 	 * Don't send a default response until the application has had a chance to respond.
659 	 */
660 	if (http_response_is_provided(&response_ctx)) {
661 		ret = http2_dynamic_response(client, frame, &response_ctx, status, dynamic_detail);
662 		if (ret < 0) {
663 			return ret;
664 		}
665 	}
666 
667 	/* Once all data is transferred to application, repeat cb until response is complete */
668 	while (!http_response_is_final(&response_ctx, status) && status == HTTP_SERVER_DATA_FINAL) {
669 		memset(&response_ctx, 0, sizeof(response_ctx));
670 		populate_request_ctx(&request_ctx, ptr, 0, request_headers_ctx);
671 
672 		ret = dynamic_detail->cb(client, status, &request_ctx, &response_ctx,
673 					 dynamic_detail->user_data);
674 		if (ret < 0) {
675 			return ret;
676 		}
677 
678 		ret = http2_dynamic_response(client, frame, &response_ctx, status, dynamic_detail);
679 		if (ret < 0) {
680 			return ret;
681 		}
682 	}
683 
684 	/* At end of stream, ensure response is sent and terminated */
685 	if (frame->length == 0 && !client->current_stream->end_stream_sent &&
686 	    is_header_flag_set(frame->flags, HTTP2_FLAG_END_STREAM)) {
687 		if (client->current_stream->headers_sent) {
688 			ret = send_data_frame(client, NULL, 0, frame->stream_identifier,
689 					      HTTP2_FLAG_END_STREAM);
690 		} else {
691 			memset(&response_ctx, 0, sizeof(response_ctx));
692 			response_ctx.final_chunk = true;
693 			ret = http2_dynamic_response(client, frame, &response_ctx,
694 						     HTTP_SERVER_DATA_FINAL, dynamic_detail);
695 		}
696 
697 		if (ret < 0) {
698 			LOG_DBG("Cannot send last frame (%d)", ret);
699 		}
700 
701 		client->current_stream->end_stream_sent = true;
702 		dynamic_detail->holder = NULL;
703 	}
704 
705 	return ret;
706 }
707 
handle_http2_dynamic_resource(struct http_resource_detail_dynamic * dynamic_detail,struct http2_frame * frame,struct http_client_ctx * client)708 static int handle_http2_dynamic_resource(
709 	struct http_resource_detail_dynamic *dynamic_detail,
710 	struct http2_frame *frame, struct http_client_ctx *client)
711 {
712 	uint32_t user_method;
713 	int ret;
714 
715 	if (dynamic_detail->cb == NULL) {
716 		return -ESRCH;
717 	}
718 
719 	user_method = dynamic_detail->common.bitmask_of_supported_http_methods;
720 
721 	if (!(BIT(client->method) & user_method)) {
722 		return -ENOPROTOOPT;
723 	}
724 
725 	if (dynamic_detail->holder != NULL && dynamic_detail->holder != client) {
726 		ret = send_http2_409(client, frame);
727 		if (ret < 0) {
728 			return ret;
729 		}
730 
731 		return enter_http_done_state(client);
732 	}
733 
734 	dynamic_detail->holder = client;
735 
736 	switch (client->method) {
737 	case HTTP_GET:
738 	case HTTP_DELETE:
739 		if (user_method & BIT(client->method)) {
740 			return dynamic_get_del_req_v2(dynamic_detail, client);
741 		}
742 
743 		goto not_supported;
744 
745 	case HTTP_POST:
746 	case HTTP_PUT:
747 	case HTTP_PATCH:
748 		/* The data will come in DATA frames. Remember the detail ptr
749 		 * which needs to be known when passing data to application.
750 		 */
751 		if (user_method & BIT(client->method)) {
752 			client->current_stream->current_detail =
753 				(struct http_resource_detail *)dynamic_detail;
754 
755 			/* If there are any header fields to pass to the application, call the
756 			 * dynamic handler now with the header data so that this may be cleared to
757 			 * re-use for any other concurrent streams
758 			 */
759 			if (IS_ENABLED(CONFIG_HTTP_SERVER_CAPTURE_HEADERS)) {
760 				ret = dynamic_post_put_req_v2(dynamic_detail, client, true);
761 				if (ret < 0) {
762 					return ret;
763 				}
764 			}
765 			break;
766 		}
767 
768 		goto not_supported;
769 
770 not_supported:
771 	default:
772 		LOG_DBG("HTTP method %s (%d) not supported.",
773 			http_method_str(client->method),
774 			client->method);
775 
776 		return -ENOTSUP;
777 	}
778 
779 	return 0;
780 }
781 
enter_http2_request(struct http_client_ctx * client)782 int enter_http2_request(struct http_client_ctx *client)
783 {
784 	int ret;
785 
786 	client->server_state = HTTP_SERVER_FRAME_HEADER_STATE;
787 	client->data_len -= sizeof(HTTP2_PREFACE) - 1;
788 	client->cursor += sizeof(HTTP2_PREFACE) - 1;
789 
790 	/* HTTP/2 client preface received, send server preface
791 	 * (settings frame).
792 	 */
793 	if (!client->preface_sent) {
794 		ret = send_settings_frame(client, false);
795 		if (ret < 0) {
796 			return ret;
797 		}
798 
799 		client->preface_sent = true;
800 	}
801 
802 	return 0;
803 }
804 
enter_http_frame_settings_state(struct http_client_ctx * client)805 static int enter_http_frame_settings_state(struct http_client_ctx *client)
806 {
807 	client->server_state = HTTP_SERVER_FRAME_SETTINGS_STATE;
808 
809 	return 0;
810 }
811 
enter_http_frame_data_state(struct http_client_ctx * client)812 static int enter_http_frame_data_state(struct http_client_ctx *client)
813 {
814 	struct http2_frame *frame = &client->current_frame;
815 	struct http2_stream_ctx *stream;
816 
817 	if (frame->stream_identifier == 0) {
818 		LOG_DBG("Stream ID 0 is forbidden for data frames.");
819 		return -EBADMSG;
820 	}
821 
822 	stream = find_http_stream_context(client, frame->stream_identifier);
823 	if (stream == NULL) {
824 		LOG_DBG("No stream context found for ID %d",
825 			frame->stream_identifier);
826 		return -EBADMSG;
827 	}
828 
829 	if (stream->stream_state != HTTP2_STREAM_OPEN &&
830 	    stream->stream_state != HTTP2_STREAM_HALF_CLOSED_REMOTE) {
831 		LOG_DBG("Stream ID %d in a wrong state %d", stream->stream_id,
832 			stream->stream_state);
833 		return -EBADMSG;
834 	}
835 
836 	stream->window_size -= frame->length;
837 	client->window_size -= frame->length;
838 	client->server_state = HTTP_SERVER_FRAME_DATA_STATE;
839 	client->current_stream = stream;
840 
841 	return 0;
842 }
843 
enter_http_frame_headers_state(struct http_client_ctx * client)844 static int enter_http_frame_headers_state(struct http_client_ctx *client)
845 {
846 	struct http2_frame *frame = &client->current_frame;
847 	struct http2_stream_ctx *stream;
848 
849 	stream = find_http_stream_context(client, frame->stream_identifier);
850 	if (!stream) {
851 		LOG_DBG("|| stream ID ||  %d", frame->stream_identifier);
852 
853 		stream = allocate_http_stream_context(client, frame->stream_identifier);
854 		if (!stream) {
855 			LOG_DBG("No available stream slots. Connection closed.");
856 
857 			return -ENOMEM;
858 		}
859 	}
860 
861 	client->current_stream = stream;
862 
863 	if (!is_header_flag_set(frame->flags, HTTP2_FLAG_END_HEADERS)) {
864 		client->expect_continuation = true;
865 	} else {
866 		client->expect_continuation = false;
867 	}
868 
869 	if (IS_ENABLED(CONFIG_HTTP_SERVER_CAPTURE_HEADERS)) {
870 		/* Reset header capture state for new headers frame */
871 		client->header_capture_ctx.count = 0;
872 		client->header_capture_ctx.cursor = 0;
873 		client->header_capture_ctx.status = HTTP_HEADER_STATUS_OK;
874 		client->header_capture_ctx.current_stream = stream;
875 	}
876 
877 	client->server_state = HTTP_SERVER_FRAME_HEADERS_STATE;
878 
879 	return 0;
880 }
881 
enter_http_frame_continuation_state(struct http_client_ctx * client)882 static int enter_http_frame_continuation_state(struct http_client_ctx *client)
883 {
884 	struct http2_frame *frame = &client->current_frame;
885 
886 	if (!is_header_flag_set(frame->flags, HTTP2_FLAG_END_HEADERS)) {
887 		client->expect_continuation = true;
888 	} else {
889 		client->expect_continuation = false;
890 	}
891 
892 	client->server_state = HTTP_SERVER_FRAME_CONTINUATION_STATE;
893 
894 	return 0;
895 }
896 
enter_http_frame_window_update_state(struct http_client_ctx * client)897 static int enter_http_frame_window_update_state(struct http_client_ctx *client)
898 {
899 	client->server_state = HTTP_SERVER_FRAME_WINDOW_UPDATE_STATE;
900 
901 	return 0;
902 }
903 
enter_http_frame_priority_state(struct http_client_ctx * client)904 static int enter_http_frame_priority_state(struct http_client_ctx *client)
905 {
906 	client->server_state = HTTP_SERVER_FRAME_PRIORITY_STATE;
907 
908 	return 0;
909 }
910 
enter_http_frame_rst_stream_state(struct http_client_ctx * client)911 static int enter_http_frame_rst_stream_state(struct http_client_ctx *client)
912 {
913 	client->server_state = HTTP_SERVER_FRAME_RST_STREAM_STATE;
914 
915 	return 0;
916 }
917 
enter_http_frame_goaway_state(struct http_client_ctx * client)918 static int enter_http_frame_goaway_state(struct http_client_ctx *client)
919 {
920 	client->server_state = HTTP_SERVER_FRAME_GOAWAY_STATE;
921 
922 	return 0;
923 }
924 
handle_http_frame_header(struct http_client_ctx * client)925 int handle_http_frame_header(struct http_client_ctx *client)
926 {
927 	int ret;
928 
929 	LOG_DBG("HTTP_SERVER_FRAME_HEADER");
930 
931 	ret = parse_http_frame_header(client, client->cursor, client->data_len);
932 	if (ret < 0) {
933 		return ret;
934 	}
935 
936 	client->cursor += HTTP2_FRAME_HEADER_SIZE;
937 	client->data_len -= HTTP2_FRAME_HEADER_SIZE;
938 
939 	print_http_frames(client);
940 
941 	if (client->expect_continuation &&
942 	    client->current_frame.type != HTTP2_CONTINUATION_FRAME) {
943 		LOG_ERR("Continuation frame expected");
944 		return -EBADMSG;
945 	}
946 
947 	client->current_stream = NULL;
948 
949 	switch (client->current_frame.type) {
950 	case HTTP2_DATA_FRAME:
951 		return enter_http_frame_data_state(client);
952 	case HTTP2_HEADERS_FRAME:
953 		return enter_http_frame_headers_state(client);
954 	case HTTP2_CONTINUATION_FRAME:
955 		return enter_http_frame_continuation_state(client);
956 	case HTTP2_SETTINGS_FRAME:
957 		return enter_http_frame_settings_state(client);
958 	case HTTP2_WINDOW_UPDATE_FRAME:
959 		return enter_http_frame_window_update_state(client);
960 	case HTTP2_RST_STREAM_FRAME:
961 		return enter_http_frame_rst_stream_state(client);
962 	case HTTP2_GOAWAY_FRAME:
963 		return enter_http_frame_goaway_state(client);
964 	case HTTP2_PRIORITY_FRAME:
965 		return enter_http_frame_priority_state(client);
966 	default:
967 		return enter_http_done_state(client);
968 	}
969 
970 	return 0;
971 }
972 
973 /* This feature is theoretically obsoleted in RFC9113, but curl for instance
974  * still uses it, so implement as described in RFC7540.
975  */
handle_http1_to_http2_upgrade(struct http_client_ctx * client)976 int handle_http1_to_http2_upgrade(struct http_client_ctx *client)
977 {
978 	static const char switching_protocols[] =
979 		"HTTP/1.1 101 Switching Protocols\r\n"
980 		"Connection: Upgrade\r\n"
981 		"Upgrade: h2c\r\n"
982 		"\r\n";
983 	struct http2_frame *frame = &client->current_frame;
984 	struct http_resource_detail *detail;
985 	struct http2_stream_ctx *stream;
986 	int path_len;
987 	int ret;
988 
989 	/* Create an artificial Data frame, so that we can proceed with HTTP2
990 	 * processing. The HTTP/1.1 request that is sent prior to upgrade is
991 	 * assigned a stream identifier of 1.
992 	 */
993 	frame->stream_identifier = 1;
994 	frame->type = HTTP2_DATA_FRAME;
995 	frame->length = client->http1_frag_data_len;
996 	if (client->parser_state == HTTP1_MESSAGE_COMPLETE_STATE) {
997 		frame->flags = HTTP2_FLAG_END_STREAM;
998 	} else {
999 		frame->flags = 0;
1000 	}
1001 
1002 	/* Allocate stream. */
1003 	stream = find_http_stream_context(client, frame->stream_identifier);
1004 	if (stream == NULL) {
1005 		stream = allocate_http_stream_context(client, frame->stream_identifier);
1006 		if (!stream) {
1007 			LOG_DBG("No available stream slots. Connection closed.");
1008 			return -ENOMEM;
1009 		}
1010 	}
1011 
1012 	client->current_stream = stream;
1013 
1014 	if (!client->preface_sent) {
1015 		ret = http_server_sendall(client, switching_protocols,
1016 					  sizeof(switching_protocols) - 1);
1017 		if (ret < 0) {
1018 			goto error;
1019 		}
1020 
1021 		/* The first HTTP/2 frame sent by the server MUST be a server connection
1022 		 * preface.
1023 		 */
1024 		ret = send_settings_frame(client, false);
1025 		if (ret < 0) {
1026 			goto error;
1027 		}
1028 
1029 		client->preface_sent = true;
1030 	}
1031 
1032 	detail = get_resource_detail(client->url_buffer, &path_len, false);
1033 	if (detail != NULL) {
1034 		detail->path_len = path_len;
1035 
1036 		if (detail->type == HTTP_RESOURCE_TYPE_STATIC) {
1037 			ret = handle_http2_static_resource(
1038 				(struct http_resource_detail_static *)detail,
1039 				frame, client);
1040 			if (ret < 0) {
1041 				goto error;
1042 			}
1043 		} else if (detail->type == HTTP_RESOURCE_TYPE_STATIC_FS) {
1044 			ret = handle_http2_static_fs_resource(
1045 				(struct http_resource_detail_static_fs *)detail, frame, client);
1046 			if (ret < 0) {
1047 				goto error;
1048 			}
1049 		} else if (detail->type == HTTP_RESOURCE_TYPE_DYNAMIC) {
1050 			ret = handle_http2_dynamic_resource(
1051 				(struct http_resource_detail_dynamic *)detail,
1052 				frame, client);
1053 			if (ret < 0) {
1054 				goto error;
1055 			}
1056 
1057 			if (client->method == HTTP_POST ||
1058 			    client->method == HTTP_PUT ||
1059 			    client->method == HTTP_PATCH) {
1060 				ret = dynamic_post_put_req_v2(
1061 					(struct http_resource_detail_dynamic *)detail, client,
1062 					false);
1063 				if (ret < 0) {
1064 					goto error;
1065 				}
1066 			}
1067 
1068 		}
1069 	} else {
1070 		ret = send_http2_404(client, frame);
1071 		if (ret < 0) {
1072 			goto error;
1073 		}
1074 	}
1075 
1076 	/* Only after the complete HTTP1 payload has been processed, switch
1077 	 * to HTTP2.
1078 	 */
1079 	if (client->parser_state == HTTP1_MESSAGE_COMPLETE_STATE) {
1080 		release_http_stream_context(client, frame->stream_identifier);
1081 		client->current_detail = NULL;
1082 		client->server_state = HTTP_SERVER_PREFACE_STATE;
1083 		client->cursor += client->data_len;
1084 		client->data_len = 0;
1085 	}
1086 
1087 	return 0;
1088 
1089 error:
1090 	return ret;
1091 }
1092 
parse_http_frame_padded_field(struct http_client_ctx * client)1093 static int parse_http_frame_padded_field(struct http_client_ctx *client)
1094 {
1095 	struct http2_frame *frame = &client->current_frame;
1096 
1097 	if (client->data_len == 0) {
1098 		return -EAGAIN;
1099 	}
1100 
1101 	frame->padding_len = *client->cursor;
1102 	client->cursor++;
1103 	client->data_len--;
1104 	frame->length--;
1105 
1106 	if (frame->length <= frame->padding_len) {
1107 		return -EBADMSG;
1108 	}
1109 
1110 	/* Subtract the padding length from frame length now to simplify
1111 	 * payload processing. Padding will be handled based on
1112 	 * frame->padding_len in a separate state.
1113 	 */
1114 	frame->length -= frame->padding_len;
1115 
1116 	/* Clear the padded flag, this indicates that padding field was
1117 	 * already parsed.
1118 	 */
1119 	clear_header_flag(&frame->flags, HTTP2_FLAG_PADDED);
1120 
1121 	return 0;
1122 }
1123 
parse_http_frame_priority_field(struct http_client_ctx * client)1124 static int parse_http_frame_priority_field(struct http_client_ctx *client)
1125 {
1126 	struct http2_frame *frame = &client->current_frame;
1127 
1128 	if (client->data_len < HTTP2_HEADERS_FRAME_PRIORITY_LEN) {
1129 		return -EAGAIN;
1130 	}
1131 
1132 	/* Priority signalling is deprecated by RFC 9113, however it still
1133 	 * should be expected to receive, just drop the bytes.
1134 	 */
1135 	client->cursor += HTTP2_HEADERS_FRAME_PRIORITY_LEN;
1136 	client->data_len -= HTTP2_HEADERS_FRAME_PRIORITY_LEN;
1137 	frame->length -= HTTP2_HEADERS_FRAME_PRIORITY_LEN;
1138 
1139 	/* Clear the priority flag, this indicates that priority field was
1140 	 * already parsed.
1141 	 */
1142 	clear_header_flag(&frame->flags, HTTP2_FLAG_PRIORITY);
1143 
1144 	return 0;
1145 }
1146 
handle_http_frame_data(struct http_client_ctx * client)1147 int handle_http_frame_data(struct http_client_ctx *client)
1148 {
1149 	struct http2_frame *frame = &client->current_frame;
1150 	int ret;
1151 
1152 	LOG_DBG("HTTP_SERVER_FRAME_DATA_STATE");
1153 
1154 	if (client->current_stream->current_detail == NULL) {
1155 		/* There is no handler */
1156 		LOG_DBG("No dynamic handler found.");
1157 		(void)send_http2_404(client, frame);
1158 		return -ENOENT;
1159 	}
1160 
1161 	if (is_header_flag_set(frame->flags, HTTP2_FLAG_PADDED)) {
1162 		ret = parse_http_frame_padded_field(client);
1163 		if (ret < 0) {
1164 			return ret;
1165 		}
1166 	}
1167 
1168 	ret = dynamic_post_put_req_v2(
1169 		(struct http_resource_detail_dynamic *)client->current_stream->current_detail,
1170 		client, false);
1171 	if (ret < 0 && ret == -ENOENT) {
1172 		ret = send_http2_404(client, frame);
1173 	}
1174 
1175 	if (ret < 0) {
1176 		return ret;
1177 	}
1178 
1179 	if (frame->length == 0) {
1180 		struct http2_stream_ctx *stream =
1181 			find_http_stream_context(client, frame->stream_identifier);
1182 
1183 		if (stream == NULL) {
1184 			LOG_DBG("No stream context found for ID %d",
1185 				frame->stream_identifier);
1186 			return -EBADMSG;
1187 		}
1188 
1189 		ret = send_window_update_frame(client, stream);
1190 		if (ret < 0) {
1191 			return ret;
1192 		}
1193 
1194 		ret = send_window_update_frame(client, NULL);
1195 		if (ret < 0) {
1196 			return ret;
1197 		}
1198 
1199 		if (is_header_flag_set(frame->flags, HTTP2_FLAG_END_STREAM)) {
1200 			client->current_stream->current_detail = NULL;
1201 			release_http_stream_context(client, frame->stream_identifier);
1202 		}
1203 
1204 		/* Whole frame consumed, expect next one. */
1205 		if (frame->padding_len > 0) {
1206 			client->server_state = HTTP_SERVER_FRAME_PADDING_STATE;
1207 		} else {
1208 			client->server_state = HTTP_SERVER_FRAME_HEADER_STATE;
1209 		}
1210 	}
1211 
1212 	return 0;
1213 }
1214 
check_user_request_headers_http2(struct http_header_capture_ctx * ctx,struct http_hpack_header_buf * hdr_buf)1215 static void check_user_request_headers_http2(struct http_header_capture_ctx *ctx,
1216 					     struct http_hpack_header_buf *hdr_buf)
1217 {
1218 	size_t required_len;
1219 	char *dest = &ctx->buffer[ctx->cursor];
1220 	size_t remaining = sizeof(ctx->buffer) - ctx->cursor;
1221 	struct http_header *current_header = &ctx->headers[ctx->count];
1222 
1223 	STRUCT_SECTION_FOREACH(http_header_name, header) {
1224 		required_len = hdr_buf->name_len + hdr_buf->value_len + 2;
1225 
1226 		if (hdr_buf->name_len == strlen(header->name) &&
1227 		    (strncasecmp(hdr_buf->name, header->name, hdr_buf->name_len) == 0)) {
1228 			if (ctx->count == ARRAY_SIZE(ctx->headers)) {
1229 				LOG_DBG("Header '%s' dropped: not enough slots", header->name);
1230 				ctx->status = HTTP_HEADER_STATUS_DROPPED;
1231 				break;
1232 			}
1233 
1234 			if (remaining < required_len) {
1235 				LOG_DBG("Header '%s' dropped: buffer too small", header->name);
1236 				ctx->status = HTTP_HEADER_STATUS_DROPPED;
1237 				break;
1238 			}
1239 
1240 			/* Copy header name from user-registered header to make HTTP1/HTTP2
1241 			 * transparent to the user - they do not need a case-insensitive comparison
1242 			 * to check which header was matched.
1243 			 */
1244 			memcpy(dest, header->name, hdr_buf->name_len);
1245 			dest[hdr_buf->name_len] = '\0';
1246 			current_header->name = dest;
1247 			ctx->cursor += (hdr_buf->name_len + 1);
1248 			dest += (hdr_buf->name_len + 1);
1249 
1250 			/* Copy header value */
1251 			memcpy(dest, hdr_buf->value, hdr_buf->value_len);
1252 			dest[hdr_buf->value_len] = '\0';
1253 			current_header->value = dest;
1254 			ctx->cursor += (hdr_buf->value_len + 1);
1255 
1256 			ctx->count++;
1257 			break;
1258 		}
1259 	}
1260 }
1261 
process_header(struct http_client_ctx * client,struct http_hpack_header_buf * header)1262 static int process_header(struct http_client_ctx *client,
1263 			  struct http_hpack_header_buf *header)
1264 {
1265 	if (IS_ENABLED(CONFIG_HTTP_SERVER_CAPTURE_HEADERS)) {
1266 		check_user_request_headers_http2(&client->header_capture_ctx, header);
1267 	}
1268 
1269 	if (header->name_len == (sizeof(":method") - 1) &&
1270 	    memcmp(header->name, ":method", header->name_len) == 0) {
1271 		const enum http_method supported_methods[] = {
1272 			HTTP_GET, HTTP_DELETE, HTTP_POST, HTTP_PUT, HTTP_PATCH
1273 		};
1274 
1275 		for (int i = 0; i < ARRAY_SIZE(supported_methods); i++) {
1276 			if ((header->value_len ==
1277 			     strlen(http_method_str(supported_methods[i]))) &&
1278 			    (memcmp(header->value,
1279 				    http_method_str(supported_methods[i]),
1280 				    header->value_len) == 0)) {
1281 				client->method = supported_methods[i];
1282 				goto out;
1283 			}
1284 		}
1285 
1286 		/* Unknown method */
1287 		return -EBADMSG;
1288 	} else if (header->name_len == (sizeof(":path") - 1) &&
1289 		   memcmp(header->name, ":path", header->name_len) == 0) {
1290 		if (header->value_len > sizeof(client->url_buffer) - 1) {
1291 			/* URL too long to handle */
1292 			return -ENOBUFS;
1293 		}
1294 
1295 		memcpy(client->url_buffer, header->value, header->value_len);
1296 		client->url_buffer[header->value_len] = '\0';
1297 	} else if (header->name_len == (sizeof("content-type") - 1) &&
1298 		   memcmp(header->name, "content-type", header->name_len) == 0) {
1299 		if (header->value_len > sizeof(client->content_type) - 1) {
1300 			/* Content-type too long to handle */
1301 			return -ENOBUFS;
1302 		}
1303 
1304 		memcpy(client->content_type, header->value, header->value_len);
1305 		client->content_type[header->value_len] = '\0';
1306 	} else if (header->name_len == (sizeof("content-length") - 1) &&
1307 		   memcmp(header->name, "content-length", header->name_len) == 0) {
1308 		char len_str[16] = { 0 };
1309 		char *endptr;
1310 		unsigned long len;
1311 
1312 		memcpy(len_str, header->value, MIN(sizeof(len_str), header->value_len));
1313 		len_str[sizeof(len_str) - 1] = '\0';
1314 
1315 		len = strtoul(len_str, &endptr, 10);
1316 		if (*endptr != '\0') {
1317 			return -EINVAL;
1318 		}
1319 
1320 		client->content_len = (size_t)len;
1321 	} else {
1322 		/* Just ignore for now. */
1323 		LOG_DBG("Ignoring field %.*s", (int)header->name_len, header->name);
1324 	}
1325 
1326 out:
1327 	return 0;
1328 }
1329 
handle_incomplete_http_header(struct http_client_ctx * client)1330 static int handle_incomplete_http_header(struct http_client_ctx *client)
1331 {
1332 	struct http2_frame *frame = &client->current_frame;
1333 	size_t extra_len, prev_frame_len;
1334 	int ret;
1335 
1336 	if (client->data_len < frame->length) {
1337 		/* Still did not receive entire frame content */
1338 		return -EAGAIN;
1339 	}
1340 
1341 	if (!client->expect_continuation) {
1342 		/* Failed to parse header field while the frame is complete
1343 		 * and no continuation frame is expected - report protocol
1344 		 * error.
1345 		 */
1346 		LOG_ERR("Incomplete header field");
1347 		return -EBADMSG;
1348 	}
1349 
1350 	/* A header field can be split between two frames, i. e. header and
1351 	 * continuation or two continuation frames. Because of this, the
1352 	 * continuation frame header can be present in the stream in between
1353 	 * header field data, so in such case we need to check for header here
1354 	 * and remove it from the stream to unblock further processing of the
1355 	 * header field.
1356 	 */
1357 	prev_frame_len = frame->length;
1358 	extra_len = client->data_len - frame->length;
1359 	ret = parse_http_frame_header(client, client->cursor + prev_frame_len,
1360 				      extra_len);
1361 	if (ret < 0) {
1362 		return -EAGAIN;
1363 	}
1364 
1365 	/* Continuation frame expected. */
1366 	if (frame->type != HTTP2_CONTINUATION_FRAME) {
1367 		LOG_ERR("Continuation frame expected");
1368 		return -EBADMSG;
1369 	}
1370 
1371 	print_http_frames(client);
1372 	/* Now remove continuation frame header from the stream, and proceed
1373 	 * with processing.
1374 	 */
1375 	extra_len -= HTTP2_FRAME_HEADER_SIZE;
1376 	client->data_len -= HTTP2_FRAME_HEADER_SIZE;
1377 	frame->length += prev_frame_len;
1378 	memmove(client->cursor + prev_frame_len,
1379 		client->cursor + prev_frame_len + HTTP2_FRAME_HEADER_SIZE,
1380 		extra_len);
1381 
1382 	return enter_http_frame_continuation_state(client);
1383 }
1384 
handle_http_frame_headers_end_stream(struct http_client_ctx * client)1385 static int handle_http_frame_headers_end_stream(struct http_client_ctx *client)
1386 {
1387 	struct http2_frame *frame = &client->current_frame;
1388 	struct http_request_ctx request_ctx;
1389 	struct http_response_ctx response_ctx;
1390 	int ret = 0;
1391 
1392 	if (client->current_stream == NULL) {
1393 		return -ENOENT;
1394 	}
1395 
1396 	if (client->current_stream->current_detail == NULL) {
1397 		goto out;
1398 	}
1399 
1400 	if (client->current_stream->current_detail->type == HTTP_RESOURCE_TYPE_DYNAMIC) {
1401 		struct http_resource_detail_dynamic *dynamic_detail =
1402 			(struct http_resource_detail_dynamic *)
1403 				client->current_stream->current_detail;
1404 
1405 		memset(&response_ctx, 0, sizeof(response_ctx));
1406 		populate_request_ctx(&request_ctx, NULL, 0, NULL);
1407 
1408 		ret = dynamic_detail->cb(client, HTTP_SERVER_DATA_FINAL, &request_ctx,
1409 					 &response_ctx, dynamic_detail->user_data);
1410 		if (ret < 0) {
1411 			dynamic_detail->holder = NULL;
1412 			goto out;
1413 		}
1414 
1415 		/* Force end stream */
1416 		response_ctx.final_chunk = true;
1417 
1418 		ret = http2_dynamic_response(client, frame, &response_ctx, HTTP_SERVER_DATA_FINAL,
1419 					     dynamic_detail);
1420 		dynamic_detail->holder = NULL;
1421 
1422 		if (ret < 0) {
1423 			goto out;
1424 		}
1425 	}
1426 
1427 	if (!client->current_stream->headers_sent) {
1428 		ret = send_headers_frame(client, HTTP_200_OK, frame->stream_identifier,
1429 					 client->current_stream->current_detail,
1430 					 HTTP2_FLAG_END_STREAM, NULL, 0);
1431 		if (ret < 0) {
1432 			LOG_DBG("Cannot write to socket (%d)", ret);
1433 			goto out;
1434 		}
1435 	} else if (!client->current_stream->end_stream_sent) {
1436 		ret = send_data_frame(client, NULL, 0, frame->stream_identifier,
1437 				      HTTP2_FLAG_END_STREAM);
1438 		if (ret < 0) {
1439 			LOG_DBG("Cannot send last frame (%d)", ret);
1440 		}
1441 	}
1442 
1443 	client->current_stream->current_detail = NULL;
1444 
1445 out:
1446 	release_http_stream_context(client, frame->stream_identifier);
1447 
1448 	return ret;
1449 }
1450 
handle_http_frame_headers(struct http_client_ctx * client)1451 int handle_http_frame_headers(struct http_client_ctx *client)
1452 {
1453 	struct http2_frame *frame = &client->current_frame;
1454 	struct http_resource_detail *detail;
1455 	int ret, path_len;
1456 
1457 	LOG_DBG("HTTP_SERVER_FRAME_HEADERS");
1458 
1459 	if (is_header_flag_set(frame->flags, HTTP2_FLAG_PADDED)) {
1460 		ret = parse_http_frame_padded_field(client);
1461 		if (ret < 0) {
1462 			return ret;
1463 		}
1464 	}
1465 
1466 	if (is_header_flag_set(frame->flags, HTTP2_FLAG_PRIORITY)) {
1467 		ret = parse_http_frame_priority_field(client);
1468 		if (ret < 0) {
1469 			return ret;
1470 		}
1471 	}
1472 
1473 	while (frame->length > 0) {
1474 		struct http_hpack_header_buf *header = &client->header_field;
1475 		size_t datalen = MIN(client->data_len, frame->length);
1476 
1477 		ret = http_hpack_decode_header(client->cursor, datalen, header);
1478 		if (ret <= 0) {
1479 			if (ret == -EAGAIN) {
1480 				ret = handle_incomplete_http_header(client);
1481 			} else if (ret == 0) {
1482 				ret = -EBADMSG;
1483 			}
1484 
1485 			return ret;
1486 		}
1487 
1488 		if (ret > frame->length) {
1489 			LOG_ERR("Protocol error, frame length exceeded");
1490 			return -EBADMSG;
1491 		}
1492 
1493 		frame->length -= ret;
1494 		client->cursor += ret;
1495 		client->data_len -= ret;
1496 
1497 		LOG_DBG("Parsed header: %.*s %.*s", (int)header->name_len,
1498 			header->name, (int)header->value_len, header->value);
1499 
1500 		ret = process_header(client, header);
1501 		if (ret < 0) {
1502 			return ret;
1503 		}
1504 	}
1505 
1506 	if (client->expect_continuation) {
1507 		/* More headers to come in the continuation frame. */
1508 		client->server_state = HTTP_SERVER_FRAME_HEADER_STATE;
1509 		return 0;
1510 	}
1511 
1512 	detail = get_resource_detail(client->url_buffer, &path_len, false);
1513 	if (detail != NULL) {
1514 		detail->path_len = path_len;
1515 
1516 		if (detail->type == HTTP_RESOURCE_TYPE_STATIC) {
1517 			ret = handle_http2_static_resource(
1518 				(struct http_resource_detail_static *)detail,
1519 				frame, client);
1520 			if (ret < 0) {
1521 				return ret;
1522 			}
1523 		} else if (detail->type == HTTP_RESOURCE_TYPE_STATIC_FS) {
1524 			ret = handle_http2_static_fs_resource(
1525 				(struct http_resource_detail_static_fs *)detail, frame, client);
1526 			if (ret < 0) {
1527 				return ret;
1528 			}
1529 		} else if (detail->type == HTTP_RESOURCE_TYPE_DYNAMIC) {
1530 			ret = handle_http2_dynamic_resource(
1531 				(struct http_resource_detail_dynamic *)detail,
1532 				frame, client);
1533 			if (ret < 0) {
1534 				return ret;
1535 			}
1536 		}
1537 
1538 	} else {
1539 		ret = send_http2_404(client, frame);
1540 		if (ret < 0) {
1541 			return ret;
1542 		}
1543 	}
1544 
1545 	if (is_header_flag_set(frame->flags, HTTP2_FLAG_END_STREAM)) {
1546 		ret = handle_http_frame_headers_end_stream(client);
1547 		if (ret < 0) {
1548 			return ret;
1549 		}
1550 	}
1551 
1552 	if (frame->padding_len > 0) {
1553 		client->server_state = HTTP_SERVER_FRAME_PADDING_STATE;
1554 	} else {
1555 		client->server_state = HTTP_SERVER_FRAME_HEADER_STATE;
1556 	}
1557 
1558 	return 0;
1559 }
1560 
handle_http_frame_priority(struct http_client_ctx * client)1561 int handle_http_frame_priority(struct http_client_ctx *client)
1562 {
1563 	struct http2_frame *frame = &client->current_frame;
1564 
1565 	LOG_DBG("HTTP_SERVER_FRAME_PRIORITY_STATE");
1566 
1567 	if (frame->length != HTTP2_PRIORITY_FRAME_LEN) {
1568 		return -EBADMSG;
1569 	}
1570 
1571 	if (client->data_len < frame->length) {
1572 		return -EAGAIN;
1573 	}
1574 
1575 	/* Priority signalling is deprecated by RFC 9113, however it still
1576 	 * should be expected to receive, just drop the bytes.
1577 	 */
1578 	client->data_len -= HTTP2_PRIORITY_FRAME_LEN;
1579 	client->cursor += HTTP2_PRIORITY_FRAME_LEN;
1580 
1581 	client->server_state = HTTP_SERVER_FRAME_HEADER_STATE;
1582 
1583 	return 0;
1584 }
1585 
handle_http_frame_rst_stream(struct http_client_ctx * client)1586 int handle_http_frame_rst_stream(struct http_client_ctx *client)
1587 {
1588 	struct http2_frame *frame = &client->current_frame;
1589 	struct http2_stream_ctx *stream_ctx;
1590 	uint32_t error_code;
1591 
1592 	LOG_DBG("FRAME_RST_STREAM");
1593 
1594 	if (frame->length != HTTP2_RST_STREAM_FRAME_LEN) {
1595 		return -EBADMSG;
1596 	}
1597 
1598 	if (client->data_len < frame->length) {
1599 		return -EAGAIN;
1600 	}
1601 
1602 	if (frame->stream_identifier == 0) {
1603 		return -EBADMSG;
1604 	}
1605 
1606 	stream_ctx = find_http_stream_context(client, frame->stream_identifier);
1607 	if (stream_ctx == NULL) {
1608 		return -EBADMSG;
1609 	}
1610 
1611 	error_code = sys_get_be32(client->cursor);
1612 
1613 	LOG_DBG("Stream %u reset with error code %u", stream_ctx->stream_id,
1614 		error_code);
1615 
1616 	release_http_stream_context(client, stream_ctx->stream_id);
1617 
1618 	client->data_len -= HTTP2_RST_STREAM_FRAME_LEN;
1619 	client->cursor += HTTP2_RST_STREAM_FRAME_LEN;
1620 
1621 	client->server_state = HTTP_SERVER_FRAME_HEADER_STATE;
1622 
1623 	return 0;
1624 }
1625 
handle_http_frame_settings(struct http_client_ctx * client)1626 int handle_http_frame_settings(struct http_client_ctx *client)
1627 {
1628 	struct http2_frame *frame = &client->current_frame;
1629 	int bytes_consumed;
1630 
1631 	LOG_DBG("HTTP_SERVER_FRAME_SETTINGS");
1632 
1633 	if (client->data_len < frame->length) {
1634 		return -EAGAIN;
1635 	}
1636 
1637 	bytes_consumed = client->current_frame.length;
1638 	client->data_len -= bytes_consumed;
1639 	client->cursor += bytes_consumed;
1640 
1641 	if (!is_header_flag_set(frame->flags, HTTP2_FLAG_SETTINGS_ACK)) {
1642 		int ret;
1643 
1644 		ret = send_settings_frame(client, true);
1645 		if (ret < 0) {
1646 			LOG_DBG("Cannot write to socket (%d)", ret);
1647 			return ret;
1648 		}
1649 	}
1650 
1651 	client->server_state = HTTP_SERVER_FRAME_HEADER_STATE;
1652 
1653 	return 0;
1654 }
1655 
handle_http_frame_goaway(struct http_client_ctx * client)1656 int handle_http_frame_goaway(struct http_client_ctx *client)
1657 {
1658 	struct http2_frame *frame = &client->current_frame;
1659 	int bytes_consumed;
1660 
1661 	LOG_DBG("HTTP_SERVER_FRAME_GOAWAY");
1662 
1663 	if (client->data_len < frame->length) {
1664 		return -EAGAIN;
1665 	}
1666 
1667 	bytes_consumed = client->current_frame.length;
1668 	client->data_len -= bytes_consumed;
1669 	client->cursor += bytes_consumed;
1670 
1671 	enter_http_done_state(client);
1672 
1673 	return 0;
1674 }
1675 
handle_http_frame_window_update(struct http_client_ctx * client)1676 int handle_http_frame_window_update(struct http_client_ctx *client)
1677 {
1678 	struct http2_frame *frame = &client->current_frame;
1679 	int bytes_consumed;
1680 
1681 	LOG_DBG("HTTP_SERVER_FRAME_WINDOW_UPDATE");
1682 
1683 	/* TODO Implement flow control, for now just ignore. */
1684 
1685 	if (client->data_len < frame->length) {
1686 		return -EAGAIN;
1687 	}
1688 
1689 	bytes_consumed = client->current_frame.length;
1690 	client->data_len -= bytes_consumed;
1691 	client->cursor += bytes_consumed;
1692 
1693 	client->server_state = HTTP_SERVER_FRAME_HEADER_STATE;
1694 
1695 	return 0;
1696 }
1697 
handle_http_frame_continuation(struct http_client_ctx * client)1698 int handle_http_frame_continuation(struct http_client_ctx *client)
1699 {
1700 	LOG_DBG("HTTP_SERVER_FRAME_CONTINUATION_STATE");
1701 	client->server_state = HTTP_SERVER_FRAME_HEADERS_STATE;
1702 
1703 	return 0;
1704 }
1705 
handle_http_frame_padding(struct http_client_ctx * client)1706 int handle_http_frame_padding(struct http_client_ctx *client)
1707 {
1708 	struct http2_frame *frame = &client->current_frame;
1709 	size_t bytes_consumed;
1710 
1711 	if (client->data_len == 0) {
1712 		return -EAGAIN;
1713 	}
1714 
1715 	bytes_consumed = MIN(client->data_len, frame->padding_len);
1716 	client->data_len -= bytes_consumed;
1717 	client->cursor += bytes_consumed;
1718 	frame->padding_len -= bytes_consumed;
1719 
1720 	if (frame->padding_len == 0) {
1721 		client->server_state = HTTP_SERVER_FRAME_HEADER_STATE;
1722 	}
1723 
1724 	return 0;
1725 }
1726 
get_frame_type_name(enum http2_frame_type type)1727 const char *get_frame_type_name(enum http2_frame_type type)
1728 {
1729 	switch (type) {
1730 	case HTTP2_DATA_FRAME:
1731 		return "DATA";
1732 	case HTTP2_HEADERS_FRAME:
1733 		return "HEADERS";
1734 	case HTTP2_PRIORITY_FRAME:
1735 		return "PRIORITY";
1736 	case HTTP2_RST_STREAM_FRAME:
1737 		return "RST_STREAM";
1738 	case HTTP2_SETTINGS_FRAME:
1739 		return "SETTINGS";
1740 	case HTTP2_PUSH_PROMISE_FRAME:
1741 		return "PUSH_PROMISE";
1742 	case HTTP2_PING_FRAME:
1743 		return "PING";
1744 	case HTTP2_GOAWAY_FRAME:
1745 		return "GOAWAY";
1746 	case HTTP2_WINDOW_UPDATE_FRAME:
1747 		return "WINDOW_UPDATE";
1748 	case HTTP2_CONTINUATION_FRAME:
1749 		return "CONTINUATION";
1750 	default:
1751 		return "UNKNOWN";
1752 	}
1753 }
1754 
parse_http_frame_header(struct http_client_ctx * client,const uint8_t * buffer,size_t buflen)1755 int parse_http_frame_header(struct http_client_ctx *client, const uint8_t *buffer,
1756 			    size_t buflen)
1757 {
1758 	struct http2_frame *frame = &client->current_frame;
1759 
1760 	if (buflen < HTTP2_FRAME_HEADER_SIZE) {
1761 		return -EAGAIN;
1762 	}
1763 
1764 	frame->length = sys_get_be24(&buffer[HTTP2_FRAME_LENGTH_OFFSET]);
1765 	frame->type = buffer[HTTP2_FRAME_TYPE_OFFSET];
1766 	frame->flags = buffer[HTTP2_FRAME_FLAGS_OFFSET];
1767 	frame->stream_identifier = sys_get_be32(
1768 				&buffer[HTTP2_FRAME_STREAM_ID_OFFSET]);
1769 	frame->stream_identifier &= HTTP2_FRAME_STREAM_ID_MASK;
1770 	frame->padding_len = 0;
1771 
1772 	LOG_DBG("Frame len %d type 0x%02x flags 0x%02x id %d",
1773 		frame->length, frame->type, frame->flags, frame->stream_identifier);
1774 
1775 	return 0;
1776 }
1777