diff options
Diffstat (limited to 'doc/chapters/exploringrequests.inc')
-rw-r--r-- | doc/chapters/exploringrequests.inc | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/doc/chapters/exploringrequests.inc b/doc/chapters/exploringrequests.inc new file mode 100644 index 00000000..2e43c38a --- /dev/null +++ b/doc/chapters/exploringrequests.inc @@ -0,0 +1,109 @@ +This chapter will deal with the information which the client sends to the +server at every request. We are going to examine the most useful fields of such an request +and print them out in a readable manner. This could be useful for logging facilities. + +The starting point is the @emph{hellobrowser} program with the former response removed. + +This time, we just want to collect information in the callback function, thus we will +just return MHD_NO after we have probed the request. This way, the connection is closed +without much ado by the server. + +@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, + size_t *upload_data_size, void **con_cls) +{ + ... + return MHD_NO; +} +@end verbatim +@noindent +The ellipsis marks the position where the following instructions shall be inserted. + + +We begin with the most obvious information available to the server, the request line. You should +already have noted that a request consists of a command (or "HTTP method") and a URI (e.g. a filename). +It also contains a string for the version of the protocol which can be found in @code{version}. +To call it a "new request" is justified because we return only @code{MHD_NO}, thus ensuring the +function will not be called again for this connection. +@verbatim +printf ("New %s request for %s using version %s\n", method, url, version); +@end verbatim +@noindent + +The rest of the information is a bit more hidden. Nevertheless, there is lot of it sent from common +Internet browsers. It is stored in "key-value" pairs and we want to list what we find in the header. +As there is no mandatory set of keys a client has to send, each key-value pair is printed out one by +one until there are no more left. We do this by writing a separate function which will be called for +each pair just like the above function is called for each HTTP request. +It can then print out the content of this pair. +@verbatim +int print_out_key (void *cls, enum MHD_ValueKind kind, + const char *key, const char *value) +{ + printf ("%s: %s\n", key, value); + return MHD_YES; +} +@end verbatim +@noindent + +To start the iteration process that calls our new function for every key, the line +@verbatim +MHD_get_connection_values (connection, MHD_HEADER_KIND, &print_out_key, NULL); +@end verbatim +@noindent +needs to be inserted in the connection callback function too. The second parameter tells the function +that we are only interested in keys from the general HTTP header of the request. Our iterating +function @code{print_out_key} does not rely on any additional information to fulfill its duties +so the last parameter can be NULL. + +All in all, this constitutes the complete @code{logging.c} program for this chapter which can be +found in the @code{examples} section. + +Connecting with any modern Internet browser should yield a handful of keys. You should try to +interpret them with the aid of @emph{RFC 2616}. +Especially worth mentioning is the "Host" key which is often used to serve several different websites +hosted under one single IP address but reachable by different domain names (this is called virtual hosting). + +@heading Conclusion +The introduced capabilities to itemize the content of a simple GET request---especially the +URI---should already allow the server to satisfy clients' requests for small specific resources +(e.g. files) or even induce alteration of server state. However, the latter is not +recommended as the GET method (including its header data) is by convention considered a "safe" +operation, which should not change the server's state in a significant way. By convention, +GET operations can thus be performed by crawlers and other automatic software. Naturally +actions like searching for a passed string are fine. + +Of course, no transmission can occur while the return value is still set to @code{MHD_NO} in the +callback function. + +@heading Exercises +@itemize @bullet +@item +By parsing the @code{url} string and delivering responses accordingly, implement a small server for +"virtual" files. When asked for @code{/index.htm@{l@}}, let the response consist of a HTML page +containing a link to @code{/another.html} page which is also to be created "on the fly" in case of +being requested. If neither of these two pages are requested, @code{MHD_HTTP_NOT_FOUND} shall be +returned accompanied by an informative message. + +@item +A very interesting information has still been ignored by our logger---the client's IP address. +Implement a callback function +@verbatim +static int on_client_connect (void *cls, + const struct sockaddr *addr, + socklen_t addrlen) +@end verbatim +@noindent +that prints out the IP address in an appropriate format. You might want to use the POSIX function +@code{inet_ntoa} but bear in mind that @code{addr} is actually just a structure containing other +substructures and is @emph{not} the variable this function expects. +Make sure to return @code{MHD_YES} so that the library knows the client is allowed to connect +(and to then process the request). If one wanted to limit access basing on IP addresses, this would be the place +to do it. The address of your @code{on_client_connect} function must be passed as the third parameter to the +@code{MHD_start_daemon} call. + +@end itemize |