bool select(string const &sid,time_t &timeout,string &data) { sqlite3_stmt *st; char const *q="SELECT data,timeout FROM sessions WHERE sid=?"; if(sqlite3_prepare(db,q,-1,&st,NULL)!=0) { throw cppcms_error(string("sqlite prepared statement:")+sqlite3_errmsg(db)); } int res; sqlite3_bind_text(st,1, sid.c_str(), sid.size(),SQLITE_STATIC); while((res=sqlite3_step(st))==SQLITE_BUSY){ poll(NULL,0,5); } if(res==SQLITE_DONE) { sqlite3_finalize(st); return false; } else if(res==SQLITE_ROW) { int64_t to=sqlite3_column_int64(st,1); if(to < time(NULL)) { sqlite3_finalize(st); del(sid); write_ops++; return false; } size_t length=sqlite3_column_bytes(st,0); data.assign((const char *)sqlite3_column_blob(st,0),length); timeout=to; sqlite3_finalize(st); return true; } else { throw cppcms_error(string("Insert error:")+sqlite3_errmsg(db)); } }
process_cache_factory::process_cache_factory(size_t memsize,char const *file) { cache=NULL; if(memsize<8*1024) { throw cppcms_error("Cache size too small -- need at least 8K"); } if(!mem) { mem=new shmem_control(memsize,file); owner_pid=getpid(); } else { throw cppcms_error("The memory initilized -- can't use more then once cache in same time"); } cache=new process_cache(memsize); };
session_backend_factory session_sqlite_storage::factory(cppcms_config const &config) { string db=config.sval("session.sqlite_db"); int db_count=config.ival("session.sqlite_db_num",4); if(db_count>8) db_count=8; if(db_count<0) db_count=0; db_count=1<<db_count; string def="fork"; if(config.sval("server.mod","")=="thread") def="thread"; string mod=config.sval("session.sqlite_mod",def); bool cache=config.ival("session.server_enable_cache",0); if(mod=="fork") { bool sync=config.ival("session.sqlite_sync",0); return builder_proc(db,db_count,sync,cache); } else if(mod=="thread") { bool sync=config.ival("session.sqlite_sync",1); int dc=config.ival("session.sqlite_commits",1000); int dt=config.ival("session.sqlite_commit_timeout",5); return builder_thread(db,db_count,sync,dc,dt,cache); } else { throw cppcms_error("Unknown sqlite mode:"+mod); } }
void cppcms_config::load(int argc,char *argv[],char const *def) { if(loaded) { return; } char const *def_file=def; int i; for(i=1;i<argc;i++) { if(strncmp(argv[i],"--config=",9)==0) { def_file=argv[i]+9; break; } else if(strcmp(argv[i],"-c")==0 && i+1<argc) { def_file=argv[i+1]; break; } } if(def_file==NULL) { def_file=getenv("CPPCMS_CONFIG"); } if(def_file==NULL) { throw cppcms_error("Configuration file not defined"); } load(def_file); }
void file::move_to_file() { std::string tmp_dir; if(temporary_dir_.empty()) { char const *tmp=getenv("TEMP"); if(!tmp) tmp=getenv("TMP"); if(!tmp) tmp="/tmp"; tmp_dir=tmp; } else { tmp_dir = temporary_dir_; } tmp_file_name_ = tmp_dir + "/cppcms_uploads_"; urandom_device rnd; char buf[16]; char rand[33]={0}; rnd.generate(buf,16); impl::tohex(buf,sizeof(buf),rand); tmp_file_name_.append(rand); tmp_file_name_+=".tmp"; file_.open(tmp_file_name_.c_str(), std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::trunc); if(!file_) throw cppcms_error("Failed to create temporary file"); file_data_.seekg(0); copy_stream(file_data_,file_); file_data_.str(""); saved_in_file_ = 1; }
void session_file_storage::gc() { std::auto_ptr<_WIN32_FIND_DATAW> entry(new _WIN32_FIND_DATAW); HANDLE d=INVALID_HANDLE_VALUE; std::string search_path = path_ + "/*"; try{ if((d=::FindFirstFileW(booster::nowide::convert(search_path).c_str(),entry.get()))==INVALID_HANDLE_VALUE) { if(GetLastError() == ERROR_FILE_NOT_FOUND) return; throw cppcms_error("Failed to open directory :"+path_); } do { if(entry->cFileName[32]!=0) continue; int i; std::string filename=booster::nowide::convert(entry->cFileName); for(i=0;i<32;i++) { if(!isxdigit(filename[i])) break; } if(i!=32) continue; { locked_file file(this,filename); if(!read_timestamp(file.handle())) ::DeleteFileW(booster::nowide::convert(file.name()).c_str()); } } while(::FindNextFileW(d,entry.get())); ::FindClose(d); } catch(...) { if(d!=INVALID_HANDLE_VALUE) ::FindClose(d); throw; } }
void file::save_to(std::string const &filename) { if(!saved_in_file_) { file_data_.clear(); file_data_.seekg(0); save_by_copy(filename,file_data_); return; } file_.clear(); file_.seekg(0); file_.sync(); #ifdef CPPCMS_WIN32 file_.close(); /// we can't move opened file on windows as it would be locked if(booster::nowide::rename(tmp_file_name_.c_str(),filename.c_str())!=0) { file_.open(tmp_file_name_.c_str(),std::ios_base::binary | std::ios_base::in | std::ios_base::out); if(!file_) { throw cppcms_error("Failed to reopen file"); } save_by_copy(filename,file_); file_.close(); booster::nowide::remove(tmp_file_name_.c_str()); } #else if(booster::nowide::rename(tmp_file_name_.c_str(),filename.c_str())!=0) { save_by_copy(filename,file_); booster::nowide::remove(tmp_file_name_.c_str()); } file_.close(); #endif removed_ = 1; }
cgicc_connection &fcgi_session::get_connection() { if(!connection) { throw cppcms_error("Connection was not prepared"); } return *connection; }
sqlite (string db_name, bool sync_, int deferred_commit_count_, int deferred_commit_time_) : db(0), deferred_commit_count(deferred_commit_count_), deferred_commit_time (deferred_commit_time_) { pthread_mutex_init(&mutex,NULL); try { if(sqlite3_open(db_name.c_str(),&db)) { string error=sqlite3_errmsg(db); throw cppcms_error(error); } exec( "CREATE TABLE IF NOT EXISTS sessions ( " " sid varchar(32) primary key not null, " " data varchar(1) not null, " " timeout integer not null " ")"); exec( "CREATE INDEX IF NOT EXISTS sessions_timeout " " ON sessions(timeout)"); if(!sync_) { exec( "PRAGMA synchronous=OFF"); } write_ops=0; last_commit=time(NULL); exec("begin"); } catch(...) { if(db) sqlite3_close(db); pthread_mutex_destroy(&mutex); throw; } }
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 generate(void *ptr,unsigned len) { if(CryptGenRandom(provider_,len,static_cast<BYTE *>(ptr))) return; std::ostringstream ss; ss<<"CryptGenRandom failed with code 0x"<<std::hex<<GetLastError(); throw cppcms_error(ss.str()); }
hmac_cipher::hmac_cipher(std::string const &hash_name,crypto::key const &k) : key_(k), hash_(hash_name) { if(key_.size() < 16) { throw cppcms_error("The key legth is too small, use at leaset the key of 16 bytes/32 hexadecimal digits"); } }
void json_rpc_server::smd_from_file(std::string const &file) { booster::nowide::ifstream smd(file.c_str()); if(!smd) throw cppcms_error("Failed to open:" + file); smd_.reserve(1024); smd_.assign( std::istreambuf_iterator<char>(smd), std::istreambuf_iterator<char>()); }
void context::async_flush_output(context::handler const &h) { if(response().io_mode() != http::response::asynchronous) { throw cppcms_error("Can't use asynchronouse operations when I/O mode is synchronous"); } conn_->async_write_response( response(), false, boost::bind(wrapper,h,_1)); }
void exec(char const *s,string const &sid,string const &data,int64_t timeout) { sqlite3_stmt *st; if(sqlite3_prepare(db,s,-1,&st,NULL)!=0) { throw cppcms_error(string("sqlite prepared statement:")+sqlite3_errmsg(db)); } sqlite3_bind_text(st,1, sid.c_str(), sid.size(),SQLITE_STATIC); sqlite3_bind_blob(st,2,data.c_str(),data.size(),SQLITE_STATIC); sqlite3_bind_int64(st,3,timeout); int res; while((res=sqlite3_step(st))==SQLITE_BUSY){ poll(NULL,0,5); } if(res==SQLITE_DONE) { sqlite3_finalize(st); } else { throw cppcms_error(string("Insert error:")+sqlite3_errmsg(db)); } }
void file::save_by_copy(std::string const &file_name,std::istream &in) { booster::nowide::ofstream f(file_name.c_str(),std::ios_base::binary | std::ios_base::out); if(!f) { throw cppcms_error("Failed to save open file:"+file_name); } copy_stream(in,f); f << std::flush; f.close(); }
std::string base_encryptor::to_binary(std::string const &k) { if(k.size() % 2 != 0) { throw cppcms_error("Cipher should be encoded as hexadecimal number with even number of digits"); } std::string key(k.size()/2,0); for(unsigned i=0;i<k.size();i+=2) { char buf[3]; if(!isxdigit(k[i]) || !isxdigit(k[i+1])) { throw cppcms_error("Cipher should be encoded as hexadecimal 32 digits number"); } buf[0]=k[i]; buf[1]=k[i+1]; buf[2]=0; unsigned v; sscanf(buf,"%x",&v); key[i/2]=v; } return key; }
void urandom_device::generate(void *ptr,unsigned len) { if(len == 0) return; int n = 0; #ifndef CPPCMS_WIN32 if(impl::daemonizer::global_urandom_fd!=-1) { n = read(impl::daemonizer::global_urandom_fd,ptr,len); } else #endif { int fd = open("/dev/urandom",O_RDONLY); if(!fd) throw cppcms_error("Failed to open /dev/urandom"); n = read(fd,ptr,len); close(fd); } if(n!=int(len)) throw cppcms_error("Failed to read /dev/urandom"); }
urandom_device_impl() { if(CryptAcquireContext(&provider_,0,0,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT)) return; if(GetLastError() == (DWORD)(NTE_BAD_KEYSET)) { if(CryptAcquireContext(&provider_,0,0,PROV_RSA_FULL,CRYPT_NEWKEYSET)) return; } std::ostringstream ss; ss<<"CryptAcquireContext failed with code 0x"<<std::hex<<GetLastError(); throw cppcms_error(ss.str()); }
locked_file(session_file_storage *object,std::string sid) : h_(INVALID_HANDLE_VALUE) { name_=object->file_name(sid); int sleep_time=0; for(;;) { h_=::CreateFileW(booster::nowide::convert(name_).c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(h_==INVALID_HANDLE_VALUE) { if(GetLastError()==ERROR_ACCESS_DENIED && sleep_time<1000 ) { ::Sleep(sleep_time); sleep_time = sleep_time == 0 ? 1 : sleep_time * 2; continue; } else { std::ostringstream tmp; tmp << "Failed to open file:" + name_ + "error code " <<std::hex << ::GetLastError(); throw cppcms_error(tmp.str()); } } else break; } OVERLAPPED ov = OVERLAPPED(); if(!::LockFileEx(h_,LOCKFILE_EXCLUSIVE_LOCK,0,0,16,&ov)) { ::CloseHandle(h_); h_=INVALID_HANDLE_VALUE; throw cppcms_error("Failed to lock file:"+name_); } }
void session_file_storage::save_to_file(HANDLE h,time_t timeout,std::string const &in) { struct { int64_t timeout; uint32_t crc; uint32_t size; } tmp = { timeout, 0, in.size() }; boost::crc_32_type crc_calc; crc_calc.process_bytes(in.data(),in.size()); tmp.crc=crc_calc.checksum(); if(!write_all(h,&tmp,sizeof(tmp)) || !write_all(h,in.data(),in.size())) throw cppcms_error("Failed to write to file"); }
fcgi_api::fcgi_api(char const *socket,int backlog) { pthread_once(&init_fcgi,fcgi_api::init); if(socket && socket[0]!='\0') { fd=FCGX_OpenSocket(socket,backlog); } else { fd=0; // STDIN } if(fd<0) { throw cppcms_error(errno,"FCGX_OpenSocket"); } }
void exec(char const *s) { char *err=NULL; int res; while((res=sqlite3_exec(db,s,NULL,NULL,&err))!=0) { if(res==SQLITE_BUSY) { sqlite3_free(err); poll(NULL,0,5); continue; } string err_msg=err; sqlite3_free(err); throw cppcms_error(err_msg); } }
session_file_storage::session_file_storage(std::string path) { if(path.empty()){ if(::getenv("TEMP")) path_=std::string(::getenv("TEMP")) + "/cppcms_sessions"; else if(::getenv("TMP")) path_=std::string(::getenv("TMP")) + "/cppcms_sessions"; else path_ = "C:/TEMP"; } else path_=path; if(!::CreateDirectory(path_.c_str(),NULL)) { if(GetLastError()!=ERROR_ALREADY_EXISTS) { throw cppcms_error("Failed to create a directory for session storage " + path_); } } }
process_cache::process_cache(size_t m) : memsize(m) { pthread_mutexattr_t a; pthread_rwlockattr_t al; if( pthread_mutexattr_init(&a) || pthread_mutexattr_setpshared(&a,PTHREAD_PROCESS_SHARED) || pthread_mutex_init(&lru_mutex,&a) || pthread_mutexattr_destroy(&a) || pthread_rwlockattr_init(&al) || pthread_rwlockattr_setpshared(&al,PTHREAD_PROCESS_SHARED) || pthread_rwlock_init(&access_lock,&al) || pthread_rwlockattr_destroy(&al)) { throw cppcms_error(errno,"Failed setup mutexes --- is this system " "supports process shared mutex/rwlock?"); } };
void cookie::write(std::ostream &out) const { if(name_.empty()) throw cppcms_error("Cookie's name is not defined"); out<<"Set-Cookie:"<<name_<<'='; if(value_.empty()) { // Nothing to do write } if(protocol::tocken(value_.begin(),value_.end())==value_.end()) out<<value_; else out<<protocol::quote(value_); if(!comment_.empty()) out<<"; Comment="<<protocol::quote(comment_); if(!domain_.empty()) out<<"; Domain="<<domain_; if(has_age_ || has_expiration_) { std::locale l=std::locale::classic(); std::stringstream ss; ss.imbue(l); if(has_age_) ss<<"; Max-Age="<<max_age_; if(has_expiration_ && d.get()) { ss<<"; Expires="; std::tm splitted = booster::ptime::universal_time(booster::ptime(d->expires)); static char const format[]="%a, %d %b %Y %H:%M:%S GMT"; char const *b=format; char const *e=b+sizeof(format)-1; std::use_facet<std::time_put<char> >(l).put(ss,ss,' ',&splitted,b,e); } out << ss.rdbuf(); } if(!path_.empty()) out<<"; Path="<<path_; if(secure_) out<<"; Secure"; out<<"; Version=1"; }
session_interface::session_interface(worker_thread &w) : worker(w) { timeout_val_def=w.app.config.ival("session.timeout",24*3600); string s_how=w.app.config.sval("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=w.app.sessions(w); }
session_interface::session_interface(http::context &context) : context_(&context), loaded_(0) { timeout_val_def_=context.service().cached_settings().session.timeout; string s_how=context.service().cached_settings().session.expire; 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_cookies::session_cookies(worker_thread &w) : worker(w) { #ifdef EN_ENCR_SESSIONS string default_type="aes"; #else string default_type="hmac"; #endif string type=w.app.config.sval("session.cookies_encryptor",default_type); string key=w.app.config.sval("session.cookies_key"); if(type=="hmac") { encr.reset(new hmac::cipher(key)); return; } #ifdef EN_ENCR_SESSIONS if(type=="aes") { encr.reset(new aes::cipher(key)); return; } #endif throw cppcms_error("Unknown encryptor "+type); }
cache_pool::cache_pool(json::value const &settings) : d(new _data()) { std::string type = settings.get("cache.backend","none"); #ifndef CPPCMS_NO_CACHE if(type=="thread_shared") { if(settings.get("service.worker_processes",0)>1) throw cppcms_error( "Can't use `thread_shared' backend with more then one process ether set " "service.worker_processes to 0 or 1 or use cache.backend=\"process_shared\""); unsigned items = settings.get("cache.limit",64); d->module=impl::thread_cache_factory(items); } else if(type=="process_shared") { #if defined(CPPCMS_WIN32) throw cppcms_error("The 'process_shared' backend is not supported under MS Windows and Cygwin platforms"); #elif defined(CPPCMS_NO_PREFOK_CACHE) throw cppcms_error("The 'process_shared' backend is disabled during build procedure"); #else // has prefork cache size_t memory = settings.get("cache.memory",16384); if(memory < 64) throw cppcms_error("'process_shared' cache backend requires at least 64 KB of cache memory: cache.memory >= 64"); unsigned items = settings.get("cache.limit",memory); d->module=impl::process_cache_factory(memory*1024,items); #endif // prefork cache } else #endif // no cache if(type != "none" ) { throw cppcms_error("Unsupported cache backend `" + type + "'"); } #ifndef CPPCMS_NO_TCP_CACHE if(settings.find("cache.tcp").type()==json::is_object) { std::vector<std::string> ips=settings.get<std::vector<std::string> >("cache.tcp.ips"); std::vector<int> ports = settings.get<std::vector<int> >("cache.tcp.ports"); if(ips.empty() || ports.empty() || ips.size()!=ports.size()) { throw cppcms_error("Invalid settings in cache.tcp.ports or cache.tcp.ips"); } booster::intrusive_ptr<impl::base_cache> l1=d->module; d->module=impl::tcp_cache_factory(ips,ports,l1); } #endif // no tcp cace }