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