Next: , Previous: , Up: Top   [Contents][Index]


1 Introduction

All symbols defined in the public API start with MHD_. MHD is a small HTTP daemon library. As such, it does not have any API for logging errors (you can only enable or disable logging to stderr). Also, it may not support all of the HTTP features directly, where applicable, portions of HTTP may have to be handled by clients of the library.

The library is supposed to handle everything that it must handle (because the API would not allow clients to do this), such as basic connection management. However, detailed interpretations of headers, such as range requests, are left to the main application. In particular, if an application developer wants to support range requests, he needs to explicitly indicate support in responses and also explicitly parse the range header and generate a response (for example, using the MHD_create_response_from_fd_at_offset call to serve ranges from a file). MHD does understands headers that control connection management (specifically, Connection: close and Expect: 100 continue are understood and handled automatically). Connection: upgrade is supported by passing control over the socket (or something that behaves like the real socket in the case of TLS) to the application (after sending the desired HTTP response header).

MHD largely ignores the semantics of the different HTTP methods, so clients are left to handle those. One exception is that MHD does understand HEAD and will only send the headers of the response and not the body, even if the client supplied a body. (In fact, clients do need to construct a response with the correct length, even for HEAD request.)

MHD understands POST data and is able to decode certain formats (at the moment only application/x-www-form-urlencoded and multipart/form-data) using the post processor API. The data stream of a POST is also provided directly to the main application, so unsupported encodings could still be processed, just not conveniently by MHD.

The header file defines various constants used by the HTTP protocol. This does not mean that MHD actually interprets all of these values. The provided constants are exported as a convenience for users of the library. MHD does not verify that transmitted HTTP headers are part of the standard specification; users of the library are free to define their own extensions of the HTTP standard and use those with MHD.

All functions are guaranteed to be completely reentrant and thread-safe. MHD checks for allocation failures and tries to recover gracefully (for example, by closing the connection). Additionally, clients can specify resource limits on the overall number of connections, number of connections per IP address and memory used per connection to avoid resource exhaustion.

1.1 Scope

MHD is currently used in a wide range of implementations. Examples based on reports we’ve received from developers include:

1.2 Thread modes and event loops

MHD supports four basic thread modes and up to three event loop styles.

The four basic thread modes are external sockets polling (MHD creates no threads, event loop is fully managed by the application), internal polling (MHD creates one thread for all connections), polling in thread pool (MHD creates a thread pool which is used to process all connections) and thread-per-connection (MHD creates one thread for listen sockets and then one thread per accepted connection).

These thread modes are then combined with the evet loop styles (polling function type). MHD support select, poll and epoll. select is available on all platforms, epoll and poll may not be available on some platforms. Note that it is possible to combine MHD using epoll with an external select-based event loop.

The default (if no other option is passed) is “external select”. The highest performance can typically be obtained with a thread pool using epoll. Apache Benchmark (ab) was used to compare the performance of select and epoll when using a thread pool and a large number of connections. Figure 1.1 shows the resulting plot from the benchmark.c example, which measures the latency between an incoming request and the completion of the transmission of the response. In this setting, the epoll thread pool with four threads was able to handle more than 45,000 connections per second on loopback (with Apache Benchmark running three processes on the same machine).

Data

Figure 1.1: Performance measurements for select vs. epoll (with thread-pool).

Not all combinations of thread modes and event loop styles are supported. This is partially to keep the API simple, and partially because some combinations simply make no sense as others are strictly superior. Note that the choice of style depends first of all on the application logic, and then on the performance requirements. Applications that perform a blocking operation while handling a request within the callbacks from MHD must use a thread per connection. This is typically rather costly. Applications that do not support threads or that must run on embedded devices without thread-support must use the external mode. Using epoll is only supported on some platform, thus portable applications must at least have a fallback option available. Table 1.1 lists the sane combinations.

selectpollepoll
externalyesnoyes
internalyesyesyes
thread poolyesyesyes
thread-per-connectionyesyesno

Table 1.1: Supported combinations of event styles and thread modes.

1.3 Compiling GNU libmicrohttpd

MHD uses the standard GNU system where the usual build process involves running

$ ./configure
$ make
$ make install

MHD supports various options to be given to configure to tailor the binary to a specific situation. Note that some of these options will remove portions of the MHD code that are required for binary-compatibility. They should only be used on embedded systems with tight resource constraints and no concerns about library versioning. Standard distributions including MHD are expected to always ship with all features enabled, otherwise unexpected incompatibilities can arise!

Here is a list of MHD-specific options that can be given to configure (canonical configure options such as “–prefix” are also supported, for a full list of options run “./configure –help”):

``--disable-curl''

disable running testcases using libcurl

``--disable-largefile''

disable support for 64-bit files

``--disable-messages''

disable logging of error messages (smaller binary size, not so much fun for debugging)

``--disable-https''

disable HTTPS support, even if GNUtls is found; this option must be used if eCOS license is desired as an option (in all cases the resulting binary falls under a GNU LGPL-only license)

``--disable-postprocessor''

do not include the post processor API (results in binary incompatibility)

``--disable-dauth''

do not include the authentication APIs (results in binary incompatibility)

``--disable-httpupgrade''

