cstl icon indicating copy to clipboard operation
cstl copied to clipboard

Help me design / write a generic HTTP routing helper library for the http_s struct.

Open thierry-f-78 opened this issue 1 year ago • 5 comments

Following this thread : https://github.com/boazsegev/facil.io/issues/155

After reading fio-stl, I better understand your position in general, and more particularly regarding regexps.

I therefore identify the wrappers strtol for integers and glob for wildcards. I will remove the regexps (anyway, regexes are heavy, slow and difficult to debug, but they make life easier for the end user). The other types I propose are trivial.

However, I don't see anything in fio-stl for timestamps.

Here's a proposed API.

I wonder if the router shouldn't return a list of "void *" that the user can execute as they want (blocking or non-blocking).

I wonder if the error reporting system should be rethought. Indeed, when parsing something complex, the user needs an error message that is more elaborate than "ok" / "nok".

/* ************************************************************************* */
#if !defined(FIO_INCLUDE_FILE) /* Dev test - ignore line */
#define FIO___DEV___           /* Development inclusion - ignore line */
#define FIO_ROUTER             /* Development inclusion - ignore line */
#include "./include.h"         /* Development inclusion - ignore line */
#endif                         /* Development inclusion - ignore line */
/* *****************************************************************************




                      HTTP requests router



Copyright and License: see header file (000 copyright.h) or top of file
***************************************************************************** */
#if defined(FIO_ROUTER) && !defined(H___FIO_ROUTER___H) &&                     \
    !defined(FIO___RECURSIVE_INCLUDE)
#define H___FIO_ROUTER___H 1

/* *****************************************************************************
Router configuration settings
***************************************************************************** */

/** Struct used to define routes */
typedef struct fio_router_s fio_router_s;

/**
 * This function handle http request, return 0 to continue processing
 * return -1 to stop processing with error, return 1 to stop processing
 * without error.
 */
typedef int (*fio_handler_t)(fio_http_s *h, int args_num, void **args);

/** Create a new router system */
FIO_IFUNC fio_router_t *fio_router_new();

/** Destroy the router system */
FIO_IFUNC void fio_router_free(fio_router_t *router);

/** Register a route
 *
 * "methods" is a comma separated list of methods.
 *
 *    GET,POST
 *
 * "path" is a path according with this EBNF definition
 *
 *    path = ["/"], { segment, "/" }, segment, ["/"]
 *
 *    segment = static_segment | dynamic_segment ;
 *
 *    static_segment = ["::", ] { character - ":" } ;
 *
 *    dynamic_segment = ":", name, [":", match] ;
 *
 *    name = (letter | "_"), { letter | digit | "_" } ;
 *
 *    match = ("~", regexp) | ("%", wildcard) | type_match | enum_match |
 *            date_match | hex_match | range_match ; type_match = "int32" |
 *            "uint32" | "int64" | "uint64" | "bool" | "b64" | "b64i" | "uuid" |
 *            "email" | "slug" ;
 *
 *    hex_match = ("hex" | "hexl" | "hexu"), ["(", length, ")"] ;
 *
 *    regexp = ? PCRE compatible regular expression ? ;
 *
 *    wildcard = ? simplified wildcard pattern, e.g., "*" for any characters,
 *               "?" for single character ? ;
 *
 *    length = digit - "0", { digit } ;
 *
 *    enum_match = * "enum", "(", word_list, ")" ;
 *
 *    word_list = word, { ",", word } ;
 *
 *    word = * (letter | digit | "-" | "_"), { letter | digit | "-" | "_" } ;
 *
 *    date_match = * "date", ["(", date_format, ")"] ;
 *
 *    range_match = "range", "(", range_list, ")" ;
 *
 *    range_list = range, { ",", range } ;
 *
 *    range = single_value | open_range | closed_range ;
 *
 *    single_value = number ; open_range = (number, "-") | ("-", number) ;
 *
 *    closed_range = number, "-", number ;
 *
 *    number = digit, { digit }, [".", { digit }] ;
 *
 *    letter = "A" | "B" | "C" | ... | "Z" | "a" | "b" | "c" |
 *             ... | "z" ; digit = "0" | "1" | "2" | ... | "8" | "9" ;
 *
 *    character = ? any Unicode character ? ;
 *
 *    date_format = ? date format string * ? ;
 *
 *  the "type_match" list could be completed with the function
 *  "fio_router_add_type" described below
 *
 *  exemples:
 *
 *  "content_types" is comment separated list of wildcard content-types.
 *  (c-comments tag forbid some form, so remove spaces if you copy these
 *  examples).
 *
 *    "application / *"
 * 	"application/json,application/ld+json,application/csp-report,application/manifest+json,application/schema+json,application/problem+json"
 *    "* / *"
 *    "" : same than "* / *"
 *
 * return 0 is the route is register, otherwise returns -1.
 *
 * Usage example:
 *
 * fio_route(router, "GET,POST", "/api/users/:id", "application/json",
 *           handle_users);
 *
 * fio_route(router, "GET,POST", "/api/users/:id:hex(32)",
 *           "* / *", handle_users);
 */
