ChipMaster's trial hacks on C++CMS starting with v1.2.1. Not sure I'll follow on with the v2 since it looks to be breaking and mostly frivolous.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

157 lines
4.6 KiB

  1. #define CPPCMS_SOURCE
  2. #include "asio_config.h"
  3. #include "connection_forwarder.h"
  4. #include "http_context.h"
  5. #include "http_request.h"
  6. #include "http_response.h"
  7. #include "service.h"
  8. #include "service_impl.h"
  9. #include "url_dispatcher.h"
  10. #include "cgi_api.h"
  11. #ifdef CPPCMS_USE_EXTERNAL_BOOST
  12. # include <boost/bind.hpp>
  13. # include <boost/enable_shared_from_this.hpp>
  14. # include <boost/format.hpp>
  15. # if defined(CPPCMS_WIN32) && _WIN32_WINNT <= 0x0501 && !defined(BOOST_ASIO_DISABLE_IOCP)
  16. # define NO_CANCELIO
  17. # endif
  18. #else // Internal Boost
  19. # include <cppcms_boost/bind.hpp>
  20. # include <cppcms_boost/enable_shared_from_this.hpp>
  21. # include <cppcms_boost/format.hpp>
  22. namespace boost = cppcms_boost;
  23. # if defined(CPPCMS_WIN32) && _WIN32_WINNT <= 0x0501 && !defined(CPPCMS_BOOST_ASIO_DISABLE_IOCP)
  24. # define NO_CANCELIO
  25. # endif
  26. #endif
  27. namespace cppcms {
  28. namespace impl {
  29. class tcp_pipe : public boost::enable_shared_from_this<tcp_pipe> {
  30. public:
  31. tcp_pipe(intrusive_ptr<http::context> connection,std::string const &ip,int port) :
  32. connection_(connection),
  33. ip_(ip),
  34. port_(port),
  35. socket_(connection_->service().impl().get_io_service())
  36. {
  37. }
  38. void async_send_receive(std::string &data)
  39. {
  40. data_.swap(data);
  41. boost::asio::ip::tcp::endpoint ep(boost::asio::ip::address::from_string(ip_),port_);
  42. socket_.async_connect(ep,boost::bind(&tcp_pipe::on_connected,shared_from_this(),boost::asio::placeholders::error));
  43. }
  44. private:
  45. void on_connected(boost::system::error_code e)
  46. {
  47. if(e) {
  48. connection_->response().make_error_response(500);
  49. connection_->async_complete_response();
  50. return;
  51. }
  52. boost::asio::async_write(socket_,
  53. boost::asio::buffer(data_),
  54. boost::bind(&tcp_pipe::on_written,shared_from_this(),boost::asio::placeholders::error));
  55. }
  56. void on_written(boost::system::error_code const &e)
  57. {
  58. if(e) {
  59. connection_->response().make_error_response(500);
  60. connection_->async_complete_response();
  61. return;
  62. }
  63. connection_->async_on_peer_reset(boost::bind(&tcp_pipe::on_peer_close,shared_from_this()));
  64. connection_->response().io_mode(http::response::asynchronous_raw);
  65. input_.resize(4096);
  66. socket_.async_read_some(boost::asio::buffer(input_),
  67. boost::bind(&tcp_pipe::on_read,shared_from_this(),
  68. boost::asio::placeholders::error,
  69. boost::asio::placeholders::bytes_transferred));
  70. }
  71. void on_peer_close()
  72. {
  73. boost::system::error_code ec;
  74. #ifndef NO_CANCELIO
  75. socket_.cancel(ec);
  76. #endif
  77. socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both,ec);
  78. socket_.close(ec);
  79. return;
  80. }
  81. void on_read(boost::system::error_code const &e,size_t n)
  82. {
  83. connection_->response().out().write(&input_.front(),n);
  84. if(e) {
  85. connection_->async_complete_response();
  86. }
  87. else {
  88. socket_.async_read_some(boost::asio::buffer(input_),
  89. boost::bind(&tcp_pipe::on_read,shared_from_this(),
  90. boost::asio::placeholders::error,
  91. boost::asio::placeholders::bytes_transferred));
  92. }
  93. }
  94. intrusive_ptr<http::context> connection_;
  95. std::string ip_;
  96. int port_;
  97. std::string data_;
  98. boost::asio::ip::tcp::socket socket_;
  99. std::vector<char> input_;
  100. };
  101. } // impl
  102. struct connection_forwarder::data {};
  103. connection_forwarder::connection_forwarder(cppcms::service &srv,std::string const &ip,int port) :
  104. application(srv),
  105. ip_(ip),
  106. port_(port)
  107. {
  108. dispatcher().assign("^(.*)$",&connection_forwarder::on_request,this);
  109. }
  110. connection_forwarder::~connection_forwarder()
  111. {
  112. }
  113. void connection_forwarder::on_request()
  114. {
  115. intrusive_ptr<http::context> con = release_context();
  116. std::string env_str;
  117. env_str.reserve(1000);
  118. std::pair<void *,size_t> post = con->request().raw_post_data();
  119. std::map<std::string,std::string> const &env = con->connection().getenv();
  120. std::map<std::string,std::string>::const_iterator cl,p;
  121. cl=env.find("CONTENT_LENGTH");
  122. if(cl==env.end())
  123. return;
  124. p=cl;
  125. env_str.append(p->first.c_str(),p->first.size()+1);
  126. env_str.append(p->second.c_str(),p->second.size()+1);
  127. for(std::map<std::string,std::string>::const_iterator p=env.begin();p!=env.end();++p) {
  128. if(p==cl)
  129. continue;
  130. env_str.append(p->first.c_str(),p->first.size()+1);
  131. env_str.append(p->second.c_str(),p->second.size()+1);
  132. }
  133. env_str+=',';
  134. std::string header=(boost::format("%1%:",std::locale::classic()) % env_str.size()).str();
  135. header.reserve(header.size()+env_str.size()+post.second);
  136. header+=env_str;
  137. header.append(reinterpret_cast<char *>(post.first),post.second);
  138. boost::shared_ptr<impl::tcp_pipe> pipe(new impl::tcp_pipe(con,ip_,port_));
  139. pipe->async_send_receive(header);
  140. }
  141. };