format, global_config replaced with json::valuemaster
@@ -26,7 +26,6 @@ libcppcms_la_SOURCES = \ | |||
http_request.cpp \ | |||
http_response.cpp \ | |||
http_context.cpp \ | |||
global_config.cpp \ | |||
cppcms_error.cpp \ | |||
cppcms_error_category.cpp \ | |||
thread_pool.cpp \ | |||
@@ -48,7 +47,8 @@ libcppcms_la_SOURCES = \ | |||
fastcgi_api.cpp \ | |||
http_api.cpp \ | |||
atomic_counter.cpp \ | |||
aio_timer.cpp | |||
aio_timer.cpp \ | |||
json.cpp | |||
@@ -57,7 +57,7 @@ cppcms::service &application::service() | |||
return *d->service; | |||
} | |||
cppcms_config const &application::settings() | |||
json::value const &application::settings() | |||
{ | |||
return service().settings(); | |||
} | |||
@@ -11,7 +11,6 @@ | |||
namespace cppcms { | |||
class service; | |||
class cppcms_config; | |||
class url_dispatcher; | |||
class applications_pool; | |||
class application; | |||
@@ -24,6 +23,9 @@ namespace cppcms { | |||
class response; | |||
class context; | |||
} | |||
namespace json { | |||
class value; | |||
} | |||
void CPPCMS_API intrusive_ptr_add_ref(application *p); | |||
void CPPCMS_API intrusive_ptr_release(application *p); | |||
@@ -34,7 +36,7 @@ namespace cppcms { | |||
virtual ~application(); | |||
cppcms::service &service(); | |||
cppcms_config const &settings(); | |||
json::value const &settings(); | |||
http::context &context(); | |||
http::request &request(); | |||
http::response &response(); | |||
@@ -2,8 +2,8 @@ | |||
#include "applications_pool.h" | |||
#include "application.h" | |||
#include "service.h" | |||
#include "global_config.h" | |||
#include "cppcms_error.h" | |||
#include "json.h" | |||
#include <set> | |||
#include <vector> | |||
#include <boost/regex.hpp> | |||
@@ -105,7 +105,7 @@ applications_pool::~applications_pool() | |||
std::string applications_pool::script_name() | |||
{ | |||
return srv_->settings().str("service.default_script_name","*"); | |||
return srv_->settings().get("service.default_script_name","*"); | |||
} | |||
void applications_pool::mount(std::auto_ptr<factory> aps) | |||
@@ -7,7 +7,7 @@ | |||
#include "http_protocol.h" | |||
#include "service.h" | |||
#include "service_impl.h" | |||
#include "global_config.h" | |||
#include "json.h" | |||
#include "cgi_api.h" | |||
#include "util.h" | |||
@@ -66,7 +66,7 @@ void connection::load_content(boost::system::error_code const &e,http::request * | |||
if(http::protocol::is_prefix_of("multipart/form-data",content_type)) { | |||
// 64 MB | |||
long long allowed=service().settings().integer("security.multipart_form_data_limit",64*1024)*1024; | |||
long long allowed=service().settings().get("security.multipart_form_data_limit",64*1024)*1024; | |||
if(content_length > allowed) { | |||
set_error(h,"security violation: multipart/form-data content length too big"); | |||
return; | |||
@@ -75,7 +75,7 @@ void connection::load_content(boost::system::error_code const &e,http::request * | |||
return; | |||
} | |||
long long allowed=service().settings().integer("security.content_length_limit",1024)*1024; | |||
long long allowed=service().settings().get("security.content_length_limit",1024)*1024; | |||
if(content_length > allowed) { | |||
set_error(h,"security violation POST content length too big"); | |||
// TODO log | |||
@@ -0,0 +1,44 @@ | |||
// CppCMS Configuration file | |||
// JSON format | |||
{ | |||
// Service description | |||
"service" : { | |||
"procs" : 0, | |||
"worker_threads": 5, | |||
"api" : "http", | |||
"port" : 8080, | |||
"ip" : "127.0.0.1" | |||
// "socket" : "/tmp/scgi.socket" | |||
}, | |||
"http" : { | |||
"script_names" : [ "/stock", "/hello" ] | |||
}, | |||
"gzip" : { | |||
"enable" : true, // Default true | |||
// "level" : 1, | |||
// "buffer" : 4096 | |||
}, | |||
"locale" : { | |||
"locales" : [ "he_IL.UTF-8", "en_US.UTF-8" ], // list of supported languages | |||
"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 | |||
}, | |||
"session" : { | |||
"expire" : "browser", | |||
"timeout" : 10, | |||
"cookies_prefix" : "cppcms_session", | |||
"cookies_domain" : "", | |||
"cookies_path" : "/", | |||
"cookies_secure" : false | |||
}, | |||
"file_server" : { | |||
"enable" : true, | |||
"doument_root" : ".", | |||
"mime_types" : "mime.type" | |||
} | |||
} |
@@ -10,7 +10,9 @@ service.ip = "127.0.0.1" | |||
#service.ip = "0.0.0.0" | |||
#service.socket = "/tmp/scgi.socket" # Default is "" -- use default socket given | |||
service.worker_threads = 5 | |||
service.api = "http" # fastcgi -- preferred API | |||
#service.api = "fastcgi" | |||
service.api = "http" | |||
# fastcgi -- preferred API | |||
# scgi -- simplefied FCGI API -- yet another alternative | |||
# cgi -- Use only in case you application does huge amount of work | |||
# such the fork()+exec() time in neligable | |||
@@ -5,7 +5,7 @@ | |||
#include "service.h" | |||
#include "service_impl.h" | |||
#include "cppcms_error_category.h" | |||
#include "global_config.h" | |||
#include "json.h" | |||
#include <iostream> | |||
#include <boost/array.hpp> | |||
@@ -26,7 +26,7 @@ namespace cgi { | |||
int procs=srv.procs_no(); | |||
if(procs < 1) procs=1; | |||
int threads=srv.threads_no(); | |||
cuncurrency_hint_=srv.settings().integer("fastcgi.cuncurrency_hint",procs*threads); | |||
cuncurrency_hint_=srv.settings().get("fastcgi.cuncurrency_hint",procs*threads); | |||
} | |||
~fastcgi() | |||
{ | |||
@@ -1,434 +0,0 @@ | |||
#define CPPCMS_SOURCE | |||
#include "global_config.h" | |||
#include "cppcms_error.h" | |||
#include <map> | |||
#include <stdio.h> | |||
#include <ctype.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <boost/any.hpp> | |||
using namespace std; | |||
namespace cppcms { | |||
class cppcms_config_impl { | |||
public: | |||
typedef std::map<string,boost::any> data_t; | |||
typedef std::pair<data_t::const_iterator,data_t::const_iterator> range_t; | |||
private: | |||
enum { WORD, INT, DOUBLE, STR }; | |||
typedef std::pair<int,string> tocken_t; | |||
typedef std::pair<string,string> key_t; | |||
data_t data; | |||
string filename; | |||
int line_counter; | |||
bool loaded; | |||
bool get_tocken(FILE *,tocken_t &T); | |||
public: | |||
template<typename T> | |||
T const *get_ptr(string const &name) const { | |||
std::map<string,boost::any>::const_iterator it; | |||
if((it=data.find(name))==data.end()) { | |||
return NULL; | |||
} | |||
T const *res=boost::any_cast<T>(&it->second); | |||
if(!res) { | |||
throw cppcms_error("Type mistmach for field "+name); | |||
} | |||
return res; | |||
} | |||
template<typename T> | |||
T const &get(string const &name,T const &def) const | |||
{ | |||
T const *p=get_ptr<T>(name); | |||
if(!p) return def; | |||
return *p; | |||
} | |||
template<typename T> | |||
T const &get(string const &name) const | |||
{ | |||
T const *p=get_ptr<T>(name); | |||
if(!p) throw cppcms_error("Configuration parameter "+name+" not found"); | |||
return *p; | |||
} | |||
template<typename T> | |||
T const &get_default(string const &name) const | |||
{ | |||
T const *p=get_ptr<T>(name); | |||
static const T v; | |||
if(!p) return v; | |||
return *p; | |||
} | |||
data_t const &get_data() const | |||
{ | |||
return data; | |||
} | |||
size_t size() const { return data.size(); } | |||
void load(char const *filename); | |||
void load(int argc,char *argv[],char const *def=NULL); | |||
range_t prefix(string pref) const { | |||
range_t res; | |||
res.first=data.lower_bound(pref+'.'); | |||
res.second=data.upper_bound(pref+char('.'+1)); | |||
return res; | |||
} | |||
cppcms_config_impl() { loaded = false;} | |||
// { begin depricated | |||
int lval(string m) const { return ival(m); } | |||
int lval(string m,int def) const { return ival(m,def); } | |||
vector<int> const &llist(string m) const { return ilist(m); } | |||
// } end depricated | |||
int ival(string m) const { | |||
return get<int>(m); | |||
} | |||
int ival(string m,int def) const { | |||
return get<int>(m,def); | |||
} | |||
double dval(string m) const { | |||
return get<double>(m); | |||
} | |||
double dval(string m,double def) const { | |||
return get<double>(m,def); | |||
} | |||
string const &sval(string m) const { | |||
return get<string>(m); | |||
} | |||
string sval(string m,string def) const { | |||
return get<string>(m,def); | |||
} | |||
vector<int> const &ilist(string m) const { | |||
return get_default<vector<int> >(m); | |||
} | |||
vector<double> const &dlist(string m) const { | |||
return get_default<vector<double> >(m); | |||
} | |||
vector<string> const &slist(string m) const { | |||
return get_default<vector<string> >(m); | |||
} | |||
}; | |||
bool cppcms_config_impl::get_tocken(FILE *f,tocken_t &T) | |||
{ | |||
int c; | |||
while((c=fgetc(f))!=EOF) { | |||
if(c=='.') { | |||
T.first='.'; | |||
return true; | |||
} | |||
else if(c=='{') { | |||
T.first='{'; | |||
return true; | |||
} | |||
else if(c=='}') { | |||
T.first='}'; | |||
return true; | |||
} | |||
else if(c=='=') { | |||
T.first='='; | |||
return true; | |||
} | |||
else if(c=='\n') { | |||
line_counter++; | |||
continue; | |||
} | |||
else if(c==' ' || c=='\r' || c=='\t') { | |||
continue; | |||
} | |||
else if(isalpha(c)) { | |||
T.second=""; | |||
T.second.reserve(32); | |||
T.second+=(char)c; | |||
while((c=fgetc(f))!=EOF && (isalnum(c) || c=='_')) { | |||
T.second+=(char)c; | |||
} | |||
if(c!=EOF){ | |||
ungetc(c,f); | |||
} | |||
T.first=WORD; | |||
return true; | |||
} | |||
else if(isdigit(c) || c=='-') { | |||
T.second=""; | |||
T.second.reserve(32); | |||
T.second+=(char)c; | |||
T.first=INT; | |||
while((c=fgetc(f))!=EOF && isdigit(c)) { | |||
T.second+=(char)c; | |||
} | |||
if(c=='.') { | |||
T.second+='.'; | |||
T.first=DOUBLE; | |||
while((c=fgetc(f))!=EOF && isdigit(c)) { | |||
T.second+=(char)c; | |||
} | |||
} | |||
if(T.second=="-" || T.second=="." || T.second=="-.") { | |||
throw cppcms_error("Illegal charrecters"); | |||
} | |||
if(c!=EOF) { | |||
ungetc(c,f); | |||
} | |||
return true; | |||
} | |||
else if(c=='\"') { | |||
T.first=STR; | |||
T.second=""; | |||
T.second.reserve(128); | |||
for(;;){ | |||
c=fgetc(f); | |||
if(c=='\\'){ | |||
if((c=fgetc(f))=='\"' ) { | |||
T.second+='"'; | |||
continue; | |||
} | |||
else { | |||
T.second+='\\'; | |||
} | |||
} | |||
if(c==EOF){ | |||
throw cppcms_error("Unexpected EOF "); | |||
} | |||
if(c=='\n') line_counter++; | |||
if(c=='\"') { | |||
return true; | |||
} | |||
T.second+=(char)c; | |||
} | |||
} | |||
else if(c=='#' || c==';'){ | |||
while((c=fgetc(f))!=EOF) { | |||
if(c=='\n'){ | |||
line_counter++; | |||
break; | |||
} | |||
} | |||
if(c==EOF) { | |||
return false; | |||
} | |||
} | |||
else { | |||
throw cppcms_error(string("Unexpected charrecter")+(char)c); | |||
} | |||
} | |||
return false; | |||
} | |||
void cppcms_config_impl::load(char const *fname) | |||
{ | |||
if(loaded){ | |||
return; | |||
} | |||
FILE *f=fopen(fname,"r"); | |||
line_counter=1; | |||
if(!f) { | |||
throw cppcms_error(string("Failed to open file:")+fname); | |||
} | |||
tocken_t T; | |||
string key; | |||
int state=0; | |||
try{ | |||
while(get_tocken(f,T) && state != -1) { | |||
switch(state) { | |||
case 0: if(T.first != WORD) { | |||
state=-1; | |||
}else{ | |||
key=T.second; | |||
state=1; | |||
} | |||
break; | |||
case 1: if(T.first != '.') | |||
state=-1; | |||
else | |||
state=2; | |||
break; | |||
case 2: if(T.first!=WORD){ | |||
state=-1; | |||
}else{ | |||
state=3; | |||
key+='.'; | |||
key+=T.second; | |||
} | |||
break; | |||
case 3: if(T.first!= '=') | |||
state=-1; | |||
else | |||
state=4; | |||
break; | |||
case 4: if(T.first=='{') { | |||
state=5; | |||
break; | |||
} | |||
if(T.first==INT) { | |||
int val=atol(T.second.c_str()); | |||
data[key]=val; | |||
} | |||
else if(T.first==DOUBLE) { | |||
double val=atof(T.second.c_str()); | |||
data[key]=val; | |||
} | |||
else if(T.first==STR){ | |||
data[key]=T.second; | |||
} | |||
else { | |||
state=-1; | |||
break; | |||
} | |||
state=0; | |||
break; | |||
case 5: | |||
if(T.first==INT || T.first==DOUBLE || T.first==STR) { | |||
int fp=T.first; | |||
vector<int> vl; | |||
vector<double> vd; | |||
vector<string> vs; | |||
do { | |||
if(T.first=='}') { | |||
state=0; | |||
} | |||
else if(T.first==fp){ | |||
switch(T.first) { | |||
case INT: vl.push_back(atol(T.second.c_str())); break; | |||
case DOUBLE: vd.push_back(atof(T.second.c_str())); break; | |||
case STR: vs.push_back(T.second); break; | |||
} | |||
} | |||
else { | |||
state=-1; | |||
} | |||
}while(state==5 && get_tocken(f,T)); | |||
if(state==0) { | |||
switch(fp) { | |||
case INT: data[key]=vl; break; | |||
case DOUBLE: data[key]=vd; break; | |||
case STR: data[key]=vs; break; | |||
}; | |||
} | |||
} | |||
else | |||
state=-1; | |||
break; | |||
} | |||
} | |||
if(state!=0) { | |||
throw cppcms_error("Parsing error"); | |||
} | |||
} | |||
catch (cppcms_error &err){ | |||
fclose(f); | |||
char stmp[32]; | |||
snprintf(stmp,32," at line %d",line_counter); | |||
throw cppcms_error(string(err.what())+stmp); | |||
} | |||
fclose(f); | |||
loaded=true; | |||
} | |||
void cppcms_config_impl::load(int argc,char *argv[],char const *def) | |||
{ | |||
if(loaded) { | |||
return; | |||
} | |||
char const *def_file=def; | |||
int i; | |||
for(i=1;i<argc;i++) { | |||
if(strncmp(argv[i],"--config=",9)==0) { | |||
def_file=argv[i]+9; | |||
break; | |||
} | |||
else if(strcmp(argv[i],"-c")==0 && i+1<argc) { | |||
def_file=argv[i+1]; | |||
break; | |||
} | |||
} | |||
if(def_file==NULL) { | |||
def_file=getenv("CPPCMS_CONFIG"); | |||
} | |||
if(def_file==NULL) { | |||
throw cppcms_error("Configuration file not defined"); | |||
} | |||
load(def_file); | |||
} | |||
int cppcms_config::ival(std::string m) const | |||
{ | |||
return pimpl_->ival(m); | |||
} | |||
int cppcms_config::ival(std::string m,int def) const | |||
{ | |||
return pimpl_->ival(m,def); | |||
} | |||
double cppcms_config::dval(std::string m) const | |||
{ | |||
return pimpl_->dval(m); | |||
} | |||
double cppcms_config::dval(std::string m,double def) const | |||
{ | |||
return pimpl_->dval(m,def); | |||
} | |||
std::string cppcms_config::sval(std::string m) const | |||
{ | |||
return pimpl_->sval(m); | |||
} | |||
std::string cppcms_config::sval(std::string m,std::string def) const | |||
{ | |||
return pimpl_->sval(m,def); | |||
} | |||
std::vector<int> const &cppcms_config::ilist(std::string m) const | |||
{ | |||
return pimpl_->ilist(m); | |||
} | |||
std::vector<double> const &cppcms_config::dlist(std::string m) const | |||
{ | |||
return pimpl_->dlist(m); | |||
} | |||
std::vector<std::string> const &cppcms_config::slist(std::string m) const | |||
{ | |||
return pimpl_->slist(m); | |||
} | |||
void cppcms_config::load(std::string const &filename) | |||
{ | |||
pimpl_->load(filename.c_str()); | |||
} | |||
void cppcms_config::load(int argc,char *argv[],char const *def) | |||
{ | |||
pimpl_->load(argc,argv,def); | |||
} | |||
cppcms_config::cppcms_config(): | |||
pimpl_(new cppcms_config_impl()) | |||
{ | |||
} | |||
cppcms_config::~cppcms_config() | |||
{ | |||
} | |||
cppcms_config::cppcms_config(cppcms_config const &other) : | |||
pimpl_(other.pimpl_) | |||
{ | |||
} | |||
cppcms_config const &cppcms_config::operator=(cppcms_config const &other) | |||
{ | |||
pimpl_=other.pimpl_; | |||
return *this; | |||
} | |||
} /// cppcms |
@@ -1,69 +0,0 @@ | |||
#ifndef CPPCMS_GLOBAL_CONFIG_H | |||
#define CPPCMS_GLOBAL_CONFIG_H | |||
#include <string> | |||
#include <vector> | |||
#include "defs.h" | |||
#include "copy_ptr.h" | |||
namespace cppcms { | |||
class cppcms_config_impl; | |||
class CPPCMS_API cppcms_config { | |||
public: | |||
int ival(std::string m) const; | |||
int ival(std::string m,int def) const; | |||
double dval(std::string m) const; | |||
double dval(std::string m,double def) const; | |||
std::string sval(std::string m) const; | |||
std::string sval(std::string m,std::string def) const; | |||
int integer(std::string m) const | |||
{ | |||
return ival(m); | |||
} | |||
int integer(std::string m,int def) const | |||
{ | |||
return ival(m,def); | |||
} | |||
double real(std::string m) const | |||
{ | |||
return dval(m); | |||
} | |||
double real(std::string m,double def) const | |||
{ | |||
return dval(m,def); | |||
} | |||
std::string str(std::string m) const | |||
{ | |||
return sval(m); | |||
} | |||
std::string str(std::string m,std::string def) const | |||
{ | |||
return sval(m,def); | |||
} | |||
std::vector<int> const &ilist(std::string m) const; | |||
std::vector<double> const &dlist(std::string m) const; | |||
std::vector<std::string> const &slist(std::string m) const; | |||
void load(std::string const &filename); | |||
void load(int argc,char *argv[],char const *def=NULL); | |||
cppcms_config(); | |||
~cppcms_config(); | |||
cppcms_config(cppcms_config const &other); | |||
cppcms_config const &operator=(cppcms_config const &other); | |||
private: | |||
util::copy_ptr<cppcms_config_impl> pimpl_; | |||
}; | |||
} // namespace cppcms | |||
#endif /* _GLOBAL_CONFIG_H */ |
@@ -5,7 +5,7 @@ | |||
#include "service.h" | |||
#include "service_impl.h" | |||
#include "cppcms_error_category.h" | |||
#include "global_config.h" | |||
#include "json.h" | |||
#include "http_protocol.h" | |||
#include "config.h" | |||
#include <iostream> | |||
@@ -33,8 +33,8 @@ namespace cgi { | |||
{ | |||
env_["SERVER_SOFTWARE"]=PACKAGE_NAME "/" PACKAGE_VERSION; | |||
env_["SERVER_NAME"]=srv.settings().str("service.ip","127.0.0.1"); | |||
env_["SERVER_PORT"]=boost::lexical_cast<std::string>(srv.settings().integer("service.port")); | |||
env_["SERVER_NAME"]=srv.settings().get("service.ip","127.0.0.1"); | |||
env_["SERVER_PORT"]=boost::lexical_cast<std::string>(srv.settings().get<int>("service.port")); | |||
env_["GATEWAY_INTERFACE"]="CGI/1.0"; | |||
env_["SERVER_PROTOCOL"]="HTTP/1.0"; | |||
@@ -274,7 +274,8 @@ namespace cgi { | |||
return; | |||
} | |||
std::vector<std::string> const &script_names=service().settings().slist("http.script_names"); | |||
std::vector<std::string> const &script_names= | |||
service().settings().get("http.script_names",std::vector<std::string>()); | |||
for(unsigned i=0;i<script_names.size();i++) { | |||
@@ -144,7 +144,7 @@ http::response &context::response() | |||
return d->response; | |||
} | |||
cppcms_config const &context::settings() | |||
json::value const &context::settings() | |||
{ | |||
return conn_->service().settings(); | |||
} | |||
@@ -8,9 +8,8 @@ | |||
namespace cppcms { | |||
class cppcms_config; | |||
class service; | |||
namespace json { class value; } | |||
namespace locale { class environment; } | |||
namespace impl { namespace cgi { class connection; } } | |||
@@ -27,7 +26,7 @@ namespace cppcms { | |||
impl::cgi::connection &connection(); | |||
http::request &request(); | |||
http::response &response(); | |||
cppcms_config const &settings(); | |||
json::value const &settings(); | |||
cppcms::locale::environment &locale(); | |||
cppcms::service &service(); | |||
@@ -5,7 +5,7 @@ | |||
#include "http_request.h" | |||
#include "http_cookie.h" | |||
#include "http_protocol.h" | |||
#include "global_config.h" | |||
#include "json.h" | |||
#include "cppcms_error.h" | |||
#include "service.h" | |||
#include "config.h" | |||
@@ -62,7 +62,7 @@ struct response::data { | |||
data(impl::cgi::connection *conn) : | |||
headers(string_i_comp), | |||
output(output_device(conn),conn->service().settings().integer("service.output_buffer_size",16384)) | |||
output(output_device(conn),conn->service().settings().get("service.output_buffer_size",16384)) | |||
{ | |||
} | |||
}; | |||
@@ -78,7 +78,7 @@ response::response(context &context) : | |||
copy_to_cache_(0) | |||
{ | |||
set_content_header("text/html"); | |||
if(context_.settings().integer("server.disable_xpowered_by",0)==0) { | |||
if(context_.settings().get("server.disable_xpowered_by",false)==0) { | |||
set_header("X-Powered-By", PACKAGE_NAME "/" PACKAGE_VERSION); | |||
} | |||
} | |||
@@ -89,7 +89,7 @@ response::~response() | |||
void response::set_content_header(std::string const &content_type) | |||
{ | |||
std::string charset=context_.settings().str("l10n.charset",""); | |||
std::string charset=context_.settings().get("l10n.charset",""); | |||
if(charset.empty()) | |||
set_header("Content-Type",content_type); | |||
else | |||
@@ -150,7 +150,7 @@ bool response::need_gzip() | |||
return false; | |||
if(io_mode_!=normal) | |||
return false; | |||
if(context_.settings().integer("gzip.enable",1)==0) | |||
if(context_.settings().get("gzip.enable",true)==0) | |||
return false; | |||
if(context_.request().http_accept_encoding().find("gzip")==std::string::npos) | |||
return false; | |||
@@ -224,10 +224,10 @@ std::ostream &response::out() | |||
if(gzip) { | |||
gzip_params params; | |||
int level=context_.settings().integer("gzip.level",-1); | |||
int level=context_.settings().get("gzip.level",-1); | |||
if(level!=-1) | |||
params.level=level; | |||
int buffer=context_.settings().integer("gzip.buffer",-1); | |||
int buffer=context_.settings().get("gzip.buffer",-1); | |||
if(buffer!=-1) | |||
d->filter.push(gzip_compressor(params,buffer)); | |||
else | |||
@@ -4,7 +4,7 @@ | |||
#include "service.h" | |||
#include "http_response.h" | |||
#include "internal_file_server.h" | |||
#include "global_config.h" | |||
#include "json.h" | |||
#include <sstream> | |||
#include <fstream> | |||
#include <boost/filesystem/operations.hpp> | |||
@@ -18,11 +18,11 @@ namespace impl { | |||
file_server::file_server(cppcms::service &srv) : application(srv) | |||
{ | |||
document_root_ = settings().str("file_server.document_root","."); | |||
document_root_ = settings().get("file_server.document_root","."); | |||
dispatcher().assign("^(.*)$",&file_server::serve_file,this,1); | |||
std::string mime_file=settings().str("file_server.mime_types",""); | |||
std::string mime_file=settings().get("file_server.mime_types",""); | |||
if(mime_file.empty()) { | |||
@@ -144,7 +144,7 @@ void file_server::serve_file(std::string file_name) | |||
response().content_type(p->second); | |||
else | |||
response().content_type("application/octet-stream"); | |||
if(!settings().integer("http.allow_deflate",0)) { | |||
if(!settings().get("http.allow_deflate",false)) { | |||
response().io_mode(http::response::nogzip); | |||
} | |||
std::ifstream file(full.file_string().c_str(),std::ifstream::binary | std::ifstream::in); | |||
@@ -15,6 +15,35 @@ | |||
namespace cppcms { | |||
namespace json { | |||
bad_value_cast::bad_value_cast() : msg_("cppcms::json::bad_cast") | |||
{ | |||
} | |||
bad_value_cast::bad_value_cast(std::string const &s) : msg_("cppcms::json::bad_cast: "+s ) | |||
{ | |||
} | |||
bad_value_cast::bad_value_cast(std::string const &s,json_type actual) : | |||
msg_("cppcms::json::bad_cast: ") | |||
{ | |||
std::ostringstream msg; | |||
msg<<"errpr converting from "<<actual; | |||
msg_ +=msg.str(); | |||
} | |||
bad_value_cast::bad_value_cast(std::string const &s,json_type expected, json_type actual) : | |||
msg_("cppcms::json::bad_cast: ") | |||
{ | |||
std::ostringstream msg; | |||
msg<<"error converting from "<<actual<<" to "<<expected; | |||
msg_ +=msg.str(); | |||
} | |||
bad_value_cast::~bad_value_cast() throw() | |||
{ | |||
} | |||
const char* bad_value_cast::what() const throw() | |||
{ | |||
return msg_.c_str(); | |||
} | |||
typedef boost::variant< | |||
undefined, | |||
@@ -68,7 +97,7 @@ namespace json { | |||
return boost::get<T>(v); | |||
} | |||
catch(boost::bad_get const &e) { | |||
throw std::bad_cast(); | |||
throw bad_value_cast("",json_type(v.which())); | |||
} | |||
} | |||
template<typename T> | |||
@@ -78,7 +107,7 @@ namespace json { | |||
return boost::get<T>(v); | |||
} | |||
catch(boost::bad_get const &e) { | |||
throw std::bad_cast(); | |||
throw bad_value_cast("",json_type(v.which())); | |||
} | |||
} | |||
@@ -263,7 +292,7 @@ namespace json { | |||
{ | |||
switch(type()) { | |||
case json::is_undefined: | |||
throw std::bad_cast(); | |||
throw bad_value_cast("Can't write undefined value to stream"); | |||
case json::is_null: | |||
out<<"null"; | |||
case json::is_number: | |||
@@ -308,7 +337,7 @@ namespace json { | |||
} | |||
break; | |||
default: | |||
throw std::bad_cast(); | |||
throw bad_value_cast("Unknown type found: internal error"); | |||
} | |||
} | |||
@@ -374,7 +403,7 @@ namespace json { | |||
{ | |||
value const &v=find(path); | |||
if(v.is_undefined()) | |||
throw std::bad_cast(); | |||
throw bad_value_cast("Value not found at "+path ); | |||
return v; | |||
} | |||
value &value::at(std::string path) | |||
@@ -388,13 +417,13 @@ namespace json { | |||
if(new_pos!=std::string::npos) | |||
new_pos++; | |||
if(part.empty()) | |||
throw std::bad_cast(); | |||
throw bad_value_cast("Invalid path provided"); | |||
if(ptr->type()!=json::is_object) | |||
throw std::bad_cast(); | |||
throw bad_value_cast("",ptr->type(),json::is_object); | |||
json::object &obj=ptr->object(); | |||
json::object::iterator p; | |||
if((p=obj.find(part))==obj.end()) | |||
throw std::bad_cast(); | |||
throw bad_value_cast("Member "+part+" not found"); | |||
ptr=&p->second; | |||
pos=new_pos; | |||
@@ -414,7 +443,7 @@ namespace json { | |||
if(new_pos!=std::string::npos) | |||
new_pos++; | |||
if(part.empty()) | |||
throw std::bad_cast(); | |||
throw bad_value_cast("Invalid path provided"); | |||
if(ptr->type()!=json::is_object) { | |||
*ptr=json::object(); | |||
} | |||
@@ -447,11 +476,11 @@ namespace json { | |||
value const &value::operator[](std::string name) const | |||
{ | |||
if(type()!=json::is_object) | |||
throw std::bad_cast(); | |||
throw bad_value_cast("",type(),json::is_object); | |||
json::object const &self=object(); | |||
json::object::const_iterator p=self.find(name); | |||
if(p==self.end()) | |||
throw std::bad_cast(); | |||
throw bad_value_cast("Member "+name+" not found"); | |||
return p->second; | |||
} | |||
@@ -468,7 +497,7 @@ namespace json { | |||
value const &value::operator[](size_t n) const | |||
{ | |||
if(type()!=json::is_array) | |||
throw std::bad_cast(); | |||
throw bad_value_cast("",type(),json::is_array); | |||
return array().at(n); | |||
} | |||
@@ -957,6 +986,22 @@ namespace json { | |||
in.setstate( std::istream::failbit ); | |||
return in; | |||
} | |||
std::ostream &operator<<(std::ostream &out,json_type t) | |||
{ | |||
switch(t) { | |||
case is_undefined: out<<"undefined"; break; | |||
case is_null: out<<"null"; break; | |||
case is_boolean: out<<"boolean"; break; | |||
case is_number: out<<"number"; break; | |||
case is_string: out<<"string"; break; | |||
case is_object: out<<"object"; break; | |||
case is_array: out<<"array"; break; | |||
default: | |||
out<<"Illegal"; | |||
} | |||
return out; | |||
} | |||
@@ -7,8 +7,7 @@ | |||
#include <vector> | |||
#include <map> | |||
#include <string> | |||
#include <ostream> | |||
#include <istream> | |||
#include <iostream> | |||
namespace cppcms { | |||
@@ -45,10 +44,31 @@ namespace json { | |||
is_array | |||
} json_type; | |||
enum { | |||
compact = 0, | |||
readable = 1 | |||
}; | |||
class CPPCMS_API bad_value_cast : public std::bad_cast { | |||
public: | |||
bad_value_cast(); | |||
bad_value_cast(std::string const &s); | |||
bad_value_cast(std::string const &s,json_type actual); | |||
bad_value_cast(std::string const &s,json_type expected, json_type actual); | |||
virtual ~bad_value_cast() throw(); | |||
virtual const char* what() const throw(); | |||
private: | |||
std::string msg_; | |||
}; | |||
class value; | |||
std::istream CPPCMS_API &operator>>(std::istream &in,value &v); | |||
std::ostream CPPCMS_API &operator<<(std::ostream &out,value const &v); | |||
std::ostream CPPCMS_API &operator<<(std::ostream &out,json_type); | |||
class CPPCMS_API value { | |||
public: | |||
@@ -123,11 +143,25 @@ namespace json { | |||
at(path,value(v)); | |||
} | |||
std::string get(std::string path,char const *def) const | |||
{ | |||
value const &v=find(path); | |||
if(v.is_undefined()) | |||
return def; | |||
try { | |||
return v.get_value<std::string>(); | |||
} | |||
catch(std::bad_cast const &e) { | |||
return def; | |||
} | |||
} | |||
template<typename T> | |||
T get(std::string path) const | |||
{ | |||
return at(path).get_value<T>(); | |||
} | |||
template<typename T> | |||
T get(std::string path,T const &def) const | |||
{ | |||
@@ -135,8 +169,7 @@ namespace json { | |||
if(v.is_undefined()) | |||
return def; | |||
try { | |||
T tmp=get_value<T>(v); | |||
return tmp; | |||
return v.get_value<T>(); | |||
} | |||
catch(std::bad_cast const &e) { | |||
return def; | |||
@@ -220,7 +253,7 @@ namespace json { | |||
static std::pair<T1,T2> get(value const &v) | |||
{ | |||
if(v.object().size()!=2) | |||
throw std::bad_cast(); | |||
throw bad_value_cast("Object with two members expected"); | |||
std::pair<T1,T2> pair(v.get_value<T1>("first"),v.get_value<T2>("second")); | |||
return pair; | |||
} | |||
@@ -234,7 +267,7 @@ namespace json { | |||
template<typename T> | |||
struct traits<std::vector<T> > { | |||
static T get(value const &v) | |||
static std::vector<T> get(value const &v) | |||
{ | |||
std::vector<T> result; | |||
json::array const &a=v.array(); | |||
@@ -243,10 +276,10 @@ namespace json { | |||
result[i]=a[i].get_value<T>(); | |||
return result; | |||
} | |||
static void set(value &v,T const &in) | |||
static void set(value &v,std::vector<T> const &in) | |||
{ | |||
v=json::array(); | |||
json::array a=v.array(); | |||
json::array &a=v.array(); | |||
a.resize(in.size()); | |||
for(unsigned i=0;i<in.size();i++) | |||
a[i].set_value(in[i]); | |||
@@ -312,8 +345,6 @@ namespace json { | |||
}; | |||
std::istream CPPCMS_API &operator>>(std::istream &in,value &v); | |||
std::ostream CPPCMS_API &operator<<(std::ostream &out,value const &v); | |||
} // json | |||
@@ -2,7 +2,7 @@ | |||
#include "locale_environment.h" | |||
#include "service.h" | |||
#include "locale_pool.h" | |||
#include "global_config.h" | |||
#include "json.h" | |||
namespace cppcms { | |||
namespace locale { | |||
@@ -18,7 +18,7 @@ environment::environment(cppcms::service &srv) : | |||
service_(srv), | |||
d(new data) | |||
{ | |||
d->locale_name=service_.settings().str("locale.default","C"); | |||
d->locale_name=service_.settings().get("locale.default","C"); | |||
setup(); | |||
} | |||
@@ -3,7 +3,7 @@ | |||
#include "cppcms_error.h" | |||
#include "locale_gettext.h" | |||
#include "locale_info.h" | |||
#include "global_config.h" | |||
#include "json.h" | |||
#include <vector> | |||
#include <map> | |||
#include <boost/shared_ptr.hpp> | |||
@@ -20,20 +20,18 @@ struct pool::data { | |||
data() : fallback(std::locale::classic()) {} | |||
}; | |||
pool::pool(cppcms_config const &settings) : | |||
pool::pool(json::value const &settings) : | |||
d(new data) | |||
{ | |||
d->path=settings.str("locale.gettext_path","/usr/local/locale"); | |||
d->domains=settings.slist("locale.gettext_domains"); | |||
d->path=settings.get("locale.gettext_path","/usr/local/locale"); | |||
d->domains=settings.get("locale.gettext_domains",std::vector<std::string>()); | |||
std::string default_domain; | |||
if(!d->domains.empty()) | |||
default_domain=d->domains.front(); | |||
default_domain=settings.str("locale.default_gettext_domain",default_domain); | |||
std::vector<std::string> const &locales=settings.slist("locale.locales"); | |||
default_domain=settings.get("locale.default_gettext_domain",default_domain); | |||
std::vector<std::string> const &locales=settings.get("locale.locales",std::vector<std::string>()); | |||
for(unsigned i=0;i<locales.size();i++) { | |||
std::string name=locales[i]; | |||
std::auto_ptr<gettext> gt(new gettext()); | |||
@@ -10,13 +10,12 @@ | |||
namespace cppcms { | |||
class cppcms_config; | |||
namespace json { class value; } | |||
namespace locale { | |||
class CPPCMS_API pool : util::noncopyable { | |||
public: | |||
pool(cppcms_config const &conf); | |||
pool(json::value const &conf); | |||
~pool(); | |||
std::locale const &get(std::string const &name) const; | |||
@@ -3,7 +3,6 @@ | |||
#include "service_impl.h" | |||
#include "applications_pool.h" | |||
#include "thread_pool.h" | |||
#include "global_config.h" | |||
#include "cppcms_error.h" | |||
#include "cgi_acceptor.h" | |||
#include "cgi_api.h" | |||
@@ -12,6 +11,7 @@ | |||
#include "fastcgi_api.h" | |||
#include "locale_pool.h" | |||
#include "internal_file_server.h" | |||
#include "json.h" | |||
#include "asio_config.h" | |||
@@ -20,26 +20,110 @@ | |||
#endif | |||
#include <iostream> | |||
#include <fstream> | |||
#include <boost/lexical_cast.hpp> | |||
#include <boost/regex.hpp> | |||
namespace cppcms { | |||
service::service(json::value const &v) : | |||
impl_(new impl::service()) | |||
{ | |||
impl_->settings_.reset(new json::value(v)); | |||
setup(); | |||
} | |||
service::service(int argc,char *argv[]) : | |||
impl_(new impl::service()) | |||
{ | |||
impl_->settings_.reset(new cppcms_config()); | |||
impl_->settings_->load(argc,argv); | |||
int apps=settings().integer("service.applications_pool_size",threads_no()*2); | |||
impl_->applications_pool_.reset(new cppcms::applications_pool(*this,apps)); | |||
impl_->settings_.reset(new json::value()); | |||
load_settings(argc,argv); | |||
setup(); | |||
} | |||
void service::load_settings(int argc,char *argv[]) | |||
{ | |||
using std::string; | |||
std::string file_name; | |||
char const *e = getenv("CPPCMS_CONFIG"); | |||
if(e) | |||
file_name = e; | |||
else { | |||
for(int i=1;i<argc;i++) { | |||
if(argv[i]==std::string("-c")) { | |||
if(!file_name.empty()) { | |||
throw cppcms_error("Switch -c can't be used twice"); | |||
} | |||
if(i+1 < argc) | |||
file_name=argv[i+1]; | |||
else | |||
throw cppcms_error("Switch -c requires configuration file parameters"); | |||
i++; | |||
} | |||
else if(argv[i]==std::string("-U")) | |||
break; | |||
} | |||
} | |||
json::value &val=*impl_->settings_; | |||
if(!file_name.empty()) { | |||
std::ifstream fin(file_name.c_str()); | |||
if(!fin) | |||
throw cppcms_error("Failed to open filename:"+file_name); | |||
int line_no=0; | |||
if(!val.load(fin,true,&line_no)) { | |||
std::ostringstream ss; | |||
ss<<"Error reading configurarion file "<<file_name<<" in line:"<<line_no; | |||
throw cppcms_error(ss.str()); | |||
} | |||
} | |||
boost::regex r("^--((\\w+)(\\.\\w+)*)=((true)|(false)|(null)|(-?\\d+(\\.\\d+)?([eE][\\+-]?\\d+)?)|(.*))$"); | |||
for(int i=1;i<argc;i++) { | |||
std::string arg=argv[i]; | |||
if(arg=="-c") { | |||
i++; | |||
continue; | |||
} | |||
if(arg=="-U") | |||
break; | |||
if(arg.substr(0,2)=="--") { | |||
boost::cmatch m; | |||
if(!boost::regex_match(arg.c_str(),m,r)) | |||
throw cppcms_error("Invalid switch: "+arg); | |||
std::string path=m[1]; | |||
if(!m[5].str().empty()) | |||
val.set(path,true); | |||
else if(!m[6].str().empty()) | |||
val.set(path,false); | |||
else if(!m[7].str().empty()) | |||
val.set(path,json::null()); | |||
else if(!m[8].str().empty()) | |||
val.set(path,boost::lexical_cast<double>(m[8].str())); | |||
else | |||
val.set(path,m[4].str()); | |||
} | |||
} | |||
} | |||
void service::setup() | |||
{ | |||
int apps=settings().get("service.applications_pool_size",threads_no()*2); | |||
impl_->applications_pool_.reset(new cppcms::applications_pool(*this,apps)); | |||
} | |||
service::~service() | |||
{ | |||
} | |||
int service::threads_no() | |||
{ | |||
return settings().integer("service.worker_threads",5); | |||
return settings().get("service.worker_threads",5); | |||
} | |||
namespace { | |||
@@ -97,7 +181,7 @@ void service::setup_exit_handling() | |||
impl_->notification_socket_=impl_->sig_.native(); | |||
if(settings().integer("service.disable_global_exit_handling",0)) | |||
if(settings().get("service.disable_global_exit_handling",false)) | |||
return; | |||
the_service=this; | |||
@@ -145,7 +229,7 @@ void service::run() | |||
locale_pool(); | |||
start_acceptor(); | |||
if(settings().integer("file_server.enable",0)) | |||
if(settings().get("file_server.enable",false)) | |||
applications_pool().mount(applications_factory<cppcms::impl::file_server>(),""); | |||
if(prefork()) { | |||
@@ -161,7 +245,7 @@ void service::run() | |||
int service::procs_no() | |||
{ | |||
int procs=settings().integer("service.procs",0); | |||
int procs=settings().get("service.procs",0); | |||
if(procs < 0) | |||
procs = 0; | |||
#ifdef CPPCMS_WIN32 | |||
@@ -180,7 +264,7 @@ bool service::prefork() | |||
#else // UNIX | |||
bool service::prefork() | |||
{ | |||
int procs=settings().integer("service.procs",0); | |||
int procs=settings().get("service.procs",0); | |||
if(procs<=0) | |||
return false; | |||
std::vector<int> pids(procs,0); | |||
@@ -233,16 +317,16 @@ bool service::prefork() | |||
void service::start_acceptor() | |||
{ | |||
using namespace impl::cgi; | |||
std::string api=settings().str("service.api"); | |||
std::string ip=settings().str("service.ip","127.0.0.1"); | |||
std::string api=settings().get<std::string>("service.api"); | |||
std::string ip=settings().get("service.ip","127.0.0.1"); | |||
int port=0; | |||
std::string socket=settings().str("service.socket",""); | |||
int backlog=settings().integer("service.backlog",threads_no() * 2); | |||
std::string socket=settings().get("service.socket",""); | |||
int backlog=settings().get("service.backlog",threads_no() * 2); | |||
bool tcp=socket.empty(); | |||
if(tcp && port==0) { | |||
port=settings().integer("service.port"); | |||
port=settings().get<int>("service.port"); | |||
} | |||
if(tcp) { | |||
@@ -292,7 +376,7 @@ cppcms::thread_pool &service::thread_pool() | |||
return *impl_->thread_pool_; | |||
} | |||
cppcms::cppcms_config const &service::settings() | |||
json::value const &service::settings() | |||
{ | |||
return *impl_->settings_; | |||
} | |||
@@ -18,11 +18,14 @@ namespace cppcms { | |||
namespace locale { | |||
class pool; | |||
} | |||
class cppcms_config; | |||
namespace json { | |||
class value; | |||
} | |||
class CPPCMS_API service : public util::noncopyable | |||
{ | |||
public: | |||
service(json::value const &v); | |||
service(int argc,char *argv[]); | |||
~service(); | |||
@@ -31,7 +34,7 @@ namespace cppcms { | |||
cppcms::applications_pool &applications_pool(); | |||
cppcms::thread_pool &thread_pool(); | |||
cppcms::cppcms_config const &settings(); | |||
json::value const &settings(); | |||
cppcms::locale::pool const &locale_pool(); | |||
cppcms::impl::service &impl(); | |||
@@ -41,6 +44,8 @@ namespace cppcms { | |||
int threads_no(); | |||
int procs_no(); | |||
private: | |||
void setup(); | |||
void load_settings(int argc,char *argv[]); | |||
void stop(); | |||
void start_acceptor(); | |||
void setup_exit_handling(); | |||
@@ -2,11 +2,11 @@ | |||
#define CPPCMS_SERVICE_IMPL_H | |||
#include "asio_config.h" | |||
#include "json.h" | |||
#include <memory> | |||
namespace cppcms { | |||
class service; | |||
class cppcms_config; | |||
class applications_pool; | |||
class thread_pool; | |||
@@ -30,7 +30,7 @@ namespace impl { | |||
boost::asio::io_service io_service_; | |||
std::auto_ptr<cgi::acceptor> acceptor_; | |||
std::auto_ptr<cppcms_config> settings_; | |||
std::auto_ptr<json::value> settings_; | |||
std::auto_ptr<applications_pool> applications_pool_; | |||
std::auto_ptr<thread_pool> thread_pool_; | |||
std::auto_ptr<locale::pool> locale_pool_; | |||
@@ -59,6 +59,19 @@ int main() | |||
cout<<line_no<<endl; | |||
cout<<"-------------"<<endl; | |||
} | |||
std::vector<std::string> vals; | |||
vals.push_back("Yes"); | |||
vals.push_back("No"); | |||
v.set("z",vals); | |||
cout<<v<<endl; | |||
vals.clear(); | |||
vals = v.get("z",std::vector<std::string>()); | |||
cout<<vals.size()<<endl; | |||
cout<<vals.at(0)<<" "<<vals.at(1)<<endl; | |||
cout<<v.get("foo.bar",5)<<endl; | |||
cout<<v.get<int>("foo.bar")<<endl; | |||
cout<<v.get("x","Nothing")<<endl; | |||
} | |||
catch(std::exception const &e) | |||