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/socket.h>
29 
30 #ifdef __cplusplus
31 extern "C" {
32 #endif
33 
34 /** @cond INTERNAL_HIDDEN */
35 
36 #if defined(CONFIG_HTTP_SERVER)
37 #define HTTP_SERVER_CLIENT_BUFFER_SIZE   CONFIG_HTTP_SERVER_CLIENT_BUFFER_SIZE
38 #define HTTP_SERVER_MAX_STREAMS          CONFIG_HTTP_SERVER_MAX_STREAMS
39 #define HTTP_SERVER_MAX_CONTENT_TYPE_LEN CONFIG_HTTP_SERVER_MAX_CONTENT_TYPE_LENGTH
40 #define HTTP_SERVER_MAX_URL_LENGTH       CONFIG_HTTP_SERVER_MAX_URL_LENGTH
41 #else
42 #define HTTP_SERVER_CLIENT_BUFFER_SIZE   0
43 #define HTTP_SERVER_MAX_STREAMS          0
44 #define HTTP_SERVER_MAX_CONTENT_TYPE_LEN 0
45 #define HTTP_SERVER_MAX_URL_LENGTH       0
46 #endif
47 
48 /* Maximum header field name / value length. This is only used to detect Upgrade and
49  * websocket header fields and values in the http1 server so the value is quite short.
50  */
51 #define HTTP_SERVER_MAX_HEADER_LEN 32
52 
53 #define HTTP2_PREFACE "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
54 
55 /** @endcond */
56 
57 /**
58  *  @brief HTTP server resource type.
59  */
60 enum http_resource_type {
61 	/** Static resource, cannot be modified on runtime. */
62 	HTTP_RESOURCE_TYPE_STATIC,
63 
64 	/** serves static gzipped files from a filesystem */
65 	HTTP_RESOURCE_TYPE_STATIC_FS,
66 
67 	/** Dynamic resource, server interacts with the application via registered
68 	 *  @ref http_resource_dynamic_cb_t.
69 	 */
70 	HTTP_RESOURCE_TYPE_DYNAMIC,
71 
72 	/** Websocket resource, application takes control over Websocket connection
73 	 *  after and upgrade.
74 	 */
75 	HTTP_RESOURCE_TYPE_WEBSOCKET,
76 };
77 
78 /**
79  * @brief Representation of a server resource, common for all resource types.
80  */
81 struct http_resource_detail {
82 	/** Bitmask of supported HTTP methods (@ref http_method). */
83 	uint32_t bitmask_of_supported_http_methods;
84 
85 	/** Resource type. */
86 	enum http_resource_type type;
87 
88 	/** Length of the URL path. */
89 	int path_len;
90 
91 	/** Content encoding of the resource. */
92 	const char *content_encoding;
93 
94 	/** Content type of the resource. */
95 	const char *content_type;
96 };
97 
98 /** @cond INTERNAL_HIDDEN */
99 BUILD_ASSERT(NUM_BITS(
100 	     sizeof(((struct http_resource_detail *)0)->bitmask_of_supported_http_methods))
101 	     >= (HTTP_METHOD_END_VALUE - 1));
102 /** @endcond */
103 
104 /**
105  * @brief Representation of a static server resource.
106  */
107 struct http_resource_detail_static {
108 	/** Common resource details. */
109 	struct http_resource_detail common;
110 
111 	/** Content of the static resource. */
112 	const void *static_data;
113 
114 	/** Size of the static resource. */
115 	size_t static_data_len;
116 };
117 
118 /** @cond INTERNAL_HIDDEN */
119 /* Make sure that the common is the first in the struct. */
120 BUILD_ASSERT(offsetof(struct http_resource_detail_static, common) == 0);
121 /** @endcond */
122 
123 /**
124  * @brief Representation of a static filesystem server resource.
125  */
126 struct http_resource_detail_static_fs {
127 	/** Common resource details. */
128 	struct http_resource_detail common;
129 
130 	/** Path in the local filesystem */
131 	const char *fs_path;
132 };
133 
134 /** @cond INTERNAL_HIDDEN */
135 /* Make sure that the common is the first in the struct. */
136 BUILD_ASSERT(offsetof(struct http_resource_detail_static_fs, common) == 0);
137 /** @endcond */
138 
139 struct http_content_type {
140 	const char *extension;
141 	size_t extension_len;
142 	const char *content_type;
143 };
144 
145 #define HTTP_SERVER_CONTENT_TYPE(_extension, _content_type)                                        \
146 	const STRUCT_SECTION_ITERABLE(http_content_type, _extension) = {                           \
147 		.extension = STRINGIFY(_extension),                                                \
148 		.extension_len = sizeof(STRINGIFY(_extension)) - 1,                                \
149 		.content_type = _content_type,                                                     \
150 	};
151 
152 #define HTTP_SERVER_CONTENT_TYPE_FOREACH(_it) STRUCT_SECTION_FOREACH(http_content_type, _it)
153 
154 struct http_client_ctx;
155 
156 /** Indicates the status of the currently processed piece of data.  */
157 enum http_data_status {
158 	/** Transaction aborted, data incomplete. */
159 	HTTP_SERVER_DATA_ABORTED = -1,
160 	/** Transaction incomplete, more data expected. */
161 	HTTP_SERVER_DATA_MORE = 0,
162 	/** Final data fragment in current transaction. */
163 	HTTP_SERVER_DATA_FINAL = 1,
164 };
165 
166 /**
167  * @typedef http_resource_dynamic_cb_t
168  * @brief Callback used when data is received. Data to be sent to client
169  *        can be specified.
170  *
171  * @param client HTTP context information for this client connection.
172  * @param status HTTP data status, indicate whether more data is expected or not.
173  * @param data_buffer Data received.
174  * @param data_len Amount of data received.
175  * @param user_data User specified data.
176  *
177  * @return >0 amount of data to be sent to client, let server to call this
178  *            function again when new data is received.
179  *          0 nothing to sent to client, close the connection
180  *         <0 error, close the connection.
181  */
182 typedef int (*http_resource_dynamic_cb_t)(struct http_client_ctx *client,
183 					  enum http_data_status status,
184 					  uint8_t *data_buffer,
185 					  size_t data_len,
186 					  void *user_data);
187 
188 /**
189  * @brief Representation of a dynamic server resource.
190  */
191 struct http_resource_detail_dynamic {
192 	/** Common resource details. */
193 	struct http_resource_detail common;
194 
195 	/** Resource callback used by the server to interact with the
196 	 *  application.
197 	 */
198 	http_resource_dynamic_cb_t cb;
199 
200 	/** Data buffer used to exchanged data between server and the,
201 	 *  application.
202 	 */
203 	uint8_t *data_buffer;
204 
205 	/** Length of the data in the data buffer. */
206 	size_t data_buffer_len;
207 
208 	/** A pointer to the client currently processing resource, used to
209 	 *  prevent concurrent access to the resource from multiple clients.
210 	 */
211 	struct http_client_ctx *holder;
212 
213 	/** A pointer to the user data registered by the application.  */
214 	void *user_data;
215 };
216 
217 /** @cond INTERNAL_HIDDEN */
218 BUILD_ASSERT(offsetof(struct http_resource_detail_dynamic, common) == 0);
219 /** @endcond */
220 
221 /**
222  * @typedef http_resource_websocket_cb_t
223  * @brief Callback used when a Websocket connection is setup. The application
224  *        will need to handle all functionality related to the connection like
225  *        reading and writing websocket data, and closing the connection.
226  *
227  * @param ws_socket A socket for the Websocket data.
228  * @param user_data User specified data.
229  *
230  * @return  0 Accepting the connection, HTTP server library will no longer
231  *            handle data to/from the socket and it is application responsibility
232  *            to send and receive data to/from the supplied socket.
233  *         <0 error, close the connection.
234  */
235 typedef int (*http_resource_websocket_cb_t)(int ws_socket,
236 					    void *user_data);
237 
238 /** @brief Representation of a websocket server resource */
239 struct http_resource_detail_websocket {
240 	/** Common resource details. */
241 	struct http_resource_detail common;
242 
243 	/** Websocket socket value */
244 	int ws_sock;
245 
246 	/** Resource callback used by the server to interact with the
247 	 *  application.
248 	 */
249 	http_resource_websocket_cb_t cb;
250 
251 	/** Data buffer used to exchanged data between server and the,
252 	 *  application.
253 	 */
254 	uint8_t *data_buffer;
255 
256 	/** Length of the data in the data buffer. */
257 	size_t data_buffer_len;
258 
259 	/** A pointer to the user data registered by the application.  */
260 	void *user_data;
261 };
262 
263 /** @cond INTERNAL_HIDDEN */
264 BUILD_ASSERT(offsetof(struct http_resource_detail_websocket, common) == 0);
265 /** @endcond */
266 
267 /** @cond INTERNAL_HIDDEN */
268 
269 enum http2_stream_state {
270 	HTTP2_STREAM_IDLE,
271 	HTTP2_STREAM_RESERVED_LOCAL,
272 	HTTP2_STREAM_RESERVED_REMOTE,
273 	HTTP2_STREAM_OPEN,
274 	HTTP2_STREAM_HALF_CLOSED_LOCAL,
275 	HTTP2_STREAM_HALF_CLOSED_REMOTE,
276 	HTTP2_STREAM_CLOSED
277 };
278 
279 enum http_server_state {
280 	HTTP_SERVER_FRAME_HEADER_STATE,
281 	HTTP_SERVER_PREFACE_STATE,
282 	HTTP_SERVER_REQUEST_STATE,
283 	HTTP_SERVER_FRAME_DATA_STATE,
284 	HTTP_SERVER_FRAME_HEADERS_STATE,
285 	HTTP_SERVER_FRAME_SETTINGS_STATE,
286 	HTTP_SERVER_FRAME_PRIORITY_STATE,
287 	HTTP_SERVER_FRAME_WINDOW_UPDATE_STATE,
288 	HTTP_SERVER_FRAME_CONTINUATION_STATE,
289 	HTTP_SERVER_FRAME_PING_STATE,
290 	HTTP_SERVER_FRAME_RST_STREAM_STATE,
291 	HTTP_SERVER_FRAME_GOAWAY_STATE,
292 	HTTP_SERVER_FRAME_PADDING_STATE,
293 	HTTP_SERVER_DONE_STATE,
294 };
295 
296 enum http1_parser_state {
297 	HTTP1_INIT_HEADER_STATE,
298 	HTTP1_WAITING_HEADER_STATE,
299 	HTTP1_RECEIVING_HEADER_STATE,
300 	HTTP1_RECEIVED_HEADER_STATE,
301 	HTTP1_RECEIVING_DATA_STATE,
302 	HTTP1_MESSAGE_COMPLETE_STATE,
303 };
304 
305 #define HTTP_SERVER_INITIAL_WINDOW_SIZE 65536
306 #define HTTP_SERVER_WS_MAX_SEC_KEY_LEN 32
307 
308 /** @endcond */
309 
310 /** @brief HTTP/2 stream representation. */
311 struct http2_stream_ctx {
312 	int stream_id; /**< Stream identifier. */
313 	enum http2_stream_state stream_state; /**< Stream state. */
314 	int window_size; /**< Stream-level window size. */
315 
316 	/** Flag indicating that headers were sent in the reply. */
317 	bool headers_sent : 1;
318 
319 	/** Flag indicating that END_STREAM flag was sent. */
320 	bool end_stream_sent : 1;
321 };
322 
323 /** @brief HTTP/2 frame representation. */
324 struct http2_frame {
325 	uint32_t length; /**< Frame payload length. */
326 	uint32_t stream_identifier; /**< Stream ID the frame belongs to. */
327 	uint8_t type; /**< Frame type. */
328 	uint8_t flags; /**< Frame flags. */
329 	uint8_t padding_len; /**< Frame padding length. */
330 };
331 
332 /**
333  * @brief Representation of an HTTP client connected to the server.
334  */
335 struct http_client_ctx {
336 	/** Socket descriptor associated with the server. */
337 	int fd;
338 
339 	/** Client data buffer.  */
340 	unsigned char buffer[HTTP_SERVER_CLIENT_BUFFER_SIZE];
341 
342 	/** Cursor indicating currently processed byte. */
343 	unsigned char *cursor;
344 
345 	/** Data left to process in the buffer. */
346 	size_t data_len;
347 
348 	/** Connection-level window size. */
349 	int window_size;
350 
351 	/** Server state for the associated client. */
352 	enum http_server_state server_state;
353 
354 	/** Currently processed HTTP/2 frame. */
355 	struct http2_frame current_frame;
356 
357 	/** Currently processed resource detail. */
358 	struct http_resource_detail *current_detail;
359 
360 	/** Currently processed stream. */
361 	struct http2_stream_ctx *current_stream;
362 
363 	/** HTTP/2 header parser context. */
364 	struct http_hpack_header_buf header_field;
365 
366 	/** HTTP/2 streams context. */
367 	struct http2_stream_ctx streams[HTTP_SERVER_MAX_STREAMS];
368 
369 	/** HTTP/1 parser configuration. */
370 	struct http_parser_settings parser_settings;
371 
372 	/** HTTP/1 parser context. */
373 	struct http_parser parser;
374 
375 	/** Request URL. */
376 	unsigned char url_buffer[HTTP_SERVER_MAX_URL_LENGTH];
377 
378 	/** Request content type. */
379 	unsigned char content_type[HTTP_SERVER_MAX_CONTENT_TYPE_LEN];
380 
381 	/** Temp buffer for currently processed header (HTTP/1 only). */
382 	unsigned char header_buffer[HTTP_SERVER_MAX_HEADER_LEN];
383 
384 	/** Request content length. */
385 	size_t content_len;
386 
387 	/** Request method. */
388 	enum http_method method;
389 
390 	/** HTTP/1 parser state. */
391 	enum http1_parser_state parser_state;
392 
393 	/** Length of the payload length in the currently processed request
394 	 * fragment (HTTP/1 only).
395 	 */
396 	int http1_frag_data_len;
397 
398 	/** Client inactivity timer. The client connection is closed by the
399 	 *  server when it expires.
400 	 */
401 	struct k_work_delayable inactivity_timer;
402 
403 /** @cond INTERNAL_HIDDEN */
404 	/** Websocket security key. */
405 	IF_ENABLED(CONFIG_WEBSOCKET, (uint8_t ws_sec_key[HTTP_SERVER_WS_MAX_SEC_KEY_LEN]));
406 /** @endcond */
407 
408 	/** Flag indicating that HTTP2 preface was sent. */
409 	bool preface_sent : 1;
410 
411 	/** Flag indicating that HTTP1 headers were sent. */
412 	bool http1_headers_sent : 1;
413 
414 	/** Flag indicating that upgrade header was present in the request. */
415 	bool has_upgrade_header : 1;
416 
417 	/** Flag indicating HTTP/2 upgrade takes place. */
418 	bool http2_upgrade : 1;
419 
420 	/** Flag indicating Websocket upgrade takes place. */
421 	bool websocket_upgrade : 1;
422 
423 	/** Flag indicating Websocket key is being processed. */
424 	bool websocket_sec_key_next : 1;
425 
426 	/** The next frame on the stream is expectd to be a continuation frame. */
427 	bool expect_continuation : 1;
428 };
429 
430 /** @brief Start the HTTP2 server.
431  *
432  * The server runs in a background thread. Once started, the server will create
433  * a server socket for all HTTP services registered in the system and accept
434  * connections from clients (see @ref HTTP_SERVICE_DEFINE).
435  */
436 int http_server_start(void);
437 
438 /** @brief Stop the HTTP2 server.
439  *
440  * All server sockets are closed and the server thread is suspended.
441  */
442 int http_server_stop(void);
443 
444 #ifdef __cplusplus
445 }
446 #endif
447 
448 /**
449  * @}
450  */
451 
452 #endif
453