1This chapter will deal with the information which the client sends to the 2server at every request. We are going to examine the most useful fields of such an request 3and print them out in a readable manner. This could be useful for logging facilities. 4 5The starting point is the @emph{hellobrowser} program with the former response removed. 6 7This time, we just want to collect information in the callback function, thus we will 8just return MHD_NO after we have probed the request. This way, the connection is closed 9without much ado by the server. 10 11@verbatim 12static int 13answer_to_connection (void *cls, struct MHD_Connection *connection, 14 const char *url, 15 const char *method, const char *version, 16 const char *upload_data, 17 size_t *upload_data_size, void **con_cls) 18{ 19 ... 20 return MHD_NO; 21} 22@end verbatim 23@noindent 24The ellipsis marks the position where the following instructions shall be inserted. 25 26 27We begin with the most obvious information available to the server, the request line. You should 28already have noted that a request consists of a command (or "HTTP method") and a URI (e.g. a filename). 29It also contains a string for the version of the protocol which can be found in @code{version}. 30To call it a "new request" is justified because we return only @code{MHD_NO}, thus ensuring the 31function will not be called again for this connection. 32@verbatim 33printf ("New %s request for %s using version %s\n", method, url, version); 34@end verbatim 35@noindent 36 37The rest of the information is a bit more hidden. Nevertheless, there is lot of it sent from common 38Internet browsers. It is stored in "key-value" pairs and we want to list what we find in the header. 39As there is no mandatory set of keys a client has to send, each key-value pair is printed out one by 40one until there are no more left. We do this by writing a separate function which will be called for 41each pair just like the above function is called for each HTTP request. 42It can then print out the content of this pair. 43@verbatim 44int print_out_key (void *cls, enum MHD_ValueKind kind, 45 const char *key, const char *value) 46{ 47 printf ("%s: %s\n", key, value); 48 return MHD_YES; 49} 50@end verbatim 51@noindent 52 53To start the iteration process that calls our new function for every key, the line 54@verbatim 55MHD_get_connection_values (connection, MHD_HEADER_KIND, &print_out_key, NULL); 56@end verbatim 57@noindent 58needs to be inserted in the connection callback function too. The second parameter tells the function 59that we are only interested in keys from the general HTTP header of the request. Our iterating 60function @code{print_out_key} does not rely on any additional information to fulfill its duties 61so the last parameter can be NULL. 62 63All in all, this constitutes the complete @code{logging.c} program for this chapter which can be 64found in the @code{examples} section. 65 66Connecting with any modern Internet browser should yield a handful of keys. You should try to 67interpret them with the aid of @emph{RFC 2616}. 68Especially worth mentioning is the "Host" key which is often used to serve several different websites 69hosted under one single IP address but reachable by different domain names (this is called virtual hosting). 70 71@heading Conclusion 72The introduced capabilities to itemize the content of a simple GET request---especially the 73URI---should already allow the server to satisfy clients' requests for small specific resources 74(e.g. files) or even induce alteration of server state. However, the latter is not 75recommended as the GET method (including its header data) is by convention considered a "safe" 76operation, which should not change the server's state in a significant way. By convention, 77GET operations can thus be performed by crawlers and other automatic software. Naturally 78actions like searching for a passed string are fine. 79 80Of course, no transmission can occur while the return value is still set to @code{MHD_NO} in the 81callback function. 82 83@heading Exercises 84@itemize @bullet 85@item 86By parsing the @code{url} string and delivering responses accordingly, implement a small server for 87"virtual" files. When asked for @code{/index.htm@{l@}}, let the response consist of a HTML page 88containing a link to @code{/another.html} page which is also to be created "on the fly" in case of 89being requested. If neither of these two pages are requested, @code{MHD_HTTP_NOT_FOUND} shall be 90returned accompanied by an informative message. 91 92@item 93A very interesting information has still been ignored by our logger---the client's IP address. 94Implement a callback function 95@verbatim 96static int on_client_connect (void *cls, 97 const struct sockaddr *addr, 98 socklen_t addrlen) 99@end verbatim 100@noindent 101that prints out the IP address in an appropriate format. You might want to use the POSIX function 102@code{inet_ntoa} but bear in mind that @code{addr} is actually just a structure containing other 103substructures and is @emph{not} the variable this function expects. 104Make sure to return @code{MHD_YES} so that the library knows the client is allowed to connect 105(and to then process the request). If one wanted to limit access basing on IP addresses, this would be the place 106to do it. The address of your @code{on_client_connect} function must be passed as the third parameter to the 107@code{MHD_start_daemon} call. 108 109@end itemize 110