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 #ifndef ZEPHYR_INCLUDE_NET_HTTP_SERVER_H_
9 #define ZEPHYR_INCLUDE_NET_HTTP_SERVER_H_
10 
11 /**
12  * @file server.h
13  *
14  * @brief HTTP server API
15  *
16  * @defgroup http_server HTTP server API
17  * @since 3.7
18  * @version 0.1.0
19  * @ingroup networking
20  * @{
21  */
22 
23 #include <stdint.h>
24 
25 #include <zephyr/kernel.h>
26 #include <zephyr/net/http/parser.h>
27 #include <zephyr/net/http/hpack.h>
28 #include <zephyr/net/http/status.h>
29 #include <zephyr/net/socket.h>
30 #include <zephyr/sys/iterable_sections.h>
31 
32 #ifdef __cplusplus
33 extern "C" {
34 #endif
35 
36 /** @cond INTERNAL_HIDDEN */
37 
38 #if defined(CONFIG_HTTP_SERVER)
39 #define HTTP_SERVER_CLIENT_BUFFER_SIZE   CONFIG_HTTP_SERVER_CLIENT_BUFFER_SIZE
40 #define HTTP_SERVER_MAX_STREAMS          CONFIG_HTTP_SERVER_MAX_STREAMS
41 #define HTTP_SERVER_MAX_CONTENT_TYPE_LEN CONFIG_HTTP_SERVER_MAX_CONTENT_TYPE_LENGTH
42 #define HTTP_SERVER_MAX_URL_LENGTH       CONFIG_HTTP_SERVER_MAX_URL_LENGTH
43 #define HTTP_SERVER_MAX_HEADER_LEN       CONFIG_HTTP_SERVER_MAX_HEADER_LEN
44 #else
45 #define HTTP_SERVER_CLIENT_BUFFER_SIZE   0
46 #define HTTP_SERVER_MAX_STREAMS          0
47 #define HTTP_SERVER_MAX_CONTENT_TYPE_LEN 0
48 #define HTTP_SERVER_MAX_URL_LENGTH       0
49 #define HTTP_SERVER_MAX_HEADER_LEN       0
50 #endif
51 
52 #if defined(CONFIG_HTTP_SERVER_CAPTURE_HEADERS)
53 #define HTTP_SERVER_CAPTURE_HEADER_BUFFER_SIZE CONFIG_HTTP_SERVER_CAPTURE_HEADER_BUFFER_SIZE
54 #define HTTP_SERVER_CAPTURE_HEADER_COUNT       CONFIG_HTTP_SERVER_CAPTURE_HEADER_COUNT
55 #else
56 #define HTTP_SERVER_CAPTURE_HEADER_BUFFER_SIZE 0
57 #define HTTP_SERVER_CAPTURE_HEADER_COUNT       0
58 #endif
59 
60 #define HTTP2_PREFACE "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
61 
62 /** @endcond */
63 
64 /**
65  *  @brief HTTP server resource type.
66  */
67 enum http_resource_type {
68 	/** Static resource, cannot be modified on runtime. */
69 	HTTP_RESOURCE_TYPE_STATIC,
70 
71 	/** serves static gzipped files from a filesystem */
72 	HTTP_RESOURCE_TYPE_STATIC_FS,
73 
74 	/** Dynamic resource, server interacts with the application via registered
75 	 *  @ref http_resource_dynamic_cb_t.
76 	 */
77 	HTTP_RESOURCE_TYPE_DYNAMIC,
78 
79 	/** Websocket resource, application takes control over Websocket connection
80 	 *  after and upgrade.
81 	 */
82 	HTTP_RESOURCE_TYPE_WEBSOCKET,
83 };
84 
85 /**
86  * @brief Representation of a server resource, common for all resource types.
87  */
88 struct http_resource_detail {
89 	/** Bitmask of supported HTTP methods (@ref http_method). */
90 	uint32_t bitmask_of_supported_http_methods;
91 
92 	/** Resource type. */
93 	enum http_resource_type type;
94 
95 	/** Length of the URL path. */
96 	int path_len;
97 
98 	/** Content encoding of the resource. */
99 	const char *content_encoding;
100 
101 	/** Content type of the resource. */
102 	const char *content_type;
103 };
104 
105 /** @cond INTERNAL_HIDDEN */
106 BUILD_ASSERT(NUM_BITS(
107 	     sizeof(((struct http_resource_detail *)0)->bitmask_of_supported_http_methods))
108 	     >= (HTTP_METHOD_END_VALUE - 1));
109 /** @endcond */
110 
111 /**
112  * @brief Representation of a static server resource.
113  */
114 struct http_resource_detail_static {
115 	/** Common resource details. */
116 	struct http_resource_detail common;
117 
118 	/** Content of the static resource. */
119 	const void *static_data;
120 
121 	/** Size of the static resource. */
122 	size_t static_data_len;
123 };
124 
125 /** @cond INTERNAL_HIDDEN */
126 /* Make sure that the common is the first in the struct. */
127 BUILD_ASSERT(offsetof(struct http_resource_detail_static, common) == 0);
128 /** @endcond */
129 
130 /**
131  * @brief Representation of a static filesystem server resource.
132  */
133 struct http_resource_detail_static_fs {
134 	/** Common resource details. */
135 	struct http_resource_detail common;
136 
137 	/** Path in the local filesystem */
138 	const char *fs_path;
139 };
140 
141 /** @brief HTTP compressions */
142 enum http_compression {
143 	HTTP_NONE = 0,     /**< NONE */
144 	HTTP_GZIP = 1,     /**< GZIP */
145 	HTTP_COMPRESS = 2, /**< COMPRESS */
146 	HTTP_DEFLATE = 3,  /**< DEFLATE */
147 	HTTP_BR = 4,       /**< BR */
148 	HTTP_ZSTD = 5      /**< ZSTD */
149 };
150 
151 /** @cond INTERNAL_HIDDEN */
152 /* Make sure that the common is the first in the struct. */
153 BUILD_ASSERT(offsetof(struct http_resource_detail_static_fs, common) == 0);
154 /** @endcond */
155 
156 struct http_content_type {
157 	const char *extension;
158 	size_t extension_len;
159 	const char *content_type;
160 };
161 
162 #define HTTP_SERVER_CONTENT_TYPE(_extension, _content_type)                                        \
163 	const STRUCT_SECTION_ITERABLE(http_content_type, _extension) = {                           \
164 		.extension = STRINGIFY(_extension),                                                \
165 		.extension_len = sizeof(STRINGIFY(_extension)) - 1,                                \
166 		.content_type = _content_type,                                                     \
167 	};
168 
169 #define HTTP_SERVER_CONTENT_TYPE_FOREACH(_it) STRUCT_SECTION_FOREACH(http_content_type, _it)
170 
171 struct http_client_ctx;
172 
173 /** Indicates the status of the currently processed piece of data.  */
174 enum http_data_status {
175 	/** Transaction aborted, data incomplete. */
176 	HTTP_SERVER_DATA_ABORTED = -1,
177 	/** Transaction incomplete, more data expected. */
178 	HTTP_SERVER_DATA_MORE = 0,
179 	/** Final data fragment in current transaction. */
180 	HTTP_SERVER_DATA_FINAL = 1,
181 };
182 
183 /** @brief Status of captured request headers */
184 enum http_header_status {
185 	HTTP_HEADER_STATUS_OK,      /**< All available headers were successfully captured. */
186 	HTTP_HEADER_STATUS_DROPPED, /**< One or more headers were dropped due to lack of space. */
187 	HTTP_HEADER_STATUS_NONE,    /**< No header status is available. */
188 };
189 
190 /** @brief HTTP header representation */
191 struct http_header {
192 	const char *name;  /**< Pointer to header name NULL-terminated string. */
193 	const char *value; /**< Pointer to header value NULL-terminated string. */
194 };
195 
196 /** @brief HTTP request context */
197 struct http_request_ctx {
198 	uint8_t *data;                          /**< HTTP request data */
199 	size_t data_len;                        /**< Length of HTTP request data */
200 	struct http_header *headers;            /**< Array of HTTP request headers */
201 	size_t header_count;                    /**< Array length of HTTP request headers */
202 	enum http_header_status headers_status; /**< Status of HTTP request headers */
203 };
204 
205 /** @brief HTTP response context */
206 struct http_response_ctx {
207 	enum http_status status;           /**< HTTP status code to include in response */
208 	const struct http_header *headers; /**< Array of HTTP headers */
209 	size_t header_count;               /**< Length of headers array */
210 	const uint8_t *body;               /**< Pointer to body data */
211 	size_t body_len;                   /**< Length of body data */
212 	bool final_chunk; /**< Flag set to true when the application has no more data to send */
213 };
214 
215 /**
216  * @typedef http_resource_dynamic_cb_t
217  * @brief Callback used when data is received. Data to be sent to client
218  *        can be specified.
219  *
220  * @param client HTTP context information for this client connection.
221  * @param status HTTP data status, indicate whether more data is expected or not.
222  * @param request_ctx Request context structure containing HTTP request data that was received.
223  * @param response_ctx Response context structure for application to populate with response data.
224  * @param user_data User specified data.
225  *
226  * @return 0 success, server can send any response data provided in the response_ctx.
227  *         <0 error, close the connection.
228  */
229 typedef int (*http_resource_dynamic_cb_t)(struct http_client_ctx *client,
230 					  enum http_data_status status,
231 					  const struct http_request_ctx *request_ctx,
232 					  struct http_response_ctx *response_ctx,
233 					  void *user_data);
234 
235 /**
236  * @brief Representation of a dynamic server resource.
237  */
238 struct http_resource_detail_dynamic {
239 	/** Common resource details. */
240 	struct http_resource_detail common;
241 
242 	/** Resource callback used by the server to interact with the
243 	 *  application.
244 	 */
245 	http_resource_dynamic_cb_t cb;
246 
247 	/** A pointer to the client currently processing resource, used to
248 	 *  prevent concurrent access to the resource from multiple clients.
249 	 */
250 	struct http_client_ctx *holder;
251 
252 	/** A pointer to the user data registered by the application.  */
253 	void *user_data;
254 };
255 
256 /** @cond INTERNAL_HIDDEN */
257 BUILD_ASSERT(offsetof(struct http_resource_detail_dynamic, common) == 0);
258 /** @endcond */
259 
260 /**
261  * @typedef http_resource_websocket_cb_t
262  * @brief Callback used when a Websocket connection is setup. The application
263  *        will need to handle all functionality related to the connection like
264  *        reading and writing websocket data, and closing the connection.
265  *
266  * @param ws_socket A socket for the Websocket data.
267  * @param request_ctx Request context structure associated with HTTP upgrade request
268  * @param user_data User specified data.
269  *
270  * @return  0 Accepting the connection, HTTP server library will no longer
271  *            handle data to/from the socket and it is application responsibility
272  *            to send and receive data to/from the supplied socket.
273  *         <0 error, close the connection.
274  */
275 typedef int (*http_resource_websocket_cb_t)(int ws_socket, struct http_request_ctx *request_ctx,
276 					    void *user_data);
277 
278 /** @brief Representation of a websocket server resource */
279 struct http_resource_detail_websocket {
280 	/** Common resource details. */
281 	struct http_resource_detail common;
282 
283 	/** Websocket socket value */
284 	int ws_sock;
285 
286 	/** Resource callback used by the server to interact with the
287 	 *  application.
288 	 */
289 	http_resource_websocket_cb_t cb;
290 
291 	/** Data buffer used to exchanged data between server and the,
292 	 *  application.
293 	 */
294 	uint8_t *data_buffer;
295 
296 	/** Length of the data in the data buffer. */
297 	size_t data_buffer_len;
298 
299 	/** A pointer to the user data registered by the application.  */
300 	void *user_data;
301 };
302 
303 /** @cond INTERNAL_HIDDEN */
304 BUILD_ASSERT(offsetof(struct http_resource_detail_websocket, common) == 0);
305 /** @endcond */
306 
307 /** @cond INTERNAL_HIDDEN */
308 
309 enum http2_stream_state {
310 	HTTP2_STREAM_IDLE,
311 	HTTP2_STREAM_RESERVED_LOCAL,
312 	HTTP2_STREAM_RESERVED_REMOTE,
313 	HTTP2_STREAM_OPEN,
314 	HTTP2_STREAM_HALF_CLOSED_LOCAL,
315 	HTTP2_STREAM_HALF_CLOSED_REMOTE,
316 	HTTP2_STREAM_CLOSED
317 };
318 
319 enum http_server_state {
320 	HTTP_SERVER_FRAME_HEADER_STATE,
321 	HTTP_SERVER_PREFACE_STATE,
322 	HTTP_SERVER_REQUEST_STATE,
323 	HTTP_SERVER_FRAME_DATA_STATE,
324 	HTTP_SERVER_FRAME_HEADERS_STATE,
325 	HTTP_SERVER_FRAME_SETTINGS_STATE,
326 	HTTP_SERVER_FRAME_PRIORITY_STATE,
327 	HTTP_SERVER_FRAME_WINDOW_UPDATE_STATE,
328 	HTTP_SERVER_FRAME_CONTINUATION_STATE,
329 	HTTP_SERVER_FRAME_PING_STATE,
330 	HTTP_SERVER_FRAME_RST_STREAM_STATE,
331 	HTTP_SERVER_FRAME_GOAWAY_STATE,
332 	HTTP_SERVER_FRAME_PADDING_STATE,
333 	HTTP_SERVER_DONE_STATE,
334 };
335 
336 enum http1_parser_state {
337 	HTTP1_INIT_HEADER_STATE,
338 	HTTP1_WAITING_HEADER_STATE,
339 	HTTP1_RECEIVING_HEADER_STATE,
340 	HTTP1_RECEIVED_HEADER_STATE,
341 	HTTP1_RECEIVING_DATA_STATE,
342 	HTTP1_MESSAGE_COMPLETE_STATE,
343 };
344 
345 #define HTTP_SERVER_INITIAL_WINDOW_SIZE 65536
346 #define HTTP_SERVER_WS_MAX_SEC_KEY_LEN 32
347 
348 /** @endcond */
349 
350 /** @brief HTTP/2 stream representation. */
351 struct http2_stream_ctx {
352 	int stream_id; /**< Stream identifier. */
353 	enum http2_stream_state stream_state; /**< Stream state. */
354 	int window_size; /**< Stream-level window size. */
355 
356 	/** Currently processed resource detail. */
357 	struct http_resource_detail *current_detail;
358 
359 	/** Flag indicating that headers were sent in the reply. */
360 	bool headers_sent : 1;
361 
362 	/** Flag indicating that END_STREAM flag was sent. */
363 	bool end_stream_sent : 1;
364 };
365 
366 /** @brief HTTP/2 frame representation. */
367 struct http2_frame {
368 	uint32_t length; /**< Frame payload length. */
369 	uint32_t stream_identifier; /**< Stream ID the frame belongs to. */
370 	uint8_t type; /**< Frame type. */
371 	uint8_t flags; /**< Frame flags. */
372 	uint8_t padding_len; /**< Frame padding length. */
373 };
374 
375 /** @cond INTERNAL_HIDDEN */
376 /** @brief Context for capturing HTTP headers */
377 struct http_header_capture_ctx {
378 	/** Buffer for HTTP headers captured for application use */
379 	unsigned char buffer[HTTP_SERVER_CAPTURE_HEADER_BUFFER_SIZE];
380 
381 	/** Descriptor of each captured HTTP header */
382 	struct http_header headers[HTTP_SERVER_CAPTURE_HEADER_COUNT];
383 
384 	/** Status of captured headers */
385 	enum http_header_status status;
386 
387 	/** Number of headers captured */
388 	size_t count;
389 
390 	/** Current position in buffer */
391 	size_t cursor;
392 
393 	/** The HTTP2 stream associated with the current headers */
394 	struct http2_stream_ctx *current_stream;
395 
396 	/** The next HTTP header value should be stored */
397 	bool store_next_value;
398 };
399 /** @endcond */
400 
401 /** @brief HTTP header name representation */
402 struct http_header_name {
403 	const char *name; /**< Pointer to header name NULL-terminated string. */
404 };
405 
406 /**
407  * @brief Representation of an HTTP client connected to the server.
408  */
409 struct http_client_ctx {
410 	/** Socket descriptor associated with the server. */
411 	int fd;
412 
413 	/** HTTP service on which the client is connected */
414 	const struct http_service_desc *service;
415 
416 	/** Client data buffer.  */
417 	unsigned char buffer[HTTP_SERVER_CLIENT_BUFFER_SIZE];
418 
419 	/** Cursor indicating currently processed byte. */
420 	unsigned char *cursor;
421 
422 	/** Data left to process in the buffer. */
423 	size_t data_len;
424 
425 	/** Connection-level window size. */
426 	int window_size;
427 
428 	/** Server state for the associated client. */
429 	enum http_server_state server_state;
430 
431 	/** Currently processed HTTP/2 frame. */
432 	struct http2_frame current_frame;
433 
434 	/** Currently processed resource detail. */
435 	struct http_resource_detail *current_detail;
436 
437 	/** Currently processed stream. */
438 	struct http2_stream_ctx *current_stream;
439 
440 	/** HTTP/2 header parser context. */
441 	struct http_hpack_header_buf header_field;
442 
443 	/** HTTP/2 streams context. */
444 	struct http2_stream_ctx streams[HTTP_SERVER_MAX_STREAMS];
445 
446 	/** HTTP/1 parser configuration. */
447 	struct http_parser_settings parser_settings;
448 
449 	/** HTTP/1 parser context. */
450 	struct http_parser parser;
451 
452 	/** Header capture context */
453 	struct http_header_capture_ctx header_capture_ctx;
454 
455 	/** Request URL. */
456 	unsigned char url_buffer[HTTP_SERVER_MAX_URL_LENGTH];
457 
458 	/** Request content type. */
459 	unsigned char content_type[HTTP_SERVER_MAX_CONTENT_TYPE_LEN];
460 
461 	/** Temp buffer for currently processed header (HTTP/1 only). */
462 	unsigned char header_buffer[HTTP_SERVER_MAX_HEADER_LEN];
463 
464 	/** Request content length. */
465 	size_t content_len;
466 
467 	/** Request method. */
468 	enum http_method method;
469 
470 	/** HTTP/1 parser state. */
471 	enum http1_parser_state parser_state;
472 
473 	/** Length of the payload length in the currently processed request
474 	 * fragment (HTTP/1 only).
475 	 */
476 	int http1_frag_data_len;
477 
478 	/** Client inactivity timer. The client connection is closed by the
479 	 *  server when it expires.
480 	 */
481 	struct k_work_delayable inactivity_timer;
482 
483 /** @cond INTERNAL_HIDDEN */
484 	/** Websocket security key. */
485 	IF_ENABLED(CONFIG_WEBSOCKET, (uint8_t ws_sec_key[HTTP_SERVER_WS_MAX_SEC_KEY_LEN]));
486 /** @endcond */
487 
488 /** @cond INTERNAL_HIDDEN */
489 	/** Client supported compression. */
490 	IF_ENABLED(CONFIG_HTTP_SERVER_COMPRESSION, (uint8_t supported_compression));
491 /** @endcond */
492 
493 	/** Flag indicating that HTTP2 preface was sent. */
494 	bool preface_sent : 1;
495 
496 	/** Flag indicating that HTTP1 headers were sent. */
497 	bool http1_headers_sent : 1;
498 
499 	/** Flag indicating that upgrade header was present in the request. */
500 	bool has_upgrade_header : 1;
501 
502 	/** Flag indicating HTTP/2 upgrade takes place. */
503 	bool http2_upgrade : 1;
504 
505 	/** Flag indicating Websocket upgrade takes place. */
506 	bool websocket_upgrade : 1;
507 
508 	/** Flag indicating Websocket key is being processed. */
509 	bool websocket_sec_key_next : 1;
510 
511 	/** Flag indicating accept encoding is being processed. */
512 	IF_ENABLED(CONFIG_HTTP_SERVER_COMPRESSION, (bool accept_encoding_next: 1));
513 
514 	/** The next frame on the stream is expectd to be a continuation frame. */
515 	bool expect_continuation : 1;
516 };
517 
518 /**
519  * @brief Register an HTTP request header to be captured by the server
520  *
521  * @param _id variable name for the header capture instance
522  * @param _header header to be captured, as literal string
523  */
524 #define HTTP_SERVER_REGISTER_HEADER_CAPTURE(_id, _header)                                          \
525 	BUILD_ASSERT(sizeof(_header) <= CONFIG_HTTP_SERVER_MAX_HEADER_LEN,                         \
526 		     "Header is too long to be captured, try increasing "                          \
527 		     "CONFIG_HTTP_SERVER_MAX_HEADER_LEN");                                         \
528 	static const char *const _id##_str = _header;                                              \
529 	static const STRUCT_SECTION_ITERABLE(http_header_name, _id) = {                            \
530 		.name = _id##_str,                                                                 \
531 	}
532 
533 /** @brief Start the HTTP2 server.
534  *
535  * The server runs in a background thread. Once started, the server will create
536  * a server socket for all HTTP services registered in the system and accept
537  * connections from clients (see @ref HTTP_SERVICE_DEFINE).
538  */
539 int http_server_start(void);
540 
541 /** @brief Stop the HTTP2 server.
542  *
543  * All server sockets are closed and the server thread is suspended.
544  */
545 int http_server_stop(void);
546 
547 #ifdef __cplusplus
548 }
549 #endif
550 
551 /**
552  * @}
553  */
554 
555 #endif
556