cstl
cstl copied to clipboard
Help me design / write a generic HTTP routing helper library for the http_s struct.
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