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