Skip to content

Commit 4b157b9

Browse files
jukkarcarlescufi
authored andcommitted
net: lib: http_server: Initial HTTP server support
Original code developed as a GSoC 2023 project by Emna Rekik. Code refactored in order to provide better bisectability as the origical commits were not bisectable. The server supports static and dynamic resources, managed by HTTP_SERVICE/HTTP_RESOURCE macros. Fixes #59685 Fixes #59686 Fixes #59688 Fixes #59690 Fixes #59670 Fixes #59700 Fixes #59684 Fixes #59693 Fixes #59693 Fixes #59694 Fixes #59699 Fixes #59696 Fixes #59688 Fixes #59690 Fixes #59670 Fixes #59700 Fixes #59685 Fixes #59686 Fixes #59688 Fixes #59691 Signed-off-by: Emna Rekik <[email protected]> Signed-off-by: Jukka Rissanen <[email protected]> Signed-off-by: Robert Lubos <[email protected]>
1 parent 318dcb6 commit 4b157b9

File tree

14 files changed

+2853
-12
lines changed

14 files changed

+2853
-12
lines changed

include/zephyr/linker/common-rom/common-rom-net.ld

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#if defined(CONFIG_HTTP_SERVER)
1818
ITERABLE_SECTION_ROM(http_service_desc, Z_LINK_ITERABLE_SUBALIGN)
19+
ITERABLE_SECTION_ROM(http_resource_desc, Z_LINK_ITERABLE_SUBALIGN)
1920
#endif
2021

2122
#if defined(CONFIG_COAP_SERVER)

include/zephyr/net/http/frame.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright (c) 2023, Emna Rekik
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_INCLUDE_NET_HTTP_SERVER_FRAME_H_
8+
#define ZEPHYR_INCLUDE_NET_HTTP_SERVER_FRAME_H_
9+
10+
#include <stdint.h>
11+
12+
enum http_frame_type {
13+
HTTP_SERVER_DATA_FRAME = 0x00,
14+
HTTP_SERVER_HEADERS_FRAME = 0x01,
15+
HTTP_SERVER_PRIORITY_FRAME = 0x02,
16+
HTTP_SERVER_RST_STREAM_FRAME = 0x03,
17+
HTTP_SERVER_SETTINGS_FRAME = 0x04,
18+
HTTP_SERVER_PUSH_PROMISE_FRAME = 0x05,
19+
HTTP_SERVER_PING_FRAME = 0x06,
20+
HTTP_SERVER_GOAWAY_FRAME = 0x07,
21+
HTTP_SERVER_WINDOW_UPDATE_FRAME = 0x08,
22+
HTTP_SERVER_CONTINUATION_FRAME = 0x09
23+
};
24+
25+
#define HTTP_SERVER_HPACK_METHOD 0
26+
#define HTTP_SERVER_HPACK_PATH 1
27+
28+
#define HTTP_SERVER_FLAG_SETTINGS_ACK 0x1
29+
#define HTTP_SERVER_FLAG_END_HEADERS 0x4
30+
#define HTTP_SERVER_FLAG_END_STREAM 0x1
31+
32+
#define HTTP_SERVER_FRAME_HEADER_SIZE 9
33+
#define HTTP_SERVER_FRAME_LENGTH_OFFSET 0
34+
#define HTTP_SERVER_FRAME_TYPE_OFFSET 3
35+
#define HTTP_SERVER_FRAME_FLAGS_OFFSET 4
36+
#define HTTP_SERVER_FRAME_STREAM_ID_OFFSET 5
37+
38+
struct http_settings_field {
39+
uint16_t id;
40+
uint32_t value;
41+
} __packed;
42+
43+
enum http_settings {
44+
HTTP_SETTINGS_HEADER_TABLE_SIZE = 1,
45+
HTTP_SETTINGS_ENABLE_PUSH = 2,
46+
HTTP_SETTINGS_MAX_CONCURRENT_STREAMS = 3,
47+
HTTP_SETTINGS_INITIAL_WINDOW_SIZE = 4,
48+
HTTP_SETTINGS_MAX_FRAME_SIZE = 5,
49+
HTTP_SETTINGS_MAX_HEADER_LIST_SIZE = 6,
50+
};
51+
52+
#endif

include/zephyr/net/http/method.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ enum http_method {
5757
HTTP_MKCALENDAR = 30, /**< MKCALENDAR */
5858
HTTP_LINK = 31, /**< LINK */
5959
HTTP_UNLINK = 32, /**< UNLINK */
60+
61+
HTTP_METHOD_END_VALUE /* keep this the last value */
6062
};
6163

6264
#ifdef __cplusplus

