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