From 65031ca3502e0c27780be847fd97c112546741a9 Mon Sep 17 00:00:00 2001 From: Xavier Del Campo Romero Date: Sat, 18 Nov 2023 00:56:04 +0100 Subject: Send HTTP headers to payload callback Even if libweb already parses some common headers, such as Content-Length, some users might find it interesting to inspect which headers were received from a request. Since HTTP/1.1 does not define a limit on the number of maximum headers a client can send, for security reasons a maximum value must be provided by the user. Any extra headers shall be then discarded by libweb. An example application showing this new feature is also provided. --- examples/headers/CMakeLists.txt | 4 ++ examples/headers/Makefile | 26 +++++++++++++ examples/headers/README.md | 16 ++++++++ examples/headers/main.c | 81 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+) create mode 100644 examples/headers/CMakeLists.txt create mode 100644 examples/headers/Makefile create mode 100644 examples/headers/README.md create mode 100644 examples/headers/main.c (limited to 'examples/headers') diff --git a/examples/headers/CMakeLists.txt b/examples/headers/CMakeLists.txt new file mode 100644 index 0000000..8c91fd7 --- /dev/null +++ b/examples/headers/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.13) +project(headers C) +add_executable(${PROJECT_NAME} main.c) +target_link_libraries(${PROJECT_NAME} PRIVATE web) diff --git a/examples/headers/Makefile b/examples/headers/Makefile new file mode 100644 index 0000000..4905fbd --- /dev/null +++ b/examples/headers/Makefile @@ -0,0 +1,26 @@ +.POSIX: + +PROJECT = headers +DEPS = \ + main.o +LIBWEB = ../../libweb.a +DYNSTR = ../../dynstr/libdynstr.a +CFLAGS = -I ../../include -I ../../dynstr/include +LIBWEB_FLAGS = -L ../../ -l web +DYNSTR_FLAGS = -L ../../dynstr -l dynstr + +all: $(PROJECT) + +clean: + rm -f $(DEPS) + +FORCE: + +$(PROJECT): $(DEPS) $(LIBWEB) $(DYNSTR) + $(CC) $(LDFLAGS) $(DEPS) $(LIBWEB_FLAGS) $(DYNSTR_FLAGS) -o $@ + +$(LIBWEB): FORCE + +cd ../../ && $(MAKE) + +$(DYNSTR): FORCE + +cd ../../dynstr && $(MAKE) diff --git a/examples/headers/README.md b/examples/headers/README.md new file mode 100644 index 0000000..01c243a --- /dev/null +++ b/examples/headers/README.md @@ -0,0 +1,16 @@ +# HTTP headers example + +This example shows a HTTP/1.1 server that listens to port `8080` and prints +the headers received from the client (up to a maximum of `max_headers`) to +standard output. + +## How to build + +If using `make(1)`, just run `make` from this directory. + +If using CMake, examples are built by default when configuring the project +from [the top-level `CMakeLists.txt`](../../CMakeLists.txt). + +## How to run + +Run the executable without any command line arguments. diff --git a/examples/headers/main.c b/examples/headers/main.c new file mode 100644 index 0000000..b465aa1 --- /dev/null +++ b/examples/headers/main.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include +#include +#include + +static const size_t max_headers = 5; + +static int hello(const struct http_payload *const pl, + struct http_response *const r, void *const user) +{ + printf("Got %zu headers from the client (max %zu).\n", + pl->n_headers, max_headers); + + for (size_t i = 0; i < pl->n_headers; i++) + { + const struct http_header *const h = &pl->headers[i]; + + printf("%s: %s\n", h->header, h->value); + } + + *r = (const struct http_response) + { + .status = HTTP_STATUS_OK + }; + + return 0; +} + +static int on_length(const unsigned long long len, + const struct http_cookie *const c, struct http_response *const r, + void *const user) +{ + *r = (const struct http_response) + { + .status = HTTP_STATUS_FORBIDDEN + }; + + return 1; +} + +int main(int argc, char *argv[]) +{ + int ret = EXIT_FAILURE; + const short port = 8080; + const struct handler_cfg cfg = + { + .length = on_length, + .max_headers = max_headers + }; + + struct handler *const h = handler_alloc(&cfg); + static const char *const urls[] = {"/", "/index.html"}; + + if (!h) + { + fprintf(stderr, "%s: handler_alloc failed\n", __func__); + goto end; + } + + for (size_t i = 0; i < sizeof urls / sizeof *urls; i++) + if (handler_add(h, urls[i], HTTP_OP_GET, hello, NULL)) + { + fprintf(stderr, "%s: handler_add failed\n", __func__); + goto end; + } + + if (handler_listen(h, port)) + { + fprintf(stderr, "%s: handler_listen failed\n", __func__); + goto end; + } + + ret = EXIT_SUCCESS; + +end: + handler_free(h); + return ret; +} -- cgit v1.2.3