include/zephyr/net/http/server.h

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
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+
#include <stdint.h>
12+
13+
#include <zephyr/kernel.h>
14+
#include <zephyr/net/http/parser.h>
15+
#include <zephyr/net/http/hpack.h>
16+
#include <zephyr/net/socket.h>
17+
18+
#define HTTP_SERVER_CLIENT_BUFFER_SIZE CONFIG_HTTP_SERVER_CLIENT_BUFFER_SIZE
19+
#define HTTP_SERVER_MAX_STREAMS CONFIG_HTTP_SERVER_MAX_STREAMS
20+
#define HTTP_SERVER_MAX_CONTENT_TYPE_LEN CONFIG_HTTP_SERVER_MAX_CONTENT_TYPE_LENGTH
21+
22+
#define HTTP2_PREFACE "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
23+
24+
enum http_resource_type {
25+
HTTP_RESOURCE_TYPE_STATIC,
26+
HTTP_RESOURCE_TYPE_DYNAMIC,
27+
};
28+
29+
struct http_resource_detail {
30+
uint32_t bitmask_of_supported_http_methods;
31+
enum http_resource_type type;
32+
int path_len; /* length of the URL path */
33+
const char *content_encoding;
34+
};
35+
BUILD_ASSERT(NUM_BITS(
36+
sizeof(((struct http_resource_detail *)0)->bitmask_of_supported_http_methods))
37+
>= (HTTP_METHOD_END_VALUE - 1));
38+
39+
struct http_resource_detail_static {
40+
struct http_resource_detail common;
41+
const void *static_data;
42+
size_t static_data_len;
43+
};
44+
45+
struct http_client_ctx;
46+
47+
/** Indicates the status of the currently processed piece of data. */
48+
enum http_data_status {
49+
/** Transaction aborted, data incomplete. */
50+
HTTP_SERVER_DATA_ABORTED = -1,
51+
/** Transaction incomplete, more data expected. */
52+
HTTP_SERVER_DATA_MORE = 0,
53+
/** Final data fragment in current transaction. */
54+
HTTP_SERVER_DATA_FINAL = 1,
55+
};
56+
57+
/**
58+
* @typedef http_resource_dynamic_cb_t
59+
* @brief Callback used when data is received. Data to be sent to client
60+
* can be specified.
61+
*
62+
* @param client HTTP context information for this client connection.
63+
* @param status HTTP data status, indicate whether more data is expected or not.
64+
* @param data_buffer Data received.
65+
* @param data_len Amount of data received.
66+
* @param user_data User specified data.
67+
*
68+
* @return >0 amount of data to be sent to client, let server to call this
69+
* function again when new data is received.
70+
* 0 nothing to sent to client, close the connection
71+
* <0 error, close the connection.
72+
*/
73+
typedef int (*http_resource_dynamic_cb_t)(struct http_client_ctx *client,
74+
enum http_data_status status,
75+
uint8_t *data_buffer,
76+
size_t data_len,
77+
void *user_data);
78+
79+
struct http_resource_detail_dynamic {
80+
struct http_resource_detail common;
81+
http_resource_dynamic_cb_t cb;
82+
uint8_t *data_buffer;
83+
size_t data_buffer_len;
84+
struct http_client_ctx *holder;
85+
void *user_data;
86+
};
87+
88+
struct http_resource_detail_rest {
89+
struct http_resource_detail common;
90+
};
91+
92+
enum http_stream_state {
93+
HTTP_SERVER_STREAM_IDLE,
94+
HTTP_SERVER_STREAM_RESERVED_LOCAL,
95+
HTTP_SERVER_STREAM_RESERVED_REMOTE,
96+
HTTP_SERVER_STREAM_OPEN,
97+
HTTP_SERVER_STREAM_HALF_CLOSED_LOCAL,
98+
HTTP_SERVER_STREAM_HALF_CLOSED_REMOTE,
99+
HTTP_SERVER_STREAM_CLOSED
100+
};
101+
102+
enum http_server_state {
103+
HTTP_SERVER_FRAME_HEADER_STATE,
104+
HTTP_SERVER_PREFACE_STATE,
105+
HTTP_SERVER_REQUEST_STATE,
106+
HTTP_SERVER_FRAME_DATA_STATE,
107+
HTTP_SERVER_FRAME_HEADERS_STATE,
108+
HTTP_SERVER_FRAME_SETTINGS_STATE,
109+
HTTP_SERVER_FRAME_PRIORITY_STATE,
110+
HTTP_SERVER_FRAME_WINDOW_UPDATE_STATE,
111+
HTTP_SERVER_FRAME_CONTINUATION_STATE,
112+
HTTP_SERVER_FRAME_PING_STATE,
113+
HTTP_SERVER_FRAME_RST_STREAM_STATE,
114+
HTTP_SERVER_FRAME_GOAWAY_STATE,
115+
HTTP_SERVER_DONE_STATE,
116+
};
117+
118+
enum http1_parser_state {
119+
HTTP1_INIT_HEADER_STATE,
120+
HTTP1_WAITING_HEADER_STATE,
121+
HTTP1_RECEIVING_HEADER_STATE,
122+
HTTP1_RECEIVED_HEADER_STATE,
123+
HTTP1_RECEIVING_DATA_STATE,
124+
HTTP1_MESSAGE_COMPLETE_STATE,
125+
};
126+
127+
#define HTTP_SERVER_INITIAL_WINDOW_SIZE 65536
128+
129+
struct http_stream_ctx {
130+
int stream_id;
131+
enum http_stream_state stream_state;
132+
int window_size; /**< Stream-level window size. */
133+
};
134+
135+
struct http_frame {
136+
uint32_t length;
137+
uint32_t stream_identifier;
138+
uint8_t type;
139+
uint8_t flags;
140+
uint8_t *payload;
141+
};
142+
143+
struct http_client_ctx {
144+
int fd;
145+
bool preface_sent;
146+
bool has_upgrade_header;
147+
unsigned char buffer[HTTP_SERVER_CLIENT_BUFFER_SIZE];
148+
unsigned char *cursor; /**< Cursor indicating currently processed byte. */
149+
size_t data_len; /**< Data left to process in the buffer. */
150+
int window_size; /**< Connection-level window size. */
151+
enum http_server_state server_state;
152+
struct http_frame current_frame;
153+
struct http_resource_detail *current_detail;
154+
struct http_hpack_header_buf header_field;
155+
struct http_stream_ctx streams[HTTP_SERVER_MAX_STREAMS];
156+
struct http_parser_settings parser_settings;
157+
struct http_parser parser;
158+
unsigned char url_buffer[CONFIG_HTTP_SERVER_MAX_URL_LENGTH];
159+
unsigned char content_type[CONFIG_HTTP_SERVER_MAX_CONTENT_TYPE_LENGTH];
160+
size_t content_len;
161+
enum http_method method;
162+
enum http1_parser_state parser_state;
163+
int http1_frag_data_len;
164+
bool headers_sent;
165+
struct k_work_delayable inactivity_timer;
166+
};
167+
168+
/* Starts the HTTP2 server */
169+
int http_server_start(void);
170+
171+
/* Stops the HTTP2 server */
172+
int http_server_stop(void);
173+
174+
#endif

