PageRenderTime 26ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

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