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.
 
 
 
 
 
 

284 lines
7.5 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 "session_pool.h"
  21. #include "service.h"
  22. #include "thread_pool.h"
  23. #include "session_cookies.h"
  24. #include "session_sid.h"
  25. #include "session_dual.h"
  26. #include "hmac_encryptor.h"
  27. #include "json.h"
  28. #include "cppcms_error.h"
  29. #include "config.h"
  30. #ifdef CPPCMS_USE_EXTERNAL_BOOST
  31. # include <boost/bind.hpp>
  32. # include <boost/shared_ptr.hpp>
  33. # include <boost/enable_shared_from_this.hpp>
  34. #else // Internal Boost
  35. # include <cppcms_boost/bind.hpp>
  36. # include <cppcms_boost/shared_ptr.hpp>
  37. # include <cppcms_boost/enable_shared_from_this.hpp>
  38. namespace boost = cppcms_boost;
  39. #endif
  40. #ifdef HAVE_GCRYPT
  41. #include "aes_encryptor.h"
  42. #endif
  43. #ifdef CPPCMS_WIN_NATIVE
  44. #include "session_win32_file_storage.h"
  45. #else
  46. #include "session_posix_file_storage.h"
  47. #endif
  48. #include "session_memory_storage.h"
  49. #include <booster/aio/deadline_timer.h>
  50. #include <booster/posix_time.h>
  51. namespace cppcms {
  52. struct session_pool::data
  53. {
  54. };
  55. using namespace cppcms::sessions;
  56. template<typename Encryptor>
  57. struct session_pool::enc_factory : public encryptor_factory {
  58. enc_factory(std::string const &key) : key_(key) {}
  59. virtual std::auto_ptr<cppcms::sessions::encryptor> get()
  60. {
  61. std::auto_ptr<cppcms::sessions::encryptor> tmp(new Encryptor(key_));
  62. return tmp;
  63. }
  64. private:
  65. std::string key_;
  66. };
  67. struct session_pool::sid_factory : public session_api_factory
  68. {
  69. sid_factory(session_pool *pool) : pool_(pool) {}
  70. bool requires_gc() {
  71. if(pool_->storage_.get())
  72. return pool_->storage_->requires_gc();
  73. else
  74. return false;
  75. }
  76. void gc()
  77. {
  78. if(pool_->storage_.get())
  79. pool_->storage_->gc_job();
  80. }
  81. intrusive_ptr<session_api> get() {
  82. if(pool_->storage_.get())
  83. return new session_sid(pool_->storage_->get());
  84. else
  85. return 0;
  86. }
  87. private:
  88. session_pool *pool_;
  89. };
  90. struct session_pool::cookies_factory : public session_api_factory
  91. {
  92. cookies_factory(session_pool *pool) : pool_(pool) {}
  93. bool requires_gc() {
  94. return false;
  95. }
  96. void gc() {}
  97. intrusive_ptr<session_api> get() {
  98. if(pool_->encryptor_.get())
  99. return new session_cookies(pool_->encryptor_->get());
  100. else
  101. return 0;
  102. }
  103. private:
  104. session_pool *pool_;
  105. };
  106. struct session_pool::dual_factory : public session_api_factory
  107. {
  108. dual_factory(unsigned limit,session_pool *pool) : limit_(limit), pool_(pool) {}
  109. bool requires_gc() {
  110. if(pool_->storage_.get())
  111. return pool_->storage_->requires_gc();
  112. else
  113. return false;
  114. }
  115. void gc()
  116. {
  117. if(pool_->storage_.get())
  118. pool_->storage_->gc_job();
  119. }
  120. intrusive_ptr<session_api> get() {
  121. if(pool_->storage_.get() && pool_->encryptor_.get())
  122. return new session_dual(pool_->encryptor_->get(),pool_->storage_->get(),limit_);
  123. else
  124. return 0;
  125. }
  126. private:
  127. unsigned limit_;
  128. session_pool *pool_;
  129. };
  130. class session_pool::gc_job : public boost::enable_shared_from_this<gc_job> {
  131. public:
  132. gc_job(service *ser,int freq,session_pool *pool) :
  133. timer_(new booster::aio::deadline_timer(ser->get_io_service())),
  134. service_(ser),
  135. freq_(freq),
  136. pool_(pool)
  137. {
  138. }
  139. void async_run() const
  140. {
  141. service_->thread_pool().post(boost::bind(&gc_job::gc,shared_from_this()));
  142. }
  143. private:
  144. void gc() const
  145. {
  146. pool_->backend_->gc();
  147. timer_->expires_from_now(booster::ptime(freq_));
  148. timer_->async_wait(boost::bind(&gc_job::async_run,shared_from_this()));
  149. }
  150. boost::shared_ptr<booster::aio::deadline_timer> timer_;
  151. service *service_;
  152. int freq_;
  153. session_pool *pool_;
  154. };
  155. void session_pool::init()
  156. {
  157. service &srv=*service_;
  158. if(backend_.get())
  159. return;
  160. std::string location=srv.settings().get("session.location","none");
  161. if(location == "client" || (location=="both" && !encryptor_.get())) {
  162. std::string enc=srv.settings().get<std::string>("session.client.encryptor");
  163. std::auto_ptr<cppcms::sessions::encryptor_factory> factory;
  164. if(enc=="hmac") {
  165. std::string key = srv.settings().get<std::string>("session.client.key");
  166. factory.reset(new enc_factory<cppcms::sessions::impl::hmac_cipher>(key));
  167. }
  168. #ifdef HAVE_GCRYPT
  169. else if(enc=="aes") {
  170. std::string key = srv.settings().get<std::string>("session.client.key");
  171. factory.reset(new enc_factory<cppcms::sessions::impl::aes_cipher>(key));
  172. }
  173. #endif
  174. else
  175. throw cppcms_error("Unknown encryptor: "+enc);
  176. encryptor(factory);
  177. }
  178. if(location == "server" || (location == "both" && !storage_.get())) {
  179. std::string stor=srv.settings().get<std::string>("session.server.storage");
  180. std::auto_ptr<sessions::session_storage_factory> factory;
  181. if(stor == "files") {
  182. std::string dir = srv.settings().get("session.server.dir","");
  183. #ifdef CPPCMS_WIN_NATIVE
  184. factory.reset(new session_file_storage_factory(dir));
  185. #else
  186. bool sharing = srv.settings().get("session.server.shared",true);
  187. int threads = srv.threads_no();
  188. int procs = srv.procs_no();
  189. if(procs == 0) procs=1;
  190. factory.reset(new session_file_storage_factory(dir,threads*procs,procs,sharing));
  191. #endif
  192. }
  193. else if(stor == "memory") {
  194. if(srv.procs_no() > 1)
  195. throw cppcms_error("Can't use memory storage with more then 1 worker process");
  196. factory.reset(new session_memory_storage_factory());
  197. }
  198. else
  199. throw cppcms_error("Unknown server side storage:"+stor);
  200. storage(factory);
  201. }
  202. if(location == "server") {
  203. std::auto_ptr<session_api_factory> f(new sid_factory(this));
  204. backend(f);
  205. }
  206. else if(location == "client") {
  207. std::auto_ptr<session_api_factory> f(new cookies_factory(this));
  208. backend(f);
  209. }
  210. else if(location == "both") {
  211. unsigned limit=srv.settings().get("session.client_size_limit",2048);
  212. std::auto_ptr<session_api_factory> f(new dual_factory(limit,this));
  213. backend(f);
  214. }
  215. else if(location == "none")
  216. ;
  217. else
  218. throw cppcms_error("Unknown location");
  219. service_->after_fork(boost::bind(&session_pool::after_fork,this));
  220. }
  221. session_pool::session_pool(service &srv) :
  222. service_(&srv)
  223. {
  224. }
  225. void session_pool::after_fork()
  226. {
  227. if(backend_.get() && backend_->requires_gc()) {
  228. if(service_->process_id()!=1)
  229. return;
  230. int frequency = service_->settings().get("session.gc",0);
  231. if(frequency > 0) {
  232. boost::shared_ptr<gc_job> job(new gc_job(service_,frequency,this));
  233. job->async_run();
  234. }
  235. }
  236. }
  237. session_pool::~session_pool()
  238. {
  239. }
  240. intrusive_ptr<session_api> session_pool::get()
  241. {
  242. if(backend_.get())
  243. return backend_->get();
  244. else
  245. return 0;
  246. }
  247. void session_pool::backend(std::auto_ptr<session_api_factory> b)
  248. {
  249. backend_=b;
  250. }
  251. void session_pool::encryptor(std::auto_ptr<sessions::encryptor_factory> e)
  252. {
  253. encryptor_=e;
  254. }
  255. void session_pool::storage(std::auto_ptr<sessions::session_storage_factory> s)
  256. {
  257. storage_=s;
  258. }
  259. } /// cppcms