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.
 
 
 
 
 
 

200 lines
5.7 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
  4. //
  5. // See accompanying file COPYING.TXT file for licensing details.
  6. //
  7. ///////////////////////////////////////////////////////////////////////////////
  8. #define CPPCMS_SOURCE
  9. #include <cppcms/forwarder.h>
  10. #include <cppcms/http_context.h>
  11. #include <cppcms/http_request.h>
  12. #include <cppcms/http_response.h>
  13. #include <cppcms/mount_point.h>
  14. #include <cppcms/service.h>
  15. #include "service_impl.h"
  16. #include <cppcms/url_dispatcher.h>
  17. #include "cgi_api.h"
  18. #include <booster/aio/socket.h>
  19. #include <booster/aio/io_service.h>
  20. #include <booster/aio/buffer.h>
  21. #include <booster/aio/endpoint.h>
  22. #include <booster/shared_ptr.h>
  23. #include <booster/enable_shared_from_this.h>
  24. #include <scgi_header.h>
  25. #include "todec.h"
  26. #include "binder.h"
  27. namespace io = booster::aio;
  28. namespace cppcms {
  29. namespace impl {
  30. class tcp_pipe : public booster::enable_shared_from_this<tcp_pipe> {
  31. public:
  32. tcp_pipe(booster::shared_ptr<http::context> connection,std::string const &ip,int port) :
  33. connection_(connection),
  34. ip_(ip),
  35. port_(port),
  36. socket_(connection_->service().impl().get_io_service())
  37. {
  38. }
  39. void async_send_receive(std::string &data)
  40. {
  41. data_.swap(data);
  42. io::endpoint ep(ip_,port_);
  43. socket_.open(ep.family());
  44. socket_.async_connect(ep,
  45. mfunc_to_event_handler(&tcp_pipe::on_connected,shared_from_this()));
  46. }
  47. private:
  48. void on_connected(booster::system::error_code const &e)
  49. {
  50. if(e) {
  51. connection_->response().make_error_response(500);
  52. connection_->async_complete_response();
  53. return;
  54. }
  55. socket_.async_write(
  56. io::buffer(data_),
  57. mfunc_to_io_handler(&tcp_pipe::on_written,shared_from_this()));
  58. }
  59. void on_written(booster::system::error_code const &e,size_t )
  60. {
  61. if(e) {
  62. connection_->response().make_error_response(500);
  63. connection_->async_complete_response();
  64. return;
  65. }
  66. connection_->async_on_peer_reset(mfunc_to_handler(&tcp_pipe::on_peer_close,shared_from_this()));
  67. connection_->response().io_mode(http::response::asynchronous_raw);
  68. input_.resize(4096);
  69. socket_.async_read_some(io::buffer(input_),
  70. mfunc_to_io_handler(&tcp_pipe::on_read,shared_from_this()));
  71. }
  72. void on_peer_close()
  73. {
  74. booster::system::error_code ec;
  75. socket_.cancel();
  76. socket_.shutdown(io::stream_socket::shut_rdwr,ec);
  77. socket_.close(ec);
  78. return;
  79. }
  80. void on_read(booster::system::error_code const &e,size_t n)
  81. {
  82. if(n > 0) {
  83. connection_->response().out().write(&input_.front(),n);
  84. }
  85. if(e) {
  86. connection_->async_complete_response();
  87. }
  88. else {
  89. socket_.async_read_some(io::buffer(input_),
  90. mfunc_to_io_handler(&tcp_pipe::on_read,shared_from_this()));
  91. }
  92. }
  93. booster::shared_ptr<http::context> connection_;
  94. std::string ip_;
  95. int port_;
  96. std::string data_;
  97. io::stream_socket socket_;
  98. std::vector<char> input_;
  99. };
  100. std::string make_scgi_header(std::map<std::string,std::string> const &env,size_t addon_size)
  101. {
  102. std::string env_str;
  103. env_str.reserve(1000);
  104. std::map<std::string,std::string>::const_iterator cl;
  105. cl=env.find("CONTENT_LENGTH");
  106. if(cl!=env.end()) {
  107. env_str.append(cl->first.c_str(),cl->first.size()+1);
  108. env_str.append(cl->second.c_str(),cl->second.size()+1);
  109. }
  110. else {
  111. env_str.append("CONTENT_LENGTH");
  112. env_str.append("\0" "0",3);
  113. }
  114. for(std::map<std::string,std::string>::const_iterator p=env.begin();p!=env.end();++p) {
  115. if(p==cl)
  116. continue;
  117. env_str.append(p->first.c_str(),p->first.size()+1);
  118. env_str.append(p->second.c_str(),p->second.size()+1);
  119. }
  120. std::string header=todec_string(env_str.size());
  121. header+=':';
  122. header.reserve(header.size()+env_str.size()+addon_size);
  123. header+=env_str;
  124. header+=',';
  125. return header;
  126. }
  127. } // impl
  128. void forward_connection(booster::shared_ptr<http::context> con,std::string const &ip,int port)
  129. {
  130. std::map<std::string,std::string> const &env = con->connection().getenv();
  131. std::pair<void *,size_t> post = con->request().raw_post_data();
  132. std::string header = impl::make_scgi_header(env,post.second);
  133. header.append(reinterpret_cast<char *>(post.first),post.second);
  134. booster::shared_ptr<impl::tcp_pipe> pipe(new impl::tcp_pipe(con,ip,port));
  135. pipe->async_send_receive(header);
  136. }
  137. struct forwarder::_data {};
  138. forwarder::forwarder()
  139. {
  140. }
  141. forwarder::~forwarder()
  142. {
  143. }
  144. void forwarder::add_forwarding_rule(booster::shared_ptr<mount_point> p,std::string const &ip,int port)
  145. {
  146. booster::unique_lock<booster::shared_mutex> lock(mutex_);
  147. rules_[p]=address_type(ip,port);
  148. }
  149. void forwarder::remove_forwarding_rule(booster::shared_ptr<mount_point> p)
  150. {
  151. booster::unique_lock<booster::shared_mutex> lock(mutex_);
  152. rules_.erase(p);
  153. }
  154. forwarder::address_type forwarder::check_forwading_rules(char const *h,char const *s,char const *p)
  155. {
  156. booster::shared_lock<booster::shared_mutex> lock(mutex_);
  157. for(rules_type::const_iterator it=rules_.begin();it!=rules_.end();++it) {
  158. if(it->first->match(h,s,p).first)
  159. return it->second;
  160. }
  161. return address_type(std::string(),0);
  162. }
  163. forwarder::address_type forwarder::check_forwading_rules(std::string const &h,std::string const &s,std::string const &p)
  164. {
  165. booster::shared_lock<booster::shared_mutex> lock(mutex_);
  166. for(rules_type::const_iterator it=rules_.begin();it!=rules_.end();++it) {
  167. if(it->first->match(h,s,p).first)
  168. return it->second;
  169. }
  170. return address_type(std::string(),0);
  171. }
  172. };