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.
 
 
 
 
 
 

476 lines
10 KiB

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