Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

FastCGI Examples

Echo
Asynchronous Echo
Amortization
Stencil
File Browser
Uploads

//
// This example simply echoes all variables back to the user. ie.
// the environment and the parsed GET, POST and cookie variables.
// Note that GET and cookie variables come from the environment
// variables QUERY_STRING and HTTP_COOKIE respectively.
//
///////////////////////////////////////////////////////////
#include <iostream>
///////////////////////////////////////////////////////////
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/program_options/environment_iterator.hpp>
///////////////////////////////////////////////////////////
#include "boost/cgi/fcgi.hpp"

//using namespace std;
using std::cerr;
using std::endl;
namespace fcgi = boost::fcgi;

// The styling information for the page, just to make things look clearer.
static const char* gCSS_text =
"body { padding: 0; margin: 3%; border-color: #efe; }"
"ul.data-map .title"
    "{ font-weight: bold; font-size: large; }"
"ul.data-map"
    "{ border: 1px dotted; padding: 2px 3px 2px 3px; margin-bottom: 3%; }"
"ul.data-map li"
    "{ border-top: 1px dotted; overflow: auto; padding: 0; margin: 0; }"
"ul.data-map div.name"
    "{ position: relative; float: left; width: 30%; font-weight: bold; }"
"ul.data-map div.value"
    "{ position: relative; float: left; width: 65%; left: 1%;"
     " border-left: 1px solid; padding: 0 5px 0 5px;"
     " overflow: auto; white-space: pre; }"
".clear"
    "{ clear: both; }"
;

std::size_t process_id()
{
#if defined(BOOST_WINDOWS)
  return _getpid();
#else
  return getpid();
#endif
}

template<typename OStream, typename Request, typename Map>
void format_map(OStream& os, Request& req, Map& m, const std::string& title);

int handle_request(fcgi::request& req);

int main()
{
try {

  // Make a `service` (more about this in other examples).
  fcgi::service s;
  
  // Make an `acceptor` for accepting requests through.
  fcgi::acceptor a(s);

  //
  // An acceptor can take a request handler as an argument to `accept` and it
  // will accept a request and pass the handler the request. The return value
  // of `accept` when used like this is the result of the handler.
  //
  // Note that a request handler is any function or function object with the
  // signature:
  //  boost::function<int (boost::fcgi::request&)>
  // See the documentation for Boost.Function and Boost.Bind for more.
  //
  // The acceptor maintains an internal queue of requests and will reuse a
  // dead request if one is waiting.
  //
  // After the initial setup, we can enter a loop to handle one request at a
  // time until there's an error of some sort.
  //
  int status(0);
  do {
    status = a.accept(&handle_request);
  } while (!status);
  
  return status;

}catch(boost::system::system_error const& se){
  // This is the type of exception thrown by the library.
  std::cerr<< "[fcgi] System error: " << se.what() << std::endl;
  return -1;
}catch(std::exception const& e){
  // Catch any other exceptions
  std::cerr<< "[fcgi] Exception: " << e.what() << std::endl;
  return -2;
}catch(...){
  std::cerr<< "[fcgi] Uncaught exception!" << std::endl;
  return -3;
}
}

