This is libmicrohttpd-tutorial.info, produced by makeinfo version 7.1.1
from libmicrohttpd-tutorial.texi.

This tutorial documents GNU libmicrohttpd version 1.0.8, last updated 28
July 2026.

   Copyright (c) 2008 Sebastian Gerhardt.

   Copyright (c) 2010, 2011, 2012, 2013, 2016, 2021, 2026 Christian
Grothoff.
     Permission is granted to copy, distribute and/or modify this
     document under the terms of the GNU Free Documentation License,
     Version 1.3 or any later version published by the Free Software
     Foundation; with no Invariant Sections, no Front-Cover Texts, and
     no Back-Cover Texts.  A copy of the license is included in the
     section entitled "GNU Free Documentation License".
INFO-DIR-SECTION Software libraries
START-INFO-DIR-ENTRY
* libmicrohttpdtutorial: (libmicrohttpd-tutorial).       A tutorial for GNU libmicrohttpd.
END-INFO-DIR-ENTRY


File: libmicrohttpd-tutorial.info,  Node: Top,  Next: Introduction,  Up: (dir)

A Tutorial for GNU libmicrohttpd
********************************

This tutorial documents GNU libmicrohttpd version 1.0.8, last updated 28
July 2026.

   Copyright (c) 2008 Sebastian Gerhardt.

   Copyright (c) 2010, 2011, 2012, 2013, 2016, 2021, 2026 Christian
Grothoff.
     Permission is granted to copy, distribute and/or modify this
     document under the terms of the GNU Free Documentation License,
     Version 1.3 or any later version published by the Free Software
     Foundation; with no Invariant Sections, no Front-Cover Texts, and
     no Back-Cover Texts.  A copy of the license is included in the
     section entitled "GNU Free Documentation License".

* Menu:

* Introduction::
* Hello browser example::
* Exploring requests::
* Response headers::
* Supporting basic authentication::
* Processing POST data::
* Improved processing of POST data::
* Session management::
* Generating responses on the fly::
* Answering from another thread::
* Adding a layer of security::
* Upgrading connections::
* Bibliography::
* License text::
* Example programs::


File: libmicrohttpd-tutorial.info,  Node: Introduction,  Next: Hello browser example,  Prev: Top,  Up: Top

1 Introduction
**************

This tutorial is for developers who want to learn how they can add HTTP
serving capabilities to their applications with the _GNU libmicrohttpd_
library, abbreviated _MHD_. The reader will learn how to implement basic
HTTP functions from simple executable sample programs that implement
various features.

   The text is supposed to be a supplement to the API reference manual
of _GNU libmicrohttpd_ and for that reason does not explain many of the
parameters.  Therefore, the reader should always consult the manual to
find the exact meaning of the functions used in the tutorial.
Furthermore, the reader is encouraged to study the relevant _RFCs_,
which document the HTTP standard.

   _GNU libmicrohttpd_ is assumed to be already installed.  This
tutorial is written for version 1.0.8.  At the time being, this tutorial
has only been tested on _GNU/Linux_ machines even though efforts were
made not to rely on anything that would prevent the samples from being
built on similar systems.

1.1 History
===========

This tutorial was originally written by Sebastian Gerhardt for MHD
0.4.0.  It was slightly polished and updated to MHD 0.9.0 by Christian
Grothoff.


File: libmicrohttpd-tutorial.info,  Node: Hello browser example,  Next: Exploring requests,  Prev: Introduction,  Up: Top

2 Hello browser example
***********************

The most basic task for a HTTP server is to deliver a static text
message to any client connecting to it.  Given that this is also easy to
implement, it is an excellent problem to start with.

   For now, the particular URI the client asks for shall have no effect
on the message that will be returned.  In addition, the server shall end
the connection after the message has been sent so that the client will
know there is nothing more to expect.

   The C program ‘hellobrowser.c’, which is to be found in the examples
section, does just that.  If you are very eager, you can compile and
start it right away but it is advisable to type the lines in by yourself
as they will be discussed and explained in detail.

   After the necessary includes and the definition of the port which our
server should listen on
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <string.h>
#include <microhttpd.h>
#include <stdio.h>

#define PORT 8888


the desired behaviour of our server when HTTP request arrive has to be
implemented.  We already have agreed that it should not care about the
particular details of the request, such as who is requesting what.  The
server will respond merely with the same small HTML page to every
request.

   The function we are going to write now will be called by _GNU
libmicrohttpd_ every time an appropriate request comes in.  While the
name of this callback function is arbitrary, its parameter list has to
follow a certain layout.  So please, ignore the lot of parameters for
now, they will be explained at the point they are needed.  We have to
use only one of them, ‘struct MHD_Connection *connection’, for the
minimalistic functionality we want to achieve at the moment.

   This parameter is set by the _libmicrohttpd_ daemon and holds the
necessary information to relate the call with a certain connection.
Keep in mind that a server might have to satisfy hundreds of concurrent
connections and we have to make sure that the correct data is sent to
the destined client.  Therefore, this variable is a means to refer to a
particular connection if we ask the daemon to sent the reply.

   Talking about the reply, it is defined as a string right after the
function header
static enum MHD_Result
answer_to_connection (void *cls, struct MHD_Connection *connection,
                      const char *url,
                      const char *method, const char *version,
                      const char *upload_data,
                      size_t *upload_data_size, void **req_cls)
{
  const char *page  = "<html><body>Hello, browser!</body></html>";


HTTP is a rather strict protocol and the client would certainly consider
it "inappropriate" if we just sent the answer string "as is".  Instead,
it has to be wrapped with additional information stored in so-called
headers and footers.  Most of the work in this area is done by the
library for us--we just have to ask.  Our reply string packed in the
necessary layers will be called a "response".  To obtain such a response
we hand our data (the reply-string) and its size over to the
‘MHD_create_response_from_buffer_static’ function.  By using the
‘_static’ variant we tell _MHD_ that the buffer will stay valid and
unchanged for at least as long as the response lives, so that _MHD_
neither has to free the message data for us when it has been sent nor
has to make an internal copy of it--which is exactly the case for our
_constant_ string.

  struct MHD_Response *response;
  enum MHD_Result ret;

  response = MHD_create_response_from_buffer_static (strlen (page), page);


Now that the response has been laced up, it is ready for delivery and
can be queued for sending.  This is done by passing it to another _GNU
libmicrohttpd_ function.  As all our work was done in the scope of one
function, the recipient is without doubt the one associated with the
local variable ‘connection’ and consequently this variable is given to
the queue function.  Every HTTP response is accompanied by a status
code, here "OK", so that the client knows this response is the intended
result of his request and not due to some error or malfunction.

   Finally, the packet is destroyed and the return value from the queue
returned, already being set at this point to either MHD_YES or MHD_NO in
case of success or failure.

  ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
  MHD_destroy_response (response);

  return ret;
}


With the primary task of our server implemented, we can start the actual
server daemon which will listen on ‘PORT’ for connections.  This is done
in the main function.
int main (void)
{
  struct MHD_Daemon *daemon;

  daemon = MHD_start_daemon (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD,
                             PORT, NULL, NULL,
                             &answer_to_connection, NULL, MHD_OPTION_END);
  if (NULL == daemon) return 1;


The first parameter is a bit-wise OR of flags selecting, among other
things, the mode of operation.  With ‘MHD_USE_INTERNAL_POLLING_THREAD’
we want the daemon to run in a separate thread and to manage all
incoming connections in the same thread.  This means that while
producing the response for one connection, the other connections will be
put on hold.  In this example, where the reply is already known and
therefore the request is served quickly, this poses no problem.  The
additional ‘MHD_USE_AUTO’ flag simply lets _MHD_ pick the best polling
function (‘epoll’, ‘poll’ or ‘select’) available on the platform.

   We will allow all clients to connect regardless of their name or
location, therefore we do not check them on connection and set the third
and fourth parameter to NULL.

   Parameter five is the address of the function we want to be called
whenever a new request has been received.  Our ‘answer_to_connection’
knows best what the client wants and needs no additional information
(which could be passed via the next parameter) so the next (sixth)
parameter is NULL. Likewise, we do not need to pass extra options to the
daemon so we just write the MHD_OPTION_END as the last parameter.

   As the server daemon runs in the background in its own thread, the
execution flow in our main function will continue right after the call.
Because of this, we must delay the execution flow in the main thread or
else the program will terminate prematurely.  We let it pause in a
processing-time friendly manner by waiting for the enter key to be
pressed.  In the end, we stop the daemon so it can do its cleanup tasks.
  getchar ();

  MHD_stop_daemon (daemon);
  return 0;
}


The first example is now complete.

   Compile it with
cc hellobrowser.c -o hellobrowser -I$PATH_TO_LIBMHD_INCLUDES
  -L$PATH_TO_LIBMHD_LIBS -lmicrohttpd
   with the two paths set accordingly and run it.

   Now open your favorite Internet browser and go to the address
‘http://localhost:8888/’, provided that 8888 is the port you chose.  If
everything works as expected, the browser will present the message of
the static HTML page it got from our minimal server.

Remarks
=======

To keep this first example as small as possible, some drastic shortcuts
were taken and are to be discussed now.

   Firstly, there is no distinction made between the kinds of requests a
client could send.  We implied that the client sends a GET request, that
means, that he actually asked for some data.  Even when it is not
intended to accept POST requests, a good server should at least
recognize that this request does not constitute a legal request and
answer with an error code.  This can be easily implemented by checking
if the parameter ‘method’ equals the string "GET" and returning a
‘MHD_NO’ if not so.

   Secondly, the above practice of queuing a response upon the first
call of the callback function brings with it some limitations.  This is
because the content of the message body will not be received if a
response is queued in the first iteration.  Furthermore, the connection
will be closed right after the response has been transferred then.  This
is typically not what you want as it disables HTTP pipelining.  The
correct approach is to simply not queue a message on the first callback
unless there is an error.  The ‘void**’ argument to the callback
provides a location for storing information about the history of the
connection; for the first call, the pointer will point to NULL. A
simplistic way to differentiate the first call from others is to check
if the pointer is NULL and set it to a non-NULL value during the first
call.

   Both of these issues you will find addressed in the official
‘minimal_example.c’ residing in the ‘src/examples’ directory of the
_MHD_ package.  The source code of this program should look very
familiar to you by now and easy to understand.

   For our example, we create the response from a static (persistent)
buffer in memory and thus use ‘MHD_create_response_from_buffer_static’.
In the usual case, responses are not transmitted immediately after being
queued.  For example, there might be other data on the system that needs
to be sent with a higher priority.  Nevertheless, the queue function
will return successfully--raising the problem that the data we have
pointed to may be invalid by the time it is about being sent.  This is
not an issue here because we can expect the ‘page’ string, which is a
constant _string literal_ here, to be static.  That means it will be
present and unchanged for as long as the program runs.  For dynamic
data, one could choose to either have _MHD_ free the memory ‘page’
points to itself when it is no longer needed (by using
‘MHD_create_response_from_buffer_with_free_callback’ with ‘&free’) or,
alternatively, have the library make and manage its own copy of it (by
using ‘MHD_create_response_from_buffer_copy’).  Naturally, this last
option is the most expensive.

Exercises
=========

   • While the server is running, use a program like ‘telnet’ or
     ‘netcat’ to connect to it.  Try to form a valid HTTP 1.1 request
     yourself like
     GET /dontcare HTTP/1.1
     Host: itsme
     <enter>
     and see what the server returns to you.

   • Also, try other requests, like POST, and see how our server does
     not mind and why.  How far in malforming a request can you go
     before the builtin functionality of _MHD_ intervenes and an altered
     response is sent?  Make sure you read about the status codes in the
     _RFC_.

   • Add the option ‘MHD_OPTION_CLIENT_DISCIPLINE_LVL’ with a value of
     ‘1’ to the start function of the daemon in ‘main’ (this option
     supersedes the deprecated ‘MHD_USE_PEDANTIC_CHECKS’ flag).  Mind
     the special format of the parameter list here which is described in
     the manual: the option is followed by its ‘int’ value, and
     ‘MHD_OPTION_END’ still terminates the list.  How indulgent is the
     server now to your input?

   • Let the main function take a string as the first command line
     argument and pass ‘argv[1]’ to the ‘MHD_start_daemon’ function as
     the sixth parameter.  The address of this string will be passed to
     the callback function via the ‘cls’ variable.  Decorate the text
     given at the command line when the server is started with proper
     HTML tags and send it as the response instead of the former static
     string.

   • _Demanding:_ Write a separate function returning a string
     containing some useful information, for example, the time.  Pass
     the function's address as the sixth parameter and evaluate this
     function on every request anew in ‘answer_to_connection’.  Remember
     to free the memory of the string every time after satisfying the
     request.


File: libmicrohttpd-tutorial.info,  Node: Exploring requests,  Next: Response headers,  Prev: Hello browser example,  Up: Top

3 Exploring requests
********************

This chapter will deal with the information which the client sends to
the server at every request.  We are going to examine the most useful
fields of such a request and print them out in a readable manner.  This
could be useful for logging facilities.

   The starting point is the _hellobrowser_ program with the former
response removed.

   This time, we just want to collect information in the callback
function, thus we will just return MHD_NO after we have probed the
request.  This way, the connection is closed without much ado by the
server.

static enum MHD_Result
answer_to_connection (void *cls, struct MHD_Connection *connection,
                      const char *url,
		      const char *method, const char *version, 
		      const char *upload_data, 
                      size_t *upload_data_size, void **req_cls)
{
  ...  
  return MHD_NO;
}
The ellipsis marks the position where the following instructions shall
be inserted.

   We begin with the most obvious information available to the server,
the request line.  You should already have noted that a request consists
of a command (or "HTTP method") and a URI (e.g.  a filename).  It also
contains a string for the version of the protocol which can be found in
‘version’.  To call it a "new request" is justified because we return
only ‘MHD_NO’, thus ensuring the function will not be called again for
this connection.
printf ("New %s request for %s using version %s\n", method, url, version);

   The rest of the information is a bit more hidden.  Nevertheless,
there is a lot of it sent from common Internet browsers.  It is stored
in "key-value" pairs and we want to list what we find in the header.  As
there is no mandatory set of keys a client has to send, each key-value
pair is printed out one by one until there are no more left.  We do this
by writing a separate function which will be called for each pair just
like the above function is called for each HTTP request.  It can then
print out the content of this pair.
static enum MHD_Result
print_out_key (void *cls, enum MHD_ValueKind kind,
               const char *key, const char *value)
{
  printf ("%s: %s\n", key, value);
  return MHD_YES;
}

   To start the iteration process that calls our new function for every
key, the line
MHD_get_connection_values (connection, MHD_HEADER_KIND, &print_out_key, NULL);
needs to be inserted in the connection callback function too.  The
second parameter tells the function that we are only interested in keys
from the general HTTP header of the request.  Our iterating function
‘print_out_key’ does not rely on any additional information to fulfill
its duties so the last parameter can be NULL.

   All in all, this constitutes the complete ‘logging.c’ program for
this chapter which can be found in the ‘examples’ section.

   Connecting with any modern Internet browser should yield a handful of
keys.  You should try to interpret them with the aid of _RFC 9110_.
Especially worth mentioning is the "Host" key which is often used to
serve several different websites hosted under one single IP address but
reachable by different domain names (this is called virtual hosting).

Conclusion
==========

The introduced capabilities to itemize the content of a simple GET
request--especially the URI--should already allow the server to satisfy
clients' requests for small specific resources (e.g.  files) or even
induce alteration of server state.  However, the latter is not
recommended as the GET method (including its header data) is by
convention considered a "safe" operation, which should not change the
server's state in a significant way.  By convention, GET operations can
thus be performed by crawlers and other automatic software.  Naturally
actions like searching for a passed string are fine.

   Of course, no transmission can occur while the return value is still
set to ‘MHD_NO’ in the callback function.

Exercises
=========

   • By parsing the ‘url’ string and delivering responses accordingly,
     implement a small server for "virtual" files.  When asked for
     ‘/index.htm{l}’, let the response consist of a HTML page containing
     a link to ‘/another.html’ page which is also to be created "on the
     fly" in case of being requested.  If neither of these two pages are
     requested, ‘MHD_HTTP_NOT_FOUND’ shall be returned accompanied by an
     informative message.

   • A very interesting information has still been ignored by our
     logger--the client's IP address.  Implement a callback function
     static enum MHD_Result
     on_client_connect (void *cls,
                        const struct sockaddr *addr,
                        socklen_t addrlen)
     that prints out the IP address in an appropriate format.  You might
     want to use the POSIX function ‘inet_ntoa’ but bear in mind that
     ‘addr’ is actually just a structure containing other substructures
     and is _not_ the variable this function expects.  Make sure to
     return ‘MHD_YES’ so that the library knows the client is allowed to
     connect (and to then process the request).  If one wanted to limit
     access basing on IP addresses, this would be the place to do it.
     The address of your ‘on_client_connect’ function must be passed as
     the third parameter to the ‘MHD_start_daemon’ call.


File: libmicrohttpd-tutorial.info,  Node: Response headers,  Next: Supporting basic authentication,  Prev: Exploring requests,  Up: Top

4 Response headers
******************

Now that we are able to inspect the incoming request in great detail,
this chapter discusses the means to enrich the outgoing responses
likewise.

   As you have learned in the _Hello, Browser_ chapter, some obligatory
header fields are added and set automatically for simple responses by
the library itself but if more advanced features are desired, additional
fields have to be created.  One of the possible fields is the content
type field and an example will be developed around it.  This will lead
to an application capable of correctly serving different types of files.

   When we responded with HTML page packed in the static string
previously, the client had no choice but guessing about how to handle
the response, because the server had not told him.  What if we had sent
a picture or a sound file?  Would the message have been understood or
merely been displayed as an endless stream of random characters in the
browser?  This is what the mime content types are for.  The header of
the response is extended by certain information about how the data is to
be interpreted.

   To introduce the concept, a picture of the format _PNG_ will be sent
to the client and labeled accordingly with ‘image/png’.  Once again, we
can base the new example on the ‘hellobrowser’ program.

#define FILENAME "picture.png"
#define MIMETYPE "image/png"

static enum MHD_Result
answer_to_connection (void *cls, struct MHD_Connection *connection,
		      const char *url,
                      const char *method, const char *version,
		      const char *upload_data,
              	      size_t *upload_data_size, void **req_cls)
{
  struct MHD_Response *response;

   We want the program to open the file for reading and determine its
size:
  int fd;
  enum MHD_Result ret;
  struct stat sbuf;

  if (0 != strcmp (method, "GET"))
    return MHD_NO;
  if ( (-1 == (fd = open (FILENAME, O_RDONLY))) ||
       (0 != fstat (fd, &sbuf)) )
    {
     /* error accessing file */
      /* ... (see below) */
    }
 /* ... (see below) */

   When dealing with files, there is a lot that could go wrong on the
server side and if so, the client should be informed with
‘MHD_HTTP_INTERNAL_SERVER_ERROR’.

      /* error accessing file */
      if (fd != -1) close (fd);
      const char *errorstr =
        "<html><body>An internal server error has occurred!\
                              </body></html>";
      response =
	MHD_create_response_from_buffer_static (strlen (errorstr),
				                errorstr);
      if (NULL != response)
        {
          ret =
            MHD_queue_response (connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
                                response);
          MHD_destroy_response (response);

          return ret;
        }
      else
        return MHD_NO;

   Note that we nevertheless have to create a response object even for
sending a simple error code.  Otherwise, the connection would just be
closed without comment, leaving the client curious about what has
happened.

   But in the case of success a response will be constructed directly
from the file descriptor:

     /* error accessing file */
     /* ... (see above) */
    }

  response =
    MHD_create_response_from_fd_at_offset64 ((uint64_t) sbuf.st_size, fd, 0);
  MHD_add_response_header (response, "Content-Type", MIMETYPE);

   Note that the response object will take care of closing the file
descriptor for us.

   Up to this point, there was little new.  The actual novelty is that
we enhance the header with the meta data about the content.  Aware of
the field's name we want to add, it is as easy as that:
MHD_add_response_header(response, "Content-Type", MIMETYPE);
We do not have to append a colon expected by the protocol behind the
first field--_GNU libmicrohttpd_ will take care of this.

   The function finishes with the well-known lines
  ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
  MHD_destroy_response (response);
  return ret;
}

   The complete program ‘responseheaders.c’ is in the ‘examples’ section
as usual.  Find a _PNG_ file you like and save it to the directory the
example is run from under the name ‘picture.png’.  You should find the
image displayed on your browser if everything worked well.

Remarks
=======

The include file of the _MHD_ library comes with the header types
mentioned in _RFC 9110_ already defined as macros.  Thus, we could have
written ‘MHD_HTTP_HEADER_CONTENT_TYPE’ instead of ‘"Content-Type"’ as
well.  However, one is not limited to these standard headers and could
add custom response headers without violating the protocol.  Whether,
and how, the client would react to these custom header is up to the
receiver.  Likewise, the client is allowed to send custom request
headers to the server as well, opening up yet more possibilities how
client and server could communicate with each other.

   The method of creating the response from a file on disk only works
for static content.  Serving dynamically created responses will be a
topic of a future chapter.

Exercises
=========

   • Remember that the original program was written under a few
     assumptions--a static response using a local file being one of
     them.  In order to simulate a very large or hard to reach file that
     cannot be provided instantly, postpone the queuing in the callback
     with the ‘sleep’ function for 30 seconds _if_ the file ‘/big.png’
     is requested (but deliver the same as above).  A request for
     ‘/picture.png’ should provide just the same but without any
     artificial delays.

     Now start two instances of your browser (or even use two machines)
     and see how the second client is put on hold while the first waits
     for his request on the slow file to be fulfilled.

     Finally, change the sourcecode to add
     ‘MHD_USE_THREAD_PER_CONNECTION’ to the daemon's flags (this flag
     must be combined with ‘MHD_USE_INTERNAL_POLLING_THREAD’) and try
     again.

   • Did you succeed in implementing the clock exercise yet?  This time,
     let the server save the program's start time ‘t’ and implement a
     response simulating a countdown that reaches 0 at ‘t+60’.
     Returning a message saying on which point the countdown is, the
     response should ultimately be to reply "Done" if the program has
     been running long enough,

     An unofficial, but widely understood, response header line is
     ‘Refresh: DELAY; url=URL’ with the uppercase words substituted to
     tell the client it should request the given resource after the
     given delay again.  Improve your program in that the browser (any
     modern browser should work) automatically reconnects and asks for
     the status again every 5 seconds or so.  The URL would have to be
     composed so that it begins with "http://", followed by the _URI_
     the server is reachable from the client's point of view.

     Maybe you want also to visualize the countdown as a status bar by
     creating a ‘<table>’ consisting of one row and ‘n’ columns whose
     fields contain small images of either a red or a green light.


File: libmicrohttpd-tutorial.info,  Node: Supporting basic authentication,  Next: Processing POST data,  Prev: Response headers,  Up: Top

5 Supporting basic authentication
*********************************

With the small exception of IP address based access control, requests
from all connecting clients where served equally until now.  This
chapter discusses a first method of client's authentication and its
limits.

   A very simple approach feasible with the means already discussed
would be to expect the password in the _URI_ string before granting
access to the secured areas.  The password could be separated from the
actual resource identifier by a certain character, thus the request line
might look like
GET /picture.png?mypassword

   In the rare situation where the client is customized enough and the
connection occurs through secured lines (e.g., a embedded device
directly attached to another via wire) and where the ability to embed a
password in the URI or to pass on a URI with a password are desired,
this can be a reasonable choice.

   But when it is assumed that the user connecting does so with an
ordinary Internet browser, this implementation brings some problems
about.  For example, the URI including the password stays in the address
field or at least in the history of the browser for anybody near enough
to see.  It will also be inconvenient to add the password manually to
any new URI when the browser does not know how to compose this
automatically.

   At least the convenience issue can be addressed by employing the
simplest built-in password facilities of HTTP compliant browsers, hence
we want to start there.  It will, however, turn out to have still severe
weaknesses in terms of security which need consideration.

   Before we will start implementing _Basic Authentication_ as described
in _RFC 7617_, we will also abandon the simplistic and generally
problematic practice of responding every request the first time our
callback is called for a given connection.  Queuing a response upon the
first request is akin to generating an error response (even if it is a
"200 OK" reply!).  The reason is that MHD usually calls the callback in
three phases:

  1. First, to initially tell the application about the connection and
     inquire whether it is OK to proceed.  This call typically happens
     before the client could upload the request body, and can be used to
     tell the client to not proceed with the upload (if the client
     requested "Expect: 100 Continue").  Applications may queue a reply
     at this point, but it will force the connection to be closed and
     thus prevent keep-alive / pipelining, which is generally a bad
     idea.  Applications wanting to proceed with the request throughout
     the other phases should just return "MHD_YES" and not queue any
     response.  Note that when an application suspends a connection in
     this callback, the phase does not advance and the application will
     be called again in this first phase.
  2. Next, to tell the application about upload data provided by the
     client.  In this phase, the application may not queue replies, and
     trying to do so will result in MHD returning an error code from
     ‘MHD_queue_response’.  If there is no upload data, this phase is
     skipped.
  3. Finally, to obtain a regular response from the application.  This
     can be almost any type of response, including ones indicating
     failures.  The one exception is a "100 Continue" response, which
     applications must never generate: MHD generates that response
     automatically when necessary in the first phase.  If the
     application does not queue a response, MHD may call the callback
     repeatedly (depending a bit on the threading model, the application
     should suspend the connection).

   But how can we tell whether the callback has been called before for
the particular request?  This is what the ‘req_cls’ parameter of the
callback is for: initially, the pointer it references is set to NULL by
_MHD_. But whatever we store there will be "remembered" on the next call
(for the same request).  Thus, we can use the ‘req_cls’ location to keep
track of the request state.  For now, we will simply generate no
response until the parameter is non-null--implying the callback was
called before at least once.  We do not need to share information
between different calls of the callback, so we can set the parameter to
any address that is assured to be not null.  The pointer to the
‘connection’ structure will be pointing to a legal address, so we take
this.

   The first time ‘answer_to_connection’ is called, we will not even
look at the headers.

static enum MHD_Result
answer_to_connection (void *cls, struct MHD_Connection *connection,
                      const char *url, const char *method, const char *version,
                      const char *upload_data, size_t *upload_data_size,
                      void **req_cls)
{
  if (0 != strcmp(method, "GET")) return MHD_NO;
  if (NULL == *req_cls) {*req_cls = connection; return MHD_YES;}

  ...
  /* else respond accordingly */
  ...
}

   Note how we lop off the connection on the first condition (no "GET"
request), but return asking for more on the other one with ‘MHD_YES’.
With this minor change, we can proceed to implement the actual
authentication process.

Request for authentication
==========================

Let us assume we had only files not intended to be handed out without
the correct username/password, so every "GET" request will be
challenged.  _RFC 7617_ describes how the server shall ask for
authentication by adding a _WWW-Authenticate_ response header with the
name of the _realm_ protected.  MHD can generate and queue such a
failure response for you using the
‘MHD_queue_basic_auth_required_response3’ API. The only thing you need
to do is construct a response with the error page to be shown to the
user if he aborts basic authentication.  But first, you should check if
the proper credentials were already supplied using the
‘MHD_basic_auth_get_username_password3’ call.  (The older
‘MHD_queue_basic_auth_fail_response’ and
‘MHD_basic_auth_get_username_password’ calls are deprecated.)

   Your code would then look like this:
static enum MHD_Result
answer_to_connection (void *cls, struct MHD_Connection *connection,
                      const char *url, const char *method,
                      const char *version, const char *upload_data,
                      size_t *upload_data_size, void **req_cls)
{
  struct MHD_BasicAuthInfo *auth_info;
  enum MHD_Result ret;
  struct MHD_Response *response;

  if (0 != strcmp (method, "GET"))
    return MHD_NO;
  if (NULL == *req_cls)
  {
    *req_cls = connection;
    return MHD_YES;
  }
  auth_info = MHD_basic_auth_get_username_password3 (connection);
  if (NULL == auth_info)
  {
    static const char *page =
      "<html><body>Authorization required</body></html>";
    response = MHD_create_response_from_buffer_static (strlen (page), page);
    ret = MHD_queue_basic_auth_required_response3 (connection,
                                                   "admins",
                                                   MHD_YES,
                                                   response);
  }
  else if ((strlen ("root") != auth_info->username_len) ||
           (0 != memcmp (auth_info->username, "root",
                         auth_info->username_len)) ||
           /* The next check against NULL is optional,
            * if 'password' is NULL then 'password_len' is always zero. */
           (NULL == auth_info->password) ||
           (strlen ("pa$$w0rd") != auth_info->password_len) ||
           (0 != memcmp (auth_info->password, "pa$$w0rd",
                         auth_info->password_len)))
  {
    static const char *page =
      "<html><body>Wrong username or password</body></html>";
    response = MHD_create_response_from_buffer_static (strlen (page), page);
    ret = MHD_queue_basic_auth_required_response3 (connection,
                                                   "admins",
                                                   MHD_YES,
                                                   response);
  }
  else
  {
    static const char *page = "<html><body>A secret.</body></html>";
    response = MHD_create_response_from_buffer_static (strlen (page), page);
    ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
  }
  if (NULL != auth_info)
    MHD_free (auth_info);
  MHD_destroy_response (response);
  return ret;
}

   See the ‘examples’ directory for the complete example file.

Remarks
=======

For a proper server, the conditional statements leading to a return of
‘MHD_NO’ should yield a response with a more precise status code instead
of silently closing the connection.  For example, failures of memory
allocation are best reported as _internal server error_ and unexpected
authentication methods as _400 bad request_.

Exercises
=========

   • Make the server respond to wrong credentials (but otherwise
     well-formed requests) with the recommended _401 unauthorized_
     status code.  If the client still does not authenticate correctly
     within the same connection, close it and store the client's IP
     address for a certain time.  (It is OK to check for expiration not
     until the main thread wakes up again on the next connection.)  If
     the client fails authenticating three times during this period, add
     it to another list for which the ‘AcceptPolicyCallback’ function
     denies connection (temporally).

   • With the network utility ‘netcat’ connect and log the response of a
     "GET" request as you did in the exercise of the first example, this
     time to a file.  Now stop the server and let _netcat_ listen on the
     same port the server used to listen on and have it fake being the
     proper server by giving the file's content as the response (e.g.
     ‘cat log | nc -l -p 8888’).  Pretending to think your were
     connecting to the actual server, browse to the eavesdropper and
     give the correct credentials.

     Copy and paste the encoded string you see in ‘netcat’'s output to
     some of the Base64 decode tools available online and see how both
     the user's name and password could be completely restored.


