SLWEB_HANDLER(7)

NAME
slweb_handler - slweb high-level website configuration

SYNOPSIS

#include <slweb/handler.h>

DESCRIPTION
This component provides abstractions that allow library users to define the behaviour of a web server. Whereas slweb_http(7) defines the HTTP/1.1 server implementation and provides a data type (namely struct http_ctx) to handle an incoming connection, slweb_handler(7):

•   Defines the list of endpoints and supported operations.

•   Defines the port slweb must listen to.

•   Keeps track of all struct http_ctx objects. slweb_handler(7) provides the following functions:

•   handler_alloc(3): allocates a struct handler object, consumed by other functions from this component.

•   handler_free(3): frees the memory previously allocated by a call to handler_alloc(3).

•   handler_add(3): adds an endpoint to the server for a given HTTP/1.1 operation.

•   handler_listen(3): puts a struct handler object to initialize the server and handle connections in a loop. The handler_alloc(3) function requires some initial configuration parameters, given by struct handler_cfg, defined as:

    struct handler_cfg
    {
        const char *tmpdir;
        int (*length)(unsigned long long len, const struct http_cookie *c, struct http_response *r, void *user);
        void *user;
    };

tmpdir, length and user are passed directly to the struct http_cfg object used to initialize a struct http_ctx object. See slweb_http(7) for further reference about these members. However, a struct handler object as returned by handler_alloc(3) alone is not enough. One or more callbacks must be set up to define the behaviour of the web server. Every callback must follow the signature below, as defined by handler_fn:

    typedef int (*handler_fn)(const struct http_payload *p, struct http_response *r, void *user);

Please read slweb_http(7) for further refence on struct http_payload and struct http_response. user is a user-defined parameter previously defined by a call to handler_add(3).

EXAMPLE
The following source code shows how to set up a simple web server that listens to TCP port 8080 and defines / and /index.html as its endpoints. For the sake of simplicity, a static response body is returned, instead of using slweb_html(7) to generate HTML data. Please read slweb_html(7) for further reference on how to generate dynamic content.

    #include <slweb/handler.h>
    #include <slweb/http.h>
    #include <stddef.h>
    #include <stdlib.h>
    static int hello(const struct http_payload *const pl,
        struct http_response *const r, void *const user)
    {
        static const char page[] =
        {
            "<html><body><p>Hello from slweb!</p></body></html>"
        };
        *r = (const struct http_response)
        {
            .status = HTTP_STATUS_OK,
            .buf.ro = page,
            .n = sizeof page - 1
        };
        if (http_response_add_header(r, "Content-Type", "text/html"))
        {
            fprintf(stderr, "%s: http_response_add_header failed\n", __func__);
            return -1;
        }
        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
        };
        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;
    }

SEE ALSO
handler_alloc(3), handler_add(3), handler_free(3), slweb_http(7).

COPYRIGHT
Copyright (C) 2023 Xavier Del Campo Romero.

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.