/// Handle one request.
int handle_request(fcgi::request& req)
{
  boost::system::error_code ec;
  
  //
  // Load in the request data so we can access it easily.
  //
  req.load(fcgi::parse_all);

  //
  // Construct a `response` object (makes writing/sending responses easier).
  //
  fcgi::response resp;

  //
  // Responses in CGI programs require at least a 'Content-type' header. The
  // library provides helpers for several common headers:
  //
  resp<< fcgi::content_type("text/html");
  
  // You can also stream text to a response. 
  // All of this just prints out the form 
  resp<< "<html>"
         "<head>"
           "<title>FastCGI Echo Example</title>"
           "<style type=\"text/css\">"
      <<       gCSS_text <<
           "</style>"
         "<head>"
         "<body>"
           "Request ID = " << req.id() << "<br />"
           "Process ID = " << process_id() << "<br />"
           "<form method=post enctype=\"multipart/form-data\">"
             "<input type=text name=name value='"
      <<         req.post.pick("name", "") << "' />"
             "<br />"
             "<input type=text name=hello value='"
      <<         req.post.pick("hello", "") << "' />"
             "<br />"
             "<input type=file name=user_file />"
             "<input type=hidden name=cmd value=multipart_test />"
             "<br />"
             "<input type=submit value=submit />"
           "</form><p />";

  // Show the request data in a formatted table.
  format_map(resp, req, req.env, "Environment Variables");
  format_map(resp, req, req.get, "GET Variables");
  format_map(resp, req, req.post, "POST Variables");
  format_map(resp, req, req.uploads, "File Uploads");
  format_map(resp, req, req.cookies, "Cookie Variables");

  // Print the buffer containing the POST data and the FastCGI params.
  resp<< "<pre>";
  resp<< std::string(req.post_buffer().begin(), req.post_buffer().end());
  resp<< "</pre>";

  //
  // Response headers can be added at any time before send/flushing it:
  //
  resp<< "Response content-length == "
      << resp.content_length(); // the content-length (returns std::size_t)

  // This function finishes up. The optional third argument
  // is the program status (default: 0).
  return fcgi::commit(req, resp);
}

//
// This function writes the title and map contents to the ostream in an
// HTML-encoded format (to make them easier on the eye).
//
template<typename OStream, typename Request, typename Map>
void format_map(OStream& os, Request& req, Map& m, const std::string& title)
{
  os<< "<ul class=\"data-map\">"
         "<div class=\"title\">"
    <<       title
    <<   "</div>";

  if (m.empty())
    os<< "<li>EMPTY</li>";
  else
    for (typename Map::const_iterator i = m.begin(); i != m.end(); ++i)
    {
      os<< "<li>"
             "<div class=\"name\">"
        <<       i->first
        <<   "</div>"
             "<div class=\"value\">"
        <<       i->second
        <<   "</div>"
           "</li>";
    }
  os<< "<div class=\"clear\"></div></ul>";
}

See the full source listing.

//
// This example simply echoes all variables back to the user. ie.
// the environment and the parsed GET, POST and cookie variables.
// Note that GET and cookie variables come from the environment
// variables QUERY_STRING and HTTP_COOKIE respectively.
//
///////////////////////////////////////////////////////////
#include <iostream>
///////////////////////////////////////////////////////////
#include <boost/date_time/posix_time/posix_time.hpp>
///////////////////////////////////////////////////////////
#include "boost/cgi/fcgi.hpp"

//using namespace std;
using namespace boost::fcgi;

// The styling information for the page, just to make things look nicer.
static const char* gCSS_text =
"body { padding: 0; margin: 3%; border-color: #efe; }"
"ul.data-map .title"
    "{ font-weight: bold; font-size: large; }"
"ul.data-map"
    "{ border: 1px dotted; padding: 2px 3px 2px 3px; margin-bottom: 3%; }"
"ul.data-map li"
    "{ border-top: 1px dotted; overflow: auto; padding: 0; margin: 0; }"
"ul.data-map div.name"
    "{ position: relative; float: left; width: 30%; font-weight: bold; }"
"ul.data-map div.value"
    "{ position: relative; float: left; width: 65%; left: 1%;"
     " border-left: 1px solid; padding: 0 5px 0 5px;"
     " overflow: auto; white-space: pre; }"
".clear"
    "{ clear: both; }"
;

//
// This function writes the title and map contents to the ostream in an
// HTML-encoded format (to make them easier on the eye).
//
template<typename OStream, typename Request, typename Map>
void format_map(OStream& os, Request& req, Map& m, const std::string& title)
{
  os<< "<ul class=\"data-map\">"
         "<div class=\"title\">"
    <<       title
    <<   "</div>";

  if (m.empty())
    os<< "<li>EMPTY</li>";
  else
    for (typename Map::const_iterator i = m.begin(); i != m.end(); ++i)
    {
      os<< "<li>"
             "<div class=\"name\">"
        <<       i->first
        <<   "</div>"
             "<div class=\"value\">"
        <<       i->second
        <<   "</div>"
           "</li>";
    }
  os<< "<div class=\"clear\"></div></ul>";
}

