Sophie

Sophie

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

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

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>fastcgi++: Display The Gnu</title>
<link href="doxygen.css" rel="stylesheet" type="text/css">
<link href="tabs.css" rel="stylesheet" type="text/css">
</head><body>
<!-- Generated by Doxygen 1.5.6 -->
<div class="navigation" id="top">
  <div class="tabs">
    <ul>
      <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
      <li><a href="namespaces.html"><span>Namespaces</span></a></li>
      <li><a href="annotated.html"><span>Classes</span></a></li>
      <li><a href="files.html"><span>Files</span></a></li>
    </ul>
  </div>
  <div class="navpath"><a class="el" href="index.html">index</a>
  </div>
</div>
<div class="contents">
<h1><a class="anchor" name="showGnu">Display The Gnu </a></h1><h2><a class="anchor" name="showGnuTutorial">
Tutorial</a></h2>
Our goal here is simple and easy. All we want to do is show the gnu.png file and effectively utilize caching.<p>
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<h3><a class="anchor" name="showGnuError">
Error Logging</a></h3>
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.<p>
<div class="fragment"><pre class="fragment"><span class="preprocessor">#include &lt;fstream&gt;</span>
<span class="preprocessor">#include &lt;boost/date_time/posix_time/posix_time.hpp&gt;</span>

<span class="keywordtype">void</span> error_log(<span class="keyword">const</span> <span class="keywordtype">char</span>* msg)
{
   <span class="keyword">using namespace </span>std;
   <span class="keyword">using namespace </span>boost;
   <span class="keyword">static</span> ofstream error;
   <span class="keywordflow">if</span>(!error.is_open())
   {
      error.open(<span class="stringliteral">"/tmp/errlog"</span>, ios_base::out | ios_base::app);
      error.imbue(locale(error.getloc(), <span class="keyword">new</span> posix_time::time_facet()));
   }

   error &lt;&lt; <span class="charliteral">'['</span> &lt;&lt; posix_time::second_clock::local_time() &lt;&lt; <span class="stringliteral">"] "</span> &lt;&lt; msg &lt;&lt; endl;
}
</pre></div><h3><a class="anchor" name="showGnuRequest">
Request Handler</a></h3>
Now we need to write the code that actually handles the request. Quite simply, all we need to do is derive from <a class="el" href="classFastcgipp_1_1Request.html" title="Request handling class">Fastcgipp::Request</a> and define the <a class="el" href="classFastcgipp_1_1Request.html#b20544d056d5f288bca354b8c996e451" title="Response generator.">Fastcgipp::Request::response()</a> function. Since we're just outputting an image, we don't need to bother with Unicode and can pass char as the template parameter.<p>
<div class="fragment"><pre class="fragment"><span class="preprocessor">#include &lt;<a class="code" href="request_8hpp.html" title="Defines the Fastcgipp::Request class.">fastcgi++/request.hpp</a>&gt;</span>

<span class="preprocessor">#include &lt;sys/types.h&gt;</span>
<span class="preprocessor">#include &lt;sys/stat.h&gt;</span>
<span class="preprocessor">#include &lt;unistd.h&gt;</span>

