libmicrohttpd

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

hellobrowser.inc (11961B)


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