Sophie

Sophie

distrib > Mandriva > 2010.0 > i586 > media > contrib-release > by-pkgid > dc51c7d3f8a5588a609f484ef81504ee > files > 76

libfastcgipp-devel-1.1-2mdv2010.0.i586.rpm

/***************************************************************************
* Copyright (C) 2007 Eddie                                                 *
*                                                                          *
* This file is part of fastcgi++.                                          *
*                                                                          *
* fastcgi++ is free software: you can redistribute it and/or modify it     *
* under the terms of the GNU Lesser General Public License as  published   *
* by the Free Software Foundation, either version 3 of the License, or (at *
* your option) any later version.                                          *
*                                                                          *
* fastcgi++ is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    *
* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public     *
* License for more details.                                                *
*                                                                          *
* You should have received a copy of the GNU Lesser General Public License *
* along with fastcgi++.  If not, see <http://www.gnu.org/licenses/>.       *
****************************************************************************/


#include <fstream>
#include <boost/date_time/posix_time/posix_time.hpp>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include <fastcgi++/request.hpp>
#include <fastcgi++/manager.hpp>

// I like to have an independent error log file to keep track of exceptions while debugging.
// You might want a different filename. I just picked this because everything has access there.
void error_log(const char* msg)
{
	using namespace std;
	using namespace boost;
	static ofstream error;
	if(!error.is_open())
	{
		error.open("/tmp/errlog", ios_base::out | ios_base::app);
		error.imbue(locale(error.getloc(), new posix_time::time_facet()));
	}

	error << '[' << posix_time::second_clock::local_time() << "] " << msg << endl;
}

// Let's make our request handling class. It must do the following:
// 1) Be derived from Fastcgipp::Request
// 2) Define the virtual response() member function from Fastcgipp::Request()

// First things first let's decide on what kind of character set we will use.
// Since we are just displaying an image, we won't need unicode so we don't
// need to use wide characters. We'll keep everything as narrow characters
// and pass the 'char' type along to the Fastcgipp::Request template.

class ShowGnu: public Fastcgipp::Request<char>
{
	// Now we define the actual function that sends a response to the client.
	bool response()
	{
		using namespace std;
		using namespace boost;

		// We are going to use boost::posix_time::ptime to communicate
		// the images modification time for cache purposes.
		posix_time::ptime modTime;
		int fileSize;
		int etag;


		{
			// Using the linux stat function (man 2 stat) to get the modification time and filesize beforehand.
			struct stat fileStat;
			stat("gnu.png", &fileStat);
			fileSize = fileStat.st_size;
			modTime = posix_time::from_time_t(fileStat.st_mtime);

			// We'll use the files inode as the etag
			etag = fileStat.st_ino;
		}

		// We need to call this to set a facet in our requests locale regarding how
		// to format the date upon insertion. It needs to conform to the http standard.
		setloc(locale(loc, new posix_time::time_facet("%a, %d %b %Y %H:%M:%S GMT")));

		// If the modification time of the file is older or equal to the if-modified-since value
		// sent to us from the client and we were actually sent an if-modified since value,
		// we don't need to send the image to them.
		if(!session.ifModifiedSince.is_not_a_date_time() && etag==session.etag && modTime<=session.ifModifiedSince)
		{
			out << "Status: 304 Not Modified\r\n\r\n";
			return true;
		}

		// Setup an fstream for our file.
		std::ifstream image("gnu.png");

		// Now we transmit our HTTP header to the client
		// First we send the modification time of the file
		out << "Last-Modified: " << modTime << '\n';
		// Then a Etag. Note that the session.etag is an integer value. NOT an std::string.
		out << "Etag: " << etag << '\n';
		// Next the size
		out << "Content-Length: " << fileSize << '\n';
		// Then content type. Remember an HTTP header is supposed to be
		// terminated with \r\n\r\n NOT just \n\n
		out << "Content-Type: image/png\r\n\r\n";

		// 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 streambuffer and it's code
		// conversion. The function is overloaded to either:
		// out.dump(basic_istream<char>& stream); or
		// out.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.
		out.dump(image);
		
		// Always return true if you are done. This will let apache know we are done
		// and the manager will 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 might do this after an SQL query
		// while waiting for a reply. Passing messages to requests through the
		// manager is possible but beyond the scope of this example.
		return true;
	}
};

// The main function is easy to set up
int main()
{
	try
	{
		// First we make a Fastcgipp::Manager object, with our request handling class
		// as a template parameter.
		Fastcgipp::Manager<ShowGnu> fcgi;
		// Now just call the object handler function. It will sleep quietly when there
		// are no requests and efficiently manage them when there are many.
		fcgi.handler();
	}
	catch(std::exception& e)
	{
		error_log(e.what());
	}
}