Skip to content

Commit b7091ed

Browse files
mrodgers-witekiokartben
authored andcommitted
net: http_server: serve resources only for their defined services
Ensure that HTTP resources can only be served to a client connected on the specific service(s) that the resource was registered against using the HTTP_RESOURCE_DEFINE macro. This allows different resources to be registered to different services, for example to make some resources only available via an HTTPS service and not via unencrypted HTTP. Signed-off-by: Matt Rodgers <[email protected]>
1 parent 3c88970 commit b7091ed

File tree

7 files changed

+78
-39
lines changed

7 files changed

+78
-39
lines changed

include/zephyr/net/http/server.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,9 @@ struct http_client_ctx {
400400
/** Socket descriptor associated with the server. */
401401
int fd;
402402

403+
/** HTTP service on which the client is connected */
404+
const struct http_service_desc *service;
405+
403406
/** Client data buffer. */
404407
unsigned char buffer[HTTP_SERVER_CLIENT_BUFFER_SIZE];
405408

include/zephyr/net/http/service.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ struct http_resource_desc {
6767
struct http_service_desc {
6868
const char *host;
6969
uint16_t *port;
70+
int *fd;
7071
void *detail;
7172
size_t concurrent;
7273
size_t backlog;
@@ -80,9 +81,11 @@ struct http_service_desc {
8081

8182
#define __z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail, _res_begin, \
8283
_res_end, ...) \
83-
const STRUCT_SECTION_ITERABLE(http_service_desc, _name) = { \
84+
static int _name##_fd = -1; \
85+
const STRUCT_SECTION_ITERABLE(http_service_desc, _name) = { \
8486
.host = _host, \
8587
.port = (uint16_t *)(_port), \
88+
.fd = &_name##_fd, \
8689
.detail = (void *)(_detail), \
8790
.concurrent = (_concurrent), \
8891
.backlog = (_backlog), \

subsys/net/lib/http/headers/server_internal.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ int enter_http2_request(struct http_client_ctx *client);
3737
int enter_http_done_state(struct http_client_ctx *client);
3838

3939
/* Others */
40-
struct http_resource_detail *get_resource_detail(const char *path, int *len, bool is_ws);
40+
struct http_resource_detail *get_resource_detail(const struct http_service_desc *service,
41+
const char *path, int *len, bool is_ws);
4142
int http_server_sendall(struct http_client_ctx *client, const void *buf, size_t len);
4243
void http_server_get_content_type_from_extension(char *url, char *content_type,
4344
size_t content_type_size);

subsys/net/lib/http/http_server_core.c

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ int http_server_init(struct http_server_ctx *ctx)
237237
LOG_DBG("Initialized HTTP Service %s:%u",
238238
svc->host ? svc->host : "<any>", *svc->port);
239239

240+
*svc->fd = fd;
240241
ctx->fds[count].fd = fd;
241242
ctx->fds[count].events = ZSOCK_POLLIN;
242243
count++;
@@ -299,6 +300,10 @@ static void close_all_sockets(struct http_server_ctx *ctx)
299300

300301
ctx->fds[i].fd = -1;
301302
}
303+
304+
HTTP_SERVICE_FOREACH(svc) {
305+
*svc->fd = -1;
306+
}
302307
}
303308

304309
static void client_release_resources(struct http_client_ctx *client)
@@ -393,9 +398,22 @@ void http_client_timer_restart(struct http_client_ctx *client)
393398
k_work_reschedule(&client->inactivity_timer, INACTIVITY_TIMEOUT);
394399
}
395400

396-
static void init_client_ctx(struct http_client_ctx *client, int new_socket)
401+
static const struct http_service_desc *lookup_service(int server_fd)
402+
{
403+
HTTP_SERVICE_FOREACH(svc) {
404+
if (*svc->fd == server_fd) {
405+
return svc;
406+
}
407+
}
408+
409+
return NULL;
410+
}
411+
412+
static void init_client_ctx(struct http_client_ctx *client, const struct http_service_desc *svc,
413+
int new_socket)
397414
{
398415
client->fd = new_socket;
416+
client->service = svc;
399417
client->data_len = 0;
400418
client->server_state = HTTP_SERVER_PREFACE_STATE;
401419
client->has_upgrade_header = false;
@@ -523,6 +541,7 @@ static int handle_http_request(struct http_client_ctx *client)
523541
static int http_server_run(struct http_server_ctx *ctx)
524542
{
525543
struct http_client_ctx *client;
544+
const struct http_service_desc *service;
526545
eventfd_t value;
527546
bool found_slot;
528547
int new_socket;
@@ -600,6 +619,9 @@ static int http_server_run(struct http_server_ctx *ctx)
600619
continue;
601620
}
602621

622+
service = lookup_service(ctx->fds[i].fd);
623+
__ASSERT(NULL != service, "fd not associated with a service");
624+
603625
found_slot = false;
604626

605627
for (j = ctx->listen_fds; j < ARRAY_SIZE(ctx->fds); j++) {
@@ -615,7 +637,7 @@ static int http_server_run(struct http_server_ctx *ctx)
615637

616638
LOG_DBG("Init client #%d", j - ctx->listen_fds);
617639

618-
init_client_ctx(&ctx->clients[j - ctx->listen_fds],
640+
init_client_ctx(&ctx->clients[j - ctx->listen_fds], service,
619641
new_socket);
620642
found_slot = true;
621643
break;
@@ -713,34 +735,30 @@ static bool skip_this(struct http_resource_desc *resource, bool is_websocket)
713735
return false;
714736
}
715737

716-
struct http_resource_detail *get_resource_detail(const char *path,
717-
int *path_len,
718-
bool is_websocket)
738+
struct http_resource_detail *get_resource_detail(const struct http_service_desc *service,
739+
const char *path, int *path_len, bool is_websocket)
719740
{
720-
HTTP_SERVICE_FOREACH(service) {
721-
HTTP_SERVICE_FOREACH_RESOURCE(service, resource) {
722-
if (skip_this(resource, is_websocket)) {
723-
continue;
724-
}
725-
726-
if (IS_ENABLED(CONFIG_HTTP_SERVER_RESOURCE_WILDCARD)) {
727-
int ret;
728-
729-
ret = fnmatch(resource->resource, path,
730-
(FNM_PATHNAME | FNM_LEADING_DIR));
731-
if (ret == 0) {
732-
*path_len = strlen(resource->resource);
733-
return resource->detail;
734-
}
735-
}
741+
HTTP_SERVICE_FOREACH_RESOURCE(service, resource) {
742+
if (skip_this(resource, is_websocket)) {
743+
continue;
744+
}
736745

737-
if (compare_strings(path, resource->resource) == 0) {
738-
NET_DBG("Got match for %s", resource->resource);
746+
if (IS_ENABLED(CONFIG_HTTP_SERVER_RESOURCE_WILDCARD)) {
747+
int ret;
739748

749+
ret = fnmatch(resource->resource, path, (FNM_PATHNAME | FNM_LEADING_DIR));
750+
if (ret == 0) {
740751
*path_len = strlen(resource->resource);
741752
return resource->detail;
742753
}
743754
}
755+
756+
if (compare_strings(path, resource->resource) == 0) {
757+
NET_DBG("Got match for %s", resource->resource);
758+
759+
*path_len = strlen(resource->resource);
760+
return resource->detail;
761+
}
744762
}
745763

746764
NET_DBG("No match for %s", path);

subsys/net/lib/http/http_server_http1.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -859,7 +859,7 @@ int handle_http1_request(struct http_client_ctx *client)
859859

860860
if (client->websocket_upgrade) {
861861
if (IS_ENABLED(CONFIG_HTTP_SERVER_WEBSOCKET)) {
862-
detail = get_resource_detail(client->url_buffer,
862+
detail = get_resource_detail(client->service, client->url_buffer,
863863
&path_len, true);
864864
if (detail == NULL) {
865865
goto not_found;
@@ -900,7 +900,7 @@ int handle_http1_request(struct http_client_ctx *client)
900900
}
901901
}
902902

903-
detail = get_resource_detail(client->url_buffer, &path_len, false);
903+
detail = get_resource_detail(client->service, client->url_buffer, &path_len, false);
904904
if (detail != NULL) {
905905
detail->path_len = path_len;
906906

subsys/net/lib/http/http_server_http2.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,7 +1029,7 @@ int handle_http1_to_http2_upgrade(struct http_client_ctx *client)
10291029
client->preface_sent = true;
10301030
}
10311031

1032-
detail = get_resource_detail(client->url_buffer, &path_len, false);
1032+
detail = get_resource_detail(client->service, client->url_buffer, &path_len, false);
10331033
if (detail != NULL) {
10341034
detail->path_len = path_len;
10351035

@@ -1509,7 +1509,7 @@ int handle_http_frame_headers(struct http_client_ctx *client)
15091509
return 0;
15101510
}
15111511

1512-
detail = get_resource_detail(client->url_buffer, &path_len, false);
1512+
detail = get_resource_detail(client->service, client->url_buffer, &path_len, false);
15131513
if (detail != NULL) {
15141514
detail->path_len = path_len;
15151515

tests/net/lib/http_server/common/src/main.c

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -296,55 +296,69 @@ ZTEST(http_service, test_HTTP_RESOURCE_DEFINE)
296296
}
297297
}
298298

299-
extern struct http_resource_detail *get_resource_detail(const char *path,
299+
extern struct http_resource_detail *get_resource_detail(const struct http_service_desc *service,
300+
const char *path,
300301
int *path_len,
301302
bool is_websocket);
302303

303-
#define CHECK_PATH(path, len) ({ *len = 0; get_resource_detail(path, len, false); })
304+
#define CHECK_PATH(svc, path, len) ({ *len = 0; get_resource_detail(&svc, path, len, false); })
304305

305306
ZTEST(http_service, test_HTTP_RESOURCE_WILDCARD)
306307
{
307308
struct http_resource_detail *res;
308309
int len;
309310

310-
res = CHECK_PATH("/", &len);
311+
res = CHECK_PATH(service_A, "/", &len);
311312
zassert_not_null(res, "Cannot find resource");
312313
zassert_true(len > 0, "Length not set");
313314
zassert_equal(res, RES(0), "Resource mismatch");
314315

315-
res = CHECK_PATH("/f", &len);
316+
res = CHECK_PATH(service_D, "/f", &len);
316317
zassert_is_null(res, "Resource found");
317318
zassert_equal(len, 0, "Length set");
318319

319-
res = CHECK_PATH("/foo1.html", &len);
320+
res = CHECK_PATH(service_D, "/foo1.html", &len);
320321
zassert_not_null(res, "Cannot find resource");
321322
zassert_true(len > 0, "Length not set");
322323
zassert_equal(res, RES(0), "Resource mismatch");
323324

324-
res = CHECK_PATH("/foo2222.html", &len);
325+
res = CHECK_PATH(service_D, "/foo2222.html", &len);
325326
zassert_not_null(res, "Cannot find resource");
326327
zassert_true(len > 0, "Length not set");
327328
zassert_equal(res, RES(1), "Resource mismatch");
328329

329-
res = CHECK_PATH("/fbo3.html", &len);
330+
res = CHECK_PATH(service_D, "/fbo3.html", &len);
330331
zassert_not_null(res, "Cannot find resource");
331332
zassert_true(len > 0, "Length not set");
332333
zassert_equal(res, RES(1), "Resource mismatch");
333334

334-
res = CHECK_PATH("/fbo3.htm", &len);
335+
res = CHECK_PATH(service_D, "/fbo3.htm", &len);
335336
zassert_not_null(res, "Cannot find resource");
336337
zassert_true(len > 0, "Length not set");
337338
zassert_equal(res, RES(0), "Resource mismatch");
338339

339-
res = CHECK_PATH("/fbo4.html", &len);
340+
res = CHECK_PATH(service_D, "/fbo4.html", &len);
340341
zassert_not_null(res, "Cannot find resource");
341342
zassert_true(len > 0, "Length not set");
342343
zassert_equal(res, RES(3), "Resource mismatch");
343344

344-
res = CHECK_PATH("/fs/index.html", &len);
345+
res = CHECK_PATH(service_A, "/fs/index.html", &len);
345346
zassert_not_null(res, "Cannot find resource");
346347
zassert_true(len > 0, "Length not set");
347348
zassert_equal(res, RES(5), "Resource mismatch");
349+
350+
/* Resources that only exist on one service should not be found on another */
351+
res = CHECK_PATH(service_A, "/foo1.htm", &len);
352+
zassert_is_null(res, "Resource found");
353+
zassert_equal(len, 0, "Length set");
354+
355+
res = CHECK_PATH(service_A, "/foo2222.html", &len);
356+
zassert_is_null(res, "Resource found");
357+
zassert_equal(len, 0, "Length set");
358+
359+
res = CHECK_PATH(service_A, "/fbo3.htm", &len);
360+
zassert_is_null(res, "Resource found");
361+
zassert_equal(len, 0, "Length set");
348362
}
349363

350364
extern void http_server_get_content_type_from_extension(char *url, char *content_type,

0 commit comments

Comments
 (0)