<span class="keyword">class </span>ShowGnu: <span class="keyword">public</span> Fastcgipp::Request&lt;char&gt;
{
</pre></div><p>
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.<p>
<div class="fragment"><pre class="fragment">   <span class="keywordtype">bool</span> response()
   {
      <span class="keyword">using namespace </span>std;
      <span class="keyword">using namespace </span>boost;
</pre></div><p>
We are going to use boost::posix_time::ptime to communicate the images modification time for cache purposes.<p>
<div class="fragment"><pre class="fragment">      posix_time::ptime modTime;
      <span class="keywordtype">int</span> fileSize;
      <span class="keywordtype">int</span> etag;
</pre></div><p>
We'll use the POSIX stat() function (man 2 stat) to get the modification time, file size and inode number.<p>
<div class="fragment"><pre class="fragment">      {
         <span class="keyword">struct </span>stat fileStat;
         stat(<span class="stringliteral">"gnu.png"</span>, &amp;fileStat);
         fileSize = fileStat.st_size;
         modTime = posix_time::from_time_t(fileStat.st_mtime);
</pre></div><p>
<a class="el" href="structFastcgipp_1_1Http_1_1Session.html" title="Data structure of HTTP session data.">Fastcgipp::Http::Session</a> implements the etag variable as an integer for better processing efficiency.<p>
<div class="fragment"><pre class="fragment">         etag = fileStat.st_ino;
      }
</pre></div><p>
We will need to call <a class="el" href="classFastcgipp_1_1Request.html#10bf656234f3434bbc8f8702fa1a9af4" title="Set the requests locale.">Fastcgipp::Request::setloc()</a> 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 <a class="el" href="classFastcgipp_1_1Request.html#10bf656234f3434bbc8f8702fa1a9af4" title="Set the requests locale.">Fastcgipp::Request::setloc()</a> function instead of directly imbueing them. This insures that the UTF-8 code conversion still functions properly if used.<p>
<div class="fragment"><pre class="fragment">      setloc(locale(loc, <span class="keyword">new</span> posix_time::time_facet(<span class="stringliteral">"%a, %d %b %Y %H:%M:%S GMT"</span>)));
</pre></div><p>
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.<p>
<div class="fragment"><pre class="fragment">      <span class="keywordflow">if</span>(!session.ifModifiedSince.is_not_a_date_time() &amp;&amp; etag==session.etag &amp;&amp; modTime&lt;=session.ifModifiedSince)
      {
         out &lt;&lt; <span class="stringliteral">"Status: 304 Not Modified\r\n\r\n"</span>;
         <span class="keywordflow">return</span> <span class="keyword">true</span>;
      }
</pre></div><p>
We're going to use std::fstream to read the file data.<p>
<div class="fragment"><pre class="fragment">      ifstream image(<span class="stringliteral">"gnu.png"</span>);
</pre></div><p>
Now we transmit our HTTP header containing the modification data, file size and etag value.<p>
<div class="fragment"><pre class="fragment">      out &lt;&lt; <span class="stringliteral">"Last-Modified: "</span> &lt;&lt; modTime &lt;&lt; <span class="charliteral">'\n'</span>;
      out &lt;&lt; <span class="stringliteral">"Etag: "</span> &lt;&lt; etag &lt;&lt; <span class="charliteral">'\n'</span>;
      out &lt;&lt; <span class="stringliteral">"Content-Length: "</span> &lt;&lt; fileSize &lt;&lt; <span class="charliteral">'\n'</span>;
      out &lt;&lt; <span class="stringliteral">"Content-Type: image/png\r\n\r\n"</span>;
</pre></div><p>
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 <a class="el" href="classFastcgipp_1_1Fcgistream.html#9eb452d9a72c44eac2561bc1afaa1b29" title="Dumps an input stream directly into the FastCGI protocol.">Fastcgipp::Fcgistream::dump(std::basic_istream&lt;char&gt;&amp; stream)</a> or <a class="el" href="classFastcgipp_1_1Fcgistream.html#ccf72ff881e5ef268aaabddae4ffd686" title="Dumps raw data directly into the FastCGI protocol.">Fastcgipp::Fcgistream::dump(char* data, size_t size)</a>. 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.<p>
<div class="fragment"><pre class="fragment">      out.dump(image);
</pre></div><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.<p>
<div class="fragment"><pre class="fragment">      <span class="keywordflow">return</span> <span class="keyword">true</span>;
   }
};
</pre></div><h3><a class="anchor" name="showGnuManager">
Requests Manager</a></h3>
Now we need to make our main() function. Really all one needs to do is create a <a class="el" href="classFastcgipp_1_1Manager.html" title="General task and protocol management class.">Fastcgipp::Manager</a> 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.<p>
<div class="fragment"><pre class="fragment"><span class="preprocessor">#include &lt;<a class="code" href="manager_8hpp.html" title="Defines the Fastcgipp::Manager class.">fastcgi++/manager.hpp</a>&gt;</span>
<span class="keywordtype">int</span> main()
{
   <span class="keywordflow">try</span>
   {
      <a class="code" href="classFastcgipp_1_1Manager.html" title="General task and protocol management class.">Fastcgipp::Manager&lt;ShowGnu&gt;</a> fcgi;
      fcgi.<a class="code" href="classFastcgipp_1_1Manager.html#578c8468166d892d1858ad6f4d953d8d" title="General handling function to be called after construction.">handler</a>();
   }
   <span class="keywordflow">catch</span>(std::exception&amp; e)
   {
      error_log(e.what());
   }
}
</pre></div><h2><a class="anchor" name="showGnuCode">
Full Source Code</a></h2>
<div class="fragment"><pre class="fragment"><span class="preprocessor">#include &lt;fstream&gt;</span>
<span class="preprocessor">#include "boost/date_time/posix_time/posix_time.hpp"</span>

