diff --git a/Makefile.am b/Makefile.am index 6be15ed..b60c26a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -50,7 +50,8 @@ libcppcms_la_SOURCES = \ aio_timer.cpp \ json.cpp \ encoding.cpp \ - locale_charset.cpp + locale_charset.cpp \ + form.cpp cppcms_config_find_param_SOURCES=cppcms_config_find_param.cpp json.cpp diff --git a/base_view.h b/base_view.h index 3cc213c..71f8a39 100644 --- a/base_view.h +++ b/base_view.h @@ -87,6 +87,25 @@ private: template<> void CPPCMS_API base_view::escape(std::ostream &,std::string const &s); +#ifdef HAVE_STD_WSTRING +template<> +void CPPCMS_API base_view::escape(std::ostream &,std::wstring const &s); +#endif + +#ifdef HAVE_CPP0X_UXSTRING +template<> +void CPPCMS_API base_view::escape(std::ostream &,std::u16string const &s); +template<> +void CPPCMS_API base_view::escape(std::ostream &,std::u32string const &s); +#endif + +#ifdef HAVE_ICU +template<> +void CPPCMS_API base_view::escape(std::ostream &,icu::UnicodeString const &s); +#endif + + + void CPPCMS_API operator<<(std::ostream &,std::tm const &t); namespace details { diff --git a/config.js b/config.js index 496220e..c86c5df 100644 --- a/config.js +++ b/config.js @@ -7,7 +7,7 @@ "procs" : 0, "worker_threads": 5, "api" : "http", - "port" : 8001, + "port" : 8080, // "ip" : "0.0.0.0" "ip" : "127.0.0.1" // "socket" : "/tmp/scgi.socket" @@ -30,11 +30,13 @@ // "buffer" : 4096 }, "locale" : { - "locales" : [ "he_IL.UTF-8", "en_US.UTF-8" ], // list of supported languages + "locales" : [ "he_IL.UTF-8", "en_US.UTF-8", "he_IL.ISO-8859-8" ], // list of supported languages + //"default" : "he_IL.ISO-8859-8", // default language (default first one) "default" : "he_IL.UTF-8", // default language (default first one) "gettext_domains" : [ "app", "test" ], // list of supported domains "default_gettext_domain" : "test", // default domain (default first one) - "gettext_path" : "./transtext/locale" // path to locale directory + "gettext_path" : "./transtext/locale", // path to locale directory + "disable_charset_in_content_type" : false // Disable }, "session" : { "expire" : "browser", diff --git a/encoding.cpp b/encoding.cpp index 1d7a257..9a44c9c 100644 --- a/encoding.cpp +++ b/encoding.cpp @@ -71,10 +71,11 @@ namespace cppcms { namespace encoding { if(descriptor_!=(iconv_t)(-1)) iconv_close(descriptor_); } - bool check_symbols(uint32_t const *begin,uint32_t const *end) + bool check_symbols(uint32_t const *begin,uint32_t const *end,size_t &count) { while(begin!=end) { uint32_t c=*begin++; + count++; if(c==0x09 || c==0xA || c==0xD) continue; if(c<0x20 || (0x7F<=c && c<=0x9F)) @@ -83,7 +84,7 @@ namespace cppcms { namespace encoding { return true; } - bool valid(char const *begin,char const *end) + bool valid(char const *begin,char const *end,size_t &count) { iconv(descriptor_,0,0,0,0); // reset uint32_t buffer[64]; @@ -95,12 +96,12 @@ namespace cppcms { namespace encoding { size_t res=do_iconv(::iconv,descriptor_,&begin,&input,(char**)&output,&outsize); if(res==(size_t)(-1) && errno==E2BIG) { - if(!check_symbols(buffer,output)) + if(!check_symbols(buffer,output,count)) return false; continue; } if(res!=(size_t)(-1) && input==0) - return check_symbols(buffer,output); + return check_symbols(buffer,output,count); return false; } return true; @@ -144,15 +145,15 @@ namespace cppcms { namespace encoding { delete iconv_; } - bool validator::valid(std::string const &s) + bool validator::valid(std::string const &s,size_t &count) { - return valid(s.data(),s.data()+s.size()); + return valid(s.data(),s.data()+s.size(),count); } - bool validator::valid(char const *begin,char const *end) + bool validator::valid(char const *begin,char const *end,size_t &count) { if(tester_) - return tester_(begin,end); - return iconv_->valid(begin,end); + return tester_(begin,end,count); + return iconv_->valid(begin,end,count); } struct validators_set::data {}; diff --git a/encoding.h b/encoding.h index 9f12444..87b2ade 100644 --- a/encoding.h +++ b/encoding.h @@ -17,7 +17,7 @@ int cppcms_validator_test_function(); namespace cppcms { namespace encoding { - typedef bool (*encoding_tester_type)(char const *begin,char const *end); + typedef bool (*encoding_tester_type)(char const *begin,char const *end,size_t &count); class iconv_validator; @@ -30,8 +30,8 @@ namespace cppcms { validator const &operator=(validator const &other); - bool valid(char const *begin,char const *end); - bool valid(std::string const &str); + bool valid(char const *begin,char const *end,size_t &count); + bool valid(std::string const &str,size_t &count); ~validator(); private: diff --git a/encoding_validators.h b/encoding_validators.h index 0c3e00a..b5da650 100644 --- a/encoding_validators.h +++ b/encoding_validators.h @@ -6,15 +6,16 @@ namespace cppcms { namespace encoding { template - bool utf8_valid(Iterator p,Iterator e) + bool utf8_valid(Iterator p,Iterator e,size_t &count) { - return utf8::validate(p,e,true); + return utf8::validate(p,e,count,true); } template - bool ascii_valid(Iterator p,Iterator e) + bool ascii_valid(Iterator p,Iterator e,size_t &count) { while(p!=e) { + count++; unsigned c=(unsigned char)*p++; if(c==0x09 || c==0xA || c==0xD) continue; @@ -24,9 +25,10 @@ namespace cppcms { namespace encoding { return true; } template - bool iso_8859_1_2_4_5_9_10_13_14_15_16_valid(Iterator p,Iterator e) + bool iso_8859_1_2_4_5_9_10_13_14_15_16_valid(Iterator p,Iterator e,size_t &count) { while(p!=e) { + count++; unsigned c=(unsigned char)*p++; if(c==0x09 || c==0xA || c==0xD) continue; @@ -36,9 +38,10 @@ namespace cppcms { namespace encoding { return true; } template - bool iso_8859_3_valid(Iterator p,Iterator e) + bool iso_8859_3_valid(Iterator p,Iterator e,size_t &count) { while(p!=e) { + count++; unsigned c=(unsigned char)*p++; if(c==0x09 || c==0xA || c==0xD) continue; @@ -58,9 +61,10 @@ namespace cppcms { namespace encoding { return true; } template - bool iso_8859_6_valid(Iterator p,Iterator e) + bool iso_8859_6_valid(Iterator p,Iterator e,size_t &count) { while(p!=e) { + count++; unsigned c=(unsigned char)*p++; if(c==0x09 || c==0xA || c==0xD) continue; @@ -81,9 +85,10 @@ namespace cppcms { namespace encoding { } template - bool iso_8859_7_valid(Iterator p,Iterator e) + bool iso_8859_7_valid(Iterator p,Iterator e,size_t &count) { while(p!=e) { + count++; unsigned c=(unsigned char)*p++; if(c==0x09 || c==0xA || c==0xD) continue; @@ -100,9 +105,10 @@ namespace cppcms { namespace encoding { } template - bool iso_8859_8_valid(Iterator p,Iterator e) + bool iso_8859_8_valid(Iterator p,Iterator e,size_t &count) { while(p!=e) { + count++; unsigned c=(unsigned char)*p++; if(c==0x09 || c==0xA || c==0xD) continue; @@ -122,9 +128,10 @@ namespace cppcms { namespace encoding { } template - bool iso_8859_11_valid(Iterator p,Iterator e) + bool iso_8859_11_valid(Iterator p,Iterator e,size_t &count) { while(p!=e) { + count++; unsigned c=(unsigned char)*p++; if(c==0x09 || c==0xA || c==0xD) continue; @@ -146,9 +153,10 @@ namespace cppcms { namespace encoding { } template - bool windows_1250_valid(Iterator p,Iterator e) + bool windows_1250_valid(Iterator p,Iterator e,size_t &count) { while(p!=e) { + count++; unsigned c=(unsigned char)*p++; if(c==0x09 || c==0xA || c==0xD) continue; @@ -166,9 +174,10 @@ namespace cppcms { namespace encoding { return true; } template - bool windows_1251_valid(Iterator p,Iterator e) + bool windows_1251_valid(Iterator p,Iterator e,size_t &count) { while(p!=e) { + count++; unsigned c=(unsigned char)*p++; if(c==0x09 || c==0xA || c==0xD) continue; @@ -178,9 +187,10 @@ namespace cppcms { namespace encoding { return true; } template - bool windows_1252_valid(Iterator p,Iterator e) + bool windows_1252_valid(Iterator p,Iterator e,size_t &count) { while(p!=e) { + count++; unsigned c=(unsigned char)*p++; if(c==0x09 || c==0xA || c==0xD) continue; @@ -198,9 +208,10 @@ namespace cppcms { namespace encoding { return true; } template - bool windows_1253_valid(Iterator p,Iterator e) + bool windows_1253_valid(Iterator p,Iterator e,size_t &count) { while(p!=e) { + count++; unsigned c=(unsigned char)*p++; if(c==0x09 || c==0xA || c==0xD) continue; @@ -231,9 +242,10 @@ namespace cppcms { namespace encoding { } template - bool windows_1254_valid(Iterator p,Iterator e) + bool windows_1254_valid(Iterator p,Iterator e,size_t &count) { while(p!=e) { + count++; unsigned c=(unsigned char)*p++; if(c==0x09 || c==0xA || c==0xD) continue; @@ -254,9 +266,10 @@ namespace cppcms { namespace encoding { } template - bool windows_1255_valid(Iterator p,Iterator e) + bool windows_1255_valid(Iterator p,Iterator e,size_t &count) { while(p!=e) { + count++; unsigned c=(unsigned char)*p++; if(c==0x09 || c==0xA || c==0xD) continue; @@ -296,9 +309,10 @@ namespace cppcms { namespace encoding { } template - bool windows_1256_valid(Iterator p,Iterator e) + bool windows_1256_valid(Iterator p,Iterator e,size_t &count) { while(p!=e) { + count++; unsigned c=(unsigned char)*p++; if(c==0x09 || c==0xA || c==0xD) continue; @@ -308,9 +322,10 @@ namespace cppcms { namespace encoding { return true; } template - bool windows_1257_valid(Iterator p,Iterator e) + bool windows_1257_valid(Iterator p,Iterator e,size_t &count) { while(p!=e) { + count++; unsigned c=(unsigned char)*p++; if(c==0x09 || c==0xA || c==0xD) continue; @@ -336,9 +351,10 @@ namespace cppcms { namespace encoding { } template - bool windows_1258_valid(Iterator p,Iterator e) + bool windows_1258_valid(Iterator p,Iterator e,size_t &count) { while(p!=e) { + count++; unsigned c=(unsigned char)*p++; if(c==0x09 || c==0xA || c==0xD) continue; @@ -360,9 +376,10 @@ namespace cppcms { namespace encoding { return true; } template - bool koi8_valid(Iterator p,Iterator e) + bool koi8_valid(Iterator p,Iterator e,size_t &count) { while(p!=e) { + count++; unsigned c=(unsigned char)*p++; if(c==0x09 || c==0xA || c==0xD) continue; diff --git a/form.cpp b/form.cpp index 54d7394..3a9df38 100644 --- a/form.cpp +++ b/form.cpp @@ -1,10 +1,10 @@ #define CPPCMS_SOURCE #include "form.h" -#include "util.h" - -#include #include -#include "cppcms_error.h" +#include +#include +#include "locale_charset.h" +#include "locale_environment.h" namespace cppcms { @@ -50,8 +50,7 @@ bool form::validate() { bool result=true; for(unsigned int i=0;ivalidate()) - result=false; + result = elements_[i].first->validate() & result; } return result; } @@ -63,14 +62,23 @@ void form::clear() } } -void form::add(base_form &subform) +void form::add(widgets::base_widget &form) +{ + elements_.push_back(widget_type(&form,false)); +} +void form::add(form &subform) +{ + elements_.push_back(widget_type(&subform,false)); +} + +void form::attach(form *subform) { - elements_.push_back(std::make_pair(&subform,false)); + elements_.push_back(widget_type(subform,true)); } -void form::attach(base_form *subform) +void form::attach(widgets::base_widget *subform) { - elements_.push_back(std::make_pair(subform,true)); + elements_.push_back(widget_type(subform,true)); } struct form::iterator::data { @@ -97,9 +105,9 @@ form::iterator const &form::iterator::operator=(form::iterator const &other) return *this; } -bool form::iterator::equal(form::iterator const &other) +bool form::iterator::equal(form::iterator const &other) const { - return d->stack == other.d->stack && d->pos=other.d->pos; + return (d->stack == other.d->stack) && (d->pos == other.d->pos); } void form::iterator::next() @@ -113,7 +121,7 @@ void form::iterator::next() form *top=d->stack.top().first; d->pos++; - if((size_t)pos >= top->elements_.size() ) { + if((size_t)d->pos >= top->elements_.size() ) { d->pos=d->stack.top().second; d->stack.pop(); continue; @@ -124,14 +132,14 @@ void form::iterator::next() form &f=dynamic_cast
(*top->elements_[d->pos].first); - d->stack.push_back(std::make_pair(&f,d->pos)); + d->stack.push(std::make_pair(&f,d->pos)); d->pos=-1; } } -form::iterator::pointer_type form::iterator::get() const +widgets::base_widget *form::iterator::get() const { - return static_cast(d->stack.top().first)->elements_[d->pos].first + return static_cast(d->stack.top().first->elements_[d->pos].first); } form::iterator form::begin() @@ -174,13 +182,17 @@ base_widget::base_widget(std::string name) : base_widget::base_widget(std::string name,std::string msg) : name_(name), - msg_(msg), + message_(msg), is_valid_(1), is_set_(0), is_disabled_(0) { } +base_widget::~base_widget() +{ +} + bool base_widget::set() { return is_set_; @@ -244,6 +256,16 @@ void base_widget::attributes_string(std::string v) attr_=v; } +bool base_widget::disabled() +{ + return is_disabled_; +} + +void base_widget::disabled(bool v) +{ + is_disabled_=v; +} + std::string base_widget::attributes_string() { return attr_; @@ -261,10 +283,10 @@ void base_widget::render(std::ostream &output,unsigned int flags) case as_table: output<<""; break; case as_ul: output<<"
  • "; break; case as_dl: output<<"
    "; break; - default; + default: ; } - if(!id().empty() && !msg().empty()) { - output<<" "; + if(!id().empty() && !message().empty()) { + output<<" "; } else { output<<" "; @@ -272,11 +294,11 @@ void base_widget::render(std::ostream &output,unsigned int flags) switch(how) { case as_table: output<<""; break; case as_dl: output<<"
    "; break; - default; + default: ; } if(!valid() && !no_error) { - output<<""< " + output<<""< "; } else { output<<" "; @@ -288,21 +310,21 @@ void base_widget::render(std::ostream &output,unsigned int flags) output<<""; if(!help().empty()) { - output<<""<"; + output<<""<"; } switch(how) { - case as_p: output<<"

    "; break; - case as_table: output<<""; break; - case as_ul: output<<"
  • "; break; - case as_dl: output<<""; break; + case as_p: output<<"

    \n"; break; + case as_table: output<<"\n"; break; + case as_ul: output<<"\n"; break; + case as_dl: output<<"\n"; break; case as_space: if(flags & as_xhtml) - output<<"
    "; + output<<"
    \n"; else - output<<"
    "; + output<<"
    \n"; break; - default; + default: ; } } @@ -318,56 +340,71 @@ bool base_widget::validate() } //////////////////////////////// -// widgets::text +// widgets::base_text //////////////////////////////// -struct text::data {} - +struct base_text::data {}; -text::text() : low_(0),high_(-1),validate_charset_(true) +base_text::base_text() : low_(0),high_(-1),validate_charset_(true) { } -text::text(std::string name) : base_widget(name), low_(0),high_(-1),validate_charset_(true) +base_text::base_text(std::string name) : base_widget(name), low_(0),high_(-1),validate_charset_(true) { } -text::text(std::string name,std::string msg) : base_widget(name,msg), low_(0),high_(-1),validate_charset_(true) +base_text::base_text(std::string name,std::string msg) : base_widget(name,msg), low_(0),high_(-1),validate_charset_(true) { } -text::~text() +base_text::~base_text() { } -std::string text::value() +std::string base_text::value() { if(!set()) throw cppcms_error("Value was not loaded"); return value_; } -void text::value(std::string v) +void base_text::value(std::string v) { set(true); value_=v; } -std::string text::value(std::locale const &v) +std::string base_text::value(std::locale const &v) { return std::use_facet(v).to_utf8(value_); } + +void base_text::value(std::string v,std::locale const &l) +{ + value(std::use_facet(l).from_utf8(v)); +} + #ifdef HAVE_STD_WSTRING -std::string text::value_wstring(std::locale const &v) +std::string base_text::value_wstring() +{ + return locale::charset().to_wstring(value_); +} + +void base_text::value(std::wstring v) +{ + value(locale::charset().from_wstring(v)); +} + +std::string base_text::value_wstring(std::locale const &v) { return std::use_facet(v).to_wstring(value_); } -void text::value(std::wstring v,std::locale const &l) +void base_text::value(std::wstring v,std::locale const &l) { value(std::use_facet(l).from_wstring(v)); } @@ -376,23 +413,45 @@ void text::value(std::wstring v,std::locale const &l) #ifdef HAVE_CPP0X_UXSTRING -std::u16string text::value_u16string(std::locale const &v) +std::u16string base_text::value_u16string() +{ + return locale::charset().to_u16string(value_); +} + +void base_text::value(std::u16string v) +{ + value(locale::charset().from_u16string(v)); +} + + +std::u32string base_text::value_u32string() +{ + return locale::charset().to_u32string(value_); +} + +void base_text::value(std::u32string v) +{ + value(locale::charset().from_u32string(v)); +} + + +std::u16string base_text::value_u16string(std::locale const &v) { return std::use_facet(v).to_u16string(value_); } -void text::value(std::u16string v,std::locale const &l) +void base_text::value(std::u16string v,std::locale const &l) { value(std::use_facet(l).from_u16string(v)); } -std::u32string text::value_u32string(std::locale const &v) +std::u32string base_text::value_u32string(std::locale const &v) { return std::use_facet(v).to_u32string(value_); } -void text::value(std::u32string v,std::locale const &l) +void base_text::value(std::u32string v,std::locale const &l) { value(std::use_facet(l).from_u32string(v)); } @@ -400,36 +459,56 @@ void text::value(std::u32string v,std::locale const &l) #endif #ifdef HAVE_ICU -icu::UnicodeString text::value_icu_string(std::locale const &v) +icu::UnicodeString base_text::value_icu_string() +{ + return locale::charset().to_icu_string(value_); +} +void base_text::value(icu::UnicodeString const &v) +{ + value(locale::charset().from_icu_string(v)); +} + +icu::UnicodeString base_text::value_icu_string(std::locale const &v) { return std::use_facet(v).to_icu_string(value_); } -void text::value(icu::UnicodeString const &v,std::locale const &l) +void base_text::value(icu::UnicodeString const &v,std::locale const &l) { value(std::use_facet(l).from_icu_string(v)); } #endif -void text::non_empty() +void base_text::non_empty() { limits(1,-1); } -void text::limits(int min,int max) +void base_text::limits(int min,int max) { low_=min; high_=max; } -void text::disable_charset_validation() +std::pair base_text::limits() +{ + return std::make_pair(low_,high_); +} + +void base_text::validate_charset(bool v) +{ + validate_charset_=v; +} + +bool base_text::validate_charset() { - validate_charset_=false; + return validate_charset_; } -void text::load(http::context &context) +void base_text::load(http::context &context) { value_.clear(); + code_points_ = 0; set(false); valid(true); if(name().empty()) { @@ -443,27 +522,184 @@ void text::load(http::context &context) value_=p->second; set(true); if(validate_charset_) { + code_points_ = 0; locale::charset const &charset=std::use_facet(context.locale().get()); - if(!charset.validate(value)) + if(!charset.validate(value_,code_points_)) valid(false); } + else { + code_points_=value_.size(); + } } -bool text::validate() +bool base_text::validate() { if(!valid()) return false; - if(!set() && low_=0 && high_==-1) { + if(!set() && low_==0 && high_==-1) { valid(true); return true; } - if(value_.size() < low_ || (high_ >=0 && value_.size() > size_t(high_))) { + if(code_points_ < size_t(low_) || (high_ >=0 && code_points_ > size_t(high_))) { valid(false); return false; } + return true; } +////////////////////////////////////////////// +/// widgets::text +///////////////////////////////////////////// + +struct text::data {}; + +text::text() : size_(-1),type_("text") {} +text::~text() {} + +text::text(std::string n) : base_text(n) , size_(-1),type_("text") {} +text::text(std::string n,std::string m) : base_text(n,m),size_(-1),type_("text") {} + +void text::type(std::string t) +{ + type_=t; +} + +void text::render_input_start(std::ostream &output,unsigned flags) +{ + output<<"= 0) + output << boost::format("size=\"%1%\" ",std::locale::classic()) % size_; + + std::pair lm=limits(); + + if(lm.second >= 0 && validate_charset()) { + output << boost::format("maxlength=\"%1%\" ",std::locale::classic()) % lm.second; + } + + if(set()) { + output << "value=\""<"; + else + output<<" >"; +} +////////////////////////////////////////////// +/// widgets::textarea +///////////////////////////////////////////// + + +struct textarea::data {}; + +textarea::textarea() : rows_(-1), cols_(-1) {} +textarea::~textarea() {} + +textarea::textarea(std::string n) : base_text(n), rows_(-1), cols_(-1) {} +textarea::textarea(std::string n,std::string m) : base_text(n,m), rows_(-1), cols_(-1) {} + +int textarea::rows() { return rows_; } +int textarea::cols() { return cols_; } + +void textarea::rows(int n) { rows_ = n; } +void textarea::cols(int n) { cols_ = n; } + +void textarea::render_input_start(std::ostream &output,unsigned flags) +{ + output<<""; + } + else { + output << ">"; + } +} + + +//////////////////////// +/// Password widget /// +//////////////////////// +struct password::data {}; + +password::password() : password_to_check_(0) +{ + type("password"); +} +password::password(std::string name) : text(name), password_to_check_(0) +{ + type("password"); +} + +password::password(std::string name,std::string msg) : text(name,msg), password_to_check_(0) +{ + type("password"); +} +password::~password() +{ +} + +void password::check_equal(password &p2) +{ + password_to_check_ = &p2; +} + +bool password::validate() +{ + if(!text::validate()) { + value(""); + return false; + } + if(password_to_check_) { + if(!password_to_check_->set() || password_to_check_->value()!=value()) { + valid(false); + value(""); + password_to_check_->value(""); + return false; + } + } + return true; + +} + } // widgets diff --git a/form.h b/form.h index afe4781..5b97b1f 100644 --- a/form.h +++ b/form.h @@ -12,6 +12,14 @@ #include #include +#include "http_context.h" +#include "http_request.h" +#include "http_response.h" +#include "copy_ptr.h" +#include "cppcms_error.h" +#include "util.h" +#include "regex.h" + namespace cppcms { namespace widgets { @@ -153,7 +161,7 @@ namespace cppcms { /// inline form &operator + (form &f) { - add(&f); + add(f); return *this; } @@ -162,7 +170,7 @@ namespace cppcms { /// inline form &operator + (widgets::base_widget &f) { - add(&f); + add(f); return *this; } /// @@ -180,7 +188,7 @@ namespace cppcms { /// \endcode /// - class iterator : public std::iterator + class CPPCMS_API iterator : public std::iterator { public: iterator(); @@ -188,11 +196,11 @@ namespace cppcms { iterator(iterator const &other); iterator const &operator = (iterator const &other); - pointer_type operator->() const + widgets::base_widget *operator->() const { return get(); } - reference operator*() const + widgets::base_widget &operator*() const { return *get(); } @@ -225,8 +233,9 @@ namespace cppcms { bool equal(iterator const &other) const; void next(); - pointer_type get() const; + widgets::base_widget *get() const; + struct data; util::copy_ptr d; }; @@ -335,6 +344,12 @@ namespace cppcms { bool disabled(); /// + /// Set/Unset disabled html attribute + /// + + void disabled(bool); + + /// /// Get the general user defined attributes string that can be added to widget /// std::string attributes_string(); @@ -367,7 +382,7 @@ namespace cppcms { /// data. /// - void name(std::string) + void name(std::string); /// /// Set short description for the widget. Generally it is good idea to @@ -410,7 +425,7 @@ namespace cppcms { virtual void render(std::ostream &output,unsigned int flags); /// - /// This is pure-virtual member function that should be implemented by each widget + /// This is a virtual member function that should be implemented by each widget /// /// It executes actual rendering of the input HTML form up to the position where /// user can insert its own data in HTML templates @@ -452,8 +467,8 @@ namespace cppcms { private: std::string id_; std::string name_; - std::string msg_; - std::string error_msg_; + std::string message_; + std::string error_message_; std::string help_; std::string attr_; @@ -466,79 +481,435 @@ namespace cppcms { util::hold_ptr 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 data from the POST + /// or GET form, it performs charset validation and if required conversion + /// to and from Unicode charset to locale charset. + /// - class text : public base_widget { + class CPPCMS_API base_text : public base_widget { public: - text(); - text(std::string name); - text(std::string name,std::string msg); - ~text(); + + /// + /// Create an empty widget + /// + base_text(); + + /// + /// Create a widget with http attribute name - \a name + /// + base_text(std::string name); + + /// + /// Create a widget with http attribute name - \a name + /// and short description \a msg. + /// + base_text(std::string name,std::string msg); + + ~base_text(); + /// + /// Get the string that contains input value of the widget + /// the string is returned in locale specific representation. + /// i.e. if the locale is ru_RU.ISO8859-5 (8 bit encoding) + /// then the string is encoded in ISO-8859-5 encoding. + /// If the locale is ru_RU.UTF-8 that the string is encoded + /// in UTF-8. + /// + + std::string value(); - std::string value(std::locale const &); + + /// + /// Get the string that contains input value of the widget + /// converting the string from the locale \a loc to + /// UTF-8 Unicode encoding. If the locale uses UTF-8 + /// natively it is just copied without conversion. + /// + + std::string value(std::locale const &loc); + + + /// + /// Set the widget content before rendering, the value \a v + /// is assumed to be encoding according to current locale. + /// It should be encoded appropriately. + /// + /// For example. If the locale is ru_RU.ISO8859-5, then \a v + /// should be encoded as ISO-8859-5 if it is ru_RU.UTF-8 + /// then it should be encoded as UTF-8 string. + /// void value(std::string v); - void value(std::string v,std::locale const &); + + /// + /// Set the widget content before rendering, to value \a v, + /// where string \a v is encoded in UTF-8 Unicode encoding, + /// and it is converted to locale specific encoding defined + /// by locale \a loc. + /// + /// If the locale uses UTF-8 encoding natively then the string + /// is just copied. + /// + void value(std::string v,std::locale const &loc); #ifdef HAVE_STD_WSTRING - std::wstring value_wstring(std::locale const &); - void value(std::wstring v,std::locale const &); + + /// + /// Get the value of the widget represented as wide character string. + /// + /// Please note, std::wstring may represent UTF-16 variable length + /// encoded string (mostly on Win32) or fixed length encoded UTF-32 string + /// (mostly UNIX platforms) according to sizeof(wchar_t). So if you develop + /// cross platform applications, never assume that one wchar_t represents + /// one code point. + /// + /// Important Note: it assumes that the current locale character encoding is UTF-8. + /// Never use it if you support non UTF-8 encodings. + /// + std::wstring value_wstring(); + + /// + /// Set the content of widget converting wide character string to UTF-8 string. + /// + /// Please note, std::wstring may represent UTF-16 variable length + /// encoded string (mostly on Win32) or fixed length encoded UTF-32 string + /// (mostly UNIX platforms) according to sizeof(wchar_t). So if you develop + /// cross platform applications, never assume that one wchar_t represents + /// one code point. + /// + /// Important Note: it assumes that the current locale character encoding is UTF-8. + /// Never use it if you support non UTF-8 encodings. + /// + void value(std::wstring v); + + /// + /// Get the value of the widget represented as wide character + /// string converting it from the locale's \a loc encoding. + /// + /// Please note, std::wstring may represent UTF-16 variable length + /// encoded string (mostly on Win32) or fixed length encoded UTF-32 string + /// (mostly UNIX platforms) according to sizeof(wchar_t). So if you develop + /// cross platform applications, never assume that one wchar_t represents + /// one code point. + /// + + std::wstring value_wstring(std::locale const &loc); + + /// + /// Set the content of widget converting wide character string to the locale's \a loc + /// encoding. + /// + /// Please note, std::wstring may represent UTF-16 variable length + /// encoded string (mostly on Win32) or fixed length encoded UTF-32 string + /// (mostly UNIX platforms) according to sizeof(wchar_t). So if you develop + /// cross platform applications, never assume that one wchar_t represents + /// one code point. + /// + void value(std::wstring v,std::locale const &loc); + #endif #ifdef HAVE_CPP0X_UXSTRING + /// + /// Get the value of the widget represented as UTF-16 encoded + /// string converting it from the locale's \a loc encoding. + /// std::u16string value_u16string(std::locale const &); + /// + /// Get the value of the widget represented as UTF-32 encoded + /// string converting it from the locale's \a loc encoding. + /// std::u32string value_u32string(std::locale const &); + /// + /// Set the content of widget converting UTF-16 encoded string to the locale's \a loc + /// encoding. + /// void value(std::u16string v,std::locale const &); + /// + /// Set the content of widget converting UTF-32 encoded string to the locale's \a loc + /// encoding. + /// void value(std::u32string v,std::locale const &); + + /// + /// Get the value of the widget represented as utf16 encoded string. + /// + /// Important Note: it assumes that the current locale character encoding is UTF-8. + /// Never use it if you support non UTF-8 encodings. + /// + std::u16string value_u16string(); + + /// + /// Get the value of the widget represented as utf32 encoded string. + /// + /// Important Note: it assumes that the current locale character encoding is UTF-8. + /// Never use it if you support non UTF-8 encodings. + /// + std::u32string value_u32string(); + + /// + /// Set the content of widget converting utf-16 encoded string to UTF-8 string. + /// + /// Important Note: it assumes that the current locale character encoding is UTF-8. + /// Never use it if you support non UTF-8 encodings. + /// + void value(std::u16string v); + + /// + /// Set the content of widget converting utf-32 encoded string to UTF-8 string. + /// + /// Important Note: it assumes that the current locale character encoding is UTF-8. + /// Never use it if you support non UTF-8 encodings. + /// + void value(std::u32string v); + #endif #ifdef HAVE_ICU + /// + /// Get the value of the widget represented ICU UnicodeString. + /// + /// Important Note: it assumes that the current locale character encoding is UTF-8. + /// Never use it if you support non UTF-8 encodings. + /// + + icu::UnicodeString value_icu_string(); + /// + /// Set the content of widget ICU UnicodeString string to UTF-8 string. + /// + /// Important Note: it assumes that the current locale character encoding is UTF-8. + /// Never use it if you support non UTF-8 encodings. + /// + void value(icu::UnicodeString const &v); + + /// + /// Get the value of the widget represented as ICU UnicodeString + /// converting it from the locale's \a loc encoding. + /// + icu::UnicodeString value_icu_string(std::locale const &); + /// + /// Set the content of widget converting ICU UnocodeString to the locale's \a loc + /// encoding. + /// void value(icu::UnicodeString const &v,std::locale const &); + #endif + /// + /// 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. Note 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 Unicode 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); - void disable_charset_validation(); + + /// + /// Get minimal and maximal size limits, + /// + + std::pair 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 from the defined in locale. + /// + void validate_charset(bool ); + + /// + /// Returns true if charset validation is enabled. + /// + + bool validate_charset(); virtual void render_input_start(std::ostream &output,unsigned flags) = 0; virtual void render_input_end(std::ostream &output,unsigned flags) = 0; + /// + /// Validate the widget content according to rules and charset encoding. + /// + /// Notes: + /// + /// - The charset validation is very efficient for variable length UTF-8 encoding, + /// and most popular fixed length ISO-8859-*, windows-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 they are + /// valid code points (like NUL = 0 or DEL=127). + /// virtual bool validate(); + + /// + /// Load the widget for http::context. It used the locale given in the context for + /// validation of text. + /// virtual void load(http::context &); private: std::string value_; - unsigned low_; + int low_; int high_; bool validate_charset_; + size_t code_points_; struct data; util::hold_ptr d; }; + /// + /// \brief This class represents html input of type text + /// + + class CPPCMS_API text : public base_text + { + public: + /// + /// Create an empty text widget + /// + text(); + + /// + /// Create a text widget with http attribute name - \a name + /// + text(std::string name); + + /// + /// Create a text widget with http attribute name - \a name + /// and short description \a msg. + /// + text(std::string name,std::string msg); + + /// + /// Set html attribute size of the widget + /// + + void size(int n); + + /// + /// Get html attribute size of the widget, -1 undefined + /// + + int size(); + + ~text(); + + + virtual void render_input_start(std::ostream &output,unsigned flags); + virtual void render_input_end(std::ostream &output,unsigned flags); + protected: + void type(std::string str); + private: + int size_; + std::string type_; + struct data; + util::hold_ptr d; + }; + + class CPPCMS_API textarea : public base_text + { + public: + /// + /// Create an empty text widget + /// + textarea(); + /// + /// Create a text widget with http attribute name - \a name + /// + textarea(std::string name); + + /// + /// Create a text widget with http attribute name - \a name + /// and short description \a msg. + /// + textarea(std::string name,std::string msg); + + ~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_start(std::ostream &output,unsigned flags); + virtual void render_input_end(std::ostream &output,unsigned flags); + private: + int rows_,cols_; + + struct data; + util::hold_ptr d; + }; + /// + /// \brief Widget for number input. It is template class that assumes that T is number + /// template - class number: public text { + class number: public base_widget { public: - number(string name="",string msg="") : - text(name,msg), - value_(0), - check_low_(false), - check_high_(false), - non_empty_(false) + + number() { + init(); } + /// + /// Construct widget with html attribute name \a name + /// + number(std::string name) : base_widget(name) + { + init(); + } + /// + /// Construct widget with html attribute name \a name and description \a msg + /// + number(std::string name,std::string msg) : base_widget(name,msg) + { + init(); + } + + /// + /// Defines that this widget should have some value + /// void non_empty() { non_empty_=true; } + + /// + /// Get loaded widget value + /// T value() { if(!set()) @@ -546,55 +917,98 @@ namespace cppcms { 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; - set_nonempty(); + non_empty(); } + /// + /// Set maximal input number value + /// + void high(T b) { max_=b; check_high_=true; - set_nonempty(); + non_empty(); } + /// + /// Same as low(a); high(b); + /// void range(T a,T b) { - set_low(a); - set_high(b); + low(a); + high(b); } - void render_input_start(std::ostream &output,unsigned flags) + /// + /// Render first part of widget + /// + + virtual void render_input_start(std::ostream &output,unsigned flags) { output<<""; + output<<"/>"; else output<<">"; } - void load(http::context &context) + virtual void clear() + { + base_widget::clear(); + loaded_string_.clear(); + } + + /// + /// Load widget data + /// + + virtual void load(http::context &context) { loaded_string_.clear(); @@ -617,10 +1031,15 @@ namespace cppcms { ss>>value_; if(ss.fail() || !ss.eof()) valid(false); + else + set(true); } } - - bool validate() + + /// + /// Validate widget + /// + virtual bool validate() { if(!valid()) return false; @@ -636,19 +1055,16 @@ namespace cppcms { return false; } if(check_high_ && value_ > max_) { - valud(false); + valid(false); return false; } return true; } private: - - void render_element(std::ostream &out,std::string const &v,char const *field) + void init() { - if(v.empty()) - return; - out<<" "< d; + password *password_to_check_; }; - class regex_field : public text { - util::regex const *exp; + + + class CPPCMS_API regex_field : public text { public: - regex_field() : exp(0) {} - regex_field(util::regex const &e,string name="",string msg="") : text(name,msg),exp(&e) {} + regex_field(util::regex const &e); + regex_field(util::regex const &e,std::string name); + regex_field(util::regex const &e,std::string name,std::string msg); + ~regex_field(); + virtual bool validate(); + private: + util::regex const *expression_; + struct data; + util::hold_ptr d; }; - class email : public regex_field { + class CPPCMS_API email : public regex_field { public: - email(string name="",string msg=""); + email(); + ~email(); + email(std::string name); + email(std::string name,std::string msg); + private: + static util::regex const email_expression_; + struct data; + util::hold_ptr d; }; - +/* class checkbox: public base_widget { public: string input_value; @@ -785,7 +1215,7 @@ namespace cppcms { 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 diff --git a/hello_world.cpp b/hello_world.cpp index 25d92ce..6ef3a96 100644 --- a/hello_world.cpp +++ b/hello_world.cpp @@ -10,6 +10,7 @@ #include "format.h" #include "aio_timer.h" #include "intrusive_ptr.h" +#include "form.h" #include #include #include @@ -157,6 +158,32 @@ private: cppcms::aio::timer timer_; }; +class my_form : public cppcms::form +{ +public: + cppcms::widgets::text name; + cppcms::widgets::number age; + cppcms::widgets::password p1; + cppcms::widgets::password p2; + cppcms::widgets::textarea description; + + my_form() : + name("name","Your Name"), + age("age","Your Age"), + p1("p1","Password"), + p2("p2","Confirm"), + description("descr","Describe") + { + name.limits(2,30); + age.range(0,120); + p1.check_equal(p2); + p1.non_empty(); + *this + name + age + p1 + p2 + description; + } +}; + + + class hello : public cppcms::application { public: hello(cppcms::service &srv) : @@ -167,6 +194,7 @@ public: dispatcher().assign("^/post$",&hello::pform,this); dispatcher().assign("^/err$",&hello::err,this); dispatcher().assign("^/forward$",&hello::forward,this); + dispatcher().assign("^/form$",&hello::form,this); dispatcher().assign(".*",&hello::hello_world,this); std::cout<<"hello()"<\n"; + if(ok) { + response().out() << f.name.value() <<" " <\n" + "\n"; + + f.render(response().out(),cppcms::form::as_table); + + response().out()<<"
    \n"; + response().out()<<""< response; data(context &cntx) : - request(cntx.connection()), - response(cntx), - locale(cntx.connection().service()) + locale(cntx.connection().service()), + request(cntx.connection()) { } }; @@ -33,7 +32,8 @@ namespace http { context::context(intrusive_ptr conn) : conn_(conn) { - d.reset(new data(*this)); + d.reset(new data(*this)); + d->response.reset(new http::response(*this)); } @@ -165,7 +165,7 @@ http::request &context::request() http::response &context::response() { - return d->response; + return *d->response; } json::value const &context::settings() diff --git a/http_context.h b/http_context.h index 46b8b04..e874f1d 100644 --- a/http_context.h +++ b/http_context.h @@ -11,6 +11,7 @@ namespace cppcms { class service; + class application; namespace json { class value; } namespace locale { class environment; } namespace impl { namespace cgi { class connection; } } diff --git a/http_response.cpp b/http_response.cpp index 85ee71f..cadd8f5 100644 --- a/http_response.cpp +++ b/http_response.cpp @@ -10,6 +10,7 @@ #include "service.h" #include "config.h" #include "locale_environment.h" +#include "locale_info.h" #include "util.h" #include @@ -89,11 +90,13 @@ response::~response() void response::set_content_header(std::string const &content_type) { - std::string charset=context_.settings().get("l10n.charset",""); - if(charset.empty()) + if(context_.settings().get("locale.disable_charset_in_content_type",false)) { set_header("Content-Type",content_type); - else + } + else { + std::string charset=std::use_facet(context_.locale().get()).encoding(); set_header("Content-Type",content_type+"; charset="+charset); + } } void response::set_html_header() { diff --git a/light.conf b/light.conf index 2737e41..50ce457 100755 --- a/light.conf +++ b/light.conf @@ -1,70 +1,27 @@ -server.modules = ("mod_fastcgi" , "mod_scgi") +server.modules = ("mod_fastcgi") server.document-root = "./" # mimetype mapping mimetype.assign = ( - ".pdf" => "application/pdf", - ".sig" => "application/pgp-signature", - ".spl" => "application/futuresplash", - ".class" => "application/octet-stream", - ".ps" => "application/postscript", - ".torrent" => "application/x-bittorrent", - ".dvi" => "application/x-dvi", - ".gz" => "application/x-gzip", - ".pac" => "application/x-ns-proxy-autoconfig", - ".swf" => "application/x-shockwave-flash", - ".tar.gz" => "application/x-tgz", - ".tgz" => "application/x-tgz", - ".tar" => "application/x-tar", - ".zip" => "application/zip", - ".mp3" => "audio/mpeg", - ".m3u" => "audio/x-mpegurl", - ".wma" => "audio/x-ms-wma", - ".wax" => "audio/x-ms-wax", - ".ogg" => "application/ogg", - ".wav" => "audio/x-wav", ".gif" => "image/gif", ".jpg" => "image/jpeg", ".jpeg" => "image/jpeg", ".png" => "image/png", - ".xbm" => "image/x-xbitmap", - ".xpm" => "image/x-xpixmap", - ".xwd" => "image/x-xwindowdump", ".css" => "text/css", ".html" => "text/html", ".htm" => "text/html", ".js" => "text/javascript", - ".asc" => "text/plain", - ".c" => "text/plain", - ".cpp" => "text/plain", - ".log" => "text/plain", - ".conf" => "text/plain", - ".text" => "text/plain", - ".txt" => "text/plain", - ".dtd" => "text/xml", ".xml" => "text/xml", - ".mpeg" => "video/mpeg", - ".mpg" => "video/mpeg", - ".mov" => "video/quicktime", - ".qt" => "video/quicktime", - ".avi" => "video/x-msvideo", - ".asf" => "video/x-ms-asf", - ".asx" => "video/x-ms-asf", - ".wmv" => "video/x-ms-wmv", - ".bz2" => "application/x-bzip", - ".tbz" => "application/x-bzip-compressed-tar", - ".tar.bz2" => "application/x-bzip-compressed-tar", # default mime type "" => "application/octet-stream", - ) +) server.port = 8080 server.bind = "0.0.0.0" -scgi.server = ( "/hello" => ( "localhost" => ( +fastcgi.server = ( "/hello" => (( "check-local" => "disable", "host" => "127.0.0.1", "port" => 8001 - # "socket" => "/tmp/scgi.socket" - ))) +))) diff --git a/locale_charset.cpp b/locale_charset.cpp index 22cbdf3..8f7d39c 100644 --- a/locale_charset.cpp +++ b/locale_charset.cpp @@ -11,6 +11,23 @@ struct charset::data {}; std::locale::id charset::id; +charset::charset(std::size_t refs) : + std::locale::facet(refs), + is_utf8_(true), + validators_(0) +{ +} + + +charset::charset(std::string charset,std::size_t refs) : + std::locale::facet(refs), + name_(charset), + validators_(0) +{ + is_utf8_ = charset=="utf8" || charset=="UTF8" || charset=="utf-8" || charset=="UTF-8"; +} + + charset::charset(std::string charset,intrusive_ptr p,std::size_t refs) : std::locale::facet(refs), name_(charset), @@ -24,10 +41,12 @@ charset::~charset() } -bool charset::do_validate(char const *begin,char const *end) const +bool charset::do_validate(char const *begin,char const *end,size_t &count) const { + if(!validators_) + return true; encoding::validator v=(*validators_)[name_]; - return v.valid(begin,end); + return v.valid(begin,end,count); } std::string charset::do_to_utf8(std::string const &v) const { diff --git a/locale_charset.h b/locale_charset.h index 0a9d694..1819892 100644 --- a/locale_charset.h +++ b/locale_charset.h @@ -18,16 +18,18 @@ namespace locale { class CPPCMS_API charset : public std::locale::facet { public: static std::locale::id id; + charset(std::size_t refs=0); + charset(std::string charset,std::size_t refs=0); charset(std::string charset,intrusive_ptr p,std::size_t refs=0); ~charset(); - bool validate(char const *begin,char const *end) const + bool validate(char const *begin,char const *end,size_t &count) const { - return do_validate(begin,end); + return do_validate(begin,end,count); } - bool validate(std::string const &s) const + bool validate(std::string const &s,size_t &count) const { - return do_validate(s.data(),s.data()+s.size()); + return do_validate(s.data(),s.data()+s.size(),count); } std::string to_utf8(std::string const &v) const @@ -104,7 +106,7 @@ namespace locale { private: - virtual bool do_validate(char const *begin,char const *end) const; + virtual bool do_validate(char const *begin,char const *end,size_t &count) const; virtual std::string do_to_utf8(std::string const &v) const; virtual std::string do_from_utf8(std::string const &v) const; diff --git a/json_object.h b/rpc_json.h similarity index 100% rename from json_object.h rename to rpc_json.h diff --git a/utf_iterator.h b/utf_iterator.h index 840ffd0..5ffbc6c 100644 --- a/utf_iterator.h +++ b/utf_iterator.h @@ -1,6 +1,7 @@ #ifndef CPPCMS_UTF_ITERATOR_H #define CPPCMS_UTF_ITERATOR_H #include +#include namespace cppcms { @@ -117,9 +118,20 @@ namespace utf8 { template + bool validate(Iterator p,Iterator e,size_t &count,bool html=false) + { + while(p!=e) { + if(next(p,e,html)==utf::illegal) + return false; + count++; + } + return true; + } + + template bool validate(Iterator p,Iterator e,bool html=false) { - while(p!=e) + while(p!=e) if(next(p,e,html)==utf::illegal) return false; return true;