fastcgi++
|
Our goal here is simple and easy. All we want to do is show the gnu.png file and effectively utilize client caching.
All code and data is located in the examples directory of the tarball. You'll have to compile with: pkg-config –libs –cflags fastcgi++
Our first step will be setting up an error logging system. Although requests can log errors directly to the HTTP server error log, I like to have an error logging system that's separate from the library when testing applications. Let's set up a function that takes a c style string and logs it to a file with a timestamp. Since everyone has access to the /tmp directory, I set it up to send error messages to /tmp/errlog. You can change it if you want to.
Now we need to write the code that actually handles the request. Quite simply, all we need to do is derive from Fastcgipp::Request and define the Fastcgipp::Request::response() function. Since we're just outputting an image, we don't need to bother with Unicode and can pass char as the template parameter.
Now we can define our response function. It is this function that is called to generate a response for the client. It isn't a good idea to define the response() function inline as it is called from numerous spots, but for the examples readability we will make an exception.
We are going to use boost::posix_time::ptime to communicate the images modification time for cache purposes.
We'll use the POSIX stat() function (man 2 stat) to get the modification time, file size and inode number.
Fastcgipp::Http::Environment implements the etag variable as an integer for better processing efficiency.
We will need to call Fastcgipp::Request::setloc() to set a facet in our requests locale regarding how to format the date upon insertion. It needs to conform to the HTTP standard. When setting locales for the streams, make sure to use the Fastcgipp::Request::setloc() function instead of directly imbueing them. This insures that the UTF-8 code conversion still functions properly if used.
If the modification time of the file is older or equal to the if-modified-since value sent to us from the client and the etag matches, we don't need to send the image to them.
We're going to use std::fstream to read the file data.
Now we transmit our HTTP header containing the modification data, file size and etag value.
Now that the header is sent, we can transmit the actual image. To send raw binary data to the client, the streams have a dump function that bypasses the stream buffer and it's code conversion. The function is overloaded to either Fastcgipp::Fcgistream::dump(std::basic_istream<char>& stream) or Fastcgipp::Fcgistream::dump(char* data, size_t size). Remember that if we are using wide characters internally, the stream converts anything sent into the stream to UTF-8 before transmitting to the client. If we want to send binary data, we definitely don't want any code conversion so that is why this function exists.
And we're basically done defining our response! All we need to do is return a boolean value. Always return true if you are done. This will let apache and the manager know we are done so they can destroy the request and free it's resources. Return false if you are not finished but want to relinquish control and allow other requests to operate. You would do this if the request needed to wait for a message to be passed back to it through the task manager.
Now we need to make our main() function. Really all one needs to do is create a Fastcgipp::Manager object with the new class we made as a template parameter, then call it's handler. Let's go one step further though and set up a try/catch loop in case we get any exceptions and log them with our error_log function.