Home Announcements Schedule Assignments Project Reading Reviews Resources

libmicrohttpd Checkpoint 3: Pasring HTTP

Due: March 18th, 2007

In this checkpoint, you will have to start parsing the HTTP messages and building responses for the client of your library. The image to the right is what I call a (B)roken UML (BUML) diagram to show you the sequence of events that occur between the daemon and the client (in this case, a web server). Note that the dark arrow heads indicate the direction of the function call (i.e., who made the function call) and time increases from the top of the figure down towards the bottom of the figure.

Initially, the Web Server calls MHD_start_daemon followed by MHD_run. At some point, a TCP connection is established with the daemon, which calls the AcceptPolicyCallback function suplied by the daemon. Assuming this returns MHD_YES, the connection is established and an HTTP request is received over the TCP connection.

When the request is received, we read it into our internal buffers and we have to parse the headers because the header is terminated by two CRLFs (i.e., "\r\n\r\n" indicates the end of the header). The first line of a request begins with GET, HEAD, PUT, POST, TRACE, OPTIONS, or DELETE. Note that HTTP 1.1 allows other methods to be defined. For our project, you will only have to deal with GETs (though you can get extra credit for implementing other methods).

Once we have determined that we have the entire body of an HTTP request, we call the AccessHandlerCallback, which passes the session to the Web Server. The Web Server will not return from this function call until it has optionally called the functions listed in the figure including MHD_queue_response. In essence, a single request will cause a single response to be created. After MHD_queue_response is called, the daemon will send the response to the network. Note that if the server created the response object by MHD_create_response_from_callback, our daemon will need to begin writing the response object to the network and continually call the MHD_ContentReaderCallback function until the Web Server has given it all of its data. Additionally, if we used MHD_ContentReaderCallback, we must call MHD_ContentReaderFreeCallback when we are done receiving data from the callback.

GET Requests

GET requests have the format:

GET /somelocation/myfile.html HTTP/1.1
Host: www.mysite.com
Accept: *


Note that the second field in the first line is the URL of the file or object you are trying to get. The third field is always HTTP/1.1, to indicate the protocol version we are implementing.

Header lines begin after the first line. These always begin with a keyword, followed by a colon (:), followed by a characters that ends with a CRLF ("\r\n"). For example, in this GET, the two header lines have keys of Host and Accept while the values of each line are www.mysite.com and * respectively.

Because the client will call MHD_get_session_values or MHD_lookup_session_values, you will need to parse these from your input buffer so that you can give them (or locate) key, value pairs.

From the daemon's perspective, the only header field you are interested in is one that looks like Connection: Close This pair indicates that a session should be terminated after the response is sent back.

How to Handle Requests

In order to decide how to handle a request, the Web Server can register Handlers. When we get a request, it will specify a URI on the first line, as noted with the GET above. URIs on this line always being with '/'. The Web Server registers prefixes which determine which handler is called. To register a prefix, the server calls MHD_register_handler (and to unregister a prefix it calls MHD_unregister_handler).

For example, a Web Server might register "/" and "/images" as the first and second handlers respectively. Anything beginning with "/images" would call the second handler while anything begining with just "/" would call the first handler.

To store this, your MHD_daemon struct must contain a list (array, whatever) of prefix to AccessHandler mappings. You'll check incoming URIs against this list and then call the correct AccessHandler.

Responses

As with headers, our daemon does not determine what kind of response is generated, but leaves it up to the web server to decide this. The web server will call MHD_create_response_from_data or MHD_create_response_from_callback. In both cases, the data you receive from the client of your code (the Web Server, in this case) fills in the data portion of your response. An HTTP response looks like the following:

HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 54

<html>...<html>
The first field in the first line is always HTTP/1.1, and the response code (the second field) is given to you when the Web Server calls MHD_queue_response. The third field is a reason code. This field can actually say whatever you want, regardless of whether it matches the response code or not. Here is a table of common response phrases. If you receive one of these response codes, you should simply match it with a default response phrase:
Status CodeReason Phrase
100Continue
101Switching Protocols
200OK
201Created
202Accepted
203Non-Authoritative Information
204No Content
205Reset Content
206Partial Content
300Multiple Choices
301Moved Permanently
302Found
303See Other
304Not Modified
305Use Proxy
306(Unused)
307Temporary Redirect
400Bad Request
401Unauthorized
402Payment Required
403Forbidden
404Not Found
405Method Not Allowed
406Not Acceptable
407Proxy Authentication Required
408Request Timeout
409Conflict
410Gone
411Length Required
412Precondition Failed
413Request Entity Too Large
414Request URI Too Long
415Unsupported Media Type
416Requested Range Not Satisfiable
417Expectation Failed
500Internal Server Error
501Not Implemented
502Bad Gateway
503Service Unavailable
504Gateway Timeout
505HTTP Version Not Supported

The additional headers for the reponse are generated by the Web Server. To add a header, the Web Server calls MHD_add_response_header and to delete a header the Web Server calls MHD_del_response_header. The Web Server can also iterate through the response headers by calling MHD_get_response_headers to which the daemon will call the MHD_KeyValueIterator for each header already in the response object.

A Working Web Server

You can build the web server side of things to test your code by using the daemontest.c code. This code can allow you to start and stop a web server, create the callbacks, and even read files and pass them as responses to GET requests (MHD_create_response_from_data can take a pointer to a buffer that holds the file in it). You can simply do this by registering a prefix handler for "/" which will handle all URI requests. This would be an excellent way to understand how your daemon works and to test it to make sure it actually works the way as intended!