File: libmicrohttpd-tutorial.info,  Node: Processing POST data,  Next: Improved processing of POST data,  Prev: Supporting basic authentication,  Up: Top

6 Processing POST data
**********************

The previous chapters already have demonstrated a variety of
possibilities to send information to the HTTP server, but it is not
recommended that the _GET_ method is used to alter the way the server
operates.  To induce changes on the server, the _POST_ method is
preferred over and is much more powerful than _GET_ and will be
introduced in this chapter.

   We are going to write an application that asks for the visitor's name
and, after the user has posted it, composes an individual response text.
Even though it was not mandatory to use the _POST_ method here, as there
is no permanent change caused by the POST, it is an illustrative example
on how to share data between different functions for the same
connection.  Furthermore, the reader should be able to extend it easily.

GET request
===========

When the first _GET_ request arrives, the server shall respond with a
HTML page containing an edit field for the name.

const char* askpage = "<html><body>\
                       What's your name, Sir?<br>\
                       <form action=\"/namepost\" method=\"post\">\
                       <input name=\"name\" type=\"text\">\
                       <input type=\"submit\" value=\" Send \"></form>\
                       </body></html>";

   The ‘action’ entry is the _URI_ to be called by the browser when
posting, and the ‘name’ will be used later to be sure it is the
editbox's content that has been posted.

   We also prepare the answer page, where the name is to be filled in
later, and an error page as the response for anything but proper _GET_
and _POST_ requests:

const char* greetingpage="<html><body><h1>Welcome, %s!</h1></body></html>";

const char* errorpage="<html><body>This doesn't seem to be right.</body></html>";

   Whenever we need to send a page, we use an extra function ‘int
send_page(struct MHD_Connection *connection, const char* page)’ for
this, which does not contain anything new and whose implementation is
therefore not discussed further in the tutorial.

POST request
============

Posted data can be of arbitrary and considerable size; for example, if a
user uploads a big image to the server.  Similar to the case of the
header fields, there may also be different streams of posted data, such
as one containing the text of an editbox and another the state of a
button.  Likewise, we will have to register an iterator function that is
going to be called maybe several times not only if there are different
POSTs but also if one POST has only been received partly yet and needs
processing before another chunk can be received.

   Such an iterator function is called by a _postprocessor_, which must
be created upon arriving of the post request.  We want the iterator
function to read the first post data which is tagged ‘name’ and to
create an individual greeting string based on the template and the name.
But in order to pass this string to other functions and still be able to
differentiate different connections, we must first define a structure to
share the information, holding the most import entries.

struct connection_info_struct
{
  int connectiontype;
  char *answerstring;
  struct MHD_PostProcessor *postprocessor;
};

   With these information available to the iterator function, it is able
to fulfill its task.  Once it has composed the greeting string, it
returns ‘MHD_YES’ so that the post processor keeps parsing the remainder
of the upload.  Returning ‘MHD_NO’ would instead abort the parsing and
make the next call to ‘MHD_post_process’ fail.  Note that this function
does not handle processing of data for the same ‘key’.  If we were to
expect that the name will be posted in several chunks, we had to expand
the namestring dynamically as additional parts of it with the same ‘key’
came in.  But in this example, the name is assumed to fit entirely
inside one single packet.

static enum MHD_Result
iterate_post (void *coninfo_cls, enum MHD_ValueKind kind, const char *key,
              const char *filename, const char *content_type,
              const char *transfer_encoding, const char *data,
	      uint64_t off, size_t size)
{
  struct connection_info_struct *con_info = coninfo_cls;

  if (0 == strcmp (key, "name"))
    {
      if ((size > 0) && (size <= MAXNAMESIZE))
        {
          char *answerstring;
          answerstring = malloc (MAXANSWERSIZE);
          if (!answerstring) return MHD_NO;

          snprintf (answerstring, MAXANSWERSIZE, greetingpage, data);
          con_info->answerstring = answerstring;
        }
      else con_info->answerstring = NULL;
    }

  return MHD_YES;
}

   Once a connection has been established, it can be terminated for many
reasons.  As these reasons include unexpected events, we have to
register another function that cleans up any resources that might have
been allocated for that connection by us, namely the post processor and
the greetings string.  This cleanup function must take into account that
it will also be called for finished requests other than _POST_ requests.

static void
request_completed (void *cls, struct MHD_Connection *connection,
     		        void **req_cls,
                        enum MHD_RequestTerminationCode toe)
{
  struct connection_info_struct *con_info = *req_cls;

  if (NULL == con_info)
    return;
  if (con_info->connectiontype == POST)
    {
      MHD_destroy_post_processor (con_info->postprocessor);
      if (con_info->answerstring) free (con_info->answerstring);
    }

  free (con_info);
  *req_cls = NULL;
}

   _GNU libmicrohttpd_ is informed that it shall call the above function
when the daemon is started in the main function.

...
daemon = MHD_start_daemon (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD,
                           PORT, NULL, NULL,
                           &answer_to_connection, NULL,
			   MHD_OPTION_NOTIFY_COMPLETED, &request_completed, NULL,
			   MHD_OPTION_END);
...

Request handling
================

With all other functions prepared, we can now discuss the actual request
handling.

   On the first iteration for a new request, we start by allocating a
new instance of a ‘struct connection_info_struct’ structure, which will
store all necessary information for later iterations and other
functions.

static enum MHD_Result
answer_to_connection (void *cls, struct MHD_Connection *connection,
		      const char *url,
                      const char *method, const char *version,
		      const char *upload_data,
                      size_t *upload_data_size, void **req_cls)
{
  if(NULL == *req_cls)
    {
      struct connection_info_struct *con_info;

      con_info = malloc (sizeof (struct connection_info_struct));
      if (NULL == con_info) return MHD_NO;
      con_info->answerstring = NULL;

   If the new request is a _POST_, the postprocessor must be created
now.  In addition, the type of the request is stored for convenience.
      if (0 == strcmp (method, "POST"))
        {
          con_info->postprocessor
	    = MHD_create_post_processor (connection, POSTBUFFERSIZE,
                                         iterate_post, (void*) con_info);

          if (NULL == con_info->postprocessor)
            {
              free (con_info);
              return MHD_NO;
            }
          con_info->connectiontype = POST;
        }
      else con_info->connectiontype = GET;

   The address of our structure will both serve as the indicator for
successive iterations and to remember the particular details about the
connection.
      *req_cls = (void*) con_info;
      return MHD_YES;
    }

   The rest of the function will not be executed on the first iteration.
A _GET_ request is easily satisfied by sending the question form.
  if (0 == strcmp (method, "GET"))
    {
      return send_page (connection, askpage);
    }

   In case of _POST_, we invoke the post processor for as long as data
keeps incoming, setting ‘*upload_data_size’ to zero in order to indicate
that we have processed--or at least have considered--all of it.
  if (0 == strcmp (method, "POST"))
    {
      struct connection_info_struct *con_info = *req_cls;

      if (*upload_data_size != 0)
        {
          if (MHD_YES !=
              MHD_post_process (con_info->postprocessor, upload_data,
	                        *upload_data_size))
            return MHD_NO;
          *upload_data_size = 0;

          return MHD_YES;
        }
      else if (NULL != con_info->answerstring)
        return send_page (connection, con_info->answerstring);
    }

   Finally, if they are neither _GET_ nor _POST_ requests, the error
page is returned.
  return send_page(connection, errorpage);
}

   These were the important parts of the program ‘simplepost.c’.


File: libmicrohttpd-tutorial.info,  Node: Improved processing of POST data,  Next: Session management,  Prev: Processing POST data,  Up: Top

7 Improved processing of POST data
**********************************

The previous chapter introduced a way to upload data to the server, but
the developed example program has some shortcomings, such as not being
able to handle larger chunks of data.  In this chapter, we are going to
discuss a more advanced server program that allows clients to upload a
file in order to have it stored on the server's filesystem.  The server
shall also watch and limit the number of clients concurrently uploading,
responding with a proper busy message if necessary.

Prepared answers
================

We choose to operate the server with the
‘MHD_USE_INTERNAL_POLLING_THREAD’ method.  This makes it easier to
synchronize the global states at the cost of possible delays for other
connections if the processing of a request is too slow.  One of these
variables that needs to be shared for all connections is the total
number of clients that are uploading.

#define MAXCLIENTS      2
static unsigned int    nr_of_uploading_clients = 0;

   If there are too many clients uploading, we want the server to
respond to all requests with a busy message.
const char* busypage =
  "<html><body>This server is busy, please try again later.</body></html>";

   Otherwise, the server will send a _form_ that informs the user of the
current number of uploading clients, and ask her to pick a file on her
local filesystem which is to be uploaded.
const char* askpage = "<html><body>\n\
                       Upload a file, please!<br>\n\
                       There are %u clients uploading at the moment.<br>\n\
                       <form action=\"/filepost\" method=\"post\" \
                         enctype=\"multipart/form-data\">\n\
                       <input name=\"file\" type=\"file\">\n\
                       <input type=\"submit\" value=\" Send \"></form>\n\
                       </body></html>";

   If the upload has succeeded, the server will respond with a message
saying so.
const char* completepage = "<html><body>The upload has been completed.</body></html>";

   We want the server to report malformed requests and internal errors,
such as file access problems, adequately.
const char* servererrorpage
  = "<html><body>Invalid request.</body></html>";
const char* fileexistspage
  = "<html><body>This file already exists.</body></html>";
const char* fileioerror
  = "<html><body>IO error writing to disk.</body></html>";
const char* postprocerror
  = "<html><body>Error processing POST data.</body></html>";

   It would be tolerable to send all these responses undifferentiated
with a ‘200 HTTP_OK’ status code but in order to improve the ‘HTTP’
conformance of our server a bit, we extend the ‘send_page’ function so
that it accepts individual status codes.

static enum MHD_Result
send_page (struct MHD_Connection *connection,
	   const char* page, unsigned int status_code)
{
  enum MHD_Result ret;
  struct MHD_Response *response;

  response = MHD_create_response_from_buffer_copy (strlen (page), page);
  if (!response) return MHD_NO;

  ret = MHD_queue_response (connection, status_code, response);
  MHD_destroy_response (response);

  return ret;
}

   Note how we ask _MHD_ to make its own copy of the message data--that
is what the ‘_copy’ suffix stands for.  The reason behind this will
become clear later.

Connection cycle
================

The decision whether the server is busy or not is made right at the
beginning of the connection.  To do that at this stage is especially
important for _POST_ requests because if no response is queued at this
point, and ‘MHD_YES’ returned, _MHD_ will not send any queued messages
until a postprocessor has been created and the post iterator is called
at least once.

static enum MHD_Result
answer_to_connection (void *cls, struct MHD_Connection *connection,
		      const char *url,
                      const char *method, const char *version,
		      const char *upload_data,
                      size_t *upload_data_size, void **req_cls)
{
  if (NULL == *req_cls)
    {
      struct connection_info_struct *con_info;

      if (nr_of_uploading_clients >= MAXCLIENTS)
        return send_page(connection, busypage, MHD_HTTP_SERVICE_UNAVAILABLE);

   If the server is not busy, the ‘connection_info’ structure is
initialized as usual, with the addition of a filepointer for each
connection.  The status code is set to zero, which we use as the marker
for "no answer decided yet".

      con_info = malloc (sizeof (struct connection_info_struct));
      if (NULL == con_info) return MHD_NO;
      con_info->answercode = 0;
      con_info->fp = NULL;

      if (0 == strcmp (method, "POST"))
        {
          ...
        }
      else con_info->connectiontype = GET;

      *req_cls = (void*) con_info;

      return MHD_YES;
    }

   For _POST_ requests, the postprocessor is created and we register a
new uploading client.  From this point on, there are many possible
places for errors to occur that make it necessary to interrupt the
uploading process.  We need a means of having the proper response
message ready at all times.  Therefore, the ‘connection_info’ structure
is extended to hold the most current response message so that whenever a
response is sent, the client will get the most informative message.
      if (0 == strcmp (method, "POST"))
        {
          con_info->postprocessor
	    = MHD_create_post_processor (connection, POSTBUFFERSIZE,
                                         iterate_post, (void*) con_info);

          if (NULL == con_info->postprocessor)
            {
              free (con_info);
              return MHD_NO;
            }

          nr_of_uploading_clients++;

          con_info->connectiontype = POST;
        }
      else con_info->connectiontype = GET;

   If the connection handler is called for the second time, _GET_
requests will be answered with the _form_.  We can keep the buffer under
function scope, because we asked _MHD_ to make its own copy of it for as
long as it is needed.
  if (0 == strcmp (method, "GET"))
    {
      char buffer[1024];

      snprintf (buffer, sizeof (buffer), askpage, nr_of_uploading_clients);
      return send_page (connection, buffer, MHD_HTTP_OK);
    }

   The rest of the ‘answer_to_connection’ function is very similar to
the ‘simplepost.c’ example, except the more flexible content of the
responses.  The _POST_ data is processed until there is none left and
the execution falls through to return an error page if the connection
constituted no expected request method.  Note that once we know the
answer--because something went wrong--we no longer feed the data to the
post processor, but we still have to consume it, or the client would
never get to read our response.
  if (0 == strcmp (method, "POST"))
    {
      struct connection_info_struct *con_info = *req_cls;

      if (0 != *upload_data_size)
        {
          if (0 == con_info->answercode)
            {
              if (MHD_YES !=
                  MHD_post_process (con_info->postprocessor,
	                            upload_data, *upload_data_size))
                {
                  con_info->answerstring = postprocerror;
                  con_info->answercode = MHD_HTTP_INTERNAL_SERVER_ERROR;
                }
            }
          *upload_data_size = 0;

          return MHD_YES;
        }

      if (NULL != con_info->fp)
        {
          fclose (con_info->fp);
          con_info->fp = NULL;
        }
      if (0 == con_info->answercode)
        {
          con_info->answerstring = completepage;
          con_info->answercode = MHD_HTTP_OK;
        }
      return send_page (connection, con_info->answerstring,
	       		con_info->answercode);
    }

  return send_page(connection, errorpage, MHD_HTTP_BAD_REQUEST);
}

Storing the data
================

Unlike the ‘simplepost.c’ example, here it is to be expected that post
iterator will be called several times now.  This means that for any
given connection (there might be several concurrent of them) the posted
data has to be written to the correct file.  That is why we store a file
handle in every ‘connection_info’, so that it is preserved between
successive iterations.
static enum MHD_Result
iterate_post (void *coninfo_cls, enum MHD_ValueKind kind,
	      const char *key,
	      const char *filename, const char *content_type,
              const char *transfer_encoding, const char *data,
	      uint64_t off, size_t size)
{
  struct connection_info_struct *con_info = coninfo_cls;
  FILE *fp;

   Because the following actions depend heavily on correct file
processing, which might be error prone, we record the page to answer
with as soon as anything goes wrong.  Note that the iterator always
returns ‘MHD_YES’: returning ‘MHD_NO’ would abort the post processor and
thus make it impossible to send our carefully chosen error page to the
client.

   In the "askpage" _form_, we told the client to label its post data
with the "file" key.  Anything else would be an error.

  if (0 != strcmp (key, "file"))
    {
      con_info->answerstring = servererrorpage;
      con_info->answercode = MHD_HTTP_BAD_REQUEST;
      return MHD_YES;
    }

   If the iterator is called for the first time, no file will have been
opened yet.  The ‘filename’ string contains the name of the file
(without any paths) the user selected on his system.  We want to take
this as the name the file will be stored on the server and make sure no
file of that name exists (or is being uploaded) before we create one
(note that the code below technically contains a race between the two
"fopen" calls, but we will overlook this for portability sake).
  if (!con_info->fp)
    {
      if (0 != con_info->answercode)  /* something went wrong before */
        return MHD_YES;

      if (NULL != (fp = fopen (filename, "rb")) )
        {
          fclose (fp);
          con_info->answerstring = fileexistspage;
          con_info->answercode = MHD_HTTP_FORBIDDEN;
          return MHD_YES;
        }

      con_info->fp = fopen (filename, "ab");
      if (!con_info->fp)
        {
          con_info->answerstring = fileioerror;
          con_info->answercode = MHD_HTTP_INTERNAL_SERVER_ERROR;
          return MHD_YES;
        }
    }

   Occasionally, the iterator function will be called even when there
are 0 new bytes to process.  The server only needs to write data to the
file if there is some.
  if (size > 0)
    {
      if (!fwrite (data, sizeof (char), size, con_info->fp))
        {
          con_info->answerstring = fileioerror;
          con_info->answercode = MHD_HTTP_INTERNAL_SERVER_ERROR;
        }
    }

   If this point has been reached without setting an answer code,
everything worked well for this iteration.  If the upload has finished,
this iterator function will not be called again and
‘answer_to_connection’ will declare success.
  return MHD_YES;
}

   The new client was registered when the postprocessor was created.
Likewise, we unregister the client on destroying the postprocessor when
the request is completed.
static void
request_completed (void *cls, struct MHD_Connection *connection,
     		        void **req_cls,
                        enum MHD_RequestTerminationCode toe)
{
  struct connection_info_struct *con_info = *req_cls;

  if (NULL == con_info) return;

  if (con_info->connectiontype == POST)
    {
      if (NULL != con_info->postprocessor)
        {
          MHD_destroy_post_processor (con_info->postprocessor);
          nr_of_uploading_clients--;
        }

      if (con_info->fp) fclose (con_info->fp);
    }

  free (con_info);
  *req_cls = NULL;
}

   This is essentially the whole example ‘largepost.c’.

Remarks
=======

Now that the clients are able to create files on the server, security
aspects are becoming even more important than before.  Aside from proper
client authentication, the server should always make sure explicitly
that no files will be created outside of a dedicated upload directory.
In particular, filenames must be checked to not contain strings like
"../".


File: libmicrohttpd-tutorial.info,  Node: Session management,  Next: Generating responses on the fly,  Prev: Improved processing of POST data,  Up: Top

8 Session management
********************

This chapter discusses how one should manage sessions, that is, share
state between multiple HTTP requests from the same user.  We use a
simple example where the user submits multiple forms and the server is
supposed to accumulate state from all of these forms.  Naturally, as
this is a network protocol, our session mechanism must support having
many users with many concurrent sessions at the same time.

   In order to track users, we use a simple session cookie.  A session
cookie expires when the user closes the browser.  Changing from session
cookies to persistent cookies only requires adding an expiration time to
the cookie.  The server creates a fresh session cookie whenever a
request without a cookie is received, or if the supplied session cookie
is not known to the server.

Looking up the cookie
=====================

Since MHD parses the HTTP cookie header for us, looking up an existing
cookie is straightforward:

const char *value;

value = MHD_lookup_connection_value (connection,
                                     MHD_COOKIE_KIND,
                                     "KEY");

   Here, "KEY" is the name we chose for our session cookie.

Setting the cookie header
=========================

MHD requires the user to provide the full cookie format string in order
to set cookies.  In order to generate a unique cookie, our example
creates a random 32-character text string to be used as the value of the
cookie:

char value[128];
char raw_value[33];

for (unsigned int i=0;i<sizeof (raw_value) - 1;i++)
  raw_value[i] = 'A' + (rand () % 26); /* bad PRNG! */
raw_value[sizeof (raw_value) - 1] = '\0';
snprintf (value, sizeof (value),
          "%s=%s",
          "KEY",
          raw_value);

   Given this cookie value, we can then set the cookie header in our
HTTP response as follows:

if (MHD_NO ==
    MHD_add_response_header (response,
                             MHD_HTTP_HEADER_SET_COOKIE,
                             value))
  fprintf (stderr, "Failed to set session cookie header!\n");

   Note that the header has to be added _before_ the response is queued
with ‘MHD_queue_response’; MHD refuses to modify a response that is
already queued.

Remark: Session expiration
==========================

It is of course possible that clients stop their interaction with the
server at any time.  In order to avoid using too much storage, the
server must thus discard inactive sessions at some point.  Our example
implements this by discarding inactive sessions after a certain amount
of time.  Alternatively, the implementation may limit the total number
of active sessions.  Which bounds are used for idle sessions or the
total number of sessions obviously depends largely on the type of the
application and available server resources.

Example code
============

A sample application implementing a website with multiple forms (which
are dynamically created using values from previous POST requests from
the same session) is available as the example ‘sessions.c’.

   Note that the example uses a simple, O(n) linked list traversal to
look up sessions and to expire old sessions.  Using a hash table and a
heap would be more appropriate if a large number of concurrent sessions
is expected.

Remarks
=======

Naturally, it is quite conceivable to store session data in a database
instead of in memory.  Still, having mechanisms to expire data
associated with long-time idle sessions (where the business process has
still not finished) is likely a good idea.


File: libmicrohttpd-tutorial.info,  Node: Generating responses on the fly,  Next: Answering from another thread,  Prev: Session management,  Up: Top

9 Generating responses on the fly
*********************************

All responses we have built so far were complete before they were
queued.  ‘MHD_create_response_from_buffer()’ needs the whole answer to
be sitting in memory already, and ‘MHD_create_response_from_fd()’ needs
it to be a file that the operating system can read for us.  Neither fits
an answer that is computed while it is being sent: the output of a
long-running report, a log file that is filtered on the fly, the result
of a database cursor, or simply a document that is far too large to be
worth assembling in a buffer first.

   For those cases _libmicrohttpd_ lets the application hand over a
callback instead of the data.  Whenever _MHD_ has room on the socket, it
calls that function and asks for the next few bytes.  The application
only ever needs one modest buffer, and the client starts receiving the
answer long before the last byte has been produced.

Creating the response
=====================

The response object is created with

struct MHD_Response *
MHD_create_response_from_callback (uint64_t size,
                                   size_t block_size,
                                   MHD_ContentReaderCallback crc,
                                   void *crc_cls,
                                   MHD_ContentReaderFreeCallback crfc);

   The five arguments are:

‘size’
     The total length of the body in bytes, or the constant
     ‘MHD_SIZE_UNKNOWN’ if the application does not know it in advance.
     If a concrete number is given, _MHD_ announces it as
     ‘Content-Length’ and expects the callback to deliver exactly that
     many bytes.

‘block_size’
     The buffer size _MHD_ should use when it queries the callback.  The
     value must not be zero--‘MHD_create_response_from_callback()’
     returns ‘NULL’ otherwise.  _MHD_ allocates a buffer of that size
     together with the response object.  Note that this buffer is only
     used for responses of known size; when chunked transfer encoding is
     in use (see below) the data is collected in the connection's own
     memory pool instead, and ‘block_size’ has no influence on how much
     _MHD_ asks for.  In either case the value is advisory: the callback
     must always look at the ‘max’ argument it is passed and never write
     more than that.

‘crc’
     The content reader callback itself, described in the next section.

‘crc_cls’
     An arbitrary pointer that is passed back to ‘crc’ on every
     invocation.  This is where the per-request state goes.

‘crfc’
     A callback that is invoked once, when the response object is
     destroyed, so that ‘crc_cls’ can be released.  May be ‘NULL’ if
     there is nothing to clean up.

The content reader callback
===========================

The callback has the following signature:

typedef ssize_t
(*MHD_ContentReaderCallback) (void *cls,
                              uint64_t pos,
                              char *buf,
                              size_t max);

   ‘cls’ is the ‘crc_cls’ pointer given at creation time.  ‘buf’ points
to the memory _MHD_ wants filled and ‘max’ is the number of bytes that
may be written there.

   The ‘pos’ argument deserves a closer look, because its meaning
depends on how the response is used.  For a response created from a file
descriptor, _MHD_ uses it as a file offset and reads with ‘pread()’;
that is what makes such a response object reusable for many connections.
For a response that is created fresh for each request--which is what we
do here--_MHD_ guarantees that ‘pos’ is simply the sum of all
non-negative values the callback has returned so far.  In other words:
for a stream, ‘pos’ is a monotonically increasing count of the bytes
already produced, and the callback will never be asked to go back.  A
generator that has no use for random access can ignore ‘pos’ completely.
Do note that the guarantee only holds as long as the response object is
used for one request; if the same object is queued for several
connections, the same content reader may be asked for the same data more
than once, and sharing one mutable buffer between them would be wrong.

   The return value tells _MHD_ what happened:

a positive number
     That many bytes were written to ‘buf’.  Returning more than ‘max’
     is a fatal application error and makes _MHD_ close the connection.

‘MHD_CONTENT_READER_END_OF_STREAM’
     The body is complete.  With chunked encoding _MHD_ terminates the
     chunk sequence properly and appends any footers; without chunked
     encoding and an unknown size it simply closes the connection.  If a
     concrete ‘size’ was announced, ending the stream early is not
     legal, and _MHD_ treats it essentially like an error--the client
     receives fewer bytes than the ‘Content-Length’ promised.

‘MHD_CONTENT_READER_END_WITH_ERROR’
     Something went wrong while generating the data; see below.

‘0’
     No data is available _right now_, but the stream is not over.

That last case is the dangerous one.  The header file states that
returning zero is legal only when _MHD_ is _not_ using an internal
sockets polling mode, and this is not a formality: _MHD_ does not
diagnose the situation, it simply arranges for the next poll to time out
immediately and calls the callback again.  A callback that returns zero
while a request is stalled for a third of a second is called several
million times in that period and pins a CPU core at 100%.  In external
polling mode the effect is milder--the callback is retried whenever the
application calls one of the ‘MHD_run*()’ functions--but it is still a
spin.  The proper answer for "no data yet" is to suspend the connection,
which is covered further down.

Keeping state per request
=========================

Because the callback is a plain C function, everything it needs to know
has to travel through ‘crc_cls’.  The natural shape of a streaming
handler is therefore: allocate a context on the heap, allocate its data
buffer, create the response with that context as ‘crc_cls’, and let the
free callback dispose of both.

struct ResponseContext
{
  char *buf;            /* heap buffer, refilled again and again */
  size_t fill;          /* number of valid bytes in buf */
  size_t off;           /* number of bytes of buf given to MHD */
  unsigned int block;   /* number of blocks produced so far */
};

   The two offsets are what make the buffer independent of _MHD_'s
appetite.  A block is generated once and may then be handed out over
several invocations, because ‘max’ can be smaller than what we have
ready:

static ssize_t
content_reader (void *cls, uint64_t pos, char *buf, size_t max)
{
  struct ResponseContext *ctx = cls;
  size_t ready;

  (void) pos;

  if (ctx->off == ctx->fill)
    {
      /* Everything we had was passed on, produce the next block. */
      if (BLOCK_COUNT == ctx->block)
        return MHD_CONTENT_READER_END_OF_STREAM;
      generate_block (ctx);
    }
  ready = ctx->fill - ctx->off;
  if (ready > max)
    ready = max;
  memcpy (buf, &ctx->buf[ctx->off], ready);
  ctx->off += ready;
  return (ssize_t) ready;
}

   ‘generate_block()’ is the place where a real application would run
its expensive computation, query, or network fetch.  The important
property is that the same buffer is reused every time, so the memory the
server needs does not grow with the size of the document.

   The handler assembles all of this and, from that moment on, hands
ownership of the context to the response object:

  ctx = malloc (sizeof (struct ResponseContext));
  if (NULL == ctx)
    return MHD_NO;
  ctx->buf = malloc (BUFFER_SIZE);
  if (NULL == ctx->buf)
    {
      free (ctx);
      return MHD_NO;
    }
  ctx->fill = 0;
  ctx->off = 0;
  ctx->block = 0;

  response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
                                                IO_BLOCK_SIZE,
                                                &content_reader,
                                                ctx,
                                                &free_context);
  if (NULL == response)
    {
      /* No response object exists, so nobody will call the free
         callback for us. */
      free_context (ctx);
      return MHD_NO;
    }
  ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
  MHD_destroy_response (response);

   Note the error path: as long as ‘MHD_create_response_from_callback()’
has not returned a response, the free callback will never run and the
application must clean up itself.

Releasing the state
===================

The free callback is trivial:

static void
free_context (void *cls)
{
  struct ResponseContext *ctx = cls;

  free (ctx->buf);
  free (ctx);
}

   _MHD_ invokes it when the last reference to the response object goes
away.  The call to ‘MHD_destroy_response()’ in the handler does not
trigger it, because queuing the response took a reference; the callback
runs when the connection is finished with the response.  That happens
after a completed body, but equally after a client that closed the
socket in the middle of the download, after a timeout, and when the
daemon is stopped.  This is precisely what makes the free callback the
right place for the cleanup: there is no other hook that covers all of
these cases.

Unknown size and chunked encoding
=================================

Passing ‘MHD_SIZE_UNKNOWN’ as the size leaves _MHD_ with the problem of
telling the client where the body ends.  For an HTTP/1.1 client it
solves it by switching to chunked transfer encoding: it adds a
‘Transfer-Encoding: chunked’ header and frames every piece the callback
returns as one chunk, terminating the body with a zero-length chunk when
the callback reports the end of the stream.  Nothing has to be done for
this; it is a consequence of the unknown size.

< HTTP/1.1 200 OK
< Content-Type: text/plain
< Transfer-Encoding: chunked

   An HTTP/1.0 client cannot be sent chunks.  In that case _MHD_ falls
back to the only other framing the protocol offers and marks the
connection as one that must be closed: the body is sent raw, without
‘Content-Length’, and its end is the end of the connection.  The data
arrives intact, but the client has no way to distinguish a complete
answer from one that was cut short.

   If the size _is_ known--and in the example program the URL ‘/sized’
shows this variant--it should be announced, simply by passing the number
instead of ‘MHD_SIZE_UNKNOWN’.  _MHD_ then emits a normal
‘Content-Length’ header, no chunk framing is added, and the callback is
queried with ‘max’ limited by both ‘block_size’ and the number of bytes
still outstanding.  The callback must produce exactly the announced
number of bytes.

Aborting a response
===================

Generating data can fail halfway through--the database connection drops,
a file disappears, an allocation fails.  Since the response headers, and
probably a good part of the body, have already been sent, there is no
way to turn the answer into an error page any more.  Returning
‘MHD_CONTENT_READER_END_WITH_ERROR’ is the way to give up: _MHD_ logs
the condition and closes the connection immediately, without writing the
terminating chunk.

   What the client sees depends on the framing.  With chunked encoding