<span class="preprocessor">#include &lt;sys/types.h&gt;</span>
<span class="preprocessor">#include &lt;sys/stat.h&gt;</span>
<span class="preprocessor">#include &lt;unistd.h&gt;</span>

<span class="preprocessor">#include &lt;<a class="code" href="request_8hpp.html" title="Defines the Fastcgipp::Request class.">fastcgi++/request.hpp</a>&gt;</span>
<span class="preprocessor">#include &lt;<a class="code" href="manager_8hpp.html" title="Defines the Fastcgipp::Manager class.">fastcgi++/manager.hpp</a>&gt;</span>

<span class="keywordtype">void</span> error_log(<span class="keyword">const</span> <span class="keywordtype">char</span>* msg)
{
   <span class="keyword">using namespace </span>std;
   <span class="keyword">using namespace </span>boost;
   <span class="keyword">static</span> ofstream error;
   <span class="keywordflow">if</span>(!error.is_open())
   {
      error.open(<span class="stringliteral">"/tmp/errlog"</span>, ios_base::out | ios_base::app);
      error.imbue(locale(error.getloc(), <span class="keyword">new</span> posix_time::time_facet()));
   }

   error &lt;&lt; <span class="charliteral">'['</span> &lt;&lt; posix_time::second_clock::local_time() &lt;&lt; <span class="stringliteral">"] "</span> &lt;&lt; msg &lt;&lt; endl;
}

<span class="keyword">class </span>ShowGnu: <span class="keyword">public</span> Fastcgipp::Request&lt;char&gt;
{
   <span class="comment">// Now we define the actual function that sends a response to the client.</span>
   <span class="keywordtype">bool</span> response()
   {
      <span class="keyword">using namespace </span>std;
      <span class="keyword">using namespace </span>boost;

      posix_time::ptime modTime;
      <span class="keywordtype">int</span> fileSize;
      <span class="keywordtype">int</span> etag;


      {
         <span class="keyword">struct </span>stat fileStat;
         stat(<span class="stringliteral">"gnu.png"</span>, &amp;fileStat);
         fileSize = fileStat.st_size;
         modTime = posix_time::from_time_t(fileStat.st_mtime);
         etag = fileStat.st_ino;
      }

      setloc(locale(loc, <span class="keyword">new</span> posix_time::time_facet(<span class="stringliteral">"%a, %d %b %Y %H:%M:%S GMT"</span>)));

      <span class="keywordflow">if</span>(!session.ifModifiedSince.is_not_a_date_time() &amp;&amp; etag==session.etag &amp;&amp; modTime&lt;=session.ifModifiedSince)
      {
         out &lt;&lt; <span class="stringliteral">"Status: 304 Not Modified\r\n\r\n"</span>;
         <span class="keywordflow">return</span> <span class="keyword">true</span>;
      }

      std::ifstream image(<span class="stringliteral">"gnu.png"</span>);

      out &lt;&lt; <span class="stringliteral">"Last-Modified: "</span> &lt;&lt; modTime &lt;&lt; <span class="charliteral">'\n'</span>;
      out &lt;&lt; <span class="stringliteral">"Etag: "</span> &lt;&lt; etag &lt;&lt; <span class="charliteral">'\n'</span>;
      out &lt;&lt; <span class="stringliteral">"Content-Length: "</span> &lt;&lt; fileSize &lt;&lt; <span class="charliteral">'\n'</span>;
      out &lt;&lt; <span class="stringliteral">"Content-Type: image/png\r\n\r\n"</span>;

      out.dump(image);
      <span class="keywordflow">return</span> <span class="keyword">true</span>;
   }
};

<span class="keywordtype">int</span> main()
{
   <span class="keywordflow">try</span>
   {
      <a class="code" href="classFastcgipp_1_1Manager.html" title="General task and protocol management class.">Fastcgipp::Manager&lt;ShowGnu&gt;</a> fcgi;
      fcgi.<a class="code" href="classFastcgipp_1_1Manager.html#578c8468166d892d1858ad6f4d953d8d" title="General handling function to be called after construction.">handler</a>();
   }
   <span class="keywordflow">catch</span>(std::exception&amp; e)
   {
      error_log(e.what());
   }
}
</pre></div> </div>
<hr size="1"><address style="text-align: right;"><small>Generated on Tue Sep 16 15:17:47 2008 for fastcgi++ by&nbsp;
<a href="http://www.doxygen.org/index.html">
<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.6 </small></address>
</body>
</html>