1The most basic task for a HTTP server is to deliver a static text message to any client connecting to it. 2Given that this is also easy to implement, it is an excellent problem to start with. 3 4For now, the particular URI the client asks for shall have no effect on the message that will 5be returned. In addition, the server shall end the connection after the message has been sent so that 6the client will know there is nothing more to expect. 7 8The C program @code{hellobrowser.c}, which is to be found in the examples section, does just that. 9If you are very eager, you can compile and start it right away but it is advisable to type the 10lines in by yourself as they will be discussed and explained in detail. 11 12After the necessary includes and the definition of the port which our server should listen on 13@verbatim 14#include <sys/types.h> 15#include <sys/select.h> 16#include <sys/socket.h> 17#include <microhttpd.h> 18 19#define PORT 8888 20 21@end verbatim 22 23@noindent 24the desired behaviour of our server when HTTP request arrive has to be implemented. We already have 25agreed that it should not care about the particular details of the request, such as who is requesting 26what. The server will respond merely with the same small HTML page to every request. 27 28The function we are going to write now will be called by @emph{GNU libmicrohttpd} every time an 29appropriate request comes in. While the name of this callback function is arbitrary, its parameter 30list has to follow a certain layout. So please, ignore the lot of parameters for now, they will be 31explained at the point they are needed. We have to use only one of them, 32@code{struct MHD_Connection *connection}, for the minimalistic functionality we want to archive at the moment. 33 34This parameter is set by the @emph{libmicrohttpd} daemon and holds the necessary information to 35relate the call with a certain connection. Keep in mind that a server might have to satisfy hundreds 36of concurrent connections and we have to make sure that the correct data is sent to the destined 37client. Therefore, this variable is a means to refer to a particular connection if we ask the 38daemon to sent the reply. 39 40Talking about the reply, it is defined as a string right after the function header 41@verbatim 42int answer_to_connection (void *cls, struct MHD_Connection *connection, 43 const char *url, 44 const char *method, const char *version, 45 const char *upload_data, 46 size_t *upload_data_size, void **con_cls) 47{ 48 const char *page = "<html><body>Hello, browser!</body></html>"; 49 50@end verbatim 51 52@noindent 53HTTP is a rather strict protocol and the client would certainly consider it "inappropriate" if we 54just 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 55just have to ask. Our reply string packed in the necessary layers will be called a "response". 56To obtain such a response we hand our data (the reply--string) and its size over to the 57@code{MHD_create_response_from_buffer} function. The last two parameters basically tell @emph{MHD} 58that we do not want it to dispose the message data for us when it has been sent and there also needs 59no internal copy to be done because the @emph{constant} string won't change anyway. 60 61@verbatim 62 struct MHD_Response *response; 63 int ret; 64 65 response = MHD_create_response_from_buffer (strlen (page), 66 (void*) page, MHD_RESPMEM_PERSISTENT); 67 68@end verbatim 69 70@noindent 71Now that the the response has been laced up, it is ready for delivery and can be queued for sending. 72This is done by passing it to another @emph{GNU libmicrohttpd} function. As all our work was done in 73the scope of one function, the recipient is without doubt the one associated with the 74local variable @code{connection} and consequently this variable is given to the queue function. 75Every HTTP response is accompanied by a status code, here "OK", so that the client knows 76this response is the intended result of his request and not due to some error or malfunction. 77 78Finally, the packet is destroyed and the return value from the queue returned, 79already being set at this point to either MHD_YES or MHD_NO in case of success or failure. 80 81@verbatim 82 ret = MHD_queue_response (connection, MHD_HTTP_OK, response); 83 MHD_destroy_response (response); 84 85 return ret; 86} 87 88@end verbatim 89 90@noindent 91With the primary task of our server implemented, we can start the actual server daemon which will listen 92on @code{PORT} for connections. This is done in the main function. 93@verbatim 94int main () 95{ 96 struct MHD_Daemon *daemon; 97 98 daemon = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY, PORT, NULL, NULL, 99 &answer_to_connection, NULL, MHD_OPTION_END); 100 if (NULL == daemon) return 1; 101 102@end verbatim 103 104@noindent 105The first parameter is one of three possible modes of operation. Here we want the daemon to run in 106a separate thread and to manage all incoming connections in the same thread. This means that while 107producing the response for one connection, the other connections will be put on hold. In this 108example, where the reply is already known and therefore the request is served quickly, this poses no problem. 109 110We will allow all clients to connect regardless of their name or location, therefore we do not check 111them on connection and set the forth and fifth parameter to NULL. 112 113Parameter six is the address of the function we want to be called whenever a new connection has been 114established. Our @code{answer_to_connection} knows best what the client wants and needs no additional 115information (which could be passed via the next parameter) so the next parameter is NULL. Likewise, 116we do not need to pass extra options to the daemon so we just write the MHD_OPTION_END as the last parameter. 117 118As the server daemon runs in the background in its own thread, the execution flow in our main 119function will contine right after the call. Because of this, we must delay the execution flow in the 120main thread or else the program will terminate prematurely. We let it pause in a processing-time 121friendly manner by waiting for the enter key to be pressed. In the end, we stop the daemon so it can 122do its cleanup tasks. 123@verbatim 124 getchar (); 125 126 MHD_stop_daemon (daemon); 127 return 0; 128} 129 130@end verbatim 131 132@noindent 133The first example is now complete. 134 135Compile it with 136@verbatim 137cc hellobrowser.c -o hellobrowser -I$PATH_TO_LIBMHD_INCLUDES 138 -L$PATH_TO_LIBMHD_LIBS -lmicrohttpd 139@end verbatim 140with the two paths set accordingly and run it. 141 142Now open your favorite Internet browser and go to the address @code{http://localhost:8888/}, provided that 8888 143is the port you chose. If everything works as expected, the browser will present the message of the 144static HTML page it got from our minimal server. 145 146@heading Remarks 147To keep this first example as small as possible, some drastic shortcuts were taken and are to be 148discussed now. 149 150Firstly, there is no distinction made between the kinds of requests a client could send. We implied 151that the client sends a GET request, that means, that he actually asked for some data. Even when 152it is not intended to accept POST requests, a good server should at least recognize that this 153request does not constitute a legal request and answer with an error code. This can be easily 154implemented by checking if the parameter @code{method} equals the string "GET" and returning a 155@code{MHD_NO} if not so. 156 157Secondly, the above practice of queuing a response upon the first call of the callback function 158brings with it some limitations. This is because the content of the message body will not be 159received if a response is queued in the first iteration. Furthermore, the connection will be closed 160right after the response has been transferred then. This is typically not what you want as it 161disables HTTP pipelining. The correct approach is to simply not queue a message on the first 162callback unless there is an error. The @code{void**} argument to the callback provides a location 163for storing information about the history of the connection; for the first call, the pointer 164will point to NULL. A simplistic way to differenciate the first call from others is to check 165if the pointer is NULL and set it to a non-NULL value during the first call. 166 167Both of these issues you will find addressed in the official @code{minimal_example.c} residing in 168the @code{src/examples} directory of the @emph{MHD} package. The source code of this 169program should look very familiar to you by now and easy to understand. 170 171For our example, the @code{must_copy} and @code{must_free} parameter at the response construction 172function could be set to @code{MHD_NO}. In the usual case, responses cannot be sent immediately 173after being queued. For example, there might be other data on the system that needs to be sent with 174a higher priority. Nevertheless, the queue function will return successfully---raising the problem 175that the data we have pointed to may be invalid by the time it is about being sent. This is not an 176issue here because we can expect the @code{page} string, which is a constant @emph{string literal} 177here, to be static. That means it will be present and unchanged for as long as the program runs. 178For dynamic data, one could choose to either have @emph{MHD} free the memory @code{page} points 179to itself when it is not longer needed or, alternatively, have the library to make and manage 180its own copy of it. 181 182@heading Exercises 183@itemize @bullet 184@item 185While the server is running, use a program like @code{telnet} or @code{netcat} to connect to it. Try to form a 186valid HTTP 1.1 request yourself like 187@verbatim 188GET /dontcare HTTP/1.1 189Host: itsme 190<enter> 191@end verbatim 192@noindent 193and see what the server returns to you. 194 195 196@item 197Also, try other requests, like POST, and see how our server does not mind and why. 198How far in malforming a request can you go before the builtin functionality of @emph{MHD} intervenes 199and an altered response is sent? Make sure you read about the status codes in the @emph{RFC}. 200 201 202@item 203Add the option @code{MHD_USE_PEDANTIC_CHECKS} to the start function of the daemon in @code{main}. 204Mind the special format of the parameter list here which is described in the manual. How indulgent 205is the server now to your input? 206 207 208@item 209Let the main function take a string as the first command line argument and pass @code{argv[1]} to 210the @code{MHD_start_daemon} function as the sixth parameter. The address of this string will be 211passed to the callback function via the @code{cls} variable. Decorate the text given at the command 212line when the server is started with proper HTML tags and send it as the response instead of the 213former static string. 214 215 216@item 217@emph{Demanding:} Write a separate function returning a string containing some useful information, 218for example, the time. Pass the function's address as the sixth parameter and evaluate this function 219on every request anew in @code{answer_to_connection}. Remember to free the memory of the string 220every time after satisfying the request. 221 222@end itemize 223