it is an abnormally terminated chunk stream, and a well-behaved client
reports it as such--‘curl’ for instance fails with "transfer closed with
outstanding read data remaining" and a non-zero exit status.  With an
announced ‘Content-Length’ the client notices that the body is shorter
than promised.  Only in the HTTP/1.0 case discussed above, where the end
of the body is the end of the connection, is the failure
indistinguishable from a normal ending; that is a property of the
protocol and not something _MHD_ can repair.  The URL ‘/error’ of the
example program aborts the stream after a few blocks so that this can be
observed.

When the data is not ready yet
==============================

So far the generator could always produce the next block on the spot.
If it cannot--because the data is coming from another thread, another
process, or the network--then, as explained above, returning ‘0’ in an
internal polling mode turns the daemon into a busy loop.  The supported
answer is to take the connection out of the event loop until the data
has arrived, with the pair

void MHD_suspend_connection (struct MHD_Connection *connection);
void MHD_resume_connection (struct MHD_Connection *connection);

   The daemon has to be started with the ‘MHD_ALLOW_SUSPEND_RESUME’
flag; both functions call ‘MHD_PANIC()’ and abort the process otherwise.
The flag implies ‘MHD_USE_ITC’, so that a resumed connection wakes the
polling thread up instead of waiting for the next timeout.  Suspending
is not available for daemons running with
‘MHD_USE_THREAD_PER_CONNECTION’, and the daemon must not be stopped
while connections are still suspended.

   ‘MHD_suspend_connection()’ may only be called from the access handler
or from the content reader callback, which means the connection handle
has to be stored in the context struct so that the callback can reach
it.  The pattern is then:

  if (! ctx->data_available)
    {
      MHD_suspend_connection (ctx->connection);
      return 0;
    }

   ‘MHD_resume_connection()’, in contrast, may be called from any thread
and at any time.  In particular it is explicitly allowed to call it
before the suspension has taken effect: the producer may already be done
by the time the callback gets around to suspending.  _MHD_ handles this
by remembering the resume request and, when the suspension is finally
processed, cancelling it instead of parking the connection, so the
wakeup can never be lost.  This is what makes the "check, suspend,
return 0" sequence above safe without a lock of its own.

   The difference is dramatic in practice.  A callback that stalls for
three hundred milliseconds and returns ‘0’ is entered several million
times and burns a full core; the same callback suspending the connection
is entered exactly once more and the daemon uses no measurable CPU time
at all.

   Suspending brings requirements of its own--on who may call what from
which thread, on how a worker thread wakes up a blocked event loop, and
on who releases the shared state when a client disappears halfway
through.  *note Answering from another thread:: works all of that out on
a complete program.

Trailers
========

Chunked responses may carry trailers, that is header fields that are
transmitted after the body.  They are added with

MHD_add_response_footer (response, "X-Checksum", "deadbeef");

   _MHD_ writes them out after the terminating zero-length chunk:

0
X-Checksum: deadbeef


   Footers may still be added while the body is being generated--even
from inside the content reader callback, immediately before returning
‘MHD_CONTENT_READER_END_OF_STREAM’--which is what makes them useful in
the first place: a checksum or a row count over data that has only just
been produced cannot be put into the headers, because those are long
gone.  This is safe as long as the response object belongs to a single
request, as it does in the pattern used here.  _MHD_ does not generate a
‘Trailer’ response header by itself; if the client should be told in
advance which fields to expect, add it with ‘MHD_add_response_header()’.
Be aware that many clients discard trailers silently.

Example code
============

The complete program is available as ‘callbackresponse.c’.  It serves a
document of sixty-four blocks that are produced one at a time into a
single heap buffer.  ‘GET /’ streams it with ‘MHD_SIZE_UNKNOWN’ and thus
with chunked encoding, ‘GET /sized’ streams the same bytes with a
‘Content-Length’ announced up front, and ‘GET /error’ aborts in the
middle.

Remarks
=======

Calls into the content reader of one response object are serialized by
_MHD_, so a per-request context needs no locking of its own as long as
no other thread touches it.  As soon as a producer thread is
involved--the suspend/resume case--the shared fields do need protection.

   The chunk boundaries are not under the application's control and
carry no meaning: a client may receive the bytes of one callback
invocation spread over several chunks or, in other configurations,
several invocations combined.  Chunked encoding is a transport detail,
and any record structure the application needs must be part of the body
itself.

   Finally, returning very small amounts of data per invocation is
correct but wasteful, since every invocation may become its own chunk
with its own framing overhead.  If the producer has more data ready, it
should fill as much of ‘buf’ as ‘max’ permits.

Exercises
=========

   • Add a URL that reports how far the transfer has progressed by
     writing the value of ‘pos’ into every line, and confirm with a slow
     client (‘curl --limit-rate’) that it really is the number of bytes
     already sent, and not a block counter.

   • Register a request completion callback with
     ‘MHD_OPTION_NOTIFY_COMPLETED’ and print the termination code.  Then
     download the document, interrupt the client in the middle, and
     watch in which order the completion callback and the content
     reader's free callback are invoked, and that the free callback runs
     in both cases.

   • Turn the generator into an asynchronous one.  Start a thread that
     appends a line to a shared buffer once per second, keep the
     connection handle in the context struct, and suspend the connection
     whenever the buffer is empty.  Do not forget
     ‘MHD_ALLOW_SUSPEND_RESUME’ when starting the daemon.  Then remove
     the call to ‘MHD_suspend_connection()’, leaving only the ‘return
     0’, and compare the CPU usage of the server process.  A complete
     solution, together with the ownership rules that a shared buffer
     between a worker and the event loop needs, is the subject of *note
     Answering from another thread::.

   • Compute a checksum over the generated document while it is being
     sent and append it as a trailer.  Watch it on the wire--most
     command line clients will not show it to you, so a raw ‘nc’ or a
     small script speaking HTTP by hand is the easier tool here.


File: libmicrohttpd-tutorial.info,  Node: Answering from another thread,  Next: Adding a layer of security,  Prev: Generating responses on the fly,  Up: Top

10 Answering from another thread
********************************

The previous chapter left one question open.  A content reader that has
no data ready may return ‘0’, but doing so turns the daemon into a busy
loop, and the honest answer--suspend the connection--was only sketched
there.  This chapter builds the thing itself: a server whose slow work
happens in threads of its own, whose connections are parked while that
work is under way, and which is driven by an external ‘select()’ loop so
that the application stays in charge of its own event handling.

   The combination is a common one.  Most requests are cheap and can be
answered on the spot; a few of them start a report, a backup or a query
that runs for seconds.  Handling the slow ones inline would block every
other client for as long as they take.  Giving every connection its own
thread--‘MHD_USE_THREAD_PER_CONNECTION’--is no answer either, both
because it scales badly and because suspending is not available in that
mode at all.  What is wanted is a single event loop that never blocks,
plus a worker per slow job.

Who may call what
=================

Almost every difficulty in this design comes from one rule, so it is
worth stating before any code:

‘MHD_queue_response()’
     Must be called from the thread that runs the daemon, from inside
     the access handler.  A worker thread must never queue a response.

‘MHD_suspend_connection()’
     May only be called from the access handler or from a content reader
     callback--that is, from _MHD_'s own thread, while _MHD_ is calling
     into the application.

‘MHD_resume_connection()’
     May be called from any thread at any time, and this is the
     exception that makes the whole design work.  It is the only _MHD_
     function a worker thread ever needs.

So the split is: the worker computes and, when it has something,
resumes.  Everything that touches the connection or the response happens
on the daemon's thread, where _MHD_ calls the application back.  The
worker and the daemon share exactly one object, a per-request context,
and the only thing the worker does with the connection handle it holds
is pass it to ‘MHD_resume_connection()’.

   The daemon has to be started with ‘MHD_ALLOW_SUSPEND_RESUME’; both
suspend and resume call ‘MHD_PANIC()’ and abort the process otherwise.
Note also that suspending does not work with a thread pool:
‘MHD_resume_connection()’ asserts that the daemon has none.

The event loop
==============

Leaving out ‘MHD_USE_INTERNAL_POLLING_THREAD’ puts _MHD_ into external
polling mode: it starts no thread of its own and does nothing until the
application asks it to.  The loop is the usual one, and the example adds
its own descriptor to the very same sets--there is nothing special about
_MHD_'s:

  FD_ZERO (&rs); FD_ZERO (&ws); FD_ZERO (&es);
  max = 0;
  if (MHD_YES != MHD_get_fdset (daemon, &rs, &ws, &es, &max))
    break;                      /* fatal internal error */
  FD_SET (wake_pipe[0], &rs);   /* our own wakeup pipe */
  if (max < wake_pipe[0])
    max = wake_pipe[0];

  if (MHD_YES == MHD_get_timeout64 (daemon, &mhd_timeout))
    { ...fill tv...; tvp = &tv; }
  else
    tvp = NULL;                 /* nothing to wait for */

  select ((int) max + 1, &rs, &ws, &es, tvp);
  MHD_run_from_select (daemon, &rs, &ws, &es);

   The interesting branch is the one that sets ‘tvp’ to ‘NULL’.
‘MHD_get_timeout64()’ returns ‘MHD_NO’ when _MHD_ has nothing whatsoever
to wait for, and with every connection suspended that is precisely the
situation: suspended connections do not time out, so there is no
deadline to wake up for.  The loop then blocks in ‘select()’
indefinitely.  Whether the server works at all depends on something
waking it up.

Waking the loop up
==================

That something is _MHD_'s inter-thread communication channel.
‘MHD_ALLOW_SUSPEND_RESUME’ is defined as ‘8192 | MHD_USE_ITC’, so
requesting suspend support requests the ITC as well; ‘MHD_get_fdset()’
puts the reading end of that channel into the read set, ahead of
everything else; and ‘MHD_resume_connection()’ writes a byte to it.  A
worker thread that resumes a connection therefore breaks the main thread
out of ‘select()’, even though the two share nothing but the daemon
handle.

   This deserves emphasis because the header file is misleading about
it: the comment on ‘MHD_USE_ITC’ says the flag is ignored with external
polling.  That is true for the flag in isolation, but not for the
channel: ‘MHD_ALLOW_SUSPEND_RESUME’ creates it regardless of the polling
mode, and in external mode it is the application's own ‘select()’ that
watches it.  Without that, a resumed connection would sit untouched
until some unrelated event happened to wake the loop.

   There is no race to guard against here.  If the worker resumes in the
window between ‘MHD_get_fdset()’ and ‘select()’, the byte is already in
the channel when ‘select()’ is entered, and ‘select()’ returns
immediately--the channel is level triggered, so a wakeup cannot be
missed.  The same property makes it safe for a worker to resume a
connection that has not finished suspending yet: _MHD_ remembers the
request and cancels the pending suspension instead of parking the
connection.  Neither side needs to know what the other is doing.

Answering in one piece
======================

The simplest of the two patterns is for an answer that is only useful as
a whole--a generated report, the result of a query.  Nothing can be sent
before it is finished, so the connection is suspended in the access
handler and the response is queued when _MHD_ comes back:

static enum MHD_Result
handle_slow (struct MHD_Connection *connection, void **req_cls)
{
  struct Job *job = *req_cls;

  if (NULL == job)
    {
      /* First call for this request: start the work and ask MHD to
         come back to us. */
      job = job_create (connection, 0);
      if (NULL == job)
        return MHD_NO;
      if (MHD_NO == job_start (job))
        { job_unref (job); job_unref (job); return MHD_NO; }
      *req_cls = job;
      return MHD_YES;
    }
  pthread_mutex_lock (&job->lock);
  if (0 == job->finished)
    {
      job->suspended = 1;
      MHD_suspend_connection (connection);
      pthread_mutex_unlock (&job->lock);
      return MHD_YES;
    }
  ...copy the result out from under the lock...
  pthread_mutex_unlock (&job->lock);
  ...MHD_create_response_from_buffer_copy() and MHD_queue_response()...
}

   The control flow is worth following, because it is not obvious that
it terminates.  _MHD_ calls the access handler for a request more than
once; the first call is the one where ‘*req_cls’ is still ‘NULL’, and
returning ‘MHD_YES’ without queueing anything tells _MHD_ to carry on.
On the second call the worker is running but not finished, so the
connection is suspended and the handler returns again.  When the worker
resumes the connection, _MHD_ calls the handler a third time--on its own
thread, with the same ‘*req_cls’--and this time ‘finished’ is set and
the response is queued.

   That third call is the answer to the question this pattern exists
for.  The worker never queues anything; it merely makes the daemon call
the application back at a moment when the answer is ready.

Answering as it is produced
===========================

The second pattern is the more useful one when the answer is long, and
it is what makes a browser show results as they appear rather than after
a long blank pause.  Here the response is queued _immediately_, with a
content reader and an unknown size, so the headers go out at once and
the body follows as the worker fills it in:

  job = job_create (connection, 1);
  response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
                                                IO_BLOCK_SIZE,
                                                &stream_reader,
                                                job,
                                                &stream_done);
  ...
  MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_TYPE,
                           "text/event-stream");
  ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
  MHD_destroy_response (response);

   Because the size is unknown, _MHD_ uses chunked transfer encoding,
and every piece the content reader hands back is framed as its own chunk
and goes out on the wire straight away.  The content reader is where
suspending happens:

static ssize_t
stream_reader (void *cls, uint64_t pos, char *buf, size_t max)
{
  struct Job *job = cls;
  size_t ready;

  pthread_mutex_lock (&job->lock);
  if (job->off == job->fill)
    {
      job->off = 0;
      job->fill = 0;
      if (0 != job->finished)
        {
          pthread_mutex_unlock (&job->lock);
          return MHD_CONTENT_READER_END_OF_STREAM;
        }
      /* Nothing to send yet.  Take the connection out of the event
         loop; the worker will put it back in. */
      job->suspended = 1;
      MHD_suspend_connection (job->connection);
      pthread_mutex_unlock (&job->lock);
      return 0;
    }
  ready = job->fill - job->off;
  if (ready > max)
    ready = max;
  memcpy (buf, &job->payload[job->off], ready);
  job->off += ready;
  pthread_mutex_unlock (&job->lock);
  return (ssize_t) ready;
}

   The return value is still ‘0’, exactly as in the busy-waiting version
the previous chapter warned about.  The difference is the line above it.
Suspending removes the connection from the event loop, so _MHD_ has no
reason to come back until the worker says so, and the process goes to
sleep.  The example ships with a test that measures this: streaming a
document that takes one second to produce costs the server no measurable
CPU time at all while the connection is suspended, and very nearly a
full second--one core, saturated--when the ‘MHD_suspend_connection()’
call is removed and only the ‘return 0’ is left.  The bytes that arrive
are identical in both cases, which is what makes this such an easy
mistake to keep.

The shared state
================

Everything the two threads share sits in one structure per request:

struct Job
{
  pthread_mutex_t lock;
  pthread_cond_t cond;
  struct MHD_Connection *connection;
  char payload[MAX_PAYLOAD];
  size_t fill;
  size_t off;
  unsigned int rc;
  int finished;
  int suspended;
  int abandoned;
  ...
};

   There is no registry of pending requests involved in answering them,
and no lookup: the pointer travels in ‘*req_cls’ for the first pattern
and in the content reader's ‘crc_cls’ for the second, and both the
daemon and the worker are handed it directly.  A shared list of all jobs
is still useful, but only for shutting down in an orderly fashion, and
it is protected by a lock of its own that is always taken before any
job's lock, never after.

   The structure is reference counted, with one reference held by _MHD_
and one by the worker.  The _MHD_ side lets go in the free callback of
the response for a streamed answer, and in the
‘MHD_OPTION_NOTIFY_COMPLETED’ callback for the other pattern; the worker
lets go when it returns.  Dropping the last reference does not free the
job, though, because the worker still has to be joined and only the main
thread may do that.  The main loop therefore ends with a sweep that
joins and frees whatever has no references left.

When the client goes away
=========================

This is the part that is easy to get wrong, because it does not happen
during development and does happen constantly in production.  A client
that closes the connection halfway through a download leaves a worker
running with a pointer to a connection _MHD_ is about to free.

   The two callbacks that tell the application a request is over--the
response's free callback and ‘MHD_OPTION_NOTIFY_COMPLETED’--are
therefore where the worker is cut loose:

static void
job_detach (struct Job *job)
{
  pthread_mutex_lock (&job->lock);
  job->abandoned = 1;
  job->connection = NULL;
  pthread_cond_signal (&job->cond);
  pthread_mutex_unlock (&job->lock);
  job_unref (job);
}

   and the worker checks that flag before every resume:

static void
job_resume_locked (struct Job *job)
{
  if ( (0 == job->suspended) || (0 != job->abandoned) )
    return;
  job->suspended = 0;
  MHD_resume_connection (job->connection);
}

   Note that this function is called with the job's lock _held_, and
calls into _MHD_ without releasing it.  That is deliberate and it is
what makes the pattern safe.  _MHD_ destroys the connection only after
the completion callback has returned, and that callback cannot run while
the worker holds the lock; so for as long as the worker is inside
‘MHD_resume_connection()’, the connection it passes is guaranteed to
still exist.  Dropping the lock first and resuming afterwards would open
exactly the window this is meant to close.

   The reverse order never occurs: _MHD_ invokes the free and completion
callbacks without holding the internal locks that
‘MHD_resume_connection()’ acquires, so there is no way for the two to
deadlock.

   The condition variable in the same function is a convenience rather
than a necessity.  Signalling it wakes a worker that is asleep between
steps, so that the work stops within microseconds of the client
disappearing instead of running to completion for nobody.

Shutting down
=============

Stopping a daemon that still has suspended connections is an API
violation, and a suspended connection is one that only a worker can
release.  The order is therefore fixed:

  1. Stop handing out new jobs.

  2. Tell every worker to give up, and _join_ them.  After this point no
     connection can be suspended any more: the workers resume before
     they exit, and the content reader only ever suspends while a worker
     is running.

  3. Keep running the event loop until the connections have drained, so
     that the last bytes actually reach the clients.

  4. ‘MHD_stop_daemon()’.

Skipping the join in step two is the tempting shortcut, and it is the
one that leaves a connection parked forever with nothing left alive to
wake it.

Example code
============

The complete program is available as ‘asyncresponse.c’.  It runs one
external ‘select()’ loop and serves four URLs:

‘/’
     A small page whose JavaScript opens the stream below and appends a
     row for every event as it arrives.  The rows visibly trickle in,
     one per step, which is the most direct demonstration of what the
     chapter is about.

‘/events’
     The stream: a response is queued at once, and the content reader
     suspends between steps.  The body is a sequence of server-sent
     events, which needs no library on the browser side.

‘/slow’
     The other pattern: the connection is suspended in the access
     handler and a complete answer is queued once the worker is done.

‘/fast’
     Answered on the spot.  The page has a button that requests it and
     reports the round trip time; it stays in the low milliseconds while
     jobs are running, which is the point of suspending rather than
     blocking.

The program takes the port, the duration of a step in milliseconds and
the number of steps on the command line.  Passing ‘0’ as the port makes
the operating system choose a free one, which the program then reports
via ‘MHD_DAEMON_INFO_BIND_PORT’:

$ ./asyncresponse 0 250 20
Listening on port 44321

   The accompanying ‘test_asyncresponse.c’ starts exactly that binary
and checks over HTTP that ‘/slow’ waits for its worker, that the body of
‘/events’ really arrives in pieces spread over the lifetime of the
request rather than in one burst at the end, that ‘/fast’ is still
served promptly while jobs are parked, that a client which hangs up in
the middle takes neither the server nor the worker with it, and that the
process exits cleanly when it is signalled while a connection is
suspended.  It also compares the server's CPU time against the wall
clock time of a transfer, which is the only one of those checks that
notices the difference between a suspended connection and a busy-waiting
one.

Remarks
=======

_MHD_ does not detect that a client has disconnected while a connection
is suspended, and the connection timeout does not run either.  A
suspended connection stays suspended until somebody resumes it, without
exception.  Any timeout on the work itself is therefore the
application's responsibility.

   Suspended connections still count against the connection limits, both
the global one and the per-IP one.  A server that parks connections for
minutes needs its limits sized for the number of jobs it expects to have
in flight, not for the number it expects to be transmitting.

   If the client vanishes in the middle of a chunked response, the next
write fails and _MHD_ logs it--with ‘MHD_USE_ERROR_LOG’ enabled the
example prints ‘Failed to send the chunked response body ... The socket
is no longer available for sending’.  That is the normal course of
events for an aborted download and not a sign of a problem.

   Finally, none of this is specific to ‘select()’.  The same argument
holds for ‘poll()’ and for ‘epoll’, where the daemon's descriptor can be
obtained with ‘MHD_DAEMON_INFO_EPOLL_FD’ and added to an epoll set of
the application's own; ‘suspend_resume_epoll.c’ among the distribution's
examples shows that variant.

Exercises
=========

   • Give the jobs a deadline.  Since a suspended connection never times
     out on its own, add a check to the main loop that resumes--and
     answers with ‘503’--any job that has been running for too long, and
     confirm with a step duration long enough to trigger it.

   • Remove the ‘MHD_suspend_connection()’ call from the content reader,
     leaving only the ‘return 0’, and watch the server process with
     ‘top’ while a single client downloads the stream.  Then put it back
     and watch again.  Both servers send the same bytes.

   • Take the resume out of the worker's final block, so that a finished
     job leaves its connection parked, and then stop the server while a
     job is in flight.  Watch what the shutdown does--and what
     ‘valgrind’ has to say about it--and work out which of the four
     steps above was violated.

   • Replace the per-request thread with a fixed pool of worker threads
     and a queue of pending jobs.  The reference counting and the
     ‘abandoned’ flag should not need to change at all; if they do, the
     ownership rules were not as clean as they looked.

   • Serve the stream to two browser windows at once and confirm from
     the timestamps that the two jobs run concurrently and are
     interleaved by a single-threaded event loop.


File: libmicrohttpd-tutorial.info,  Node: Adding a layer of security,  Next: Upgrading connections,  Prev: Answering from another thread,  Up: Top

11 Adding a layer of security
*****************************

We left the basic authentication chapter with the unsatisfactory
conclusion that any traffic, including the credentials, could be
intercepted by anyone between the browser client and the server.
Protecting the data while it is sent over unsecured lines will be the
goal of this chapter.

   The _MHD_ library includes support for encrypting the traffic by
employing TLS (the protocol formerly known as SSL). If _GNU
libmicrohttpd_ has been configured to support this, encryption and
decryption can be applied transparently on the data being sent, with
only minimal changes to the actual source code of the example.

Preparation
===========

First, a private key for the server will be generated.  With this key,
the server will later be able to authenticate itself to the
client--preventing anyone else from stealing the password by faking its
identity.  The _OpenSSL_ suite, which is available on many operating
systems, can generate such a key.  1024 bit keys are no longer
considered secure, so we use a 2048 bit key:
> openssl genrsa -out server.key 2048

   In addition to the key, a certificate describing the server in human
readable tokens is also needed.  This certificate will be attested with
our aforementioned key.  In this way, we obtain a self-signed
certificate, valid for one year.

   To avoid unnecessary error messages in the browser, the certificate
needs to carry a _subjectAltName_ that matches the _URI_, for example,
"localhost" or the domain (current browsers ignore the common name and
look at the _subjectAltName_ only).

> openssl req -days 365 -out server.pem -new -x509 -key server.key \
      -addext "subjectAltName=DNS:localhost"

   If you plan to have a publicly reachable server, you will need to ask
a trusted third party, called _Certificate Authority_, or _CA_, to
attest the certificate for you.  This way, any visitor can make sure the
server's identity is real.

   Whether the server's certificate is signed by us or a third party,
once it has been accepted by the client, both sides will be
communicating over encrypted channels.  From this point on, it is the
client's turn to authenticate itself.  But this has already been
implemented in the basic authentication scheme.

Changing the source code
========================

We merely have to extend the server program so that it loads the two
files into memory,

int
main (void)
{
  struct MHD_Daemon *daemon;
  char *key_pem;
  char *cert_pem;

  key_pem = load_file (SERVERKEYFILE);
  cert_pem = load_file (SERVERCERTFILE);

  if ((key_pem == NULL) || (cert_pem == NULL))
  {
    printf ("The key/certificate files could not be read.\n");
    return 1;
  }

   and then we point the _MHD_ daemon to it upon initialization.

  daemon = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_TLS,
  	   		     PORT, NULL, NULL,
                             &answer_to_connection, NULL,
                             MHD_OPTION_HTTPS_MEM_KEY, key_pem,
                             MHD_OPTION_HTTPS_MEM_CERT, cert_pem,
                             MHD_OPTION_END);

  if (NULL == daemon)
    {
      printf ("%s\n", cert_pem);

      free (key_pem);
      free (cert_pem);

      return 1;
    }

   The rest consists of little new besides some additional memory
cleanups.

  getchar ();

  MHD_stop_daemon (daemon);
  free (key_pem);
  free (cert_pem);

  return 0;
}

   The rather unexciting file loader can be found in the complete
example ‘tlsauthentication.c’.

Remarks
=======

   • While the standard _HTTP_ port is 80, it is 443 for _HTTPS_. The
     common internet browsers assume standard _HTTP_ if they are asked
     to access other ports than these.  Therefore, you will have to type
     ‘https://localhost:8888’ explicitly when you test the example, or
     the browser will not know how to handle the answer properly.

   • The remaining weak point is the question how the server will be
     trusted initially.  Either a _CA_ signs the certificate or the
     client obtains the key over secure means.  Anyway, the clients have
     to be aware (or configured) that they should not accept
     certificates of unknown origin.

   • The introduced method of certificates makes it mandatory to set an
     expiration date--making it less feasible to hardcode certificates
     in embedded devices.

   • The cryptographic facilities consume memory space and computing
     time.  For this reason, websites usually consists both of
     uncritically _HTTP_ parts and secured _HTTPS_.

Client authentication
=====================

You can also use MHD to authenticate the client via SSL/TLS certificates
(as an alternative to using the password-based Basic or Digest
authentication).  To do this, you will need to link your application
against _gnutls_.  Next, when you start the MHD daemon, you must specify
the root CA that you're willing to trust:
  daemon = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_TLS,
  	   		     PORT, NULL, NULL,
                             &answer_to_connection, NULL,
                             MHD_OPTION_HTTPS_MEM_KEY, key_pem,
                             MHD_OPTION_HTTPS_MEM_CERT, cert_pem,
			     MHD_OPTION_HTTPS_MEM_TRUST, root_ca_pem,
                             MHD_OPTION_END);

   With this, you can then obtain client certificates for each session.
In order to obtain the identity of the client, you first need to obtain
the raw GnuTLS session handle from _MHD_ using
‘MHD_get_connection_info’.

#include <gnutls/gnutls.h>
#include <gnutls/x509.h>

gnutls_session_t tls_session;
const union MHD_ConnectionInfo *ci;

ci = MHD_get_connection_info (connection,
                              MHD_CONNECTION_INFO_GNUTLS_SESSION);
tls_session = (gnutls_session_t) ci->tls_session;

   You can then extract the client certificate:

/**
 * Get the client's certificate
 *
 * @param tls_session the TLS session
 * @return NULL if no valid client certificate could be found, a pointer
 *  	to the certificate if found
 */
static gnutls_x509_crt_t
get_client_certificate (gnutls_session_t tls_session)
{
  unsigned int listsize;
  const gnutls_datum_t * pcert;
  gnutls_certificate_status_t client_cert_status;
  gnutls_x509_crt_t client_cert;

  if (tls_session == NULL)
    return NULL;
  if (gnutls_certificate_verify_peers2(tls_session,
				       &client_cert_status))
    return NULL;
  if (0 != client_cert_status)
  {
    fprintf (stderr,
            "Failed client certificate invalid: %d\n",
            client_cert_status);
    return NULL;
  }
  pcert = gnutls_certificate_get_peers(tls_session,
				       &listsize);
  if ( (pcert == NULL) ||
       (listsize == 0))
    {
      fprintf (stderr,
	       "Failed to retrieve client certificate chain\n");
      return NULL;
    }
  if (gnutls_x509_crt_init(&client_cert))
    {
      fprintf (stderr,
	       "Failed to initialize client certificate\n");
      return NULL;
    }
  /* Note that by passing values between 0 and listsize here, you
     can get access to the CA's certs */
  if (gnutls_x509_crt_import(client_cert,
			     &pcert[0],
			     GNUTLS_X509_FMT_DER))
    {
      fprintf (stderr,
	       "Failed to import client certificate\n");
      gnutls_x509_crt_deinit(client_cert);
      return NULL;
    }
  return client_cert;
}

   Using the client certificate, you can then get the client's
distinguished name and alternative names:

/**
 * Get the distinguished name from the client's certificate
 *
 * @param client_cert the client certificate
 * @return NULL if no dn or certificate could be found, a pointer
 * 			to the dn if found
 */
char *
cert_auth_get_dn(gnutls_x509_crt_t client_cert)
{
  char* buf;
  size_t lbuf;

  lbuf = 0;
  gnutls_x509_crt_get_dn(client_cert, NULL, &lbuf);
  buf = malloc(lbuf);
  if (buf == NULL)
    {
      fprintf (stderr,
	       "Failed to allocate memory for certificate dn\n");
      return NULL;
    }
  gnutls_x509_crt_get_dn(client_cert, buf, &lbuf);
  return buf;
}


/**
 * Get the alternative name of specified type from the client's certificate
 *
 * @param client_cert the client certificate
 * @param nametype The requested name type
 * @param index The position of the alternative name if multiple names are
 * 			matching the requested type, 0 for the first matching name
 * @return NULL if no matching alternative name could be found, a pointer
 * 			to the alternative name if found
 */
