All code and data is located in the examples directory of the tarball. Make sure to link this with the following library options: -lfastcgipp -lboost_thread
#include <fstream> #include <boost/date_time/posix_time/posix_time.hpp> 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; }
#include <fastcgi++/request.hpp> class HelloWorld: public Fastcgipp::Request<wchar_t> {
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.
bool response()
{
First thing we need to do is output our HTTP header. Let us start with settting a cookie in the client using a Unicode string. Just to see how it echoes.
wchar_t langString[] = { 0x0440, 0x0443, 0x0441, 0x0441, 0x043a, 0x0438, 0x0439, 0x0000 }; out << "Set-Cookie: lang=" << langString << '\n';
Next of course we need to output our content type part of the header. Note the charset=utf-8. Remember that HTTP headers must be terminated with "\r\n\r\n". Not just "\n\n".
out << "Content-Type: text/html; charset=utf-8\r\n\r\n";
Next we'll get some initial HTML stuff out of the way
out << "<html><head><meta http-equiv='Content-Type' content='text/html; charset=utf-8' />"; out << "<title>fastcgi++: Echo in UTF-8</title></head><body>";
Now we are ready to start outputting session data. We'll start with the non-post session data. This data is defined and initialized in the session object which is of type Fastcgipp::Http::Session.
out << "<h1>Session Parameters</h1>"; out << "<p><b>Hostname:</b> " << session.host << "<br />"; out << "<b>User Agent:</b> " << session.userAgent << "<br />"; out << "<b>Accepted Content Types:</b> " << session.acceptContentTypes << "<br />"; out << "<b>Accepted Languages:</b> " << session.acceptLanguages << "<br />"; out << "<b>Accepted Characters Sets:</b> " << session.acceptCharsets << "<br />"; out << "<b>Referer:</b> " << session.referer << "<br />"; out << "<b>Content Type:</b> " << session.contentType << "<br />"; out << "<b>Query String:</b> " << session.queryString << "<br />"; out << "<b>Cookies:</b> " << session.cookies << "<br />"; out << "<b>Root:</b> " << session.root << "<br />"; out << "<b>Script Name:</b> " << session.scriptName << "<br />"; out << "<b>Content Length:</b> " << session.contentLength << "<br />"; out << "<b>Keep Alive Time:</b> " << session.keepAlive << "<br />"; out << "<b>Server Address:</b> " << session.serverAddress << "<br />"; out << "<b>Server Port:</b> " << session.serverPort << "<br />"; out << "<b>Client Address:</b> " << session.remoteAddress << "<br />"; out << "<b>Client Port:</b> " << session.remotePort << "<br />"; out << "<b>If Modified Since:</b> " << session.ifModifiedSince << "</p>";
Next, we will make a little loop to output the post data. The post data is stored in the associative container session.posts of type Fastcgipp::Http::Session::Posts linking field names to Fastcgipp::Http::Post objects.
out << "<h1>Post Data</h1>";
If there isn't any POST data, we'll just say so
if(session.posts.size()) for(Fastcgipp::Http::Session<wchar_t>::Posts::iterator it=session.posts.begin(); it!=session.posts.end(); ++it) { out << "<h2>" << it->first << "</h2>"; if(it->second.type==Fastcgipp::Http::Post<wchar_t>::form) { out << "<p><b>Type:</b> form data<br />"; out << "<b>Value:</b> " << it->second.value << "</p>"; } else { out << "<p><b>Type:</b> file<br />";
When the post type is a file, the filename is stored in Post::value
out << "<b>Filename:</b> " << it->second.value << "<br />"; out << "<b>Size:</b> " << it->second.size << "<br />"; out << "<b>Data:</b></p><pre>";
We will use Fastcgipp::Fcgistream::dump to send the file raw data directly to the client
out.dump(it->second.data.get(), it->second.size); out << "</pre>"; } } else out << "<p>No post data</p>";
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.
return true; } };
#include <fastcgi++/manager.hpp> int main() { try { Fastcgipp::Manager<Echo> fcgi; fcgi.handler(); } catch(std::exception& e) { error_log(e.what()); } }
#include <fstream> #include "boost/date_time/posix_time/posix_time.hpp" #include <fastcgi++/request.hpp> #include <fastcgi++/manager.hpp> 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; } class Echo: public Fastcgipp::Request<wchar_t> { bool response() { wchar_t langString[] = { 0x0440, 0x0443, 0x0441, 0x0441, 0x043a, 0x0438, 0x0439, 0x0000 }; out << "Set-Cookie: lang=" << langString << '\n'; out << "Content-Type: text/html; charset=utf-8\r\n\r\n"; out << "<html><head><meta http-equiv='Content-Type' content='text/html; charset=utf-8' />"; out << "<title>fastcgi++: Echo in UTF-8</title></head><body>"; out << "<h1>Session Parameters</h1>"; out << "<p><b>Hostname:</b> " << session.host << "<br />"; out << "<b>User Agent:</b> " << session.userAgent << "<br />"; out << "<b>Accepted Content Types:</b> " << session.acceptContentTypes << "<br />"; out << "<b>Accepted Languages:</b> " << session.acceptLanguages << "<br />"; out << "<b>Accepted Characters Sets:</b> " << session.acceptCharsets << "<br />"; out << "<b>Referer:</b> " << session.referer << "<br />"; out << "<b>Content Type:</b> " << session.contentType << "<br />"; out << "<b>Query String:</b> " << session.queryString << "<br />"; out << "<b>Cookies:</b> " << session.cookies << "<br />"; out << "<b>Root:</b> " << session.root << "<br />"; out << "<b>Script Name:</b> " << session.scriptName << "<br />"; out << "<b>Content Length:</b> " << session.contentLength << "<br />"; out << "<b>Keep Alive Time:</b> " << session.keepAlive << "<br />"; out << "<b>Server Address:</b> " << session.serverAddress << "<br />"; out << "<b>Server Port:</b> " << session.serverPort << "<br />"; out << "<b>Client Address:</b> " << session.remoteAddress << "<br />"; out << "<b>Client Port:</b> " << session.remotePort << "<br />"; out << "<b>If Modified Since:</b> " << session.ifModifiedSince << "</p>"; out << "<h1>Post Data</h1>"; if(session.posts.size()) for(Fastcgipp::Http::Session<wchar_t>::Posts::iterator it=session.posts.begin(); it!=session.posts.end(); ++it) { out << "<h2>" << it->first << "</h2>"; if(it->second.type==Fastcgipp::Http::Post<wchar_t>::form) { out << "<p><b>Type:</b> form data<br />"; out << "<b>Value:</b> " << it->second.value << "</p>"; } else { out << "<p><b>Type:</b> file<br />"; out << "<b>Filename:</b> " << it->second.value << "<br />"; out << "<b>Size:</b> " << it->second.size << "<br />"; out << "<b>Data:</b></p><pre>"; out.dump(it->second.data.get(), it->second.size); out << "</pre>"; } } else out << "<p>No post data</p>"; out << "</body></html>"; return true; } }; int main() { try { Fastcgipp::Manager<Echo> fcgi; fcgi.handler(); } catch(std::exception& e) { error_log(e.what()); } }