libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

commit e9aa6dcdc1a3db145d7a77de3472e0a5e4a8235c
parent f2e3bbda41c6263527808187c45f90b1704332f9
Author: Christian Grothoff <christian@grothoff.org>
Date:   Sat, 16 Aug 2025 15:48:06 +0200

fix rvalues (#9667)

Diffstat:
Mdoc/chapters/largerpost.inc | 138++++++++++++++++++++++++++++++++++++++++----------------------------------------
Mdoc/chapters/processingpost.inc | 94++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mdoc/chapters/responseheaders.inc | 58+++++++++++++++++++++++++++++-----------------------------
Mdoc/chapters/websocket.inc | 2+-
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. */