char *
MHD_cert_auth_get_alt_name(gnutls_x509_crt_t client_cert,
			   int nametype,
			   unsigned int index)
{
  char* buf;
  size_t lbuf;
  unsigned int seq;
  unsigned int subseq;
  unsigned int type;
  int result;

  subseq = 0;
  for (seq=0;;seq++)
    {
      lbuf = 0;
      result = gnutls_x509_crt_get_subject_alt_name2(client_cert, seq, NULL, &lbuf,
						     &type, NULL);
      if (result == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
	return NULL;
      if (nametype != (int) type)
	continue;
      if (subseq == index)
	break;
      subseq++;
    }
  buf = malloc(lbuf);
  if (buf == NULL)
    {
      fprintf (stderr,
	       "Failed to allocate memory for certificate alt name\n");
      return NULL;
    }
  result = gnutls_x509_crt_get_subject_alt_name2(client_cert,
						 seq,
						 buf,
						 &lbuf,
						 NULL, NULL);
  if (result != nametype)
    {
      fprintf (stderr,
	       "Unexpected return value from gnutls: %d\n",
	       result);
      free (buf);
      return NULL;
    }
  return buf;
}

   Finally, you should release the memory associated with the client
certificate:

gnutls_x509_crt_deinit (client_cert);

Using TLS Server Name Indication (SNI)
======================================

SNI enables hosting multiple domains under one IP address with TLS. So
SNI is the TLS-equivalent of virtual hosting.  To use SNI with MHD, you
need at least GnuTLS 3.0.  The main change compared to the simple
hosting of one domain is that you need to provide a callback instead of
the key and certificate.  For example, when you start the MHD daemon,
you could do this:
  daemon = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_TLS,
  	   		     PORT, NULL, NULL,
                             &answer_to_connection, NULL,
                             MHD_OPTION_HTTPS_CERT_CALLBACK, &sni_callback,
                             MHD_OPTION_END);
   Here, ‘sni_callback’ is the name of a function that you will have to
implement to retrieve the X.509 certificate for an incoming connection.
The callback has type ‘gnutls_certificate_retrieve_function2’ and is
documented in the GnuTLS API for the
‘gnutls_certificate_set_retrieve_function2’ as follows:

 -- Function Pointer: int *gnutls_certificate_retrieve_function2
          (gnutls_session_t, const gnutls_datum_t* req_ca_dn, int nreqs,
          const gnutls_pk_algorithm_t* pk_algos, int pk_algos_length,
          gnutls_pcert_st** pcert, unsigned int *pcert_length,
          gnutls_privkey_t * pkey)

     REQ_CA_DN
          is only used in X.509 certificates.  Contains a list with the
          CA names that the server considers trusted.  Normally we
          should send a certificate that is signed by one of these CAs.
          These names are DER encoded.  To get a more meaningful value
          use the function ‘gnutls_x509_rdn_get()’.

     PK_ALGOS
          contains a list with server's acceptable signature algorithms.
          The certificate returned should support the server's given
          algorithms.

     PCERT
          should contain a single certificate and public or a list of
          them.

     PCERT_LENGTH
          is the size of the previous list.

     PKEY
          is the private key.

   A possible implementation of this callback would look like this:

struct Hosts
{
  struct Hosts *next;
  const char *hostname;
  gnutls_pcert_st pcrt;
  gnutls_privkey_t key;
};

static struct Hosts *hosts;

int
sni_callback (gnutls_session_t session,
              const gnutls_datum_t* req_ca_dn,
              int nreqs,
              const gnutls_pk_algorithm_t* pk_algos,
              int pk_algos_length,
              gnutls_pcert_st** pcert,
              unsigned int *pcert_length,
              gnutls_privkey_t * pkey)
{
  char name[256];
  size_t name_len;
  struct Hosts *host;
  unsigned int type;

  name_len = sizeof (name);
  if (GNUTLS_E_SUCCESS !=
      gnutls_server_name_get (session,
                              name,
                              &name_len,
                              &type,
                              0 /* index */))
    return -1;
  for (host = hosts; NULL != host; host = host->next)
    if (0 == strncmp (name, host->hostname, name_len))
      break;
  if (NULL == host)
    {
      fprintf (stderr,
               "Need certificate for %.*s\n",
               (int) name_len,
               name);
      return -1;
    }
  fprintf (stderr,
           "Returning certificate for %.*s\n",
           (int) name_len,
           name);
  *pkey = host->key;
  *pcert_length = 1;
  *pcert = &host->pcrt;
  return 0;
}

   Note that MHD cannot offer passing a closure or any other additional
information to this callback, as the GnuTLS API unfortunately does not
permit this at this point.

   The ‘hosts’ list can be initialized by loading the private keys and
X.509 certificates from disk as follows:

static void
load_keys(const char *hostname,
          const char *CERT_FILE,
          const char *KEY_FILE)
{
  int ret;
  gnutls_datum_t data;
  struct Hosts *host;

  host = malloc (sizeof (struct Hosts));
  host->hostname = hostname;
  host->next = hosts;
  hosts = host;

  ret = gnutls_load_file (CERT_FILE, &data);
  if (ret < 0)
  {
    fprintf (stderr,
             "*** Error loading certificate file %s.\n",
             CERT_FILE);
    exit(1);
  }
  ret =
    gnutls_pcert_import_x509_raw (&host->pcrt, &data, GNUTLS_X509_FMT_PEM,
                                  0);
  if (ret < 0)
  {
    fprintf(stderr,
            "*** Error loading certificate file: %s\n",
            gnutls_strerror (ret));
    exit(1);
  }
  gnutls_free (data.data);

  ret = gnutls_load_file (KEY_FILE, &data);
  if (ret < 0)
  {
    fprintf (stderr,
             "*** Error loading key file %s.\n",
             KEY_FILE);
    exit(1);
  }

  gnutls_privkey_init (&host->key);
  ret =
    gnutls_privkey_import_x509_raw (host->key,
                                    &data, GNUTLS_X509_FMT_PEM,
                                    NULL, 0);
  if (ret < 0)
  {
    fprintf (stderr,
             "*** Error loading key file: %s\n",
             gnutls_strerror (ret));
    exit(1);
  }
  gnutls_free (data.data);
}

   The code above was largely lifted from GnuTLS. You can find other
methods for initializing certificates and keys in the GnuTLS manual and
source code.


File: libmicrohttpd-tutorial.info,  Node: Upgrading connections,  Next: Bibliography,  Prev: Adding a layer of security,  Up: Top

12 Upgrading connections
************************

HTTP is a request/response protocol: the client asks, the server
answers, and the connection is either closed or reused for the next
request.  Some applications need something else entirely -- a
bidirectional byte stream that neither side has to poll for.  Rather
than opening a second connection on another port, _RFC 9110_ lets a
client ask the server to switch the already established connection over
to a different protocol.  The client sends an ordinary request carrying
an ‘Upgrade:’ header field, and if the server agrees it answers with the
status code ‘101 Switching Protocols’.  Once that response has gone out,
HTTP is over: the two sides simply talk whatever protocol they agreed on
over the same TCP connection.

   Since version 0.9.52 _libmicrohttpd_ supports this protocol switch.
The API is deliberately protocol-agnostic -- _MHD_ performs the HTTP
part of the handshake and then hands you the socket.  What you send over
that socket afterwards is entirely your business; _MHD_ neither parses
nor generates a single byte of it any more.

   The best known user of this mechanism is the Websocket protocol (_RFC
6455_), which uses the upgrade API as a means to an end and then needs a
good deal of machinery of its own for framing, masking and the closing
handshake.  This chapter takes the opposite approach: it shows the
upgrade API on its own, with a protocol so simple that no helper library
is needed.  Our server switches to a line-based echo protocol: every
line the client sends is sent straight back, until the client sends the
line ‘QUIT’.

Enabling upgrades
=================

Upgrading is not allowed by default, because handing raw sockets to
application code has consequences the library cannot control.  You opt
in with the ‘MHD_ALLOW_UPGRADE’ flag:

daemon = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION |
                           MHD_USE_INTERNAL_POLLING_THREAD |
                           MHD_ALLOW_UPGRADE |
                           MHD_USE_ERROR_LOG,
                           PORT, NULL, NULL,
                           &access_handler, NULL,
                           MHD_OPTION_END);

   The choice of threading mode matters more here than anywhere else in
this tutorial, because it decides whether your code is allowed to block.

   With ‘MHD_USE_THREAD_PER_CONNECTION’ every connection already has a
thread of its own, and that thread is the one that will run your upgrade
callback.  Blocking in it stalls exactly one client, so you may write
the straightforward loop of ‘recv()’ and ‘send()’ calls that everybody
has in their head.  This is what makes the example in this chapter short
enough to read in one go.

   Without it -- that is, with a single internal polling thread, a
thread pool, epoll, or an external event loop -- your callback runs
_inside_ _MHD_'s event loop.  Blocking there freezes every other
connection the same loop is serving.  In that case the callback must
return immediately, and you have to register the socket in your own
event loop (or hand it to a thread you started yourself) and drive the
conversation from there.

Deciding whether to upgrade
===========================

A client that wants to switch protocols says so twice: it names the
protocol in the ‘Upgrade:’ header field, and it lists the token
‘Upgrade’ in the ‘Connection:’ header field.  Both fields are
comma-separated lists, so a browser may well send ‘Connection:
keep-alive, Upgrade’.  Comparing the whole field value against the
string ‘"Upgrade"’ would reject such a request; the example therefore
contains a small helper ‘has_token()’ that walks the list.  Note also
that a protocol switch is a HTTP/1.1 feature; ‘MHD_queue_response()’
will refuse an upgrade response on a HTTP/1.0 connection.

  if ( (0 != strcmp (method, MHD_HTTP_METHOD_GET)) ||
       (0 != strcmp (version, MHD_HTTP_VERSION_1_1)) ||
       (! has_token (MHD_lookup_connection_value (connection,
                                                  MHD_HEADER_KIND,
                                                  MHD_HTTP_HEADER_CONNECTION),
                     "Upgrade")) ||
       (! has_token (MHD_lookup_connection_value (connection,
                                                  MHD_HEADER_KIND,
                                                  MHD_HTTP_HEADER_UPGRADE),
                     PROTOCOL)) )
    return answer_plain (connection,
                         MHD_HTTP_UPGRADE_REQUIRED,
                         PAGE_UPGRADE_REQUIRED,
                         1);

   Refusing is not an error condition: the client asked a question and
gets an ordinary HTTP answer.  Which answer depends on who is at fault.
If the request is malformed -- for instance an ‘Upgrade:’ field without
the matching ‘Connection:’ token -- ‘MHD_HTTP_BAD_REQUEST’ is
appropriate.  If the request is perfectly well-formed but simply does
not speak the protocol this resource requires,
‘MHD_HTTP_UPGRADE_REQUIRED’ (426) is the better answer, and it should
carry an ‘Upgrade:’ header field naming the protocol the server would
have accepted.  Our example folds both cases into a 426 for brevity.
Either way you queue a perfectly normal response and the connection
stays a HTTP connection.

Creating the upgrade response
=============================

If we do want to switch, we create a special response object with
‘MHD_create_response_for_upgrade()’.  It takes the callback that will
receive the socket and a closure pointer for it, and returns ‘NULL’ on
error.  The response has no body -- it is a header and nothing else.

  response = MHD_create_response_for_upgrade (&upgrade_handler,
                                              NULL);
  if (NULL == response)
    return MHD_NO;
  MHD_add_response_header (response,
                           MHD_HTTP_HEADER_UPGRADE,
                           PROTOCOL);
  ret = MHD_queue_response (connection,
                            MHD_HTTP_SWITCHING_PROTOCOLS,
                            response);
  MHD_destroy_response (response);
  return ret;

   Two details are easy to get wrong here.

   The first is the ‘Connection: Upgrade’ response header field, and the
surprise is that you must _not_ add it.
‘MHD_create_response_for_upgrade()’ puts it into the response itself,
and ‘MHD_queue_response()’ then verifies that it is still there and
still contains the ‘upgrade’ token before it accepts the response.
_MHD_ does merge repeated ‘Connection:’ header fields into a single
field rather than emitting two of them, but it only de-duplicates the
‘close’ token, so adding ‘Upgrade’ a second time puts ‘Connection:
Upgrade, Upgrade’ on the wire.  Clients tolerate that, but there is no
reason to send it.

   What _MHD_ does _not_ invent for you is the ‘Upgrade:’ field naming
the new protocol -- that one is yours to add, since only you know what
you are switching to.  Do not forget it: ‘MHD_queue_response()’ does not
check for it, so in a normal build the client simply receives a 101 that
fails to say what it switched to, while a library built with assertions
enabled aborts when it performs the switch.

   The second is the status code.  ‘MHD_queue_response()’ rejects an
upgrade response with any status other than
‘MHD_HTTP_SWITCHING_PROTOCOLS’, and conversely it rejects status 101
combined with a response that is not an upgrade response.  On any of
these mistakes it returns ‘MHD_NO’ and, with ‘MHD_USE_ERROR_LOG’
enabled, explains itself on ‘stderr’; this is by far the quickest way to
debug a handshake that does not happen.

   The response object itself follows the usual rules.
‘MHD_queue_response()’ takes its own reference, so calling
‘MHD_destroy_response()’ immediately afterwards is correct and is what
all the other examples in this tutorial do.  The object is only really
freed once the last connection using it is done with it, which for an
upgrade means after the callback has returned.  As with any other
response you may build one upgrade response and queue it for many
connections; the callback is then simply invoked once per connection.

The upgrade callback
====================

After the 101 response has been written to the socket, _MHD_ calls the
‘MHD_UpgradeHandler’ you registered:

static void
upgrade_handler (void *cls,
                 struct MHD_Connection *connection,
                 void *req_cls,
                 const char *extra_in,
                 size_t extra_in_size,
                 MHD_socket sock,
                 struct MHD_UpgradeResponseHandle *urh)

‘cls’
     The closure that was passed to ‘MHD_create_response_for_upgrade()’.
     Since the same response object may serve many connections, this is
     per-_response_ state, not per-connection state.

‘connection’
     The original HTTP connection.  It is handed over so that you can
     have a last look at the request -- ‘MHD_lookup_connection_value()’
     still works here, which is how a real protocol picks up, say, a
     subprotocol name or an authentication token.  Do not queue anything
     on it any more.

‘req_cls’
     Whatever your access handler left in ‘*req_cls’.  This is the
     natural place to put per-connection state that the access handler
     already computed.

‘extra_in / extra_in_size’
     Bytes of your new protocol that the client sent immediately behind
     the request header, and that _MHD_ therefore already read off the
     socket while parsing the request.  They are _gone_ from the socket:
     if you go straight to ‘recv()’ you silently lose them.  Process
     this buffer first, exactly as if you had read it yourself.  The
     buffer belongs to _MHD_ and is only valid for the duration of the
     call, so copy anything you want to keep.  A client that waits for
     the 101 before it starts talking will produce ‘extra_in_size == 0’,
     which is why this argument is so easy to overlook and so annoying
     when it finally bites.

‘sock’
     The socket.  For a plain HTTP connection this is the connection to
     the client; for HTTPS it is one end of a socketpair with _MHD_
     relaying the TLS traffic, so socket options and ‘getpeername()’
     will not give you what you expect.  Read and write it as you
     please, and you may call ‘shutdown()’ on it, but you must never
     call ‘close()’.

‘urh’
     The handle for ‘MHD_upgrade_action()’, described below.

   The loop itself is then unremarkable, apart from consuming ‘extra_in’
before the first ‘recv()’:

  make_blocking (sock);
  es.line_len = 0;
  done = echo_feed (sock, &es, extra_in, extra_in_size);
  while (0 == done)
  {
    got = recv (sock, buf, sizeof (buf), 0);
    if (0 > got)
    {
      if (EINTR == errno)
        continue;
      break;                    /* read error */
    }
    if (0 == got)
      break;                    /* client closed the connection */
    done = echo_feed (sock, &es, buf, (size_t) got);
  }
  MHD_upgrade_action (urh,
                      MHD_UPGRADE_ACTION_CLOSE);

Blocking or not blocking
========================

The call to ‘make_blocking()’ deserves a warning, because the current
behaviour is the opposite of what the threading modes suggest.  _MHD_
puts every accepted client socket into non-blocking mode, and it does so
regardless of the threading mode -- in fact the library refuses to
perform the switch at all, logging ‘Cannot execute "upgrade" as the
socket is in the blocking mode’, if it finds the socket blocking.  So
even under ‘MHD_USE_THREAD_PER_CONNECTION’, where you are perfectly
entitled to block, the socket you are handed is non-blocking and a
‘recv()’ on an idle connection returns ‘-1’ with ‘EAGAIN’ instead of
waiting.

   If you want the simple blocking loop shown above, you therefore have
to ask for it.  The example does so with a small ‘make_blocking()’
helper -- ‘fcntl()’ clearing ‘O_NONBLOCK’ on POSIX systems,
‘ioctlsocket()’ on W32 -- which is the only operating-system-dependent
code in the whole program.

   Under any other threading mode you leave the socket alone, keep it
non-blocking, and add it to your own event loop instead.

Closing the connection
======================

The last obligation of the callback is to hand the socket back:

  MHD_upgrade_action (urh,
                      MHD_UPGRADE_ACTION_CLOSE);

   This is not a formality.  An upgraded connection is put into an
internal "suspended" state, and it stays there -- socket open,
connection structure allocated, slot counted against the connection
limit -- until the application says it is done.  Only
‘MHD_UPGRADE_ACTION_CLOSE’ says that.  Calling ‘close()’ on the socket
yourself does not, and additionally leaves _MHD_ holding a file
descriptor number that the operating system may already have handed to
somebody else.  Call the action exactly once, on every path out of the
callback, including the error paths.

   ‘MHD_upgrade_action()’ takes two further actions in the current
release, ‘MHD_UPGRADE_ACTION_CORK_ON’ and ‘MHD_UPGRADE_ACTION_CORK_OFF’.
They switch ‘TCP_CORK’ (or ‘TCP_NOPUSH’) on the underlying socket so
that several small writes can be coalesced into a single segment.  They
are a hint, not a guarantee: the call returns ‘MHD_NO’ if the platform
has no such option or if the socket is not a TCP socket, which is the
normal case for HTTPS connections.  The header file marks this part of
the API as not yet finalised, so do not build anything load-bearing on
it.

Remarks
=======

‘MHD_stop_daemon()’ does _not_ interrupt an upgraded connection.  It
marks the connection as closed internally and logs ‘Initiated daemon
shutdown while "upgraded" connection was not closed’, but it neither
shuts down nor closes the socket -- and then it waits for the
connection's thread, which means it blocks until your callback has
returned.  A callback parked in a blocking ‘recv()’ therefore hangs the
shutdown for as long as the client keeps the connection open.  Any
server that wants to terminate on demand needs its own way out of that
loop: a global shutdown flag combined with a ‘shutdown()’ on the sockets
you are holding, a self-pipe added to a ‘select()’ in the loop, or a
receive timeout on the socket.  Our example sidesteps the problem by
only stopping the daemon when the user presses return at a moment when
nothing is connected.

   Error handling in the callback is entirely yours.  _MHD_ will not
tell you that a client vanished and will not time an upgraded connection
out -- ‘MHD_OPTION_CONNECTION_TIMEOUT’ stops applying the moment the
connection is upgraded.  Treat ‘0’ from ‘recv()’ as a clean disconnect
and a negative return as a broken one, and remember that a peer which
disappears without a FIN produces neither until the TCP stack gives up,
which can take a very long time.  Whatever happens, end by calling
‘MHD_upgrade_action()’ with ‘MHD_UPGRADE_ACTION_CLOSE’.

   Finally, keep in mind that an upgraded connection is a connection
that _MHD_ can no longer recycle, and that intermediaries are entitled
to be unhelpful: ‘Upgrade:’ is listed in ‘Connection:’ and is therefore
a hop-by-hop header field.  A proxy that does not understand your
protocol is allowed to drop it, in which case your server never sees an
upgrade request at all and the client gets an ordinary HTTP response
where it expected a 101.  This is the main reason why deployed protocols
on top of this mechanism -- Websockets above all -- make the handshake
verifiable by both ends instead of trusting that the request arrived
intact.

   The complete program is available as ‘upgrade.c’ in the ‘examples’
section.  Start it and talk to it with any tool that lets you type raw
bytes at a socket -- ‘telnet localhost 8888’ will do -- by sending

GET / HTTP/1.1
Host: localhost
Connection: Upgrade
Upgrade: echo


   followed by an empty line.  The server answers with

HTTP/1.1 101 Switching Protocols
Date: ...
Connection: Upgrade
Upgrade: echo


   and from then on echoes every line back until you type ‘QUIT’.  Note
the absence of a ‘Content-Length:’ field: a 101 response has no body,
and everything after the empty line already belongs to the new protocol.

   For a real-world protocol built on exactly this API, read _RFC 6455_
and note how much of it exists only to make the handshake and the
framing verifiable -- none of which the upgrade API itself has an
opinion about.

Exercises
=========

   • Point a browser at the server.  The browser sends a plain ‘GET /’
     and receives the ‘426’ page.  Now add a second resource that serves
     a small HTML page and switch the upgrade to a different URL, so
     that the same server can be both browsed and upgraded.

   • Make the echo server useful: keep a list of the sockets of all
     upgraded connections and forward every line one client sends to all
     the others, turning the example into a minimal chat server.  You
     will need a mutex around the list, and you will discover why the
     closing rules matter -- a socket must leave the list before its
     callback returns.

   • Fix the shutdown behaviour discussed in the remarks.  Add a global
     "quitting" flag and a list of active sockets, have ‘main()’ set the
     flag and call ‘shutdown (sock, SHUT_RDWR)’ on every entry before it
     calls ‘MHD_stop_daemon()’, and verify that the daemon now stops
     even while a client is connected and silent.

   • Change the daemon flags to plain ‘MHD_USE_INTERNAL_POLLING_THREAD’
     without ‘MHD_USE_THREAD_PER_CONNECTION’ and observe that the server
     now serves exactly one upgraded client and stops answering
     everybody else.  Then repair it: leave the socket non-blocking,
     start a thread from within the callback, and return immediately.

   • Have the client send a line longer than ‘LINE_SIZE’.  The example
     silently drops the excess.  What should a real protocol do instead,
     and which status code would you have used if the problem had been
     detectable during the handshake?


File: libmicrohttpd-tutorial.info,  Node: Bibliography,  Next: License text,  Prev: Upgrading connections,  Up: Top

Appendix A Bibliography
***********************

API reference
=============

   • The _GNU libmicrohttpd_ manual by Marco Maggi and Christian
     Grothoff
     <https://www.gnu.org/software/libmicrohttpd/manual/libmicrohttpd.html>

   • All referenced RFCs can be found on the website of _The Internet
     Engineering Task Force_ <https://www.ietf.org/>

   • _RFC 2616_: Fielding, R., Gettys, J., Mogul, J., Frystyk, H.,
     Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext Transfer
     Protocol - HTTP/1.1", RFC 2616, June 1999.

   • _RFC 2617_: Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence,
     S., Leach, P., Luotonen, A., and L. Stewart, "HTTP Authentication:
     Basic and Digest Access Authentication", RFC 2617, June 1999.

   • _RFC 6455_: Fette, I., Melnikov, A., "The WebSocket Protocol", RFC
     6455, December 2011.

   • A well-structured _HTML_ reference can be found on
     <http://www.echoecho.com/html.htm>

     For those readers understanding German, there is an excellent
     document both for learning _HTML_ and for reference, whose English
     and French versions unfortunately have been discontinued.
     <https://wiki.selfhtml.org/>


File: libmicrohttpd-tutorial.info,  Node: License text,  Next: Example programs,  Prev: Bibliography,  Up: Top