std::size_t process_id()
{
#if defined(BOOST_WINDOWS)
  return _getpid();
#else
  return getpid();
#endif
}


int handle_request(acceptor& a, request& req)
{
  boost::system::error_code ec;
  
  //
  // Load in the request data so we can access it easily.
  //
  req.load(parse_all); // Read and parse STDIN (ie. POST) data.

  //
  // Construct a `response` object (makes writing/sending responses easier).
  //
  response resp;

  //
  // Responses in CGI programs require at least a 'Content-type' header. The
  // library provides helpers for several common headers:
  //
  resp<< content_type("text/html");
  
  // You can also stream text to a response. 
  // All of this just prints out the form 
  resp<< "<html>"
         "<head>"
           "<title>FastCGI Echo Example</title>"
           "<style type=\"text/css\">"
      <<       gCSS_text <<
           "</style>"
         "<head>"
         "<body>"
           "Request ID = " << req.id() << "<br />"
           "Request Hash = " << req.hash() << "<br />"
           "Process ID = " << process_id() << "<br />"
           "<form method=post enctype=\"multipart/form-data\">"
             "<input type=text name=name value='"
      <<         req.post["name"] << "' />"
             "<br />"
             "<input type=text name=hello value='"
      <<         req.post["hello"] << "' />"
             "<br />"
             "<input type=file name=user_file />"
             "<input type=hidden name=cmd value=multipart_test />"
             "<br />"
             "<input type=submit value=submit />"
           "</form><p />";

  //
  // Use the function defined above to show some of the request data.
  // (this function isn't part of the library)
  //
  format_map(resp, req, req.env, "Environment Variables");
  format_map(resp, req, req.get, "GET Variables");
  format_map(resp, req, req.post, "POST Variables");
  format_map(resp, req, req.uploads, "File Uploads");
  format_map(resp, req, req.cookies, "Cookie Variables");

  // Print the buffer containing the POST data and the FastCGI params.
  resp<< "<pre>";
  resp<< std::string(req.post_buffer().begin(), req.post_buffer().end());
  resp<< "</pre>";

  //
  // Response headers can be added at any time before send/flushing it:
  //
  resp<< "Response content-length == "
      << resp.content_length(); // the content-length (returns std::size_t)

  //
  // Write the response. If the commit is successful, start up another
  // asynchronous accept request.
  //
  int status = commit(req, resp);
  if (!status)
    a.async_accept(boost::bind(&handle_request, boost::ref(a), _1));

  // The return value isn't used for anything.
  return status;
}

int main()
{
try {

  std::cerr<< "*** Ping! ***" << '\n';
  // Make a `service` (more about this in other examples).
  service s;
  
  // Make an `acceptor` for accepting requests through.
  acceptor a;

  //
  // After the initial setup, we can enter a loop to handle one request at a
  // time until there's an error of some sort.
  //
  int count(10);
  while (--count)
  {
    //
    // An acceptor can take a request handler as an argument to `accept` and it
    // will accept a request and pass the handler the request. The return value
    // of `accept` when used like this is the result of the handler.
    //
    // Note that a request handler is any function or function object with the
    // signature:
    //  boost::function<int (boost::fcgi::request&)>
    // See the documentation for Boost.Function and Boost.Bind for more.
    //
    // The acceptor maintains an internal queue of requests and will reuse a
    // dead request if one is waiting.
    //
    a.async_accept(boost::bind(&handle_request, boost::ref(a), _1));
  }
  
  std::cerr<< "Start running service..." << std::endl;
  s.run();
  std::cerr<< "Shutdown ." << std::endl;
  
  std::cerr<< "Processing finished. Press enter to continue..." << std::endl;
  std::cin.get();
  
  //return 0;

}catch(boost::system::system_error const& se){
  // This is the type of error thrown by the library.
  std::cerr<< "[fcgi] System error: " << se.what() << std::endl;
  //return -1;
}catch(std::exception const& e){
  // Catch any other exceptions
  std::cerr<< "[fcgi] Exception: " << e.what() << std::endl;
  //return -2;
}catch(...){
  std::cerr<< "[fcgi] Uncaught exception!" << std::endl;
  //return -3;
}
  std::cerr<< "Press enter to continue." << std::endl;
  std::cin.get();
}

