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.
 
 
 
 
 
 

242 lines
5.0 KiB

  1. #define CPPCMS_SOURCE
  2. #include "asio_config.h"
  3. #include "url_dispatcher.h"
  4. #include "http_request.h"
  5. #include "http_response.h"
  6. #include "http_protocol.h"
  7. #include "service.h"
  8. #include "service_impl.h"
  9. #include "global_config.h"
  10. #include "cgi_api.h"
  11. #include "util.h"
  12. #include <boost/bind.hpp>
  13. namespace cppcms { namespace impl { namespace cgi {
  14. connection::connection(cppcms::service &srv) :
  15. service_(&srv)
  16. {
  17. }
  18. connection::~connection()
  19. {
  20. }
  21. cppcms::service &connection::service()
  22. {
  23. return *service_;
  24. }
  25. intrusive_ptr<connection> connection::self()
  26. {
  27. return this;
  28. }
  29. void connection::async_prepare_request( http::request &request,
  30. boost::function<void(bool)> const &h)
  31. {
  32. async_read_headers(boost::bind(&connection::load_content,self(),_1,&request,h));
  33. }
  34. void connection::set_error(ehandler const &h,std::string s)
  35. {
  36. error_=s;
  37. h(true);
  38. }
  39. void connection::load_content(boost::system::error_code const &e,http::request *request,ehandler const &h)
  40. {
  41. if(e) {
  42. set_error(h,e.message());
  43. return;
  44. }
  45. std::string content_type = getenv("CONTENT_TYPE");
  46. std::string s_content_length=getenv("CONTENT_LENGTH");
  47. long long content_length = s_content_length.empty() ? 0 : atoll(s_content_length.c_str());
  48. if(content_length < 0) {
  49. set_error(h,"Incorrect content length");
  50. return;
  51. }
  52. if(http::protocol::is_prefix_of("multipart/form-data",content_type)) {
  53. // 64 MB
  54. long long allowed=service().settings().integer("security.multipart_form_data_limit",64*1024)*1024;
  55. if(content_length > allowed) {
  56. set_error(h,"security violation: multipart/form-data content length too big");
  57. return;
  58. }
  59. // FIXME
  60. return;
  61. }
  62. long long allowed=service().settings().integer("security.content_length_limit",1024)*1024;
  63. if(content_length > allowed) {
  64. set_error(h,"security violation POST content length too big");
  65. // TODO log
  66. return;
  67. }
  68. content_.clear();
  69. if(content_length > 0) {
  70. content_.resize(content_length,0);
  71. async_read( &content_.front(),
  72. content_.size(),
  73. boost::bind(&connection::on_post_data_loaded,self(),_1,request,h));
  74. }
  75. else {
  76. on_post_data_loaded(boost::system::error_code(),request,h);
  77. }
  78. }
  79. void connection::on_post_data_loaded(boost::system::error_code const &e,http::request *request,ehandler const &h)
  80. {
  81. if(e) { set_error(h,e.message()); return; }
  82. request->set_post_data(content_);
  83. if(!request->prepare()) {
  84. set_error(h,"Bad Request");
  85. return;
  86. }
  87. h(false);
  88. }
  89. bool connection::is_reuseable()
  90. {
  91. return error_.empty() && keep_alive();
  92. }
  93. std::string connection::last_error()
  94. {
  95. return error_;
  96. }
  97. void connection::async_write_response( http::response &response,
  98. bool complete_response,
  99. ehandler const &h)
  100. {
  101. async_chunk_=response.get_async_chunk();
  102. if(!async_chunk_.empty()) {
  103. async_write( async_chunk_.data(),
  104. async_chunk_.size(),
  105. boost::bind( &connection::on_async_write_written,
  106. self(),
  107. _1,
  108. complete_response,
  109. h));
  110. return;
  111. }
  112. if(complete_response) {
  113. on_async_write_written(boost::system::error_code(),complete_response,h);
  114. return;
  115. }
  116. service().impl().get_io_service().post(boost::bind(h,false));
  117. }
  118. void connection::on_async_write_written(boost::system::error_code const &e,bool complete_response,ehandler const &h)
  119. {
  120. if(complete_response) {
  121. async_write_eof(boost::bind(&connection::on_eof_written,self(),_1,h));
  122. return;
  123. }
  124. service().impl().get_io_service().post(boost::bind(h,false));
  125. }
  126. void connection::async_complete_response(ehandler const &h)
  127. {
  128. async_write_eof(boost::bind(&connection::on_eof_written,self(),_1,h));
  129. }
  130. void connection::on_eof_written(boost::system::error_code const &e,ehandler const &h)
  131. {
  132. if(e) { set_error(h,e.message()); return; }
  133. h(false);
  134. }
  135. struct connection::reader {
  136. reader(connection *C,io_handler const &H,size_t S,char *P) : h(H), s(S), p(P),conn(C)
  137. {
  138. done=0;
  139. }
  140. io_handler h;
  141. size_t s;
  142. size_t done;
  143. char *p;
  144. connection *conn;
  145. void operator() (boost::system::error_code const &e=boost::system::error_code(),size_t read = 0)
  146. {
  147. if(e) {
  148. h(e,done+read);
  149. }
  150. s-=read;
  151. p+=read;
  152. done+=read;
  153. if(s==0)
  154. h(boost::system::error_code(),done);
  155. else
  156. conn->async_read_some(p,s,*this);
  157. }
  158. };
  159. struct connection::writer {
  160. writer(connection *C,io_handler const &H,size_t S,char const *P) : h(H), s(S), p(P),conn(C)
  161. {
  162. done=0;
  163. }
  164. io_handler h;
  165. size_t s;
  166. size_t done;
  167. char const *p;
  168. connection *conn;
  169. void operator() (boost::system::error_code const &e=boost::system::error_code(),size_t wr = 0)
  170. {
  171. if(e) {
  172. h(e,done+wr);
  173. }
  174. s-=wr;
  175. p+=wr;
  176. done+=wr;
  177. if(s==0)
  178. h(boost::system::error_code(),done);
  179. else
  180. conn->async_write_some(p,s,*this);
  181. }
  182. };
  183. void connection::async_read(void *p,size_t s,io_handler const &h)
  184. {
  185. reader r(this,h,s,(char*)p);
  186. r();
  187. }
  188. void connection::async_write(void const *p,size_t s,io_handler const &h)
  189. {
  190. writer w(this,h,s,(char const *)p);
  191. w();
  192. }
  193. size_t connection::write(void const *data,size_t n)
  194. {
  195. char const *p=reinterpret_cast<char const *>(data);
  196. size_t wr=0;
  197. while(n > 0) {
  198. size_t d=write_some(p,n);
  199. if(d == 0)
  200. return wr;
  201. p+=d;
  202. wr+=d;
  203. n-=d;
  204. }
  205. return wr;
  206. }
  207. } // cgi
  208. } // impl
  209. } // cppcms