libmicrohttpd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [libmicrohttpd] STF M1


From: Emmanuel Engelhart
Subject: Re: [libmicrohttpd] STF M1
Date: Sat, 25 May 2024 16:36:20 +0200
User-agent: Mozilla Thunderbird

Hi Christian

Congratulation to all the developers for this first milestone!

I can not wait to make the use of it in Kiwix Server.

Wish you the best until the release!

Kelson

On 17.04.24 14:59, Christian Grothoff wrote:
Dear all,

We're happy to announce reaching the first milestone for the
STF-funded MHD 2.0 project, which is completing the MHD HTTP header
and thus the design for the next generation API.  We have now
spent several months iterating between discussing, designing,
optimizing, editing, and testing details and are finally
happy with the result.

Key objectives for us were:

- simplify application code that uses MHD
- keep the API and the MHD code size small
- ensure the API is extensible
- enable use of different TLS backends, avoid backend-specific
   settings to use backends in the same way.
- make API work with HTTP 1.x, HTTP/2 and HTTP/3
- preserve or improve portability across platforms
- stay compatible to a wide range of C and C++ compilers

The main changes these objectives inspired are to:

- Split the MHD_AccessHandlerCallback functionality into
   various separate callbacks to keep the API simple for
   simple requests while allowing complex logic to be
   incrementally introduced via the new "struct MHD_Action".
   Main effects:
   * improved type safety
   * client code most likely to always need all arguments
     passed to callbacks, while keeping rarely used
     arguments available via the introspection API
   * harder or impossible to make calls at the wrong time
     or to forget to do key processing steps
   * clients more likely to avoid repeated URL dispatching
   * Easier to add commonly used features like a generic
     URL dispatcher
   * Improved modularity, easier to not compile in some
     features (actions) to minimize code size
- We changed how MHD is configured, providing a new
   strongly-typed but still extensible mechanism
   to set options, avoiding the use of 'varargs' for
   options while also not introducing new symbols for
   any kind of option. The new construction uses
   either inline functions or macros depending on the
   compiler to initialize a struct with a variant union;
   as a result, application developers get the experience
   of using well-typed functions, while no such functions
   actually exist in the library, keeping the code size
   minimal, especially if features are not even used :-).
- Unified the way how settings are used for daemon,
   connection and response objects.
- Removed the separation of options and flags and
   made it harder to pass inconsistent options
- improved terminology across the API, in particular by
   eliminating confusion between 'request' and 'connection',
   but also by introducing new 'nouns' such as 'session',
   'stream' and 'action', but also 'String' which returns a
   'String' that is both 0-terminated but ALSO has a
   known length (eliminating need for applications
   to call strlen() on all strings returned by MHD).
   Also changed the API to use more consistent
   prefixes for related functions by using
   "MHD_subject_verb_object" naming convention
- significantly simplified for application processing of
   client's upload. Removed the need for troublesome (for
   application) incremental processing (especially problematic
   for forms processing), while keeping automatic limits
   for memory allocations, preventing by design a wide range
   of remote attacks.
- Added unified and detailed introspection API for library,
   daemon, connection, stream and request objects.
   The API is designed in the same way for all object, simplifying
   use for the application. The new API is detailed and allow
   application to extract any required information in a simple
   way. Also separated "fixed" and "dynamic" properties of objects
   for letting compiler optimise application code better.
- Integrated HTTP status into the response object, as
   this is way more logical and we are aware of various
   implementations being forced to basically pass them
   around as a tuple.
- simplified API for common-case of one-shot responses by
   eliminating need for destroy response in most cases
- Improved portability by avoiding fixed types, like uint32_t,
   as they may not exist on some platforms. Instead use
   types like uint_fast32_t.  Avoided use of enums with very
   large bitmasks as 'int' could be just 16 bits on some platforms
   resulting in enum values higher than 65535 being silently dropped.
- Improved possibility of use of zero-copy style for parsing
   uploaded data, including of the PostProcessor parser while
   still allowing applications to do stream processing if data
   does not fit into main memory. This both simplifies usage
   in the common case where uploaded data is small, while also
   nicely supporting use-cases with large data streams.