See the full source listing.

This example uses Google.cTemplate to move HTML out of the program and into HTML template files, which would be easily editable by anyone familiar with HTML.

[Note] Note

You need to download and install Google's cTemplate library and you may have to modify Jamfile.v2 to point to your compiled ctemplate library (see the lib ctemplate ... lines).

//
// Amortization Calculator
// -----------------------
//
// This file uses Google cTemplate to show the benefits of using an
// HTML template engine. The code isn't commented yet, but should be 
// *reasonably* self-explanatory.
//
// It is a very basic amortization calculator.
//
#include <iostream>
#include <iomanip>
#include <boost/cgi/fcgi.hpp>
#include <boost/algorithm/string/regex.hpp>
#include <ctemplate/template.h>

using namespace boost::fcgi;

/// Convert a string like '$250,000' into one like '250000'.
std::string string_from_currency(std::string amt)
{
  // this is much too hardcore, but it works fine...
  boost::algorithm::erase_all_regex(amt, boost::regex("[$, ]"));
  return amt;
}

/// This function fills a dictionary.
template<typename Request>
void fill_amortization_dictionary(
  ctemplate::TemplateDictionary& dict, Request& req)
{
  dict.SetValue("LoanAmt", req.post.count("LoanAmt")
      ? "$250,000" : req.post["LoanAmt"]);
  dict.SetIntValue("YearlyIntRate", req.post.pick("YearlyIntRate", 6.000));

  boost::array<std::string, 8> year_opts
    = {{ "5", "7", "10", "20", "30", "40", "50" }};
    
  BOOST_FOREACH(std::string& year, year_opts)
  {
    dict.SetValueAndShowSection("TermYrs", year, "SELECT_TERM_YEARS");
  }

  if (req.post["Amortize"].empty())
    dict.ShowSection("NotAmortize");
  else
  {
    double P = boost::lexical_cast<double>(
      string_from_currency(req.post["LoanAmt"]));
    double i = req.post.pick("YearlyIntRate", 1.0) / 1200;
    double n = req.post.pick("TermYrs", 1.0) * 12;
    double monthly_payments = (P*i) / (1 - std::pow((1+i), -n));
    
    ctemplate::TemplateDictionary* sub_dict
      = dict.AddSectionDictionary("RegPmtSummary");
    sub_dict->ShowSection("RegPmtSummary");
    sub_dict->SetFormattedValue("MonthlyPmt", "%.2f", monthly_payments);

    dict.ShowSection("Amortize");
    dict.SetValue("SCRIPT_NAME", req.script_name());

    double balance = P;
    int row_num = 0;
    double interest;
    double principal_paid;
    double total_interest = 0;
    do{
      ctemplate::TemplateDictionary* sub_dict2
        = dict.AddSectionDictionary("PaymentEntry");
      sub_dict2->ShowSection("PaymentEntry");
      sub_dict2->SetFormattedValue("Payment", "%.2f", monthly_payments);
      sub_dict2->SetIntValue("ROW_NUM", ++row_num);
      sub_dict2->SetIntValue("ROW_TYPE", (row_num % 2) + 1);
      interest = balance * i;
      total_interest += interest;
      sub_dict2->SetFormattedValue("InterestPaid", "%.2f", interest);
      principal_paid = monthly_payments - interest;
      sub_dict2->SetFormattedValue("PrincipalPaid", "%.2f", principal_paid);
      balance -= principal_paid; // Note: balance can increase.
      sub_dict2->SetFormattedValue("Balance", "%.2f", balance);

    }while(balance > 0);

    sub_dict->SetFormattedValue(
      "RegPmt_TotalIntPd", "%.2f", total_interest);
    sub_dict->SetFormattedValue(
      "RegPmt_TotalPmts", "%.2f", total_interest + P);
  }
}

