cgi /libs/cgi/example/fcgi/server2/main.cpp

Language C++ Lines 194
MD5 Hash de52743593e8ecdeed9116e2157fce44 Estimated Cost $2,560 (why?)
Repository git://github.com/darrengarvey/cgi.git View Raw File
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
//                 -- server2/main.hpp --
//
//           Copyright (c) Darren Garvey 2007.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)
//
////////////////////////////////////////////////////////////////
//
//[fcgi_server2
//
// 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.
//
// It is a demonstration of how a 'server' can be used to abstract
// away the differences between FastCGI and CGI requests.
//
// This is very similar to the fcgi_echo and fcgi_server1 examples.
// Unlike in the server1 example, the server class in this example uses
// asynchronous functions, to increase throughput.
//

#include <fstream>
///////////////////////////////////////////////////////////
#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 namespace boost;
using namespace boost::fcgi;


// 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 Map>
void format_map(OStream& os, Map& m, const std::string& title)
{
  os<< "<h2>" << title << "</h2>";
  if (m.empty()) os<< "NONE<br />";
  for (typename Map::const_iterator i = m.begin(), end = m.end()
      ; i != end; ++i)
  {
    os<< "<b>" << i->first << "</b> = <i>" << i->second << "</i><br />";
  }
}

/// Handle one request and return.
/**
 * If it returns != 0 then an error has occurred. Sets ec to the error_code
 * corresponding to the error.
 */
int handle_request(fcgi::request& req, boost::system::error_code& ec)
{
  // 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 object. 
      << "Hello there, universe!<p />";

  // Use the function defined above to show some of the request data.
  format_map(resp, req.env, "Environment Variables");
  format_map(resp, req.get, "GET Variables");
  format_map(resp, req.cookies, "Cookie Variables");

  //log_<< "Handled request, handling another." << std::endl;

  return commit(req, resp);
}


/// The server is used to abstract away protocol-specific setup of requests.
/**
 * This server only works with FastCGI, but as you can see in the
 * request_handler::handle_request() function above, the request in there could
 * just as easily be a cgi::request.
 *
 * Later examples will demonstrate making protocol-independent servers.
 * (**FIXME**)
 */
class server
{
public:
  typedef fcgi::service                         service_type;
  typedef fcgi::acceptor                        acceptor_type;
  typedef fcgi::request                         request_type;
  typedef boost::function<
            int ( request_type&
                , boost::system::error_code&)
          >                                     function_type;

  server(const function_type& handler)
    : handler_(handler)
    , service_()
    , acceptor_(service_)
  {}

  void run(int num_threads = 0)
  {
    // Create a new request (on the heap - uses boost::shared_ptr<>).
    request_type::pointer new_request = request_type::create(service_);
    // Add the request to the set of existing requests.
    requests_.insert(new_request);

    start_accept(new_request);
    boost::thread_group tgroup;
    for(int i(num_threads); i != 0; --i)
    {
      tgroup.create_thread(boost::bind(&service_type::run, &service_));
    }
    tgroup.join_all();
  }

  void start_accept(request_type::pointer& new_request)
  {
    acceptor_.async_accept(*new_request, boost::bind(&server::handle_accept
                                                    , this, new_request
                                                    , boost::asio::placeholders::error)
                          );
  }

  int handle_accept(request_type::pointer req  
                    , boost::system::error_code ec)
  {
    if (ec)
    {
      //std::cerr<< "Error accepting request: " << ec.message() << std::endl;
      return -1;
    }

    req->load(parse_all, ec);

    //req->async_load(boost::bind(&server::handle_request, this
    //                           , req, boost::asio::placeholders::error)
    //               , true);

    service_.post(boost::bind(&server::handle_request, this, req, ec));

    // Create a new request (on the heap - uses boost::shared_ptr<>).
    request_type::pointer new_request = request_type::create(service_);
    // Add the request to the set of existing requests.
    requests_.insert(new_request);

    start_accept(new_request);
    return 0;
  }

  void handle_request(request_type::pointer req
                     , boost::system::error_code ec)
  {
    
    if (handler_(*req, ec) || ec)
    {
      //std::cerr<< "Request handled, but ended in error: " << ec.message()
      //         << std::endl;
    }
    start_accept(req);
  }

private:
  function_type handler_;
  service_type service_;
  acceptor_type acceptor_;
  std::set<request_type::pointer> requests_;
};

int main()
try
{
  server s(&handle_request);

  // Run the server with 10 threads handling the asynchronous functions.
  s.run(10);

  return 0;
  
}catch(boost::system::system_error& se){
  cerr<< "[fcgi] System error: " << se.what() << endl;
  return 1313;
}catch(std::exception* e){
  cerr<< "[fcgi] Exception: " << e->what() << endl;
  return 666;
}catch(...){
  cerr<< "[fcgi] Uncaught exception!" << endl;
  return 667;
}
//]
Back to Top