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.
 
 
 
 
 
 

460 lines
9.4 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 "json.h"
  10. #include "cgi_api.h"
  11. #include "util.h"
  12. #include <stdlib.h>
  13. #include "config.h"
  14. #ifdef CPPCMS_USE_EXTERNAL_BOOST
  15. # include <boost/bind.hpp>
  16. #else // Internal Boost
  17. # include <cppcms_boost/bind.hpp>
  18. namespace boost = cppcms_boost;
  19. #endif
  20. namespace cppcms { namespace impl { namespace cgi {
  21. /*
  22. class multipart_separator {
  23. public:
  24. multipart_separator(std::vector<char> &body,unsigned &body_ptr,std::string boundary) :
  25. body_(body),
  26. body_ptr_(body_ptr)
  27. {
  28. boundary_ = "--" + boundary;
  29. pos_ = 0;
  30. last_ = false;
  31. }
  32. int getc()
  33. {
  34. if(body_ptr_ < body_.size()) {
  35. return body_[body_ptr_++];
  36. }
  37. else {
  38. body_.clear();
  39. body_ptr_=0;
  40. return -1;
  41. }
  42. }
  43. enum { incomplete, last_chunk, chunk };
  44. int next()
  45. {
  46. for(;;){
  47. int c=getc();
  48. if(c < 0)
  49. return incomplete;
  50. if(pos_ < bodundary_.size()) {
  51. if(c == boundary_[pos_]) {
  52. pos_++;
  53. }
  54. else {
  55. if(pos_ != 0)
  56. output_.append(boundary_.substr(0,pos_));
  57. output_.append(char(c));
  58. pos_ = 0;
  59. }
  60. }
  61. else if(pos_ == boundary_.size()) {
  62. c == '-';
  63. last_ = true;
  64. pos_ = 0x10001;
  65. }
  66. else {
  67. unsigned diff = pos_ & 0xFFFF;
  68. if(last_){
  69. if(last_ending[diff]==c) {
  70. pos_ ++;
  71. diff ++ ;
  72. }
  73. else {
  74. output_.append(last_ending,diff);
  75. output_.append(char(c));
  76. pos_ = 0;
  77. last_ = false;
  78. }
  79. if(diff == 4)
  80. return last_chunk;
  81. }
  82. else {
  83. if(ending[diff] == c) {
  84. pos_ ++;
  85. diff ++;
  86. }
  87. else {
  88. output_.append(ending,diff);
  89. output_.append(char(c));
  90. pos_ = 0;
  91. }
  92. if(diff == 2) {
  93. pos_ = 0;
  94. return chunk;
  95. }
  96. }
  97. }
  98. }
  99. }
  100. private:
  101. static char const last_ending[]="--\r\n"
  102. static char const ending[]="\r\n"
  103. };
  104. class multipart_parser : public util::noncopyable {
  105. public:
  106. multipart_parser(std::vector<char> &body, unsigned &ptr) :
  107. separator_(body,ptr),
  108. parser_(body,ptr)
  109. {
  110. }
  111. struct none{};
  112. struct eof{};
  113. typedef std::pair<std::string,std::string> pair_type;
  114. typedef boost::shared_ptr<http::file> file_type;
  115. typedef enum { none, eof, error } result_type;
  116. typedef boost::variant<result_type,pair_type,file_type,eof> variant_type;
  117. void append(bool final = false)
  118. {
  119. if(result_.which() == 1) {
  120. std::string &last=boost::get<pair_type>(result_).second;
  121. last.append(separator_.output());
  122. }
  123. else if(result_.which() == 2) {
  124. file_type &file == boost::get<file_type>(result_);
  125. file.write(separator_.output());
  126. if(final)
  127. file.close();
  128. }
  129. }
  130. variant_type next()
  131. {
  132. switch(state:) {
  133. case done:
  134. return eof;
  135. case reading_data:
  136. switch(separator_.next()) {
  137. case multipart_separator::incomplete:
  138. append();
  139. return none;
  140. case multipart_separator::chunk;
  141. {
  142. append(final);
  143. variant_type tmp = result_;
  144. result_=none;
  145. state_ = reading_headers;
  146. return tmp;
  147. }
  148. case multipart_separator::last_chunk;
  149. {
  150. append(final);
  151. variant_type tmp = result_;
  152. result_=none;
  153. state_ = done;
  154. return tmp;
  155. }
  156. default:
  157. throw cppcms_error(
  158. (boost::format("Internal error at " __FILE__ "line %d") % __LINE__).str());
  159. }
  160. break;
  161. case reading_headers:
  162. switch(parser_.step())
  163. case parset::mode_data:
  164. return none;
  165. case parser::error_observerd:
  166. return error;
  167. case parser::end_of_headers:
  168. if(result_.which() == 0)
  169. return error;
  170. state_ = reading_data;
  171. return none;
  172. case parser::got_header:
  173. {
  174. std::string const header = parser.header_;
  175. parser.header_.clean();
  176. std::string::const_iterator m,p=header.begin();
  177. std::string::const_iterator e=header.end();
  178. p=http::protocol::skip_ws(p,e);
  179. m=p;
  180. p=http::protocol::tocken(p,e);
  181. std::string type(m,p);
  182. if(http::protocol::compare("Content-Disposition",type)==0)
  183. {
  184. while(p!=e) {
  185. if(http::protocol::separator(*p)) {
  186. ++p;
  187. continue;
  188. }
  189. m=p;
  190. if((p=http::protocol::tocken(p,e))!=m) {
  191. if(http::protocol::compare(std::string(m,p),"name"))
  192. }
  193. }
  194. }
  195. }
  196. }
  197. }
  198. private:
  199. multipart_separator separator_;
  200. cppcms::http::impl::parser parser_;
  201. };
  202. */
  203. connection::connection(cppcms::service &srv) :
  204. service_(&srv),
  205. request_in_progress_(true)
  206. {
  207. }
  208. connection::~connection()
  209. {
  210. }
  211. cppcms::service &connection::service()
  212. {
  213. return *service_;
  214. }
  215. intrusive_ptr<connection> connection::self()
  216. {
  217. return this;
  218. }
  219. void connection::async_prepare_request( http::request &request,
  220. boost::function<void(bool)> const &h)
  221. {
  222. async_read_headers(boost::bind(&connection::load_content,self(),_1,&request,h));
  223. }
  224. void connection::aync_wait_for_close_by_peer(boost::function<void()> const &on_eof)
  225. {
  226. async_read_eof(boost::bind(&connection::handle_eof,self(),on_eof));
  227. }
  228. void connection::handle_eof(callback const &on_eof)
  229. {
  230. if(request_in_progress_) {
  231. on_eof();
  232. }
  233. }
  234. void connection::set_error(ehandler const &h,std::string s)
  235. {
  236. error_=s;
  237. h(true);
  238. }
  239. void connection::load_content(boost::system::error_code const &e,http::request *request,ehandler const &h)
  240. {
  241. if(e) {
  242. set_error(h,e.message());
  243. return;
  244. }
  245. std::string content_type = getenv("CONTENT_TYPE");
  246. std::string s_content_length=getenv("CONTENT_LENGTH");
  247. long long content_length = s_content_length.empty() ? 0 : atoll(s_content_length.c_str());
  248. if(content_length < 0) {
  249. set_error(h,"Incorrect content length");
  250. return;
  251. }
  252. if(http::protocol::is_prefix_of("multipart/form-data",content_type)) {
  253. // 64 MB
  254. long long allowed=service().settings().get("security.multipart_form_data_limit",64*1024)*1024;
  255. if(content_length > allowed) {
  256. set_error(h,"security violation: multipart/form-data content length too big");
  257. return;
  258. }
  259. // FIXME
  260. return;
  261. }
  262. long long allowed=service().settings().get("security.content_length_limit",1024)*1024;
  263. if(content_length > allowed) {
  264. set_error(h,"security violation POST content length too big");
  265. // TODO log
  266. return;
  267. }
  268. content_.clear();
  269. if(content_length > 0) {
  270. content_.resize(content_length,0);
  271. async_read( &content_.front(),
  272. content_.size(),
  273. boost::bind(&connection::on_post_data_loaded,self(),_1,request,h));
  274. }
  275. else {
  276. on_post_data_loaded(boost::system::error_code(),request,h);
  277. }
  278. }
  279. void connection::on_post_data_loaded(boost::system::error_code const &e,http::request *request,ehandler const &h)
  280. {
  281. if(e) { set_error(h,e.message()); return; }
  282. request->set_post_data(content_);
  283. if(!request->prepare()) {
  284. set_error(h,"Bad Request");
  285. return;
  286. }
  287. h(false);
  288. }
  289. bool connection::is_reuseable()
  290. {
  291. return error_.empty() && keep_alive();
  292. }
  293. std::string connection::last_error()
  294. {
  295. return error_;
  296. }
  297. void connection::async_write_response( http::response &response,
  298. bool complete_response,
  299. ehandler const &h)
  300. {
  301. async_chunk_=response.get_async_chunk();
  302. if(!async_chunk_.empty()) {
  303. async_write( async_chunk_.data(),
  304. async_chunk_.size(),
  305. boost::bind( &connection::on_async_write_written,
  306. self(),
  307. _1,
  308. complete_response,
  309. h));
  310. return;
  311. }
  312. if(complete_response) {
  313. on_async_write_written(boost::system::error_code(),complete_response,h);
  314. return;
  315. }
  316. service().impl().get_io_service().post(boost::bind(h,false));
  317. }
  318. void connection::on_async_write_written(boost::system::error_code const &e,bool complete_response,ehandler const &h)
  319. {
  320. if(complete_response) {
  321. async_write_eof(boost::bind(&connection::on_eof_written,self(),_1,h));
  322. request_in_progress_=false;
  323. return;
  324. }
  325. service().impl().get_io_service().post(boost::bind(h,false));
  326. }
  327. void connection::async_complete_response(ehandler const &h)
  328. {
  329. async_write_eof(boost::bind(&connection::on_eof_written,self(),_1,h));
  330. request_in_progress_=false;
  331. }
  332. void connection::on_eof_written(boost::system::error_code const &e,ehandler const &h)
  333. {
  334. if(e) { set_error(h,e.message()); return; }
  335. h(false);
  336. }
  337. struct connection::reader {
  338. reader(connection *C,io_handler const &H,size_t S,char *P) : h(H), s(S), p(P),conn(C)
  339. {
  340. done=0;
  341. }
  342. io_handler h;
  343. size_t s;
  344. size_t done;
  345. char *p;
  346. connection *conn;
  347. void operator() (boost::system::error_code const &e=boost::system::error_code(),size_t read = 0)
  348. {
  349. if(e) {
  350. h(e,done+read);
  351. }
  352. s-=read;
  353. p+=read;
  354. done+=read;
  355. if(s==0)
  356. h(boost::system::error_code(),done);
  357. else
  358. conn->async_read_some(p,s,*this);
  359. }
  360. };
  361. struct connection::writer {
  362. writer(connection *C,io_handler const &H,size_t S,char const *P) : h(H), s(S), p(P),conn(C)
  363. {
  364. done=0;
  365. }
  366. io_handler h;
  367. size_t s;
  368. size_t done;
  369. char const *p;
  370. connection *conn;
  371. void operator() (boost::system::error_code const &e=boost::system::error_code(),size_t wr = 0)
  372. {
  373. if(e) {
  374. h(e,done+wr);
  375. }
  376. s-=wr;
  377. p+=wr;
  378. done+=wr;
  379. if(s==0)
  380. h(boost::system::error_code(),done);
  381. else
  382. conn->async_write_some(p,s,*this);
  383. }
  384. };
  385. void connection::async_read(void *p,size_t s,io_handler const &h)
  386. {
  387. reader r(this,h,s,(char*)p);
  388. r();
  389. }
  390. void connection::async_write(void const *p,size_t s,io_handler const &h)
  391. {
  392. writer w(this,h,s,(char const *)p);
  393. w();
  394. }
  395. size_t connection::write(void const *data,size_t n)
  396. {
  397. char const *p=reinterpret_cast<char const *>(data);
  398. size_t wr=0;
  399. while(n > 0) {
  400. size_t d=write_some(p,n);
  401. if(d == 0)
  402. return wr;
  403. p+=d;
  404. wr+=d;
  405. n-=d;
  406. }
  407. return wr;
  408. }
  409. } // cgi
  410. } // impl
  411. } // cppcms