template<typename Request>
int write_amortization_template(Request& req, response& resp)
{
  ctemplate::TemplateDictionary dict("amortization");

  fill_amortization_dictionary(dict, req);

  ctemplate::Template* tmpl
    = ctemplate::Template::GetTemplate("../stencils/amortization.html", ctemplate::STRIP_WHITESPACE);

  std::string h("Content-type: text/html\r\n\r\n");
  write(req.client(), buffer(h));

  int arg = req.get.pick("arg", 2); // 2 is the default.

  // Different, but equivalent ways of writing the output.
  std::string output;
  switch (arg)
  {
  case 1:
    tmpl->Expand(&output, &dict);
    resp<< output;
    break;
  case 2:
    tmpl->Expand(&output, &dict);
    write(req.client(), buffer(output));
    break;
  case 3:
//    // This requires a modified version of Google.cTemplate, so it won't work.
//    std::string s;
//    std::vector<boost::asio::const_buffer> out;
//
//    tmpl->Expand(&s, &out, &dict);
//    write(req.client(), out);
    break;
  default:
    resp<< "Error!";
    return 1;
  }

  return 0;
}

int handle_request(acceptor& a)
{
  boost::system::error_code ec;

  request req(a.protocol_service());
 
  int ret = 0;
  int num = 0;
  while(!ec && ret == 0)
  {
    response resp;
    ++num;

    // Accepting on a closed request is fine (and more efficient than 
    // constantly creating/destructing request objects).
    a.accept(req);

    req.load(parse_all);

    resp<< content_type("text/html")
        << "map size := " << req.post.size() << "<p>";
  
    ret = write_amortization_template(req, resp);

    ret = commit(req, resp, 0, ec);
  }
  return ret;
}

int main()
{
  try{

    service s;
    acceptor a(s);

    for(;;)
    {
      // Keep handling requests until something goes wrong.
      // An exception will be thrown.
      if (handle_request(a))
        break;
    }
    
    return 0;

  }catch(boost::system::system_error& err){
    std::cout<< "Content-type: text/plain\r\n\r\n"
             << "Error (" << err.code() << "): " << err.what();
    return 0;
  }catch(std::exception& e){
    std::cout<< "Content-type: text/html\r\n\r\n"
             << "Exception caught: " << e.what();
    return 0;
  }catch(...){
    std::cout<< "Content-type: text/html\r\n\r\n"
             << "Unknown error!";    
  }
}

See the full source listing.

[cgi_stencil]

See the full source listing.

//
// This example is a simple browser-based file browser.
//
///////////////////////////////////////////////////////////
#include <istream>
#include <fstream>
#include <boost/filesystem.hpp>
#include <boost/shared_array.hpp>
#include <boost/algorithm/string/find.hpp>
#include <boost/algorithm/string/case_conv.hpp>
///////////////////////////////////////////////////////////
#include "boost/cgi/cgi.hpp"

using std::cerr;
using std::endl;
using std::ifstream;
using namespace boost::cgi;
namespace fs = boost::filesystem;
namespace algo = boost::algorithm;


/// Get the MIME type of the file. 
/**
 * @returns The MIME type as a string. Returns an empty string if the
 *          file type isn't recognised / supported.
 */
