diff --git a/doc/Makefile.am b/doc/Makefile.am
index 3a236cc9..34428fb5 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -24,6 +24,7 @@ microhttpd_TEXINFOS = \
microhttpd_tutorial_TEXINFOS = \
chapters/basicauthentication.inc \
chapters/bibliography.inc \
+ chapters/callbackresponse.inc \
chapters/exploringrequests.inc \
chapters/hellobrowser.inc \
chapters/introduction.inc \
@@ -32,7 +33,7 @@ microhttpd_tutorial_TEXINFOS = \
chapters/responseheaders.inc \
chapters/tlsauthentication.inc \
chapters/sessions.inc \
- chapters/websocket.inc
+ chapters/upgrade.inc
EXTRA_DIST = \
$(microhttpd_TEXINFOS) $(microhttpd_tutorial_TEXINFOS) \
diff --git a/doc/chapters/basicauthentication.inc b/doc/chapters/basicauthentication.inc
index ec0dd386..70da1d73 100644
--- a/doc/chapters/basicauthentication.inc
+++ b/doc/chapters/basicauthentication.inc
@@ -30,7 +30,7 @@ start there. It will, however, turn out to have still severe weaknesses in
terms of security which need consideration.
Before we will start implementing @emph{Basic Authentication} as described in
-@emph{RFC 2617}, we will also abandon the simplistic and generally
+@emph{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!).
@@ -64,8 +64,9 @@ application should suspend the connection).
@end enumerate
But how can we tell whether the callback has been called before for the
-particular request? Initially, the pointer this parameter references is
-set by @emph{MHD} in the callback. But it will also be "remembered" on the
+particular request? This is what the @code{req_cls} parameter of the callback
+is for: initially, the pointer it references is set to NULL by @emph{MHD}.
+But whatever we store there will be "remembered" on the
next call (for the same request). Thus, we can use the @code{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
@@ -77,7 +78,7 @@ will be pointing to a legal address, so we take this.
The first time @code{answer_to_connection} is called, we will not even look at the headers.
@verbatim
-static int
+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,
@@ -104,11 +105,13 @@ correct username/password, so every "GET" request will be challenged.
@emph{RFC 7617} describes how the server shall ask for authentication by
adding a @emph{WWW-Authenticate} response header with the name of the
@emph{realm} protected. MHD can generate and queue such a failure response
-for you using the @code{MHD_queue_basic_auth_fail_response} API. The only
+for you using the @code{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
-@code{MHD_basic_auth_get_username_password} call.
+@code{MHD_basic_auth_get_username_password3} call. (The older
+@code{MHD_queue_basic_auth_fail_response} and
+@code{MHD_basic_auth_get_username_password} calls are deprecated.)
Your code would then look like this:
@verbatim
@@ -135,10 +138,10 @@ answer_to_connection (void *cls, struct MHD_Connection *connection,
static const char *page =
"
Authorization required";
response = MHD_create_response_from_buffer_static (strlen (page), page);
- ret = MHD_queue_basic_auth_fail_response3 (connection,
- "admins",
- MHD_YES,
- response);
+ 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",
@@ -153,10 +156,10 @@ answer_to_connection (void *cls, struct MHD_Connection *connection,
static const char *page =
"Wrong username or password";
response = MHD_create_response_from_buffer_static (strlen (page), page);
- ret = MHD_queue_basic_auth_fail_response3 (connection,
- "admins",
- MHD_YES,
- response);
+ ret = MHD_queue_basic_auth_required_response3 (connection,
+ "admins",
+ MHD_YES,
+ response);
}
else
{
diff --git a/doc/chapters/bibliography.inc b/doc/chapters/bibliography.inc
index bdaa6187..db3ad695 100644
--- a/doc/chapters/bibliography.inc
+++ b/doc/chapters/bibliography.inc
@@ -1,16 +1,16 @@
@heading API reference
@itemize @bullet
@item
-The @emph{GNU libmicrohttpd} manual by Marco Maggi and Christian Grothoff 2008
-@uref{http://gnunet.org/libmicrohttpd/microhttpd.html}
+The @emph{GNU libmicrohttpd} manual by Marco Maggi and Christian Grothoff
+@uref{https://www.gnu.org/software/libmicrohttpd/manual/libmicrohttpd.html}
@item
All referenced RFCs can be found on the website of @emph{The Internet Engineering Task Force}
-@uref{http://www.ietf.org/}
+@uref{https://www.ietf.org/}
@item
-@emph{RFC 2616}: Fielding, R., Gettys, J., Mogul, J., Frystyk, H., and T. Berners-Lee,
-"Hypertext Transfer Protocol -- HTTP/1.1", RFC 2016, January 1997.
+@emph{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.
@item
@emph{RFC 2617}: Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, S., Leach, P.,
@@ -20,13 +20,14 @@ Luotonen, A., and L. Stewart, "HTTP Authentication: Basic and Digest Access Auth
@emph{RFC 6455}: Fette, I., Melnikov, A., "The WebSocket Protocol", RFC 6455, December 2011.
-@item
+@item
A well--structured @emph{HTML} reference can be found on
@uref{http://www.echoecho.com/html.htm}
-For those readers understanding German or French, there is an excellent document both for learning
-@emph{HTML} and for reference, whose English version unfortunately has been discontinued.
-@uref{http://de.selfhtml.org/} and @uref{http://fr.selfhtml.org/}
+For those readers understanding German, there is an excellent document both for learning
+@emph{HTML} and for reference, whose English and French versions unfortunately have been
+discontinued.
+@uref{https://wiki.selfhtml.org/}
@end itemize
diff --git a/doc/chapters/callbackresponse.inc b/doc/chapters/callbackresponse.inc
new file mode 100644
index 00000000..61335ee4
--- /dev/null
+++ b/doc/chapters/callbackresponse.inc
@@ -0,0 +1,467 @@
+All responses we have built so far were complete before they were
+queued. @code{MHD_create_response_from_buffer()} needs the whole
+answer to be sitting in memory already, and
+@code{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 @emph{libmicrohttpd} lets the application hand over a
+callback instead of the data. Whenever @emph{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.
+
+
+@heading Creating the response
+
+The response object is created with
+
+@verbatim
+struct MHD_Response *
+MHD_create_response_from_callback (uint64_t size,
+ size_t block_size,
+ MHD_ContentReaderCallback crc,
+ void *crc_cls,
+ MHD_ContentReaderFreeCallback crfc);
+@end verbatim
+@noindent
+
+The five arguments are:
+
+@table @code
+@item size
+The total length of the body in bytes, or the constant
+@code{MHD_SIZE_UNKNOWN} if the application does not know it in
+advance. If a concrete number is given, @emph{MHD} announces it as
+@code{Content-Length} and expects the callback to deliver exactly that
+many bytes.
+
+@item block_size
+The buffer size @emph{MHD} should use when it queries the callback.
+The value must not be zero---@code{MHD_create_response_from_callback()}
+returns @code{NULL} otherwise. @emph{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 @code{block_size} has no influence on how much
+@emph{MHD} asks for. In either case the value is advisory: the
+callback must always look at the @code{max} argument it is passed and
+never write more than that.
+
+@item crc
+The content reader callback itself, described in the next section.
+
+@item crc_cls
+An arbitrary pointer that is passed back to @code{crc} on every
+invocation. This is where the per-request state goes.
+
+@item crfc
+A callback that is invoked once, when the response object is
+destroyed, so that @code{crc_cls} can be released. May be
+@code{NULL} if there is nothing to clean up.
+@end table
+
+
+@heading The content reader callback
+
+The callback has the following signature:
+
+@verbatim
+typedef ssize_t
+(*MHD_ContentReaderCallback) (void *cls,
+ uint64_t pos,
+ char *buf,
+ size_t max);
+@end verbatim
+@noindent
+
+@code{cls} is the @code{crc_cls} pointer given at creation time.
+@code{buf} points to the memory @emph{MHD} wants filled and
+@code{max} is the number of bytes that may be written there.
+
+The @code{pos} argument deserves a closer look, because its meaning
+depends on how the response is used. For a response created from a
+file descriptor, @emph{MHD} uses it as a file offset and reads with
+@code{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---@emph{MHD} guarantees that
+@code{pos} is simply the sum of all non-negative values the callback
+has returned so far. In other words: for a stream, @code{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 @code{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 @emph{MHD} what happened:
+
+@table @asis
+@item a positive number
+That many bytes were written to @code{buf}. Returning more than
+@code{max} is a fatal application error and makes @emph{MHD} close the
+connection.
+
+@item @code{MHD_CONTENT_READER_END_OF_STREAM}
+The body is complete. With chunked encoding @emph{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 @code{size} was announced, ending the stream early is not
+legal, and @emph{MHD} treats it essentially like an error---the client
+receives fewer bytes than the @code{Content-Length} promised.
+
+@item @code{MHD_CONTENT_READER_END_WITH_ERROR}
+Something went wrong while generating the data; see below.
+
+@item @code{0}
+No data is available @emph{right now}, but the stream is not over.
+@end table
+
+@noindent
+That last case is the dangerous one. The header file states that
+returning zero is legal only when @emph{MHD} is @emph{not} using an
+internal sockets polling mode, and this is not a formality:
+@emph{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
+@code{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.
+
+
+@heading Keeping state per request
+
+Because the callback is a plain C function, everything it needs to
+know has to travel through @code{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
+@code{crc_cls}, and let the free callback dispose of both.
+
+@verbatim
+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 */
+};
+@end verbatim
+@noindent
+
+The two offsets are what make the buffer independent of @emph{MHD}'s
+appetite. A block is generated once and may then be handed out over
+several invocations, because @code{max} can be smaller than what we
+have ready:
+
+@verbatim
+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;
+}
+@end verbatim
+@noindent
+
+@code{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:
+
+@verbatim
+ 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);
+@end verbatim
+@noindent
+
+Note the error path: as long as
+@code{MHD_create_response_from_callback()} has not returned a response,
+the free callback will never run and the application must clean up
+itself.
+
+
+@heading Releasing the state
+
+The free callback is trivial:
+
+@verbatim
+static void
+free_context (void *cls)
+{
+ struct ResponseContext *ctx = cls;
+
+ free (ctx->buf);
+ free (ctx);
+}
+@end verbatim
+@noindent
+
+@emph{MHD} invokes it when the last reference to the response object
+goes away. The call to @code{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.
+
+
+@heading Unknown size and chunked encoding
+
+Passing @code{MHD_SIZE_UNKNOWN} as the size leaves @emph{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 @code{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.
+
+@verbatim
+< HTTP/1.1 200 OK
+< Content-Type: text/plain
+< Transfer-Encoding: chunked
+@end verbatim
+@noindent
+
+An HTTP/1.0 client cannot be sent chunks. In that case @emph{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
+@code{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 @emph{is} known---and in the example program the URL
+@code{/sized} shows this variant---it should be announced, simply by
+passing the number instead of @code{MHD_SIZE_UNKNOWN}. @emph{MHD}
+then emits a normal @code{Content-Length} header, no chunk framing is
+added, and the callback is queried with @code{max} limited by both
+@code{block_size} and the number of bytes still outstanding. The
+callback must produce exactly the announced number of bytes.
+
+
+@heading 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 @code{MHD_CONTENT_READER_END_WITH_ERROR} is the way to give
+up: @emph{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---@code{curl} for instance fails with "transfer
+closed with outstanding read data remaining" and a non-zero exit
+status. With an announced @code{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 @emph{MHD} can
+repair. The URL @code{/error} of the example program aborts the
+stream after a few blocks so that this can be observed.
+
+
+@heading 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
+@code{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
+
+@verbatim
+void MHD_suspend_connection (struct MHD_Connection *connection);
+void MHD_resume_connection (struct MHD_Connection *connection);
+@end verbatim
+@noindent
+
+The daemon has to be started with the @code{MHD_ALLOW_SUSPEND_RESUME}
+flag; both functions call @code{MHD_PANIC()} and abort the process
+otherwise. The flag implies @code{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
+@code{MHD_USE_THREAD_PER_CONNECTION}, and the daemon must not be
+stopped while connections are still suspended.
+
+@code{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:
+
+@verbatim
+ if (! ctx->data_available)
+ {
+ MHD_suspend_connection (ctx->connection);
+ return 0;
+ }
+@end verbatim
+@noindent
+
+@code{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.
+@emph{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 @code{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.
+
+
+@heading Trailers
+
+Chunked responses may carry trailers, that is header fields that are
+transmitted after the body. They are added with
+
+@verbatim
+MHD_add_response_footer (response, "X-Checksum", "deadbeef");
+@end verbatim
+@noindent
+
+@emph{MHD} writes them out after the terminating zero-length chunk:
+
+@verbatim
+0
+X-Checksum: deadbeef
+
+@end verbatim
+@noindent
+
+Footers may still be added while the body is being generated---even
+from inside the content reader callback, immediately before returning
+@code{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.
+@emph{MHD} does not generate a @code{Trailer} response header by
+itself; if the client should be told in advance which fields to
+expect, add it with @code{MHD_add_response_header()}. Be aware that
+many clients discard trailers silently.
+
+
+@heading Example code
+
+The complete program is available as @code{callbackresponse.c}. It
+serves a document of sixty-four blocks that are produced one at a time
+into a single heap buffer. @code{GET /} streams it with
+@code{MHD_SIZE_UNKNOWN} and thus with chunked encoding,
+@code{GET /sized} streams the same bytes with a @code{Content-Length}
+announced up front, and @code{GET /error} aborts in the middle.
+
+
+@heading Remarks
+
+Calls into the content reader of one response object are serialized by
+@emph{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 @code{buf} as @code{max} permits.
+
+
+@heading Exercises
+
+@itemize @bullet
+
+@item
+Add a URL that reports how far the transfer has progressed by writing
+the value of @code{pos} into every line, and confirm with a slow
+client (@code{curl --limit-rate}) that it really is the number of
+bytes already sent, and not a block counter.
+
+@item
+Register a request completion callback with
+@code{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.
+
+@item
+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 @code{MHD_ALLOW_SUSPEND_RESUME} when
+starting the daemon. Then remove the call to
+@code{MHD_suspend_connection()}, leaving only the @code{return 0}, and
+compare the CPU usage of the server process.
+
+@item
+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 @code{nc} or a small script
+speaking HTTP by hand is the easier tool here.
+
+@end itemize
diff --git a/doc/chapters/exploringrequests.inc b/doc/chapters/exploringrequests.inc
index 8237c9bb..1f55258a 100644
--- a/doc/chapters/exploringrequests.inc
+++ b/doc/chapters/exploringrequests.inc
@@ -1,5 +1,5 @@
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 an request
+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 @emph{hellobrowser} program with the former response removed.
@@ -9,9 +9,9 @@ just return MHD_NO after we have probed the request. This way, the connection is
without much ado by the server.
@verbatim
-static int
-answer_to_connection (void *cls, struct MHD_Connection *connection,
- const char *url,
+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)
@@ -34,15 +34,16 @@ printf ("New %s request for %s using version %s\n", method, url, version);
@end verbatim
@noindent
-The rest of the information is a bit more hidden. Nevertheless, there is lot of it sent from common
+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.
@verbatim
-int print_out_key (void *cls, enum MHD_ValueKind kind,
- const char *key, const char *value)
+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;
@@ -63,8 +64,8 @@ so the last parameter can be NULL.
All in all, this constitutes the complete @code{logging.c} program for this chapter which can be
found in the @code{examples} section.
-Connecting with any modern Internet browser should yield a handful of keys. You should try to
-interpret them with the aid of @emph{RFC 2616}.
+Connecting with any modern Internet browser should yield a handful of keys. You should try to
+interpret them with the aid of @emph{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).
@@ -93,9 +94,10 @@ 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
@verbatim
-static int on_client_connect (void *cls,
- const struct sockaddr *addr,
- socklen_t addrlen)
+static enum MHD_Result
+on_client_connect (void *cls,
+ const struct sockaddr *addr,
+ socklen_t addrlen)
@end verbatim
@noindent
that prints out the IP address in an appropriate format. You might want to use the POSIX function
diff --git a/doc/chapters/hellobrowser.inc b/doc/chapters/hellobrowser.inc
index 6ca37df9..5ef4df3e 100644
--- a/doc/chapters/hellobrowser.inc
+++ b/doc/chapters/hellobrowser.inc
@@ -14,7 +14,9 @@ After the necessary includes and the definition of the port which our server sho
#include
#include
#include
+#include
#include
+#include
#define PORT 8888
@@ -39,11 +41,12 @@ daemon to sent the reply.
Talking about the reply, it is defined as a string right after the function header
@verbatim
-int 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)
+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 = "Hello, browser!";
@@ -54,21 +57,22 @@ HTTP is a rather strict protocol and the client would certainly consider it "ina
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
-@code{MHD_create_response_from_buffer} function. The last two parameters basically tell @emph{MHD}
-that we do not want it to dispose the message data for us when it has been sent and there also needs
-no internal copy to be done because the @emph{constant} string won't change anyway.
+@code{MHD_create_response_from_buffer_static} function. By using the @code{_static}
+variant we tell @emph{MHD} that the buffer will stay valid and unchanged for at least
+as long as the response lives, so that @emph{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 @emph{constant} string.
@verbatim
struct MHD_Response *response;
- int ret;
+ enum MHD_Result ret;
- response = MHD_create_response_from_buffer (strlen (page),
- (void*) page, MHD_RESPMEM_PERSISTENT);
+ response = MHD_create_response_from_buffer_static (strlen (page), page);
@end verbatim
@noindent
-Now that the the response has been laced up, it is ready for delivery and can be queued for sending.
+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 @emph{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 @code{connection} and consequently this variable is given to the queue function.
@@ -91,27 +95,31 @@ already being set at this point to either MHD_YES or MHD_NO in case of success o
With the primary task of our server implemented, we can start the actual server daemon which will listen
on @code{PORT} for connections. This is done in the main function.
@verbatim
-int main ()
+int main (void)
{
struct MHD_Daemon *daemon;
- daemon = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD, PORT, NULL, NULL,
+ 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;
@end verbatim
@noindent
-The first parameter is one of three possible modes of operation. Here we want the daemon to run in
+The first parameter is a bit-wise OR of flags selecting, among other things, the mode of
+operation. With @code{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 @code{MHD_USE_AUTO} flag simply lets @emph{MHD} pick the best polling function
+(@code{epoll}, @code{poll} or @code{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 connection has been
-established. Our @code{answer_to_connection} knows best what the client wants and needs no additional
+Parameter five is the address of the function we want to be called whenever a new request has been
+received. Our @code{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.
@@ -168,16 +176,19 @@ Both of these issues you will find addressed in the official @code{minimal_examp
the @code{src/examples} directory of the @emph{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 pass @code{MHD_RESPMEM_PERSISTENT} to the response construction
-function. In the usual case, responses are not transmitted immediately
+For our example, we create the response from a static (persistent) buffer in memory and thus use
+@code{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 @code{page} string, which is a constant @emph{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 @emph{MHD} free the memory @code{page} points
-to itself when it is not longer needed (by passing @code{MHD_RESPMEM_MUST_FREE}) or, alternatively, have the library to make and manage
-its own copy of it (by passing @code{MHD_RESPMEM_MUST_COPY}). Naturally, this last option is the most expensive.
+to itself when it is no longer needed (by using
+@code{MHD_create_response_from_buffer_with_free_callback} with @code{&free}) or, alternatively,
+have the library make and manage its own copy of it (by using
+@code{MHD_create_response_from_buffer_copy}). Naturally, this last option is the most expensive.
@heading Exercises
@itemize @bullet
@@ -200,9 +211,11 @@ and an altered response is sent? Make sure you read about the status codes in th
@item
-Add the option @code{MHD_USE_PEDANTIC_CHECKS} to the start function of the daemon in @code{main}.
-Mind the special format of the parameter list here which is described in the manual. How indulgent
-is the server now to your input?
+Add the option @code{MHD_OPTION_CLIENT_DISCIPLINE_LVL} with a value of @code{1} to the start
+function of the daemon in @code{main} (this option supersedes the deprecated
+@code{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 @code{int} value, and @code{MHD_OPTION_END}
+still terminates the list. How indulgent is the server now to your input?
@item
diff --git a/doc/chapters/largerpost.inc b/doc/chapters/largerpost.inc
index 3ccfb05b..86b5d16a 100644
--- a/doc/chapters/largerpost.inc
+++ b/doc/chapters/largerpost.inc
@@ -6,7 +6,7 @@ clients concurrently uploading, responding with a proper busy message if necessa
@heading Prepared answers
-We choose to operate the server with the @code{SELECT_INTERNALLY} method. This makes it easier to
+We choose to operate the server with the @code{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.
@@ -45,13 +45,17 @@ const char* completepage = "The upload has been completed.An internal server error has occurred.";
+ = "Invalid request.";
const char* fileexistspage
= "This file already exists.";
+const char* fileioerror
+ = "IO error writing to disk.";
+const char* postprocerror
+ = "Error processing POST data.";
@end verbatim
@noindent
@@ -62,13 +66,12 @@ status code but in order to improve the @code{HTTP} conformance of our server a
@verbatim
static enum MHD_Result
send_page (struct MHD_Connection *connection,
- const char* page, int status_code)
+ const char* page, unsigned int status_code)
{
enum MHD_Result ret;
struct MHD_Response *response;
- response = MHD_create_response_from_buffer (strlen (page), (void*) page,
- MHD_RESPMEM_MUST_COPY);
+ response = MHD_create_response_from_buffer_copy (strlen (page), page);
if (!response) return MHD_NO;
ret = MHD_queue_response (connection, status_code, response);
@@ -79,14 +82,14 @@ send_page (struct MHD_Connection *connection,
@end verbatim
@noindent
-Note how we ask @emph{MHD} to make its own copy of the message data. The reason behind this will
-become clear later.
+Note how we ask @emph{MHD} to make its own copy of the message data---that is what the
+@code{_copy} suffix stands for. The reason behind this will become clear later.
@heading 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 @emph{POST} requests because if no response is
-queued at this point, and @code{MHD_YES} returned, @emph{MHD} will not sent any queued messages until
+queued at this point, and @code{MHD_YES} returned, @emph{MHD} will not send any queued messages until
a postprocessor has been created and the post iterator is called at least once.
@verbatim
@@ -107,12 +110,14 @@ answer_to_connection (void *cls, struct MHD_Connection *connection,
@noindent
If the server is not busy, the @code{connection_info} structure is initialized as usual, with
-the addition of a filepointer for each connection.
+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".
@verbatim
con_info = malloc (sizeof (struct connection_info_struct));
if (NULL == con_info) return MHD_NO;
- con_info->fp = 0;
+ con_info->answercode = 0;
+ con_info->fp = NULL;
if (0 == strcmp (method, "POST"))
{
@@ -131,8 +136,7 @@ For @emph{POST} requests, the postprocessor is created and we register a new upl
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 @code{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. Here,
-the structure is initialized to "no error".
+message so that whenever a response is sent, the client will get the most informative message.
@verbatim
if (0 == strcmp (method, "POST"))
{
@@ -149,8 +153,6 @@ the structure is initialized to "no error".
nr_of_uploading_clients++;
con_info->connectiontype = POST;
- con_info->answercode = MHD_HTTP_OK;
- con_info->answerstring = completepage;
}
else con_info->connectiontype = GET;
@end verbatim
@@ -164,7 +166,7 @@ own copy of it for as long as it is needed.
{
char buffer[1024];
- sprintf (buffer, askpage, nr_of_uploading_clients);
+ snprintf (buffer, sizeof (buffer), askpage, nr_of_uploading_clients);
return send_page (connection, buffer, MHD_HTTP_OK);
}
@end verbatim
@@ -174,7 +176,9 @@ own copy of it for as long as it is needed.
The rest of the @code{answer_to_connection} function is very similar to the @code{simplepost.c}
example, except the more flexible content of the responses. The @emph{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.
+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.
@verbatim
if (0 == strcmp (method, "POST"))
{
@@ -182,15 +186,33 @@ constituted no expected request method.
if (0 != *upload_data_size)
{
- MHD_post_process (con_info->postprocessor,
- upload_data, *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;
}
- else
- return send_page (connection, con_info->answerstring,
- con_info->answercode);
+
+ 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);
@@ -199,11 +221,11 @@ constituted no expected request method.
@noindent
-@heading Storing to data
+@heading Storing the data
Unlike the @code{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
-@code{connection_info}, so that the it is preserved between successive iterations.
+@code{connection_info}, so that it is preserved between successive iterations.
@verbatim
static enum MHD_Result
iterate_post (void *coninfo_cls, enum MHD_ValueKind kind,
@@ -213,23 +235,25 @@ iterate_post (void *coninfo_cls, enum MHD_ValueKind kind,
uint64_t off, size_t size)
{
struct connection_info_struct *con_info = coninfo_cls;
+ FILE *fp;
@end verbatim
@noindent
Because the following actions depend heavily on correct file processing, which might be error prone,
-we default to reporting internal errors in case anything will go wrong.
-
-@verbatim
-con_info->answerstring = servererrorpage;
-con_info->answercode = MHD_HTTP_INTERNAL_SERVER_ERROR;
-@end verbatim
-@noindent
+we record the page to answer with as soon as anything goes wrong. Note that the iterator always
+returns @code{MHD_YES}: returning @code{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" @emph{form}, we told the client to label its post data with the "file" key. Anything else
would be an error.
@verbatim
- if (0 != strcmp (key, "file")) return MHD_NO;
+ if (0 != strcmp (key, "file"))
+ {
+ con_info->answerstring = servererrorpage;
+ con_info->answercode = MHD_HTTP_BAD_REQUEST;
+ return MHD_YES;
+ }
@end verbatim
@noindent
@@ -241,16 +265,24 @@ race between the two "fopen" calls, but we will overlook this for portability sa
@verbatim
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_NO;
+ return MHD_YES;
}
con_info->fp = fopen (filename, "ab");
- if (!con_info->fp) return MHD_NO;
+ if (!con_info->fp)
+ {
+ con_info->answerstring = fileioerror;
+ con_info->answercode = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ return MHD_YES;
+ }
}
@end verbatim
@noindent
@@ -259,20 +291,21 @@ race between the two "fopen" calls, but we will overlook this for portability sa
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.
@verbatim
-if (size > 0)
+ if (size > 0)
{
- if (!fwrite (data, size, sizeof(char), con_info->fp))
- return MHD_NO;
+ if (!fwrite (data, sizeof (char), size, con_info->fp))
+ {
+ con_info->answerstring = fileioerror;
+ con_info->answercode = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ }
}
@end verbatim
@noindent
-If this point has been reached, everything worked well for this iteration and the response can
-be set to success again. If the upload has finished, this iterator function will not be called again.
+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
+@code{answer_to_connection} will declare success.
@verbatim
- con_info->answerstring = completepage;
- con_info->answercode = MHD_HTTP_OK;
-
return MHD_YES;
}
@end verbatim
@@ -282,7 +315,7 @@ be set to success again. If the upload has finished, this iterator function will
The new client was registered when the postprocessor was created. Likewise, we unregister the client
on destroying the postprocessor when the request is completed.
@verbatim
-void
+static void
request_completed (void *cls, struct MHD_Connection *connection,
void **req_cls,
enum MHD_RequestTerminationCode toe)
diff --git a/doc/chapters/processingpost.inc b/doc/chapters/processingpost.inc
index fff74904..f7451dd6 100644
--- a/doc/chapters/processingpost.inc
+++ b/doc/chapters/processingpost.inc
@@ -17,7 +17,7 @@ edit field for the name.
const char* askpage = "\
What's your name, Sir?
\
\
";
@end verbatim
@@ -30,7 +30,7 @@ We also prepare the answer page, where the name is to be filled in later, and an
as the response for anything but proper @emph{GET} and @emph{POST} requests:
@verbatim
-const char* greatingpage="Welcome, %s!
";
+const char* greetingpage="Welcome, %s!
";
const char* errorpage="This doesn't seem to be right.";
@end verbatim
@@ -67,11 +67,13 @@ struct connection_info_struct
@noindent
With these information available to the iterator function, it is able to fulfill its task.
-Once it has composed the greeting string, it returns @code{MHD_NO} to inform the post processor
-that it does not need to be called again. Note that this function does not handle processing
-of data for the same @code{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 @code{key}
-came in. But in this example, the name is assumed to fit entirely inside one single packet.
+Once it has composed the greeting string, it returns @code{MHD_YES} so that the post processor
+keeps parsing the remainder of the upload. Returning @code{MHD_NO} would instead abort the
+parsing and make the next call to @code{MHD_post_process} fail. Note that this function does not
+handle processing of data for the same @code{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 @code{key} came in. But in this example, the name is assumed to fit entirely inside
+one single packet.
@verbatim
static enum MHD_Result
@@ -90,12 +92,10 @@ iterate_post (void *coninfo_cls, enum MHD_ValueKind kind, const char *key,
answerstring = malloc (MAXANSWERSIZE);
if (!answerstring) return MHD_NO;
- snprintf (answerstring, MAXANSWERSIZE, greatingpage, data);
+ snprintf (answerstring, MAXANSWERSIZE, greetingpage, data);
con_info->answerstring = answerstring;
}
else con_info->answerstring = NULL;
-
- return MHD_NO;
}
return MHD_YES;
@@ -110,7 +110,7 @@ string. This cleanup function must take into account that it will also be called
requests other than @emph{POST} requests.
@verbatim
-void
+static void
request_completed (void *cls, struct MHD_Connection *connection,
void **req_cls,
enum MHD_RequestTerminationCode toe)
@@ -136,7 +136,8 @@ in the main function.
@verbatim
...
-daemon = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD, PORT, NULL, NULL,
+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);
@@ -218,8 +219,10 @@ considered---all of it.
if (*upload_data_size != 0)
{
- MHD_post_process (con_info->postprocessor, upload_data,
- *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;
diff --git a/doc/chapters/responseheaders.inc b/doc/chapters/responseheaders.inc
index 3caa9109..e5b86b56 100644
--- a/doc/chapters/responseheaders.inc
+++ b/doc/chapters/responseheaders.inc
@@ -30,7 +30,6 @@ answer_to_connection (void *cls, struct MHD_Connection *connection,
const char *upload_data,
size_t *upload_data_size, void **req_cls)
{
- unsigned char *buffer = NULL;
struct MHD_Response *response;
@end verbatim
@noindent
@@ -58,46 +57,24 @@ server side and if so, the client should be informed with @code{MHD_HTTP_INTERNA
@verbatim
/* error accessing file */
- if (fd != -1) close (fd);
+ if (fd != -1) close (fd);
const char *errorstr =
"An internal server error has occurred!\
";
response =
- MHD_create_response_from_buffer (strlen (errorstr),
- (void *) errorstr,
- MHD_RESPMEM_PERSISTENT);
- if (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 MHD_YES;
+ return ret;
}
else
return MHD_NO;
- if (!ret)
- {
- const char *errorstr = "An internal server error has occurred!\
- ";
-
- if (buffer) free(buffer);
-
- response = MHD_create_response_from_buffer (strlen(errorstr), (void*) errorstr,
- MHD_RESPMEM_PERSISTENT);
-
- if (response)
- {
- ret = MHD_queue_response (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- response);
- MHD_destroy_response (response);
-
- return MHD_YES;
- }
- else return MHD_NO;
- }
@end verbatim
@noindent
@@ -113,10 +90,8 @@ But in the case of success a response will be constructed directly from the file
}
response =
- MHD_create_response_from_fd_at_offset (sbuf.st_size, fd, 0);
+ MHD_create_response_from_fd_at_offset64 ((uint64_t) sbuf.st_size, fd, 0);
MHD_add_response_header (response, "Content-Type", MIMETYPE);
- ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
- MHD_destroy_response (response);
@end verbatim
@noindent
@@ -129,7 +104,7 @@ MHD_add_response_header(response, "Content-Type", MIMETYPE);
@end verbatim
@noindent
We do not have to append a colon expected by the protocol behind the first
-field---@emph{GNU libhttpdmicro} will take care of this.
+field---@emph{GNU libmicrohttpd} will take care of this.
The function finishes with the well-known lines
@verbatim
@@ -145,7 +120,7 @@ Find a @emph{PNG} file you like and save it to the directory the example is run
@code{picture.png}. You should find the image displayed on your browser if everything worked well.
@heading Remarks
-The include file of the @emph{MHD} library comes with the header types mentioned in @emph{RFC 2616}
+The include file of the @emph{MHD} library comes with the header types mentioned in @emph{RFC 9110}
already defined as macros. Thus, we could have written @code{MHD_HTTP_HEADER_CONTENT_TYPE} instead
of @code{"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
@@ -169,8 +144,8 @@ instantly, postpone the queuing in the callback with the @code{sleep} function f
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 use @code{MHD_USE_THREAD_PER_CONNECTION} when the daemon is
-started and try again.
+Finally, change the sourcecode to add @code{MHD_USE_THREAD_PER_CONNECTION} to the daemon's flags
+(this flag must be combined with @code{MHD_USE_INTERNAL_POLLING_THREAD}) and try again.
@item
diff --git a/doc/chapters/sessions.inc b/doc/chapters/sessions.inc
index ee48e58e..1087bcc5 100644
--- a/doc/chapters/sessions.inc
+++ b/doc/chapters/sessions.inc
@@ -30,15 +30,15 @@ Here, "KEY" is the name we chose for our session cookie.
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
-64-character text string to be used as the value of the cookie:
+32-character text string to be used as the value of the cookie:
@verbatim
char value[128];
-char raw_value[65];
+char raw_value[33];
-for (unsigned int i=0;i openssl genrsa -out server.key 1024
+> openssl genrsa -out server.key 2048
@end verbatim
@noindent
@@ -25,13 +25,16 @@ In addition to the key, a certificate describing the server in human readable to
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
+@emph{subjectAltName} that matches the @emph{URI}, for example, "localhost" or the domain
+(current browsers ignore the common name and look at the @emph{subjectAltName} only).
+
@verbatim
-> openssl req -days 365 -out server.pem -new -x509 -key server.key
+> openssl req -days 365 -out server.pem -new -x509 -key server.key \
+ -addext "subjectAltName=DNS:localhost"
@end verbatim
@noindent
-To avoid unnecessary error messages in the browser, the certificate needs to
-have a name that matches the @emph{URI}, for example, "localhost" or the domain.
If you plan to have a publicly reachable server, you will need to ask a trusted third party,
called @emph{Certificate Authority}, or @emph{CA}, to attest the certificate for you. This way,
any visitor can make sure the server's identity is real.
@@ -48,7 +51,7 @@ We merely have to extend the server program so that it loads the two files into
@verbatim
int
-main ()
+main (void)
{
struct MHD_Daemon *daemon;
char *key_pem;
@@ -68,7 +71,7 @@ main ()
and then we point the @emph{MHD} daemon to it upon initialization.
@verbatim
- daemon = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_SSL,
+ 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,
@@ -138,7 +141,7 @@ To do this, you will need to link your application against @emph{gnutls}.
Next, when you start the MHD daemon, you must specify the root CA that you're
willing to trust:
@verbatim
- daemon = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_SSL,
+ 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,
@@ -157,7 +160,7 @@ obtain the raw GnuTLS session handle from @emph{MHD} using
#include
gnutls_session_t tls_session;
-union MHD_ConnectionInfo *ci;
+const union MHD_ConnectionInfo *ci;
ci = MHD_get_connection_info (connection,
MHD_CONNECTION_INFO_GNUTLS_SESSION);
@@ -333,7 +336,7 @@ 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:
@verbatim
- daemon = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_SSL,
+ 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,
@@ -348,11 +351,11 @@ as follows:
@deftypefn {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)
@table @var
-@item req_ca_cert
+@item 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 @code{gnutls_x509_rdn_get()}.
@item pk_algos
-contains a list with server’s acceptable signature algorithms. The certificate returned should support the server’s given algorithms.
+contains a list with server's acceptable signature algorithms. The certificate returned should support the server's given algorithms.
@item pcert
should contain a single certificate and public or a list of them.
diff --git a/doc/chapters/upgrade.inc b/doc/chapters/upgrade.inc
new file mode 100644
index 00000000..274d01ec
--- /dev/null
+++ b/doc/chapters/upgrade.inc
@@ -0,0 +1,422 @@
+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, @emph{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 @code{Upgrade:} header field, and if the server agrees it
+answers with the status code @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 @emph{libmicrohttpd} supports this protocol
+switch. The API is deliberately protocol-agnostic --- @emph{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;
+@emph{MHD} neither parses nor generates a single byte of it any more.
+
+The best known user of this mechanism is the Websocket protocol
+(@emph{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 @code{QUIT}.
+
+@heading 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 @code{MHD_ALLOW_UPGRADE} flag:
+
+@verbatim
+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);
+@end verbatim
+@noindent
+
+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 @code{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 @code{recv()} and @code{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
+@emph{inside} @emph{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.
+
+@heading Deciding whether to upgrade
+
+A client that wants to switch protocols says so twice: it names the
+protocol in the @code{Upgrade:} header field, and it lists the token
+@code{Upgrade} in the @code{Connection:} header field. Both fields
+are comma-separated lists, so a browser may well send
+@code{Connection: keep-alive, Upgrade}. Comparing the whole field
+value against the string @code{"Upgrade"} would reject such a request;
+the example therefore contains a small helper @code{has_token()} that
+walks the list. Note also that a protocol switch is a HTTP/1.1
+feature; @code{MHD_queue_response()} will refuse an upgrade response
+on a HTTP/1.0 connection.
+
+@verbatim
+ 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);
+@end verbatim
+@noindent
+
+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
+@code{Upgrade:} field without the matching @code{Connection:} token
+--- @code{MHD_HTTP_BAD_REQUEST} is appropriate. If the request is
+perfectly well-formed but simply does not speak the protocol this
+resource requires, @code{MHD_HTTP_UPGRADE_REQUIRED} (426) is the
+better answer, and it should carry an @code{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.
+
+@heading Creating the upgrade response
+
+If we do want to switch, we create a special response object with
+@code{MHD_create_response_for_upgrade()}. It takes the callback that
+will receive the socket and a closure pointer for it, and returns
+@code{NULL} on error. The response has no body --- it is a header and
+nothing else.
+
+@verbatim
+ 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;
+@end verbatim
+@noindent
+
+Two details are easy to get wrong here.
+
+The first is the @code{Connection: Upgrade} response header field, and
+the surprise is that you must @emph{not} add it.
+@code{MHD_create_response_for_upgrade()} puts it into the response
+itself, and @code{MHD_queue_response()} then verifies that it is still
+there and still contains the @code{upgrade} token before it accepts
+the response. @emph{MHD} does merge repeated @code{Connection:}
+header fields into a single field rather than emitting two of them,
+but it only de-duplicates the @code{close} token, so adding
+@code{Upgrade} a second time puts @code{Connection: Upgrade, Upgrade}
+on the wire. Clients tolerate that, but there is no reason to send
+it.
+
+What @emph{MHD} does @emph{not} invent for you is the @code{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:
+@code{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. @code{MHD_queue_response()} rejects an
+upgrade response with any status other than
+@code{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 @code{MHD_NO} and, with
+@code{MHD_USE_ERROR_LOG} enabled, explains itself on @code{stderr};
+this is by far the quickest way to debug a handshake that does not
+happen.
+
+The response object itself follows the usual rules.
+@code{MHD_queue_response()} takes its own reference, so calling
+@code{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.
+
+@heading The upgrade callback
+
+After the 101 response has been written to the socket, @emph{MHD}
+calls the @code{MHD_UpgradeHandler} you registered:
+
+@verbatim
+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)
+@end verbatim
+@noindent
+
+@table @code
+@item cls
+The closure that was passed to
+@code{MHD_create_response_for_upgrade()}. Since the same response
+object may serve many connections, this is per-@emph{response} state,
+not per-connection state.
+
+@item connection
+The original HTTP connection. It is handed over so that you can have
+a last look at the request --- @code{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.
+
+@item req_cls
+Whatever your access handler left in @code{*req_cls}. This is the
+natural place to put per-connection state that the access handler
+already computed.
+
+@item extra_in / extra_in_size
+Bytes of your new protocol that the client sent immediately behind the
+request header, and that @emph{MHD} therefore already read off the
+socket while parsing the request. They are @emph{gone} from the
+socket: if you go straight to @code{recv()} you silently lose them.
+Process this buffer first, exactly as if you had read it yourself.
+The buffer belongs to @emph{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
+@code{extra_in_size == 0}, which is why this argument is so easy to
+overlook and so annoying when it finally bites.
+
+@item 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 @emph{MHD}
+relaying the TLS traffic, so socket options and @code{getpeername()}
+will not give you what you expect. Read and write it as you please,
+and you may call @code{shutdown()} on it, but you must never call
+@code{close()}.
+
+@item urh
+The handle for @code{MHD_upgrade_action()}, described below.
+@end table
+
+The loop itself is then unremarkable, apart from consuming
+@code{extra_in} before the first @code{recv()}:
+
+@verbatim
+ 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);
+@end verbatim
+@noindent
+
+@heading Blocking or not blocking
+
+The call to @code{make_blocking()} deserves a warning, because the
+current behaviour is the opposite of what the threading modes suggest.
+@emph{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 @code{Cannot
+execute "upgrade" as the socket is in the blocking mode}, if it finds
+the socket blocking. So even under
+@code{MHD_USE_THREAD_PER_CONNECTION}, where you are perfectly entitled
+to block, the socket you are handed is non-blocking and a
+@code{recv()} on an idle connection returns @code{-1} with
+@code{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
+@code{make_blocking()} helper --- @code{fcntl()} clearing
+@code{O_NONBLOCK} on POSIX systems, @code{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.
+
+@heading Closing the connection
+
+The last obligation of the callback is to hand the socket back:
+
+@verbatim
+ MHD_upgrade_action (urh,
+ MHD_UPGRADE_ACTION_CLOSE);
+@end verbatim
+@noindent
+
+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
+@code{MHD_UPGRADE_ACTION_CLOSE} says that. Calling @code{close()} on
+the socket yourself does not, and additionally leaves @emph{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.
+
+@code{MHD_upgrade_action()} takes two further actions in the current
+release, @code{MHD_UPGRADE_ACTION_CORK_ON} and
+@code{MHD_UPGRADE_ACTION_CORK_OFF}. They switch @code{TCP_CORK} (or
+@code{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 @code{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.
+
+@heading Remarks
+
+@code{MHD_stop_daemon()} does @emph{not} interrupt an upgraded
+connection. It marks the connection as closed internally and logs
+@code{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 @code{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
+@code{shutdown()} on the sockets you are holding, a self-pipe added to
+a @code{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. @emph{MHD} will not
+tell you that a client vanished and will not time an upgraded
+connection out --- @code{MHD_OPTION_CONNECTION_TIMEOUT} stops applying
+the moment the connection is upgraded. Treat @code{0} from
+@code{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 @code{MHD_upgrade_action()} with
+@code{MHD_UPGRADE_ACTION_CLOSE}.
+
+Finally, keep in mind that an upgraded connection is a connection that
+@emph{MHD} can no longer recycle, and that intermediaries are entitled
+to be unhelpful: @code{Upgrade:} is listed in @code{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 @code{upgrade.c} in the
+@code{examples} section. Start it and talk to it with any tool that
+lets you type raw bytes at a socket --- @code{telnet localhost 8888}
+will do --- by sending
+
+@verbatim
+GET / HTTP/1.1
+Host: localhost
+Connection: Upgrade
+Upgrade: echo
+
+@end verbatim
+@noindent
+
+followed by an empty line. The server answers with
+
+@verbatim
+HTTP/1.1 101 Switching Protocols
+Date: ...
+Connection: Upgrade
+Upgrade: echo
+
+@end verbatim
+@noindent
+
+and from then on echoes every line back until you type @code{QUIT}.
+Note the absence of a @code{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
+@emph{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.
+
+@heading Exercises
+
+@itemize @bullet
+
+@item
+Point a browser at the server. The browser sends a plain @code{GET /}
+and receives the @code{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.
+
+@item
+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.
+
+@item
+Fix the shutdown behaviour discussed in the remarks. Add a global
+``quitting'' flag and a list of active sockets, have @code{main()} set
+the flag and call @code{shutdown (sock, SHUT_RDWR)} on every entry
+before it calls @code{MHD_stop_daemon()}, and verify that the daemon
+now stops even while a client is connected and silent.
+
+@item
+Change the daemon flags to plain
+@code{MHD_USE_INTERNAL_POLLING_THREAD} without
+@code{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.
+
+@item
+Have the client send a line longer than @code{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?
+
+@end itemize
diff --git a/doc/chapters/websocket.inc b/doc/chapters/websocket.inc
deleted file mode 100644
index 4a5b4960..00000000
--- a/doc/chapters/websocket.inc
+++ /dev/null
@@ -1,886 +0,0 @@
-Websockets are a genuine way to implement push notifications,
-where the server initiates the communication while the client can be idle.
-Usually a HTTP communication is half-duplex and always requested by the client,
-but websockets are full-duplex and only initialized by the client.
-In the further communication both sites can use the websocket at any time
-to send data to the other site.
-
-To initialize a websocket connection the client sends a special HTTP request
-to the server and initializes
-a handshake between client and server which switches from the HTTP protocol
-to the websocket protocol.
-Thus both the server as well as the client must support websockets.
-If proxys are used, they must support websockets too.
-In this chapter we take a look on server and client, but with a focus on
-the server with @emph{libmicrohttpd}.
-
-Since version 0.9.52 @emph{libmicrohttpd} supports upgrading requests,
-which is required for switching from the HTTP protocol.
-Since version 0.9.74 the library @emph{libmicrohttpd_ws} has been added
-to support the websocket protocol.
-
-@heading Upgrading connections with libmicrohttpd
-
-To support websockets we need to enable upgrading of HTTP connections first.
-This is done by passing the flag @code{MHD_ALLOW_UPGRADE} to
-@code{MHD_start_daemon()}.
-
-
-@verbatim
-daemon = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD |
- MHD_USE_THREAD_PER_CONNECTION |
- MHD_ALLOW_UPGRADE |
- MHD_USE_ERROR_LOG,
- PORT, NULL, NULL,
- &access_handler, NULL,
- MHD_OPTION_END);
-@end verbatim
-@noindent
-
-
-The next step is to turn a specific request into an upgraded connection.
-This done in our @code{access_handler} by calling
-@code{MHD_create_response_for_upgrade()}.
-An @code{upgrade_handler} will be passed to perform the low-level actions
-on the socket.
-
-@emph{Please note that the socket here is just a regular socket as provided
-by the operating system.
-To use it as a websocket, some more steps from the following
-chapters are required.}
-
-
-@verbatim
-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 **ptr)
-{
- /* ... */
- /* some code to decide whether to upgrade or not */
- /* ... */
-
- /* create the response for upgrade */
- response = MHD_create_response_for_upgrade (&upgrade_handler,
- NULL);
-
- /* ... */
- /* additional headers, etc. */
- /* ... */
-
- ret = MHD_queue_response (connection,
- MHD_HTTP_SWITCHING_PROTOCOLS,
- response);
- MHD_destroy_response (response);
-
- return ret;
-}
-@end verbatim
-@noindent
-
-
-In the @code{upgrade_handler} we receive the low-level socket,
-which is used for the communication with the specific client.
-In addition to the low-level socket we get:
-@itemize @bullet
-@item
-Some data, which has been read too much while @emph{libmicrohttpd} was
-switching the protocols.
-This value is usually empty, because it would mean that the client
-has sent data before the handshake was complete.
-
-@item
-A @code{struct MHD_UpgradeResponseHandle} which is used to perform
-special actions like closing, corking or uncorking the socket.
-These commands are executed by passing the handle
-to @code{MHD_upgrade_action()}.
-
-
-@end itemize
-
-Depending of the flags specified while calling @code{MHD_start_deamon()}
-our @code{upgrade_handler} is either executed in the same thread
-as our daemon or in a thread specific for each connection.
-If it is executed in the same thread then @code{upgrade_handler} is
-a blocking call for our webserver and
-we should finish it as fast as possible (i. e. by creating a thread and
-passing the information there).
-If @code{MHD_USE_THREAD_PER_CONNECTION} was passed to
-@code{MHD_start_daemon()} then a separate thread is used and
-thus our @code{upgrade_handler} needs not to start a separate thread.
-
-An @code{upgrade_handler}, which is called with a separate thread
-per connection, could look like this:
-
-
-@verbatim
-static void
-upgrade_handler (void *cls,
- struct MHD_Connection *connection,
- void *req_cls,
- const char *extra_in,
- size_t extra_in_size,
- MHD_socket fd,
- struct MHD_UpgradeResponseHandle *urh)
-{
- /* ... */
- /* do something with the socket `fd` like `recv()` or `send()` */
- /* ... */
-
- /* close the socket when it is not needed anymore */
- MHD_upgrade_action (urh,
- MHD_UPGRADE_ACTION_CLOSE);
-}
-@end verbatim
-@noindent
-
-
-This is all you need to know for upgrading connections
-with @emph{libmicrohttpd}.
-The next chapters focus on using the websocket protocol
-with @emph{libmicrohttpd_ws}.
-
-
-@heading Websocket handshake with libmicrohttpd_ws
-
-To request a websocket connection the client must send
-the following information with the HTTP request:
-
-@itemize @bullet
-@item
-A @code{GET} request must be sent.
-
-@item
-The version of the HTTP protocol must be 1.1 or higher.
-
-@item
-A @code{Host} header field must be sent
-
-@item
-A @code{Upgrade} header field containing the keyword "websocket"
-(case-insensitive).
-Please note that the client could pass multiple protocols separated by comma.
-
-@item
-A @code{Connection} header field that includes the token "Upgrade"
-(case-insensitive).
-Please note that the client could pass multiple tokens separated by comma.
-
-@item
-A @code{Sec-WebSocket-Key} header field with a base64-encoded value.
-The decoded the value is 16 bytes long
-and has been generated randomly by the client.
-
-@item
-A @code{Sec-WebSocket-Version} header field with the value "13".
-
-@end itemize
-
-
-Optionally the client can also send the following information:
-
-
-@itemize @bullet
-@item
-A @code{Origin} header field can be used to determine the source
-of the client (i. e. the website).
-
-@item
-A @code{Sec-WebSocket-Protocol} header field can contain a list
-of supported protocols by the client, which can be sent over the websocket.
-
-@item
-A @code{Sec-WebSocket-Extensions} header field which may contain extensions
-to the websocket protocol. The extensions must be registered by IANA.
-
-@end itemize
-
-
-A valid example request from the client could look like this:
-
-
-@verbatim
-GET /chat HTTP/1.1
-Host: server.example.com
-Upgrade: websocket
-Connection: Upgrade
-Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
-Sec-WebSocket-Version: 13
-@end verbatim
-@noindent
-
-
-To complete the handshake the server must respond with
-some specific response headers:
-
-@itemize @bullet
-@item
-The HTTP response code @code{101 Switching Protocols} must be answered.
-
-@item
-An @code{Upgrade} header field containing the value "websocket" must be sent.
-
-@item
-A @code{Connection} header field containing the value "Upgrade" must be sent.
-
-@item
-A @code{Sec-WebSocket-Accept} header field containing a value, which
-has been calculated from the @code{Sec-WebSocket-Key} request header field,
-must be sent.
-
-@end itemize
-
-
-Optionally the server may send following headers:
-
-
-@itemize @bullet
-@item
-A @code{Sec-WebSocket-Protocol} header field containing a protocol
-of the list specified in the corresponding request header field.
-
-@item
-A @code{Sec-WebSocket-Extension} header field containing all used extensions
-of the list specified in the corresponding request header field.
-
-@end itemize
-
-
-A valid websocket HTTP response could look like this:
-
-@verbatim
-HTTP/1.1 101 Switching Protocols
-Upgrade: websocket
-Connection: Upgrade
-Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
-@end verbatim
-@noindent
-
-
-To upgrade a connection to a websocket the @emph{libmicrohttpd_ws} provides
-some helper functions for the @code{access_handler} callback function:
-
-@itemize @bullet
-@item
-@code{MHD_websocket_check_http_version()} checks whether the HTTP version
-is 1.1 or above.
-
-@item
-@code{MHD_websocket_check_connection_header()} checks whether the value
-of the @code{Connection} request header field contains
-an "Upgrade" token (case-insensitive).
-
-@item
-@code{MHD_websocket_check_upgrade_header()} checks whether the value
-of the @code{Upgrade} request header field contains
-the "websocket" keyword (case-insensitive).
-
-@item
-@code{MHD_websocket_check_version_header()} checks whether the value
-of the @code{Sec-WebSocket-Version} request header field is "13".
-
-@item
-@code{MHD_websocket_create_accept_header()} takes the value from
-the @code{Sec-WebSocket-Key} request header and calculates the value
-for the @code{Sec-WebSocket-Accept} response header field.
-
-@end itemize
-
-
-The @code{access_handler} example of the previous chapter can now be
-extended with these helper functions to perform the websocket handshake:
-
-@verbatim
-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 **ptr)
-{
- static int aptr;
- 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. */
-
- if (0 != strcmp (method, "GET"))
- return MHD_NO; /* unexpected method */
- if (&aptr != *ptr)
- {
- /* do never respond on first call */
- *ptr = &aptr;
- return MHD_YES;
- }
- *ptr = NULL; /* reset when done */
-
- if (0 == strcmp (url, "/"))
- {
- /* Default page for visiting the server */
- struct MHD_Response *response = MHD_create_response_from_buffer (
- strlen (PAGE),
- PAGE,
- MHD_RESPMEM_PERSISTENT);
- ret = MHD_queue_response (connection,
- MHD_HTTP_OK,
- response);
- MHD_destroy_response (response);
- }
- else if (0 == strcmp (url, "/chat"))
- {
- char is_valid = 1;
- const char* value = NULL;
- char sec_websocket_accept[29];
-
- if (0 != MHD_websocket_check_http_version (version))
- {
- is_valid = 0;
- }
- value = MHD_lookup_connection_value (connection,
- MHD_HEADER_KIND,
- MHD_HTTP_HEADER_CONNECTION);
- if (0 != MHD_websocket_check_connection_header (value))
- {
- is_valid = 0;
- }
- value = MHD_lookup_connection_value (connection,
- MHD_HEADER_KIND,
- MHD_HTTP_HEADER_UPGRADE);
- if (0 != MHD_websocket_check_upgrade_header (value))
- {
- is_valid = 0;
- }
- value = MHD_lookup_connection_value (connection,
- MHD_HEADER_KIND,
- MHD_HTTP_HEADER_SEC_WEBSOCKET_VERSION);
- if (0 != MHD_websocket_check_version_header (value))
- {
- is_valid = 0;
- }
- value = MHD_lookup_connection_value (connection,
- MHD_HEADER_KIND,
- MHD_HTTP_HEADER_SEC_WEBSOCKET_KEY);
- if (0 != MHD_websocket_create_accept_header (value, sec_websocket_accept))
- {
- is_valid = 0;
- }
-
- if (1 == is_valid)
- {
- /* upgrade the connection */
- response = MHD_create_response_for_upgrade (&upgrade_handler,
- NULL);
- MHD_add_response_header (response,
- MHD_HTTP_HEADER_CONNECTION,
- "Upgrade");
- MHD_add_response_header (response,
- MHD_HTTP_HEADER_UPGRADE,
- "websocket");
- MHD_add_response_header (response,
- MHD_HTTP_HEADER_SEC_WEBSOCKET_ACCEPT,
- sec_websocket_accept);
- ret = MHD_queue_response (connection,
- MHD_HTTP_SWITCHING_PROTOCOLS,
- response);
- MHD_destroy_response (response);
- }
- else
- {
- /* return error page */
- struct MHD_Response*response = MHD_create_response_from_buffer (
- strlen (PAGE_INVALID_WEBSOCKET_REQUEST),
- PAGE_INVALID_WEBSOCKET_REQUEST,
- MHD_RESPMEM_PERSISTENT);
- ret = MHD_queue_response (connection,
- MHD_HTTP_BAD_REQUEST,
- response);
- MHD_destroy_response (response);
- }
- }
- else
- {
- struct MHD_Response*response = MHD_create_response_from_buffer (
- strlen (PAGE_NOT_FOUND),
- PAGE_NOT_FOUND,
- MHD_RESPMEM_PERSISTENT);
- ret = MHD_queue_response (connection,
- MHD_HTTP_NOT_FOUND,
- response);
- MHD_destroy_response (response);
- }
-
- return ret;
-}
-@end verbatim
-@noindent
-
-Please note that we skipped the check of the Host header field here,
-because we don't know the host for this example.
-
-@heading Decoding/encoding the websocket protocol with libmicrohttpd_ws
-
-Once the websocket connection is established you can receive/send frame data
-with the low-level socket functions @code{recv()} and @code{send()}.
-The frame data which goes over the low-level socket is encoded according
-to the websocket protocol.
-To use received payload data, you need to decode the frame data first.
-To send payload data, you need to encode it into frame data first.
-
-@emph{libmicrohttpd_ws} provides several functions for encoding of
-payload data and decoding of frame data:
-
-@itemize @bullet
-@item
-@code{MHD_websocket_decode()} decodes received frame data.
-The payload data may be of any kind, depending upon what the client has sent.
-So this decode function is used for all kind of frames and returns
-the frame type along with the payload data.
-
-@item
-@code{MHD_websocket_encode_text()} encodes text.
-The text must be encoded with UTF-8.
-
-@item
-@code{MHD_websocket_encode_binary()} encodes binary data.
-
-@item
-@code{MHD_websocket_encode_ping()} encodes a ping request to
-check whether the websocket is still valid and to test latency.
-
-@item
-@code{MHD_websocket_encode_ping()} encodes a pong response to
-answer a received ping request.
-
-@item
-@code{MHD_websocket_encode_close()} encodes a close request.
-
-@item
-@code{MHD_websocket_free()} frees data returned by the encode/decode functions.
-
-@end itemize
-
-Since you could receive or send fragmented data (i. e. due to a too
-small buffer passed to @code{recv}) all of these encode/decode
-functions require a pointer to a @code{struct MHD_WebSocketStream} passed
-as argument.
-In this structure @emph{libmicrohttpd_ws} stores information
-about encoding/decoding of the particular websocket.
-For each websocket you need a unique @code{struct MHD_WebSocketStream}
-to encode/decode with this library.
-
-To create or destroy @code{struct MHD_WebSocketStream}
-we have additional functions:
-
-@itemize @bullet
-@item
-@code{MHD_websocket_stream_init()} allocates and initializes
-a new @code{struct MHD_WebSocketStream}.
-You can specify some options here to alter the behavior of the websocket stream.
-
-@item
-@code{MHD_websocket_stream_free()} frees a previously allocated
-@code{struct MHD_WebSocketStream}.
-
-@end itemize
-
-With these encode/decode functions we can improve our @code{upgrade_handler}
-callback function from an earlier example to a working websocket:
-
-
-@verbatim
-static void
-upgrade_handler (void *cls,
- struct MHD_Connection *connection,
- void *req_cls,
- const char *extra_in,
- size_t extra_in_size,
- MHD_socket fd,
- struct MHD_UpgradeResponseHandle *urh)
-{
- /* make the socket blocking (operating-system-dependent code) */
- make_blocking (fd);
-
- /* create a websocket stream for this connection */
- struct MHD_WebSocketStream* ws;
- int result = MHD_websocket_stream_init (&ws,
- 0,
- 0);
- if (0 != result)
- {
- /* Couldn't create the websocket stream.
- * So we close the socket and leave
- */
- MHD_upgrade_action (urh,
- MHD_UPGRADE_ACTION_CLOSE);
- return;
- }
-
- /* Let's wait for incoming data */
- const size_t buf_len = 256;
- char buf[buf_len];
- ssize_t got;
- while (MHD_WEBSOCKET_VALIDITY_VALID == MHD_websocket_stream_is_valid (ws))
- {
- got = recv (fd,
- buf,
- buf_len,
- 0);
- if (0 >= got)
- {
- /* the TCP/IP socket has been closed */
- break;
- }
-
- /* parse the entire received data */
- size_t buf_offset = 0;
- while (buf_offset < (size_t) got)
- {
- size_t new_offset = 0;
- char *frame_data = NULL;
- size_t frame_len = 0;
- int status = MHD_websocket_decode (ws,
- buf + buf_offset,
- ((size_t) got) - buf_offset,
- &new_offset,
- &frame_data,
- &frame_len);
- if (0 > status)
- {
- /* an error occurred and the connection must be closed */
- if (NULL != frame_data)
- {
- MHD_websocket_free (ws, frame_data);
- }
- break;
- }
- else
- {
- buf_offset += new_offset;
- if (0 < status)
- {
- /* the frame is complete */
- switch (status)
- {
- case MHD_WEBSOCKET_STATUS_TEXT_FRAME:
- /* The client has sent some text.
- * We will display it and answer with a text frame.
- */
- if (NULL != frame_data)
- {
- printf ("Received message: %s\n", frame_data);
- MHD_websocket_free (ws, frame_data);
- frame_data = NULL;
- }
- result = MHD_websocket_encode_text (ws,
- "Hello",
- 5, /* length of "Hello" */
- 0,
- &frame_data,
- &frame_len,
- NULL);
- if (0 == result)
- {
- send_all (fd,
- frame_data,
- frame_len);
- }
- break;
-
- case MHD_WEBSOCKET_STATUS_CLOSE_FRAME:
- /* if we receive a close frame, we will respond with one */
- MHD_websocket_free (ws,
- frame_data);
- frame_data = NULL;
-
- result = MHD_websocket_encode_close (ws,
- 0,
- NULL,
- 0,
- &frame_data,
- &frame_len);
- if (0 == result)
- {
- send_all (fd,
- frame_data,
- frame_len);
- }
- break;
-
- case MHD_WEBSOCKET_STATUS_PING_FRAME:
- /* if we receive a ping frame, we will respond */
- /* with the corresponding pong frame */
- {
- char *pong = NULL;
- size_t pong_len = 0;
- result = MHD_websocket_encode_pong (ws,
- frame_data,
- frame_len,
- &pong,
- &pong_len);
- if (0 == result)
- {
- send_all (fd,
- pong,
- pong_len);
- }
- MHD_websocket_free (ws,
- pong);
- }
- break;
-
- default:
- /* Other frame types are ignored
- * in this minimal example.
- * This is valid, because they become
- * automatically skipped if we receive them unexpectedly
- */
- break;
- }
- }
- if (NULL != frame_data)
- {
- MHD_websocket_free (ws, frame_data);
- }
- }
- }
- }
-
- /* free the websocket stream */
- MHD_websocket_stream_free (ws);
-
- /* close the socket when it is not needed anymore */
- MHD_upgrade_action (urh,
- MHD_UPGRADE_ACTION_CLOSE);
-}
-
-/* This helper function is used for the case that
- * we need to resend some data
- */
-static void
-send_all (MHD_socket fd,
- const char *buf,
- size_t len)
-{
- ssize_t ret;
- size_t off;
-
- for (off = 0; off < len; off += ret)
- {
- ret = send (fd,
- &buf[off],
- (int) (len - off),
- 0);
- if (0 > ret)
- {
- if (EAGAIN == errno)
- {
- ret = 0;
- continue;
- }
- break;
- }
- if (0 == ret)
- break;
- }
-}
-
-/* This helper function contains operating-system-dependent code and
- * is used to make a socket blocking.
- */
-static void
-make_blocking (MHD_socket fd)
-{
-#if defined(MHD_POSIX_SOCKETS)
- int flags;
-
- flags = fcntl (fd, F_GETFL);
- if (-1 == flags)
- return;
- if ((flags & ~O_NONBLOCK) != flags)
- if (-1 == fcntl (fd, F_SETFL, flags & ~O_NONBLOCK))
- abort ();
-#elif defined(MHD_WINSOCK_SOCKETS)
- unsigned long flags = 0;
-
- ioctlsocket (fd, FIONBIO, &flags);
-#endif /* MHD_WINSOCK_SOCKETS */
-}
-
-@end verbatim
-@noindent
-
-
-Please note that the websocket in this example is only half-duplex.
-It waits until the blocking @code{recv()} call returns and
-only does then something.
-In this example all frame types are decoded by @emph{libmicrohttpd_ws},
-but we only do something when a text, ping or close frame is received.
-Binary and pong frames are ignored in our code.
-This is legit, because the server is only required to implement at
-least support for ping frame or close frame (the other frame types
-could be skipped in theory, because they don't require an answer).
-The pong frame doesn't require an answer and whether text frames or
-binary frames get an answer simply belongs to your server application.
-So this is a valid minimal example.
-
-Until this point you've learned everything you need to basically
-use websockets with @emph{libmicrohttpd} and @emph{libmicrohttpd_ws}.
-These libraries offer much more functions for some specific cases.
-
-
-The further chapters of this tutorial focus on some specific problems
-and the client site programming.
-
-
-@heading Using full-duplex websockets
-
-To use full-duplex websockets you can simply create two threads
-per websocket connection.
-One of these threads is used for receiving data with
-a blocking @code{recv()} call and the other thread is triggered
-by the application internal codes and sends the data.
-
-A full-duplex websocket example is implemented in the example file
-@code{websocket_chatserver_example.c}.
-
-@heading Error handling
-
-The most functions of @emph{libmicrohttpd_ws} return a value
-of @code{enum MHD_WEBSOCKET_STATUS}.
-The values of this enumeration can be converted into an integer
-and have an easy interpretation:
-
-@itemize @bullet
-@item
-If the value is less than zero an error occurred and the call has failed.
-Check the enumeration values for more specific information.
-
-@item
-If the value is equal to zero, the call succeeded.
-
-@item
-If the value is greater than zero, the call succeeded and the value
-specifies the decoded frame type.
-Currently positive values are only returned by @code{MHD_websocket_decode()}
-(of the functions with this return enumeration type).
-
-@end itemize
-
-A websocket stream can also get broken when invalid frame data is received.
-Also the other site could send a close frame which puts the stream into
-a state where it may not be used for regular communication.
-Whether a stream has become broken, can be checked with
-@code{MHD_websocket_stream_is_valid()}.
-
-
-@heading Fragmentation
-
-In addition to the regular TCP/IP fragmentation the websocket protocol also
-supports fragmentation.
-Fragmentation could be used for continuous payload data such as video data
-from a webcam.
-Whether or not you want to receive fragmentation is specified upon
-initialization of the websocket stream.
-If you pass @code{MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS} in the flags parameter
-of @code{MHD_websocket_stream_init()} then you can receive fragments.
-If you don't pass this flag (in the most cases you just pass zero as flags)
-then you don't want to handle fragments on your own.
-@emph{libmicrohttpd_ws} removes then the fragmentation for you
-in the background.
-You only get the completely assembled frames.
-
-Upon encoding you specify whether or not you want to create a fragmented frame
-by passing a flag to the corresponding encode function.
-Only @code{MHD_websocket_encode_text()} and @code{MHD_websocket_encode_binary()}
-can be used for fragmentation, because the other frame types may
-not be fragmented.
-Encoding fragmented frames is independent of
-the @code{MHD_WEBSOCKET_FLAG_WANT_FRAGMENTS} flag upon initialization.
-
-@heading Quick guide to websockets in JavaScript
-
-Websockets are supported in all modern web browsers.
-You initialize a websocket connection by creating an instance of
-the @code{WebSocket} class provided by the web browser.
-
-There are some simple rules for using websockets in the browser:
-
-@itemize @bullet
-@item
-When you initialize the instance of the websocket class you must pass an URL.
-The URL must either start with @code{ws://}
-(for not encrypted websocket protocol) or @code{wss://}
-(for TLS-encrypted websocket protocol).
-
-@strong{IMPORTANT:} If your website is accessed via @code{https://}
-then you are in a security context, which means that you are only allowed to
-access other secure protocols.
-So you can only use @code{wss://} for websocket connections then.
-If you try to @code{ws://} instead then your websocket connection will
-automatically fail.
-
-@item
-The WebSocket class uses events to handle the receiving of data.
-JavaScript is per definition a single-threaded language so
-the receiving events will never overlap.
-Sending is done directly by calling a method of the instance of
-the WebSocket class.
-
-@end itemize
-
-
-Here is a short example for receiving/sending data to the same host
-as the website is running on:
-
-@verbatim
-
-
-
-
-Websocket Demo
-
-
-
-
-
-
-@end verbatim
-@noindent
diff --git a/doc/examples/.gitignore b/doc/examples/.gitignore
index bffda70a..97b8b511 100644
--- a/doc/examples/.gitignore
+++ b/doc/examples/.gitignore
@@ -1,3 +1,4 @@
+/upgrade
/tlsauthentication
/simplepost
/sessions
@@ -5,6 +6,7 @@
/logging
/largepost
/hellobrowser
+/callbackresponse
/basicauthentication
*.exe
*.o
diff --git a/doc/examples/Makefile.am b/doc/examples/Makefile.am
index e28fdf6c..579132dc 100644
--- a/doc/examples/Makefile.am
+++ b/doc/examples/Makefile.am
@@ -21,10 +21,16 @@ $(top_builddir)/src/microhttpd/libmicrohttpd.la: $(top_builddir)/src/microhttpd/
# example programs
noinst_PROGRAMS = \
+ callbackresponse \
hellobrowser \
logging \
responseheaders
-
+
+if ENABLE_UPGRADE
+noinst_PROGRAMS += \
+ upgrade
+endif
+
if ENABLE_BAUTH
noinst_PROGRAMS += \
basicauthentication
@@ -42,19 +48,20 @@ if HAVE_W32
AM_CPPFLAGS += -DWINDOWS
endif
-if HAVE_EXPERIMENTAL
-noinst_PROGRAMS += websocket
-endif
-
basicauthentication_SOURCES = \
basicauthentication.c
basicauthentication_LDADD = \
$(top_builddir)/src/microhttpd/libmicrohttpd.la
+callbackresponse_SOURCES = \
+ callbackresponse.c
+callbackresponse_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
+
hellobrowser_SOURCES = \
- hellobrowser.c
+ hellobrowser.c
hellobrowser_LDADD = \
- $(top_builddir)/src/microhttpd/libmicrohttpd.la
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
logging_SOURCES = \
logging.c
@@ -86,8 +93,7 @@ largepost_SOURCES = \
largepost_LDADD = \
$(top_builddir)/src/microhttpd/libmicrohttpd.la
-websocket_SOURCES = \
- websocket.c
-websocket_LDADD = \
- $(top_builddir)/src/microhttpd/libmicrohttpd.la \
- $(top_builddir)/src/microhttpd_ws/libmicrohttpd_ws.la
+upgrade_SOURCES = \
+ upgrade.c
+upgrade_LDADD = \
+ $(top_builddir)/src/microhttpd/libmicrohttpd.la
diff --git a/doc/examples/callbackresponse.c b/doc/examples/callbackresponse.c
new file mode 100644
index 00000000..93e22696
--- /dev/null
+++ b/doc/examples/callbackresponse.c
@@ -0,0 +1,281 @@
+/* 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
+#ifndef _WIN32
+#include
+#include
+#else
+#include
+#endif
+#include
+#include
+#include
+#include
+
+#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;
+}
diff --git a/doc/examples/largepost.c b/doc/examples/largepost.c
index d52cabe0..ed080aaa 100644
--- a/doc/examples/largepost.c
+++ b/doc/examples/largepost.c
@@ -92,7 +92,9 @@ send_page (struct MHD_Connection *connection,
enum MHD_Result ret;
struct MHD_Response *response;
- response = MHD_create_response_from_buffer_static (strlen (page), page);
+ /* 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 !=
@@ -319,7 +321,7 @@ answer_to_connection (void *cls,
con_info->answercode);
}
- /* Note a GET or a POST, generate error */
+ /* Not a GET or a POST, generate error */
return send_page (connection,
errorpage,
MHD_HTTP_BAD_REQUEST);
diff --git a/doc/examples/responseheaders.c b/doc/examples/responseheaders.c
index fd8807d8..f90c119c 100644
--- a/doc/examples/responseheaders.c
+++ b/doc/examples/responseheaders.c
@@ -63,7 +63,7 @@ answer_to_connection (void *cls, struct MHD_Connection *connection,
return MHD_NO;
}
response =
- MHD_create_response_from_fd_at_offset64 ((size_t) sbuf.st_size,
+ MHD_create_response_from_fd_at_offset64 ((uint64_t) sbuf.st_size,
fd,
0);
if (MHD_YES !=
diff --git a/doc/examples/sessions.c b/doc/examples/sessions.c
index 86caaa20..be92ff9c 100644
--- a/doc/examples/sessions.c
+++ b/doc/examples/sessions.c
@@ -449,9 +449,8 @@ not_found_page (const void *cls,
/* unsupported HTTP method */
response = MHD_create_response_from_buffer_static (strlen (NOT_FOUND_ERROR),
NOT_FOUND_ERROR);
- ret = MHD_queue_response (connection,
- MHD_HTTP_NOT_FOUND,
- response);
+ /* 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,
@@ -461,6 +460,9 @@ not_found_page (const void *cls,
"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;
}
@@ -474,7 +476,7 @@ static const struct Page pages[] = {
{ "/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, NULL, ¬_found_page, NULL } /* 404 */
+ { NULL, "text/html", ¬_found_page, NULL } /* 404 */
};
diff --git a/doc/examples/simplepost.c b/doc/examples/simplepost.c
index 61c34231..1fa20a11 100644
--- a/doc/examples/simplepost.c
+++ b/doc/examples/simplepost.c
@@ -39,7 +39,7 @@ static const char *askpage =
"