Appendix B GNU Free Documentation License
*****************************************

                     Version 1.3, 3 November 2008

     Copyright © 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
     <http://fsf.org/>

     Everyone is permitted to copy and distribute verbatim copies
     of this license document, but changing it is not allowed.

  0. PREAMBLE

     The purpose of this License is to make a manual, textbook, or other
     functional and useful document “free” in the sense of freedom: to
     assure everyone the effective freedom to copy and redistribute it,
     with or without modifying it, either commercially or
     noncommercially.  Secondarily, this License preserves for the
     author and publisher a way to get credit for their work, while not
     being considered responsible for modifications made by others.

     This License is a kind of "copyleft", which means that derivative
     works of the document must themselves be free in the same sense.
     It complements the GNU General Public License, which is a copyleft
     license designed for free software.

     We have designed this License in order to use it for manuals for
     free software, because free software needs free documentation: a
     free program should come with manuals providing the same freedoms
     that the software does.  But this License is not limited to
     software manuals; it can be used for any textual work, regardless
     of subject matter or whether it is published as a printed book.  We
     recommend this License principally for works whose purpose is
     instruction or reference.

  1. APPLICABILITY AND DEFINITIONS

     This License applies to any manual or other work, in any medium,
     that contains a notice placed by the copyright holder saying it can
     be distributed under the terms of this License.  Such a notice
     grants a world-wide, royalty-free license, unlimited in duration,
     to use that work under the conditions stated herein.  The
     "Document", below, refers to any such manual or work.  Any member
     of the public is a licensee, and is addressed as "you".  You accept
     the license if you copy, modify or distribute the work in a way
     requiring permission under copyright law.

     A "Modified Version" of the Document means any work containing the
     Document or a portion of it, either copied verbatim, or with
     modifications and/or translated into another language.

     A "Secondary Section" is a named appendix or a front-matter section
     of the Document that deals exclusively with the relationship of the
     publishers or authors of the Document to the Document's overall
     subject (or to related matters) and contains nothing that could
     fall directly within that overall subject.  (Thus, if the Document
     is in part a textbook of mathematics, a Secondary Section may not
     explain any mathematics.)  The relationship could be a matter of
     historical connection with the subject or with related matters, or
     of legal, commercial, philosophical, ethical or political position
     regarding them.

     The "Invariant Sections" are certain Secondary Sections whose
     titles are designated, as being those of Invariant Sections, in the
     notice that says that the Document is released under this License.
     If a section does not fit the above definition of Secondary then it
     is not allowed to be designated as Invariant.  The Document may
     contain zero Invariant Sections.  If the Document does not identify
     any Invariant Sections then there are none.

     The "Cover Texts" are certain short passages of text that are
     listed, as Front-Cover Texts or Back-Cover Texts, in the notice
     that says that the Document is released under this License.  A
     Front-Cover Text may be at most 5 words, and a Back-Cover Text may
     be at most 25 words.

     A "Transparent" copy of the Document means a machine-readable copy,
     represented in a format whose specification is available to the
     general public, that is suitable for revising the document
     straightforwardly with generic text editors or (for images composed
     of pixels) generic paint programs or (for drawings) some widely
     available drawing editor, and that is suitable for input to text
     formatters or for automatic translation to a variety of formats
     suitable for input to text formatters.  A copy made in an otherwise
     Transparent file format whose markup, or absence of markup, has
     been arranged to thwart or discourage subsequent modification by
     readers is not Transparent.  An image format is not Transparent if
     used for any substantial amount of text.  A copy that is not
     "Transparent" is called "Opaque".

     Examples of suitable formats for Transparent copies include plain
     ASCII without markup, Texinfo input format, LaTeX input format,
     SGML or XML using a publicly available DTD, and standard-conforming
     simple HTML, PostScript or PDF designed for human modification.
     Examples of transparent image formats include PNG, XCF and JPG.
     Opaque formats include proprietary formats that can be read and
     edited only by proprietary word processors, SGML or XML for which
     the DTD and/or processing tools are not generally available, and
     the machine-generated HTML, PostScript or PDF produced by some word
     processors for output purposes only.

     The "Title Page" means, for a printed book, the title page itself,
     plus such following pages as are needed to hold, legibly, the
     material this License requires to appear in the title page.  For
     works in formats which do not have any title page as such, "Title
     Page" means the text near the most prominent appearance of the
     work's title, preceding the beginning of the body of the text.

     The "publisher" means any person or entity that distributes copies
     of the Document to the public.

     A section "Entitled XYZ" means a named subunit of the Document
     whose title either is precisely XYZ or contains XYZ in parentheses
     following text that translates XYZ in another language.  (Here XYZ
     stands for a specific section name mentioned below, such as
     "Acknowledgements", "Dedications", "Endorsements", or "History".)
     To "Preserve the Title" of such a section when you modify the
     Document means that it remains a section "Entitled XYZ" according
     to this definition.

     The Document may include Warranty Disclaimers next to the notice
     which states that this License applies to the Document.  These
     Warranty Disclaimers are considered to be included by reference in
     this License, but only as regards disclaiming warranties: any other
     implication that these Warranty Disclaimers may have is void and
     has no effect on the meaning of this License.

  2. VERBATIM COPYING

     You may copy and distribute the Document in any medium, either
     commercially or noncommercially, provided that this License, the
     copyright notices, and the license notice saying this License
     applies to the Document are reproduced in all copies, and that you
     add no other conditions whatsoever to those of this License.  You
     may not use technical measures to obstruct or control the reading
     or further copying of the copies you make or distribute.  However,
     you may accept compensation in exchange for copies.  If you
     distribute a large enough number of copies you must also follow the
     conditions in section 3.

     You may also lend copies, under the same conditions stated above,
     and you may publicly display copies.

  3. COPYING IN QUANTITY

     If you publish printed copies (or copies in media that commonly
     have printed covers) of the Document, numbering more than 100, and
     the Document's license notice requires Cover Texts, you must
     enclose the copies in covers that carry, clearly and legibly, all
     these Cover Texts: Front-Cover Texts on the front cover, and
     Back-Cover Texts on the back cover.  Both covers must also clearly
     and legibly identify you as the publisher of these copies.  The
     front cover must present the full title with all words of the title
     equally prominent and visible.  You may add other material on the
     covers in addition.  Copying with changes limited to the covers, as
     long as they preserve the title of the Document and satisfy these
     conditions, can be treated as verbatim copying in other respects.

     If the required texts for either cover are too voluminous to fit
     legibly, you should put the first ones listed (as many as fit
     reasonably) on the actual cover, and continue the rest onto
     adjacent pages.

     If you publish or distribute Opaque copies of the Document
     numbering more than 100, you must either include a machine-readable
     Transparent copy along with each Opaque copy, or state in or with
     each Opaque copy a computer-network location from which the general
     network-using public has access to download using public-standard
     network protocols a complete Transparent copy of the Document, free
     of added material.  If you use the latter option, you must take
     reasonably prudent steps, when you begin distribution of Opaque
     copies in quantity, to ensure that this Transparent copy will
     remain thus accessible at the stated location until at least one
     year after the last time you distribute an Opaque copy (directly or
     through your agents or retailers) of that edition to the public.

     It is requested, but not required, that you contact the authors of
     the Document well before redistributing any large number of copies,
     to give them a chance to provide you with an updated version of the
     Document.

  4. MODIFICATIONS

     You may copy and distribute a Modified Version of the Document
     under the conditions of sections 2 and 3 above, provided that you
     release the Modified Version under precisely this License, with the
     Modified Version filling the role of the Document, thus licensing
     distribution and modification of the Modified Version to whoever
     possesses a copy of it.  In addition, you must do these things in
     the Modified Version:

       A. Use in the Title Page (and on the covers, if any) a title
          distinct from that of the Document, and from those of previous
          versions (which should, if there were any, be listed in the
          History section of the Document).  You may use the same title
          as a previous version if the original publisher of that
          version gives permission.

       B. List on the Title Page, as authors, one or more persons or
          entities responsible for authorship of the modifications in
          the Modified Version, together with at least five of the
          principal authors of the Document (all of its principal
          authors, if it has fewer than five), unless they release you
          from this requirement.

       C. State on the Title page the name of the publisher of the
          Modified Version, as the publisher.

       D. Preserve all the copyright notices of the Document.

       E. Add an appropriate copyright notice for your modifications
          adjacent to the other copyright notices.

       F. Include, immediately after the copyright notices, a license
          notice giving the public permission to use the Modified
          Version under the terms of this License, in the form shown in
          the Addendum below.

       G. Preserve in that license notice the full lists of Invariant
          Sections and required Cover Texts given in the Document's
          license notice.

       H. Include an unaltered copy of this License.

       I. Preserve the section Entitled "History", Preserve its Title,
          and add to it an item stating at least the title, year, new
          authors, and publisher of the Modified Version as given on the
          Title Page.  If there is no section Entitled "History" in the
          Document, create one stating the title, year, authors, and
          publisher of the Document as given on its Title Page, then add
          an item describing the Modified Version as stated in the
          previous sentence.

       J. Preserve the network location, if any, given in the Document
          for public access to a Transparent copy of the Document, and
          likewise the network locations given in the Document for
          previous versions it was based on.  These may be placed in the
          "History" section.  You may omit a network location for a work
          that was published at least four years before the Document
          itself, or if the original publisher of the version it refers
          to gives permission.

       K. For any section Entitled "Acknowledgements" or "Dedications",
          Preserve the Title of the section, and preserve in the section
          all the substance and tone of each of the contributor
          acknowledgements and/or dedications given therein.

       L. Preserve all the Invariant Sections of the Document, unaltered
          in their text and in their titles.  Section numbers or the
          equivalent are not considered part of the section titles.

       M. Delete any section Entitled "Endorsements".  Such a section
          may not be included in the Modified Version.

       N. Do not retitle any existing section to be Entitled
          "Endorsements" or to conflict in title with any Invariant
          Section.

       O. Preserve any Warranty Disclaimers.

     If the Modified Version includes new front-matter sections or
     appendices that qualify as Secondary Sections and contain no
     material copied from the Document, you may at your option designate
     some or all of these sections as invariant.  To do this, add their
     titles to the list of Invariant Sections in the Modified Version's
     license notice.  These titles must be distinct from any other
     section titles.

     You may add a section Entitled "Endorsements", provided it contains
     nothing but endorsements of your Modified Version by various
     parties--for example, statements of peer review or that the text
     has been approved by an organization as the authoritative
     definition of a standard.

     You may add a passage of up to five words as a Front-Cover Text,
     and a passage of up to 25 words as a Back-Cover Text, to the end of
     the list of Cover Texts in the Modified Version.  Only one passage
     of Front-Cover Text and one of Back-Cover Text may be added by (or
     through arrangements made by) any one entity.  If the Document
     already includes a cover text for the same cover, previously added
     by you or by arrangement made by the same entity you are acting on
     behalf of, you may not add another; but you may replace the old
     one, on explicit permission from the previous publisher that added
     the old one.

     The author(s) and publisher(s) of the Document do not by this
     License give permission to use their names for publicity for or to
     assert or imply endorsement of any Modified Version.

  5. COMBINING DOCUMENTS

     You may combine the Document with other documents released under
     this License, under the terms defined in section 4 above for
     modified versions, provided that you include in the combination all
     of the Invariant Sections of all of the original documents,
     unmodified, and list them all as Invariant Sections of your
     combined work in its license notice, and that you preserve all
     their Warranty Disclaimers.

     The combined work need only contain one copy of this License, and
     multiple identical Invariant Sections may be replaced with a single
     copy.  If there are multiple Invariant Sections with the same name
     but different contents, make the title of each such section unique
     by adding at the end of it, in parentheses, the name of the
     original author or publisher of that section if known, or else a
     unique number.  Make the same adjustment to the section titles in
     the list of Invariant Sections in the license notice of the
     combined work.

     In the combination, you must combine any sections Entitled
     "History" in the various original documents, forming one section
     Entitled "History"; likewise combine any sections Entitled
     "Acknowledgements", and any sections Entitled "Dedications".  You
     must delete all sections Entitled "Endorsements."

  6. COLLECTIONS OF DOCUMENTS

     You may make a collection consisting of the Document and other
     documents released under this License, and replace the individual
     copies of this License in the various documents with a single copy
     that is included in the collection, provided that you follow the
     rules of this License for verbatim copying of each of the documents
     in all other respects.

     You may extract a single document from such a collection, and
     distribute it individually under this License, provided you insert
     a copy of this License into the extracted document, and follow this
     License in all other respects regarding verbatim copying of that
     document.

  7. AGGREGATION WITH INDEPENDENT WORKS

     A compilation of the Document or its derivatives with other
     separate and independent documents or works, in or on a volume of a
     storage or distribution medium, is called an "aggregate" if the
     copyright resulting from the compilation is not used to limit the
     legal rights of the compilation's users beyond what the individual
     works permit.  When the Document is included in an aggregate, this
     License does not apply to the other works in the aggregate which
     are not themselves derivative works of the Document.

     If the Cover Text requirement of section 3 is applicable to these
     copies of the Document, then if the Document is less than one half
     of the entire aggregate, the Document's Cover Texts may be placed
     on covers that bracket the Document within the aggregate, or the
     electronic equivalent of covers if the Document is in electronic
     form.  Otherwise they must appear on printed covers that bracket
     the whole aggregate.

  8. TRANSLATION

     Translation is considered a kind of modification, so you may
     distribute translations of the Document under the terms of section
     4.  Replacing Invariant Sections with translations requires special
     permission from their copyright holders, but you may include
     translations of some or all Invariant Sections in addition to the
     original versions of these Invariant Sections.  You may include a
     translation of this License, and all the license notices in the
     Document, and any Warranty Disclaimers, provided that you also
     include the original English version of this License and the
     original versions of those notices and disclaimers.  In case of a
     disagreement between the translation and the original version of
     this License or a notice or disclaimer, the original version will
     prevail.

     If a section in the Document is Entitled "Acknowledgements",
     "Dedications", or "History", the requirement (section 4) to
     Preserve its Title (section 1) will typically require changing the
     actual title.

  9. TERMINATION

     You may not copy, modify, sublicense, or distribute the Document
     except as expressly provided under this License.  Any attempt
     otherwise to copy, modify, sublicense, or distribute it is void,
     and will automatically terminate your rights under this License.

     However, if you cease all violation of this License, then your
     license from a particular copyright holder is reinstated (a)
     provisionally, unless and until the copyright holder explicitly and
     finally terminates your license, and (b) permanently, if the
     copyright holder fails to notify you of the violation by some
     reasonable means prior to 60 days after the cessation.

     Moreover, your license from a particular copyright holder is
     reinstated permanently if the copyright holder notifies you of the
     violation by some reasonable means, this is the first time you have
     received notice of violation of this License (for any work) from
     that copyright holder, and you cure the violation prior to 30 days
     after your receipt of the notice.

     Termination of your rights under this section does not terminate
     the licenses of parties who have received copies or rights from you
     under this License.  If your rights have been terminated and not
     permanently reinstated, receipt of a copy of some or all of the
     same material does not give you any rights to use it.

  10. FUTURE REVISIONS OF THIS LICENSE

     The Free Software Foundation may publish new, revised versions of
     the GNU Free Documentation License from time to time.  Such new
     versions will be similar in spirit to the present version, but may
     differ in detail to address new problems or concerns.  See
     <http://www.gnu.org/copyleft/>.

     Each version of the License is given a distinguishing version
     number.  If the Document specifies that a particular numbered
     version of this License "or any later version" applies to it, you
     have the option of following the terms and conditions either of
     that specified version or of any later version that has been
     published (not as a draft) by the Free Software Foundation.  If the
     Document does not specify a version number of this License, you may
     choose any version ever published (not as a draft) by the Free
     Software Foundation.  If the Document specifies that a proxy can
     decide which future versions of this License can be used, that
     proxy's public statement of acceptance of a version permanently
     authorizes you to choose that version for the Document.

  11. RELICENSING

     "Massive Multiauthor Collaboration Site" (or "MMC Site") means any
     World Wide Web server that publishes copyrightable works and also
     provides prominent facilities for anybody to edit those works.  A
     public wiki that anybody can edit is an example of such a server.
     A "Massive Multiauthor Collaboration" (or "MMC") contained in the
     site means any set of copyrightable works thus published on the MMC
     site.

     "CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0
     license published by Creative Commons Corporation, a not-for-profit
     corporation with a principal place of business in San Francisco,
     California, as well as future copyleft versions of that license
     published by that same organization.

     "Incorporate" means to publish or republish a Document, in whole or
     in part, as part of another Document.

     An MMC is "eligible for relicensing" if it is licensed under this
     License, and if all works that were first published under this
     License somewhere other than this MMC, and subsequently
     incorporated in whole or in part into the MMC, (1) had no cover
     texts or invariant sections, and (2) were thus incorporated prior
     to November 1, 2008.

     The operator of an MMC Site may republish an MMC contained in the
     site under CC-BY-SA on the same site at any time before August 1,
     2009, provided the MMC is eligible for relicensing.

ADDENDUM: How to use this License for your documents
====================================================

To use this License in a document you have written, include a copy of
the License in the document and put the following copyright and license
notices just after the title page:

       Copyright (C)  YEAR  YOUR NAME.
       Permission is granted to copy, distribute and/or modify this document
       under the terms of the GNU Free Documentation License, Version 1.3
       or any later version published by the Free Software Foundation;
       with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
       Texts.  A copy of the license is included in the section entitled ``GNU
       Free Documentation License''.

   If you have Invariant Sections, Front-Cover Texts and Back-Cover
Texts, replace the "with...Texts."  line with this:

         with the Invariant Sections being LIST THEIR TITLES, with
         the Front-Cover Texts being LIST, and with the Back-Cover Texts
         being LIST.

   If you have Invariant Sections without Cover Texts, or some other
combination of the three, merge those two alternatives to suit the
situation.

   If your document contains nontrivial examples of program code, we
recommend releasing these examples in parallel under your choice of free
software license, such as the GNU General Public License, to permit
their use in free software.


File: libmicrohttpd-tutorial.info,  Node: Example programs,  Prev: License text,  Up: Top

Appendix C Example programs
***************************

* Menu:

* hellobrowser.c::
* logging.c::
* responseheaders.c::
* basicauthentication.c::
* simplepost.c::
* largepost.c::
* sessions.c::
* callbackresponse.c::
* asyncresponse.c::
* tlsauthentication.c::
* upgrade.c::


File: libmicrohttpd-tutorial.info,  Node: hellobrowser.c,  Next: logging.c,  Up: Example programs

C.1 hellobrowser.c
==================

     /* Feel free to use this example code in any way
        you see fit (Public Domain) */
     
     #include <sys/types.h>
     #ifndef _WIN32
     #include <sys/select.h>
     #include <sys/socket.h>
     #else
     #include <winsock2.h>
     #endif
     #include <string.h>
     #include <microhttpd.h>
     #include <stdio.h>
     
     #define PORT 8888
     
     static enum MHD_Result
     answer_to_connection (void *cls, struct MHD_Connection *connection,
                           const char *url, const char *method,
                           const char *version, const char *upload_data,
                           size_t *upload_data_size, void **req_cls)
     {
       const char *page = "<html><body>Hello, browser!</body></html>";
       struct MHD_Response *response;
       enum MHD_Result ret;
       (void) cls;               /* Unused. Silent compiler warning. */
       (void) url;               /* Unused. Silent compiler warning. */
       (void) method;            /* Unused. Silent compiler warning. */
       (void) version;           /* Unused. Silent compiler warning. */
       (void) upload_data;       /* Unused. Silent compiler warning. */
       (void) upload_data_size;  /* Unused. Silent compiler warning. */
       (void) req_cls;           /* Unused. Silent compiler warning. */
     
       response = MHD_create_response_from_buffer_static (strlen (page), page);
       ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
       MHD_destroy_response (response);
     
       return ret;
     }
     
     
     int
     main (void)
     {
       struct MHD_Daemon *daemon;
     
       daemon = MHD_start_daemon (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD,
                                  PORT, NULL, NULL,
                                  &answer_to_connection, NULL, MHD_OPTION_END);
       if (NULL == daemon)
         return 1;
     
       (void) getchar ();
     
       MHD_stop_daemon (daemon);
       return 0;
     }


File: libmicrohttpd-tutorial.info,  Node: logging.c,  Next: responseheaders.c,  Prev: hellobrowser.c,  Up: Example programs

C.2 logging.c
=============

     /* Feel free to use this example code in any way
        you see fit (Public Domain) */
     
     #include <sys/types.h>
     #ifndef _WIN32
     #include <sys/select.h>
     #include <sys/socket.h>
     #else
     #include <winsock2.h>
     #endif
     #include <microhttpd.h>
     #include <stdio.h>
     
     #define PORT 8888
     
     
     static enum MHD_Result
     print_out_key (void *cls, enum MHD_ValueKind kind, const char *key,
                    const char *value)
     {
       (void) cls;    /* Unused. Silent compiler warning. */
       (void) kind;   /* Unused. Silent compiler warning. */
       printf ("%s: %s\n", key, value);
       return MHD_YES;
     }
     
     
     static enum MHD_Result
     answer_to_connection (void *cls, struct MHD_Connection *connection,
                           const char *url, const char *method,
                           const char *version, const char *upload_data,
                           size_t *upload_data_size, void **req_cls)
     {
       (void) cls;               /* Unused. Silent compiler warning. */
       (void) version;           /* Unused. Silent compiler warning. */
       (void) upload_data;       /* Unused. Silent compiler warning. */
       (void) upload_data_size;  /* Unused. Silent compiler warning. */
       (void) req_cls;           /* Unused. Silent compiler warning. */
       printf ("New %s request for %s using version %s\n", method, url, version);
     
       MHD_get_connection_values (connection, MHD_HEADER_KIND, print_out_key,
                                  NULL);
     
       return MHD_NO;
     }
     
     
     int
     main (void)
     {
       struct MHD_Daemon *daemon;
     
       daemon = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD, PORT, NULL, NULL,
                                  &answer_to_connection, NULL, MHD_OPTION_END);
       if (NULL == daemon)
         return 1;
     
       (void) getchar ();
     
       MHD_stop_daemon (daemon);
       return 0;
     }


File: libmicrohttpd-tutorial.info,  Node: responseheaders.c,  Next: basicauthentication.c,  Prev: logging.c,  Up: Example programs

C.3 responseheaders.c
=====================

     /* Feel free to use this example code in any way
        you see fit (Public Domain) */
     
     #include <sys/types.h>
     #ifndef _WIN32
     #include <sys/select.h>
     #include <sys/socket.h>
     #else
     #include <winsock2.h>
     #endif
     #include <microhttpd.h>
     #include <time.h>
     #include <sys/stat.h>
     #include <fcntl.h>
     #include <string.h>
     #include <stdio.h>
     
     #define PORT 8888
     #define FILENAME "picture.png"
     #define MIMETYPE "image/png"
     
     static enum MHD_Result
     answer_to_connection (void *cls, struct MHD_Connection *connection,
                           const char *url, const char *method,
                           const char *version, const char *upload_data,
                           size_t *upload_data_size, void **req_cls)
     {
       struct MHD_Response *response;
       int fd;
       enum MHD_Result ret;
       struct stat sbuf;
       (void) cls;               /* Unused. Silent compiler warning. */
       (void) url;               /* Unused. Silent compiler warning. */
       (void) version;           /* Unused. Silent compiler warning. */
       (void) upload_data;       /* Unused. Silent compiler warning. */
       (void) upload_data_size;  /* Unused. Silent compiler warning. */
       (void) req_cls;           /* Unused. Silent compiler warning. */
     
       if (0 != strcmp (method, "GET"))
         return MHD_NO;
     
       if ( (-1 == (fd = open (FILENAME, O_RDONLY))) ||
            (0 != fstat (fd, &sbuf)) )
       {
         const char *errorstr =
           "<html><body>An internal server error has occurred!\
                                   </body></html>";
         /* error accessing file */
         if (fd != -1)
           (void) close (fd);
         response =
           MHD_create_response_from_buffer_static (strlen (errorstr), errorstr);
         if (NULL != response)
         {
           ret =
             MHD_queue_response (connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
                                 response);
           MHD_destroy_response (response);
     
           return ret;
         }
         else
           return MHD_NO;
       }
       response =
         MHD_create_response_from_fd_at_offset64 ((uint64_t) sbuf.st_size,
                                                  fd,
                                                  0);
       if (MHD_YES !=
           MHD_add_response_header (response,
                                    MHD_HTTP_HEADER_CONTENT_TYPE,
                                    MIMETYPE))
       {
         fprintf (stderr,
                  "Failed to set content type header!\n");
         /* return response without content encoding anyway ... */
       }
       ret = MHD_queue_response (connection,
                                 MHD_HTTP_OK,
                                 response);
       MHD_destroy_response (response);
     
       return ret;
     }
     
     
     int
     main (void)
     {
       struct MHD_Daemon *daemon;
     
       daemon = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD, PORT, NULL, NULL,
                                  &answer_to_connection, NULL, MHD_OPTION_END);
       if (NULL == daemon)
         return 1;
     
       (void) getchar ();
     
       MHD_stop_daemon (daemon);
     
       return 0;
     }


File: libmicrohttpd-tutorial.info,  Node: basicauthentication.c,  Next: simplepost.c,  Prev: responseheaders.c,  Up: Example programs

C.4 basicauthentication.c
=========================

     /* Feel free to use this example code in any way
        you see fit (Public Domain) */
     
     #include <sys/types.h>
     #ifndef _WIN32
     #include <sys/select.h>
     #include <sys/socket.h>
     #else
     #include <winsock2.h>
     #endif
     #include <microhttpd.h>
     #include <time.h>
     #include <string.h>
     #include <stdlib.h>
     #include <stdio.h>
     
     #define PORT 8888
     
     
     static enum MHD_Result
     answer_to_connection (void *cls, struct MHD_Connection *connection,
                           const char *url, const char *method,
                           const char *version, const char *upload_data,
                           size_t *upload_data_size, void **req_cls)
     {
       struct MHD_BasicAuthInfo *auth_info;
       enum MHD_Result ret;
       struct MHD_Response *response;
       (void) cls;               /* Unused. Silent compiler warning. */
       (void) url;               /* Unused. Silent compiler warning. */
       (void) version;           /* Unused. Silent compiler warning. */
       (void) upload_data;       /* Unused. Silent compiler warning. */
       (void) upload_data_size;  /* Unused. Silent compiler warning. */
     
       if (0 != strcmp (method, "GET"))
         return MHD_NO;
       if (NULL == *req_cls)
       {
         *req_cls = connection;
         return MHD_YES;
       }
       auth_info = MHD_basic_auth_get_username_password3 (connection);
       if (NULL == auth_info)
       {
         static const char *page =
           "<html><body>Authorization required</body></html>";
         response = MHD_create_response_from_buffer_static (strlen (page), page);
         ret = MHD_queue_basic_auth_required_response3 (connection,
                                                        "admins",
                                                        MHD_YES,
                                                        response);
       }
       else if ((strlen ("root") != auth_info->username_len) ||
                (0 != memcmp (auth_info->username, "root",
                              auth_info->username_len)) ||
                /* The next check against NULL is optional,
                 * if 'password' is NULL then 'password_len' is always zero. */
                (NULL == auth_info->password) ||
                (strlen ("pa$$w0rd") != auth_info->password_len) ||
                (0 != memcmp (auth_info->password, "pa$$w0rd",
                              auth_info->password_len)))
       {
         static const char *page =
           "<html><body>Wrong username or password</body></html>";
         response = MHD_create_response_from_buffer_static (strlen (page), page);
         ret = MHD_queue_basic_auth_required_response3 (connection,
                                                        "admins",
                                                        MHD_YES,
                                                        response);
       }
       else
       {
         static const char *page = "<html><body>A secret.</body></html>";
         response = MHD_create_response_from_buffer_static (strlen (page), page);
         ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
       }
       if (NULL != auth_info)
         MHD_free (auth_info);
       MHD_destroy_response (response);
       return ret;
     }
     
     
     int
     main (void)
     {
       struct MHD_Daemon *daemon;
     
       daemon = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD, PORT, NULL, NULL,
                                  &answer_to_connection, NULL, MHD_OPTION_END);
       if (NULL == daemon)
         return 1;
     
       (void) getchar ();
     
       MHD_stop_daemon (daemon);
       return 0;
     }


File: libmicrohttpd-tutorial.info,  Node: simplepost.c,  Next: largepost.c,  Prev: basicauthentication.c,  Up: Example programs

C.5 simplepost.c
================

     /* Feel free to use this example code in any way
        you see fit (Public Domain) */
     
     #include <sys/types.h>
     #ifndef _WIN32
     #include <sys/select.h>
     #include <sys/socket.h>
     #else
     #include <winsock2.h>
     #endif
     #include <microhttpd.h>
     #include <stdio.h>
     #include <string.h>
     #include <stdlib.h>
     
     #if defined(_MSC_VER) && _MSC_VER + 0 <= 1800
     /* Substitution is OK while return value is not used */
     #define snprintf _snprintf
     #endif
     
     #define PORT            8888
     #define POSTBUFFERSIZE  512
     #define MAXNAMESIZE     20
     #define MAXANSWERSIZE   512
     
     struct connection_info_struct
     {
       enum { GET, POST } connectiontype;
       char *answerstring;
       struct MHD_PostProcessor *postprocessor;
     };
     
     static const char *askpage =
       "<html><body>\n"
       "What's your name, Sir?<br>\n"
       "<form action=\"/namepost\" method=\"post\">\n"
       "<input name=\"name\" type=\"text\">\n"
       "<input type=\"submit\" value=\" Send \"></form>\n"
       "</body></html>";
     
     #define GREETINGPAGE \
             "<html><body><h1>Welcome, %s!</h1></body></html>"
     
     static const char *errorpage =
       "<html><body>This doesn't seem to be right.</body></html>";
     
     
     static enum MHD_Result
     send_page (struct MHD_Connection *connection,
                const char *page)
     {
       enum MHD_Result ret;
       struct MHD_Response *response;
     
       response = MHD_create_response_from_buffer_static (strlen (page),
                                                          page);
       if (! response)
         return MHD_NO;
       ret = MHD_queue_response (connection,
                                 MHD_HTTP_OK,
                                 response);
       MHD_destroy_response (response);
       return ret;
     }
     
     
     static enum MHD_Result
     iterate_post (void *coninfo_cls,
                   enum MHD_ValueKind kind,
                   const char *key,
                   const char *filename,
                   const char *content_type,
                   const char *transfer_encoding,
                   const char *data,
                   uint64_t off,
                   size_t size)
     {
       struct connection_info_struct *con_info = coninfo_cls;
     
       (void) kind;               /* Unused. Silent compiler warning. */
       (void) filename;           /* Unused. Silent compiler warning. */
       (void) content_type;       /* Unused. Silent compiler warning. */
       (void) transfer_encoding;  /* Unused. Silent compiler warning. */
       (void) off;                /* Unused. Silent compiler warning. */
       if (0 != strcmp (key,
                        "name"))
         return MHD_YES;
       if ( (size > 0) &&
            (size <= MAXNAMESIZE) )
       {
         char *answerstring;
     
         answerstring = malloc (MAXANSWERSIZE);
         if (! answerstring)
           return MHD_NO;
         snprintf (answerstring,
                   MAXANSWERSIZE,
                   GREETINGPAGE,
                   data);
         con_info->answerstring = answerstring;
       }
       else
       {
         con_info->answerstring = NULL;
       }
       return MHD_YES;
     }
     
     
     static void
     request_completed (void *cls,
                        struct MHD_Connection *connection,
                        void **req_cls,
                        enum MHD_RequestTerminationCode toe)
     {
       struct connection_info_struct *con_info = *req_cls;
     
       (void) cls;         /* Unused. Silent compiler warning. */
       (void) connection;  /* Unused. Silent compiler warning. */
       (void) toe;         /* Unused. Silent compiler warning. */
       if (NULL == con_info)
         return;
       if (POST == con_info->connectiontype)
       {
         MHD_destroy_post_processor (con_info->postprocessor);
         if (con_info->answerstring)
           free (con_info->answerstring);
       }
       free (con_info);
       *req_cls = NULL;
     }
     
     
     static enum MHD_Result
     answer_to_connection (void *cls,
                           struct MHD_Connection *connection,
                           const char *url,
                           const char *method,
                           const char *version,
                           const char *upload_data,
                           size_t *upload_data_size,
                           void **req_cls)
     {
       struct connection_info_struct *con_info = *req_cls;
     
       (void) cls;               /* Unused. Silent compiler warning. */
       (void) url;               /* Unused. Silent compiler warning. */
       (void) version;           /* Unused. Silent compiler warning. */
       if (NULL == con_info)
       {
         con_info = malloc (sizeof (struct connection_info_struct));
         *req_cls = (void *) con_info;
         if (NULL == con_info)
           return MHD_NO;
         con_info->answerstring = NULL;
     
         if (0 == strcmp (method, "POST"))
         {
           con_info->postprocessor =
             MHD_create_post_processor (connection,
                                        POSTBUFFERSIZE,
                                        iterate_post,
                                        (void *) con_info);
           if (NULL == con_info->postprocessor)
           {
             free (con_info);
             return MHD_NO;
           }
           con_info->connectiontype = POST;
         }
         else
         {
           con_info->connectiontype = GET;
         }
         return MHD_YES;
       }
       if (0 == strcmp (method, "GET"))
       {
         return send_page (connection,
                           askpage);
       }
       if (0 == strcmp (method, "POST"))
       {
         if (0 != *upload_data_size)
         {
           if (MHD_YES !=
               MHD_post_process (con_info->postprocessor,
                                 upload_data,
                                 *upload_data_size))
             return MHD_NO;
           *upload_data_size = 0;
           return MHD_YES;
         }
         else if (NULL != con_info->answerstring)
           return send_page (connection,
                             con_info->answerstring);
       }
       return send_page (connection,
                         errorpage);
     }
     
     
     int
     main (void)
     {
       struct MHD_Daemon *daemon;
     
       daemon = MHD_start_daemon (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD,
                                  PORT, NULL, NULL,
                                  &answer_to_connection, NULL,
                                  MHD_OPTION_NOTIFY_COMPLETED,
                                  &request_completed, NULL,
                                  MHD_OPTION_END);
       if (NULL == daemon)
         return 1;
       (void) getchar ();
       MHD_stop_daemon (daemon);
       return 0;
     }


File: libmicrohttpd-tutorial.info,  Node: largepost.c,  Next: sessions.c,  Prev: simplepost.c,  Up: Example programs