std::string get_mime_type(fs::path const& file)
{
  std::string filetype (file.filename());
  // Note: we want the string after the '.'
  std::size_t pos (filetype.rfind(".")+1);
  if (pos == std::string::npos)
    return "";
  
  filetype = filetype.substr(pos);
  algo::to_lower(filetype);
  
  /// Ordinary text files.
  if (filetype == "ini" || filetype == "txt" || filetype == "conf")
    return "text/plain";  
  else
  if (filetype == "js")
    return "application/javascript";
  else
  if (filetype == "json")
    return "application/json";
  else
  if (filetype == "css")
    return "text/css";
  else
  /// Structured text files.
  if (filetype == "html" || filetype == "htm")
    return "text/html";
  else
  if (filetype == "xml")
    return "text/xml";
  else
  if (filetype == "csv")
    return "text/csv";
  else
  if (filetype == "rtf")
    return "text/rtf";
  else
  /// Image files.
  if (filetype == "jpg" || filetype == "jpeg")
    return "image/jpeg";
  else
  if (filetype == "gif")
    return "image/gif";
  else
  if (filetype == "bmp")
    return "image/x-ms-bmp";
  else
  if (filetype == "png")
    return "image/png";
  else  
  if (filetype == "tiff")
    return "image/tiff";
  else  
  /// Audio files.
  if (filetype == "ogg")
    return "audio/ogg";
  else
  if (filetype == "mp3")
    return "audio/mpeg";
  else
  /// Video files.
  if (filetype == "avi")
    return "video/x-msvideo";
  else
  /// Rich media files.
  if (filetype == "pdf")
    return "application/pdf";
  else
  if (filetype == "doc")
    return "application/msword";
  else
  if (filetype == "swf")
    return "application/x-shockwave-flash";
  else
  if (filetype == "xls")
    return "application/vnd.ms-excel";
  /// Compressed files.
  else
  if (filetype == "zip")
    return "application/zip";
  else
  if (filetype == "tar")
    return "application/x-tar";
  /// Other files.
  else
  if (filetype == "pl")
    return "application/x-perl";
  else
  if (filetype == "py")
    return "application/x-python";
  else
  if (filetype == "exe" || filetype == "dll" || filetype == "sys" ||
      filetype == "chm" || filetype == "lib" || filetype == "pdb" ||
      filetype == "obj" || filetype == "dep" || filetype == "idb" ||
      filetype == "pyd" || filetype == "sqm" || filetype == "idb" ||
      filetype == "asm" || filetype == "suo" || filetype == "sbr")
    return ""; // Not allowed to download these file types.

  return "text/plain";
}

/// Show the file to the user.
/**
 * This will send the file to the user using an appropriate content-type
 * header. Some browsers (eg. Firefox) will be able to handle many file types
 * directly, while others (eg. Internet Explorer) will prompt the user to
 * save / open the file externally.
 *
 * This function actually buffers the entire file before sending it to the user,
 * so this isn't very scalable. You could choose to stream the file directly
 * instead, but make sure your HTTP server won't buffer the response.
 *
 * Files over 200MB won't be displayed.
 */
template<typename Response, typename Client>
void show_file(Response& resp, Client& client, fs::path const& file)
{
  if (!fs::exists(file))
    resp<< "File not found.";
  else
  {
    boost::uintmax_t size (fs::file_size(file));
    if (size > 200000000L) // Files must be < 200MB
      resp<< "File too large: " << file.string() << " [" << size << ']';
    else
    {
      /// Check the file type is allowed.
      std::string mime_type (get_mime_type(file));
      if (!mime_type.empty())
      {
        std::string ctype (content_type(mime_type).content + "\r\n\r\n");
        /// Open the file and read it as binary data.
        ifstream ifs (file.string().c_str(), std::ios::binary);
        if (ifs.is_open())
        {
          resp<< content_type(mime_type);
          boost::uintmax_t bufsize = 500;
          boost::uintmax_t read_bytes;
          char buf[500];
          ifs.seekg(0, std::ios::beg);
          while (!ifs.eof() && size > 0)
          {
            ifs.read(buf, size < bufsize ? size : bufsize);
            read_bytes = ifs.gcount();
            size -= read_bytes;
            resp.write(buf, read_bytes);
          }
        }
      }
      else
        resp<< "File type not allowed.";
    }
  }
}
    
template<typename Response>
void show_paths(Response& resp, fs::path const& parent, bool recursive = true)
{
  if (!fs::exists(parent))
  {
    resp<< "File does not exist\n";
    return;
  }
  
  resp<< "<ul>";
  if (fs::is_directory(parent))
  {
    resp<< parent << "\n";
    resp<< "<li class=\"directory\"><a href=\"?dir="
        << parent.string() << "\">.</a></li>\n";
    if (fs::is_directory(parent.parent_path()))
      resp<< "<li class=\"directory\"><a href=\"?dir="
          << parent.parent_path().string() << "\">..</a></li>\n";
    for (fs::directory_iterator iter(parent), end; iter != end; ++iter)
    {
      if (fs::is_directory(*iter))
      {
        resp<< "<li class=\"directory\"><a href=\"?dir="
            << iter->string() << "\">" << iter->path() << "</a></li>\n";
        if (recursive)
          show_paths(resp, iter->path(), recursive);
      }
      else
      {
        // display filename only.
        resp<< "<li class=\"file\"><a href=\"?file="
            << iter->string() << "\">" << iter->path().filename()
            << "</a>";
        //if (fs::is_regular_file(iter->status()))
        //  resp<< " [" << fs::file_size(iter->path()) << " bytes]";
        resp<< "</li>\n";
      }
    }
  }
  else
  {
    resp<< "<li class=\"file\">" << "<a href=\"?file="
            << parent.string() << "\">" << parent << "</li>\n";
  }
  resp<< "</ul>";
}

