|
- #define CPPCMS_SOURCE
- #include "session_interface.h"
- #include "session_pool.h"
- #include "session_api.h"
- #include "util.h"
- #include "http_context.h"
- #include "http_request.h"
- #include "http_response.h"
- #include "http_cookie.h"
- #include "cppcms_error.h"
- #include "service.h"
- #include "json.h"
-
- #include <sstream>
- #include "string.h"
-
- using namespace std;
-
- namespace cppcms {
-
- struct session_interface::data {};
-
- struct session_interface::entry {
- std::string value;
- bool exposed;
- entry(std::string v="",bool exp=false) : value(v) , exposed(exp) {}
- bool operator==(entry const &other) const
- {
- return value==other.value && exposed==other.exposed;
- }
- bool operator!=(entry const &other) const
- {
- return !(*this==other);
- }
- };
-
- session_interface::session_interface(http::context &context) :
- context_(&context),
- loaded_(0)
- {
- timeout_val_def_=context_->settings().get("session.timeout",24*3600);
- string s_how=context_->settings().get("session.expire","browser");
- if(s_how=="fixed") {
- how_def_=fixed;
- }
- else if(s_how=="renew") {
- how_def_=renew;
- }
- else if(s_how=="browser") {
- how_def_=browser;
- }
- else {
- throw cppcms_error("Unsupported `session.expire' type `"+s_how+"'");
- }
-
- storage_=context_->service().session_pool().get();
- }
-
- session_interface::~session_interface()
- {
- }
-
- bool session_interface::load()
- {
- if(loaded_)
- return false; // FIXME
- loaded_ = 1;
- if(!storage_.get())
- return false;
- data_.clear();
- data_copy_.clear();
- timeout_val_=timeout_val_def_;
- how_=how_def_;
- string ar;
- saved_=0;
- on_server_=0;
- if(!storage_->load(*this,ar,timeout_in_)) {
- return false;
- }
- load_data(data_,ar);
- data_copy_=data_;
- if(is_set("_t"))
- timeout_val_=get<int>("_t");
- if(is_set("_h"))
- how_=get<int>("_h");
- if(is_set("_s"))
- on_server_=get<int>("_s");
- return true;
- }
-
- int session_interface::cookie_age()
- {
- if(how_==browser)
- return 0;
- if(how_==renew || ( how_==fixed && new_session_ ))
- return timeout_val_;
- return timeout_in_ - time(NULL);
- }
-
- time_t session_interface::session_age()
- {
- if(how_==browser || how_==renew || (how_==fixed && new_session_))
- return timeout_val_ + time(NULL);
- return timeout_in_;
- }
-
- namespace {
- struct packed {
- uint32_t key_size : 10;
- uint32_t exposed : 1;
- uint32_t data_size : 21;
- packed() {}
- packed(unsigned ks,bool exp, unsigned ds)
- {
- if(ks >=1024)
- throw cppcms_error("session::save key too long");
- if(ds >= 1024 * 1024 * 2)
- throw cppcms_error("session::save value too long");
- key_size=ks;
- exposed = exp ? 1 : 0;
- data_size=ds;
- }
- packed(char const *start,char const *end)
- {
- if(start + 4 <= end ) {
- memcpy(this,start,4);
- }
- else
- throw cppcms_error("session::format violation -> pack");
- }
- };
-
- }
-
-
- void session_interface::save_data(data_type const &data,std::string &s)
- {
- s.clear();
- data_type::const_iterator p;
- for(p=data.begin();p!=data.end();++p) {
- packed header(p->first.size(),p->second.exposed,p->second.value.size());
- char *ptr=(char *)&header;
- s.append(ptr,ptr+sizeof(header));
- s.append(p->first.begin(),p->first.end());
- s.append(p->second.value.begin(),p->second.value.end());
- }
- }
-
- void session_interface::load_data(data_type &data,std::string const &s)
- {
- data.clear();
- char const *begin=s.data(),*end=begin+s.size();
- while(begin < end) {
- packed p(begin,end);
- begin +=sizeof(p);
- if(end - begin >= int(p.key_size + p.data_size)) {
- string key(begin,begin+p.key_size);
- begin+=p.key_size;
- string val(begin,begin+p.data_size);
- begin+=p.data_size;
- entry &ent=data[key];
- ent.exposed = p.exposed;
- ent.value.swap(val);
- }
- else {
- throw cppcms_error("sessions::format violation data");
- }
-
- }
-
- }
-
-
-
- void session_interface::update_exposed(bool force)
- {
- for(data_type::iterator p=data_.begin();p!=data_.end();++p) {
- data_type::iterator p2=data_copy_.find(p->first);
- if(p->second.exposed && (force || p2==data_copy_.end() || !p2->second.exposed || p->second.value!=p2->second.value)){
- set_session_cookie(cookie_age(),p->second.value,p->first);
- }
- else if(!p->second.exposed && ((p2!=data_copy_.end() && p2->second.exposed) || force)) {
- set_session_cookie(-1,"",p->first);
- }
- }
- for(data_type::iterator p=data_copy_.begin();p!=data_copy_.end();++p) {
- if(p->second.exposed && data_.find(p->first)==data_.end()) {
- set_session_cookie(-1,"",p->first);
- }
- }
- }
-
- void session_interface::save()
- {
- if(storage_.get()==NULL || !loaded_ || saved_)
- return;
- check();
- new_session_ = data_copy_.empty() && !data_.empty();
- if(data_.empty()) {
- if(get_session_cookie()!="")
- storage_->clear(*this);
- update_exposed(true);
- return;
- }
-
- time_t now = time(NULL);
-
- bool force_update=false;
- if(data_==data_copy_) {
- if(how_==fixed) {
- return;
- }
- if(how_==renew || how_==browser) {
- int64_t delta=now + timeout_val_ - timeout_in_;
- if(delta < timeout_val_ * 0.1) {// Less then 10% -- no renew need
- return;
- }
- }
- force_update=true;
- }
-
- string ar;
- save_data(data_,ar);
-
- temp_cookie_.clear();
- storage_->save(*this,ar,session_age(),new_session_,on_server_);
- set_session_cookie(cookie_age(),temp_cookie_);
- temp_cookie_.clear();
-
- update_exposed(force_update);
- saved_=true;
- }
-
- void session_interface::check()
- {
- if(storage_.get()==NULL)
- throw cppcms_error("Session storage backend is not loaded\n");
- }
-
- string &session_interface::operator[](string const &key)
- {
- check();
- return data_[key].value;
- }
-
- void session_interface::erase(string const &key)
- {
- check();
- data_.erase(key);
- }
-
- bool session_interface::is_set(string const &key)
- {
- check();
- return data_.find(key)!=data_.end();
- }
-
- void session_interface::clear()
- {
- check();
- data_.clear();
- }
-
- std::string session_interface::get(std::string const &key)
- {
- check();
- data_type::const_iterator p=data_.find(key);
- if(p==data_.end())
- throw cppcms_error("Undefined session key "+key);
- return p->second.value;
- }
-
- void session_interface::set(std::string const &key,std::string const &v)
- {
- check();
- data_[key]=v;
- }
-
- void session_interface::clear_session_cookie()
- {
- check();
- if(get_session_cookie()!="")
- set_session_cookie(-1,"");
- }
- void session_interface::set_session_cookie(int64_t age,string const &data,string const &key)
- {
- if(data.empty())
- age=-1;
- std::string cookie_name=context_->settings().get("session.cookies.prefix","cppcms_session");
- if(!key.empty()) {
- cookie_name+="_";
- cookie_name+=key;
- }
- std::string domain = context_->settings().get("session.cookies.domain","");
- std::string path = context_->settings().get("session.cookies.path","/");
- bool secure = context_->settings().get("session.cookies.secure",0);
-
- http::cookie the_cookie(cookie_name,util::urlencode(data),path,domain);
-
- if(age < 0) {
- the_cookie.max_age(0);
- }
- else if(age == 0)
- the_cookie.browser_age();
- else
- the_cookie.max_age(age);
- the_cookie.secure(secure);
- context_->response().set_cookie(the_cookie);
- }
-
- void session_interface::set_session_cookie(string const &data)
- {
- check();
- temp_cookie_=data;
- }
-
- string session_interface::get_session_cookie()
- {
- check();
- string name=context_->settings().get("session.cookies.prefix","cppcms_session");
- http::request::cookies_type const &cookies = context_->request().cookies();
- http::request::cookies_type::const_iterator p=cookies.find(name);
- if(p==cookies.end())
- return "";
- return p->second.value();
- }
-
- bool session_interface::is_exposed(std::string const &key)
- {
- data_type::iterator p=data_.find(key);
- if(p!=data_.end())
- return p->second.exposed;
- return false;
- }
-
- void session_interface::expose(string const &key,bool exp)
- {
- data_[key].exposed=exp;
- }
-
- void session_interface::hide(string const &key)
- {
- check();
- expose(key,false);
- }
-
- void session_interface::age(int t)
- {
- check();
- timeout_val_=t;
- set("_t",t);
- }
-
- int session_interface::age()
- {
- check();
- return timeout_val_;
- }
-
- void session_interface::default_age()
- {
- check();
- erase("_t");
- timeout_val_=timeout_val_def_;
- }
-
- int session_interface::expiration()
- {
- check();
- return how_;
- }
-
- void session_interface::expiration(int h)
- {
- check();
- how_=h;
- set("_h",h);
- }
- void session_interface::default_expiration()
- {
- check();
- erase("_h");
- how_=how_def_;
- }
-
- void session_interface::on_server(bool srv)
- {
- check();
- on_server_=srv;
- set("_s",int(srv));
- }
-
- bool session_interface::on_server()
- {
- check();
- return on_server_;
- }
-
-
-
-
- } // cppcms
|