C.6 largepost.c
===============

     /* Feel free to use this example code in any way
        you see fit (Public Domain) */
     
     #include <sys/types.h>
     #ifndef _WIN32
     #include <sys/select.h>
     #include <sys/socket.h>
     #else
     #include <winsock2.h>
     #endif
     #include <stdio.h>
     #include <stdlib.h>
     #include <string.h>
     #include <microhttpd.h>
     
     #if defined(_MSC_VER) && _MSC_VER + 0 <= 1800
     /* Substitution is OK while return value is not used */
     #define snprintf _snprintf
     #endif
     
     #define PORT            8888
     #define POSTBUFFERSIZE  512
     #define MAXCLIENTS      2
     
     enum ConnectionType
     {
       GET = 0,
       POST = 1
     };
     
     static unsigned int nr_of_uploading_clients = 0;
     
     
     /**
      * Information we keep per connection.
      */
     struct connection_info_struct
     {
       enum ConnectionType connectiontype;
     
       /**
        * Handle to the POST processing state.
        */
       struct MHD_PostProcessor *postprocessor;
     
       /**
        * File handle where we write uploaded data.
        */
       FILE *fp;
     
       /**
        * HTTP response body we will return, NULL if not yet known.
        */
       const char *answerstring;
     
       /**
        * HTTP status code we will return, 0 for undecided.
        */
       unsigned int answercode;
     };
     
     
     #define ASKPAGE \
       "<html><body>\n" \
       "Upload a file, please!<br>\n" \
       "There are %u clients uploading at the moment.<br>\n" \
       "<form action=\"/filepost\" method=\"post\" enctype=\"multipart/form-data\">\n" \
       "<input name=\"file\" type=\"file\">\n" \
       "<input type=\"submit\" value=\" Send \"></form>\n" \
       "</body></html>"
     static const char *busypage =
       "<html><body>This server is busy, please try again later.</body></html>";
     static const char *completepage =
       "<html><body>The upload has been completed.</body></html>";
     static const char *errorpage =
       "<html><body>This doesn't seem to be right.</body></html>";
     static const char *servererrorpage =
       "<html><body>Invalid request.</body></html>";
     static const char *fileexistspage =
       "<html><body>This file already exists.</body></html>";
     static const char *fileioerror =
       "<html><body>IO error writing to disk.</body></html>";
     static const char *const postprocerror =
       "<html><head><title>Error</title></head><body>Error processing POST data</body></html>";
     
     
     static enum MHD_Result
     send_page (struct MHD_Connection *connection,
                const char *page,
                unsigned int status_code)
     {
       enum MHD_Result ret;
       struct MHD_Response *response;
     
       /* NOTE: we let MHD make its own copy of the page, as some of the
          pages we serve live in a buffer on the stack of the caller. */
       response = MHD_create_response_from_buffer_copy (strlen (page), page);
       if (! response)
         return MHD_NO;
       if (MHD_YES !=
           MHD_add_response_header (response,
                                    MHD_HTTP_HEADER_CONTENT_TYPE,
                                    "text/html"))
       {
         fprintf (stderr,
                  "Failed to set content type header!\n");
       }
       ret = MHD_queue_response (connection,
                                 status_code,
                                 response);
       MHD_destroy_response (response);
     
       return ret;
     }
     
     
     static enum MHD_Result
     iterate_post (void *coninfo_cls,
                   enum MHD_ValueKind kind,
                   const char *key,
                   const char *filename,
                   const char *content_type,
                   const char *transfer_encoding,
                   const char *data,
                   uint64_t off,
                   size_t size)
     {
       struct connection_info_struct *con_info = coninfo_cls;
       FILE *fp;
       (void) kind;               /* Unused. Silent compiler warning. */
       (void) content_type;       /* Unused. Silent compiler warning. */
       (void) transfer_encoding;  /* Unused. Silent compiler warning. */
       (void) off;                /* Unused. Silent compiler warning. */
     
       if (0 != strcmp (key, "file"))
       {
         con_info->answerstring = servererrorpage;
         con_info->answercode = MHD_HTTP_BAD_REQUEST;
         return MHD_YES;
       }
     
       if (! con_info->fp)
       {
         if (0 != con_info->answercode)   /* something went wrong */
           return MHD_YES;
         if (NULL != (fp = fopen (filename, "rb")))
         {
           fclose (fp);
           con_info->answerstring = fileexistspage;
           con_info->answercode = MHD_HTTP_FORBIDDEN;
           return MHD_YES;
         }
         /* NOTE: This is technically a race with the 'fopen()' above,
            but there is no easy fix, short of moving to open(O_EXCL)
            instead of using fopen(). For the example, we do not care. */
         con_info->fp = fopen (filename, "ab");
         if (! con_info->fp)
         {
           con_info->answerstring = fileioerror;
           con_info->answercode = MHD_HTTP_INTERNAL_SERVER_ERROR;
           return MHD_YES;
         }
       }
     
       if (size > 0)
       {
         if (! fwrite (data, sizeof (char), size, con_info->fp))
         {
           con_info->answerstring = fileioerror;
           con_info->answercode = MHD_HTTP_INTERNAL_SERVER_ERROR;
           return MHD_YES;
         }
       }
     
       return MHD_YES;
     }
     
     
     static void
     request_completed (void *cls,
                        struct MHD_Connection *connection,
                        void **req_cls,
                        enum MHD_RequestTerminationCode toe)
     {
       struct connection_info_struct *con_info = *req_cls;
       (void) cls;         /* Unused. Silent compiler warning. */
       (void) connection;  /* Unused. Silent compiler warning. */
       (void) toe;         /* Unused. Silent compiler warning. */
     
       if (NULL == con_info)
         return;
     
       if (con_info->connectiontype == POST)
       {
         if (NULL != con_info->postprocessor)
         {
           MHD_destroy_post_processor (con_info->postprocessor);
           nr_of_uploading_clients--;
         }
     
         if (con_info->fp)
           fclose (con_info->fp);
       }
     
       free (con_info);
       *req_cls = NULL;
     }
     
     
     static enum MHD_Result
     answer_to_connection (void *cls,
                           struct MHD_Connection *connection,
                           const char *url,
                           const char *method,
                           const char *version,
                           const char *upload_data,
                           size_t *upload_data_size,
                           void **req_cls)
     {
       (void) cls;               /* Unused. Silent compiler warning. */
       (void) url;               /* Unused. Silent compiler warning. */
       (void) version;           /* Unused. Silent compiler warning. */
     
       if (NULL == *req_cls)
       {
         /* First call, setup data structures */
         struct connection_info_struct *con_info;
     
         if (nr_of_uploading_clients >= MAXCLIENTS)
           return send_page (connection,
                             busypage,
                             MHD_HTTP_SERVICE_UNAVAILABLE);
     
         con_info = malloc (sizeof (struct connection_info_struct));
         if (NULL == con_info)
           return MHD_NO;
         con_info->answercode = 0;   /* none yet */
         con_info->fp = NULL;
     
         if (0 == strcmp (method, MHD_HTTP_METHOD_POST))
         {
           con_info->postprocessor =
             MHD_create_post_processor (connection,
                                        POSTBUFFERSIZE,
                                        &iterate_post,
                                        (void *) con_info);
     
           if (NULL == con_info->postprocessor)
           {
             free (con_info);
             return MHD_NO;
           }
     
           nr_of_uploading_clients++;
     
           con_info->connectiontype = POST;
         }
         else
         {
           con_info->connectiontype = GET;
         }
     
         *req_cls = (void *) con_info;
     
         return MHD_YES;
       }
     
       if (0 == strcmp (method, MHD_HTTP_METHOD_GET))
       {
         /* We just return the standard form for uploads on all GET requests */
         char buffer[1024];
     
         snprintf (buffer,
                   sizeof (buffer),
                   ASKPAGE,
                   nr_of_uploading_clients);
         return send_page (connection,
                           buffer,
                           MHD_HTTP_OK);
       }
     
       if (0 == strcmp (method, MHD_HTTP_METHOD_POST))
       {
         struct connection_info_struct *con_info = *req_cls;
     
         if (0 != *upload_data_size)
         {
           /* Upload not yet done */
           if (0 != con_info->answercode)
           {
             /* we already know the answer, skip rest of upload */
             *upload_data_size = 0;
             return MHD_YES;
           }
           if (MHD_YES !=
               MHD_post_process (con_info->postprocessor,
                                 upload_data,
                                 *upload_data_size))
           {
             con_info->answerstring = postprocerror;
             con_info->answercode = MHD_HTTP_INTERNAL_SERVER_ERROR;
           }
           *upload_data_size = 0;
     
           return MHD_YES;
         }
         /* Upload finished */
         if (NULL != con_info->fp)
         {
           fclose (con_info->fp);
           con_info->fp = NULL;
         }
         if (0 == con_info->answercode)
         {
           /* No errors encountered, declare success */
           con_info->answerstring = completepage;
           con_info->answercode = MHD_HTTP_OK;
         }
         return send_page (connection,
                           con_info->answerstring,
                           con_info->answercode);
       }
     
       /* Not a GET or a POST, generate error */
       return send_page (connection,
                         errorpage,
                         MHD_HTTP_BAD_REQUEST);
     }
     
     
     int
     main (void)
     {
       struct MHD_Daemon *daemon;
     
       daemon = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD,
                                  PORT, NULL, NULL,
                                  &answer_to_connection, NULL,
                                  MHD_OPTION_NOTIFY_COMPLETED, &request_completed,
                                  NULL,
                                  MHD_OPTION_END);
       if (NULL == daemon)
       {
         fprintf (stderr,
                  "Failed to start daemon.\n");
         return 1;
       }
       (void) getchar ();
       MHD_stop_daemon (daemon);
       return 0;
     }


File: libmicrohttpd-tutorial.info,  Node: sessions.c,  Next: callbackresponse.c,  Prev: largepost.c,  Up: Example programs

C.7 sessions.c
==============

     /* Feel free to use this example code in any way
        you see fit (Public Domain) */
     
     #include <stdlib.h>
     #include <string.h>
     #include <stdio.h>
     #include <errno.h>
     #include <time.h>
     #include <microhttpd.h>
     
     /**
      * Invalid method page.
      */
     #define METHOD_ERROR \
       "<html><head><title>Illegal request</title></head><body>Go away.</body></html>"
     
     /**
      * Invalid URL page.
      */
     #define NOT_FOUND_ERROR \
       "<html><head><title>Not found</title></head><body>Go away.</body></html>"
     
     /**
      * Front page. (/)
      */
     #define MAIN_PAGE \
       "<html><head><title>Welcome</title></head><body><form action=\"/2\" method=\"post\">What is your name? <input type=\"text\" name=\"v1\" value=\"%s\" /><input type=\"submit\" value=\"Next\" /></body></html>"
     
     #define FORM_V1 MAIN_PAGE
     
     /**
      * Second page. (/2)
      */
     #define SECOND_PAGE \
       "<html><head><title>Tell me more</title></head><body><a href=\"/\">previous</a> <form action=\"/S\" method=\"post\">%s, what is your job? <input type=\"text\" name=\"v2\" value=\"%s\" /><input type=\"submit\" value=\"Next\" /></body></html>"
     
     #define FORM_V1_V2 SECOND_PAGE
     
     /**
      * Second page (/S)
      */
     #define SUBMIT_PAGE \
       "<html><head><title>Ready to submit?</title></head><body><form action=\"/F\" method=\"post\"><a href=\"/2\">previous </a> <input type=\"hidden\" name=\"DONE\" value=\"yes\" /><input type=\"submit\" value=\"Submit\" /></body></html>"
     
     /**
      * Last page.
      */
     #define LAST_PAGE \
       "<html><head><title>Thank you</title></head><body>Thank you.</body></html>"
     
     /**
      * Name of our cookie.
      */
     #define COOKIE_NAME "session"
     
     
     /**
      * State we keep for each user/session/browser.
      */
     struct Session
     {
       /**
        * We keep all sessions in a linked list.
        */
       struct Session *next;
     
       /**
        * Unique ID for this session.
        */
       char sid[33];
     
       /**
        * Reference counter giving the number of connections
        * currently using this session.
        */
       unsigned int rc;
     
       /**
        * Time when this session was last active.
        */
       time_t start;
     
       /**
        * String submitted via form.
        */
       char value_1[64];
     
       /**
        * Another value submitted via form.
        */
       char value_2[64];
     
     };
     
     
     /**
      * Data kept per request.
      */
     struct Request
     {
     
       /**
        * Associated session.
        */
       struct Session *session;
     
       /**
        * Post processor handling form data (IF this is
        * a POST request).
        */
       struct MHD_PostProcessor *pp;
     
       /**
        * URL to serve in response to this POST (if this request
        * was a 'POST')
        */
       const char *post_url;
     
     };
     
     
     /**
      * Linked list of all active sessions.  Yes, O(n) but a
      * hash table would be overkill for a simple example...
      */
     static struct Session *sessions;
     
     
     /**
      * Return the session handle for this connection, or
      * create one if this is a new user.
      */
     static struct Session *
     get_session (struct MHD_Connection *connection)
     {
       struct Session *ret;
       const char *cookie;
     
       cookie = MHD_lookup_connection_value (connection,
                                             MHD_COOKIE_KIND,
                                             COOKIE_NAME);
       if (cookie != NULL)
       {
         /* find existing session */
         ret = sessions;
         while (NULL != ret)
         {
           if (0 == strcmp (cookie, ret->sid))
             break;
           ret = ret->next;
         }
         if (NULL != ret)
         {
           ret->rc++;
           return ret;
         }
       }
       /* create fresh session */
       ret = calloc (1, sizeof (struct Session));
       if (NULL == ret)
       {
         fprintf (stderr, "calloc error: %s\n", strerror (errno));
         return NULL;
       }
       /* not a super-secure way to generate a random session ID,
          but should do for a simple example... */
       snprintf (ret->sid,
                 sizeof (ret->sid),
                 "%X%X%X%X",
                 (unsigned int) rand (),
                 (unsigned int) rand (),
                 (unsigned int) rand (),
                 (unsigned int) rand ());
       ret->rc++;
       ret->start = time (NULL);
       ret->next = sessions;
       sessions = ret;
       return ret;
     }
     
     
     /**
      * Type of handler that generates a reply.
      *
      * @param cls content for the page (handler-specific)
      * @param mime mime type to use
      * @param session session information
      * @param connection connection to process
      * @param #MHD_YES on success, #MHD_NO on failure
      */
     typedef enum MHD_Result (*PageHandler)(const void *cls,
                                            const char *mime,
                                            struct Session *session,
                                            struct MHD_Connection *connection);
     
     
     /**
      * Entry we generate for each page served.
      */
     struct Page
     {
       /**
        * Acceptable URL for this page.
        */
       const char *url;
     
       /**
        * Mime type to set for the page.
        */
       const char *mime;
     
       /**
        * Handler to call to generate response.
        */
       PageHandler handler;
     
       /**
        * Extra argument to handler.
        */
       const void *handler_cls;
     };
     
     
     /**
      * Add header to response to set a session cookie.
      *
      * @param session session to use
      * @param response response to modify
      */
     static void
     add_session_cookie (struct Session *session,
                         struct MHD_Response *response)
     {
       char cstr[256];
       snprintf (cstr,
                 sizeof (cstr),
                 "%s=%s",
                 COOKIE_NAME,
                 session->sid);
       if (MHD_NO ==
           MHD_add_response_header (response,
                                    MHD_HTTP_HEADER_SET_COOKIE,
                                    cstr))
       {
         fprintf (stderr,
                  "Failed to set session cookie header!\n");
       }
     }
     
     
     /**
      * Handler that returns a simple static HTTP page that
      * is passed in via 'cls'.
      *
      * @param cls a 'const char *' with the HTML webpage to return
      * @param mime mime type to use
      * @param session session handle
      * @param connection connection to use
      */
     static enum MHD_Result
     serve_simple_form (const void *cls,
                        const char *mime,
                        struct Session *session,
                        struct MHD_Connection *connection)
     {
       enum MHD_Result ret;
       const char *form = cls;
       struct MHD_Response *response;
     
       /* return static form */
       response = MHD_create_response_from_buffer_static (strlen (form), form);
       add_session_cookie (session, response);
       if (MHD_YES !=
           MHD_add_response_header (response,
                                    MHD_HTTP_HEADER_CONTENT_TYPE,
                                    mime))
       {
         fprintf (stderr,
                  "Failed to set content type header!\n");
         /* return response without content type anyway ... */
       }
       ret = MHD_queue_response (connection,
                                 MHD_HTTP_OK,
                                 response);
       MHD_destroy_response (response);
       return ret;
     }
     
     
     /**
      * Handler that adds the 'v1' value to the given HTML code.
      *
      * @param cls a 'const char *' with the HTML webpage to return
      * @param mime mime type to use
      * @param session session handle
      * @param connection connection to use
      */
     static enum MHD_Result
     fill_v1_form (const void *cls,
                   const char *mime,
                   struct Session *session,
                   struct MHD_Connection *connection)
     {
       enum MHD_Result ret;
       char *reply;
       struct MHD_Response *response;
       int reply_len;
       (void) cls; /* Unused */
     
       /* Emulate 'asprintf' */
       reply_len = snprintf (NULL, 0, FORM_V1, session->value_1);
       if (0 > reply_len)
         return MHD_NO; /* Internal error */
     
       reply = (char *) malloc ((size_t) ((size_t) reply_len + 1));
       if (NULL == reply)
         return MHD_NO; /* Out-of-memory error */
     
       if (reply_len != snprintf (reply,
                                  (size_t) (((size_t) reply_len) + 1),
                                  FORM_V1,
                                  session->value_1))
       {
         free (reply);
         return MHD_NO; /* printf error */
       }
     
       /* return static form */
       response =
         MHD_create_response_from_buffer_with_free_callback ((size_t) reply_len,
                                                             (void *) reply,
                                                             &free);
       if (NULL != response)
       {
         add_session_cookie (session, response);
         if (MHD_YES !=
             MHD_add_response_header (response,
                                      MHD_HTTP_HEADER_CONTENT_TYPE,
                                      mime))
         {
           fprintf (stderr,
                    "Failed to set content type header!\n");
           /* return response without content type anyway ... */
         }
         ret = MHD_queue_response (connection,
                                   MHD_HTTP_OK,
                                   response);
         MHD_destroy_response (response);
       }
       else
       {
         free (reply);
         ret = MHD_NO;
       }
       return ret;
     }
     
     
     /**
      * Handler that adds the 'v1' and 'v2' values to the given HTML code.
      *
      * @param cls a 'const char *' with the HTML webpage to return
      * @param mime mime type to use
      * @param session session handle
      * @param connection connection to use
      */
     static enum MHD_Result
     fill_v1_v2_form (const void *cls,
                      const char *mime,
                      struct Session *session,
                      struct MHD_Connection *connection)
     {
       enum MHD_Result ret;
       char *reply;
       struct MHD_Response *response;
       int reply_len;
       (void) cls; /* Unused */
     
       /* Emulate 'asprintf' */
       reply_len = snprintf (NULL, 0, FORM_V1_V2, session->value_1,
                             session->value_2);
       if (0 > reply_len)
         return MHD_NO; /* Internal error */
     
       reply = (char *) malloc ((size_t) ((size_t) reply_len + 1));
       if (NULL == reply)
         return MHD_NO; /* Out-of-memory error */
     
       if (reply_len != snprintf (reply,
                                  (size_t) ((size_t) reply_len + 1),
                                  FORM_V1_V2,
                                  session->value_1,
                                  session->value_2))
       {
         free (reply);
         return MHD_NO; /* printf error */
       }
     
       /* return static form */
       response =
         MHD_create_response_from_buffer_with_free_callback ((size_t) reply_len,
                                                             (void *) reply,
                                                             &free);
       if (NULL != response)
       {
         add_session_cookie (session, response);
         if (MHD_YES !=
             MHD_add_response_header (response,
                                      MHD_HTTP_HEADER_CONTENT_TYPE,
                                      mime))
         {
           fprintf (stderr,
                    "Failed to set content type header!\n");
           /* return response without content type anyway ... */
         }
         ret = MHD_queue_response (connection,
                                   MHD_HTTP_OK,
                                   response);
         MHD_destroy_response (response);
       }
       else
       {
         free (reply);
         ret = MHD_NO;
       }
       return ret;
     }
     
     
     /**
      * Handler used to generate a 404 reply.
      *
      * @param cls a 'const char *' with the HTML webpage to return
      * @param mime mime type to use
      * @param session session handle
      * @param connection connection to use
      */
     static enum MHD_Result
     not_found_page (const void *cls,
                     const char *mime,
                     struct Session *session,
                     struct MHD_Connection *connection)
     {
       enum MHD_Result ret;
       struct MHD_Response *response;
       (void) cls;     /* Unused. Silent compiler warning. */
       (void) session; /* Unused. Silent compiler warning. */
     
       /* unsupported HTTP method */
       response = MHD_create_response_from_buffer_static (strlen (NOT_FOUND_ERROR),
                                                          NOT_FOUND_ERROR);
       /* NOTE: headers must be added _before_ the response is queued,
          MHD refuses to modify a response that was already queued. */
       if (MHD_YES !=
           MHD_add_response_header (response,
                                    MHD_HTTP_HEADER_CONTENT_TYPE,
                                    mime))
       {
         fprintf (stderr,
                  "Failed to set content type header!\n");
         /* return response without content type anyway ... */
       }
       ret = MHD_queue_response (connection,
                                 MHD_HTTP_NOT_FOUND,
                                 response);
       MHD_destroy_response (response);
       return ret;
     }
     
     
     /**
      * List of all pages served by this HTTP server.
      */
     static const struct Page pages[] = {
       { "/", "text/html",  &fill_v1_form, NULL },
       { "/2", "text/html", &fill_v1_v2_form, NULL },
       { "/S", "text/html", &serve_simple_form, SUBMIT_PAGE },
       { "/F", "text/html", &serve_simple_form, LAST_PAGE },
       { NULL, "text/html", &not_found_page, NULL }   /* 404 */
     };
     
     
     /**
      * Iterator over key-value pairs where the value
      * maybe made available in increments and/or may
      * not be zero-terminated.  Used for processing
      * POST data.
      *
      * @param cls user-specified closure
      * @param kind type of the value
      * @param key 0-terminated key for the value
      * @param filename name of the uploaded file, NULL if not known
      * @param content_type mime-type of the data, NULL if not known
      * @param transfer_encoding encoding of the data, NULL if not known
      * @param data pointer to size bytes of data at the
      *              specified offset
      * @param off offset of data in the overall value
      * @param size number of bytes in data available
      * @return #MHD_YES to continue iterating,
      *         #MHD_NO to abort the iteration
      */
     static enum MHD_Result
     post_iterator (void *cls,
                    enum MHD_ValueKind kind,
                    const char *key,
                    const char *filename,
                    const char *content_type,
                    const char *transfer_encoding,
                    const char *data, uint64_t off, size_t size)
     {
       struct Request *request = cls;
       struct Session *session = request->session;
       (void) kind;               /* Unused. Silent compiler warning. */
       (void) filename;           /* Unused. Silent compiler warning. */
       (void) content_type;       /* Unused. Silent compiler warning. */
       (void) transfer_encoding;  /* Unused. Silent compiler warning. */
     
       if (0 == strcmp ("DONE", key))
       {
         fprintf (stdout,
                  "Session `%s' submitted `%s', `%s'\n",
                  session->sid,
                  session->value_1,
                  session->value_2);
         return MHD_YES;
       }
       if (0 == strcmp ("v1", key))
       {
         if (off >= sizeof(session->value_1) - 1)
           return MHD_YES; /* Discard extra data */
         if (size + off >= sizeof(session->value_1))
           size = (size_t) (sizeof (session->value_1) - off - 1); /* crop extra data */
         memcpy (&session->value_1[off],
                 data,
                 size);
         if (size + off < sizeof (session->value_1))
           session->value_1[size + off] = '\0';
         return MHD_YES;
       }
       if (0 == strcmp ("v2", key))
       {
         if (off >= sizeof(session->value_2) - 1)
           return MHD_YES; /* Discard extra data */
         if (size + off >= sizeof(session->value_2))
           size = (size_t) (sizeof (session->value_2) - off - 1); /* crop extra data */
         memcpy (&session->value_2[off],
                 data,
                 size);
         if (size + off < sizeof (session->value_2))
           session->value_2[size + off] = '\0';
         return MHD_YES;
       }
       fprintf (stderr, "Unsupported form value `%s'\n", key);
       return MHD_YES;
     }
     
     
     /**
      * Main MHD callback for handling requests.
      *
      *
      * @param cls argument given together with the function
      *        pointer when the handler was registered with MHD
      * @param connection handle to connection which is being processed
      * @param url the requested url
      * @param method the HTTP method used ("GET", "PUT", etc.)
      * @param version the HTTP version string (i.e. "HTTP/1.1")
      * @param upload_data the data being uploaded (excluding HEADERS,
      *        for a POST that fits into memory and that is encoded
      *        with a supported encoding, the POST data will NOT be
      *        given in upload_data and is instead available as
      *        part of MHD_get_connection_values; very large POST
      *        data *will* be made available incrementally in
      *        upload_data)
      * @param upload_data_size set initially to the size of the
      *        upload_data provided; the method must update this
      *        value to the number of bytes NOT processed;
      * @param req_cls pointer that the callback can set to some
      *        address and that will be preserved by MHD for future
      *        calls for this request; since the access handler may
      *        be called many times (i.e., for a PUT/POST operation
      *        with plenty of upload data) this allows the application
      *        to easily associate some request-specific state.
      *        If necessary, this state can be cleaned up in the
      *        global "MHD_RequestCompleted" callback (which
      *        can be set with the MHD_OPTION_NOTIFY_COMPLETED).
      *        Initially, <tt>*req_cls</tt> will be NULL.
      * @return MHS_YES if the connection was handled successfully,
      *         MHS_NO if the socket must be closed due to a serious
      *         error while handling the request
      */
     static enum MHD_Result
     create_response (void *cls,
                      struct MHD_Connection *connection,
                      const char *url,
                      const char *method,
                      const char *version,
                      const char *upload_data,
                      size_t *upload_data_size,
                      void **req_cls)
     {
       struct MHD_Response *response;
       struct Request *request;
       struct Session *session;
       enum MHD_Result ret;
       unsigned int i;
       (void) cls;               /* Unused. Silent compiler warning. */
       (void) version;           /* Unused. Silent compiler warning. */
     
       request = *req_cls;
       if (NULL == request)
       {
         request = calloc (1, sizeof (struct Request));
         if (NULL == request)
         {
           fprintf (stderr, "calloc error: %s\n", strerror (errno));
           return MHD_NO;
         }
         *req_cls = request;
         if (0 == strcmp (method, MHD_HTTP_METHOD_POST))
         {
           request->pp = MHD_create_post_processor (connection, 1024,
                                                    &post_iterator, request);
           if (NULL == request->pp)
           {
             fprintf (stderr, "Failed to setup post processor for `%s'\n",
                      url);
             return MHD_NO; /* internal error */
           }
         }
         return MHD_YES;
       }
       if (NULL == request->session)
       {
         request->session = get_session (connection);
         if (NULL == request->session)
         {
           fprintf (stderr, "Failed to setup session for `%s'\n",
                    url);
           return MHD_NO; /* internal error */
         }
       }
       session = request->session;
       session->start = time (NULL);
       if (0 == strcmp (method, MHD_HTTP_METHOD_POST))
       {
         /* evaluate POST data */
         if (MHD_YES !=
             MHD_post_process (request->pp,
                               upload_data,
                               *upload_data_size))
           return MHD_NO; /* internal error */
         if (0 != *upload_data_size)
         {
           *upload_data_size = 0;
           return MHD_YES;
         }
         /* done with POST data, serve response */
         MHD_destroy_post_processor (request->pp);
         request->pp = NULL;
         method = MHD_HTTP_METHOD_GET;   /* fake 'GET' */
         if (NULL != request->post_url)
           url = request->post_url;
       }
     
       if ( (0 == strcmp (method, MHD_HTTP_METHOD_GET)) ||
            (0 == strcmp (method, MHD_HTTP_METHOD_HEAD)) )
       {
         /* find out which page to serve */
         i = 0;
         while ( (pages[i].url != NULL) &&
                 (0 != strcmp (pages[i].url, url)) )
           i++;
         ret = pages[i].handler (pages[i].handler_cls,
                                 pages[i].mime,
                                 session, connection);
         if (ret != MHD_YES)
           fprintf (stderr, "Failed to create page for `%s'\n",
                    url);
         return ret;
       }
       /* unsupported HTTP method */
       response = MHD_create_response_from_buffer_static (strlen (METHOD_ERROR),
                                                          METHOD_ERROR);
       ret = MHD_queue_response (connection,
                                 MHD_HTTP_NOT_ACCEPTABLE,
                                 response);
       MHD_destroy_response (response);
       return ret;
     }
     
     
     /**
      * Callback called upon completion of a request.
      * Decrements session reference counter.
      *
      * @param cls not used
      * @param connection connection that completed
      * @param req_cls session handle
      * @param toe status code
      */
     static void
     request_completed_callback (void *cls,
                                 struct MHD_Connection *connection,
                                 void **req_cls,
                                 enum MHD_RequestTerminationCode toe)
     {
       struct Request *request = *req_cls;
       (void) cls;         /* Unused. Silent compiler warning. */
       (void) connection;  /* Unused. Silent compiler warning. */
       (void) toe;         /* Unused. Silent compiler warning. */
     
       if (NULL == request)
         return;
       if (NULL != request->session)
         request->session->rc--;
       if (NULL != request->pp)
         MHD_destroy_post_processor (request->pp);
       free (request);
     }
     
     
     /**
      * Clean up handles of sessions that have been idle for
      * too long.
      */
     static void
     expire_sessions (void)
     {
       struct Session *pos;
       struct Session *prev;
       struct Session *next;
       time_t now;
     
       now = time (NULL);
       prev = NULL;
       pos = sessions;
       while (NULL != pos)
       {
         next = pos->next;
         if (now - pos->start > 60 * 60)
         {
           /* expire sessions after 1h */
           if (NULL == prev)
             sessions = pos->next;
           else
             prev->next = next;
           free (pos);
         }
         else
           prev = pos;
         pos = next;
       }
     }
     
     
     /**
      * Call with the port number as the only argument.
      * Never terminates (other than by signals, such as CTRL-C).
      */
     int
     main (int argc, char *const *argv)
     {
       struct MHD_Daemon *d;
       struct timeval tv;
       struct timeval *tvp;
       fd_set rs;
       fd_set ws;
       fd_set es;
       MHD_socket max;
       uint64_t mhd_timeout;
       unsigned int port;
     
       if (argc != 2)
       {
         printf ("%s PORT\n", argv[0]);
         return 1;
       }
       if ( (1 != sscanf (argv[1], "%u", &port)) ||
            (0 == port) || (65535 < port) )
       {
         fprintf (stderr,
                  "Port must be a number between 1 and 65535.\n");
         return 1;
       }
     
       /* initialize PRNG */
       srand ((unsigned int) time (NULL));
       d = MHD_start_daemon (MHD_USE_ERROR_LOG,
                             (uint16_t) port,
                             NULL, NULL,
                             &create_response, NULL,
                             MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 15,
                             MHD_OPTION_NOTIFY_COMPLETED,
                             &request_completed_callback, NULL,
                             MHD_OPTION_APP_FD_SETSIZE, (int) FD_SETSIZE,
                             MHD_OPTION_END);
       if (NULL == d)
         return 1;
       while (1)
       {
         expire_sessions ();
         max = 0;
         FD_ZERO (&rs);
         FD_ZERO (&ws);
         FD_ZERO (&es);
         if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
           break; /* fatal internal error */
         if (MHD_get_timeout64 (d, &mhd_timeout) == MHD_YES)
         {
     #if ! defined(_WIN32) || defined(__CYGWIN__)
           tv.tv_sec = (time_t) (mhd_timeout / 1000);
     #else  /* Native W32 */
           tv.tv_sec = (long) (mhd_timeout / 1000);
     #endif /* Native W32 */
           tv.tv_usec = ((long) (mhd_timeout % 1000)) * 1000;
           tvp = &tv;
         }
         else
           tvp = NULL;
         if (-1 == select ((int) max + 1, &rs, &ws, &es, tvp))
         {
           if (EINTR != errno)
             fprintf (stderr,
                      "Aborting due to error during select: %s\n",
                      strerror (errno));
           break;
         }
         MHD_run (d);
       }
       MHD_stop_daemon (d);
       return 0;
     }


File: libmicrohttpd-tutorial.info,  Node: callbackresponse.c,  Next: asyncresponse.c,  Prev: sessions.c,  Up: Example programs

