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