PageRenderTime 131ms CodeModel.GetById 50ms app.highlight 15ms RepoModel.GetById 50ms app.codeStats 1ms

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

http://github.com/darrengarvey/cgi
C++ | 190 lines | 105 code | 26 blank | 59 comment | 6 complexity | ca43e16897e9ad91bf95168de60ea231 MD5 | raw file
  1//                 -- server4/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_server4
 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#include <boost/date_time/posix_time/posix_time.hpp>
 27#include <boost/program_options/environment_iterator.hpp>
 28
 29#include <boost/cgi/fcgi.hpp>
 30
 31using namespace std;
 32using namespace boost;
 33using namespace boost::fcgi;
 34
 35/// Handle one request and return.
 36/**
 37 * If it returns != 0 then an error has occurred. Sets ec to the error_code
 38 * corresponding to the error.
 39 */
 40int handle_request(fcgi::request& req, fcgi::response& resp
 41                  , boost::system::error_code& ec)
 42{
 43  // Responses in CGI programs require at least a 'Content-type' header. The
 44  // library provides helpers for several common headers:
 45  resp<< content_type("text/html")
 46  // You can also stream text to a response object. 
 47      << "Hello there, universe!<p />";
 48
 49  // Use the function defined above to show some of the request data.
 50  //format_map(req.env(), resp, "Environment Variables");
 51  //format_map(req.GET(), resp, "GET Variables");
 52  //format_map(req.cookie(), resp, "Cookie Variables");
 53
 54  // Response headers can be added at any time before send/flushing it:
 55  resp<< "content-length == " << content_length(resp.content_length())
 56      << content_length(resp.content_length());
 57
 58  //log_<< "Handled request, handling another." << std::endl;
 59  //
 60  return 0;
 61}
 62
 63/// The server is used to abstract away protocol-specific setup of requests.
 64/**
 65 * This server only works with FastCGI, but as you can see in the
 66 * request_handler::handle_request() function above, the request in there could
 67 * just as easily be a cgi::request.
 68 *
 69 * Later examples will demonstrate making protocol-independent servers.
 70 * (**FIXME**)
 71 */
 72class server
 73{
 74public:
 75  typedef fcgi::service                         service_type;
 76  typedef fcgi::acceptor                        acceptor_type;
 77  typedef fcgi::request                         request_type;
 78  typedef fcgi::response                        response_type;
 79  typedef boost::function<
 80            int ( request_type&, response_type&
 81                , boost::system::error_code&)
 82          >                                     function_type;
 83
 84  server(const function_type& handler)
 85    : handler_(handler)
 86    , service_()
 87    , acceptor_(service_)
 88  {}
 89
 90  void run(int num_threads = 1)
 91  {
 92    // Create a new request (on the heap - uses boost::shared_ptr<>).
 93    request_type::pointer new_request = request_type::create(service_);
 94    // Add the request to the set of existing requests.
 95    requests_.insert(new_request);
 96
 97    start_accept(new_request);
 98
 99    // Run all asynchronous functions in `num_threads` threads.
100    boost::thread_group tgroup;
101    for(int i(num_threads); i != 0; --i)
102    {
103      tgroup.create_thread(boost::bind(&service_type::run, &service_));
104    }
105    // Make sure we don't leave this function until all threads have exited.
106    tgroup.join_all();
107  }
108
109  void start_accept(request_type::pointer& new_request)
110  {
111    acceptor_.async_accept(*new_request, boost::bind(&server::handle_accept
112                                                    , this, new_request
113                                                    , boost::asio::placeholders::error)
114                          );
115  }
116
117  void handle_accept(request_type::pointer req  
118                    , boost::system::error_code ec)
119  {
120    if (ec)
121    {
122      //std::cerr<< "Error accepting request: " << ec.message() << std::endl;
123      return;
124    }
125
126    req->load(ec, true);
127
128    boost::shared_ptr<response_type> new_response(new response_type);
129    responses_.insert(new_response);
130
131    //req->async_load(boost::bind(&server::handle_request, this
132    //                           , req, boost::asio::placeholders::error)
133    //               , true);
134
135    service_.post(boost::bind(&server::handle_request, this
136                             , req, new_response, ec)
137                 );
138
139    // Create a new request (on the heap - uses boost::shared_ptr<>).
140    request_type::pointer new_request = request_type::create(service_);
141    // Add the request to the set of existing requests.
142    requests_.insert(new_request);
143
144    start_accept(new_request);
145  }
146
147  void handle_request(request_type::pointer req
148                     , boost::shared_ptr<response_type> resp
149                     , boost::system::error_code ec)
150  {
151    int program_status( handler_(*req, *resp, ec) );
152    if (ec
153     || resp->send(*req, ec)
154     || req->close(resp->status(), program_status, ec))
155    {
156      std::cerr<< "Couldn't send response/close request." << std::endl;
157    }
158    else
159      start_accept(req);
160  }
161
162private:
163  function_type handler_;
164  service_type service_;
165  acceptor_type acceptor_;
166  std::set<request_type::pointer> requests_;
167  std::set<boost::shared_ptr<response_type> > responses_;
168};
169
170int main()
171try
172{
173  server s(&handle_request);
174
175  // Run the server.
176  s.run();
177
178  return 0;
179  
180}catch(boost::system::system_error& se){
181  cerr<< "[fcgi] System error: " << se.what() << endl;
182  return 1313;
183}catch(std::exception& e){
184  cerr<< "[fcgi] Exception: " << e.what() << endl;
185  return 666;
186}catch(...){
187  cerr<< "[fcgi] Uncaught exception!" << endl;
188  return 667;
189}
190//]