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.
 
 
 
 
 
 

301 lines
6.6 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 "cgi_api.h"
  10. #include <cppcms/service.h>
  11. #include <cppcms/http_context.h>
  12. #include <cppcms/http_request.h>
  13. #include <cppcms/http_response.h>
  14. #include <cppcms/application.h>
  15. #include <cppcms/applications_pool.h>
  16. #include <cppcms/thread_pool.h>
  17. #include <cppcms/views_pool.h>
  18. #include <cppcms/cache_interface.h>
  19. #include <cppcms/session_interface.h>
  20. #include <cppcms/cppcms_error.h>
  21. #include <booster/log.h>
  22. #include <booster/backtrace.h>
  23. #include "cached_settings.h"
  24. #include <cppcms/config.h>
  25. #include "binder.h"
  26. namespace cppcms {
  27. namespace http {
  28. struct context::_data {
  29. std::locale locale;
  30. std::string skin;
  31. http::request request;
  32. std::auto_ptr<http::response> response;
  33. std::auto_ptr<cache_interface> cache;
  34. std::auto_ptr<session_interface> session;
  35. _data(context &cntx) :
  36. locale(cntx.connection().service().locale()),
  37. request(cntx.connection())
  38. {
  39. }
  40. };
  41. context::context(booster::shared_ptr<impl::cgi::connection> conn) :
  42. conn_(conn)
  43. {
  44. d.reset(new _data(*this));
  45. d->response.reset(new http::response(*this));
  46. skin(service().views_pool().default_skin());
  47. }
  48. std::string context::skin()
  49. {
  50. return d->skin;
  51. }
  52. cache_interface &context::cache()
  53. {
  54. if(!d->cache.get()) {
  55. d->cache.reset(new cache_interface(*this));
  56. }
  57. return *d->cache;
  58. }
  59. void context::skin(std::string const &skin)
  60. {
  61. d->skin=skin;
  62. }
  63. namespace {
  64. struct ct_to_bool {
  65. void (context::*member)(bool r);
  66. booster::shared_ptr<context> ctx;
  67. void operator()(context::completion_type c)
  68. {
  69. ((*ctx).*member)(c!=context::operation_completed);
  70. }
  71. };
  72. }
  73. void context::run()
  74. {
  75. ct_to_bool cb = { &context::on_request_ready, self() };
  76. conn_->async_prepare_request(this,cb);
  77. }
  78. namespace {
  79. struct dispatcher {
  80. void (*func)(booster::intrusive_ptr<application>,std::string,bool);
  81. booster::intrusive_ptr<application> app;
  82. std::string url;
  83. void operator()() { func(app,url,true); }
  84. };
  85. }
  86. void context::on_request_ready(bool error)
  87. {
  88. if(error) return;
  89. char const *host = conn_->cgetenv("HTTP_HOST");
  90. char const *path_info = conn_->cgetenv("PATH_INFO");
  91. char const *script_name = conn_->cgetenv("SCRIPT_NAME");
  92. std::string matched;
  93. booster::intrusive_ptr<application> app = service().applications_pool().get(host,script_name,path_info,matched);
  94. if(!app) {
  95. response().io_mode(http::response::asynchronous);
  96. response().make_error_response(http::response::not_found);
  97. async_complete_response();
  98. return;
  99. }
  100. app->assign_context(self());
  101. if(app->is_asynchronous()) {
  102. response().io_mode(http::response::asynchronous);
  103. // Don't post, as context may be reassigned
  104. dispatch(app,matched,false);
  105. }
  106. else {
  107. dispatcher dt;
  108. dt.func = &context::dispatch;
  109. dt.app = app;
  110. dt.url.swap(matched);
  111. app->service().thread_pool().post(dt);
  112. }
  113. }
  114. namespace {
  115. struct run_ctx {
  116. booster::shared_ptr<context> ctx;
  117. void operator()() {
  118. ctx->run();
  119. }
  120. };
  121. }
  122. void context::complete_response()
  123. {
  124. response().finalize();
  125. if(conn_->is_reuseable()) {
  126. booster::shared_ptr<context> cont(new context(conn_));
  127. run_ctx rn = { cont };
  128. service().post(rn);
  129. }
  130. conn_.reset();
  131. }
  132. // static
  133. void context::dispatch(booster::intrusive_ptr<application> app,std::string url,bool syncronous)
  134. {
  135. try {
  136. if(syncronous && !app->context().service().cached_settings().session.disable_automatic_load)
  137. app->context().session().load();
  138. app->main(url);
  139. }
  140. catch(request_forgery_error const &e) {
  141. if(app->get_context() && !app->response().some_output_was_written()) {
  142. app->response().make_error_response(http::response::forbidden);
  143. }
  144. }
  145. catch(std::exception const &e){
  146. BOOSTER_ERROR("cppcms") << "Caught exception ["<<e.what()<<"]\n" << booster::trace(e) ;
  147. if(app->get_context()) {
  148. if(!app->response().some_output_was_written()) {
  149. if(app->service().cached_settings().security.display_error_message) {
  150. std::ostringstream ss;
  151. ss << e.what() << '\n';
  152. ss << booster::trace(e);
  153. app->response().make_error_response(http::response::internal_server_error,ss.str());
  154. }
  155. else
  156. app->response().make_error_response(http::response::internal_server_error);
  157. }
  158. }
  159. }
  160. if(app->get_context()) {
  161. if(syncronous) {
  162. app->context().complete_response();
  163. }
  164. else {
  165. app->context().async_complete_response();
  166. }
  167. }
  168. }
  169. namespace {
  170. void wrapper(context::handler const &h,bool r)
  171. {
  172. h(r ? context::operation_aborted : context::operation_completed);
  173. }
  174. }
  175. void context::async_flush_output(context::handler const &h)
  176. {
  177. if(response().io_mode() != http::response::asynchronous && response().io_mode()!=http::response::asynchronous_raw) {
  178. throw cppcms_error("Can't use asynchronouse operations when I/O mode is synchronous");
  179. }
  180. conn_->async_write_response(
  181. response(),
  182. false,
  183. h);
  184. }
  185. void context::async_complete_response()
  186. {
  187. response().finalize();
  188. if(response().io_mode() == http::response::asynchronous || response().io_mode() == http::response::asynchronous_raw) {
  189. ct_to_bool cb = { &context::try_restart, self() };
  190. conn_->async_write_response(
  191. response(),
  192. true,
  193. cb);
  194. return;
  195. }
  196. complete_response();
  197. }
  198. void context::try_restart(bool e)
  199. {
  200. if(e) return;
  201. if(conn_->is_reuseable()) {
  202. booster::shared_ptr<context> cont(new context(conn_));
  203. cont->run();
  204. }
  205. conn_.reset();
  206. }
  207. booster::shared_ptr<context> context::self()
  208. {
  209. return shared_from_this();
  210. }
  211. context::~context()
  212. {
  213. }
  214. void context::async_on_peer_reset(booster::callback<void()> const &h)
  215. {
  216. conn_->aync_wait_for_close_by_peer(h);
  217. }
  218. impl::cgi::connection &context::connection()
  219. {
  220. return *conn_;
  221. }
  222. cppcms::service &context::service()
  223. {
  224. return conn_->service();
  225. }
  226. http::request &context::request()
  227. {
  228. return d->request;
  229. }
  230. http::response &context::response()
  231. {
  232. return *d->response;
  233. }
  234. json::value const &context::settings()
  235. {
  236. return conn_->service().settings();
  237. }
  238. std::locale context::locale()
  239. {
  240. return d->locale;
  241. }
  242. void context::locale(std::locale const &new_locale)
  243. {
  244. d->locale=new_locale;
  245. if(response().some_output_was_written())
  246. response().out().imbue(d->locale);
  247. }
  248. void context::locale(std::string const &name)
  249. {
  250. locale(service().locale(name));
  251. }
  252. session_interface &context::session()
  253. {
  254. if(!d->session.get())
  255. d->session.reset(new session_interface(*this));
  256. return *d->session;
  257. }
  258. } // http
  259. } // cppcms