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 | |||
base64.h | base64.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_BASE64_H | #ifndef CPPCMS_BASE64_H | |||
#define CPPCMS_BASE64_H | #define CPPCMS_BASE64_H | |||
#include <cppcms/defs.h> | ||||
#include <string> | #include <string> | |||
namespace cppcms { | namespace cppcms { | |||
/// | ||||
/// \brief this namespace provides functions useful for modified Bas | ||||
e64 encoding for URL. | ||||
/// This encoding does not insert newline characters, do not pad the | ||||
text with = character and | ||||
/// use "_" and "-" instead of "+" and "/" characters reserved by UR | ||||
L format for special purposes. | ||||
/// | ||||
namespace b64url { | namespace b64url { | |||
ssize_t encoded_size(size_t s); | ||||
ssize_t decoded_size(size_t s); | /// | |||
unsigned char *encode(unsigned char const *begin,unsigned char const | /// Calculate required buffer size of base64-url compatible encoding | |||
*end,unsigned char *target); | for source of size \a s | |||
unsigned char *decode(unsigned char const *begin,unsigned char const | /// | |||
*end,unsigned char *target); | int CPPCMS_API encoded_size(size_t s); | |||
/// | ||||
/// Calculate required buffer size of base64-url compatible decoding | ||||
for source of size \a s | ||||
/// | ||||
/// Note, if original size is invalid, negative value is returned | ||||
/// | ||||
int CPPCMS_API decoded_size(size_t s); | ||||
/// | ||||
/// Perform base64 URL encoding of the binary data in range [\a begi | ||||
n,\a end), and store it to output buffer | ||||
/// \a target. The size of target storage should have a capacity cal | ||||
culated with encoded_size(end-begin). | ||||
/// | ||||
/// Pointer to the first character directly after text string ends i | ||||
s returned. | ||||
/// | ||||
unsigned char CPPCMS_API *encode(unsigned char const *begin,unsigned | ||||
char const *end,unsigned char *target); | ||||
/// | ||||
/// Perform base64 URL decoding of the binary data in range [\a begi | ||||
n,\a end), and store it to output buffer | ||||
/// \a target. The size of target storage should have a capacity cal | ||||
culated with encoded_size(end-begin). | ||||
/// | ||||
/// Pointer to the first character directly after text string ends i | ||||
s returned. Invalid codes are substituted | ||||
/// by 0 values. | ||||
/// | ||||
/// | ||||
unsigned char CPPCMS_API *decode(unsigned char const *begin,unsigned | ||||
char const *end,unsigned char *target); | ||||
} | } | |||
} | } | |||
#endif | #endif | |||
End of changes. 4 change blocks. | ||||
6 lines changed or deleted | 70 lines changed or added | |||
base_view.h | base_view.h | |||
---|---|---|---|---|
#ifndef CPPCMS_BASEVIEW_H | /////////////////////////////////////////////////////////////////////////// | |||
#define CPPCMS_BASEVIEW_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_BASE_VIEW_H | ||||
#define CPPCMS_BASE_VIEW_H | ||||
#include <cppcms/defs.h> | ||||
#include <ostream> | #include <ostream> | |||
#include <sstream> | #include <sstream> | |||
#include <string> | #include <string> | |||
#include <cstring> | ||||
#include <map> | #include <map> | |||
#include <memory> | ||||
#include <ctime> | #include <ctime> | |||
#include <boost/format/format_fwd.hpp> | #include <memory> | |||
#include "cppcms_error.h" | ||||
#include "config.h" | ||||
namespace cppcms { | #include <booster/hold_ptr.h> | |||
using namespace std; | #include <cppcms/base_content.h> | |||
#include <booster/noncopyable.h> | ||||
#include <cppcms/config.h> | ||||
// Just simple polimorphic class | namespace cppcms { | |||
class base_content { | ||||
public: | ||||
virtual ~base_content() {}; | ||||
}; | ||||
namespace transtext { class trans; } | /// | |||
/// \brief This class is base class for all views (skins) rendered by CppCM | ||||
S template engine. | ||||
/// | ||||
/// Users are not expected to derive from this class or use it directly. Cp | ||||
pCMS template compiler | ||||
/// create skins that are usable with template engine and each template is | ||||
derived from the \a base_view | ||||
/// class. | ||||
/// | ||||
class format { | class CPPCMS_API base_view : booster::noncopyable { | |||
mutable std::auto_ptr<boost::format> impl; | ||||
friend ostream &operator<<(ostream &,format &); | ||||
public: | public: | |||
format(std::string const &s); | /// | |||
format(format const &f); | /// The main rendering function -- render the main HTML page. It is | |||
format &operator % (int n); | usually overridden in template engine. | |||
format &operator % (string const &); | /// | |||
format &operator % (char const *); | virtual void render(); | |||
string str(); | virtual ~base_view(); | |||
~format(); | ||||
}; | ||||
ostream &operator<<(ostream &,format &); | ||||
class worker_thread; | ||||
class base_view { | ||||
public: | ||||
struct settings { | ||||
worker_thread *worker; | ||||
ostream *output; | ||||
settings(worker_thread *w); | ||||
settings(worker_thread *w,ostream *o); | ||||
}; | ||||
protected: | protected: | |||
worker_thread &worker; | ||||
ostream &cout; | ||||
transtext::trans const *tr; | ||||
base_view(settings s) : | /// \cond INTERNAL | |||
worker(*s.worker), | ||||
cout(*s.output) | ||||
{ | ||||
} | ||||
::cppcms::format format(std::string const &s) | ||||
{ | ||||
return ::cppcms::format(s); | ||||
} | ||||
void set_domain(char const *); | ||||
char const *gettext(char const *); | ||||
char const *ngettext(char const *,char const *,int n); | ||||
template<typename T> | ||||
string escape(T const &v) | ||||
{ | ||||
ostringstream s; | ||||
s<<v; | ||||
return s.str(); | ||||
}; | ||||
string escape(string const &s); | ||||
inline string raw(string s) { return s; }; | ||||
string intf(int val,string f); | ||||
string strftime(std::tm const &t,string f); | ||||
string date(std::tm const &t) { return strftime(t,"%Y-%m-%d"); }; | ||||
string time(std::tm const &t) { return strftime(t,"%H:%M"); }; | ||||
string timesec(std::tm const &t) { return strftime(t,"%T"); }; | ||||
string escape(std::tm const &t) { return strftime(t,"%Y-%m-%d %T"); | ||||
} | ||||
string urlencode(string const &s); | ||||
public: | ||||
virtual void render() {}; | ||||
virtual ~base_view() {}; | ||||
}; | ||||
namespace details { | base_view(std::ostream &out); | |||
std::ostream &out(); | ||||
template<typename T,typename VT> | /// \endcond | |||
base_view *view_builder(base_view::settings s,base_content *c) { | ||||
VT *p=dynamic_cast<VT *>(c); | ||||
if(!p) throw cppcms_error("Incorrect content type"); | ||||
return new T(s,*p); | ||||
}; | ||||
class views_storage { | ||||
public: | ||||
typedef base_view *(*view_factory_t)(base_view::settings s,base_cont | ||||
ent *c); | ||||
private: | private: | |||
typedef map<string,view_factory_t> template_views_t; | struct _data; | |||
typedef map<string,template_views_t> templates_t; | booster::hold_ptr<_data> d; | |||
templates_t storage; | ||||
public: | ||||
void add_view( string template_name, | ||||
string view_name, | ||||
view_factory_t); | ||||
void remove_views(string template_name); | ||||
base_view *fetch_view(string template_name,string view_name,base_vie | ||||
w::settings ,base_content *c); | ||||
static views_storage &instance(); | ||||
}; | }; | |||
}; // DETAILS | } // cppcms | |||
}; // CPPCMS | ||||
#define cppcms_view(X) \ | ||||
do { \ | ||||
void X##_symbol(); \ | ||||
X##_symbol(); \ | ||||
} while(0) | ||||
#if defined(HAVE_CPP_0X_AUTO) | #if defined(CPPCMS_HAVE_CPP_0X_AUTO) | |||
# define CPPCMS_TYPEOF(x) auto | # define CPPCMS_TYPEOF(x) auto | |||
#elif defined(HAVE_CPP_0X_DECLTYPE) | #elif defined(CPPCMS_HAVE_CPP_0X_DECLTYPE) | |||
# define CPPCMS_TYPEOF(x) decltype(x) | # define CPPCMS_TYPEOF(x) decltype(x) | |||
#elif defined(HAVE_GCC_TYPEOF) | #elif defined(CPPCMS_HAVE_GCC_TYPEOF) | |||
# define CPPCMS_TYPEOF(x) typeof(x) | # define CPPCMS_TYPEOF(x) typeof(x) | |||
#elif defined(HAVE_UNDERSCORE_TYPEOF) | #elif defined(CPPCMS_HAVE_UNDERSCORE_TYPEOF) | |||
# define CPPCMS_TYPEOF(x) __typeof__(x) | # define CPPCMS_TYPEOF(x) __typeof__(x) | |||
#elif defined(HAVE_WORKING_BOOST_TYPEOF) | ||||
# include <boost/typeof/typeof.hpp> | ||||
# define CPPCMS_TYPEOF(x) BOOST_TYPEOF(x) | ||||
#else | #else | |||
# error "No useful C++0x auto/decltype/typeof method for this compiler " | # define CPPCMS_TYPEOF(x) automatic_type_identification_is_not_support ed_by_this_compiler | |||
#endif | #endif | |||
#endif | #endif | |||
End of changes. 24 change blocks. | ||||
119 lines changed or deleted | 61 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 | |||
config.h | config.h | |||
---|---|---|---|---|
/* config.h. Generated from config.h.in by configure. */ | // | |||
/* config.h.in. Generated from configure.in by autoheader. */ | // Copyright (c) 2010 Artyom Beilis (Tonkikh) | |||
// | ||||
/* "Make embedded version of cppcms library" */ | // Distributed under the Boost Software License, Version 1.0. (See | |||
/* #undef CPPCMS_EMBEDDED */ | // accompanying file LICENSE_1_0.txt or copy at | |||
// http://www.boost.org/LICENSE_1_0.txt) | ||||
/* "Embedded with threads" */ | // | |||
/* #undef CPPCMS_EMBEDDED_THREAD */ | #ifndef BOOSTER_CONFIG_H | |||
#define BOOSTER_CONFIG_H | ||||
/* "Enable encrypted sessions" */ | ||||
#define EN_ENCR_SESSIONS | ||||
/* "Fastcgi headers in fastcgi dir" */ | ||||
/* #undef EN_FASTCGI_LONG_PATH */ | ||||
/* "Enable fastcgi backend" */ | ||||
#define EN_FCGI_BACKEND | ||||
/* "Enable fork cache" */ | ||||
#define EN_FORK_CACHE | ||||
/* "Enable sqlite sessions" */ | ||||
#define EN_SQLITE_SESSIONS | ||||
/* "Enable tcp cache" */ | ||||
#define EN_TCP_CACHE | ||||
/* "Have C++0x auto" */ | ||||
/* #undef HAVE_CPP_0X_AUTO */ | ||||
/* "Have C++0x decltype" */ | ||||
/* #undef HAVE_CPP_0X_DECLTYPE */ | ||||
/* Define to 1 if you have the <dlfcn.h> header file. */ | ||||
#define HAVE_DLFCN_H 1 | ||||
/* "Can use $ in indentifiers" */ | ||||
#define HAVE_DOLLAR_SIGN | ||||
/* "Have g++ typeof" */ | ||||
#define HAVE_GCC_TYPEOF | ||||
/* Define to 1 if you have the <inttypes.h> header file. */ | ||||
#define HAVE_INTTYPES_H 1 | ||||
/* Define to 1 if you have the <memory.h> header file. */ | ||||
#define HAVE_MEMORY_H 1 | ||||
/* "Have Pshared" */ | ||||
#define HAVE_PTHREADS_PSHARED | ||||
/* Define to 1 if you have the <stdint.h> header file. */ | ||||
#define HAVE_STDINT_H 1 | ||||
/* Define to 1 if you have the <stdlib.h> header file. */ | ||||
#define HAVE_STDLIB_H 1 | ||||
/* Define to 1 if you have the <strings.h> header file. */ | ||||
#define HAVE_STRINGS_H 1 | ||||
/* Define to 1 if you have the <string.h> header file. */ | ||||
#define HAVE_STRING_H 1 | ||||
/* Define to 1 if you have the <sys/stat.h> header file. */ | ||||
#define HAVE_SYS_STAT_H 1 | ||||
/* Define to 1 if you have the <sys/types.h> header file. */ | ||||
#define HAVE_SYS_TYPES_H 1 | ||||
/* "Have g++ typeof" */ | #if defined(__WIN32) || defined(_WIN32) || defined(WIN32) || defined(__CYGW | |||
#define HAVE_UNDERSCORE_TYPEOF | IN__) | |||
# if defined(DLL_EXPORT) | ||||
# if defined(BOOSTER_SOURCE) | ||||
# define BOOSTER_API __declspec(dllexport) | ||||
# else | ||||
# define BOOSTER_API __declspec(dllimport) | ||||
# endif | ||||
# else | ||||
# define BOOSTER_API | ||||
# endif | ||||
#else // ELF BINARIES | ||||
# if defined(BOOSTER_SOURCE) && defined(BOOSTER_VISIBILITY_SUPPORT) | ||||
# define BOOSTER_API __attribute__ ((visibility("default"))) | ||||
# else | ||||
# define BOOSTER_API | ||||
# endif | ||||
#endif | ||||
/* Define to 1 if you have the <unistd.h> header file. */ | #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32)) && !defined(__C | |||
#define HAVE_UNISTD_H 1 | YGWIN__) | |||
#define BOOSTER_WIN_NATIVE | ||||
#endif | ||||
/* "Have working BOOST_TYPEOF" */ | #if defined(__CYGWIN__) | |||
#define HAVE_WORKING_BOOST_TYPEOF | #define BOOSTER_CYGWIN | |||
#endif | ||||
/* Name of package */ | #if defined(BOOSTER_WIN_NATIVE) || defined(BOOSTER_CYGWIN) | |||
#define PACKAGE "cppcms" | #define BOOSTER_WIN32 | |||
#endif | ||||
/* Define to the address where bug reports for this package should be sent. | #if !defined(BOOSTER_WIN_NATIVE) | |||
*/ | #define BOOSTER_POSIX | |||
#define PACKAGE_BUGREPORT "artyomtnk@yahoo.com" | #endif | |||
/* Define to the full name of this package. */ | #if defined(_MSC_VER) | |||
#define PACKAGE_NAME "cppcms" | #define BOOSTER_MSVC | |||
// This warning is really not revevant | ||||
#pragma warning (disable: 4275 4251) | ||||
#endif | ||||
/* Define to the full name and version of this package. */ | #undef BOOSTER_HAS_CHAR16_T | |||
#define PACKAGE_STRING "cppcms 0.0.8" | #undef BOOSTER_HAS_CHAR32_T | |||
#undef BOOSTER_NO_STD_WSTRING | ||||
#undef BOOST_NO_SWPRINTF | ||||
/* Define to the one symbol short name of this package. */ | #ifdef __GNUC__ | |||
#define PACKAGE_TARNAME "cppcms" | # define BOOSTER_GCC | |||
#endif | ||||
/* Define to the version of this package. */ | #if defined(__GNUC__) && __GNUC__ < 4 | |||
#define PACKAGE_VERSION "0.0.8" | # define BOOSTER_GCC3 | |||
#endif | ||||
/* Define to 1 if you have the ANSI C header files. */ | #if defined(__CYGWIN__) || (defined(BOOSTER_WIN32) && defined(BOOSTER_GCC3) | |||
#define STDC_HEADERS 1 | ) | |||
# define BOOSTER_NO_STD_WSTRING | ||||
#endif | ||||
/* "Use boost::asio" */ | #if defined(BOOSTER_WIN32) && defined(BOOSTER_GCC) | |||
/* #undef USE_BOOST_ASIO */ | # define BOOST_NO_SWPRINTF | |||
#endif | ||||
/* Version number of package */ | #endif /// BOOSTER_CONFIG_H | |||
#define VERSION "0.0.8" | ||||
End of changes. 13 change blocks. | ||||
91 lines changed or deleted | 62 lines changed or added | |||
cppcms_error.h | cppcms_error.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_ERROR_H | #ifndef CPPCMS_ERROR_H | |||
#define CPPCMS_ERROR_H | #define CPPCMS_ERROR_H | |||
#include <cppcms/defs.h> | ||||
#include <string> | #include <string> | |||
#include <stdexcept> | #include <stdexcept> | |||
namespace cppcms { | namespace cppcms { | |||
class cppcms_error : public std::runtime_error { | /// | |||
/// \brief Exception thrown by CppCMS framework. | ||||
/// | ||||
/// Every exception that is thrown from CppCMS modules derived from this ex | ||||
ception. | ||||
/// | ||||
class CPPCMS_API cppcms_error : public std::runtime_error { | ||||
std::string strerror(int err); | std::string strerror(int err); | |||
public: | public: | |||
/// | ||||
/// Create an object with error code err (errno) and a message \a er | ||||
ror | ||||
/// | ||||
cppcms_error(int err,std::string const &error); | cppcms_error(int err,std::string const &error); | |||
/// | ||||
/// Create an object with message \a error | ||||
/// | ||||
cppcms_error(std::string const &error) : std::runtime_error(error) { }; | cppcms_error(std::string const &error) : std::runtime_error(error) { }; | |||
}; | }; | |||
} | } | |||
#endif /* _HTTP_ERROR_H */ | #endif /* _HTTP_ERROR_H */ | |||
End of changes. 5 change blocks. | ||||
1 lines changed or deleted | 38 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_api.h | session_api.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_API_H | #ifndef CPPCMS_SESSION_API_H | |||
#define CPPCMS_SESSION_API_H | #define CPPCMS_SESSION_API_H | |||
#include <boost/noncopyable.hpp> | ||||
#include <cppcms/defs.h> | ||||
#include <booster/noncopyable.h> | ||||
#include <booster/shared_ptr.h> | ||||
#include <string> | #include <string> | |||
namespace cppcms { | namespace cppcms { | |||
class worker_thread; | ||||
class session_interface; | class session_interface; | |||
class session_api : private boost::noncopyable { | /// | |||
/// \brief This class represents the most generic implementation of session | ||||
storage device | ||||
/// | ||||
/// This classes are created using session_api_factory and are designed to | ||||
be reimplemented by users | ||||
/// to provide an additional backends. | ||||
/// | ||||
/// This class is most generic that does not provide any goodies with excep | ||||
tion of setting or getting session cookie, | ||||
/// the user should generally take a look on sessions::session_storage or s | ||||
essions::encryptor for easier implementation of session storage | ||||
/// | ||||
/// Note: these objects must be thread safe. | ||||
/// | ||||
class session_api : public booster::noncopyable | ||||
{ | ||||
public: | public: | |||
virtual void save(session_interface *,std::string const &data,time_t | /// | |||
timeout, bool new_data) = 0; | /// Save session's data: | |||
virtual bool load(session_interface *,std::string &data,time_t &time | /// | |||
out) = 0; | /// \param iface - the session_interface object that allows set sess | |||
virtual void clear(session_interface *) = 0; | ion cookie | |||
virtual ~session_api(){}; | /// \param data - the data that should be stored in the session | |||
/// \param timeout - the absolute expiration POSIX time | ||||
/// \param new_data - flag that marks that new session object should | ||||
be created regardless of current cookie value | ||||
/// \param on_server - flag that marks that the data must be stored | ||||
on the server and not in cookies only | ||||
/// | ||||
virtual void save(session_interface &iface,std::string const &data,t | ||||
ime_t timeout, bool new_data, bool on_server) = 0; | ||||
/// | ||||
/// Load session's data | ||||
/// | ||||
/// \param iface - the session_interface object that allows read and | ||||
set session cookie | ||||
/// \param data - the string that should be filled with session data | ||||
/// \param timeout - the expiration time of this session object | ||||
/// \return true of session was loaded, false otherwise | ||||
virtual bool load(session_interface &iface,std::string &data,time_t | ||||
&timeout) = 0; | ||||
/// | ||||
/// Remove the session object | ||||
/// | ||||
/// \param iface - the session_interface object that allows read and | ||||
set session cookie | ||||
/// | ||||
virtual void clear(session_interface &iface) = 0; | ||||
/// | ||||
/// Destructor | ||||
/// | ||||
virtual ~session_api() {} | ||||
}; | ||||
/// | ||||
/// \brief the factory object that generates custom implemented session_api | ||||
objects | ||||
/// | ||||
class session_api_factory { | ||||
public: | ||||
/// | ||||
/// Return true if this session API requires Garbage collection: i.e | ||||
. execution of special function time to time | ||||
/// to clear expired sessions from the memory | ||||
/// | ||||
virtual bool requires_gc() = 0; | ||||
/// | ||||
/// The actual garbage collection job (may do nothing). | ||||
/// | ||||
virtual void gc() = 0; | ||||
/// | ||||
/// Return a pointer to the session_api object. Note it may be share | ||||
d between multiple requests or may be created each time per request | ||||
/// | ||||
virtual booster::shared_ptr<session_api> get() = 0; | ||||
/// | ||||
/// Destructor and cleanup function | ||||
/// | ||||
virtual ~session_api_factory() {} | ||||
}; | }; | |||
} // cppcms | } // cppcms | |||
#endif | #endif | |||
End of changes. 5 change blocks. | ||||
9 lines changed or deleted | 109 lines changed or added | |||
session_cookies.h | session_cookies.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_COOKIES_H | #ifndef CPPCMS_SESSION_COOKIES_H | |||
#define CPPCMS_SESSION_COOKIES_H | #define CPPCMS_SESSION_COOKIES_H | |||
#include "session_api.h" | #include <cppcms/session_api.h> | |||
#include <booster/hold_ptr.h> | ||||
#include <booster/noncopyable.h> | ||||
#include <memory> | #include <memory> | |||
#include <string> | #include <string> | |||
#include "session_backend_factory.h" | ||||
namespace cppcms { | namespace cppcms { | |||
class encryptor; | ||||
class worker_thread; | ||||
class session_interface; | class session_interface; | |||
class session_cookies : public session_api { | /// | |||
worker_thread &worker; | /// \brief this namespace keeps various session storage backends | |||
std::auto_ptr<encryptor> encr; | /// | |||
public: | namespace sessions { | |||
static session_backend_factory factory(); | ||||
session_cookies(worker_thread &w); | /// | |||
session_cookies(worker_thread &w,std::auto_ptr<encryptor>); | /// \brief This is an interface to generic session cookies encryptio | |||
virtual void save(session_interface *,std::string const &data,time_t | n or signing API. | |||
timeout,bool ); | /// | |||
virtual bool load(session_interface *,std::string &data,time_t &time | /// Note for users implementing their own ecryptor classes: | |||
out); | /// | |||
virtual void clear(session_interface *); | /// - Be super paranoid and extremely careful in what you are doing. | |||
}; | /// - Take in mind that this object are created and destroyed much f | |||
requently then they are actually | ||||
/// accessed, so lazy initialization is your best friend. | ||||
/// | ||||
/// Note this class does not have to be thread safe to use from mult | ||||
iple threads. | ||||
/// | ||||
class encryptor : public booster::noncopyable { | ||||
public: | ||||
/// | ||||
/// Encrypt or sign the plain text \a plain together with \a | ||||
timeout and return the encrypted value for a cookie. | ||||
/// Don't forget to use base64 encoding in order to create a | ||||
string that is valid for cookie | ||||
/// | ||||
virtual std::string encrypt(std::string const &plain,time_t | ||||
timeout) = 0; | ||||
/// | ||||
/// Decrypt the \a cipher text or check the signature and re | ||||
turn the \a plain text and the session expiration value: \a timeout. | ||||
/// | ||||
/// If signature checks or decryption failed return false. | ||||
/// | ||||
virtual bool decrypt(std::string const &cipher,std::string & | ||||
plain,time_t *timeout = 0) = 0; | ||||
/// | ||||
/// Destructor | ||||
/// | ||||
virtual ~encryptor() {} | ||||
}; | ||||
/// | ||||
/// \brief This is an interface for an object that creates new encry | ||||
ptors | ||||
/// | ||||
/// This class must be thread safe. | ||||
/// | ||||
class encryptor_factory { | ||||
public: | ||||
/// | ||||
/// Return a pointer to a newly created encryptor. | ||||
/// | ||||
virtual std::auto_ptr<encryptor> get() = 0; | ||||
/// | ||||
/// Destructor - cleanup everything | ||||
/// | ||||
virtual ~encryptor_factory() {} | ||||
}; | ||||
/// | ||||
/// The implementation of session_api using encrypted or signed cook | ||||
ies | ||||
/// | ||||
class CPPCMS_API session_cookies : public session_api { | ||||
public: | ||||
/// | ||||
/// Create a new object passing it a pointer ecryptor as par | ||||
ameter | ||||
/// | ||||
session_cookies(std::auto_ptr<encryptor> encryptor); | ||||
/// | ||||
/// Destroy it and destroy an encryptor it was created with | ||||
/// | ||||
~session_cookies(); | ||||
/// | ||||
/// Save session to cookies, see session_api::save | ||||
/// | ||||
virtual void save(session_interface &,std::string const &dat | ||||
a,time_t timeout,bool newone ,bool on_server); | ||||
/// | ||||
/// Load session from cookies, see session_api::load | ||||
/// | ||||
virtual bool load(session_interface &,std::string &data,time | ||||
_t &timeout); | ||||
/// | ||||
/// Delete session, see session_api::clear | ||||
/// | ||||
virtual void clear(session_interface &); | ||||
private: | ||||
struct _data; | ||||
booster::hold_ptr<_data> d; | ||||
std::auto_ptr<encryptor> encryptor_; | ||||
}; | ||||
} // sessions | ||||
} // cppcms | } // cppcms | |||
#endif | #endif | |||
End of changes. 6 change blocks. | ||||
19 lines changed or deleted | 122 lines changed or added | |||
session_dual.h | session_dual.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_DUAL_H | #ifndef CPPCMS_SESSION_DUAL_H | |||
#define CPPCMS_SESSION_DUAL_H | #define CPPCMS_SESSION_DUAL_H | |||
#include "session_api.h" | #include <cppcms/session_api.h> | |||
#include "session_backend_factory.h" | #include <cppcms/defs.h> | |||
#include <boost/shared_ptr.hpp> | #include <booster/hold_ptr.h> | |||
#include <booster/shared_ptr.h> | ||||
#include <memory> | ||||
namespace cppcms { | namespace cppcms { | |||
namespace sessions { | ||||
class session_dual : public session_api { | class session_storage; | |||
boost::shared_ptr<session_api> client; | class session_sid; | |||
boost::shared_ptr<session_api> server; | class session_cookies; | |||
size_t limit; | class encryptor; | |||
public: | ||||
static session_backend_factory factory(session_backend_factory c,ses | ||||
sion_backend_factory s,size_t l); | ||||
session_dual(boost::shared_ptr<session_api> c,boost::shared_ptr<sess | ||||
ion_api> s,size_t l) : | ||||
client(c), | ||||
server(s), | ||||
limit(l) | ||||
{ | ||||
} | ||||
virtual void save(session_interface *,std::string const &data,time_t | ||||
timeout,bool new_session); | ||||
virtual bool load(session_interface *,std::string &data,time_t &time | ||||
out); | ||||
virtual void clear(session_interface *); | ||||
/// | ||||
/// \brief Client and Server side storage implementation of session_api | ||||
/// | ||||
class CPPCMS_API session_dual : public session_api { | ||||
public: | ||||
/// | ||||
/// Create a new object using encryptor \a enc and session_storage \ | ||||
a storage. | ||||
/// \a data_size_limit represents the maximal data size that can be | ||||
stored on client side, if the data size is bigger then that | ||||
/// the session data will be stored on server | ||||
/// | ||||
session_dual( std::auto_ptr<encryptor> enc, | ||||
booster::shared_ptr<session_storage> storage, | ||||
size_t data_size_limit); | ||||
/// | ||||
/// Destroy the object: release pointer to \a storage and delete an | ||||
encryptor it was created with. | ||||
/// | ||||
virtual ~session_dual(); | ||||
/// | ||||
/// See session_api::save | ||||
/// | ||||
virtual void save(session_interface &,std::string const &data,time_t | ||||
timeout,bool new_session,bool on_server); | ||||
/// | ||||
/// See session_api::load | ||||
/// | ||||
virtual bool load(session_interface &,std::string &data,time_t &time | ||||
out); | ||||
/// | ||||
/// See session_api::clear | ||||
/// | ||||
virtual void clear(session_interface &); | ||||
private: | ||||
struct _data; | ||||
booster::hold_ptr<_data> d; | ||||
booster::shared_ptr<session_cookies> client_; | ||||
booster::shared_ptr<session_sid> server_; | ||||
size_t data_size_limit_; | ||||
}; | }; | |||
} | } // sessions | |||
} // cppcms | ||||
#endif | #endif | |||
End of changes. 6 change blocks. | ||||
23 lines changed or deleted | 74 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 | |||
session_sid.h | session_sid.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_SID_H | #ifndef CPPCMS_SESSION_SID_H | |||
#define CPPCMS_SESSION_SID_H | #define CPPCMS_SESSION_SID_H | |||
#include <sys/time.h> | #include <cppcms/session_api.h> | |||
#include <boost/shared_ptr.hpp> | #include <cppcms/defs.h> | |||
#include "session_api.h" | #include <booster/hold_ptr.h> | |||
#include <booster/shared_ptr.h> | ||||
#include <stdint.h> | #include <cppcms/session_storage.h> | |||
#include <stdio.h> | ||||
namespace cppcms { | namespace cppcms { | |||
namespace sessions { | ||||
class session_server_storage; | namespace impl { class sid_generator; } | |||
class session_interface; | ||||
namespace details { | /// | |||
class sid_generator : public boost::noncopyable { | /// \brief An implementation of session_api that stores the data usi | |||
struct for_hash { | ng session_storage and unique session id. | |||
char uid[16]; | /// | |||
uint64_t session_counter; | class CPPCMS_API session_sid : public session_api { | |||
struct timeval tv; | public: | |||
} hashed; | /// | |||
public: | /// Create a new session_sid with a pointer \a s to session_ | |||
sid_generator(); | storage | |||
std::string operator()(); | /// | |||
}; | session_sid(booster::shared_ptr<session_storage> s); | |||
} | /// | |||
/// Delete an object and release a session_storage it used. | ||||
/// | ||||
~session_sid(); | ||||
/// | ||||
/// See session_api::save | ||||
/// | ||||
virtual void save(session_interface &,std::string const &dat | ||||
a,time_t timeout,bool,bool); | ||||
/// | ||||
/// See session_api::load | ||||
/// | ||||
virtual bool load(session_interface &,std::string &data,time | ||||
_t &timeout); | ||||
/// | ||||
/// See session_api::clear | ||||
/// | ||||
virtual void clear(session_interface &); | ||||
private: | ||||
class session_sid : public session_api { | bool valid_sid(std::string const &cookie,std::string &id); | |||
details::sid_generator sid; | std::string key(std::string sid); | |||
boost::shared_ptr<session_server_storage> storage; | ||||
bool cache; | ||||
std::string key(std::string sid); | ||||
public: | ||||
bool valid_sid(std::string const &str); | ||||
session_sid(boost::shared_ptr<session_server_storage> s,bool c=false | ||||
) : | ||||
storage(s), | ||||
cache(c) | ||||
{ | ||||
} | ||||
virtual void save(session_interface *,std::string const &data,time_t | ||||
timeout,bool); | ||||
virtual bool load(session_interface *,std::string &data,time_t &time | ||||
out); | ||||
virtual void clear(session_interface *); | ||||
}; | struct _data; | |||
} | booster::hold_ptr<_data> d; | |||
booster::shared_ptr<session_storage> storage_; | ||||
}; | ||||
} // sessions | ||||
} // cppcms | ||||
#endif | #endif | |||
End of changes. 7 change blocks. | ||||
40 lines changed or deleted | 68 lines changed or added | |||
session_storage.h | session_storage.h | |||
---|---|---|---|---|
#ifndef SESSION_STORAGE_H | /////////////////////////////////////////////////////////////////////////// | |||
#define SESSION_STORAGE_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_STORAGE_H | ||||
#define CPPCMS_SESSION_STORAGE_H | ||||
#include <boost/noncopyable.hpp> | #include <cppcms/defs.h> | |||
#include <boost/function.hpp> | #include <booster/noncopyable.h> | |||
#include <booster/shared_ptr.h> | ||||
#include <string> | #include <string> | |||
namespace cppcms { | namespace cppcms { | |||
namespace sessions { | ||||
class session_server_storage : private boost::noncopyable { | /// | |||
public: | /// \a session_server_storage is an abstract class that allows user | |||
virtual void save(std::string const &sid,time_t timeout,std::string | to implements | |||
const &in) = 0; | /// custom session storage device like, database storage device | |||
virtual bool load(std::string const &sid,time_t *timeout,std::string | /// | |||
&out) = 0; | /// Note: if the member functions save/load/remove are thread safe - | |||
virtual void remove(std::string const &sid) = 0; | - can be called | |||
virtual ~session_server_storage() | /// from different threads, than you may create a single session and | |||
{ | return \a shared_ptr | |||
} | /// to a single instance, otherwise you have to create multiple inst | |||
}; | ances of object | |||
/// | ||||
class empty_session_server_storage :public session_server_storage | class session_storage : public booster::noncopyable | |||
{ | ||||
public: | ||||
void save(std::string const &sid,time_t timeout,std::string const &i | ||||
n) | ||||
{ | ||||
} | ||||
bool load(std::string const &sid,time_t *timeout,std::string &out) | ||||
{ | ||||
return false; | ||||
} | ||||
void remove(std::string const &sid) | ||||
{ | { | |||
} | public: | |||
}; | /// | |||
/// Save session with end of life time at \a timeout using s | ||||
ession id \a sid and content \a in | ||||
/// | ||||
virtual void save(std::string const &sid,time_t timeout,std: | ||||
:string const &in) = 0; | ||||
/// | ||||
/// Load session with \a sid, put its end of life time to \a | ||||
timeout and return its | ||||
/// value to \a out | ||||
/// | ||||
virtual bool load(std::string const &sid,time_t &timeout,std | ||||
::string &out) = 0; | ||||
/// | ||||
/// Remove a session with id \a sid from the storage | ||||
/// | ||||
virtual void remove(std::string const &sid) = 0; | ||||
/// | ||||
/// Destroy an object | ||||
/// | ||||
virtual ~session_storage() | ||||
{ | ||||
} | ||||
}; | ||||
/// | ||||
/// \brief The factory is an interface to a factory that creates ses | ||||
sion_storage objects, it should be thread safe. | ||||
/// | ||||
class session_storage_factory { | ||||
public: | ||||
/// | ||||
/// Get a pointer to session_storage. Note if the returned p | ||||
ointer is same for different calls | ||||
/// session_storage implementation should be thread safe. | ||||
/// | ||||
virtual booster::shared_ptr<session_storage> get() = 0; | ||||
/// | ||||
/// Return true if session_storage requires garbage collecti | ||||
on - removal of expired session time-to-time | ||||
/// | ||||
virtual bool requires_gc() = 0; | ||||
/// | ||||
/// Actual garbage collection job (if required). If requires | ||||
_gc returns true it will be called once-in-a-while to remove | ||||
/// all expired objects from the DB. | ||||
/// | ||||
virtual void gc_job() {} | ||||
/// | ||||
/// Delete the object, cleanup | ||||
/// | ||||
virtual ~session_storage_factory() {} | ||||
}; | ||||
} // sessions | ||||
} // cppcms | } // cppcms | |||
#endif | #endif | |||
End of changes. 7 change blocks. | ||||
29 lines changed or deleted | 102 lines changed or added | |||
util.h | util.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_UTIL_H | #ifndef CPPCMS_UTIL_H | |||
#define CPPCMS_UTIL_H | #define CPPCMS_UTIL_H | |||
#include <cppcms/defs.h> | ||||
#include <string> | #include <string> | |||
namespace cppcms { | namespace cppcms { | |||
std::string escape(std::string const &s); | ||||
std::string urlencode(std::string const &s); | /// | |||
/// \brief This namespace holds various useful helper functions for | ||||
we developer | ||||
/// | ||||
namespace util { | ||||
/// | ||||
/// Escape string for inclusion in HTML page, i.e. | ||||
/// | ||||
/// - < - \< | ||||
/// - > - \> | ||||
/// - \& - \& | ||||
/// - " - \" | ||||
/// | ||||
/// Note, this function does not deal with encodings, so it' | ||||
s up to you to | ||||
/// provide valid text encoding | ||||
/// | ||||
std::string CPPCMS_API escape(std::string const &s); | ||||
/// | ||||
/// Encode string for URL (percent encoding) | ||||
/// | ||||
std::string CPPCMS_API urlencode(std::string const &s); | ||||
/// | ||||
/// Decode string from URL-encoding (percent-encoding) | ||||
/// | ||||
std::string CPPCMS_API urldecode(std::string const &s); | ||||
/// | ||||
/// Decode text in range [begin,end) from URL-encoding (perc | ||||
ent-encoding) | ||||
/// | ||||
std::string CPPCMS_API urldecode(char const *begin,char cons | ||||
t *end); | ||||
/// | ||||
/// Make MD5 hash of string \a input converting into binary | ||||
string of 16 bytes | ||||
/// | ||||
std::string CPPCMS_API md5(std::string const &input); | ||||
/// | ||||
/// Make MD5 hash of string \a input converting it into hexa | ||||
decimal string representing this hash | ||||
/// | ||||
std::string CPPCMS_API md5hex(std::string const &input); | ||||
} | ||||
} | } | |||
#endif | #endif | |||
End of changes. 4 change blocks. | ||||
2 lines changed or deleted | 71 lines changed or added | |||