PageRenderTime 194ms CodeModel.GetById 91ms app.highlight 13ms RepoModel.GetById 88ms app.codeStats 0ms

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

http://github.com/darrengarvey/cgi
C++ | 193 lines | 106 code | 28 blank | 59 comment | 8 complexity | de52743593e8ecdeed9116e2157fce44 MD5 | raw file
  1//                 -- server2/main.hpp --
  2//
  3//           Copyright (c) Darren Garvey 2007.
  4// Distributed under the Boost Software License, Version 1.0.
  5//    (See accompanying file LICENSE_1_0.txt or copy at
  6//          http://www.boost.org/LICENSE_1_0.txt)
  7//
  8////////////////////////////////////////////////////////////////
  9//
 10//[fcgi_server2
 11//
 12// This example simply echoes all variables back to the user. ie.
 13// the environment and the parsed GET, POST and cookie variables.
 14// Note that GET and cookie variables come from the environment
 15// variables QUERY_STRING and HTTP_COOKIE respectively.
 16//
 17// It is a demonstration of how a 'server' can be used to abstract
 18// away the differences between FastCGI and CGI requests.
 19//
 20// This is very similar to the fcgi_echo and fcgi_server1 examples.
 21// Unlike in the server1 example, the server class in this example uses
 22// asynchronous functions, to increase throughput.
 23//
 24
 25#include <fstream>
 26///////////////////////////////////////////////////////////
 27#include <boost/date_time/posix_time/posix_time.hpp>
 28#include <boost/program_options/environment_iterator.hpp>
 29///////////////////////////////////////////////////////////
 30#include "boost/cgi/fcgi.hpp"
 31
 32using namespace std;
 33using namespace boost;
 34using namespace boost::fcgi;
 35
 36
 37// This function writes the title and map contents to the ostream in an
 38// HTML-encoded format (to make them easier on the eye).
 39template<typename OStream, typename Map>
 40void format_map(OStream& os, Map& m, const std::string& title)
 41{
 42  os<< "<h2>" << title << "</h2>";
 43  if (m.empty()) os<< "NONE<br />";
 44  for (typename Map::const_iterator i = m.begin(), end = m.end()
 45      ; i != end; ++i)
 46  {
 47    os<< "<b>" << i->first << "</b> = <i>" << i->second << "</i><br />";
 48  }
 49}
 50
 51/// Handle one request and return.
 52/**
 53 * If it returns != 0 then an error has occurred. Sets ec to the error_code
 54 * corresponding to the error.
 55 */
 56int handle_request(fcgi::request& req, boost::system::error_code& ec)
 57{
 58  // Construct a `response` object (makes writing/sending responses easier).
 59  response resp;
 60
 61  // Responses in CGI programs require at least a 'Content-type' header. The
 62  // library provides helpers for several common headers:
 63  resp<< content_type("text/html")
 64  // You can also stream text to a response object. 
 65      << "Hello there, universe!<p />";
 66
 67  // Use the function defined above to show some of the request data.
 68  format_map(resp, req.env, "Environment Variables");
 69  format_map(resp, req.get, "GET Variables");
 70  format_map(resp, req.cookies, "Cookie Variables");
 71
 72  //log_<< "Handled request, handling another." << std::endl;
 73
 74  return commit(req, resp);
 75}
 76
 77
 78/// The server is used to abstract away protocol-specific setup of requests.
 79/**
 80 * This server only works with FastCGI, but as you can see in the
 81 * request_handler::handle_request() function above, the request in there could
 82 * just as easily be a cgi::request.
 83 *
 84 * Later examples will demonstrate making protocol-independent servers.
 85 * (**FIXME**)
 86 */
 87class server
 88{
 89public:
 90  typedef fcgi::service                         service_type;
 91  typedef fcgi::acceptor                        acceptor_type;
 92  typedef fcgi::request                         request_type;
 93  typedef boost::function<
 94            int ( request_type&
 95                , boost::system::error_code&)
 96          >                                     function_type;
 97
 98  server(const function_type& handler)
 99    : handler_(handler)
100    , service_()
101    , acceptor_(service_)
102  {}
103
104  void run(int num_threads = 0)
105  {
106    // Create a new request (on the heap - uses boost::shared_ptr<>).
107    request_type::pointer new_request = request_type::create(service_);
108    // Add the request to the set of existing requests.
109    requests_.insert(new_request);
110
111    start_accept(new_request);
112    boost::thread_group tgroup;
113    for(int i(num_threads); i != 0; --i)
114    {
115      tgroup.create_thread(boost::bind(&service_type::run, &service_));
116    }
117    tgroup.join_all();
118  }
119
120  void start_accept(request_type::pointer& new_request)
121  {
122    acceptor_.async_accept(*new_request, boost::bind(&server::handle_accept
123                                                    , this, new_request
124                                                    , boost::asio::placeholders::error)
125                          );
126  }
127
128  int handle_accept(request_type::pointer req  
129                    , boost::system::error_code ec)
130  {
131    if (ec)
132    {
133      //std::cerr<< "Error accepting request: " << ec.message() << std::endl;
134      return -1;
135    }
136
137    req->load(parse_all, ec);
138
139    //req->async_load(boost::bind(&server::handle_request, this
140    //                           , req, boost::asio::placeholders::error)
141    //               , true);
142
143    service_.post(boost::bind(&server::handle_request, this, req, ec));
144
145    // Create a new request (on the heap - uses boost::shared_ptr<>).
146    request_type::pointer new_request = request_type::create(service_);
147    // Add the request to the set of existing requests.
148    requests_.insert(new_request);
149
150    start_accept(new_request);
151    return 0;
152  }
153
154  void handle_request(request_type::pointer req
155                     , boost::system::error_code ec)
156  {
157    
158    if (handler_(*req, ec) || ec)
159    {
160      //std::cerr<< "Request handled, but ended in error: " << ec.message()
161      //         << std::endl;
162    }
163    start_accept(req);
164  }
165
166private:
167  function_type handler_;
168  service_type service_;
169  acceptor_type acceptor_;
170  std::set<request_type::pointer> requests_;
171};
172
173int main()
174try
175{
176  server s(&handle_request);
177
178  // Run the server with 10 threads handling the asynchronous functions.
179  s.run(10);
180
181  return 0;
182  
183}catch(boost::system::system_error& se){
184  cerr<< "[fcgi] System error: " << se.what() << endl;
185  return 1313;
186}catch(std::exception* e){
187  cerr<< "[fcgi] Exception: " << e->what() << endl;
188  return 666;
189}catch(...){
190  cerr<< "[fcgi] Uncaught exception!" << endl;
191  return 667;
192}
193//]