FIO_IFUNC int fio_register_route(fio_router_t *router,
                                 const char *methods,
                                 const char *path,
                                 const char *content_types,
                                 fio_handler_t handler);

/** Define validation and parsing functions for custom parameters types
 *
 *  The function gets buffer and it length (buffer is not nul terminated).
 *  ptr points on opaque pointer.
 *  The function fill opaque pointer with parser value and return 0 if
 *  the parser is a success otherwise return -1.
 */
typedef int (*fio_parser_t)(const char *buffer, int length, void **ptr);

/** Add custom parameters types
 *
 *  The fucntion add application specific parser. This parser can be used
 *  in path definition. The specific parser is just a keyword and cannot
 *  handle parameters. The fucntion fails if the parser nale already exists.
 *  Return 0 in success case, otherwise return -1.
 */
FIO_IFUNC int fio_router_add_type(const char *type_name, fio_parser_t parser);

/** Add middleware to a router
 *
 *  The middleware function is executed when the router is selectionned and
 *  at least one item matchs.
 *
 *  The function returns 0 if the registration is success, otherwise it returns
 *  -1. Note this function fail only on out of memory error.
 */
FIO_IFUNC int fio_router_set_middleware(fio_router_t *router,
                                        fio_handler_t middleware);

/** Add a sub-router
 *
 *  bind sub router on some path. More than one subrouter could be registered
 *  on specific path. There are evaluated in the declaration order.
 *
 *  The function returns 0 if the registration is success, otherwise it returns
 *  -1.
 */
FIO_IFUNC int fio_router_mount(fio_router_t *parent,
                               const char *prefix,
                               fio_router_t *child);

/* *****************************************************************************
Router compilation and runtime
***************************************************************************** */

/** Used to execute router */
typedef struct fio_router_exec_s fio_router_exec_s;

/** Compile the router system
 *
 *  Compile declared routes. Return NULL if an error occurs, otherwise
 *  return pointer on new router_exec instance.
 */
FIO_IFUNC fio_router_exec_s *fio_router_compile(fio_router_t *router);

/** Destroy the router exec system */
FIO_IFUNC void fio_router_exec_free(fio_router_exec_s *router_exec);

/** Execute router
 *
 *  Return -1 if a critical error occurs, otherwise return 0 to continue
 *  processing, or 1 to stop processing.
 */
FIO_IFUNC int fio_router_exec(fio_router_exec_s *router_exec, fio_http_s *h)

/* *****************************************************************************
ROUTER - cleanup
***************************************************************************** */
#undef FIO___ROUTER_ON_ALLOC
#undef FIO___ROUTER_ON_FREE
#endif /* FIO_EXTERN_COMPLETE*/
#endif /* FIO_ROUTER */
#undef FIO_ROUTER

thierry-f-78 avatar Aug 09 '24 12:08 thierry-f-78