mirror of
https://git.gnunet.org/libmicrohttpd.git
synced 2026-09-25 04:09:31 +03:00
195 lines
8.3 KiB
Plaintext
195 lines
8.3 KiB
Plaintext
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,
|
|
optimising, 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
|