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 /** @cond INTERNAL_HIDDEN */
142 /* Make sure that the common is the first in the struct. */
143 BUILD_ASSERT(offsetof(struct http_resource_detail_static_fs, common) == 0);
144 /** @endcond */
145 
146 struct http_content_type {
147 	const char *extension;
148 	size_t extension_len;
149 	const char *content_type;
150 };
151 
152 #define HTTP_SERVER_CONTENT_TYPE(_extension, _content_type)                                        \
153 	const STRUCT_SECTION_ITERABLE(http_content_type, _extension) = {                           \
154 		.extension = STRINGIFY(_extension),                                                \
155 		.extension_len = sizeof(STRINGIFY(_extension)) - 1,                                \
156 		.content_type = _content_type,                                                     \
157 	};
158 
159 #define HTTP_SERVER_CONTENT_TYPE_FOREACH(_it) STRUCT_SECTION_FOREACH(http_content_type, _it)
160 
161 struct http_client_ctx;
162 
163 /** Indicates the status of the currently processed piece of data.  */
164 enum http_data_status {
165 	/** Transaction aborted, data incomplete. */
166 	HTTP_SERVER_DATA_ABORTED = -1,
167 	/** Transaction incomplete, more data expected. */
168 	HTTP_SERVER_DATA_MORE = 0,
169 	/** Final data fragment in current transaction. */
170 	HTTP_SERVER_DATA_FINAL = 1,
171 };
172 
173 /** @brief Status of captured request headers */
174 enum http_header_status {
175 	HTTP_HEADER_STATUS_OK,      /**< All available headers were successfully captured. */
176 	HTTP_HEADER_STATUS_DROPPED, /**< One or more headers were dropped due to lack of space. */
177 	HTTP_HEADER_STATUS_NONE,    /**< No header status is available. */
178 };
179 
180 /** @brief HTTP header representation */
181 struct http_header {
182 	const char *name;  /**< Pointer to header name NULL-terminated string. */
183 	const char *value; /**< Pointer to header value NULL-terminated string. */
184 };
185 
186 /** @brief HTTP request context */
187 struct http_request_ctx {
188 	uint8_t *data;                          /**< HTTP request data */
189 	size_t data_len;                        /**< Length of HTTP request data */
190 	struct http_header *headers;            /**< Array of HTTP request headers */
191 	size_t header_count;                    /**< Array length of HTTP request headers */
192 	enum http_header_status headers_status; /**< Status of HTTP request headers */
193 };
194 
195 /** @brief HTTP response context */
196 struct http_response_ctx {
197 	enum http_status status;           /**< HTTP status code to include in response */
198 	const struct http_header *headers; /**< Array of HTTP headers */
199 	size_t header_count;               /**< Length of headers array */
200 	const uint8_t *body;               /**< Pointer to body data */
201 	size_t body_len;                   /**< Length of body data */
202 	bool final_chunk; /**< Flag set to true when the application has no more data to send */
203 };
204 
205 /**
206  * @typedef http_resource_dynamic_cb_t
207  * @brief Callback used when data is received. Data to be sent to client
208  *        can be specified.
209  *
210  * @param client HTTP context information for this client connection.
211  * @param status HTTP data status, indicate whether more data is expected or not.
212  * @param request_ctx Request context structure containing HTTP request data that was received.
213  * @param response_ctx Response context structure for application to populate with response data.
214  * @param user_data User specified data.
215  *
216  * @return 0 success, server can send any response data provided in the response_ctx.
217  *         <0 error, close the connection.
218  */
219 typedef int (*http_resource_dynamic_cb_t)(struct http_client_ctx *client,
220 					  enum http_data_status status,
221 					  const struct http_request_ctx *request_ctx,
222 					  struct http_response_ctx *response_ctx,
223 					  void *user_data);
224 
225 /**
226  * @brief Representation of a dynamic server resource.
227  */
228 struct http_resource_detail_dynamic {
229 	/** Common resource details. */
230 	struct http_resource_detail common;
231 
232 	/** Resource callback used by the server to interact with the
233 	 *  application.
234 	 */
235 	http_resource_dynamic_cb_t cb;
236 
237 	/** A pointer to the client currently processing resource, used to
238 	 *  prevent concurrent access to the resource from multiple clients.
239 	 */
240 	struct http_client_ctx *holder;
241 
242 	/** A pointer to the user data registered by the application.  */
243 	void *user_data;
244 };
245 
246 /** @cond INTERNAL_HIDDEN */
247 BUILD_ASSERT(offsetof(struct http_resource_detail_dynamic, common) == 0);
248 /** @endcond */
249 
250 /**
251  * @typedef http_resource_websocket_cb_t
252  * @brief Callback used when a Websocket connection is setup. The application
253  *        will need to handle all functionality related to the connection like
254  *        reading and writing websocket data, and closing the connection.
255  *
256  * @param ws_socket A socket for the Websocket data.
257  * @param user_data User specified data.
258  *
259  * @return  0 Accepting the connection, HTTP server library will no longer
260  *            handle data to/from the socket and it is application responsibility
261  *            to send and receive data to/from the supplied socket.
262  *         <0 error, close the connection.
263  */
264 typedef int (*http_resource_websocket_cb_t)(int ws_socket,
265 					    void *user_data);
266 
267 /** @brief Representation of a websocket server resource */
268 struct http_resource_detail_websocket {
269 	/** Common resource details. */
270 	struct http_resource_detail common;
271 
272 	/** Websocket socket value */
273 	int ws_sock;
274 
275 	/** Resource callback used by the server to interact with the
276 	 *  application.
277 	 */
278 	http_resource_websocket_cb_t cb;
279 
280 	/** Data buffer used to exchanged data between server and the,
281 	 *  application.
282 	 */
283 	uint8_t *data_buffer;
284 
285 	/** Length of the data in the data buffer. */
286 	size_t data_buffer_len;
287 
288 	/** A pointer to the user data registered by the application.  */
289 	void *user_data;
290 };
291 
292 /** @cond INTERNAL_HIDDEN */
293 BUILD_ASSERT(offsetof(struct http_resource_detail_websocket, common) == 0);
294 /** @endcond */
295 
296 /** @cond INTERNAL_HIDDEN */
297 
298 enum http2_stream_state {
299 	HTTP2_STREAM_IDLE,
300 	HTTP2_STREAM_RESERVED_LOCAL,
301 	HTTP2_STREAM_RESERVED_REMOTE,
302 	HTTP2_STREAM_OPEN,
303 	HTTP2_STREAM_HALF_CLOSED_LOCAL,
304 	HTTP2_STREAM_HALF_CLOSED_REMOTE,
305 	HTTP2_STREAM_CLOSED
306 };
307 
308 enum http_server_state {
309 	HTTP_SERVER_FRAME_HEADER_STATE,
310 	HTTP_SERVER_PREFACE_STATE,
311 	HTTP_SERVER_REQUEST_STATE,
312 	HTTP_SERVER_FRAME_DATA_STATE,
313 	HTTP_SERVER_FRAME_HEADERS_STATE,
314 	HTTP_SERVER_FRAME_SETTINGS_STATE,
315 	HTTP_SERVER_FRAME_PRIORITY_STATE,
316 	HTTP_SERVER_FRAME_WINDOW_UPDATE_STATE,
317 	HTTP_SERVER_FRAME_CONTINUATION_STATE,
318 	HTTP_SERVER_FRAME_PING_STATE,
319 	HTTP_SERVER_FRAME_RST_STREAM_STATE,
320 	HTTP_SERVER_FRAME_GOAWAY_STATE,
321 	HTTP_SERVER_FRAME_PADDING_STATE,
322 	HTTP_SERVER_DONE_STATE,
323 };
324 
325 enum http1_parser_state {
326 	HTTP1_INIT_HEADER_STATE,
327 	HTTP1_WAITING_HEADER_STATE,
328 	HTTP1_RECEIVING_HEADER_STATE,
329 	HTTP1_RECEIVED_HEADER_STATE,
330 	HTTP1_RECEIVING_DATA_STATE,
331 	HTTP1_MESSAGE_COMPLETE_STATE,
332 };
333 
334 #define HTTP_SERVER_INITIAL_WINDOW_SIZE 65536
335 #define HTTP_SERVER_WS_MAX_SEC_KEY_LEN 32
336 
337 /** @endcond */
338 
339 /** @brief HTTP/2 stream representation. */
340 struct http2_stream_ctx {
341 	int stream_id; /**< Stream identifier. */
342 	enum http2_stream_state stream_state; /**< Stream state. */
343 	int window_size; /**< Stream-level window size. */
344 
345 	/** Currently processed resource detail. */
346 	struct http_resource_detail *current_detail;
347 
348 	/** Flag indicating that headers were sent in the reply. */
349 	bool headers_sent : 1;
350 
351 	/** Flag indicating that END_STREAM flag was sent. */
352 	bool end_stream_sent : 1;
353 };
354 
355 /** @brief HTTP/2 frame representation. */
356 struct http2_frame {
357 	uint32_t length; /**< Frame payload length. */
358 	uint32_t stream_identifier; /**< Stream ID the frame belongs to. */
359 	uint8_t type; /**< Frame type. */
360 	uint8_t flags; /**< Frame flags. */
361 	uint8_t padding_len; /**< Frame padding length. */
362 };
363 
364 /** @cond INTERNAL_HIDDEN */
365 /** @brief Context for capturing HTTP headers */
366 struct http_header_capture_ctx {
367 	/** Buffer for HTTP headers captured for application use */
368 	unsigned char buffer[HTTP_SERVER_CAPTURE_HEADER_BUFFER_SIZE];
369 
370 	/** Descriptor of each captured HTTP header */
371 	struct http_header headers[HTTP_SERVER_CAPTURE_HEADER_COUNT];
372 
373 	/** Status of captured headers */
374 	enum http_header_status status;
375 
376 	/** Number of headers captured */
377 	size_t count;
378 
379 	/** Current position in buffer */
380 	size_t cursor;
381 
382 	/** The HTTP2 stream associated with the current headers */
383 	struct http2_stream_ctx *current_stream;
384 
385 	/** The next HTTP header value should be stored */
386 	bool store_next_value;
387 };
388 /** @endcond */
389 
390 /** @brief HTTP header name representation */
391 struct http_header_name {
392 	const char *name; /**< Pointer to header name NULL-terminated string. */
393 };
394 
395 /**
396  * @brief Representation of an HTTP client connected to the server.
397  */
398 struct http_client_ctx {
399 	/** Socket descriptor associated with the server. */
400 	int fd;
401 
402 	/** Client data buffer.  */
403 	unsigned char buffer[HTTP_SERVER_CLIENT_BUFFER_SIZE];
404 
405 	/** Cursor indicating currently processed byte. */
406 	unsigned char *cursor;
407 
408 	/** Data left to process in the buffer. */
409 	size_t data_len;
410 
411 	/** Connection-level window size. */
412 	int window_size;
413 
414 	/** Server state for the associated client. */
415 	enum http_server_state server_state;
416 
417 	/** Currently processed HTTP/2 frame. */
418 	struct http2_frame current_frame;
419 
420 	/** Currently processed resource detail. */
421 	struct http_resource_detail *current_detail;
422 
423 	/** Currently processed stream. */
424 	struct http2_stream_ctx *current_stream;
425 
426 	/** HTTP/2 header parser context. */
427 	struct http_hpack_header_buf header_field;
428 
429 	/** HTTP/2 streams context. */
430 	struct http2_stream_ctx streams[HTTP_SERVER_MAX_STREAMS];
431 
432 	/** HTTP/1 parser configuration. */
433 	struct http_parser_settings parser_settings;
434 
435 	/** HTTP/1 parser context. */
436 	struct http_parser parser;
437 
438 	/** Header capture context */
439 	struct http_header_capture_ctx header_capture_ctx;
440 
441 	/** Request URL. */
442 	unsigned char url_buffer[HTTP_SERVER_MAX_URL_LENGTH];
443 
444 	/** Request content type. */
445 	unsigned char content_type[HTTP_SERVER_MAX_CONTENT_TYPE_LEN];
446 
447 	/** Temp buffer for currently processed header (HTTP/1 only). */
448 	unsigned char header_buffer[HTTP_SERVER_MAX_HEADER_LEN];
449 
450 	/** Request content length. */
451 	size_t content_len;
452 
453 	/** Request method. */
454 	enum http_method method;
455 
456 	/** HTTP/1 parser state. */
457 	enum http1_parser_state parser_state;
458 
459 	/** Length of the payload length in the currently processed request
460 	 * fragment (HTTP/1 only).
461 	 */
462 	int http1_frag_data_len;
463 
464 	/** Client inactivity timer. The client connection is closed by the
465 	 *  server when it expires.
466 	 */
467 	struct k_work_delayable inactivity_timer;
468 
469 /** @cond INTERNAL_HIDDEN */
470 	/** Websocket security key. */
471 	IF_ENABLED(CONFIG_WEBSOCKET, (uint8_t ws_sec_key[HTTP_SERVER_WS_MAX_SEC_KEY_LEN]));
472 /** @endcond */
473 
474 	/** Flag indicating that HTTP2 preface was sent. */
475 	bool preface_sent : 1;
476 
477 	/** Flag indicating that HTTP1 headers were sent. */
478 	bool http1_headers_sent : 1;
479 
480 	/** Flag indicating that upgrade header was present in the request. */
481 	bool has_upgrade_header : 1;
482 
483 	/** Flag indicating HTTP/2 upgrade takes place. */
484 	bool http2_upgrade : 1;
485 
486 	/** Flag indicating Websocket upgrade takes place. */
487 	bool websocket_upgrade : 1;
488 
489 	/** Flag indicating Websocket key is being processed. */
490 	bool websocket_sec_key_next : 1;
491 
492 	/** The next frame on the stream is expectd to be a continuation frame. */
493 	bool expect_continuation : 1;
494 };
495 
496 /**
497  * @brief Register an HTTP request header to be captured by the server
498  *
499  * @param _id variable name for the header capture instance
500  * @param _header header to be captured, as literal string
501  */
502 #define HTTP_SERVER_REGISTER_HEADER_CAPTURE(_id, _header)                                          \
503 	BUILD_ASSERT(sizeof(_header) <= CONFIG_HTTP_SERVER_MAX_HEADER_LEN,                         \
504 		     "Header is too long to be captured, try increasing "                          \
505 		     "CONFIG_HTTP_SERVER_MAX_HEADER_LEN");                                         \
506 	static const char *const _id##_str = _header;                                              \
507 	static const STRUCT_SECTION_ITERABLE(http_header_name, _id) = {                            \
508 		.name = _id##_str,                                                                 \
509 	}
510 
511 /** @brief Start the HTTP2 server.
512  *
513  * The server runs in a background thread. Once started, the server will create
514  * a server socket for all HTTP services registered in the system and accept
515  * connections from clients (see @ref HTTP_SERVICE_DEFINE).
516  */
517 int http_server_start(void);
518 
519 /** @brief Stop the HTTP2 server.
520  *
521  * All server sockets are closed and the server thread is suspended.
522  */
523 int http_server_stop(void);
524 
525 #ifdef __cplusplus
526 }
527 #endif
528 
529 /**
530  * @}
531  */
532 
533 #endif
534