aboutsummaryrefslogtreecommitdiff
path: root/doc/chapters/exploringrequests.inc
diff options
context:
space:
mode:
Diffstat (limited to 'doc/chapters/exploringrequests.inc')
-rw-r--r--doc/chapters/exploringrequests.inc109
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