include/zephyr/net/http/service.h

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ struct http_resource_desc {
4444
const STRUCT_SECTION_ITERABLE_ALTERNATE(http_resource_desc_##_service, http_resource_desc, \
4545
_name) = { \
4646
.resource = _resource, \
47-
.detail = (_detail), \
47+
.detail = (void *)(_detail), \
4848
}
4949

5050
struct http_service_desc {
@@ -55,12 +55,14 @@ struct http_service_desc {
5555
size_t backlog;
5656
struct http_resource_desc *res_begin;
5757
struct http_resource_desc *res_end;
58+
#if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
5859
const sec_tag_t *sec_tag_list;
5960
size_t sec_tag_list_size;
61+
#endif
6062
};
6163

62-
#define __z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail, _res_begin, \
63-
_res_end, ...) \
64+
#define __z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail, _res_begin, \
65+
_res_end, ...) \
6466
static const STRUCT_SECTION_ITERABLE(http_service_desc, _name) = { \
6567
.host = _host, \
6668
.port = (uint16_t *)(_port), \
@@ -69,10 +71,12 @@ struct http_service_desc {
6971
.backlog = (_backlog), \
7072
.res_begin = (_res_begin), \
7173
.res_end = (_res_end), \
72-
.sec_tag_list = COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__), (NULL), \
73-
(GET_ARG_N(1, __VA_ARGS__))), \
74-
.sec_tag_list_size = COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__), (0), \
75-
(GET_ARG_N(1, GET_ARGS_LESS_N(1, __VA_ARGS__)))), \
74+
COND_CODE_1(CONFIG_NET_SOCKETS_SOCKOPT_TLS, \
75+
(.sec_tag_list = COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__), (NULL), \
76+
(GET_ARG_N(1, __VA_ARGS__))),), ()) \
77+
COND_CODE_1(CONFIG_NET_SOCKETS_SOCKOPT_TLS, \
78+
(.sec_tag_list_size = COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__), (0),\
79+
(GET_ARG_N(1, GET_ARGS_LESS_N(1, __VA_ARGS__))))), ())\
7680
}
7781

7882
/**

subsys/net/lib/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ if (CONFIG_DNS_RESOLVER
2727
add_subdirectory(dns)
2828
endif()
2929

30-
if(CONFIG_HTTP_PARSER_URL OR CONFIG_HTTP_PARSER OR CONFIG_HTTP_CLIENT)
30+
if(CONFIG_HTTP)
3131
add_subdirectory(http)
3232
endif()
3333

subsys/net/lib/http/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,8 @@ zephyr_include_directories(${ZEPHYR_BASE}/subsys/net/ip)
1111
zephyr_library_sources_ifdef(CONFIG_HTTP_PARSER http_parser.c)
1212
zephyr_library_sources_ifdef(CONFIG_HTTP_PARSER_URL http_parser_url.c)
1313
zephyr_library_sources_ifdef(CONFIG_HTTP_CLIENT http_client.c)
14+
zephyr_library_sources_ifdef(CONFIG_HTTP_SERVER http_server_core.c
15+
http_server_http1.c
16+
http_server_http2.c
17+
http_hpack.c
18+
http_huffman.c)

0 commit comments

Comments
 (0)