/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. #include <fstream>
  25. ///////////////////////////////////////////////////////////
  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. using namespace std;
  31. using namespace boost;
  32. using namespace boost::fcgi;
  33. // This function writes the title and map contents to the ostream in an
  34. // HTML-encoded format (to make them easier on the eye).
  35. template<typename OStream, typename Map>
  36. void format_map(OStream& os, Map& m, const std::string& title)
  37. {
  38. os<< "<h2>" << title << "</h2>";
  39. if (m.empty()) os<< "NONE<br />";
  40. for (typename Map::const_iterator i = m.begin(), end = m.end()
  41. ; i != end; ++i)
  42. {
  43. os<< "<b>" << i->first << "</b> = <i>" << i->second << "</i><br />";
  44. }
  45. }
  46. /// Handle one request and return.
  47. /**
  48. * If it returns != 0 then an error has occurred. Sets ec to the error_code
  49. * corresponding to the error.
  50. */
  51. int handle_request(fcgi::request& req, boost::system::error_code& ec)
  52. {
  53. // Construct a `response` object (makes writing/sending responses easier).
  54. response resp;
  55. // Responses in CGI programs require at least a 'Content-type' header. The
  56. // library provides helpers for several common headers:
  57. resp<< content_type("text/html")
  58. // You can also stream text to a response object.
  59. << "Hello there, universe!<p />";
  60. // Use the function defined above to show some of the request data.
  61. format_map(resp, req.env, "Environment Variables");
  62. format_map(resp, req.get, "GET Variables");
  63. format_map(resp, req.cookies, "Cookie Variables");
  64. //log_<< "Handled request, handling another." << std::endl;
  65. return commit(req, resp);
  66. }
  67. /// The server is used to abstract away protocol-specific setup of requests.
  68. /**
  69. * This server only works with FastCGI, but as you can see in the
  70. * request_handler::handle_request() function above, the request in there could
  71. * just as easily be a cgi::request.
  72. *
  73. * Later examples will demonstrate making protocol-independent servers.
  74. * (**FIXME**)
  75. */
  76. class server
  77. {
  78. public:
  79. typedef fcgi::service service_type;
  80. typedef fcgi::acceptor acceptor_type;
  81. typedef fcgi::request request_type;
  82. typedef boost::function<
  83. int ( request_type&
  84. , boost::system::error_code&)
  85. > function_type;
  86. server(const function_type& handler)
  87. : handler_(handler)
  88. , service_()
  89. , acceptor_(service_)
  90. {}
  91. void run(int num_threads = 0)
  92. {
  93. // Create a new request (on the heap - uses boost::shared_ptr<>).
  94. request_type::pointer new_request = request_type::create(service_);
  95. // Add the request to the set of existing requests.
  96. requests_.insert(new_request);
  97. start_accept(new_request);
  98. boost::thread_group tgroup;
  99. for(int i(num_threads); i != 0; --i)
  100. {
  101. tgroup.create_thread(boost::bind(&service_type::run, &service_));
  102. }
  103. tgroup.join_all();
  104. }
  105. void start_accept(request_type::pointer& new_request)
  106. {
  107. acceptor_.async_accept(*new_request, boost::bind(&server::handle_accept
  108. , this, new_request
  109. , boost::asio::placeholders::error)
  110. );
  111. }
  112. int handle_accept(request_type::pointer req
  113. , boost::system::error_code ec)
  114. {
  115. if (ec)
  116. {
  117. //std::cerr<< "Error accepting request: " << ec.message() << std::endl;
  118. return -1;
  119. }
  120. req->load(parse_all, ec);
  121. //req->async_load(boost::bind(&server::handle_request, this
  122. // , req, boost::asio::placeholders::error)
  123. // , true);
  124. service_.post(boost::bind(&server::handle_request, this, req, ec));
  125. // Create a new request (on the heap - uses boost::shared_ptr<>).
  126. request_type::pointer new_request = request_type::create(service_);
  127. // Add the request to the set of existing requests.
  128. requests_.insert(new_request);
  129. start_accept(new_request);
  130. return 0;
  131. }
  132. void handle_request(request_type::pointer req
  133. , boost::system::error_code ec)
  134. {
  135. if (handler_(*req, ec) || ec)
  136. {
  137. //std::cerr<< "Request handled, but ended in error: " << ec.message()
  138. // << std::endl;
  139. }
  140. start_accept(req);
  141. }
  142. private:
  143. function_type handler_;
  144. service_type service_;
  145. acceptor_type acceptor_;
  146. std::set<request_type::pointer> requests_;
  147. };
  148. int main()
  149. try
  150. {
  151. server s(&handle_request);
  152. // Run the server with 10 threads handling the asynchronous functions.
  153. s.run(10);
  154. return 0;
  155. }catch(boost::system::system_error& se){
  156. cerr<< "[fcgi] System error: " << se.what() << endl;
  157. return 1313;
  158. }catch(std::exception* e){
  159. cerr<< "[fcgi] Exception: " << e->what() << endl;
  160. return 666;
  161. }catch(...){
  162. cerr<< "[fcgi] Uncaught exception!" << endl;
  163. return 667;
  164. }
  165. //]