C.8 callbackresponse.c
======================

     /* Feel free to use this example code in any way
        you see fit (Public Domain) */
     
     /**
      * @file callbackresponse.c
      * @brief   Example for generating a response on the fly with
      *          MHD_create_response_from_callback().  The body is not a
      *          file and is never assembled in memory as a whole; it is
      *          produced block by block into a single heap buffer that is
      *          refilled every time libmicrohttpd asks for more data.
      *          "GET /" streams the document with an unknown size (and thus
      *          with chunked transfer encoding), "GET /sized" streams the
      *          very same document with a "Content-Length" announced up
      *          front, and "GET /error" aborts the stream in the middle to
      *          show MHD_CONTENT_READER_END_WITH_ERROR.
      * @author  Christian Grothoff
      */
     
     #include <sys/types.h>
     #ifndef _WIN32
     #include <sys/select.h>
     #include <sys/socket.h>
     #else
     #include <winsock2.h>
     #endif
     #include <microhttpd.h>
     #include <stdio.h>
     #include <stdlib.h>
     #include <string.h>
     
     #define PORT 8888
     
     /**
      * Length of one generated line, including the newline character.
      */
     #define LINE_SIZE 64
     
     /**
      * Size of the heap buffer that is refilled over and over again.  This
      * is the amount of data we produce in one go; it has nothing to do
      * with the block size we pass to MHD.
      */
     #define BUFFER_SIZE (64 * LINE_SIZE)
     
     /**
      * Number of times the buffer is refilled before the stream ends.  The
      * complete document is BLOCK_COUNT * BUFFER_SIZE bytes long.
      */
     #define BLOCK_COUNT 64
     
     /**
      * Block size we ask MHD to use when it queries our callback.  MHD
      * allocates a buffer of this size together with the response; it is an
      * advisory value and MHD may ask for less.
      */
     #define IO_BLOCK_SIZE 1024
     
     /**
      * For the "/error" URL: number of blocks to deliver before the stream
      * is aborted with MHD_CONTENT_READER_END_WITH_ERROR.
      */
     #define ABORT_AFTER 3
     
     
     /**
      * State we keep for one response that is being streamed.  One such
      * structure is allocated per request and released by the free callback
      * that we hand to MHD_create_response_from_callback().
      */
     struct ResponseContext
     {
       /**
        * Heap buffer holding the block that is currently being delivered.
        * Refilled by generate_block() whenever it has been drained.
        */
       char *buf;
     
       /**
        * Number of valid bytes in @e buf.
        */
       size_t fill;
     
       /**
        * Number of bytes of @e buf that were already handed to MHD.
        */
       size_t off;
     
       /**
        * Number of blocks generated so far, and thus the number of the
        * block that generate_block() will produce next.
        */
       unsigned int block;
     
       /**
        * Non-zero if this stream is supposed to fail in the middle.
        */
       int fail;
     };
     
     
     /**
      * Produce the next block of the document into @a ctx->buf.  This
      * stands in for whatever expensive computation, database query or
      * network fetch a real application would perform here.  Note that the
      * same buffer is reused for every block, so the memory needed by the
      * server does not grow with the size of the document.
      *
      * Every line is exactly LINE_SIZE bytes long, which is what allows us
      * to announce an exact "Content-Length" for the "/sized" URL.
      *
      * @param ctx the per-response state to refill
      */
     static void
     generate_block (struct ResponseContext *ctx)
     {
       unsigned int i;
       char *line;
       char label[32];
       int len;
     
       for (i = 0; i < BUFFER_SIZE / LINE_SIZE; i++)
       {
         line = &ctx->buf[i * LINE_SIZE];
         memset (line, '.', LINE_SIZE);
         len = snprintf (label,
                         sizeof (label),
                         "block %3u line %3u ",
                         ctx->block,
                         i);
         if ((0 < len) && (LINE_SIZE > (size_t) len))
           memcpy (line, label, (size_t) len);
         line[LINE_SIZE - 1] = '\n';
       }
       ctx->fill = BUFFER_SIZE;
       ctx->off = 0;
       ctx->block++;
     }
     
     
     /**
      * Callback used by MHD to obtain the next piece of the response body.
      *
      * @param cls our `struct ResponseContext`
      * @param pos number of bytes already returned for this response
      * @param buf where to copy the data
      * @param max maximum number of bytes to copy to @a buf
      * @return number of bytes written to @a buf,
      *         MHD_CONTENT_READER_END_OF_STREAM for the regular end,
      *         MHD_CONTENT_READER_END_WITH_ERROR to abort the transfer
      */
     static ssize_t
     content_reader (void *cls,
                     uint64_t pos,
                     char *buf,
                     size_t max)
     {
       struct ResponseContext *ctx = cls;
       size_t ready;
     
       /* We generate a pure stream and never look back, so the position is
          of no interest to us.  MHD guarantees that it is the sum of all
          non-negative values we returned so far. */
       (void) pos;                   /* Unused. Silent compiler warning. */
     
       if (ctx->off == ctx->fill)
       {
         /* Everything we had was passed on, produce the next block. */
         if (BLOCK_COUNT == ctx->block)
           return MHD_CONTENT_READER_END_OF_STREAM;
         if ((0 != ctx->fail) && (ABORT_AFTER == ctx->block))
           return MHD_CONTENT_READER_END_WITH_ERROR;
         generate_block (ctx);
       }
       /* Hand over as much of the current block as MHD is willing to take;
          the rest follows on the next invocation. */
       ready = ctx->fill - ctx->off;
       if (ready > max)
         ready = max;
       memcpy (buf, &ctx->buf[ctx->off], ready);
       ctx->off += ready;
       return (ssize_t) ready;
     }
     
     
     /**
      * Release the resources of a `struct ResponseContext`.  MHD calls this
      * once the response is destroyed, which happens no matter whether the
      * body was transmitted completely or the client went away early.
      *
      * @param cls our `struct ResponseContext`
      */
     static void
     free_context (void *cls)
     {
       struct ResponseContext *ctx = cls;
     
       free (ctx->buf);
       free (ctx);
     }
     
     
     static enum MHD_Result
     answer_to_connection (void *cls, struct MHD_Connection *connection,
                           const char *url, const char *method,
                           const char *version, const char *upload_data,
                           size_t *upload_data_size, void **req_cls)
     {
       struct ResponseContext *ctx;
       struct MHD_Response *response;
       enum MHD_Result ret;
       uint64_t size;
       (void) cls;               /* Unused. Silent compiler warning. */
       (void) version;           /* Unused. Silent compiler warning. */
       (void) upload_data;       /* Unused. Silent compiler warning. */
       (void) upload_data_size;  /* Unused. Silent compiler warning. */
       (void) req_cls;           /* Unused. Silent compiler warning. */
     
       if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
         return MHD_NO;
     
       /* Allocate the state of this particular response before the response
          object exists; from now on the free callback owns it. */
       ctx = malloc (sizeof (struct ResponseContext));
       if (NULL == ctx)
         return MHD_NO;
       ctx->buf = malloc (BUFFER_SIZE);
       if (NULL == ctx->buf)
       {
         free (ctx);
         return MHD_NO;
       }
       ctx->fill = 0;
       ctx->off = 0;
       ctx->block = 0;
       ctx->fail = (0 == strcmp (url, "/error"));
     
       /* "/sized" announces the length in advance, everything else is sent
          with an unknown size and thus with chunked transfer encoding. */
       if (0 == strcmp (url, "/sized"))
         size = (uint64_t) BLOCK_COUNT * BUFFER_SIZE;
       else
         size = MHD_SIZE_UNKNOWN;
     
       response = MHD_create_response_from_callback (size,
                                                     IO_BLOCK_SIZE,
                                                     &content_reader,
                                                     ctx,
                                                     &free_context);
       if (NULL == response)
       {
         /* The response was never created, so nobody will call the free
            callback for us. */
         free_context (ctx);
         return MHD_NO;
       }
       (void) MHD_add_response_header (response,
                                       MHD_HTTP_HEADER_CONTENT_TYPE,
                                       "text/plain");
       ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
       MHD_destroy_response (response);
     
       return ret;
     }
     
     
     int
     main (void)
     {
       struct MHD_Daemon *daemon;
     
       daemon = MHD_start_daemon (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD,
                                  PORT, NULL, NULL,
                                  &answer_to_connection, NULL, MHD_OPTION_END);
       if (NULL == daemon)
         return 1;
     
       (void) getchar ();
     
       MHD_stop_daemon (daemon);
       return 0;
     }


File: libmicrohttpd-tutorial.info,  Node: asyncresponse.c,  Next: tlsauthentication.c,  Prev: callbackresponse.c,  Up: Example programs

C.9 asyncresponse.c
===================

     /* Feel free to use this example code in any way
        you see fit (Public Domain) */
     
     /**
      * @file asyncresponse.c
      * @brief   Example for answering a request from another thread while
      *          the daemon is driven by an external select() loop.  The
      *          main thread owns libmicrohttpd and does nothing but poll;
      *          every slow request gets a worker thread of its own and the
      *          connection is suspended for as long as that worker has
      *          nothing to say.
      *
      *          "GET /" serves a small page whose JavaScript renders the
      *          data as it trickles in, "GET /events" is the stream behind
      *          it (a response is queued immediately and the content reader
      *          suspends between chunks), "GET /slow" suspends in the access
      *          handler until a complete answer is ready, and "GET /fast" is
      *          answered on the spot so that it can be used to show that the
      *          event loop never blocks.
      *
      *          This example needs POSIX threads.
      * @author  Christian Grothoff
      */
     
     #include <sys/types.h>
     #include <sys/select.h>
     #include <sys/socket.h>
     #include <microhttpd.h>
     #include <errno.h>
     #include <pthread.h>
     #include <signal.h>
     #include <stdio.h>
     #include <stdlib.h>
     #include <string.h>
     #include <time.h>
     #include <unistd.h>
     
     /**
      * Port to listen on if none was given on the command line.  Pass 0 to
      * let the operating system pick a free port; the port that was
      * actually bound is then printed on standard output.
      */
     #define DEFAULT_PORT 8888
     
     /**
      * Time the worker thread pretends to need for one step, in
      * milliseconds.
      */
     #define DEFAULT_STEP_MS 250
     
     /**
      * Number of steps that make up one job.
      */
     #define DEFAULT_STEPS 20
     
     /**
      * Size of the buffer in which a job collects the bytes that the
      * content reader has not picked up yet.
      */
     #define MAX_PAYLOAD 4096
     
     /**
      * Block size we ask MHD to use when it queries our content reader.
      */
     #define IO_BLOCK_SIZE 1024
     
     /**
      * How long we are willing to wait for the last connections to go away
      * when the server is shutting down, in milliseconds.
      */
     #define DRAIN_TIMEOUT_MS 2000
     
     
     /**
      * The front page.  Its JavaScript opens the "/events" stream and adds
      * a row for every server-sent event as it arrives, so that the delay
      * between the steps is plainly visible.  The "ping" button fires a
      * request against "/fast" and reports the round trip time; it stays in
      * the low milliseconds even while several jobs are running, which is
      * the whole point of suspending instead of blocking.
      */
     static const char *PAGE =
       "<!DOCTYPE html>\n"
       "<html lang='en'>\n"
       "<head>\n"
       "<meta charset='utf-8'>\n"
       "<title>libmicrohttpd: answering from another thread</title>\n"
       "<style>\n"
       "body { font-family: sans-serif; max-width: 40em; margin: 2em auto; }\n"
       "#bar { height: 1em; border: 1px solid #888; margin: 1em 0; }\n"
       "#fill { height: 100%; width: 0; background: #4a90d9; transition: width .2s; }\n"
       "#log { font-family: monospace; font-size: 90%; list-style: none; padding: 0; }\n"
       "#log li { border-bottom: 1px solid #eee; padding: 2px 0; }\n"
       "button { margin-right: .5em; }\n"
       "</style>\n"
       "</head>\n"
       "<body>\n"
       "<h1>Answering from another thread</h1>\n"
       "<p>The server runs a single external <code>select()</code> loop.  The job\n"
       "below is computed by a thread of its own, and the connection carrying it is\n"
       "suspended whenever that thread has nothing to say.  Nothing is buffered: each\n"
       "row appears the moment the worker produced it.</p>\n"
       "<button id='go'>Start a job</button>\n"
       "<button id='ping'>Ping /fast</button>\n"
       "<div id='bar'><div id='fill'></div></div>\n"
       "<p id='status'>idle</p>\n"
       "<ul id='log'></ul>\n"
       "<script>\n"
       "const $ = (id) => document.getElementById(id);\n"
       "let es = null;\n"
       "let t0 = 0;\n"
       "const stop = () => { if (es) { es.close(); es = null; } };\n"
       "$('go').onclick = () => {\n"
       "  stop ();\n"
       "  $('log').innerHTML = '';\n"
       "  $('fill').style.width = '0';\n"
       "  $('status').textContent = 'running';\n"
       "  t0 = performance.now ();\n"
       "  es = new EventSource ('/events');\n"
       "  es.addEventListener ('step', (e) => {\n"
       "    const d = JSON.parse (e.data);\n"
       "    const li = document.createElement ('li');\n"
       "    li.textContent = '+' + Math.round (performance.now () - t0) +\n"
       "                     ' ms   ' + d.label;\n"
       "    $('log').appendChild (li);\n"
       "    $('fill').style.width = (100 * d.n / d.total) + '%';\n"
       "  });\n"
       "  es.addEventListener ('done', () => {\n"
       "    stop ();\n"
       "    $('status').textContent = 'done after ' +\n"
       "      Math.round (performance.now () - t0) + ' ms';\n"
       "  });\n"
       "  es.onerror = () => { stop (); $('status').textContent = 'connection lost'; };\n"
       "};\n"
       "$('ping').onclick = async () => {\n"
       "  const t = performance.now ();\n"
       "  await fetch ('/fast', { cache: 'no-store' });\n"
       "  $('status').textContent = '/fast answered in ' +\n"
       "    Math.round (performance.now () - t) + ' ms';\n"
       "};\n"
       "</script>\n"
       "</body>\n"
       "</html>\n";
     
     
     /**
      * State shared between the thread that runs libmicrohttpd and the
      * worker thread that produces the answer.  Everything below @e lock is
      * protected by it.
      *
      * The structure is reference counted, with one reference held by MHD
      * (dropped in #stream_done() or #request_completed()) and one held by
      * the worker (dropped when the worker function returns).  Reaching zero
      * does not free the job: only the main thread does that, in
      * #reap_jobs(), because it is also the thread that has to join the
      * worker.
      */
     struct Job
     {
       /**
        * Kept in a doubly linked list of all jobs, so that the shutdown
        * code can reach every worker.  The list is protected by
        * #jobs_lock, never by @e lock.
        */
       struct Job *next;
     
       /**
        * See @e next.
        */
       struct Job *prev;
     
       /**
        * Protects every field below, and---just as importantly---keeps the
        * connection alive across #MHD_resume_connection().
        */
       pthread_mutex_t lock;
     
       /**
        * Used to wake the worker out of its sleep when the client goes away
        * or the server is shutting down.
        */
       pthread_cond_t cond;
     
       /**
        * The worker thread.  Only touched by the main thread, under
        * #jobs_lock.
        */
       pthread_t tid;
     
       /**
        * The connection this job answers.  Set to NULL by the MHD side as
        * soon as MHD is done with the connection; the worker must not touch
        * it after that, which is why @e abandoned is checked under @e lock
        * before every #MHD_resume_connection().
        */
       struct MHD_Connection *connection;
     
       /**
        * Bytes produced by the worker that the content reader has not
        * picked up yet.
        */
       char payload[MAX_PAYLOAD];
     
       /**
        * Number of valid bytes in @e payload.
        */
       size_t fill;
     
       /**
        * Number of bytes of @e payload already handed to MHD.
        */
       size_t off;
     
       /**
        * Number of references, see the comment on the structure.
        */
       unsigned int rc;
     
       /**
        * Non-zero if the answer is streamed as it is produced ("/events"),
        * zero if the client only ever sees the finished result ("/slow").
        * A streaming job resumes the connection after every step, the other
        * kind only once, at the very end.
        */
       int stream;
     
       /**
        * Non-zero once the worker has produced everything it is going to
        * produce.
        */
       int finished;
     
       /**
        * Non-zero while the connection is suspended (or is just about to
        * be, which under @e lock is the same thing).
        */
       int suspended;
     
       /**
        * Non-zero once MHD is done with the connection.  The worker must
        * not call any MHD function on @e connection any more.
        */
       int abandoned;
     
       /**
        * Non-zero if the worker should give up early.
        */
       int stop;
     
       /**
        * Non-zero once the worker thread was started.  Main thread only.
        */
       int started;
     
       /**
        * Non-zero once the worker thread was joined.  Main thread only.
        */
       int joined;
     };
     
     
     /**
      * Head of the list of all jobs.
      */
     static struct Job *jobs_head;
     
     /**
      * Protects #jobs_head and the list links of every job.  Lock order is
      * #jobs_lock before any `struct Job`'s @e lock, never the other way
      * round.
      */
     static pthread_mutex_t jobs_lock = PTHREAD_MUTEX_INITIALIZER;
     
     /**
      * Set by the signal handler, read by the main loop.
      */
     static volatile sig_atomic_t shutdown_requested;
     
     /**
      * Written to by the signal handler so that a blocking select() returns
      * at once.  MHD's own wakeup goes through its inter-thread
      * communication channel, but our signal is our own business.
      */
     static int wake_pipe[2] = { -1, -1 };
     
     /**
      * Milliseconds the worker sleeps per step.
      */
     static unsigned int step_ms = DEFAULT_STEP_MS;
     
     /**
      * Number of steps that make up one job.
      */
     static unsigned int total_steps = DEFAULT_STEPS;
     
     
     /**
      * Signal handler for SIGINT and SIGTERM.  Does the two things that are
      * safe to do here: set a flag and poke a pipe.
      *
      * @param sig the signal that was received
      */
     static void
     signal_handler (int sig)
     {
       static const char c = 'x';
     
       (void) sig;               /* Unused. Silent compiler warning. */
       shutdown_requested = 1;
       if (0 > write (wake_pipe[1],
                      &c,
                      1))
       {
         /* Nothing useful can be done about this here. */
       }
     }
     
     
     /**
      * Allocate a job and put it on the global list.
      *
      * @param connection the connection the job answers
      * @param stream non-zero to deliver the steps as they are produced
      * @return the new job with a reference count of two (one for MHD, one
      *         for the worker that the caller is about to start), NULL on
      *         error
      */
     static struct Job *
     job_create (struct MHD_Connection *connection,
                 int stream)
     {
       struct Job *job;
     
       job = malloc (sizeof (struct Job));
       if (NULL == job)
         return NULL;
       memset (job,
               0,
               sizeof (struct Job));
       if (0 != pthread_mutex_init (&job->lock,
                                    NULL))
       {
         free (job);
         return NULL;
       }
       if (0 != pthread_cond_init (&job->cond,
                                   NULL))
       {
         pthread_mutex_destroy (&job->lock);
         free (job);
         return NULL;
       }
       job->connection = connection;
       job->stream = stream;
       job->rc = 2;
       pthread_mutex_lock (&jobs_lock);
       job->next = jobs_head;
       if (NULL != jobs_head)
         jobs_head->prev = job;
       jobs_head = job;
       pthread_mutex_unlock (&jobs_lock);
       return job;
     }
     
     
     /**
      * Drop a reference.  Note that this never frees the job: the main
      * thread has to join the worker first, and only it may do that.  See
      * #reap_jobs().
      *
      * @param job the job to release
      */
     static void
     job_unref (struct Job *job)
     {
       pthread_mutex_lock (&job->lock);
       job->rc--;
       pthread_mutex_unlock (&job->lock);
     }
     
     
     /**
      * Called by the MHD side once MHD is done with the connection.  After
      * this returns, the worker will not touch the connection again.
      *
      * @param job the job to detach from its connection
      */
     static void
     job_detach (struct Job *job)
     {
       pthread_mutex_lock (&job->lock);
       job->abandoned = 1;
       job->connection = NULL;
       /* Wake the worker out of its sleep: if the client hung up in the
          middle of the transfer there is no point in producing the rest. */
       pthread_cond_signal (&job->cond);
       pthread_mutex_unlock (&job->lock);
       job_unref (job);
     }
     
     
     /**
      * Resume the connection of @a job if it is suspended.
      *
      * Must be called with @a job's lock held, and it deliberately calls
      * into MHD while holding it: the MHD thread has to take the very same
      * lock in #job_detach() before it can finish the connection, so as
      * long as we hold the lock the connection cannot go away underneath
      * us.  The reverse order never occurs---MHD invokes our callbacks
      * without holding any of its own locks that #MHD_resume_connection()
      * would need---so this cannot deadlock.
      *
      * @param job the job whose connection to resume
      */
     static void
     job_resume_locked (struct Job *job)
     {
       if ( (0 == job->suspended) ||
            (0 != job->abandoned) )
         return;
       job->suspended = 0;
       MHD_resume_connection (job->connection);
     }
     
     
     /**
      * Sleep for one step, or until the job is woken up.
      *
      * @param job the job to sleep on
      * @return non-zero if the worker should stop early
      */
     static int
     job_sleep (struct Job *job)
     {
       struct timespec ts;
       int stop;
     
       if (0 != clock_gettime (CLOCK_REALTIME,
                               &ts))
         return 1;
       ts.tv_sec += (time_t) (step_ms / 1000);
       ts.tv_nsec += (long) (step_ms % 1000) * 1000000L;
       if (1000000000L <= ts.tv_nsec)
       {
         ts.tv_nsec -= 1000000000L;
         ts.tv_sec++;
       }
       pthread_mutex_lock (&job->lock);
       while ( (0 == job->stop) &&
               (0 == job->abandoned) )
       {
         if (ETIMEDOUT == pthread_cond_timedwait (&job->cond,
                                                  &job->lock,
                                                  &ts))
           break;
       }
       stop = (0 != job->stop) || (0 != job->abandoned);
       pthread_mutex_unlock (&job->lock);
       return stop;
     }
     
     
     /**
      * Append @a len bytes from @a data to the job's payload buffer,
      * compacting the buffer first.  Must be called with @a job's lock
      * held.  A real application would need a policy for the case that the
      * client cannot keep up; here we simply drop the step, which cannot
      * happen with the sizes used in this example.
      *
      * @param job the job to append to
      * @param data the bytes to append
      * @param len the number of bytes to append
      */
     static void
     job_append_locked (struct Job *job,
                        const char *data,
                        size_t len)
     {
       if (0 != job->off)
       {
         memmove (job->payload,
                  &job->payload[job->off],
                  job->fill - job->off);
         job->fill -= job->off;
         job->off = 0;
       }
       if (len > MAX_PAYLOAD - job->fill)
         return;
       memcpy (&job->payload[job->fill],
               data,
               len);
       job->fill += len;
     }
     
     
     /**
      * The worker.  This stands in for whatever expensive computation,
      * database cursor or remote query a real application would run: it
      * produces one server-sent event per step and resumes the connection
      * whenever it has something new to offer.
      *
      * Note that the only MHD function this thread ever calls is
      * #MHD_resume_connection().  Building and queueing the response is the
      * business of the thread that runs the daemon.
      *
      * @param cls the `struct Job` to work on
      * @return always NULL
      */
     static void *
     worker (void *cls)
     {
       struct Job *job = cls;
       char event[256];
       unsigned int i;
       int len;
     
       for (i = 1; i <= total_steps; i++)
       {
         if (0 != job_sleep (job))
           break;
         if (0 != job->stream)
           len = snprintf (event,
                           sizeof (event),
                           "event: step\ndata: {\"n\":%u,\"total\":%u,"
                           "\"label\":\"step %u of %u done\"}\n\n",
                           i,
                           total_steps,
                           i,
                           total_steps);
         else
           len = snprintf (event,
                           sizeof (event),
                           "step %u of %u done\n",
                           i,
                           total_steps);
         if ( (0 >= len) ||
              (sizeof (event) <= (size_t) len) )
           break;
         pthread_mutex_lock (&job->lock);
         job_append_locked (job,
                            event,
                            (size_t) len);
         /* Only a streaming job has anything to show yet.  The other kind
            stays suspended until the very last step. */
         if (0 != job->stream)
           job_resume_locked (job);
         pthread_mutex_unlock (&job->lock);
       }
       if (0 != job->stream)
         len = snprintf (event,
                         sizeof (event),
                         "event: done\ndata: {\"n\":%u,\"total\":%u}\n\n",
                         total_steps,
                         total_steps);
       else
         len = snprintf (event,
                         sizeof (event),
                         "all %u steps done\n",
                         total_steps);
       pthread_mutex_lock (&job->lock);
       if ( (0 < len) &&
            (sizeof (event) > (size_t) len) )
         job_append_locked (job,
                            event,
                            (size_t) len);
       job->finished = 1;
       /* The last resume is not optional: if the connection were left
          suspended, nothing would ever wake it up again, and the daemon
          could not be stopped. */
       job_resume_locked (job);
       pthread_mutex_unlock (&job->lock);
       job_unref (job);
       return NULL;
     }
     
     
     /**
      * Start the worker thread of @a job.
      *
      * @param job the job whose worker to start
      * @return #MHD_YES on success
      */
     static enum MHD_Result
     job_start (struct Job *job)
     {
       pthread_mutex_lock (&jobs_lock);
       if (0 != pthread_create (&job->tid,
                                NULL,
                                &worker,
                                job))
       {
         pthread_mutex_unlock (&jobs_lock);
         return MHD_NO;
       }
       job->started = 1;
       pthread_mutex_unlock (&jobs_lock);
       return MHD_YES;
     }
     
     
     /**
      * Content reader for the "/events" stream.  This is the interesting
      * one: when the worker has produced nothing since the last call we
      * suspend the connection and return zero, instead of returning zero on
      * its own---which would make MHD ask again immediately and burn a CPU
      * core for the whole duration of the transfer.
      *
      * @param cls our `struct Job`
      * @param pos number of bytes already returned for this response
      * @param buf where to copy the data
      * @param max maximum number of bytes to copy to @a buf
      * @return number of bytes written to @a buf, 0 if the connection was
      *         suspended, MHD_CONTENT_READER_END_OF_STREAM at the end
      */
     static ssize_t
     stream_reader (void *cls,
                    uint64_t pos,
                    char *buf,
                    size_t max)
     {
       struct Job *job = cls;
       size_t ready;
     
       (void) pos;               /* Unused. Silent compiler warning. */
       pthread_mutex_lock (&job->lock);
       if (job->off == job->fill)
       {
         job->off = 0;
         job->fill = 0;
         if (0 != job->finished)
         {
           pthread_mutex_unlock (&job->lock);
           return MHD_CONTENT_READER_END_OF_STREAM;
         }
         /* Nothing to send yet.  Take the connection out of the event loop;
            the worker will put it back in. */
         job->suspended = 1;
         MHD_suspend_connection (job->connection);
         pthread_mutex_unlock (&job->lock);
         return 0;
       }
       ready = job->fill - job->off;
       if (ready > max)
         ready = max;
       memcpy (buf,
               &job->payload[job->off],
               ready);
       job->off += ready;
       pthread_mutex_unlock (&job->lock);
       return (ssize_t) ready;
     }
     
     
     /**
      * Called by MHD when the response object of an "/events" request is
      * destroyed, which happens for a completed transfer just as well as
      * for a client that went away in the middle of one.  This is the MHD
      * side of the job's reference count.
      *
      * @param cls our `struct Job`
      */
     static void
     stream_done (void *cls)
     {
       job_detach (cls);
     }
     
     
     /**
      * Handle "GET /events": queue a streaming response right away and let
      * the content reader deal with the fact that the data does not exist
      * yet.
      *
      * @param connection the connection to answer
      * @return #MHD_YES on success
      */
     static enum MHD_Result
     handle_events (struct MHD_Connection *connection)
     {
       struct MHD_Response *response;
       struct Job *job;
       enum MHD_Result ret;
     
       job = job_create (connection,
                         1);
       if (NULL == job)
         return MHD_NO;
       response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
                                                     IO_BLOCK_SIZE,
                                                     &stream_reader,
                                                     job,
                                                     &stream_done);
       if (NULL == response)
       {
         /* No response object exists, so nobody will call stream_done() for
            us; drop both references by hand.  The worker was never
            started. */
         job_unref (job);
         job_unref (job);
         return MHD_NO;
       }
       if (MHD_NO == job_start (job))
       {
         MHD_destroy_response (response);
         job_unref (job);
         return MHD_NO;
       }
       (void) MHD_add_response_header (response,
                                       MHD_HTTP_HEADER_CONTENT_TYPE,
                                       "text/event-stream");
       (void) MHD_add_response_header (response,
                                       MHD_HTTP_HEADER_CACHE_CONTROL,
                                       "no-cache");
       ret = MHD_queue_response (connection,
                                 MHD_HTTP_OK,
                                 response);
       MHD_destroy_response (response);
       return ret;
     }
     
     
     /**
      * Handle "GET /slow": the answer is only useful as a whole, so instead
      * of streaming we suspend the connection until the worker is done.
      * MHD then calls this function again---on its own thread---and that is
      * where the response is queued.  #MHD_queue_response() is never called
      * from the worker.
      *
      * @param connection the connection to answer
      * @param req_cls the per-request pointer, holding our `struct Job`
      * @return #MHD_YES on success
      */
     static enum MHD_Result
     handle_slow (struct MHD_Connection *connection,
                  void **req_cls)
     {
       struct MHD_Response *response;
       struct Job *job = *req_cls;
       char answer[MAX_PAYLOAD];
       size_t len;
       enum MHD_Result ret;
     
       if (NULL == job)
       {
         /* First call for this request: start the work and ask MHD to come
            back to us. */
         job = job_create (connection,
                           0);
         if (NULL == job)
           return MHD_NO;
         if (MHD_NO == job_start (job))
         {
           job_unref (job);
           job_unref (job);
           return MHD_NO;
         }
         *req_cls = job;
         return MHD_YES;
       }
       pthread_mutex_lock (&job->lock);
       if (0 == job->finished)
       {
         /* Still working.  Park the connection; the worker resumes it when
            it is done, and MHD will then enter this function once more. */
         job->suspended = 1;
         MHD_suspend_connection (connection);
         pthread_mutex_unlock (&job->lock);
         return MHD_YES;
       }
       len = job->fill - job->off;
       if (len > sizeof (answer))
         len = sizeof (answer);
       memcpy (answer,
               &job->payload[job->off],
               len);
       pthread_mutex_unlock (&job->lock);
     
       response = MHD_create_response_from_buffer_copy (len,
                                                        answer);
       if (NULL == response)
         return MHD_NO;
       (void) MHD_add_response_header (response,
                                       MHD_HTTP_HEADER_CONTENT_TYPE,
                                       "text/plain");
       ret = MHD_queue_response (connection,
                                 MHD_HTTP_OK,
                                 response);
       MHD_destroy_response (response);
       return ret;
     }
     
     
     /**
      * Queue a complete response that is already sitting in memory.
      *
      * @param connection the connection to answer
      * @param status the HTTP status code to use
      * @param mime the value for the "Content-Type" header
      * @param body the body to send
      * @return #MHD_YES on success
      */
     static enum MHD_Result
     queue_static (struct MHD_Connection *connection,
                   unsigned int status,
                   const char *mime,
                   const char *body)
     {
       struct MHD_Response *response;
       enum MHD_Result ret;
     
       response = MHD_create_response_from_buffer_copy (strlen (body),
                                                        body);
       if (NULL == response)
         return MHD_NO;
       (void) MHD_add_response_header (response,
                                       MHD_HTTP_HEADER_CONTENT_TYPE,
                                       mime);
       (void) MHD_add_response_header (response,
                                       MHD_HTTP_HEADER_CACHE_CONTROL,
                                       "no-store");
       ret = MHD_queue_response (connection,
                                 status,
                                 response);
       MHD_destroy_response (response);
       return ret;
     }
     
     
     static enum MHD_Result
     answer_to_connection (void *cls,
                           struct MHD_Connection *connection,
                           const char *url,
                           const char *method,
                           const char *version,
                           const char *upload_data,
                           size_t *upload_data_size,
                           void **req_cls)
     {
       (void) cls;               /* Unused. Silent compiler warning. */
       (void) version;           /* Unused. Silent compiler warning. */
       (void) upload_data;       /* Unused. Silent compiler warning. */
       (void) upload_data_size;  /* Unused. Silent compiler warning. */
     
       if (0 != strcmp (method,
                        MHD_HTTP_METHOD_GET))
         return MHD_NO;
       if (0 == strcmp (url,
                        "/"))
         return queue_static (connection,
                              MHD_HTTP_OK,
                              "text/html",
                              PAGE);
       if (0 == strcmp (url,
                        "/fast"))
         return queue_static (connection,
                              MHD_HTTP_OK,
                              "text/plain",
                              "pong\n");
       if ( (0 == strcmp (url,
                          "/events")) ||
            (0 == strcmp (url,
                          "/slow")) )
       {
         if (0 != shutdown_requested)
           return queue_static (connection,
                                MHD_HTTP_SERVICE_UNAVAILABLE,
                                "text/plain",
                                "shutting down\n");
         if (0 == strcmp (url,
                          "/events"))
           return handle_events (connection);
         return handle_slow (connection,
                             req_cls);
       }
       return queue_static (connection,
                            MHD_HTTP_NOT_FOUND,
                            "text/plain",
                            "not found\n");
     }
     
     
     /**
      * Called by MHD when a request is done.  For "/slow" this is where the
      * MHD side of the reference count is dropped; the other handlers leave
      * @a req_cls alone, so there is nothing to do for them.
      *
      * @param cls closure, unused
      * @param connection the connection that finished
      * @param req_cls the per-request pointer
      * @param toe why the request ended
      */
     static void
     request_completed (void *cls,
                        struct MHD_Connection *connection,
                        void **req_cls,
                        enum MHD_RequestTerminationCode toe)
     {
       struct Job *job = *req_cls;
     
       (void) cls;               /* Unused. Silent compiler warning. */
       (void) connection;        /* Unused. Silent compiler warning. */
       (void) toe;               /* Unused. Silent compiler warning. */
       if (NULL == job)
         return;
       *req_cls = NULL;
       job_detach (job);
     }
     
     
     /**
      * Free every job that nobody references any more, joining its worker
      * on the way.  Called from the main loop, and thus always from the
      * thread that also runs the daemon.
      */
     static void
     reap_jobs (void)
     {
       struct Job *job;
       struct Job *next;
       unsigned int rc;
     
       pthread_mutex_lock (&jobs_lock);
       for (job = jobs_head; NULL != job; job = next)
       {
         next = job->next;
         pthread_mutex_lock (&job->lock);
         rc = job->rc;
         pthread_mutex_unlock (&job->lock);
         if (0 != rc)
           continue;
         if ( (0 != job->started) &&
              (0 == job->joined) )
         {
           pthread_join (job->tid,
                         NULL);
           job->joined = 1;
         }
         if (NULL != job->prev)
           job->prev->next = job->next;
         else
           jobs_head = job->next;
         if (NULL != job->next)
           job->next->prev = job->prev;
         pthread_cond_destroy (&job->cond);
         pthread_mutex_destroy (&job->lock);
         free (job);
       }
       pthread_mutex_unlock (&jobs_lock);
     }
     
     
     /**
      * Ask every worker to stop and wait until they all did.
      *
      * This has to happen before the daemon is stopped: a worker that is
      * still asleep may be holding the only promise to resume a suspended
      * connection, and stopping a daemon that has suspended connections is
      * an API violation.  Once every worker has returned, no connection can
      * be suspended any more, because the workers resume before they exit
      * and the content reader only ever suspends while a worker is running.
      */
     static void
     stop_all_jobs (void)
     {
       struct Job *job;
     
       pthread_mutex_lock (&jobs_lock);
       for (job = jobs_head; NULL != job; job = job->next)
       {
         pthread_mutex_lock (&job->lock);
         job->stop = 1;
         pthread_cond_signal (&job->cond);
         pthread_mutex_unlock (&job->lock);
       }
       for (job = jobs_head; NULL != job; job = job->next)
       {
         if ( (0 != job->started) &&
              (0 == job->joined) )
         {
           pthread_join (job->tid,
                         NULL);
           job->joined = 1;
         }
       }
       pthread_mutex_unlock (&jobs_lock);
     }
     
     
     /**
      * Number of connections the daemon is currently handling.
      *
      * @param daemon the daemon to query
      * @return the number of connections, 0 if it cannot be determined
      */
     static unsigned int
     connection_count (struct MHD_Daemon *daemon)
     {
       const union MHD_DaemonInfo *info;
     
       info = MHD_get_daemon_info (daemon,
                                   MHD_DAEMON_INFO_CURRENT_CONNECTIONS);
       if (NULL == info)
         return 0;
       return info->num_connections;
     }
     
     
     int
     main (int argc,
           char *const *argv)
     {
       struct MHD_Daemon *daemon;
       const union MHD_DaemonInfo *info;
       struct sigaction sa;
       fd_set rs;
       fd_set ws;
       fd_set es;
       struct timeval tv;
       struct timeval *tvp;
       MHD_socket max;
       uint64_t mhd_timeout;
       unsigned long port = DEFAULT_PORT;
       unsigned int drained_ms = 0;
       char drain_buf[64];
       int draining = 0;
       int ret = 0;
     
       if (1 < argc)
         port = strtoul (argv[1],
                         NULL,
                         10);
       if (2 < argc)
         step_ms = (unsigned int) strtoul (argv[2],
                                           NULL,
                                           10);
       if (3 < argc)
         total_steps = (unsigned int) strtoul (argv[3],
                                               NULL,
                                               10);
       if ( (65535 < port) ||
            (0 == total_steps) )
       {
         fprintf (stderr,
                  "Usage: %s [PORT [STEP_MS [STEPS]]]\n"
                  "Pass 0 as PORT to let the system pick a free one.\n",
                  argv[0]);
         return 1;
       }
     
       if (0 > pipe (wake_pipe))
       {
         fprintf (stderr,
                  "Failed to create wakeup pipe: %s\n",
                  strerror (errno));
         return 1;
       }
       memset (&sa,
               0,
               sizeof (sa));
       sa.sa_handler = &signal_handler;
       sigaction (SIGINT,
                  &sa,
                  NULL);
       sigaction (SIGTERM,
                  &sa,
                  NULL);
       sa.sa_handler = SIG_IGN;
       sigaction (SIGPIPE,
                  &sa,
                  NULL);
     
       /* No MHD_USE_INTERNAL_POLLING_THREAD: the loop below is ours.
          MHD_ALLOW_SUSPEND_RESUME implies MHD_USE_ITC, and that channel is
          what lets a worker thread break us out of the select() call. */
       daemon = MHD_start_daemon (MHD_ALLOW_SUSPEND_RESUME | MHD_USE_ERROR_LOG,
                                  (uint16_t) port,
                                  NULL, NULL,
                                  &answer_to_connection, NULL,
                                  MHD_OPTION_NOTIFY_COMPLETED,
                                  &request_completed, NULL,
                                  MHD_OPTION_END);
       if (NULL == daemon)
       {
         fprintf (stderr,
                  "Failed to start daemon.\n");
         return 1;
       }
       info = MHD_get_daemon_info (daemon,
                                   MHD_DAEMON_INFO_BIND_PORT);
       if ( (NULL == info) ||
            (0 == info->port) )
       {
         fprintf (stderr,
                  "Failed to determine bound port.\n");
         MHD_stop_daemon (daemon);
         return 1;
       }
       printf ("Listening on port %u\n",
               (unsigned int) info->port);
       fflush (stdout);
     
       while (1)
       {
         if ( (0 != shutdown_requested) &&
              (0 == draining) )
         {
           /* Every worker has to be gone before the daemon may be stopped. */
           stop_all_jobs ();
           draining = 1;
         }
         if ( (0 != draining) &&
              ( (0 == connection_count (daemon)) ||
                (DRAIN_TIMEOUT_MS <= drained_ms) ) )
           break;
     
         FD_ZERO (&rs);
         FD_ZERO (&ws);
         FD_ZERO (&es);
         max = 0;
         if (MHD_YES != MHD_get_fdset (daemon,
                                       &rs,
                                       &ws,
                                       &es,
                                       &max))
         {
           fprintf (stderr,
                    "Failed to obtain the file descriptor set.\n");
           ret = 1;
           break;
         }
         /* Our own descriptors go into the very same sets. */
         FD_SET (wake_pipe[0],
                 &rs);
         if (max < wake_pipe[0])
           max = wake_pipe[0];
     
         if (0 != draining)
         {
           /* Look at the drain deadline regularly. */
           tv.tv_sec = 0;
           tv.tv_usec = 50 * 1000;
           tvp = &tv;
           drained_ms += 50;
         }
         else if (MHD_YES == MHD_get_timeout64 (daemon,
                                                &mhd_timeout))
         {
           tv.tv_sec = (time_t) (mhd_timeout / 1000);
           tv.tv_usec = ((long) (mhd_timeout % 1000)) * 1000;
           tvp = &tv;
         }
         else
         {
           /* MHD has nothing to wait for.  With every connection suspended
              this is the normal case, and the loop simply sleeps until a
              worker resumes one---which reaches us through MHD's ITC, as it
              is part of the read set above. */
           tvp = NULL;
         }
     
         if (-1 == select ((int) max + 1,
                           &rs,
                           &ws,
                           &es,
                           tvp))
         {
           if (EINTR == errno)
             continue;
           fprintf (stderr,
                    "Aborting due to error during select: %s\n",
                    strerror (errno));
           ret = 1;
           break;
         }
         if (FD_ISSET (wake_pipe[0],
                       &rs))
           (void) read (wake_pipe[0],
                        drain_buf,
                        sizeof (drain_buf));
         MHD_run_from_select (daemon,
                              &rs,
                              &ws,
                              &es);
         reap_jobs ();
       }
     
       stop_all_jobs ();
       reap_jobs ();
       MHD_stop_daemon (daemon);
       close (wake_pipe[0]);
       close (wake_pipe[1]);
       return ret;
     }


