commit e9aa6dcdc1a3db145d7a77de3472e0a5e4a8235c
parent f2e3bbda41c6263527808187c45f90b1704332f9
Author: Christian Grothoff <christian@grothoff.org>
Date: Sat, 16 Aug 2025 15:48:06 +0200
fix rvalues (#9667)
Diffstat:
4 files changed, 147 insertions(+), 145 deletions(-)
diff --git a/doc/chapters/largerpost.inc b/doc/chapters/largerpost.inc
@@ -1,12 +1,12 @@
-The previous chapter introduced a way to upload data to the server, but the developed example program
+The previous chapter introduced a way to upload data to the server, but the developed example program
has some shortcomings, such as not being able to handle larger chunks of data. In this chapter, we
-are going to discuss a more advanced server program that allows clients to upload a file in order to
+are going to discuss a more advanced server program that allows clients to upload a file in order to
have it stored on the server's filesystem. The server shall also watch and limit the number of
clients concurrently uploading, responding with a proper busy message if necessary.
@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{SELECT_INTERNALLY} 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.
@@ -20,13 +20,13 @@ static unsigned int nr_of_uploading_clients = 0;
If there are too many clients uploading, we want the server to respond to all requests with a busy
message.
@verbatim
-const char* busypage =
+const char* busypage =
"<html><body>This server is busy, please try again later.</body></html>";
@end verbatim
@noindent
-Otherwise, the server will send a @emph{form} that informs the user of the current number of uploading clients,
-and ask her to pick a file on her local filesystem which is to be uploaded.
+Otherwise, the server will send a @emph{form} that informs the user of the current number of uploading clients,
+and ask her to pick a file on her local filesystem which is to be uploaded.
@verbatim
const char* askpage = "<html><body>\n\
Upload a file, please!<br>\n\
@@ -46,31 +46,31 @@ const char* completepage = "<html><body>The upload has been completed.</body></h
@noindent
We want the server to report internal errors, such as memory shortage or file access problems,
-adequately.
+adequately.
@verbatim
-const char* servererrorpage
+const char* servererrorpage
= "<html><body>An internal server error has occurred.</body></html>";
const char* fileexistspage
= "<html><body>This file already exists.</body></html>";
@end verbatim
@noindent
-It would be tolerable to send all these responses undifferentiated with a @code{200 HTTP_OK}
-status code but in order to improve the @code{HTTP} conformance of our server a bit, we extend the
-@code{send_page} function so that it accepts individual status codes.
+It would be tolerable to send all these responses undifferentiated with a @code{200 HTTP_OK}
+status code but in order to improve the @code{HTTP} conformance of our server a bit, we extend the
+@code{send_page} function so that it accepts individual status codes.
@verbatim
-static int
-send_page (struct MHD_Connection *connection,
+static enum MHD_Result
+send_page (struct MHD_Connection *connection,
const char* page, int status_code)
{
- int ret;
+ enum MHD_Result ret;
struct MHD_Response *response;
-
- response = MHD_create_response_from_buffer (strlen (page), (void*) page,
+
+ response = MHD_create_response_from_buffer (strlen (page), (void*) page,
MHD_RESPMEM_MUST_COPY);
if (!response) return MHD_NO;
-
+
ret = MHD_queue_response (connection, status_code, response);
MHD_destroy_response (response);
@@ -84,29 +84,29 @@ 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
+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
a postprocessor has been created and the post iterator is called at least once.
@verbatim
-static int
-answer_to_connection (void *cls, struct MHD_Connection *connection,
- const char *url,
- const char *method, const char *version,
- const char *upload_data,
+static enum MHD_Result
+answer_to_connection (void *cls, struct MHD_Connection *connection,
+ const char *url,
+ const char *method, const char *version,
+ const char *upload_data,
size_t *upload_data_size, void **req_cls)
{
- if (NULL == *req_cls)
+ if (NULL == *req_cls)
{
struct connection_info_struct *con_info;
- if (nr_of_uploading_clients >= MAXCLIENTS)
+ if (nr_of_uploading_clients >= MAXCLIENTS)
return send_page(connection, busypage, MHD_HTTP_SERVICE_UNAVAILABLE);
@end verbatim
@noindent
-If the server is not busy, the @code{connection_info} structure is initialized as usual, with
+If the server is not busy, the @code{connection_info} structure is initialized as usual, with
the addition of a filepointer for each connection.
@verbatim
@@ -114,44 +114,44 @@ the addition of a filepointer for each connection.
if (NULL == con_info) return MHD_NO;
con_info->fp = 0;
- if (0 == strcmp (method, "POST"))
- {
+ if (0 == strcmp (method, "POST"))
+ {
...
- }
+ }
else con_info->connectiontype = GET;
*req_cls = (void*) con_info;
-
+
return MHD_YES;
}
@end verbatim
@noindent
-For @emph{POST} requests, the postprocessor is created and we register a new uploading client. From
+For @emph{POST} requests, the postprocessor is created and we register a new uploading client. From
this point on, there are many possible places for errors to occur that make it necessary to interrupt
-the uploading process. We need a means of having the proper response message ready at all times.
+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".
@verbatim
- if (0 == strcmp (method, "POST"))
- {
- con_info->postprocessor
- = MHD_create_post_processor (connection, POSTBUFFERSIZE,
- iterate_post, (void*) con_info);
+ if (0 == strcmp (method, "POST"))
+ {
+ con_info->postprocessor
+ = MHD_create_post_processor (connection, POSTBUFFERSIZE,
+ iterate_post, (void*) con_info);
- if (NULL == con_info->postprocessor)
+ if (NULL == con_info->postprocessor)
{
- free (con_info);
+ free (con_info);
return MHD_NO;
}
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
@noindent
@@ -160,14 +160,13 @@ If the connection handler is called for the second time, @emph{GET} requests wil
the @emph{form}. We can keep the buffer under function scope, because we asked @emph{MHD} to make its
own copy of it for as long as it is needed.
@verbatim
- if (0 == strcmp (method, "GET"))
+ if (0 == strcmp (method, "GET"))
{
- int ret;
char buffer[1024];
-
+
sprintf (buffer, askpage, nr_of_uploading_clients);
- return send_page (connection, buffer, MHD_HTTP_OK);
- }
+ return send_page (connection, buffer, MHD_HTTP_OK);
+ }
@end verbatim
@noindent
@@ -177,22 +176,22 @@ example, except the more flexible content of the responses. The @emph{POST} data
there is none left and the execution falls through to return an error page if the connection
constituted no expected request method.
@verbatim
- if (0 == strcmp (method, "POST"))
+ if (0 == strcmp (method, "POST"))
{
struct connection_info_struct *con_info = *req_cls;
-
- if (0 != *upload_data_size)
- {
+
+ if (0 != *upload_data_size)
+ {
MHD_post_process (con_info->postprocessor,
upload_data, *upload_data_size);
*upload_data_size = 0;
-
+
return MHD_YES;
- }
- else
- return send_page (connection, con_info->answerstring,
+ }
+ else
+ return send_page (connection, con_info->answerstring,
con_info->answercode);
- }
+ }
return send_page(connection, errorpage, MHD_HTTP_BAD_REQUEST);
}
@@ -206,11 +205,11 @@ several times now. This means that for any given connection (there might be seve
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.
@verbatim
-static int
-iterate_post (void *coninfo_cls, enum MHD_ValueKind kind,
+static enum MHD_Result
+iterate_post (void *coninfo_cls, enum MHD_ValueKind kind,
const char *key,
const char *filename, const char *content_type,
- const char *transfer_encoding, const char *data,
+ const char *transfer_encoding, const char *data,
uint64_t off, size_t size)
{
struct connection_info_struct *con_info = coninfo_cls;
@@ -249,19 +248,19 @@ race between the two "fopen" calls, but we will overlook this for portability sa
con_info->answercode = MHD_HTTP_FORBIDDEN;
return MHD_NO;
}
-
+
con_info->fp = fopen (filename, "ab");
- if (!con_info->fp) return MHD_NO;
+ if (!con_info->fp) return MHD_NO;
}
@end verbatim
@noindent
-Occasionally, the iterator function will be called even when there are 0 new bytes to process. The
+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;
}
@@ -283,7 +282,8 @@ 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 request_completed (void *cls, struct MHD_Connection *connection,
+void
+request_completed (void *cls, struct MHD_Connection *connection,
void **req_cls,
enum MHD_RequestTerminationCode toe)
{
@@ -293,17 +293,17 @@ void request_completed (void *cls, struct MHD_Connection *connection,
if (con_info->connectiontype == POST)
{
- if (NULL != con_info->postprocessor)
+ if (NULL != con_info->postprocessor)
{
- MHD_destroy_post_processor (con_info->postprocessor);
+ MHD_destroy_post_processor (con_info->postprocessor);
nr_of_uploading_clients--;
}
- if (con_info->fp) fclose (con_info->fp);
+ if (con_info->fp) fclose (con_info->fp);
}
free (con_info);
- *req_cls = NULL;
+ *req_cls = NULL;
}
@end verbatim
@noindent
diff --git a/doc/chapters/processingpost.inc b/doc/chapters/processingpost.inc
@@ -1,4 +1,4 @@
-The previous chapters already have demonstrated a variety of possibilities to send information
+The previous chapters already have demonstrated a variety of possibilities to send information
to the HTTP server, but it is not recommended that the @emph{GET} method is used to alter the way
the server operates. To induce changes on the server, the @emph{POST} method is preferred over
and is much more powerful than @emph{GET} and will be introduced in this chapter.
@@ -26,7 +26,7 @@ const char* askpage = "<html><body>\
The @code{action} entry is the @emph{URI} to be called by the browser when posting, and the
@code{name} will be used later to be sure it is the editbox's content that has been posted.
-We also prepare the answer page, where the name is to be filled in later, and an error page
+We also prepare the answer page, where the name is to be filled in later, and an error page
as the response for anything but proper @emph{GET} and @emph{POST} requests:
@verbatim
@@ -38,7 +38,7 @@ const char* errorpage="<html><body>This doesn't seem to be right.</body></html>"
Whenever we need to send a page, we use an extra function
@code{int send_page(struct MHD_Connection *connection, const char* page)}
-for this, which does not contain anything new and whose implementation is therefore
+for this, which does not contain anything new and whose implementation is therefore
not discussed further in the tutorial.
@@ -46,13 +46,13 @@ not discussed further in the tutorial.
Posted data can be of arbitrary and considerable size; for example, if a user uploads a big
image to the server. Similar to the case of the header fields, there may also be different streams
of posted data, such as one containing the text of an editbox and another the state of a button.
-Likewise, we will have to register an iterator function that is going to be called maybe several times
+Likewise, we will have to register an iterator function that is going to be called maybe several times
not only if there are different POSTs but also if one POST has only been received partly yet and
needs processing before another chunk can be received.
Such an iterator function is called by a @emph{postprocessor}, which must be created upon arriving
of the post request. We want the iterator function to read the first post data which is tagged
-@code{name} and to create an individual greeting string based on the template and the name.
+@code{name} and to create an individual greeting string based on the template and the name.
But in order to pass this string to other functions and still be able to differentiate different
connections, we must first define a structure to share the information, holding the most import entries.
@@ -61,12 +61,12 @@ struct connection_info_struct
{
int connectiontype;
char *answerstring;
- struct MHD_PostProcessor *postprocessor;
+ struct MHD_PostProcessor *postprocessor;
};
@end verbatim
@noindent
-With these information available to the iterator function, it is able to fulfill its task.
+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
@@ -74,10 +74,10 @@ chunks, we had to expand the namestring dynamically as additional parts of it wi
came in. But in this example, the name is assumed to fit entirely inside one single packet.
@verbatim
-static int
+static enum MHD_Result
iterate_post (void *coninfo_cls, enum MHD_ValueKind kind, const char *key,
const char *filename, const char *content_type,
- const char *transfer_encoding, const char *data,
+ const char *transfer_encoding, const char *data,
uint64_t off, size_t size)
{
struct connection_info_struct *con_info = coninfo_cls;
@@ -89,10 +89,10 @@ iterate_post (void *coninfo_cls, enum MHD_ValueKind kind, const char *key,
char *answerstring;
answerstring = malloc (MAXANSWERSIZE);
if (!answerstring) return MHD_NO;
-
+
snprintf (answerstring, MAXANSWERSIZE, greatingpage, data);
- con_info->answerstring = answerstring;
- }
+ con_info->answerstring = answerstring;
+ }
else con_info->answerstring = NULL;
return MHD_NO;
@@ -106,25 +106,27 @@ iterate_post (void *coninfo_cls, enum MHD_ValueKind kind, const char *key,
Once a connection has been established, it can be terminated for many reasons. As these
reasons include unexpected events, we have to register another function that cleans up any resources
that might have been allocated for that connection by us, namely the post processor and the greetings
-string. This cleanup function must take into account that it will also be called for finished
+string. This cleanup function must take into account that it will also be called for finished
requests other than @emph{POST} requests.
@verbatim
-void request_completed (void *cls, struct MHD_Connection *connection,
+void
+request_completed (void *cls, struct MHD_Connection *connection,
void **req_cls,
enum MHD_RequestTerminationCode toe)
{
struct connection_info_struct *con_info = *req_cls;
- if (NULL == con_info) return;
+ if (NULL == con_info)
+ return;
if (con_info->connectiontype == POST)
{
- MHD_destroy_post_processor (con_info->postprocessor);
+ MHD_destroy_post_processor (con_info->postprocessor);
if (con_info->answerstring) free (con_info->answerstring);
}
-
+
free (con_info);
- *req_cls = NULL;
+ *req_cls = NULL;
}
@end verbatim
@noindent
@@ -135,7 +137,7 @@ in the main function.
@verbatim
...
daemon = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD, PORT, NULL, NULL,
- &answer_to_connection, NULL,
+ &answer_to_connection, NULL,
MHD_OPTION_NOTIFY_COMPLETED, &request_completed, NULL,
MHD_OPTION_END);
...
@@ -145,19 +147,19 @@ daemon = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD, PORT, NULL, NULL,
@heading Request handling
With all other functions prepared, we can now discuss the actual request handling.
-On the first iteration for a new request, we start by allocating a new instance of a
+On the first iteration for a new request, we start by allocating a new instance of a
@code{struct connection_info_struct} structure, which will store all necessary information for later
iterations and other functions.
@verbatim
-static int
-answer_to_connection (void *cls, struct MHD_Connection *connection,
- const char *url,
- const char *method, const char *version,
- const char *upload_data,
+static enum MHD_Result
+answer_to_connection (void *cls, struct MHD_Connection *connection,
+ const char *url,
+ const char *method, const char *version,
+ const char *upload_data,
size_t *upload_data_size, void **req_cls)
{
- if(NULL == *req_cls)
+ if(NULL == *req_cls)
{
struct connection_info_struct *con_info;
@@ -170,19 +172,19 @@ answer_to_connection (void *cls, struct MHD_Connection *connection,
If the new request is a @emph{POST}, the postprocessor must be created now. In addition, the type
of the request is stored for convenience.
@verbatim
- if (0 == strcmp (method, "POST"))
- {
- con_info->postprocessor
- = MHD_create_post_processor (connection, POSTBUFFERSIZE,
- iterate_post, (void*) con_info);
+ if (0 == strcmp (method, "POST"))
+ {
+ con_info->postprocessor
+ = MHD_create_post_processor (connection, POSTBUFFERSIZE,
+ iterate_post, (void*) con_info);
- if (NULL == con_info->postprocessor)
+ if (NULL == con_info->postprocessor)
{
- free (con_info);
+ free (con_info);
return MHD_NO;
}
con_info->connectiontype = POST;
- }
+ }
else con_info->connectiontype = GET;
@end verbatim
@noindent
@@ -190,7 +192,7 @@ of the request is stored for convenience.
The address of our structure will both serve as the indicator for successive iterations and to remember
the particular details about the connection.
@verbatim
- *req_cls = (void*) con_info;
+ *req_cls = (void*) con_info;
return MHD_YES;
}
@end verbatim
@@ -199,10 +201,10 @@ the particular details about the connection.
The rest of the function will not be executed on the first iteration. A @emph{GET} request is easily
satisfied by sending the question form.
@verbatim
- if (0 == strcmp (method, "GET"))
+ if (0 == strcmp (method, "GET"))
{
- return send_page (connection, askpage);
- }
+ return send_page (connection, askpage);
+ }
@end verbatim
@noindent
@@ -210,27 +212,27 @@ In case of @emph{POST}, we invoke the post processor for as long as data keeps i
@code{*upload_data_size} to zero in order to indicate that we have processed---or at least have
considered---all of it.
@verbatim
- if (0 == strcmp (method, "POST"))
+ if (0 == strcmp (method, "POST"))
{
struct connection_info_struct *con_info = *req_cls;
- if (*upload_data_size != 0)
+ if (*upload_data_size != 0)
{
- MHD_post_process (con_info->postprocessor, upload_data,
+ MHD_post_process (con_info->postprocessor, upload_data,
*upload_data_size);
*upload_data_size = 0;
-
+
return MHD_YES;
- }
- else if (NULL != con_info->answerstring)
+ }
+ else if (NULL != con_info->answerstring)
return send_page (connection, con_info->answerstring);
- }
+ }
@end verbatim
@noindent
Finally, if they are neither @emph{GET} nor @emph{POST} requests, the error page is returned.
@verbatim
- return send_page(connection, errorpage);
+ return send_page(connection, errorpage);
}
@end verbatim
@noindent
diff --git a/doc/chapters/responseheaders.inc b/doc/chapters/responseheaders.inc
@@ -1,7 +1,7 @@
Now that we are able to inspect the incoming request in great detail,
this chapter discusses the means to enrich the outgoing responses likewise.
-As you have learned in the @emph{Hello, Browser} chapter, some obligatory
+As you have learned in the @emph{Hello, Browser} chapter, some obligatory
header fields are added and set automatically for simple responses by the library
itself but if more advanced features are desired, additional fields have to be created.
One of the possible fields is the content type field and an example will be developed around it.
@@ -9,13 +9,13 @@ This will lead to an application capable of correctly serving different types of
When we responded with HTML page packed in the static string previously, the client had no choice
-but guessing about how to handle the response, because the server had not told him.
+but guessing about how to handle the response, because the server had not told him.
What if we had sent a picture or a sound file? Would the message have been understood
or merely been displayed as an endless stream of random characters in the browser?
This is what the mime content types are for. The header of the response is extended
-by certain information about how the data is to be interpreted.
+by certain information about how the data is to be interpreted.
-To introduce the concept, a picture of the format @emph{PNG} will be sent to the client
+To introduce the concept, a picture of the format @emph{PNG} will be sent to the client
and labeled accordingly with @code{image/png}.
Once again, we can base the new example on the @code{hellobrowser} program.
@@ -23,22 +23,22 @@ Once again, we can base the new example on the @code{hellobrowser} program.
#define FILENAME "picture.png"
#define MIMETYPE "image/png"
-static int
-answer_to_connection (void *cls, struct MHD_Connection *connection,
- const char *url,
- const char *method, const char *version,
- const char *upload_data,
+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)
{
unsigned char *buffer = NULL;
struct MHD_Response *response;
@end verbatim
@noindent
-
+
We want the program to open the file for reading and determine its size:
@verbatim
int fd;
- int ret;
+ enum MHD_Result ret;
struct stat sbuf;
if (0 != strcmp (method, "GET"))
@@ -56,15 +56,15 @@ We want the program to open the file for reading and determine its size:
When dealing with files, there is a lot that could go wrong on the
server side and if so, the client should be informed with @code{MHD_HTTP_INTERNAL_SERVER_ERROR}.
-@verbatim
+@verbatim
/* error accessing file */
if (fd != -1) close (fd);
const char *errorstr =
"<html><body>An internal server error has occurred!\
</body></html>";
response =
- MHD_create_response_from_buffer (strlen (errorstr),
- (void *) errorstr,
+ MHD_create_response_from_buffer (strlen (errorstr),
+ (void *) errorstr,
MHD_RESPMEM_PERSISTENT);
if (response)
{
@@ -77,25 +77,25 @@ server side and if so, the client should be informed with @code{MHD_HTTP_INTERNA
}
else
return MHD_NO;
- if (!ret)
+ if (!ret)
{
const char *errorstr = "<html><body>An internal server error has occurred!\
</body></html>";
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,
+ {
+ ret = MHD_queue_response (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
response);
MHD_destroy_response (response);
- return MHD_YES;
- }
+ return MHD_YES;
+ }
else return MHD_NO;
}
@end verbatim
@@ -128,8 +128,8 @@ meta data about the content. Aware of the field's name we want to add, it is as
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.
+We do not have to append a colon expected by the protocol behind the first
+field---@emph{GNU libhttpdmicro} will take care of this.
The function finishes with the well-known lines
@verbatim
@@ -150,7 +150,7 @@ already defined as macros. Thus, we could have written @code{MHD_HTTP_HEADER_CON
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
to these custom header is up to the receiver. Likewise, the client is allowed to send custom request
-headers to the server as well, opening up yet more possibilities how client and server could
+headers to the server as well, opening up yet more possibilities how client and server could
communicate with each other.
The method of creating the response from a file on disk only works for static content.
@@ -162,31 +162,31 @@ Serving dynamically created responses will be a topic of a future chapter.
@item
Remember that the original program was written under a few assumptions---a static response
using a local file being one of them. In order to simulate a very large or hard to reach file that cannot be provided
-instantly, postpone the queuing in the callback with the @code{sleep} function for 30 seconds
+instantly, postpone the queuing in the callback with the @code{sleep} function for 30 seconds
@emph{if} the file @code{/big.png} is requested (but deliver the same as above). A request for
@code{/picture.png} should provide just the same but without any artificial delays.
Now start two instances of your browser (or even use two machines) and see how the second client
is put on hold while the first waits for his request on the slow file to be fulfilled.
-Finally, change the sourcecode to use @code{MHD_USE_THREAD_PER_CONNECTION} when the daemon is
+Finally, change the sourcecode to use @code{MHD_USE_THREAD_PER_CONNECTION} when the daemon is
started and try again.
@item
-Did you succeed in implementing the clock exercise yet? This time, let the server save the
+Did you succeed in implementing the clock exercise yet? This time, let the server save the
program's start time @code{t} and implement a response simulating a countdown that reaches 0 at
@code{t+60}. Returning a message saying on which point the countdown is, the response should
ultimately be to reply "Done" if the program has been running long enough,
An unofficial, but widely understood, response header line is @code{Refresh: DELAY; url=URL} with
-the uppercase words substituted to tell the client it should request the given resource after
+the uppercase words substituted to tell the client it should request the given resource after
the given delay again. Improve your program in that the browser (any modern browser should work)
automatically reconnects and asks for the status again every 5 seconds or so. The URL would have
to be composed so that it begins with "http://", followed by the @emph{URI} the server is reachable
from the client's point of view.
-Maybe you want also to visualize the countdown as a status bar by creating a
+Maybe you want also to visualize the countdown as a status bar by creating a
@code{<table>} consisting of one row and @code{n} columns whose fields contain small images of either
a red or a green light.
diff --git a/doc/chapters/websocket.inc b/doc/chapters/websocket.inc
@@ -308,7 +308,7 @@ access_handler (void *cls,
{
static int aptr;
struct MHD_Response *response;
- int ret;
+ enum MHD_Result ret;
(void) cls; /* Unused. Silent compiler warning. */
(void) upload_data; /* Unused. Silent compiler warning. */