| application.h | | application.h | |
|
| | | /////////////////////////////////////////////////////////////////////////// | |
| | | //// | |
| | | // | |
| | | // Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com> | |
| | | // | |
| | | // This program is free software: you can redistribute it and/or modify | |
| | | // it under the terms of the GNU Lesser General Public License as publishe | |
| | | d by | |
| | | // the Free Software Foundation, either version 3 of the License, or | |
| | | // (at your option) any later version. | |
| | | // | |
| | | // This program is distributed in the hope that it will be useful, | |
| | | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| | | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | // GNU Lesser General Public License for more details. | |
| | | // | |
| | | // You should have received a copy of the GNU Lesser General Public Licens | |
| | | e | |
| | | // along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| | | // | |
| | | /////////////////////////////////////////////////////////////////////////// | |
| | | //// | |
| #ifndef CPPCMS_APPLICATION_H | | #ifndef CPPCMS_APPLICATION_H | |
| #define CPPCMS_APPLICATION_H | | #define CPPCMS_APPLICATION_H | |
|
| #include "worker_thread.h" | | | |
| #include "manager.h" | | #include <cppcms/defs.h> | |
| | | #include <booster/noncopyable.h> | |
| | | #include <booster/hold_ptr.h> | |
| | | #include <booster/atomic_counter.h> | |
| | | #include <booster/intrusive_ptr.h> | |
| | | #include <booster/shared_ptr.h> | |
| | | #include <string> | |
| | | | |
| namespace cppcms { | | namespace cppcms { | |
|
| | | class application; | |
| | | } | |
| | | | |
|
| struct application { | | namespace booster { | |
| | | void CPPCMS_API intrusive_ptr_add_ref(cppcms::application *p); | |
| | | void CPPCMS_API intrusive_ptr_release(cppcms::application *p); | |
| | | } | |
| | | | |
|
| // Data | | namespace cppcms { | |
| worker_thread &worker; | | | |
| url_parser &url; | | | |
| manager const &app; | | | |
| Cgicc *&cgi; | | | |
| CgiEnvironment const *&env; | | | |
| cgicc_connection *&cgi_conn; | | | |
| | | | |
|
| cache_iface &cache; | | class service; | |
| session_interface &session; | | class url_dispatcher; | |
| | | class applications_pool; | |
| | | class application; | |
| | | class base_content; | |
| | | class cache_interface; | |
| | | class session_interface; | |
| | | | |
|
| ostream &cout; | | namespace http { | |
| | | class request; | |
| | | class response; | |
| | | class context; | |
| | | } | |
| | | namespace json { | |
| | | class value; | |
| | | } | |
| | | | |
|
| boost::signal<void()> &on_start; | | /// | |
| boost::signal<void()> &on_end; | | /// \brief application class is the base class for all user created | |
| | | applications. | |
| | | /// | |
| | | /// This class is the base for all user actions required for web pag | |
| | | e generation. | |
| | | /// User application classes are created upon web page request and t | |
| | | hen cached in \a application_pool. | |
| | | /// | |
| | | /// Applications can be bundled to hierarchies. You may add a sub ap | |
| | | plication to hierarchy, | |
| | | /// and they will always be connected with topmost application and t | |
| | | heir lifetime would be binded to them. | |
| | | /// | |
| | | /// application class is reference counted and may be used with \a i | |
| | | ntrusive_ptr. But reference count | |
| | | /// semantics is very different form an ordinary semantics for other | |
| | | classes derived from \a cppcms::refcounted. | |
| | | /// | |
| | | /// 1. All hierarchy share the counter of the topmost application. | |
| | | Thus, when all bundle is counted | |
| | | /// as a single unit allowing passing intrusive_ptr to itself to | |
| | | the central service safely. | |
| | | /// When the topmost application is destroyed, it destroys all i | |
| | | ts children application classes. | |
| | | /// 2. When reference count goes to 0, the application is not destr | |
| | | oyed but rather recycled to the | |
| | | /// application pool for future use. | |
| | | /// 3. The above hold only for synchronous applications, asynchrono | |
| | | us one are destroyed when all | |
| | | /// reference count goes to 0. | |
| | | /// | |
| | | /// There two ways to add sub-applications to hierarchy: | |
| | | /// | |
| | | /// 1. Using member function family \a add, usually used with direc | |
| | | t members of the parent class. | |
| | | /// Such child are not destroyed explicitly. | |
| | | /// 2. Using member function family \a attach. The ownership on the | |
| | | application is moved to the | |
| | | /// parent class and it destroys an attached class with delete. | |
| | | /// | |
| | | | |
|
| // Construction | | class CPPCMS_API application : public booster::noncopyable { | |
| application(worker_thread &w); | | public: | |
| virtual ~application(); | | /// | |
| // API | | /// Create a new application running on service \a srv, with | |
| | | a parent \a parent | |
| | | /// | |
| | | application(cppcms::service &srv); | |
| | | | |
|
| void set_header(HTTPHeader *h) { worker.set_header(h); } | | /// | |
| void add_header(string s) { worker.add_header(s); } | | /// Destroys an application and all assigned application chi | |
| void set_cookie(cgicc::HTTPCookie const &c) { worker.set_cookie(c); | | ldren. | |
| } | | /// | |
| void set_user_io() { worker.set_user_io(); } | | virtual ~application(); | |
| void no_gzip() { worker.no_gzip(); } | | | |
| | | | |
|
| HTTPHeader &header() { return worker.header(); } | | /// | |
| | | /// Get the main service | |
| | | /// | |
| | | cppcms::service &service(); | |
| | | | |
|
| void set_lang() { worker.set_lang(); } | | /// | |
| void set_lang(string const &s) { worker.set_lang(s) ; } | | /// Get global service settings | |
| | | /// | |
| | | json::value const &settings(); | |
| | | | |
|
| void use_template(string s="") { worker.use_template(s); } | | /// | |
| | | /// Get a context of the single HTTP request/response. | |
| | | /// | |
| | | http::context &context(); | |
| | | | |
|
| void render(string n,base_content &c) { worker.render(n,c); } | | /// | |
| void render(string t,string n,base_content &c) { worker.render(t,n,c | | /// Get a HTTP request information class, same as context(). | |
| ); } | | request(); | |
| void render(string n,base_content &c,ostream &o) { worker.render(n,c | | /// | |
| ,o); } | | http::request &request(); | |
| void render(string t,string n,base_content &c,ostream &o) { worker.r | | | |
| ender(t,n,c,o); } | | | |
| | | | |
|
| virtual void on_404(); | | /// | |
| | | /// Get a HTTP response information class, same as context() | |
| | | .response(); | |
| | | /// | |
| | | http::response &response(); | |
| | | | |
|
| inline char const *gettext(char const *s) { return worker.gettext(s) | | /// | |
| ; }; | | /// Get a dispatched class -- class that responsible on mapp | |
| inline char const *ngettext(char const *s,char const *p,int n) { ret | | ing between URLs and a member | |
| urn worker.ngettext(s,p,n); } | | /// functions of application class. This member function is | |
| | | application specific and not | |
| | | /// Connection specific. | |
| | | /// | |
| | | url_dispatcher &dispatcher(); | |
| | | | |
|
| transtext::trans const *domain_gettext(string const &d) { return wor | | /// | |
| ker.domain_gettext(d); } | | /// Get a cache_interface instance. Same as context().cache( | |
| | | ); | |
| | | /// | |
| | | cache_interface &cache(); | |
| | | | |
|
| virtual void main(); | | /// | |
| | | /// Get current session_interface instance. Same as context( | |
| | | ).session(); | |
| | | /// | |
| | | session_interface &session(); | |
| | | | |
|
| template<typename SQL> | | /// | |
| void dbixx_load(SQL &sql) | | /// Render a template \a template_name of default skin using | |
| { | | content \a content. | |
| using std::string; | | /// | |
| string driver=app.config.sval("dbixx.driver"); | | /// Side effect requires: output stream for response class, | |
| sql.driver(driver); | | causes all updated session | |
| | | /// data be saved and all headers be written. You can't chan | |
| | | ge headers after calling this function. | |
| | | /// | |
| | | void render(std::string template_name,base_content &content) | |
| | | ; | |
| | | /// | |
| | | /// Render a template \a template_name of \a skin skin using | |
| | | content \a content. | |
| | | /// | |
| | | /// Side effect requires: output stream for response class, | |
| | | causes all updated session | |
| | | /// data be saved and all headers be written. You can't chan | |
| | | ge headers after calling this function. | |
| | | /// | |
| | | void render(std::string skin,std::string template_name,base_ | |
| | | content &content); | |
| | | | |
|
| cppcms_config::range_t range=app.config.prefix(driver); | | /// | |
| size_t len=driver.size()+1; | | /// Render a template \a template_name of default skin using | |
| for(cppcms_config::data_t::const_iterator p=range.first;p!=r | | content \a content to an output | |
| ange.second;++p){ | | /// stream \a out. Note: You are responsible to imbue suitab | |
| string param=p->first.substr(len); | | le locale to the stream. | |
| if(p->second.type()==typeid(string)) { | | /// | |
| string val=boost::any_cast<string>(p->second | | /// You should use context().locale() or service().generator | |
| ); | | () to create such locales. | |
| sql.param(param,val); | | /// | |
| } | | void render(std::string template_name,std::ostream &out,base | |
| else if(p->second.type()==typeid(int)) { | | _content &content); | |
| int val=boost::any_cast<int>(p->second); | | | |
| sql.param(param,val); | | | |
| } | | | |
| } | | | |
| sql.connect(); | | | |
| } | | | |
| | | | |
|
| template<typename SQL> | | /// | |
| void soci_load(SQL &sql) | | /// Render a template \a template_name of a skin \a skin usi | |
| { | | ng content \a content to an output | |
| string tmp; | | /// stream \a out. Note: You are responsible to imbue suitab | |
| if(!(tmp=app.config.sval("soci.conn","")).empty()) { | | le locale to the stream. | |
| sql.open(app.config.sval("soci.conn")); | | /// | |
| } | | /// You should use context().locale() or service().generator | |
| else { | | () to create such locales. | |
| sql.open(app.config.sval("soci.driver"),app.config.s | | /// | |
| val("soci.params")); | | void render(std::string skin,std::string template_name,std:: | |
| } | | ostream &out,base_content &content); | |
| } | | | |
| | | | |
|
| }; | | /// | |
| | | /// Register an application \a app as child. Ownership of ap | |
| | | p is not transfered to parent, however | |
| | | /// it would shared it's parent reference count. | |
| | | /// | |
| | | void add(application &app); | |
| | | | |
|
| template<typename T> | | /// | |
| class application_worker : public worker_thread { | | /// Register an application \a app as child. Ownership of ap | |
| T app; | | p is not transfered to parent, however | |
| public: | | /// it would shared it's parent reference count. | |
| application_worker(manager const &m) : | | /// | |
| worker_thread(m), | | /// All URL that match regular expression \a regex would be | |
| app(*this) | | passed to the child for match. Matched part | |
| { | | /// \a part would be used by child for matching. | |
| } | | /// | |
| virtual void main() | | /// For example: | |
| { | | /// | |
| app.main(); | | /// \code | |
| } | | /// add(users,"^/users(.*)$",1") | |
| }; | | /// \endcode | |
| | | /// | |
| | | /// For URL /users/moshe would pass only "/moshe" to URL dis | |
| | | patched of \a users object | |
| | | /// | |
| | | void add(application &app,std::string regex,int part); | |
| | | | |
|
| template<typename T> | | /// | |
| class application_factory : public simple_factory<application_worker<T> > | | /// Register an application \a app as child. Ownership of ap | |
| { | | p is transfered to parent | |
| }; | | /// | |
| | | void attach(application *app); | |
| | | /// | |
| | | /// Register an application \a app as child. Ownership of ap | |
| | | p is transfered to parent | |
| | | /// | |
| | | /// All URL that match regular expression \a regex would be | |
| | | passed to the child for match. Matched part | |
| | | /// \a part would be used by child for matching. | |
| | | /// | |
| | | /// For example: | |
| | | /// | |
| | | /// \code | |
| | | /// add(users,"^/users(.*)$",1") | |
| | | /// \endcode | |
| | | /// | |
| | | /// For URL /users/moshe would pass only "/moshe" to URL dis | |
| | | patched of \a users object | |
| | | /// | |
| | | void attach(application *app,std::string regex,int part); | |
| | | | |
|
| } | | /// | |
| | | /// Get the parent of the application, if the application is | |
| | | the topmost class in hierarchy, | |
| | | /// it would return \a this, So, if you want to check if the | |
| | | application has any parent test | |
| | | /// app->parent()!=app; | |
| | | /// | |
| | | application *parent(); | |
| | | | |
| | | /// | |
| | | /// Get the root application of the hierarchy. Note, if the | |
| | | application is the topmost one, | |
| | | /// \a this pointer would be returned | |
| | | /// | |
| | | application *root(); | |
| | | | |
| | | /// | |
| | | /// Request from an application give-up on ownership of the | |
| | | http::context class and give it | |
| | | /// to the user control. Usually it is required for processi | |
| | | ng asynchronous requests. | |
| | | /// | |
| | | /// Note: because application hierarchy shared same context, | |
| | | it affects all classes in it. | |
| | | /// | |
| | | booster::shared_ptr<http::context> release_context(); | |
| | | | |
| | | /// | |
| | | /// Get reference counted pointer to the http::context | |
| | | /// | |
| | | booster::shared_ptr<http::context> get_context(); | |
| | | | |
| | | /// | |
| | | /// Set context to the application. The application gets sha | |
| | | red ownership on the context. | |
| | | /// | |
| | | /// Note: because application hierarchy shared same context, | |
| | | it affects all classes in it. | |
| | | /// | |
| | | void assign_context(booster::shared_ptr<http::context> conn) | |
| | | ; | |
| | | | |
| | | /// | |
| | | /// Returns true if current application was created as async | |
| | | hronous application. | |
| | | /// | |
| | | bool is_asynchronous(); | |
| | | | |
| | | /// | |
| | | /// This is main function of the application that is called | |
| | | when it is matched | |
| | | /// according to the regular expression in the applications_ | |
| | | pool class. | |
| | | /// | |
| | | /// By default, main calls dispatcher().dispatch(url). And i | |
| | | f the last fails, it | |
| | | /// creates 404 Error page. This allows developers to create | |
| | | its own hooks for | |
| | | /// reaction on incoming URL as, initialization and cleanup | |
| | | of general resources, | |
| | | /// Custom 404 and error handlers etc. | |
| | | /// | |
| | | virtual void main(std::string url); | |
| | | | |
| | | private: | |
| | | | |
| | | void recycle(); | |
| | | void parent(application *parent); | |
| | | | |
| | | void pool_id(int id); | |
| | | int pool_id(); | |
| | | | |
| | | struct _data; // future use | |
| | | booster::hold_ptr<_data> d; | |
| | | | |
| | | application *parent_; | |
| | | application *root_; | |
| | | | |
| | | booster::atomic_counter refs_; | |
| | | friend class applications_pool; | |
| | | friend void booster::intrusive_ptr_add_ref(application *p); | |
| | | friend void booster::intrusive_ptr_release(application *p); | |
| | | }; | |
| | | | |
| | | } // cppcms | |
| | | | |
| #endif | | #endif | |
| | | | |
End of changes. 25 change blocks. |
| 99 lines changed or deleted | | 322 lines changed or added | |
|
| cache_interface.h | | cache_interface.h | |
|
| #ifndef CACHE_IFACE_H | | /////////////////////////////////////////////////////////////////////////// | |
| #define CACHE_IFACE_H | | //// | |
| | | // | |
| | | // Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com> | |
| | | // | |
| | | // This program is free software: you can redistribute it and/or modify | |
| | | // it under the terms of the GNU Lesser General Public License as publishe | |
| | | d by | |
| | | // the Free Software Foundation, either version 3 of the License, or | |
| | | // (at your option) any later version. | |
| | | // | |
| | | // This program is distributed in the hope that it will be useful, | |
| | | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| | | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | // GNU Lesser General Public License for more details. | |
| | | // | |
| | | // You should have received a copy of the GNU Lesser General Public Licens | |
| | | e | |
| | | // along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| | | // | |
| | | /////////////////////////////////////////////////////////////////////////// | |
| | | //// | |
| | | #ifndef CPPCMS_CACHE_INTERFACE_H | |
| | | #define CPPCMS_CACHE_INTERFACE_H | |
| | | | |
| #include <string> | | #include <string> | |
| #include <set> | | #include <set> | |
|
| #include "archive.h" | | | |
| #include "base_cache.h" | | | |
| | | | |
|
| namespace cppcms { | | #include <cppcms/defs.h> | |
| | | #include <cppcms/serialization_classes.h> | |
| | | #include <booster/noncopyable.h> | |
| | | #include <booster/intrusive_ptr.h> | |
| | | #include <booster/hold_ptr.h> | |
| | | #include <cppcms/cstdint.h> | |
| | | | |
|
| using namespace std; | | namespace cppcms { | |
| | | | |
|
| class worker_thread; | | namespace impl { | |
| class cache_iface { | | class base_cache; | |
| worker_thread *cms; | | | |
| set<string> triggers; | | | |
| public: | | | |
| void reset() { triggers.clear(); }; | | | |
| cache_iface(worker_thread *w) : cms (w) {}; | | | |
| bool fetch_page(string const &key); | | | |
| void store_page(string const &key,int timeout=-1); | | | |
| void rise(string const &trigger); | | | |
| void add_trigger(string const &trigger); | | | |
| bool fetch_frame(string const &key,string &result,bool notriggers=fa | | | |
| lse); | | | |
| void store_frame(string const &key, | | | |
| string const &frame, | | | |
| set<string> const &triggers=set<string>(), | | | |
| int timeout=-1, | | | |
| bool notriggers=false); | | | |
| void store_frame(string const &key, | | | |
| string const &frame, | | | |
| int timeout, | | | |
| bool notriggers=false) | | | |
| { | | | |
| store_frame(key,frame,set<string>(),timeout,notriggers); | | | |
| } | | | |
| bool fetch_data(string const &key,serializable &data,bool notriggers | | | |
| =false); | | | |
| void store_data(string const &key,serializable const &data, | | | |
| set<string> const &triggers=set<string>(), | | | |
| int timeout=-1,bool notriggers=false); | | | |
| void store_data(string const &key,serializable const &data,int timeo | | | |
| ut,bool notriggers=false) | | | |
| { | | | |
| store_data(key,data,set<string>(),timeout,notriggers); | | | |
| } | | } | |
|
| void clear(); | | namespace http { | |
| bool stats(unsigned &keys,unsigned &triggers); | | class context; | |
| | | }; | |
| | | | |
|
| }; | | /// | |
| | | /// \brief This class is the major gateway of the application to Cpp | |
| | | CMS caching abilities. Any access too cache | |
| | | /// would be done via this class. | |
| | | /// | |
| | | /// CppCMS cache model supports following concepts: | |
| | | /// | |
| | | /// - \a key the unique identification of the object in cache | |
| | | /// - \a timeout -- the maximal time the cached object remains valid | |
| | | /// - \a trigger -- special key that allows fast invalidation of mul | |
| | | tiple cache objects. | |
| | | /// | |
| | | /// The first two concepts are quite popular and available in most o | |
| | | f Web framework, but the last one is very | |
| | | /// unique to CppCMS that gives fine grained cache invalidation tool | |
| | | s. | |
| | | /// | |
| | | /// Each time the page is created it automatically receives some tri | |
| | | ggers during the process of creation. | |
| | | /// When some object is fetched from the cache or stored into it, it | |
| | | adds triggers to the major page. This provides | |
| | | /// semi-automatic triggers management. | |
| | | /// | |
| | | /// For example: | |
| | | /// | |
| | | /// \code | |
| | | /// if(cache().fetch_page("main_page")) | |
| | | /// return; | |
| | | /// if(!cache().fetch_frame("article_"+id,article)) { | |
| | | /// article=generate_article_from_data_base(id); | |
| | | /// cache.store_frame("article_"+id,article); | |
| | | /// } | |
| | | /// // Generate some HTML here using article | |
| | | /// cache.store_page("main"); | |
| | | /// \endcode | |
| | | /// | |
| | | /// Let's assume that "main_page" wasn't found in cache, then we try | |
| | | to fetch a frame that holds only a single | |
| | | /// article "article_123", if it is fetched, the result is stored in | |
| | | a string article and the trigger "article_123" | |
| | | /// is automatically added to set of triggers that "main_page" depen | |
| | | ds on them. | |
| | | /// | |
| | | /// When the article updated, and "article_123" key is risen, it wou | |
| | | ld automatically invalidate "main_page" as well. | |
| | | /// | |
| | | /// CppCMS cache_interface allows storing arbitrary object in cache, | |
| | | For this purpose they should be "serializable". | |
| | | /// This can be done by specializing a class cppcms::setialization_t | |
| | | raits | |
| | | /// | |
| | | | |
|
| void deflate(string const &text,ostream &stream,long level,long length); | | class CPPCMS_API cache_interface : public booster::noncopyable { | |
| string deflate(string const &text,long level,long length); | | public: | |
| | | | |
|
| class cache_factory { | | /// | |
| public: | | /// \cond INTERNAL | |
| virtual base_cache *get() const { return NULL; }; | | /// | |
| virtual void del(base_cache *p) const { }; | | /// Internal API, don't use it | |
| virtual ~cache_factory() {}; | | /// | |
| }; | | cache_interface(http::context &context); | |
| | | ~cache_interface(); | |
| | | | |
| | | /// \endcond | |
| | | | |
| | | /// | |
| | | /// Rise a trigger \a trigger. All cached objects that depen | |
| | | d on this trigger would be invalidated | |
| | | /// | |
| | | void rise(std::string const &trigger); | |
| | | | |
| | | /// | |
| | | /// Add a trigger \a trigger to the list of dependencies of | |
| | | current page. | |
| | | /// | |
| | | | |
| | | void add_trigger(std::string const &trigger); | |
| | | | |
| | | /// | |
| | | /// Clear all CppCMS cache - use carefully | |
| | | /// | |
| | | void clear(); | |
| | | | |
| | | /// | |
| | | /// Remove all triggers added to current page so far | |
| | | /// | |
| | | void reset(); | |
| | | | |
| | | /// | |
| | | /// Get statistics about items stored in cache. May require | |
| | | O(n) complexity, use with care. | |
| | | /// | |
| | | /// \param keys -- the number of items stored in cache | |
| | | /// \param triggers -- the number of various triggers existi | |
| | | ng in the cache. | |
| | | /// | |
| | | /// Returns false if caching system is disabled. | |
| | | /// | |
| | | bool stats(unsigned &keys,unsigned &triggers); | |
| | | | |
| | | /// | |
| | | /// Returns true if caching system is enabled | |
| | | /// | |
| | | bool has_cache(); | |
| | | | |
| | | /// | |
| | | /// Opposite of \a has_cache | |
| | | /// | |
| | | bool nocache(); | |
| | | | |
| | | /// | |
| | | /// Fetch a page from the cache with a key \a key. If the pa | |
| | | ge exists, it is written to output | |
| | | /// and true is returned. Otherwise false is returned. | |
| | | /// | |
| | | bool fetch_page(std::string const &key); | |
| | | | |
| | | /// | |
| | | /// Store page with key \a akey in cache, with timeout \a ti | |
| | | meout. | |
| | | /// | |
| | | /// This function stores a page with dependencies on all tri | |
| | | ggers that were added so far. | |
| | | /// | |
| | | /// \param key -- the key that defines the cache. | |
| | | /// \param timeout -- maximal valid time of the page. \a tim | |
| | | eout=-1 means infinite. Use with care. | |
| | | /// | |
| | | /// Note: store_page does not rise the trigger \a key, only | |
| | | replaces the value. | |
| | | /// | |
| | | | |
| | | void store_page(std::string const &key,int timeout=-1); | |
| | | | |
| | | /// | |
| | | /// Fetch a string (usually some HTML part) from the cache. | |
| | | /// | |
| | | /// \param key -- the key that uniquely defines the frame. | |
| | | /// \param result -- string to store fetched value | |
| | | /// \param notriggers -- if true, no triggers that a frame i | |
| | | s dependent on would be added to dependencies of | |
| | | /// the current page, otherwise (false, default), the | |
| | | all triggers that page is dependent on, including | |
| | | /// the \a key itself would be added as dependent trig | |
| | | gers to current rendered page. | |
| | | /// \return returns true if the entry was found. | |
| | | /// | |
| | | bool fetch_frame(std::string const &key,std::string &result, | |
| | | bool notriggers=false); | |
| | | | |
| | | /// | |
| | | /// Store a string (usually some HTML part) to the cache. | |
| | | /// | |
| | | /// \param key -- the key that uniquely defines the frame. | |
| | | /// \param frame -- the actual value | |
| | | /// \param triggers -- the set of triggers that the key sho | |
| | | uld depend on (\a key is added automatically) | |
| | | /// \param timeout -- maximal object lifetime, -1 is infinit | |
| | | y | |
| | | /// \param notriggers -- if \a notriggers is true no frame d | |
| | | ependent triggers would be added to the current | |
| | | /// page trigger set. Otherwise (default) current page w | |
| | | ould depend on the \a key and \a triggers as its | |
| | | /// dependent triggers. | |
| | | /// | |
| | | void store_frame(std::string const &key, | |
| | | std::string const &frame, | |
| | | std::set<std::string> const &triggers=std:: | |
| | | set<std::string>(), | |
| | | int timeout=-1, | |
| | | bool notriggers=false); | |
| | | | |
| | | /// | |
| | | /// Store a string (usually some HTML part) to the cache. | |
| | | /// | |
| | | /// \param key -- the key that uniquely defines the frame. | |
| | | /// \param frame -- the actual value | |
| | | /// \param timeout -- maximal object lifetime, -1 is infinit | |
| | | y | |
| | | /// \param notriggers -- if \a notriggers is true \a key add | |
| | | ed to the current | |
| | | /// page trigger set. Otherwise (default) current page w | |
| | | ould depend on the \a key | |
| | | /// | |
| | | void store_frame(std::string const &key, | |
| | | std::string const &frame, | |
| | | int timeout, | |
| | | bool notriggers=false); | |
| | | | |
| | | /// | |
| | | /// Fetch a serializeable object from the cache. | |
| | | /// | |
| | | /// \param key -- the key that uniquely defines the frame. | |
| | | /// \param data -- an object store fetched data | |
| | | /// \param notriggers -- if true, no triggers that an object | |
| | | is dependent on would be added to dependencies of | |
| | | /// the current page, otherwise (false, default), the | |
| | | all triggers that the object is dependent on, including | |
| | | /// the \a key itself would be added as dependent trig | |
| | | gers to current rendered page. | |
| | | /// \return returns true if the entry was found. | |
| | | /// | |
| | | template<typename Serializable> | |
| | | bool fetch_data(std::string const &key,Serializable &data,bo | |
| | | ol notriggers=false) | |
| | | { | |
| | | std::string buffer; | |
| | | if(!fetch(key,buffer,notriggers)) | |
| | | return false; | |
| | | serialization_traits<Serializable>::load(buffer,data | |
| | | ); | |
| | | return true; | |
| | | } | |
| | | /// | |
| | | /// Store a serializeable object to the cache. | |
| | | /// | |
| | | /// \param key -- the key that uniquely defines the object. | |
| | | /// \param data -- the actual object | |
| | | /// \param triggers -- the set of triggers that the key sho | |
| | | uld depend on (\a key is added automatically) | |
| | | /// \param timeout -- maximal object lifetime, -1 is infinit | |
| | | y | |
| | | /// \param notriggers -- if \a notriggers is true no frame d | |
| | | ependent triggers would be added to the current | |
| | | /// page trigger set. Otherwise (default) current page w | |
| | | ould depend on the \a key and \a triggers as its | |
| | | /// dependent triggers. | |
| | | /// | |
| | | | |
| | | template<typename Serializable> | |
| | | void store_data(std::string const &key,Serializable const &d | |
| | | ata, | |
| | | std::set<std::string> const &triggers=std::s | |
| | | et<std::string>(), | |
| | | int timeout=-1,bool notriggers=false) | |
| | | { | |
| | | std::string buffer; | |
| | | serialization_traits<Serializable>::save(data,buffer | |
| | | ); | |
| | | store(key,buffer,triggers,timeout,notriggers); | |
| | | } | |
| | | | |
| | | /// | |
| | | /// Store a serializeable object to the cache. | |
| | | /// | |
| | | /// \param key -- the key that uniquely defines the object. | |
| | | /// \param data -- the actual object | |
| | | /// \param timeout -- maximal object lifetime, -1 is infinit | |
| | | y | |
| | | /// \param notriggers -- if \a notriggers is true \a key add | |
| | | ed to the current | |
| | | /// page trigger set. Otherwise (default) current page w | |
| | | ould depend on the \a key | |
| | | /// | |
| | | | |
| | | template<typename Serializable> | |
| | | void store_data(std::string const &key,Serializable const &d | |
| | | ata,int timeout,bool notriggers=false) | |
| | | { | |
| | | store_data<Serializable>(key,data,std::set<std::stri | |
| | | ng>(),timeout,notriggers); | |
| | | } | |
| | | | |
| | | private: | |
| | | | |
| | | void store( std::string const &key, | |
| | | std::string const &data, | |
| | | std::set<std::string> const &triggers, | |
| | | int timeout, | |
| | | bool notriggers); | |
| | | | |
| | | bool fetch( std::string const &key, | |
| | | std::string &buffer, | |
| | | bool notriggers); | |
| | | | |
| | | struct _data; | |
| | | booster::hold_ptr<_data> d; | |
| | | http::context *context_; | |
| | | std::set<std::string> triggers_; | |
| | | booster::intrusive_ptr<impl::base_cache> cache_module_; | |
| | | | |
| | | uint32_t page_compression_used_ : 1; | |
| | | uint32_t reserved : 31; | |
| | | }; | |
| | | | |
| } | | } | |
| | | | |
| #endif | | #endif | |
| | | | |
End of changes. 9 change blocks. |
| 51 lines changed or deleted | | 318 lines changed or added | |
|
| form.h | | form.h | |
|
| | | /////////////////////////////////////////////////////////////////////////// | |
| | | //// | |
| | | // | |
| | | // Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com> | |
| | | // | |
| | | // This program is free software: you can redistribute it and/or modify | |
| | | // it under the terms of the GNU Lesser General Public License as publishe | |
| | | d by | |
| | | // the Free Software Foundation, either version 3 of the License, or | |
| | | // (at your option) any later version. | |
| | | // | |
| | | // This program is distributed in the hope that it will be useful, | |
| | | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| | | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | // GNU Lesser General Public License for more details. | |
| | | // | |
| | | // You should have received a copy of the GNU Lesser General Public Licens | |
| | | e | |
| | | // along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| | | // | |
| | | /////////////////////////////////////////////////////////////////////////// | |
| | | //// | |
| #ifndef CPPCMS_FORM_H | | #ifndef CPPCMS_FORM_H | |
| #define CPPCMS_FORM_H | | #define CPPCMS_FORM_H | |
|
| | | | |
| | | #include <cppcms/defs.h> | |
| | | #include <booster/noncopyable.h> | |
| | | | |
| #include <string> | | #include <string> | |
| #include <set> | | #include <set> | |
| #include <map> | | #include <map> | |
| #include <list> | | #include <list> | |
| #include <vector> | | #include <vector> | |
|
| #include <boost/regex_fwd.hpp> | | #include <stack> | |
| #include <boost/noncopyable.hpp> | | | |
| #include <ostream> | | #include <ostream> | |
| #include <sstream> | | #include <sstream> | |
|
| | | #include <cppcms/http_context.h> | |
| namespace cgicc { class Cgicc; } | | #include <cppcms/http_request.h> | |
| | | #include <cppcms/http_response.h> | |
| | | #include <booster/copy_ptr.h> | |
| | | #include <booster/perl_regex.h> | |
| | | #include <booster/shared_ptr.h> | |
| | | #include <cppcms/cppcms_error.h> | |
| | | #include <cppcms/util.h> | |
| | | #include <cppcms/localization.h> | |
| | | | |
| namespace cppcms { | | namespace cppcms { | |
|
| using namespace std; | | | |
| class base_form { | | | |
| public: | | | |
| virtual ~base_form(); | | | |
| enum { as_html = 0, | | | |
| as_xhtml= 1, | | | |
| as_p = 0, | | | |
| as_table= 1<<1, | | | |
| as_ul = 2<<1, | | | |
| as_dl = 3<<1, | | | |
| as_space= 4<<1, | | | |
| as_mask = 7<<1, | | | |
| error_with = 0, | | | |
| error_no = 0x10, | | | |
| error_mask = 0x10, }; | | | |
| | | | |
|
| virtual string render(int how) = 0; | | namespace http { | |
| virtual void load(cgicc::Cgicc const &cgi) = 0; | | class file; | |
| inline void load(cgicc::Cgicc const *cgi) { if(cgi) load(*cgi); } | | } | |
| virtual bool validate() = 0; | | | |
| virtual void clear() = 0; | | | |
| }; | | | |
| | | | |
|
| class form : public boost::noncopyable , public base_form { | | namespace widgets { | |
| protected: | | class base_widget; | |
| list<base_form *> elements; | | } | |
| public: | | | |
| void append(base_form *ptr); | | | |
| inline form &operator & (base_form &f) { append(&f); return *this; } | | | |
| virtual string render(int how); | | | |
| virtual void load(cgicc::Cgicc const &cgi); | | | |
| virtual bool validate(); | | | |
| virtual void clear(); | | | |
| }; | | | |
| | | | |
|
| namespace widgets { | | /// | |
| | | /// \brief this struct holds various flags for HTML generation contr | |
| | | ol | |
| | | /// | |
| | | struct form_flags { | |
| | | /// | |
| | | /// This enum represents HTML/XHTML switch | |
| | | /// | |
| | | typedef enum { | |
| | | as_html = 0, ///< render form/widget as ordinary | |
| | | HTML | |
| | | as_xhtml= 1, ///< render form/widget as XHTML | |
| | | } html_type; | |
| | | | |
|
| class base_widget : public base_form { | | /// | |
| public: | | /// This enum represents the style of widgets generation | |
| bool is_set; | | /// | |
| base_widget(string name="",string msg=""); | | typedef enum { | |
| string id; | | as_p = 0 , ///< Render each widget using paragrap | |
| string name; | | hs | |
| string msg; | | as_table= 1 , ///< Render each widget using table | |
| string error_msg; | | as_ul = 2 , ///< Render each widget using unordere | |
| string help; | | d list | |
| bool is_valid; | | as_dl = 3 , ///< Render each widget using definiti | |
| virtual string render(int how); | | ons list | |
| virtual string render_input(int ) = 0; | | as_space= 4 ///< Render each widget using simple b | |
| virtual string render_error(); | | lank space separators | |
| virtual void clear(); | | } html_list_type; | |
| virtual bool validate(); | | | |
| void not_valid() { is_valid=false; } | | | |
| }; | | | |
| | | | |
|
| class text : public base_widget { | | /// | |
| protected: | | /// This is special flag for partial generation of widget's | |
| string type; | | HTML | |
| unsigned low; | | /// | |
| int high; | | typedef enum { | |
| public: | | first_part = 0, ///< Render part 1; HTML attributes | |
| string value; | | can be inserted after it | |
| text(string name="",string msg="") : base_widget(name,msg) , type("t | | second_part = 1 ///< Render part 2 -- compete part | |
| ext"){ low=0,high=-1; }; | | 1. | |
| void set_limits(int min,int max) { low=min,high=max; } | | } widget_part_type; | |
| void set_nonempty() { low = 1, high=-1;}; | | }; | |
| void set_limits(string e,int min,int max) { error_msg=e; set_limits( | | | |
| min,max); } | | | |
| void set_nonempty(string e){ error_msg=e; set_nonempty(); }; | | | |
| virtual string render_input(int how); | | | |
| void set(string const &s); | | | |
| string &str(); | | | |
| string const &get(); | | | |
| virtual bool validate(); | | | |
| virtual void load(cgicc::Cgicc const &cgi); | | | |
| }; | | | |
| | | | |
|
| template<typename T> | | /// | |
| class number: public text { | | /// \brief This class represent the context required for generation | |
| T min,max,value; | | of HTML for the widgets | |
| bool check_low,check_high; | | /// | |
| public: | | class CPPCMS_API form_context : public form_flags | |
| number(string name="",string msg="") : | | | |
| text(name,msg), | | | |
| value(0),check_low(false),check_high(false) | | | |
| {}; | | | |
| void set_low(T a) | | | |
| { | | | |
| min=a; | | | |
| check_low=true; | | | |
| set_nonempty(); | | | |
| } | | | |
| void set_high(T b) | | | |
| { | | | |
| max=b; | | | |
| check_high=true; | | | |
| set_nonempty(); | | | |
| } | | | |
| void set_range(T a,T b) | | | |
| { | | { | |
|
| min=a; max=b; | | public: | |
| check_low=check_high=true; | | /// | |
| set_nonempty(); | | /// Default constructor | |
| } | | /// | |
| virtual bool validate() | | form_context(); | |
| | | /// | |
| | | /// Copy-constructor | |
| | | /// | |
| | | form_context(form_context const &other); | |
| | | /// | |
| | | /// Assignment | |
| | | /// | |
| | | form_context const &operator = (form_context const &other); | |
| | | /// | |
| | | /// Create a rendering context | |
| | | /// | |
| | | /// \param output the output std::ostream to write HTML to | |
| | | /// \param ht flags representing the type of HTML that shoul | |
| | | d be generated | |
| | | /// \param hlt flag that defines the style of widgets genera | |
| | | tion | |
| | | /// | |
| | | form_context( std::ostream &output, | |
| | | html_type ht = form_flags::as_html, | |
| | | html_list_type hlt=form_flags::as_p); | |
| | | /// | |
| | | /// Destructor | |
| | | /// | |
| | | ~form_context(); | |
| | | | |
| | | /// | |
| | | /// Set an HTML/XHTML flag | |
| | | /// | |
| | | void html(html_type t); | |
| | | /// | |
| | | /// Set widgets rendering style | |
| | | /// | |
| | | void html_list(html_list_type t); | |
| | | /// | |
| | | /// Set flag for rendering of partial widget | |
| | | /// | |
| | | void widget_part(widget_part_type t); | |
| | | | |
| | | /// | |
| | | /// Set the output stream | |
| | | /// | |
| | | void out(std::ostream &out); | |
| | | | |
| | | /// | |
| | | /// Set an HTML/XHTML flag - default as_html | |
| | | /// | |
| | | html_type html() const; | |
| | | /// | |
| | | /// Get widgets rendering style - default as_p | |
| | | /// | |
| | | html_list_type html_list() const; | |
| | | /// | |
| | | /// Get the part of widget that should be generated, see wid | |
| | | get_part_type, default first_part | |
| | | /// | |
| | | widget_part_type widget_part() const; | |
| | | /// | |
| | | /// Get the output stream | |
| | | /// | |
| | | std::ostream &out() const; | |
| | | | |
| | | private: | |
| | | uint32_t html_type_; | |
| | | uint32_t html_list_type_; | |
| | | uint32_t widget_part_type_; | |
| | | std::ostream *output_; | |
| | | uint32_t reserved_1; | |
| | | uint32_t reserved_2; | |
| | | struct _data; | |
| | | booster::hold_ptr<_data> d; | |
| | | | |
| | | }; | |
| | | | |
| | | /// | |
| | | /// \brief This class is base class of any form or form-widget used | |
| | | in CppCMS. | |
| | | /// | |
| | | /// It provides abstract basic operations that every widget or form | |
| | | should implement | |
| | | /// | |
| | | | |
| | | class CPPCMS_API base_form : public form_flags { | |
| | | public: | |
| | | | |
| | | /// | |
| | | /// Render the widget to std::ostream \a output with control | |
| | | flags \a flags. | |
| | | /// Usually this function is called directly by template ren | |
| | | dering functions | |
| | | /// | |
| | | | |
| | | virtual void render(form_context &context) = 0; | |
| | | | |
| | | /// | |
| | | /// Load the information of form from the provided http::con | |
| | | text \a context. | |
| | | /// User calls this function for loading all information fro | |
| | | m the raw POST/GET | |
| | | /// form to internal widget representation. | |
| | | /// | |
| | | | |
| | | virtual void load(http::context &context) = 0; | |
| | | | |
| | | /// | |
| | | /// Validate the form according to defined rules. If all che | |
| | | cks are OK | |
| | | /// true is returned. If some widget or form fails, false is | |
| | | returned. | |
| | | /// | |
| | | | |
| | | virtual bool validate() = 0; | |
| | | | |
| | | /// | |
| | | /// Clear the form from all user provided data. | |
| | | /// | |
| | | virtual void clear() = 0; | |
| | | | |
| | | /// | |
| | | /// Set parent of this form. Used internaly, should not be u | |
| | | sed | |
| | | /// | |
| | | | |
| | | virtual void parent(base_form *subform) = 0; | |
| | | | |
| | | /// | |
| | | /// Get parent of this form. If this is topmost form, NULL i | |
| | | s returned | |
| | | /// | |
| | | virtual base_form *parent() = 0; | |
| | | | |
| | | base_form(); | |
| | | virtual ~base_form(); | |
| | | }; | |
| | | | |
| | | /// | |
| | | /// \brief The \a form is a container that used to collect other wid | |
| | | gets and forms to single unit | |
| | | /// | |
| | | /// Generally various widgets and forms are combined into single for | |
| | | m in order to simplify rendering | |
| | | /// and validation of forms that include more then one widget | |
| | | /// | |
| | | | |
| | | class CPPCMS_API form : public booster::noncopyable, | |
| | | public base_form | |
| { | | { | |
|
| if(!text::validate()) | | public: | |
| return false; | | | |
| if(!str().empty()) { | | form(); | |
| std::istringstream ss(str()); | | virtual ~form(); | |
| ss>>value; | | | |
| if(ss.fail() || !ss.eof()) | | /// | |
| is_valid=false; | | /// Render all widgets and sub-forms to \a output, using | |
| | | /// base_form \a flags | |
| | | /// | |
| | | | |
| | | virtual void render(form_context &context); | |
| | | | |
| | | /// | |
| | | /// Load all information from widgets from http::context \a | |
| | | cont | |
| | | /// | |
| | | virtual void load(http::context &cont); | |
| | | | |
| | | /// | |
| | | /// validate all subforms and widgets. If at least one of th | |
| | | em fails, | |
| | | /// false is returned. Otherwise, true is returned. | |
| | | /// | |
| | | | |
| | | virtual bool validate(); | |
| | | | |
| | | /// | |
| | | /// Clear all subforms and widgets for all loaded data. | |
| | | /// | |
| | | virtual void clear(); | |
| | | | |
| | | /// | |
| | | /// adds \a subform to form, the ownership is not transferre | |
| | | d to | |
| | | /// to the parent | |
| | | /// | |
| | | | |
| | | void add(form &subform); | |
| | | | |
| | | /// | |
| | | /// add \a subform to form, the ownership is transferred to | |
| | | /// the parent and subform will be destroyed together with | |
| | | /// the parent | |
| | | /// | |
| | | | |
| | | void attach(form *subform); | |
| | | | |
| | | /// | |
| | | /// adds \a widget to form, the ownership is not transferred | |
| | | to | |
| | | /// to the parent | |
| | | /// | |
| | | | |
| | | void add(widgets::base_widget &widget); | |
| | | | |
| | | /// | |
| | | /// add \a widget to form, the ownership is transferred to | |
| | | /// the parent the widget will be destroyed together with | |
| | | /// the parent form | |
| | | /// | |
| | | | |
| | | void attach(widgets::base_widget *widget); | |
| | | | |
| | | /// | |
| | | /// Shortcut to \a add | |
| | | /// | |
| | | inline form &operator + (form &f) | |
| | | { | |
| | | add(f); | |
| | | return *this; | |
| } | | } | |
|
| if((check_low || check_high) && str().empty()) | | | |
| return (is_valid=false); | | | |
| if(check_low && value<min) | | | |
| return (is_valid=false); | | | |
| if(check_high && value>max) | | | |
| return (is_valid=false); | | | |
| return (is_valid=true); | | | |
| } | | | |
| T get() const { return value; }; | | | |
| void set(T v) | | | |
| { | | | |
| value=v; | | | |
| std::ostringstream ss; | | | |
| ss<<v; | | | |
| text::set(ss.str()); | | | |
| } | | | |
| }; | | | |
| | | | |
|
| class password: public text { | | /// | |
| password *other; | | /// Shortcut to \a add | |
| public: | | /// | |
| password(string name="",string msg="") : text(name,msg),other(0) {} | | inline form &operator + (widgets::base_widget &f) | |
| ; | | { | |
| void set_equal(password &p2) { other=&p2; } ; | | add(f); | |
| virtual bool validate(); | | return *this; | |
| virtual string render_input(int how); | | } | |
| }; | | /// | |
| class textarea: public text { | | /// Set parent of this form. Used internaly, should not be u | |
| public: | | sed. It is called | |
| int rows,cols; | | /// when the form is added or attached to other form. | |
| textarea(string name="",string msg="") : text(name,msg) { rows=cols= | | /// | |
| -1; }; | | | |
| virtual string render_input(int how); | | | |
| }; | | | |
| | | | |
|
| class regex_field : public text { | | virtual void parent(base_form *subform); | |
| boost::regex const *exp; | | | |
| public: | | | |
| regex_field() : exp(0) {} | | | |
| regex_field(boost::regex const &e,string name="",string msg="") : te | | | |
| xt(name,msg),exp(&e) {} | | | |
| virtual bool validate(); | | | |
| }; | | | |
| | | | |
|
| class email : public regex_field { | | /// | |
| public: | | /// Get parent of this form. If this is topmost form, NULL i | |
| email(string name="",string msg=""); | | s returned | |
| }; | | /// It is assumed that the parent is always form. | |
| | | /// | |
| | | virtual form *parent(); | |
| | | | |
|
| class checkbox: public base_widget { | | /// | |
| public: | | /// \brief Input iterator that is used to iterate over all w | |
| string input_value; | | idgets of the form | |
| bool value; | | /// | |
| checkbox(string name="",string msg="") : base_widget(name,msg),input | | /// This class is mainly used by templates framework for wid | |
| _value("1") | | gets rendering. It | |
| { | | /// walks on all widgets and subforms recursively. | |
| set(false); | | /// | |
| }; | | /// Note: it walks over widgets only: | |
| virtual string render_input(int how); | | /// | |
| void set(bool v) { value=v; is_set=true; }; | | /// \code | |
| void set(string const &s) { input_value=s; }; | | /// iterator p=f.begin(); | |
| bool get() { return value; }; | | /// if(p!=f.end()) | |
| virtual void load(cgicc::Cgicc const &cgi); | | /// if p!=f.end() --> *p is derived from widgets::base_wid | |
| }; | | get. | |
| | | /// \endcode | |
| | | /// | |
| | | | |
|
| class select_multiple : public base_widget { | | class CPPCMS_API iterator : public std::iterator<std::input_ | |
| int min; | | iterator_tag,widgets::base_widget> | |
| public: | | { | |
| int size; | | public: | |
| select_multiple(string name="",int s=0,string msg="") : base_widget( | | /// | |
| name,msg),min(-1),size(s) {}; | | /// End iterator | |
| set<string> chosen; | | /// | |
| map<string,string> available; | | | |
| void add(string val,string opt,bool selected=false); | | | |
| void add(int val,string opt,bool selected=false); | | | |
| void add(string v,bool s=false) { add(v,v,s); } | | | |
| void add(int v,bool s=false) { | | | |
| ostringstream ss; | | | |
| ss<<v; | | | |
| add(v,ss.str(),s); | | | |
| } | | | |
| set<string> &get() { return chosen; }; | | | |
| set<int> geti(); | | | |
| void set_min(int n) { min=n; }; | | | |
| virtual string render_input(int how); | | | |
| virtual bool validate(); | | | |
| virtual void load(cgicc::Cgicc const &cgi); | | | |
| virtual void clear(); | | | |
| }; | | | |
| | | | |
|
| class select_base : public base_widget { | | iterator(); | |
| public: | | | |
| string value; | | /// | |
| struct option { | | /// Create widgets iterator | |
| string value; | | /// | |
| string option; | | iterator(form &); | |
| | | | |
| | | /// | |
| | | /// Destructor | |
| | | /// | |
| | | ~iterator(); | |
| | | | |
| | | /// | |
| | | /// Copy the iterator, this is not cheap operation. | |
| | | /// | |
| | | | |
| | | iterator(iterator const &other); | |
| | | /// | |
| | | /// Assign the iterator, this is not cheap operation | |
| | | . | |
| | | /// | |
| | | iterator const &operator = (iterator const &other); | |
| | | | |
| | | /// | |
| | | /// Returns the underlying widget. Condition: *this! | |
| | | =iterator() | |
| | | /// | |
| | | widgets::base_widget *operator->() const | |
| | | { | |
| | | return get(); | |
| | | } | |
| | | | |
| | | /// | |
| | | /// Returns the underlying widget. Condition: *this! | |
| | | =iterator() | |
| | | /// | |
| | | widgets::base_widget &operator*() const | |
| | | { | |
| | | return *get(); | |
| | | } | |
| | | | |
| | | /// | |
| | | /// Check if two iterators pointing to same element | |
| | | /// | |
| | | bool operator==(iterator const &other) const | |
| | | { | |
| | | return equal(other); | |
| | | } | |
| | | /// | |
| | | /// Check if two iterators pointing to different ele | |
| | | ment | |
| | | /// | |
| | | bool operator!=(iterator const &other) const | |
| | | { | |
| | | return !equal(other); | |
| | | } | |
| | | | |
| | | /// | |
| | | /// Post Increment operator, it forward the iterator | |
| | | no text widget. | |
| | | /// Note it does not point to higher level form cont | |
| | | ainer. | |
| | | /// | |
| | | /// Note: prefer using ++i then i++ as copying itera | |
| | | tor is not cheap. | |
| | | /// | |
| | | iterator operator++(int unused) | |
| | | { | |
| | | iterator tmp(*this); | |
| | | next(); | |
| | | return tmp; | |
| | | } | |
| | | /// | |
| | | /// Increment operator. It forward the iterator no t | |
| | | ext widget. | |
| | | /// Note it does not point to higher level form cont | |
| | | ainer | |
| | | /// | |
| | | iterator &operator++() | |
| | | { | |
| | | next(); | |
| | | return *this; | |
| | | } | |
| | | | |
| | | private: | |
| | | | |
| | | friend class form; | |
| | | | |
| | | bool equal(iterator const &other) const; | |
| | | void zero(); | |
| | | void next(); | |
| | | widgets::base_widget *get() const; | |
| | | | |
| | | std::stack<unsigned> return_positions_; | |
| | | form *current_; | |
| | | unsigned offset_; | |
| | | struct _data; | |
| | | booster::copy_ptr<_data> d; | |
| | | | |
| | | }; | |
| | | | |
| | | /// | |
| | | /// Returns an iterator to the first widget. | |
| | | /// | |
| | | iterator begin(); | |
| | | | |
| | | /// | |
| | | /// Returns the end-iterator for walking over all widgets. | |
| | | /// | |
| | | iterator end(); | |
| | | | |
| | | private: | |
| | | friend class iterator; | |
| | | | |
| | | struct _data; | |
| | | // Widget and ownership true mine | |
| | | typedef std::pair<base_form *,bool> widget_type; | |
| | | std::vector<widget_type> elements_; | |
| | | form *parent_; | |
| | | booster::hold_ptr<_data> d; | |
| }; | | }; | |
|
| list<option> select_list; | | | |
| select_base(string name="",string msg="") : base_widget(name,msg){}; | | | |
| void add(string value,string option); | | | |
| void add(string v) { add(v,v); } | | | |
| void add(int value,string option); | | | |
| void add(int v) { | | | |
| ostringstream ss; | | | |
| ss<<v; | | | |
| add(v,ss.str()); | | | |
| } | | | |
| void set(string value); | | | |
| void set(int value); | | | |
| string get(); | | | |
| int geti(); | | | |
| virtual bool validate(); | | | |
| virtual void load(cgicc::Cgicc const &cgi); | | | |
| }; | | | |
| | | | |
|
| class select : public select_base { | | /// | |
| int size; | | /// \brief This namespace includes all widgets (html-forms) supporte | |
| public: | | d by cppcms | |
| select(string n="",string m="") : select_base(n,m),size(-1) {}; | | /// | |
| void set_size(int n) { size=n;} | | namespace widgets { | |
| virtual string render_input(int how); | | | |
| }; | | | |
| | | | |
|
| class radio : public select_base { | | /// | |
| bool add_br; | | /// \brief this class is the base class of all renderable wi | |
| public: | | dgets that can be | |
| radio(string name="",string msg="") : select_base(name,msg),add_br(f | | /// used together with forms | |
| alse) {} | | /// | |
| void set_vertical() { add_br=true; } | | /// All cppcms widgets are derived from this class. User, wh | |
| virtual string render_input(int how); | | o want to create | |
| }; | | /// its own custom widgets must derive them from this class | |
| | | /// | |
| | | | |
|
| class hidden : public text { | | class CPPCMS_API base_widget : | |
| public: | | public base_form, | |
| hidden(string n="",string msg="") : text(n,msg) { set_nonempty(); }; | | public booster::noncopyable | |
| virtual string render(int how); | | { | |
| }; | | public: | |
| | | | |
|
| class submit : public base_widget { | | /// | |
| public: | | /// Default constructor | |
| string value; | | /// | |
| bool pressed; | | base_widget(); | |
| submit(string name="",string button="",string msg="") : base_widget( | | | |
| name,msg), value(button),pressed(false) {}; | | | |
| virtual string render_input(int); | | | |
| virtual void load(cgicc::Cgicc const &cgi); | | | |
| }; | | | |
| | | | |
|
| } // widgets | | virtual ~base_widget(); | |
| | | | |
|
| class widgetset { | | /// | |
| public: | | /// Check if a value was assigned to widget. Usually | |
| typedef vector<widgets::base_widget*> widgets_t; | | becomes true | |
| widgets_t widgets; | | /// when user assignees value to widget or the widge | |
| inline widgetset &operator<<(widgets::base_widget &w) { widgets.push | | t is loaded. | |
| _back(&w); return *this; } | | /// | |
| widgetset(); | | bool set(); | |
| virtual string render(int how); | | | |
| virtual ~widgetset(); | | /// | |
| }; | | /// After executing validation, each widget can be t | |
| | | ested for validity | |
| | | /// | |
| | | bool valid(); | |
| | | | |
| | | /// | |
| | | /// Get html id attribute | |
| | | /// | |
| | | std::string id(); | |
| | | | |
| | | /// | |
| | | /// Get html name attribute | |
| | | /// | |
| | | std::string name(); | |
| | | | |
| | | /// | |
| | | /// Get short message that would be displayed near t | |
| | | he widget | |
| | | /// | |
| | | locale::message message(); | |
| | | | |
| | | /// | |
| | | /// Check if message is set | |
| | | /// | |
| | | bool has_message(); | |
| | | | |
| | | /// | |
| | | /// Get associated error message that would be displ | |
| | | ayed near the widget | |
| | | /// if widget validation failed. | |
| | | /// | |
| | | locale::message error_message(); | |
| | | | |
| | | /// | |
| | | /// Check if error message is set | |
| | | /// | |
| | | | |
| | | bool has_error_message(); | |
| | | | |
| | | /// | |
| | | /// Get long description for specific widget | |
| | | /// | |
| | | | |
| | | locale::message help(); | |
| | | | |
| | | /// | |
| | | /// Check if help message is set | |
| | | /// | |
| | | | |
| | | bool has_help(); | |
| | | | |
| | | /// | |
| | | /// Get disabled html attribute | |
| | | /// | |
| | | | |
| | | bool disabled(); | |
| | | | |
| | | /// | |
| | | /// Set/Unset disabled html attribute | |
| | | /// | |
| | | | |
| | | void disabled(bool); | |
| | | | |
| | | /// | |
| | | /// Get the general user defined attributes string t | |
| | | hat can be added to widget | |
| | | /// | |
| | | std::string attributes_string(); | |
| | | | |
| | | /// | |
| | | /// Set the existence of content for widget. By defa | |
| | | ult the widget is not set. | |
| | | /// Any value fetch from "unset" widget by conventio | |
| | | n should throw an exception | |
| | | /// Calling set with true -- changes state to "set" | |
| | | and with false to "unset" | |
| | | /// | |
| | | | |
| | | void set(bool); | |
| | | | |
| | | /// | |
| | | /// Set validity state of widget. By default the wid | |
| | | get is valid. When it | |
| | | /// passes validation its validity state is changed | |
| | | by calling this function | |
| | | /// | |
| | | /// Note: widget maybe not-set but still valid and i | |
| | | t may be set but not-valid | |
| | | /// | |
| | | | |
| | | void valid(bool); | |
| | | | |
| | | /// | |
| | | /// Set html id attribute of the widget | |
| | | /// | |
| | | void id(std::string); | |
| | | | |
| | | /// | |
| | | /// Set html name attribute of the widget. Note: if | |
| | | this attribute | |
| | | /// is not set, the widget would not be able to be l | |
| | | oaded from POST/GET | |
| | | /// data. | |
| | | /// | |
| | | | |
| | | void name(std::string); | |
| | | | |
| | | /// | |
| | | /// Set short description for the widget. Generally | |
| | | it is good idea to | |
| | | /// define this value. | |
| | | /// | |
| | | /// Short message can be also set using base_widget | |
| | | constructor | |
| | | /// | |
| | | void message(std::string); | |
| | | | |
| | | /// | |
| | | /// Set short translatable description for the widge | |
| | | t. Generally it is good idea to | |
| | | /// define this value. | |
| | | /// | |
| | | /// Short message can be also set using base_widget | |
| | | constructor | |
| | | /// | |
| | | void message(locale::message const &); | |
| | | | |
| | | /// | |
| | | /// Set error message that is displayed for invalid | |
| | | widgets. | |
| | | /// | |
| | | /// If it is not set, simple "*" is shown | |
| | | /// | |
| | | void error_message(std::string); | |
| | | | |
| | | /// | |
| | | /// Set translatable error message that is displayed | |
| | | for invalid widgets. | |
| | | /// | |
| | | /// If it is not set, simple "*" is shown | |
| | | /// | |
| | | void error_message(locale::message const &); | |
| | | | |
| | | /// | |
| | | /// Set longer help message that describes this widg | |
| | | et | |
| | | /// | |
| | | void help(std::string); | |
| | | | |
| | | /// | |
| | | /// Set translatable help message that describes thi | |
| | | s widget | |
| | | /// | |
| | | void help(locale::message const &msg); | |
| | | | |
| | | /// | |
| | | /// Set general html attributes that are not support | |
| | | ed | |
| | | /// directly. For example: | |
| | | /// | |
| | | /// \code | |
| | | /// my_widget.attributes_string("style='direction:r | |
| | | tl' onclick='return foo()'"); | |
| | | /// \endcode | |
| | | /// | |
| | | /// This string is inserted as-is just behind render | |
| | | _input_start | |
| | | /// | |
| | | void attributes_string(std::string v); | |
| | | | |
| | | /// | |
| | | /// Render full widget with error messages and decor | |
| | | ations as paragraphs | |
| | | /// or table elements to \a output | |
| | | /// | |
| | | | |
| | | virtual void render(form_context &context); | |
| | | | |
| | | /// | |
| | | /// This is a virtual member function that should be | |
| | | implemented by each widget | |
| | | /// It executes actual rendering of the input HTML f | |
| | | orm | |
| | | /// | |
| | | virtual void render_input(form_context &context) = 0 | |
| | | ; | |
| | | | |
| | | /// | |
| | | /// Clean the form. Calls set(false) as well | |
| | | /// | |
| | | virtual void clear(); | |
| | | | |
| | | /// | |
| | | /// Validate form. If not overridden it sets widget | |
| | | to valid | |
| | | /// | |
| | | virtual bool validate(); | |
| | | | |
| | | /// | |
| | | /// Render standard common attributes like id, name, | |
| | | disabled etc. | |
| | | /// | |
| | | | |
| | | virtual void render_attributes(form_context &context | |
| | | ); | |
| | | | |
| | | /// | |
| | | /// Set parent of this widget. Used internaly, shoul | |
| | | d not be used. It is called | |
| | | /// when the form is added or attached to other form | |
| | | . | |
| | | /// | |
| | | | |
| | | virtual void parent(base_form *subform); | |
| | | | |
| | | /// | |
| | | /// Get parent of this form. If this is topmost form | |
| | | , NULL is returned | |
| | | /// Note widget is assumed to be assigned to forms o | |
| | | nly | |
| | | /// | |
| | | virtual form *parent(); | |
| | | | |
| | | protected: | |
| | | /// | |
| | | /// This function should be called by overloaded loa | |
| | | d/render methods | |
| | | /// before rendering/loading starts | |
| | | /// | |
| | | void auto_generate(form_context *context = 0); | |
| | | private: | |
| | | | |
| | | void generate(int position,form_context *context = 0 | |
| | | ); | |
| | | | |
| | | std::string id_; | |
| | | std::string name_; | |
| | | locale::message message_; | |
| | | locale::message error_message_; | |
| | | locale::message help_; | |
| | | std::string attr_; | |
| | | form *parent_; | |
| | | | |
| | | uint32_t is_valid_ : 1; | |
| | | uint32_t is_set_ : 1; | |
| | | uint32_t is_disabled_ : 1; | |
| | | uint32_t is_generation_done_ : 1; | |
| | | uint32_t has_message_ : 1; | |
| | | uint32_t has_error_ : 1; | |
| | | uint32_t has_help_ : 1; | |
| | | uint32_t reserverd_ : 25; | |
| | | | |
| | | struct _data; | |
| | | booster::hold_ptr<_data> d; | |
| | | }; | |
| | | | |
| | | /// | |
| | | /// \brief this is the widget that is used as base for text | |
| | | input field representation | |
| | | /// | |
| | | /// This widget is used as base class for other widgets that | |
| | | are used for | |
| | | /// text input like: text, textarea, etc. | |
| | | /// | |
| | | /// This widget does much more then reading simple filed dat | |
| | | a from the POST | |
| | | /// or GET form, it performs charset validation and if requi | |
| | | red conversion | |
| | | /// to and from Unicode charset to locale charset. | |
| | | /// | |
| | | | |
| | | class CPPCMS_API base_text : virtual public base_widget { | |
| | | public: | |
| | | | |
| | | base_text(); | |
| | | virtual ~base_text(); | |
| | | | |
| | | /// | |
| | | /// Get the string that contains input value of the | |
| | | widget. | |
| | | /// | |
| | | | |
| | | std::string value(); | |
| | | | |
| | | /// | |
| | | /// Set the widget content before rendering, the val | |
| | | ue \a v | |
| | | /// | |
| | | | |
| | | void value(std::string v); | |
| | | | |
| | | /// | |
| | | /// Acknowledge the validator that this text widget | |
| | | should contain some text. | |
| | | /// similar to limits(1,-1) | |
| | | /// | |
| | | void non_empty(); | |
| | | /// | |
| | | /// Set minimum and maximum limits for text size. No | |
| | | te max == -1 indicates that there | |
| | | /// is no maximal limit, min==0 indicates that there | |
| | | is no minimal limit. | |
| | | /// | |
| | | /// Note: these numbers represent the length in Unic | |
| | | ode code points (even if the encoding | |
| | | /// is not Unicode). If character set validation is | |
| | | disabled, then these number represent | |
| | | /// the number of octets in the string. | |
| | | /// | |
| | | void limits(int min,int max); | |
| | | | |
| | | /// | |
| | | /// Get minimal and maximal size limits, | |
| | | /// | |
| | | | |
| | | std::pair<int,int> limits(); | |
| | | | |
| | | /// | |
| | | /// Acknowledge the validator if it should not check | |
| | | the validity of the charset. | |
| | | /// Default -- enabled | |
| | | /// | |
| | | /// Generally you should not use this option unless | |
| | | you want to load some raw data as | |
| | | /// form input, or the character set is different fr | |
| | | om the defined in locale. | |
| | | /// | |
| | | void validate_charset(bool ); | |
| | | | |
| | | /// | |
| | | /// Returns true if charset validation is enabled. | |
| | | /// | |
| | | | |
| | | bool validate_charset(); | |
| | | | |
| | | /// | |
| | | /// Validate the widget content according to rules a | |
| | | nd charset encoding. | |
| | | /// | |
| | | /// Notes: | |
| | | /// | |
| | | /// - The charset validation is very efficient for | |
| | | variable length UTF-8 encoding, | |
| | | /// and most popular fixed length ISO-8859-*, win | |
| | | dows-125* and koi8* encodings, for other | |
| | | /// encodings iconv conversion is used for actual | |
| | | validation. | |
| | | /// - Special characters (that not allowed in HTML) | |
| | | are assumed as forbidden, even if they are | |
| | | /// valid code points (like NUL = 0 or DEL=127). | |
| | | /// | |
| | | virtual bool validate(); | |
| | | | |
| | | /// | |
| | | /// Load the widget for http::context. It used the l | |
| | | ocale given in the context for | |
| | | /// validation of text. | |
| | | /// | |
| | | virtual void load(http::context &); | |
| | | private: | |
| | | std::string value_; | |
| | | int low_; | |
| | | int high_; | |
| | | bool validate_charset_; | |
| | | size_t code_points_; | |
| | | struct _data; | |
| | | booster::hold_ptr<_data> d; | |
| | | }; | |
| | | | |
| | | /// | |
| | | /// This class represents a basic widget that generates html | |
| | | for common widgets | |
| | | /// that use <input \/> HTML tag. | |
| | | /// | |
| | | /// It allows you creating your own widgets easier as it doe | |
| | | s most of job required for | |
| | | /// generating the HTML and user is required only to generat | |
| | | e actual value like | |
| | | /// value="10.34" as for numeric widget. | |
| | | /// | |
| | | | |
| | | class CPPCMS_API base_html_input : virtual public base_widge | |
| | | t { | |
| | | public: | |
| | | | |
| | | /// | |
| | | /// Creates new instance, \a type is HTML type tag o | |
| | | f the input element, for example "text" or | |
| | | /// "password". | |
| | | /// | |
| | | base_html_input(std::string const &type); | |
| | | /// | |
| | | /// Virtual destructor... | |
| | | /// | |
| | | virtual ~base_html_input(); | |
| | | /// | |
| | | /// This function is actual HTML generation function | |
| | | that calls render_value where needed. | |
| | | /// | |
| | | virtual void render_input(form_context &context); | |
| | | | |
| | | protected: | |
| | | /// | |
| | | /// This is what user actually expected to implement | |
| | | . Write actual value HTML tag. | |
| | | /// | |
| | | virtual void render_value(form_context &context) = 0 | |
| | | ; | |
| | | private: | |
| | | struct _data; | |
| | | booster::hold_ptr<_data> d; | |
| | | std::string type_; | |
| | | }; | |
| | | | |
| | | /// | |
| | | /// \brief This class represents html input of type text | |
| | | /// | |
| | | | |
| | | class CPPCMS_API text : public base_html_input, public base_ | |
| | | text | |
| | | { | |
| | | public: | |
| | | /// | |
| | | /// Create text field widget | |
| | | /// | |
| | | text(); | |
| | | | |
| | | /// | |
| | | /// This constructor is provided for use by derived | |
| | | classes where it is required | |
| | | /// to change the type of widget, like text, passwor | |
| | | d, etc. | |
| | | /// | |
| | | text(std::string const &type); | |
| | | | |
| | | ~text(); | |
| | | | |
| | | /// | |
| | | /// Set html attribute size of the widget | |
| | | /// | |
| | | | |
| | | void size(int n); | |
| | | | |
| | | /// | |
| | | /// Get html attribute size of the widget, -1 undefi | |
| | | ned | |
| | | /// | |
| | | | |
| | | int size(); | |
| | | | |
| | | virtual void render_attributes(form_context &context | |
| | | ); | |
| | | virtual void render_value(form_context &context); | |
| | | private: | |
| | | int size_; | |
| | | struct _data; | |
| | | booster::hold_ptr<_data> d; | |
| | | }; | |
| | | | |
| | | /// | |
| | | /// This widget represents hidden input form type. It is use | |
| | | d to provide | |
| | | /// some invisible to user information. | |
| | | /// | |
| | | /// I has same properties that text widget has but it does n | |
| | | ot render any HTML | |
| | | /// related to message(), help() and other informational typ | |
| | | es. | |
| | | /// | |
| | | /// When your render the form in templates it is good idea t | |
| | | o render it separately | |
| | | /// to make sure that no invalid HTML would be created. | |
| | | /// | |
| | | | |
| | | class CPPCMS_API hidden : public text | |
| | | { | |
| | | public: | |
| | | hidden(); | |
| | | ~hidden(); | |
| | | /// | |
| | | /// Actual rendering function that is redefined | |
| | | /// | |
| | | virtual void render(form_context &context); | |
| | | private: | |
| | | struct _data; | |
| | | booster::hold_ptr<_data> d; | |
| | | }; | |
| | | | |
| | | /// | |
| | | /// This text widget behaves similarly to text widget but us | |
| | | es rather HTML | |
| | | /// textarea and not input HTML tags | |
| | | /// | |
| | | class CPPCMS_API textarea : public base_text | |
| | | { | |
| | | public: | |
| | | textarea(); | |
| | | ~textarea(); | |
| | | | |
| | | /// | |
| | | /// Get number of rows in textarea -- default -1 -- | |
| | | undefined | |
| | | /// | |
| | | int rows(); | |
| | | /// | |
| | | /// Get number of columns in textarea -- default -1 | |
| | | -- undefined | |
| | | /// | |
| | | int cols(); | |
| | | | |
| | | /// | |
| | | /// Set number of rows in textarea | |
| | | /// | |
| | | void rows(int n); | |
| | | /// | |
| | | /// Set number of columns in textarea | |
| | | /// | |
| | | void cols(int n); | |
| | | | |
| | | virtual void render_input(form_context &context); | |
| | | private: | |
| | | int rows_,cols_; | |
| | | | |
| | | struct _data; | |
| | | booster::hold_ptr<_data> d; | |
| | | }; | |
| | | | |
| | | /// | |
| | | /// \brief Widget for number input. It is template class tha | |
| | | t assumes that T is number | |
| | | /// | |
| | | | |
| | | template<typename T> | |
| | | class numeric: public base_html_input { | |
| | | public: | |
| | | numeric() : | |
| | | base_html_input("text"), | |
| | | check_low_(false), | |
| | | check_high_(false), | |
| | | non_empty_(false) | |
| | | { | |
| | | } | |
| | | | |
| | | /// | |
| | | /// Defines that this widget should have some value | |
| | | /// | |
| | | void non_empty() | |
| | | { | |
| | | non_empty_=true; | |
| | | } | |
| | | | |
| | | /// | |
| | | /// Get loaded widget value | |
| | | /// | |
| | | T value() | |
| | | { | |
| | | if(!set()) | |
| | | throw cppcms_error("Value not loaded | |
| | | "); | |
| | | return value_; | |
| | | } | |
| | | | |
| | | /// | |
| | | /// Set widget value | |
| | | /// | |
| | | void value(T v) | |
| | | { | |
| | | set(true); | |
| | | value_=v; | |
| | | } | |
| | | | |
| | | /// | |
| | | /// Set minimal input number value | |
| | | /// | |
| | | void low(T a) | |
| | | { | |
| | | min_=a; | |
| | | check_low_=true; | |
| | | non_empty(); | |
| | | } | |
| | | | |
| | | /// | |
| | | /// Set maximal input number value | |
| | | /// | |
| | | | |
| | | void high(T b) | |
| | | { | |
| | | max_=b; | |
| | | check_high_=true; | |
| | | non_empty(); | |
| | | } | |
| | | | |
| | | /// | |
| | | /// Same as low(a); high(b); | |
| | | /// | |
| | | void range(T a,T b) | |
| | | { | |
| | | low(a); | |
| | | high(b); | |
| | | } | |
| | | | |
| | | /// | |
| | | /// Render first part of widget | |
| | | /// | |
| | | | |
| | | virtual void render_value(form_context &context) | |
| | | { | |
| | | if(set()) | |
| | | context.out()<<"value=\""<<value_<<" | |
| | | \" "; | |
| | | else | |
| | | context.out()<<"value=\""<<util::esc | |
| | | ape(loaded_string_)<<"\" "; | |
| | | } | |
| | | | |
| | | virtual void clear() | |
| | | { | |
| | | base_html_input::clear(); | |
| | | loaded_string_.clear(); | |
| | | } | |
| | | | |
| | | /// | |
| | | /// Load widget data | |
| | | /// | |
| | | | |
| | | virtual void load(http::context &context) | |
| | | { | |
| | | auto_generate(); | |
| | | | |
| | | loaded_string_.clear(); | |
| | | | |
| | | set(false); | |
| | | valid(true); | |
| | | | |
| | | http::request::form_type::const_iterator p; | |
| | | http::request::form_type const &request=cont | |
| | | ext.request().post_or_get(); | |
| | | p=request.find(name()); | |
| | | if(p==request.end()) { | |
| | | return; | |
| | | } | |
| | | else { | |
| | | loaded_string_=p->second; | |
| | | if(loaded_string_.empty()) | |
| | | return; | |
| | | | |
| | | std::istringstream ss(loaded_string_ | |
| | | ); | |
| | | ss.imbue(context.locale()); | |
| | | ss>>value_; | |
| | | if(ss.fail() || !ss.eof()) | |
| | | valid(false); | |
| | | else | |
| | | set(true); | |
| | | } | |
| | | } | |
| | | | |
| | | /// | |
| | | /// Validate widget | |
| | | /// | |
| | | virtual bool validate() | |
| | | { | |
| | | if(!valid()) | |
| | | return false; | |
| | | if(!set()) { | |
| | | if(non_empty_) { | |
| | | valid(false); | |
| | | return false; | |
| | | } | |
| | | return true; | |
| | | } | |
| | | if(check_low_ && value_ <min_) { | |
| | | valid(false); | |
| | | return false; | |
| | | } | |
| | | if(check_high_ && value_ > max_) { | |
| | | valid(false); | |
| | | return false; | |
| | | } | |
| | | return true; | |
| | | } | |
| | | | |
| | | private: | |
| | | | |
| | | T min_,max_,value_; | |
| | | | |
| | | bool check_low_; | |
| | | bool check_high_; | |
| | | bool non_empty_; | |
| | | std::string loaded_string_; | |
| | | }; | |
| | | | |
| | | /// | |
| | | /// \brief The password widget is a simple text widget with | |
| | | some different | |
| | | // | |
| | | | |
| | | class CPPCMS_API password: public text { | |
| | | public: | |
| | | password(); | |
| | | | |
| | | ~password(); | |
| | | | |
| | | /// | |
| | | /// Set equality constraint to password widget -- th | |
| | | is password should be | |
| | | /// equal to other one \a p2. Usefull for creation o | |
| | | f new passwords -- if passwords | |
| | | /// are not equal, validation would fail | |
| | | /// | |
| | | void check_equal(password &p2); | |
| | | virtual bool validate(); | |
| | | private: | |
| | | struct _data; | |
| | | booster::hold_ptr<_data> d; | |
| | | password *password_to_check_; | |
| | | }; | |
| | | | |
| | | /// | |
| | | /// \brief This class is extinction of text widget that vali | |
| | | dates it using additional regular expression | |
| | | /// | |
| | | | |
| | | class CPPCMS_API regex_field : public text { | |
| | | public: | |
| | | regex_field(); | |
| | | /// | |
| | | /// Create widget using regular expression \a e | |
| | | /// | |
| | | regex_field(booster::regex const &e); | |
| | | | |
| | | /// | |
| | | /// Create widget using regular expression \a e | |
| | | /// | |
| | | regex_field(std::string const &e); | |
| | | | |
| | | /// | |
| | | /// Set regular expression | |
| | | /// | |
| | | void regex(booster::regex const &e); | |
| | | | |
| | | ~regex_field(); | |
| | | | |
| | | virtual bool validate(); | |
| | | private: | |
| | | booster::regex expression_; | |
| | | struct _data; | |
| | | booster::hold_ptr<_data> d; | |
| | | }; | |
| | | | |
| | | /// | |
| | | /// \brief widget that checks that input is valid e-mail | |
| | | /// | |
| | | | |
| | | class CPPCMS_API email : public regex_field { | |
| | | public: | |
| | | | |
| | | email(); | |
| | | ~email(); | |
| | | | |
| | | private: | |
| | | struct _data; | |
| | | booster::hold_ptr<_data> d; | |
| | | }; | |
| | | | |
| | | /// | |
| | | /// This class represent an html checkbox input widget | |
| | | /// | |
| | | class CPPCMS_API checkbox: public base_html_input { | |
| | | public: | |
| | | /// | |
| | | /// The constructor that allows you to specify other | |
| | | type like "radio" | |
| | | /// | |
| | | checkbox(std::string const &type); | |
| | | /// | |
| | | /// Default constructor, type checkbox | |
| | | /// | |
| | | checkbox(); | |
| | | virtual ~checkbox(); | |
| | | | |
| | | /// | |
| | | /// Returns true of box was checked (selected) | |
| | | /// | |
| | | bool value(); | |
| | | /// | |
| | | /// Set checked state | |
| | | /// | |
| | | void value(bool is_set); | |
| | | | |
| | | /// | |
| | | /// Get unique identification of the checkbox | |
| | | /// | |
| | | std::string identification(); | |
| | | | |
| | | /// | |
| | | /// Set unique identification to the checkbox, usefu | |
| | | l when you want to | |
| | | /// have many options with same name | |
| | | /// | |
| | | void identification(std::string const &); | |
| | | | |
| | | virtual void render_value(form_context &context); | |
| | | virtual void load(http::context &context); | |
| | | private: | |
| | | struct _data; | |
| | | booster::hold_ptr<_data> d; | |
| | | std::string identification_; | |
| | | bool value_; | |
| | | }; | |
| | | | |
| | | /// | |
| | | /// Select multiple elements widget | |
| | | /// | |
| | | class CPPCMS_API select_multiple : public base_widget { | |
| | | public: | |
| | | select_multiple(); | |
| | | ~select_multiple(); | |
| | | | |
| | | /// | |
| | | /// Add a new option to list with display name \a ms | |
| | | g, and specify if it is initially | |
| | | /// selected, default false | |
| | | /// | |
| | | void add(std::string const &msg,bool selected=false) | |
| | | ; | |
| | | /// | |
| | | /// Add a new option to list with display name \a ms | |
| | | g, and specify if it is initially | |
| | | /// selected, default false, providing unique identi | |
| | | fication for the element \a id | |
| | | /// | |
| | | void add(std::string const &msg,std::string const &i | |
| | | d,bool selected=false); | |
| | | /// | |
| | | /// Add a new option to list with localized display | |
| | | name \a msg, and specify if it is initially | |
| | | /// selected, default false | |
| | | /// | |
| | | void add(locale::message const &msg,bool selected=fa | |
| | | lse); | |
| | | /// | |
| | | /// Add a new option to list with localized display | |
| | | name \a msg, and specify if it is initially | |
| | | /// selected, default false, providing unique identi | |
| | | fication for the element \a id | |
| | | /// | |
| | | void add(locale::message const &msg,std::string cons | |
| | | t &id,bool selected=false); | |
| | | | |
| | | /// | |
| | | /// Get the mapping of all selected items according | |
| | | to the order they where added to the list | |
| | | /// | |
| | | std::vector<bool> selected_map(); | |
| | | /// | |
| | | /// Get all selected items ids according to the orde | |
| | | r they where added to the list, if no | |
| | | /// specific id was given, strings "0", "1"... would | |
| | | be used | |
| | | /// | |
| | | std::set<std::string> selected_ids(); | |
| | | | |
| | | /// | |
| | | /// Get minimal amount of options that should be cho | |
| | | sen, default = 0 | |
| | | /// | |
| | | unsigned at_least(); | |
| | | | |
| | | /// | |
| | | /// Set minimal amount of options that should be cho | |
| | | sen, default = 0 | |
| | | /// | |
| | | void at_least(unsigned v); | |
| | | | |
| | | /// | |
| | | /// Get maximal amount of options that should be cho | |
| | | sen, default unlimited | |
| | | /// | |
| | | unsigned at_most(); | |
| | | /// | |
| | | /// Set maximal amount of options that should be cho | |
| | | sen, default unlimited | |
| | | /// | |
| | | void at_most(unsigned v); | |
| | | | |
| | | /// | |
| | | /// Same as at_least(1) | |
| | | /// | |
| | | void non_empty(); | |
| | | | |
| | | /// | |
| | | /// Get the number of rows used for widget, default | |
| | | 0 -- undefined | |
| | | /// | |
| | | unsigned rows(); | |
| | | /// | |
| | | /// Set the number of rows used for widget, default | |
| | | 0 -- undefined | |
| | | /// | |
| | | void rows(unsigned n); | |
| | | | |
| | | virtual void render_input(form_context &context); | |
| | | virtual bool validate(); | |
| | | virtual void load(http::context &context); | |
| | | virtual void clear(); | |
| | | private: | |
| | | struct _data; | |
| | | booster::hold_ptr<_data> d; | |
| | | | |
| | | struct element { | |
| | | element(); | |
| | | element(std::string const &v,locale::message | |
| | | const &msg,bool sel); | |
| | | element(std::string const &v,std::string con | |
| | | st &msg,bool sel); | |
| | | uint32_t selected : 1; | |
| | | uint32_t need_translation : 1; | |
| | | uint32_t original_select : 1; | |
| | | uint32_t reserved : 29; | |
| | | std::string id; | |
| | | std::string str_option; | |
| | | locale::message tr_option; | |
| | | friend std::ostream &operator<<(std::ostream | |
| | | &out,element const &el); | |
| | | }; | |
| | | | |
| | | std::vector<element> elements_; | |
| | | | |
| | | unsigned low_; | |
| | | unsigned high_; | |
| | | unsigned rows_; | |
| | | | |
| | | }; | |
| | | | |
| | | /// | |
| | | /// This is the base class for "select" like widgets which i | |
| | | ncludes dropdown list | |
| | | /// and radio buttons set. | |
| | | /// | |
| | | class CPPCMS_API select_base : public base_widget { | |
| | | public: | |
| | | select_base(); | |
| | | virtual ~select_base(); | |
| | | | |
| | | /// | |
| | | /// Add new entry to selection list | |
| | | /// | |
| | | void add(std::string const &string); | |
| | | | |
| | | /// | |
| | | /// Add new entry to selection list giving the uniqu | |
| | | e entry identification \a id | |
| | | /// | |
| | | void add(std::string const &string,std::string const | |
| | | &id); | |
| | | /// | |
| | | /// Add new localized entry to selection list | |
| | | /// | |
| | | void add(locale::message const &msg); | |
| | | /// | |
| | | /// Add new localized entry to selection list giving | |
| | | the unique entry identification \a id | |
| | | /// | |
| | | void add(locale::message const &msg,std::string cons | |
| | | t &id); | |
| | | | |
| | | /// | |
| | | /// Return the selected entry number in the list sta | |
| | | rting from 0. -1 indicates that nothing | |
| | | /// was selected. | |
| | | /// | |
| | | int selected(); | |
| | | | |
| | | /// | |
| | | /// Return the identification string of the selected | |
| | | entry, empty string indicates that | |
| | | /// nothing was selected | |
| | | /// | |
| | | std::string selected_id(); | |
| | | | |
| | | /// | |
| | | /// Select entry number \a no in the list for render | |
| | | ing | |
| | | /// | |
| | | void selected(int no); | |
| | | /// | |
| | | /// Select entry with identification \a id in the li | |
| | | st for rendering | |
| | | /// | |
| | | void selected_id(std::string id); | |
| | | | |
| | | /// | |
| | | /// Require that item should be selected (for valida | |
| | | tion) | |
| | | /// | |
| | | void non_empty(); | |
| | | | |
| | | virtual void render_input(form_context &context) = 0 | |
| | | ; | |
| | | virtual bool validate(); | |
| | | virtual void load(http::context &context); | |
| | | virtual void clear(); | |
| | | protected: | |
| | | | |
| | | struct CPPCMS_API element { | |
| | | | |
| | | element(); | |
| | | element(std::string const &v,locale::message | |
| | | const &msg); | |
| | | element(std::string const &v,std::string con | |
| | | st &msg); | |
| | | element(element const &); | |
| | | element const &operator=(element const &); | |
| | | ~element(); | |
| | | | |
| | | uint32_t need_translation : 1; | |
| | | uint32_t reserved : 31; | |
| | | std::string id; | |
| | | std::string str_option; | |
| | | locale::message tr_option; | |
| | | | |
| | | private: | |
| | | struct _data; | |
| | | booster::copy_ptr<_data> d; | |
| | | | |
| | | }; | |
| | | | |
| | | std::vector<element> elements_; | |
| | | private: | |
| | | struct _data; | |
| | | booster::hold_ptr<_data> d; | |
| | | | |
| | | int selected_; | |
| | | int default_selected_; | |
| | | | |
| | | uint32_t non_empty_ : 1; | |
| | | uint32_t reserverd : 32; | |
| | | }; | |
| | | | |
| | | /// | |
| | | /// Select widget that uses drop-down list | |
| | | /// | |
| | | | |
| | | class CPPCMS_API select : public select_base { | |
| | | public: | |
| | | select(); | |
| | | virtual ~select(); | |
| | | virtual void render_input(form_context &context); | |
| | | private: | |
| | | struct _data; | |
| | | booster::hold_ptr<_data> d; | |
| | | }; | |
| | | | |
| | | /// | |
| | | /// Select widget that uses a set of radio buttons | |
| | | /// | |
| | | class CPPCMS_API radio : public select_base { | |
| | | public: | |
| | | radio(); | |
| | | virtual ~radio(); | |
| | | virtual void render_input(form_context &context); | |
| | | | |
| | | /// | |
| | | /// Return the rendering order | |
| | | /// | |
| | | bool vertical(); | |
| | | /// | |
| | | /// Set rendering order of the list one behind other | |
| | | (default) or in same line. | |
| | | /// | |
| | | void vertical(bool); | |
| | | | |
| | | private: | |
| | | uint32_t vertical_ : 1; | |
| | | uint32_t reserved_ : 31; | |
| | | | |
| | | struct _data; | |
| | | booster::hold_ptr<_data> d; | |
| | | }; | |
| | | | |
| | | /// | |
| | | /// Class that represents file upload form entry | |
| | | /// | |
| | | class CPPCMS_API file : public base_html_input { | |
| | | public: | |
| | | /// | |
| | | /// Ensure that file is uploaded. | |
| | | /// | |
| | | void non_empty(); | |
| | | /// | |
| | | /// Set minimum and maximum limits for file size. No | |
| | | te max == -1 indicates that there | |
| | | /// is no maximal limit, min==0 indicates that there | |
| | | is no minimal limit. | |
| | | /// | |
| | | /// | |
| | | void limits(int min,int max); | |
| | | | |
| | | /// | |
| | | /// Get minimal and maximal size limits, | |
| | | /// | |
| | | | |
| | | std::pair<int,int> limits(); | |
| | | | |
| | | /// | |
| | | /// Set filename validation pattern. For example ".* | |
| | | \\.(jpg|jpeg|png)" | |
| | | /// | |
| | | /// Please, note that it is good idea to check magic | |
| | | number as well. | |
| | | /// | |
| | | void filename(booster::regex const &fn); | |
| | | | |
| | | /// | |
| | | /// Get regular expression for filename validation | |
| | | /// | |
| | | booster::regex filename(); | |
| | | | |
| | | /// | |
| | | /// Validate the filename's charset (default is on) | |
| | | /// | |
| | | void validate_filename_charset(bool); | |
| | | /// | |
| | | /// Get validation option for filename's charset | |
| | | /// | |
| | | bool validate_filename_charset(); | |
| | | | |
| | | /// | |
| | | /// Get uploaded file | |
| | | /// | |
| | | booster::shared_ptr<http::file> value(); | |
| | | | |
| | | /// | |
| | | /// Set required file mime type | |
| | | /// | |
| | | void mime(std::string const &); | |
| | | | |
| | | /// | |
| | | /// Set regular expression that checks for valid mim | |
| | | e type | |
| | | /// | |
| | | void mime(booster::regex const &expr); | |
| | | | |
| | | /// | |
| | | /// Add a string that represents a valid magic numbe | |
| | | r that shoud exist on begging of file | |
| | | /// | |
| | | /// By default no tests are performed | |
| | | /// | |
| | | void add_valid_magic(std::string const &); | |
| | | | |
| | | virtual void load(http::context &context); | |
| | | virtual void render_value(form_context &context); | |
| | | virtual bool validate(); | |
| | | | |
| | | file(); | |
| | | ~file(); | |
| | | | |
| | | private: | |
| | | | |
| | | int size_min_; | |
| | | int size_max_; | |
| | | | |
| | | std::vector<std::string> magics_; | |
| | | | |
| | | std::string mime_string_; | |
| | | booster::regex mime_regex_; | |
| | | booster::regex filename_regex_; | |
| | | | |
| | | uint32_t check_charset_ : 1; | |
| | | uint32_t check_non_empty_ : 1; | |
| | | uint32_t reserved_ : 30; | |
| | | | |
| | | booster::shared_ptr<http::file> file_; | |
| | | | |
| | | struct _data; | |
| | | booster::hold_ptr<_data> d; | |
| | | }; | |
| | | | |
| | | /// | |
| | | /// Submit button widget | |
| | | /// | |
| | | class CPPCMS_API submit : public base_html_input { | |
| | | public: | |
| | | submit(); | |
| | | ~submit(); | |
| | | | |
| | | /// | |
| | | /// Returns true if this specific button was pressed | |
| | | /// | |
| | | bool value(); | |
| | | | |
| | | /// | |
| | | /// Sets the text on button | |
| | | /// | |
| | | void value(std::string val); | |
| | | /// | |
| | | /// Sets the text on button | |
| | | /// | |
| | | void value(locale::message const &msg); | |
| | | | |
| | | virtual void render_value(form_context &context); | |
| | | virtual void load(http::context &context); | |
| | | private: | |
| | | struct _data; | |
| | | booster::hold_ptr<_data> d; | |
| | | bool pressed_; | |
| | | locale::message value_; | |
| | | }; | |
| | | | |
| | | } // widgets | |
| | | | |
| } //cppcms | | } //cppcms | |
| | | | |
| #endif // CPPCMS_FORM_H | | #endif // CPPCMS_FORM_H | |
| | | | |
End of changes. 27 change blocks. |
| 256 lines changed or deleted | | 1714 lines changed or added | |
|
| session_interface.h | | session_interface.h | |
|
| | | /////////////////////////////////////////////////////////////////////////// | |
| | | //// | |
| | | // | |
| | | // Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com> | |
| | | // | |
| | | // This program is free software: you can redistribute it and/or modify | |
| | | // it under the terms of the GNU Lesser General Public License as publishe | |
| | | d by | |
| | | // the Free Software Foundation, either version 3 of the License, or | |
| | | // (at your option) any later version. | |
| | | // | |
| | | // This program is distributed in the hope that it will be useful, | |
| | | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| | | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | // GNU Lesser General Public License for more details. | |
| | | // | |
| | | // You should have received a copy of the GNU Lesser General Public Licens | |
| | | e | |
| | | // along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| | | // | |
| | | /////////////////////////////////////////////////////////////////////////// | |
| | | //// | |
| #ifndef CPPCMS_SESSION_INTERFACE_H | | #ifndef CPPCMS_SESSION_INTERFACE_H | |
| #define CPPCMS_SESSION_INTERFACE_H | | #define CPPCMS_SESSION_INTERFACE_H | |
| | | | |
|
| #include <boost/noncopyable.hpp> | | #include <cppcms/defs.h> | |
| #include <boost/lexical_cast.hpp> | | #include <booster/noncopyable.h> | |
| #include <boost/shared_ptr.hpp> | | #include <booster/hold_ptr.h> | |
| | | #include <booster/shared_ptr.h> | |
| | | #include <cppcms/cstdint.h> | |
| | | #include <cppcms/serialization_classes.h> | |
| #include <string> | | #include <string> | |
| #include <map> | | #include <map> | |
|
| | | #include <memory> | |
| | | #include <sstream> | |
| | | #include <typeinfo> | |
| | | | |
| namespace cppcms { | | namespace cppcms { | |
|
| | | namespace http { | |
| | | class context; | |
| | | class request; | |
| | | class response; | |
| | | } | |
| | | | |
| class session_api; | | class session_api; | |
|
| class worker_thread; | | | |
| class serializable; | | | |
| | | | |
|
| class session_interface : private boost::noncopyable { | | /// | |
| struct entry { | | /// \brief This class provides an access to an application for session mana | |
| std::string value; | | gement | |
| bool exposed; | | /// | |
| entry(std::string v="",bool exp=false) : value(v) , exposed( | | /// Usually it is accessed via application::session member function. | |
| exp) {} | | /// | |
| bool operator==(entry const &other) const | | /// Note, when the application is asynchronous, the sessions should be load | |
| { | | ed manually as | |
| return value==other.value && exposed==other.exposed; | | /// fetching information from session may be not so cheap | |
| } | | /// | |
| bool operator!=(entry const &other) const | | /// Generally, session data is represented as a map of key-value strings th | |
| { | | at can be read | |
| return !(*this==other); | | /// and written. All changes in session should be done before headers are w | |
| } | | ritten to the output | |
| }; | | /// (before requesting an output stream from http::response object) | |
| typedef std::map<std::string,entry> data_t; | | /// | |
| data_t data,data_copy; | | /// Each of the values in session may be also exposed to client as cookie. | |
| worker_thread &worker; | | For example if | |
| | | /// you want to disclose "foo" session key to the client side (Java Script) | |
| // Cached defaults | | and session | |
| int timeout_val_def; | | /// cookie is cppcms_session=S231abc23c34ca242352a then a cookie with name | |
| int how_def; | | /// cppcms_session_foo will be created caring the value of this key. | |
| | | /// | |
| // User Values | | /// Notes: | |
| int timeout_val; | | /// - Be careful with values you pass, cookies can carry quite a limited ra | |
| int how; | | nge of strings | |
| | | /// so it is your responsibility to make sure that these values are actual | |
| // Information from session data | | ly legal. | |
| time_t timeout_in; | | /// - Of course the client side can alter these cookies but this would not | |
| bool new_session; | | have an effect | |
| bool saved; | | /// on the actual values fetched using session object. But still remember y | |
| | | ou should not | |
| | | /// relay on cookies values on server side for obvious security reasons. | |
| | | /// | |
| | | class CPPCMS_API session_interface : private booster::noncopyable { | |
| | | public: | |
| | | | |
|
| int cookie_age(); | | /// \cond INTERNAL | |
| time_t session_age(); | | session_interface(http::context &); | |
| | | ~session_interface(); | |
| | | /// \endcond | |
| | | | |
|
| void check(); | | /// | |
| bool load(); | | /// Check if a \a key is set (assigned some value to it) in the sess | |
| void update_exposed(bool force=false); | | ion | |
| | | /// | |
| | | bool is_set(std::string const &key); | |
| | | /// | |
| | | /// Erase specific \a key from the session | |
| | | /// | |
| | | void erase(std::string const &key); | |
| | | /// | |
| | | /// Remove all keys from the session and delete the session at all. | |
| | | (i.e. empty session is automatically deleted) | |
| | | /// | |
| | | void clear(); | |
| | | | |
|
| std::string temp_cookie; | | /// | |
| | | /// Returns true if specific \a key is exposed to client via cookies | |
| | | /// | |
| | | bool is_exposed(std::string const &key); | |
| | | /// | |
| | | /// Set exposition of the \a key to client side, if val is true the | |
| | | value will be exposed, otherwise hidden and cookie | |
| | | /// will be deleted. | |
| | | /// | |
| | | void expose(std::string const &key,bool val=true); | |
| | | /// | |
| | | /// Disable exposition of a \a key. Same as expose(key,false); | |
| | | /// | |
| | | void hide(std::string const &key); | |
| | | | |
|
| boost::shared_ptr<session_api> storage; | | /// | |
| void set_session_cookie(int64_t age,std::string const &data,std::str | | /// Get the reference to a value for a \a key. Note if \a key is not | |
| ing const &key=std::string()); | | exist, empty string is created in session object | |
| | | /// and reference to it returned (similarly to std::map's operator[] | |
| | | ) | |
| | | /// | |
| | | std::string &operator[](std::string const &key); | |
| | | /// | |
| | | /// Set value \a v for a session key \a key | |
| | | /// | |
| | | void set(std::string const &key,std::string const &v); | |
| | | | |
|
| void save_data(data_t const &data,std::string &s); | | /// | |
| void load_data(data_t &data,std::string const &s); | | /// Get a value for a session \a key. If it is not set, throws cppcm | |
| | | s_error. It is good idea to call is_set before | |
| | | /// you call this function. | |
| | | /// | |
| | | std::string get(std::string const &key); | |
| | | | |
|
| public: | | /// | |
| session_interface(worker_thread &w); | | /// Get convert the value that is set for a key \a key to type T usi | |
| bool is_set(std::string const &key); | | ng std::iostream. For example you can | |
| void del(std::string const &key); | | /// read a number using int n=session().get<int>("number"). | |
| std::string &operator[](std::string const &); | | /// | |
| | | /// - it throws cppcms_error if a key \a key not set/ | |
| | | /// - it throws std::bad_cast of the conversion using std::iostream | |
| | | fails | |
| | | /// | |
| | | /// Note: the conversion is locale independent (uses C locale) | |
| | | /// | |
| template<typename T> | | template<typename T> | |
|
| T get(std::string const &key) { | | T get(std::string const &key) | |
| return boost::lexical_cast<T>((*this)[key]); | | { | |
| | | std::istringstream ss(get(key)); | |
| | | ss.imbue(std::locale::classic()); | |
| | | T value; | |
| | | ss>>value; | |
| | | if(ss.fail() || !ss.eof()) | |
| | | throw std::bad_cast(); | |
| | | return value; | |
| } | | } | |
|
| | | | |
| | | /// | |
| | | /// Assign a \a value of type \a T to \a key converting it to string | |
| | | using std::iostream. | |
| | | /// For example session().set("num",100); | |
| | | /// Note: the conversion is locale independent (uses C locale) | |
| | | /// | |
| template<typename T> | | template<typename T> | |
|
| void set(std::string const &key,T const &val) { | | void set(std::string const &key,T const &value) | |
| (*this)[key]=boost::lexical_cast<std::string>(val); | | { | |
| | | std::ostringstream ss; | |
| | | ss.imbue(std::locale::classic()); | |
| | | ss<<value; | |
| | | set(key,ss.str()); | |
| } | | } | |
| | | | |
|
| void get(std::string const &key,serializable &); | | /// | |
| void set(std::string const &key,serializable const &); | | /// Serialize an \a object and store it under a \a key. | |
| bool is_exposed(std::string const &key); | | /// | |
| void expose(std::string const &key,bool val=true); | | /// The serialization is done using cppcms::serialization_traits | |
| void hide(std::string const &key); | | /// | |
| | | template<typename Serializable> | |
| | | void store_data(std::string const &key,Serializable const &object) | |
| | | { | |
| | | std::string buffer; | |
| | | serialization_traits<Serializable>::save(object,buffer); | |
| | | set(key,buffer); | |
| | | } | |
| | | | |
|
| void clear(); | | /// | |
| | | /// Fetch an \a object under \a key from the session deserializing i | |
| | | t. | |
| | | /// | |
| | | /// The serialization is done using cppcms::serialization_traits | |
| | | /// | |
| | | /// Throws cppcms_error if the key is not set, may throw archive_err | |
| | | or if deserialization fails | |
| | | /// (assuming that serialization uses cppcms::archive. | |
| | | /// | |
| | | template<typename Serializable> | |
| | | void fetch_data(std::string const &key,Serializable &object) | |
| | | { | |
| | | std::string buffer=get(key); | |
| | | serialization_traits<Serializable>::load(buffer,object); | |
| | | } | |
| | | | |
|
| enum { fixed, renew, browser }; | | /// | |
| void set_age(int t); | | /// This enum defines the way session timeout is managed | |
| void set_expiration(int h); | | /// | |
| void set_age(); | | enum { | |
| void set_expiration(); | | fixed, ///< Once the session is created it will expire in a | |
| void save(); | | ge() second from the moment it created | |
| | | renew, ///< Once the session expires in age() seconds of in | |
| | | activity, once user sends an HTTP request again | |
| | | ///< it is renewed | |
| | | browser ///< The session is kept as long as browser keeps it | |
| | | (does not get closed). In addition the "renew" expiration | |
| | | ///< policy is valid. So if user does not close his | |
| | | browser but is not active, it will expire in age() seconds. | |
| | | }; | |
| | | | |
|
| // Special interface | | /// | |
| | | /// Get the maximal age of the session in seconds | |
| | | /// | |
| | | int age(); | |
| | | /// | |
| | | /// Set the maximal age of the session in seconds | |
| | | /// | |
| | | void age(int t); | |
| | | /// | |
| | | /// Reset the maximal age of the session to default (session.timeout | |
| | | settings value or 24 hours if not set) | |
| | | /// | |
| | | void default_age(); | |
| | | | |
| | | /// | |
| | | /// Get the expiration policy of the session: renew, fixed or browse | |
| | | r | |
| | | /// | |
| | | int expiration(); | |
| | | /// | |
| | | /// Set the expiration policy of the session: renew, fixed or browse | |
| | | r | |
| | | /// | |
| | | void expiration(int h); | |
| | | /// | |
| | | /// Reset the expiration policy to the default (session.expire setti | |
| | | ngs value or browser if not set) | |
| | | /// | |
| | | void default_expiration(); | |
| | | | |
| | | /// | |
| | | /// Set store on server side option for session. If srv is true then | |
| | | the session will be always stored on server | |
| | | /// side and not in cookies only (required "server" or "both" type s | |
| | | torage in session.location setting | |
| | | /// | |
| | | /// Rationale: client side storage using encrypted or signed cookies | |
| | | is very efficient, however it lacks of one | |
| | | /// important security feature: there is no other way to control the | |
| | | ir expiration but using timeout. | |
| | | /// So user may just revert the cookie to the old state to get back | |
| | | in time and restore its own session. | |
| | | /// | |
| | | /// So it is recommended to use server side storage in such critical | |
| | | cases, like soling captcha or playing a game | |
| | | /// where you can't return to previous status when storing the data | |
| | | in the session object. | |
| | | /// | |
| | | void on_server(bool srv); | |
| | | | |
| | | /// | |
| | | /// Get on_server session property | |
| | | /// | |
| | | bool on_server(); | |
| | | | |
| | | /// | |
| | | /// Set the cookie that represents the current session (the value of | |
| | | the cookie) | |
| | | /// | |
| | | /// This function should be used only by user implementations of ses | |
| | | sion storage | |
| | | /// | |
| void set_session_cookie(std::string const &data); | | void set_session_cookie(std::string const &data); | |
|
| | | /// | |
| | | /// Remove the cookie of the current session | |
| | | /// | |
| | | /// This function should be used only by user implementations of ses | |
| | | sion storage | |
| | | /// | |
| void clear_session_cookie(); | | void clear_session_cookie(); | |
|
| | | | |
| | | /// | |
| | | /// Get the value of the cookie that represents session on the clien | |
| | | t | |
| | | /// | |
| | | /// This function should be used only by user implementations of ses | |
| | | sion storage | |
| | | /// | |
| std::string get_session_cookie(); | | std::string get_session_cookie(); | |
|
| void set_api(boost::shared_ptr<session_api>); | | | |
| | | | |
|
| void on_start(); | | /// | |
| void on_end(); | | /// Load the session, should be called one when dealing with session | |
| worker_thread &get_worker(); | | s on asynchronous API where sessions | |
| | | /// are not loaded by default. This function returns true if any dat | |
| | | a was loaded. | |
| | | /// | |
| | | bool load(); | |
| | | | |
| | | /// | |
| | | /// Save the session data, generally should not be called as it is s | |
| | | aved automatically. However when | |
| | | /// writing asynchronous application and using custom slow storage d | |
| | | evices like SQL it may be useful to control | |
| | | /// when and how save() is called. | |
| | | /// | |
| | | void save(); | |
| | | | |
| | | private: | |
| | | friend class http::response; | |
| | | friend class http::request; | |
| | | | |
| | | struct entry; | |
| | | | |
| | | typedef std::map<std::string,entry> data_type; | |
| | | data_type data_,data_copy_; | |
| | | http::context *context_; | |
| | | | |
| | | // Cached defaults | |
| | | int timeout_val_def_; | |
| | | int how_def_; | |
| | | | |
| | | // User Values | |
| | | int timeout_val_; | |
| | | int how_; | |
| | | | |
| | | // Information from session data | |
| | | time_t timeout_in_; | |
| | | | |
| | | uint32_t new_session_ : 1; | |
| | | uint32_t saved_ : 1; | |
| | | uint32_t on_server_ : 1; | |
| | | uint32_t loaded_ : 1; | |
| | | uint32_t reserved_ : 28; | |
| | | | |
| | | std::string temp_cookie_; | |
| | | | |
| | | // storage itself | |
| | | | |
| | | booster::shared_ptr<session_api> storage_; | |
| | | struct _data; | |
| | | booster::hold_ptr<_data> d; // for future use | |
| | | | |
| | | int cookie_age(); | |
| | | time_t session_age(); | |
| | | | |
| | | void check(); | |
| | | void update_exposed(bool); | |
| | | | |
| | | void set_session_cookie(int64_t age,std::string const &data,std::str | |
| | | ing const &key=std::string()); | |
| | | | |
| | | void save_data(std::map<std::string,entry> const &data,std::string & | |
| | | s); | |
| | | void load_data(std::map<std::string,entry> &data,std::string const & | |
| | | s); | |
| }; | | }; | |
| | | | |
| } // cppcms | | } // cppcms | |
| | | | |
| #endif | | #endif | |
| | | | |
End of changes. 23 change blocks. |
| 73 lines changed or deleted | | 337 lines changed or added | |
|