- Made responses unmodifiable after first use. Modifiable responses
   cannot be thread-safe. However, MHD-generated headers (Date,
   Connection/Keep-Alive) are part of the *request* and do not count
   as part of the immutable "response" here.  Removed "footers" from
   responses.  With unmodifiable responses everything should be "headers".
   However, footers are supported as part of a *request* instead.
- Move response codes from MHD_HTTP_xxx namespace to MHD_HTTP_CODE_xxx
   namespace. This avoids potential clashes with other MHD constant names.
- Introduced various new "enums" especially for constants
   introduced in HTTP/2 where use of these constants can
   then avoid having to map between protocol numbers and
   strings (but applications may still also use the strings)
   This also includes better status codes returned from
   API calls to diagnose issues (no more just "YES/NO")
- Let application to use request methods as a enum, avoid repeated
   string comparison by sharing result of the already performed
   internal detection of the request method.  Keep ability to
   use non-standard HTTP requests methods if needed via use
   of introspection API.
- Introduced "MHD_APP_SOCKET_CNTX_TYPE" hack to allow
   applications to improve type-safety by overriding
   the type of "closure" arguments instead of using
   "void *" pointers.
- Significant re-design of the event loop APIs to simplify integrating
   MHD with external event loops while preserving O(1) processing cost.
- Added many annotations to help compiler determine invariants (if
   supported by the compiler), such as arguments not being NULL, etc.
- Removal of various legacy symbols only exported for API compatibility.


While these are lots of changes, we want to give you a first brief preview of how this will impact client code using the library.  Here is an example of how
clients used to initialize the MHD daemon (from demo.c):

OLD>>
d = MHD_start_daemon (
     MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD
     | MHD_USE_ERROR_LOG,
     (uint16_t) port,
     NULL, NULL,
     &generate_page,
     NULL,
     MHD_OPTION_CONNECTION_MEMORY_LIMIT,
     (size_t) (256 * 1024),
#ifdef PRODUCTION
     MHD_OPTION_PER_IP_CONNECTION_LIMIT,
     (unsigned int) (64),
#endif
     MHD_OPTION_CONNECTION_TIMEOUT,
     (unsigned int) (120 /* seconds */),
     MHD_OPTION_THREAD_POOL_SIZE,
     (unsigned int) NUMBER_OF_THREADS,
     MHD_OPTION_NOTIFY_COMPLETED,
     &response_completed_callback,
     NULL,
     MHD_OPTION_END);
if (NULL == d)
   error();
<<

This was one big variadic mess, and getting any of the
types wrong for any of the options could result in
trouble, sometimes depending on the target platform.

With MHD 2.0, the same code will look like this:

NEW>>
d = MHD_daemon_create (&generate_page,
                        NULL);
if (MHD_SC_OK !=
     MHD_daemon_options_set (
       d,
       MHD_D_OPTION_BIND_PORT (MHD_AF_DUAL, port),
       MHD_D_OPTION_WM_WORKER_THREADS (NUMBER_OF_THREADS),
       MHD_D_OPTION_CONN_MEMORY_LIMIT (256*1024),
       MHD_D_OPTION_PER_IP_LIMIT (64),
       MHD_D_OPTION_DEFAULT_TIMEOUT (120),
       MHD_D_OPTION_NOTIFY_CONNECTION (&response_completed_callback,
                                       NULL)))
   error();
if (MHD_SC_OK !=
     MHD_daemon_start (d))
   error();
<<

Note that you can can call MHD_daemon_options_set() multiple times if you need to handle errors for individual options.  Thanks to extensive trickery on our part, the resulting type-safe code should *also* be almost as compact and fast as the previous version (mostly, this adds two additional library API calls, but in return you can get more precise status codes back).


While we thought hard about the new API and poured our experience into the re-design, we still might have overlooked something and thus value community feedback.

We thank Sovereign Tech Fund for funding this work.

Happy hacking!

Christian & Evgeny


--
Kiwix - Wikipedia Offline & more
* Web: https://kiwix.org/
* Mastodon: https://mastodon.social/@kiwix
* Wiki: https://wiki.kiwix.org/

Attachment: OpenPGP_signature.asc
Description: OpenPGP digital signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]