/// This function accepts and handles a single request.
template<typename Request>
int handle_request(Request& req)
{
  boost::system::error_code ec;
  
  //
  // Load in the request data so we can access it easily.
  //
  req.load(parse_all); // Read and parse STDIN (ie. POST) data.

  //
  // Construct a `response` object (makes writing/sending responses easier).
  //
  response resp;

  if (req.get.count("file"))
  {
    show_file(resp, req.client(), req.get["file"]);
    //return req.close(http::ok, 0);
  }
  else
  if (req.get.count("dir"))
  {
    //
    // Responses in CGI programs require at least a 'Content-type' header.
    // The library provides helpers for several common headers:
    //
    resp<< content_type("text/html");
    
    // You can also stream text to a response. 
    // All of this just prints out the form 
    resp<< "<html>"
           "<head><title>CGI File Browser Example</title><head>"
           "<body>";

    show_paths(resp, req.get["dir"], req.get["recurse"] == "1");

    resp<< "</body></html>";
  }
  else
    resp<< content_type("text/html")
        << "No path specified. Search for a path using, eg. "
        << " <a href=\"?dir=/\">" << req.script_name() << "?dir=/some/path</a>\n";

  resp<< header("CGI-client", "fcgi_file_browser");
  return commit(req, resp);
}

int main()
{
try {

  request req;
  return handle_request(req);

}catch(boost::system::system_error const& se){
  // This is the type of error thrown by the library.
  cerr<< "[fcgi] System error: " << se.what() << endl;
  return -1;
}catch(std::exception const& e){
  // Catch any other exceptions
  cerr<< "[fcgi] Exception: " << e.what() << endl;
  return -1;
}catch(...){
  cerr<< "[fcgi] Uncaught exception!" << endl;
  return -1;
}
}

See the full source listing.

//

#include <boost/cgi/fcgi.hpp>
#include <boost/cgi/utility/stencil.hpp>

namespace cgi = boost::fcgi;
namespace http = boost::fcgi::http;

int main()
{
try {
  cgi::service service;
  // Construct a request. Parses all GET, POST and environment data,
  // as well as cookies.
  cgi::request req(service);
  
  cgi::acceptor acceptor(service);
  
  int ret(0);
  
  for(;;)
  {
    acceptor.accept(req);
    
    try {
      req.load(cgi::parse_all);
  
      // Using a response is the simplest way to write data back to the client.
      cgi::stencil resp;
  
      resp<< cgi::content_type("text/html");
      resp.set("filename", req.post["file"]);
      resp.set("path", req.uploads["file"].path.parent_path().string());
      resp.set("filename_check", req.uploads["file"].filename);
      resp.set("content_type", req.uploads["file"].content_type);
      resp.set("content_disposition", req.uploads["file"].content_disposition);
  
      resp.expand("upload.html");
    
      ret = cgi::commit(req, resp);
      
    } catch(boost::system::system_error& e) {
      using namespace std;
      cerr<< "Error " << e.code() << ": " << e.what() << endl;
      boost::system::error_code ec;
      ret = req.close(http::internal_server_error, 1, ec);
    } catch(std::exception& e) {
      using namespace std;
      cerr<< "Error: " << e.what() << endl;
      boost::system::error_code ec;
      ret = req.close(http::internal_server_error, 1, ec);
    }
  }

  // Leave this function, after sending the response and closing the request.
  // Returns 0 on success.
  return ret;
  
} catch(std::exception& e) {
  using namespace std;
  cerr<< "Error: " << e.what() << endl;
  cin.get();
  return 1;
} catch(...) {
  using namespace std;
  cerr<< "Unexpected exception." << endl;
  cin.get();
  return 1;
}
}

See the full source listing.


PrevUpHomeNext