/////////////////////////////////////////////////////////////////////////////////// Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>//// See accompanying file COPYING.TXT file for licensing details./////////////////////////////////////////////////////////////////////////////////#define CPPCMS_SOURCE#include <cppcms/session_pool.h>#include <cppcms/service.h>#include <cppcms/thread_pool.h>#include <cppcms/session_cookies.h>#include <cppcms/session_sid.h>#include <cppcms/session_dual.h>#include "hmac_encryptor.h"#include <cppcms/json.h>#include <cppcms/cppcms_error.h>#include <booster/shared_ptr.h>#include <booster/shared_object.h>#include <booster/enable_shared_from_this.h>#include <cppcms/config.h>#include <cppcms/mem_bind.h>#include "aes_encryptor.h"#ifdef CPPCMS_WIN_NATIVE#include "session_win32_file_storage.h"#else#include "session_posix_file_storage.h"#endif#include "session_memory_storage.h"#ifndef CPPCMS_NO_TCP_CACHE#include "session_tcp_storage.h"#endif#include <booster/aio/deadline_timer.h>#include <booster/callback.h>#include <booster/posix_time.h>#include <booster/system_error.h>#include "cached_settings.h"namespace cppcms {struct session_pool::_data{booster::shared_object module;cppcms::json::value settings;booster::hold_ptr<impl::cached_settings> cached_settings;};using namespace cppcms::sessions;struct session_pool::sid_factory : public session_api_factory{sid_factory(session_pool *pool) : pool_(pool) {}bool requires_gc() {if(pool_->storage_.get())return pool_->storage_->requires_gc();elsereturn false;}void gc(){if(pool_->storage_.get())pool_->storage_->gc_job();}booster::shared_ptr<session_api> get(){booster::shared_ptr<session_api> p;if(pool_->storage_.get())p.reset(new session_sid(pool_->storage_->get()));return p;}private:session_pool *pool_;};struct session_pool::cookies_factory : public session_api_factory{cookies_factory(session_pool *pool) : pool_(pool) {}bool requires_gc() {return false;}void gc() {}booster::shared_ptr<session_api> get(){booster::shared_ptr<session_api> p;if(pool_->encryptor_.get())p.reset(new session_cookies(pool_->encryptor_->get()));return p;}private:session_pool *pool_;};struct session_pool::dual_factory : public session_api_factory{dual_factory(unsigned limit,session_pool *pool) : limit_(limit), pool_(pool) {}bool requires_gc() {if(pool_->storage_.get())return pool_->storage_->requires_gc();elsereturn false;}void gc(){if(pool_->storage_.get())pool_->storage_->gc_job();}booster::shared_ptr<session_api> get(){booster::shared_ptr<session_api> p;if(pool_->storage_.get() && pool_->encryptor_.get())p.reset(new session_dual(pool_->encryptor_->get(),pool_->storage_->get(),limit_));return p;}private:unsigned limit_;session_pool *pool_;};class session_pool::gc_job : public booster::enable_shared_from_this<gc_job> {public:gc_job(service *ser,double freq,session_pool *pool) :timer_(new booster::aio::deadline_timer(ser->get_io_service())),service_(ser),freq_(freq),pool_(pool){}void async_run(booster::system::error_code const &e){if(e)return;service_->thread_pool().post(cppcms::util::mem_bind(&gc_job::gc,shared_from_this()));}private:void gc(){booster::ptime start = booster::ptime::now();booster::ptime restart = start + booster::ptime::from_number(freq_);pool_->backend_->gc();timer_->expires_at(restart);timer_->async_wait(cppcms::util::mem_bind(&gc_job::async_run,shared_from_this()));}booster::shared_ptr<booster::aio::deadline_timer> timer_;service *service_;double freq_;session_pool *pool_;};void session_pool::init(){cppcms::json::value const &settings = (service_ ? service_->settings() : d->settings);if(backend_.get())return;std::string location=settings.get("session.location","none");if((location == "client" || location=="both") && !encryptor_.get()) {using namespace cppcms::sessions::impl;std::string enc=settings.get("session.client.encryptor","");std::string mac=settings.get("session.client.hmac","");std::string cbc=settings.get("session.client.cbc","");if(enc.empty() && mac.empty() && cbc.empty()) {throw cppcms_error("Using clinet session storage without encryption method");}if(!enc.empty() && (!mac.empty() || !cbc.empty())) {throw cppcms_error("Can't specify both session.client.encryptor and session.client.hmac or session.client.cbc");}if(!cbc.empty() && mac.empty()) {throw cppcms_error("Can't use session encryption without MAC");}std::auto_ptr<cppcms::sessions::encryptor_factory> factory;if(!enc.empty()) {crypto::key k;std::string key_file = settings.get("session.client.key_file","");if(key_file.empty())k=crypto::key(settings.get<std::string>("session.client.key"));elsek.read_from_file(key_file);if(enc=="hmac") {factory.reset(new hmac_factory("sha1",k));}else if(enc.compare(0,5,"hmac-") == 0) {std::string algo = enc.substr(5);factory.reset(new hmac_factory(algo,k));}else if(enc.compare(0,3,"aes") == 0) {factory.reset(new aes_factory(enc,k));}elsethrow cppcms_error("Unknown encryptor: "+enc);}else {crypto::key hmac_key;std::string hmac_key_file = settings.get("session.client.hmac_key_file","");if(hmac_key_file.empty())hmac_key = crypto::key(settings.get<std::string>("session.client.hmac_key"));elsehmac_key.read_from_file(hmac_key_file);if(cbc.empty()) {factory.reset(new hmac_factory(mac,hmac_key));}else {crypto::key cbc_key;std::string cbc_key_file = settings.get("session.client.cbc_key_file","");if(cbc_key_file.empty())cbc_key = crypto::key(settings.get<std::string>("session.client.cbc_key"));elsecbc_key.read_from_file(cbc_key_file);factory.reset(new aes_factory(cbc,cbc_key,mac,hmac_key));}}encryptor(factory);}if((location == "server" || location == "both") && !storage_.get()) {std::string stor=settings.get<std::string>("session.server.storage");std::auto_ptr<sessions::session_storage_factory> factory;#ifndef CPPCMS_NO_GZIPif(stor == "files") {std::string dir = settings.get("session.server.dir","");#ifdef CPPCMS_WIN_NATIVEfactory.reset(new session_file_storage_factory(dir));#elseif(!service_) {if(!settings.get("session.server.shared",true)) {throw cppcms_error("When using external session management with file storage ""session.server.shared must be true");}factory.reset(new session_file_storage_factory(dir,booster::thread::hardware_concurrency()+1,2,true));}else {bool sharing = settings.get("session.server.shared",true);int threads = service_->threads_no();int procs = service_->procs_no();if(procs == 0) procs=1;factory.reset(new session_file_storage_factory(dir,threads*procs,procs,sharing));}#endif}else#endif// CPPCMS_NO_GZIPif(stor == "memory") {if(!service_) {throw cppcms_error("Can't use memory storage for external session management");}if(service_->procs_no() > 1)throw cppcms_error("Can't use memory storage with more then 1 worker process");factory.reset(new session_memory_storage_factory());}else if(stor == "external") {std::string so = settings.get<std::string>("session.server.shared_object","");std::string module = settings.get<std::string>("session.server.module","");std::string entry_point = settings.get<std::string>("session.server.entry_point","sessions_generator");if(so.empty() && module.empty())throw cppcms_error( "sessions_pool: session.storage=external ""and neither session.server.shared_object ""nor session.server.module is defined");if(!so.empty() && !module.empty())throw cppcms_error( "sessions_pool: both session.server.shared_object ""and session.server.module are defined");if(so.empty()) {so = booster::shared_object::name(module);}std::string error;if(!d->module.open(so,error)) {throw cppcms_error("sessions_pool: failed to load shared object " + so + ": " + error);}cppcms_session_storage_generator_type f=0;d->module.symbol(f,entry_point);factory.reset(f(settings.find("session.server.settings")));}#ifndef CPPCMS_NO_TCP_CACHEelse if(stor == "network") {typedef std::vector<std::string> ips_type;typedef std::vector<int> ports_type;ips_type ips = settings.get<ips_type>("session.server.ips");ports_type ports = settings.get<ports_type>("session.server.ports");if(ips.size() != ports.size())throw cppcms_error( "sessions_pool: session.server.ips and ""session.server.ports are not of the same size");if(ips.empty()) {throw cppcms_error("sessions_pool:session.server.ips is empty");}factory.reset(new tcp_factory(ips,ports));}#endifelsethrow cppcms_error("sessions_pool: unknown server side storage:"+stor);storage(factory);}if(location == "server") {std::auto_ptr<session_api_factory> f(new sid_factory(this));backend(f);}else if(location == "client") {std::auto_ptr<session_api_factory> f(new cookies_factory(this));backend(f);}else if(location == "both") {unsigned limit=settings.get("session.client_size_limit",2048);std::auto_ptr<session_api_factory> f(new dual_factory(limit,this));backend(f);}else if(location == "none");elsethrow cppcms_error("Unknown location");if(service_)service_->after_fork(cppcms::util::mem_bind(&session_pool::after_fork,this));}session_pool::session_pool(service &srv) :d(new _data()),service_(&srv){}session_pool::session_pool(cppcms::json::value const &v) :d(new _data()),service_(0){d->settings = v;d->cached_settings.reset(new cppcms::impl::cached_settings(v));}void session_pool::after_fork(){if(backend_.get() && backend_->requires_gc()) {if(service_->process_id()!=1)return;double frequency = service_->settings().get("session.gc",0.0);if(frequency > 0) {booster::shared_ptr<gc_job> job(new gc_job(service_,frequency,this));job->async_run(booster::system::error_code());}}}session_pool::~session_pool(){}booster::shared_ptr<session_api> session_pool::get(){booster::shared_ptr<session_api> p;if(backend_.get())p=backend_->get();return p;}void session_pool::backend(std::auto_ptr<session_api_factory> b){backend_=b;}void session_pool::encryptor(std::auto_ptr<sessions::encryptor_factory> e){encryptor_=e;}void session_pool::storage(std::auto_ptr<sessions::session_storage_factory> s){storage_=s;}cppcms::impl::cached_settings const &session_pool::cached_settings(){return service_? service_->cached_settings() : *d->cached_settings;}} /// cppcms
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。