123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- 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 **req_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
|