do not build code for HTTP “Upgrade” (smaller binary size, binary incompatible library)

``--disable-epoll''

do not include epoll support, even if it supported (minimally smaller binary size, good for portability testing)

``--enable-coverage''

set flags for analysis of code-coverage with gcc/gcov (results in slow, large binaries)

``--with-threads=posix,w32,none,auto''

sets threading library to use. With use “none” to not support threads. In this case, MHD will only support the “external” threading modes and not perform any locking of data structures! Use MHD_is_feature_supported(MHD_FEATURE_THREADS) to test if threads are available. Default is “auto”.

``--with-gcrypt=PATH''

specifies path to libgcrypt installation

``--with-gnutls=PATH''

specifies path to libgnutls installation

1.4 Validity of pointers

MHD will give applications access to its internal data structures via pointers via arguments and return values from its API. This creates the question as to how long those pointers are assured to stay valid.

Most MHD data structures are associated with the connection of an HTTP client. Thus, pointers associated with a connection are typically valid until the connection is finished, at which point MHD will call the MHD_RequestCompletedCallback if one is registered. Applications that have such a callback registered may assume that keys and values from the MHD_KeyValueIterator, return values from MHD_lookup_connection_value and the url, method and version arguments to the MHD_AccessHandlerCallback will remain valid until the respective MHD_RequestCompletedCallback is invoked.

In contrast, the upload_data argument of MHD_RequestCompletedCallback as well as all pointers from the MHD_PostDataIterator are only valid for the duration of the callback.

Pointers returned from MHD_get_response_header are valid as long as the response itself is valid.

1.5 Including the microhttpd.h header

Ideally, before including "microhttpd.h" you should add the necessary includes to define the uint64_t, size_t, fd_set, socklen_t and struct sockaddr data types. Which specific headers are needed may depend on your platform and your build system might include some tests to provide you with the necessary conditional operations. For possible suggestions consult platform.h and configure.ac in the MHD distribution.

Once you have ensured that you manually (!) included the right headers for your platform before "microhttpd.h", you should also add a line with #define MHD_PLATFORM_H which will prevent the "microhttpd.h" header from trying (and, depending on your platform, failing) to include the right headers.

If you do not define MHD_PLATFORM_H, the "microhttpd.h" header will automatically include headers needed on GNU/Linux systems (possibly causing problems when porting to other platforms).

1.6 SIGPIPE

MHD does not install a signal handler for SIGPIPE. On platforms where this is possible (such as GNU/Linux), it disables SIGPIPE for its I/O operations (by passing MSG_NOSIGNAL or similar). On other platforms, SIGPIPE signals may be generated from network operations by MHD and will cause the process to die unless the developer explicitly installs a signal handler for SIGPIPE.

Hence portable code using MHD must install a SIGPIPE handler or explicitly block the SIGPIPE signal. MHD does not do so in order to avoid messing with other parts of the application that may need to handle SIGPIPE in a particular way. You can make your application handle SIGPIPE by calling the following function in main:

static void
catcher (int sig)
{
}

static void
ignore_sigpipe ()
{
  struct sigaction oldsig;
  struct sigaction sig;

  sig.sa_handler = &catcher;
  sigemptyset (&sig.sa_mask);
#ifdef SA_INTERRUPT
  sig.sa_flags = SA_INTERRUPT;  /* SunOS */
#else
  sig.sa_flags = SA_RESTART;
#endif
  if (0 != sigaction (SIGPIPE, &sig, &oldsig))
    fprintf (stderr,
             "Failed to install SIGPIPE handler: %s\n", strerror (errno));
}

1.7 MHD_UNSIGNED_LONG_LONG

Some platforms do not support long long. Hence MHD defines a macro MHD_UNSIGNED LONG_LONG which will default to unsigned long long. For standard desktop operating systems, this is all you need to know.

However, if your platform does not support unsigned long long, you should change "platform.h" to define MHD_LONG_LONG and MHD_UNSIGNED_LONG_LONG to an appropriate alternative type and also define MHD_LONG_LONG_PRINTF and MHD_UNSIGNED_LONG_LONG_PRINTF to the corresponding format string for printing such a data type. Note that the “signed” versions are deprecated. Also, for historical reasons, MHD_LONG_LONG_PRINTF is without the percent sign, whereas MHD_UNSIGNED_LONG_LONG_PRINTF is with the percent sign. Newly written code should only use the unsigned versions. However, you need to define both in "platform.h" if you need to change the definition for the specific platform.

1.8 Portability to W32

libmicrohttpd in general ported well to W32. Most libmicrohttpd features are supported. W32 do not support some functions, like epoll and corresponding MHD features are not available on W32.

1.9 Portability to z/OS

To compile MHD on z/OS, extract the archive and run

iconv -f UTF-8 -t IBM-1047 contrib/ascebc > /tmp/ascebc.sh
chmod +x /tmp/ascebc.sh
for n in `find * -type f`
do
  /tmp/ascebc.sh $n
done

to convert all source files to EBCDIC. Note that you must run configure from the directory where the configure script is located. Otherwise, configure will fail to find the contrib/xcc script (which is a wrapper around the z/OS c89 compiler).


Next: , Previous: , Up: Top   [Contents][Index]