http-server.c

Basic HTTP server and router in C
git clone git://git.finwo.net/lib/http-server.c
Log | Files | Refs | README

commit f7b0ebc55151031b850e113eeddcbe9e68de3c26
parent 71c7f3ff5fc67cb605db69b8d3c579dc2e6e52ce
Author: Yersa Nordman <yersa@finwo.nl>
Date:   Tue, 24 Oct 2023 22:56:55 +0200

Add the ability to change port after start

Diffstat:
Mexample.c | 35++++++++++++++++++++++++++++-------
Msrc/http-server.c | 40+++++++++++++++++++++++-----------------
Msrc/http-server.h | 9+++++----
3 files changed, 56 insertions(+), 28 deletions(-)

diff --git a/example.c b/example.c @@ -2,11 +2,14 @@ #include <stdlib.h> #include <string.h> +#include "finwo/fnet.h" #include "finwo/http-parser.h" #include "tidwall/buf.h" #include "http-server.h" +uint16_t targetPort = 8080; + void onServing(char *addr, uint16_t port, void *udata) { printf("Serving at %s:%d\n", addr, port); } @@ -18,6 +21,12 @@ void onTick(void *udata) { printf("10 seconds have passed\n"); ticksHad = 0; } + + struct http_server_opts *opts = udata; + if (opts->port != targetPort) { + opts->port = targetPort; + fnet_close(opts->listen_connection); + } } void route_get_hello(struct http_server_reqdata *reqdata) { @@ -29,6 +38,16 @@ void route_get_hello(struct http_server_reqdata *reqdata) { return; } +void route_post_port(struct http_server_reqdata *reqdata) { + http_parser_header_set(reqdata->reqres->response, "Content-Type", "text/plain"); + targetPort = atoi(reqdata->reqres->request->body->data); + reqdata->reqres->response->body = calloc(1, sizeof(struct buf)); + reqdata->reqres->response->body->data = strdup("OK\n"); + reqdata->reqres->response->body->len = strlen(reqdata->reqres->response->body->data); + http_server_response_send(reqdata, true); + return; +} + void route_404(struct http_server_reqdata *reqdata) { http_parser_header_set(reqdata->reqres->response, "Content-Type", "text/plain"); reqdata->reqres->response->status = 404; @@ -40,19 +59,21 @@ void route_404(struct http_server_reqdata *reqdata) { } int main() { - struct http_server_events evs = { .serving = onServing, .close = NULL, .notFound = route_404, .tick = onTick, }; + struct http_server_opts opts = { + .evs = &evs, + .addr = "0.0.0.0", + .port = targetPort, + .udata = &opts, + }; - http_server_route("GET", "/hello", route_get_hello); + http_server_route("GET" , "/hello", route_get_hello); + http_server_route("POST", "/port" , route_post_port); - http_server_main(&(const struct http_server_opts){ - .evs = &evs, - .addr = "0.0.0.0", - .port = 8080, - }); + http_server_main(&opts); } diff --git a/src/http-server.c b/src/http-server.c @@ -8,10 +8,8 @@ #include "http-server.h" struct fnet_udata { - struct http_server_events *evs; - char *addr; - uint16_t port; - void *cudata; + struct http_server_opts *opts; + struct fnet_options_t *fnet_opts; }; struct hs_route { @@ -26,16 +24,16 @@ struct hs_route *registered_routes = NULL; void _hs_onServing(struct fnet_ev *ev) { struct fnet_udata *ludata = ev->udata; - if (ludata->evs && ludata->evs->serving) { - ludata->evs->serving(ludata->addr, ludata->port, ludata->cudata); + if (ludata->opts->evs && ludata->opts->evs->serving) { + ludata->opts->evs->serving(ludata->opts->addr, ludata->opts->port, ludata->opts->udata); } } void _hs_onTick(struct fnet_ev *ev) { struct fnet_udata *ludata = ev->udata; - if (ludata->evs && ludata->evs->tick) { - ludata->evs->tick(ludata->cudata); + if (ludata->opts->evs && ludata->opts->evs->tick) { + ludata->opts->evs->tick(ludata->opts->udata); } } @@ -94,7 +92,7 @@ void _hs_onConnect(struct fnet_ev *ev) { reqdata->connection = conn; reqdata->reqres = http_parser_pair_init(reqdata); reqdata->reqres->onRequest = _hs_onRequest; - reqdata->evs = ludata->evs; + reqdata->evs = ludata->opts->evs; ev->connection->udata = reqdata; // Setup data flowing from connection into reqres @@ -121,24 +119,32 @@ void http_server_route(const char *method, const char *path, void (*fn)(struct h registered_routes = route; } -void http_server_main(const struct http_server_opts *opts) { +void _hs_onListenClose(struct fnet_ev *ev) { + struct fnet_udata *ludata = ev->udata; + ludata->opts->listen_connection = fnet_listen(ludata->opts->addr, ludata->opts->port, ludata->fnet_opts); +} + +void http_server_main(struct http_server_opts *opts) { + if (!opts) exit(1); struct fnet_udata *ludata = calloc(1, sizeof(struct fnet_udata)); - ludata->addr = opts->addr; - ludata->port = opts->port; - ludata->cudata = opts->udata; - ludata->evs = opts->evs; + ludata->opts = opts; - if (!fnet_listen(opts->addr, opts->port, &((struct fnet_options_t){ + struct fnet_options_t fnet_opts = { .proto = FNET_PROTO_TCP, .flags = 0, .onListen = _hs_onServing, .onConnect = _hs_onConnect, .onData = NULL, .onTick = _hs_onTick, - .onClose = NULL, + .onClose = _hs_onListenClose, .udata = ludata, - }))) { + }; + + ludata->fnet_opts = &fnet_opts; + + ludata->opts->listen_connection = fnet_listen(ludata->opts->addr, ludata->opts->port, ludata->fnet_opts); + if (!(ludata->opts->listen_connection)) { exit(1); } diff --git a/src/http-server.h b/src/http-server.h @@ -13,9 +13,10 @@ struct http_server_reqdata { struct http_server_opts { struct http_server_events *evs; - char *addr; - uint16_t port; - void *udata; + char *addr; + uint16_t port; + void *udata; + struct fnet_t *listen_connection; }; struct http_server_events { @@ -25,7 +26,7 @@ struct http_server_events { void (*tick)(void *udata); }; -void http_server_main(const struct http_server_opts *opts); +void http_server_main(struct http_server_opts *opts); void http_server_response_send(struct http_server_reqdata *reqdata, bool close); void http_server_route(const char *method, const char *path, void (*fn)(struct http_server_reqdata*));