File: libmicrohttpd-tutorial.info,  Node: tlsauthentication.c,  Next: upgrade.c,  Prev: asyncresponse.c,  Up: Example programs

C.10 tlsauthentication.c
========================

     /* Feel free to use this example code in any way
        you see fit (Public Domain) */
     
     #include <sys/types.h>
     #ifndef _WIN32
     #include <sys/select.h>
     #include <sys/socket.h>
     #else
     #include <winsock2.h>
     #endif
     #include <microhttpd.h>
     #include <string.h>
     #include <stdio.h>
     #include <stdlib.h>
     
     #define PORT 8888
     
     #define REALM     "Maintenance"
     #define USER      "a legitimate user"
     #define PASSWORD  "and his password"
     
     #define SERVERKEYFILE "server.key"
     #define SERVERCERTFILE "server.pem"
     
     
     static size_t
     get_file_size (const char *filename)
     {
       FILE *fp;
     
       fp = fopen (filename, "rb");
       if (fp)
       {
         long size;
     
         if ((0 != fseek (fp, 0, SEEK_END)) || (-1 == (size = ftell (fp))))
           size = 0;
     
         fclose (fp);
     
         return (size_t) size;
       }
       else
         return 0;
     }
     
     
     static char *
     load_file (const char *filename)
     {
       FILE *fp;
       char *buffer;
       size_t size;
     
       size = get_file_size (filename);
       if (0 == size)
         return NULL;
     
       fp = fopen (filename, "rb");
       if (! fp)
         return NULL;
     
       buffer = malloc (size + 1);
       if (! buffer)
       {
         fclose (fp);
         return NULL;
       }
       buffer[size] = '\0';
     
       if (size != fread (buffer, 1, size, fp))
       {
         free (buffer);
         buffer = NULL;
       }
     
       fclose (fp);
       return buffer;
     }
     
     
     static enum MHD_Result
     ask_for_authentication (struct MHD_Connection *connection, const char *realm)
     {
       enum MHD_Result ret;
       struct MHD_Response *response;
     
       response = MHD_create_response_empty (MHD_RF_NONE);
       if (! response)
         return MHD_NO;
     
       ret = MHD_queue_basic_auth_required_response3 (connection,
                                                      realm,
                                                      MHD_YES,
                                                      response);
       MHD_destroy_response (response);
       return ret;
     }
     
     
     static int
     is_authenticated (struct MHD_Connection *connection,
                       const char *username,
                       const char *password)
     {
       struct MHD_BasicAuthInfo *auth_info;
       int authenticated;
     
       auth_info = MHD_basic_auth_get_username_password3 (connection);
       if (NULL == auth_info)
         return 0;
       authenticated =
         ( (strlen (username) == auth_info->username_len) &&
           (0 == memcmp (auth_info->username, username, auth_info->username_len)) &&
           /* The next check against NULL is optional,
            * if 'password' is NULL then 'password_len' is always zero. */
           (NULL != auth_info->password) &&
           (strlen (password) == auth_info->password_len) &&
           (0 == memcmp (auth_info->password, password, auth_info->password_len)) );
     
       MHD_free (auth_info);
     
       return authenticated;
     }
     
     
     static enum MHD_Result
     secret_page (struct MHD_Connection *connection)
     {
       enum MHD_Result ret;
       struct MHD_Response *response;
       const char *page = "<html><body>A secret.</body></html>";
     
       response = MHD_create_response_from_buffer_static (strlen (page), page);
       if (! response)
         return MHD_NO;
     
       ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
       MHD_destroy_response (response);
     
       return ret;
     }
     
     
     static enum MHD_Result
     answer_to_connection (void *cls, struct MHD_Connection *connection,
                           const char *url, const char *method,
                           const char *version, const char *upload_data,
                           size_t *upload_data_size, void **req_cls)
     {
       (void) cls;               /* Unused. Silent compiler warning. */
       (void) url;               /* Unused. Silent compiler warning. */
       (void) version;           /* Unused. Silent compiler warning. */
       (void) upload_data;       /* Unused. Silent compiler warning. */
       (void) upload_data_size;  /* Unused. Silent compiler warning. */
     
       if (0 != strcmp (method, "GET"))
         return MHD_NO;
       if (NULL == *req_cls)
       {
         *req_cls = connection;
         return MHD_YES;
       }
     
       if (! is_authenticated (connection, USER, PASSWORD))
         return ask_for_authentication (connection, REALM);
     
       return secret_page (connection);
     }
     
     
     int
     main (void)
     {
       struct MHD_Daemon *daemon;
       char *key_pem;
       char *cert_pem;
     
       key_pem = load_file (SERVERKEYFILE);
       cert_pem = load_file (SERVERCERTFILE);
     
       if ((key_pem == NULL) || (cert_pem == NULL))
       {
         printf ("The key/certificate files could not be read.\n");
         if (NULL != key_pem)
           free (key_pem);
         if (NULL != cert_pem)
           free (cert_pem);
         return 1;
       }
     
       daemon =
         MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_TLS, PORT, NULL,
                           NULL, &answer_to_connection, NULL,
                           MHD_OPTION_HTTPS_MEM_KEY, key_pem,
                           MHD_OPTION_HTTPS_MEM_CERT, cert_pem, MHD_OPTION_END);
       if (NULL == daemon)
       {
         printf ("%s\n", cert_pem);
     
         free (key_pem);
         free (cert_pem);
     
         return 1;
       }
     
       (void) getchar ();
     
       MHD_stop_daemon (daemon);
       free (key_pem);
       free (cert_pem);
     
       return 0;
     }


File: libmicrohttpd-tutorial.info,  Node: upgrade.c,  Prev: tlsauthentication.c,  Up: Example programs

C.11 upgrade.c
==============

     /* Feel free to use this example code in any way
        you see fit (Public Domain) */
     
     /**
      * @file upgrade.c
      * @brief   Minimal example for the HTTP "Upgrade" API of libmicrohttpd.
      *          A "GET /" carrying "Connection: Upgrade" and "Upgrade: echo"
      *          is answered with "101 Switching Protocols"; afterwards the
      *          raw socket speaks a trivial line-based echo protocol until
      *          the client sends the line "QUIT" or closes the connection.
      * @author  Christian Grothoff
      */
     
     #include <sys/types.h>
     #ifndef _WIN32
     #include <sys/select.h>
     #include <sys/socket.h>
     #include <fcntl.h>
     #else
     #include <winsock2.h>
     #endif
     #include <microhttpd.h>
     #include <stdio.h>
     #include <stdlib.h>
     #include <string.h>
     #include <errno.h>
     
     #define PORT 8888
     
     /**
      * Name of the protocol we are willing to switch to.  Any name would
      * do; "echo" is not registered with IANA and is only used here to keep
      * the example self-contained.
      */
     #define PROTOCOL "echo"
     
     /**
      * Maximum length of a line of the echo protocol.  Longer lines are
      * truncated.
      */
     #define LINE_SIZE 1024
     
     #define PAGE_UPGRADE_REQUIRED \
       "This resource speaks the \"" PROTOCOL "\" protocol only.\n"
     
     #define PAGE_NOT_FOUND \
       "Not found.\n"
     
     
     /**
      * State of the line-based echo protocol for one connection.
      */
     struct EchoState
     {
       /**
        * Bytes of the line received so far (without the line terminator).
        */
       char line[LINE_SIZE];
     
       /**
        * Number of valid bytes in @e line.
        */
       size_t line_len;
     };
     
     
     /**
      * Compare the first @a len bytes of @a a and @a b, ignoring case.
      * Only ASCII letters are folded, which is all HTTP tokens may contain.
      *
      * @param a first string
      * @param b second string
      * @param len number of bytes to compare
      * @return 1 if the strings match, 0 if they do not
      */
     static int
     equal_caseless (const char *a,
                     const char *b,
                     size_t len)
     {
       size_t i;
     
       for (i = 0; i < len; i++)
       {
         char ca = a[i];
         char cb = b[i];
     
         if (('A' <= ca) && ('Z' >= ca))
           ca = (char) (ca - 'A' + 'a');
         if (('A' <= cb) && ('Z' >= cb))
           cb = (char) (cb - 'A' + 'a');
         if (ca != cb)
           return 0;
       }
       return 1;
     }
     
     
     /**
      * Check whether the comma-separated list @a value contains the token
      * @a token.  Both the "Connection:" and the "Upgrade:" request header
      * fields are lists, so a client may legitimately send
      * "Connection: keep-alive, Upgrade"; a plain string comparison against
      * the whole field value would reject such a request.
      *
      * @param value the header field value, may be NULL
      * @param token the token to look for, compared case-insensitively
      * @return 1 if @a token is one of the tokens in @a value, 0 if not
      */
     static int
     has_token (const char *value,
                const char *token)
     {
       const size_t token_len = strlen (token);
       const char *pos = value;
     
       if (NULL == value)
         return 0;
       while ('\0' != *pos)
       {
         const char *end;
         size_t len;
     
         /* skip separators and optional whitespace before the token */
         while ((',' == *pos) || (' ' == *pos) || ('\t' == *pos))
           pos++;
         end = pos;
         while (('\0' != *end) && (',' != *end))
           end++;
         len = (size_t) (end - pos);
         /* strip optional whitespace after the token */
         while ((0 != len) &&
                ((' ' == pos[len - 1]) || ('\t' == pos[len - 1])))
           len--;
         if ((len == token_len) &&
             (equal_caseless (pos, token, token_len)))
           return 1;
         pos = end;
         if ('\0' != *pos)
           pos++;   /* skip the comma */
       }
       return 0;
     }
     
     
     /**
      * Send @a len bytes from @a buf over @a sock, retrying until either
      * everything was sent or the connection broke.
      *
      * @param sock the socket to write to
      * @param buf the data to send
      * @param len number of bytes in @a buf
      * @return 1 on success, 0 if the connection broke
      */
     static int
     send_all (MHD_socket sock,
               const char *buf,
               size_t len)
     {
       ssize_t ret;
       size_t off;
     
       for (off = 0; off < len; off += (size_t) ret)
       {
         ret = send (sock,
                     buf + off,
                     (int) (len - off),
                     0);
         if (0 > ret)
         {
           if (EINTR == errno)
           {
             ret = 0;
             continue;
           }
           return 0;
         }
         if (0 == ret)
           return 0;
       }
       return 1;
     }
     
     
     /**
      * Make @a sock blocking.  MHD hands out the socket in non-blocking
      * mode, see the tutorial chapter for the reason why.  This function
      * contains the only operating-system-dependent code of this example.
      *
      * @param sock the socket to modify
      */
     static void
     make_blocking (MHD_socket sock)
     {
     #ifndef _WIN32
       int flags;
     
       flags = fcntl (sock, F_GETFL);
       if (-1 == flags)
         abort ();
       if ((flags & ~O_NONBLOCK) != flags)
         if (-1 == fcntl (sock, F_SETFL, flags & ~O_NONBLOCK))
           abort ();
     #else  /* _WIN32 */
       unsigned long flags = 0;
     
       if (0 != ioctlsocket (sock, (int) FIONBIO, &flags))
         abort ();
     #endif /* _WIN32 */
     }
     
     
     /**
      * Feed @a size bytes of received data into the echo protocol state
      * machine, echoing back every complete line.
      *
      * @param sock the socket to echo to
      * @param es the protocol state of this connection
      * @param data the received bytes
      * @param size number of bytes in @a data
      * @return 1 if the client asked us to stop or the connection broke,
      *         0 if we should keep going
      */
     static int
     echo_feed (MHD_socket sock,
                struct EchoState *es,
                const char *data,
                size_t size)
     {
       size_t i;
     
       for (i = 0; i < size; i++)
       {
         if ('\n' != data[i])
         {
           if (es->line_len < sizeof (es->line))
             es->line[es->line_len++] = data[i];
           /* else: line too long, drop the excess bytes */
           continue;
         }
         /* A complete line was received; drop the CR of a CRLF terminator */
         if ((0 != es->line_len) &&
             ('\r' == es->line[es->line_len - 1]))
           es->line_len--;
         if ((4 == es->line_len) &&
             (equal_caseless (es->line, "QUIT", 4)))
         {
           (void) send_all (sock, "BYE\r\n", 5);
           es->line_len = 0;
           return 1;
         }
         if ((! send_all (sock, es->line, es->line_len)) ||
             (! send_all (sock, "\r\n", 2)))
           return 1;
         es->line_len = 0;
       }
       return 0;
     }
     
     
     /**
      * Called by MHD once the "101 Switching Protocols" response was sent.
      * From here on MHD is out of the picture: @a sock is an ordinary
      * socket and we are free to speak whatever protocol we like on it.
      *
      * As the daemon runs with #MHD_USE_THREAD_PER_CONNECTION, this
      * function has a thread of its own and may block for as long as it
      * wants.
      *
      * @param cls closure given to #MHD_create_response_for_upgrade()
      * @param connection the original HTTP connection
      * @param req_cls last value of @a req_cls of the access handler
      * @param extra_in bytes the client sent after the request header and
      *                 which MHD read together with the header
      * @param extra_in_size number of bytes in @a extra_in
      * @param sock the socket to talk to the client on
      * @param urh handle to pass to #MHD_upgrade_action()
      */
     static void
     upgrade_handler (void *cls,
                      struct MHD_Connection *connection,
                      void *req_cls,
                      const char *extra_in,
                      size_t extra_in_size,
                      MHD_socket sock,
                      struct MHD_UpgradeResponseHandle *urh)
     {
       struct EchoState es;
       char buf[256];
       ssize_t got;
       int done;
     
       (void) cls;         /* Unused. Silent compiler warning. */
       (void) connection;  /* Unused. Silent compiler warning. */
       (void) req_cls;     /* Unused. Silent compiler warning. */
     
       /* MHD hands out a non-blocking socket; this example wants to use
          plain blocking recv()/send() calls on it. */
       make_blocking (sock);
     
       es.line_len = 0;
     
       /* The client may have pipelined payload directly behind the request
          header, in which case MHD has read it already.  Those bytes are
          gone from the socket, so they must be processed first. */
       done = echo_feed (sock,
                         &es,
                         extra_in,
                         extra_in_size);
     
       while (0 == done)
       {
         got = recv (sock,
                     buf,
                     sizeof (buf),
                     0);
         if (0 > got)
         {
           if (EINTR == errno)
             continue;
           break;            /* read error */
         }
         if (0 == got)
           break;            /* client closed the connection */
         done = echo_feed (sock,
                           &es,
                           buf,
                           (size_t) got);
       }
     
       /* Hand the socket back to MHD.  This is the only legal way to get
          rid of it; never call close() on it ourselves, and note that the
          connection is not cleaned up before this call happens. */
       MHD_upgrade_action (urh,
                           MHD_UPGRADE_ACTION_CLOSE);
     }
     
     
     /**
      * Answer an ordinary HTTP request from a static string.
      *
      * @param connection the connection to answer
      * @param status_code the HTTP status code to use
      * @param page the response body
      * @param offer_upgrade if true, advertise our protocol in an
      *                      "Upgrade:" header field
      * @return #MHD_YES on success, #MHD_NO on error
      */
     static enum MHD_Result
     answer_plain (struct MHD_Connection *connection,
                   unsigned int status_code,
                   const char *page,
                   int offer_upgrade)
     {
       struct MHD_Response *response;
       enum MHD_Result ret;
     
       response = MHD_create_response_from_buffer_static (strlen (page),
                                                          page);
       if (NULL == response)
         return MHD_NO;
       if (offer_upgrade)
         (void) MHD_add_response_header (response,
                                         MHD_HTTP_HEADER_UPGRADE,
                                         PROTOCOL);
       ret = MHD_queue_response (connection,
                                 status_code,
                                 response);
       MHD_destroy_response (response);
       return ret;
     }
     
     
     static enum MHD_Result
     access_handler (void *cls,
                     struct MHD_Connection *connection,
                     const char *url,
                     const char *method,
                     const char *version,
                     const char *upload_data,
                     size_t *upload_data_size,
                     void **req_cls)
     {
       struct MHD_Response *response;
       enum MHD_Result ret;
     
       (void) cls;               /* Unused. Silent compiler warning. */
       (void) upload_data;       /* Unused. Silent compiler warning. */
       (void) upload_data_size;  /* Unused. Silent compiler warning. */
       (void) req_cls;           /* Unused. Silent compiler warning. */
     
       if (0 != strcmp (url, "/"))
         return answer_plain (connection,
                              MHD_HTTP_NOT_FOUND,
                              PAGE_NOT_FOUND,
                              0);
       /* Upgrading requires HTTP/1.1 and a request that actually asks for
          our protocol.  A client that does not ask gets a plain 426. */
       if ((0 != strcmp (method, MHD_HTTP_METHOD_GET)) ||
           (0 != strcmp (version, MHD_HTTP_VERSION_1_1)) ||
           (! has_token (MHD_lookup_connection_value (connection,
                                                      MHD_HEADER_KIND,
                                                      MHD_HTTP_HEADER_CONNECTION),
                         "Upgrade")) ||
           (! has_token (MHD_lookup_connection_value (connection,
                                                      MHD_HEADER_KIND,
                                                      MHD_HTTP_HEADER_UPGRADE),
                         PROTOCOL)))
         return answer_plain (connection,
                              MHD_HTTP_UPGRADE_REQUIRED,
                              PAGE_UPGRADE_REQUIRED,
                              1);
     
       /* The request is fine, switch protocols.  MHD already put
          "Connection: Upgrade" into the response for us, we only have to
          name the protocol we switch to. */
       response = MHD_create_response_for_upgrade (&upgrade_handler,
                                                   NULL);
       if (NULL == response)
         return MHD_NO;
       if (MHD_YES !=
           MHD_add_response_header (response,
                                    MHD_HTTP_HEADER_UPGRADE,
                                    PROTOCOL))
       {
         MHD_destroy_response (response);
         return MHD_NO;
       }
       ret = MHD_queue_response (connection,
                                 MHD_HTTP_SWITCHING_PROTOCOLS,
                                 response);
       /* The response may be destroyed right away: MHD keeps its own
          reference until the upgrade handler has been called. */
       MHD_destroy_response (response);
       return ret;
     }
     
     
     int
     main (void)
     {
       struct MHD_Daemon *daemon;
     
       daemon = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
                                  | MHD_USE_INTERNAL_POLLING_THREAD
                                  | MHD_ALLOW_UPGRADE
                                  | MHD_USE_ERROR_LOG,
                                  PORT, NULL, NULL,
                                  &access_handler, NULL,
                                  MHD_OPTION_END);
       if (NULL == daemon)
         return 1;
     
       (void) getchar ();
     
       MHD_stop_daemon (daemon);
       return 0;
     }



Tag Table:
Node: Top880
Node: Introduction2035
Node: Hello browser example3340
Node: Exploring requests15307
Node: Response headers20835
Node: Supporting basic authentication28169
Node: Processing POST data38545
Node: Improved processing of POST data47472
Node: Session management59717
Node: Generating responses on the fly63414
Node: Answering from another thread82089
Node: Adding a layer of security101122
Node: Upgrading connections116114
Node: Bibliography134581
Node: License text135901
Node: Example programs161060
Node: hellobrowser.c161430
Node: logging.c163561
Node: responseheaders.c165725
Node: basicauthentication.c169256
Node: simplepost.c173194
Node: largepost.c180403
Node: sessions.c191718
Node: callbackresponse.c219130
Node: asyncresponse.c228980
Node: tlsauthentication.c268825
Node: upgrade.c274892

End Tag Table


Local Variables:
coding: utf-8
End:
