Browse Source

Moved to json as primary configuration

format, global_config replaced with json::value
master
Artyom Beilis 15 years ago
parent
commit
4dc6f031f2
24 changed files with 310 additions and 590 deletions
  1. +2
    -2
      Makefile.am
  2. +1
    -1
      application.cpp
  3. +4
    -2
      application.h
  4. +2
    -2
      applications_pool.cpp
  5. +3
    -3
      cgi_api.cpp
  6. +44
    -0
      config.js
  7. +3
    -1
      config.txt
  8. +2
    -2
      fastcgi_api.cpp
  9. +0
    -434
      global_config.cpp
  10. +0
    -69
      global_config.h
  11. +5
    -4
      http_api.cpp
  12. +1
    -1
      http_context.cpp
  13. +2
    -3
      http_context.h
  14. +7
    -7
      http_response.cpp
  15. +4
    -4
      internal_file_server.cpp
  16. +57
    -12
      json.cpp
  17. +41
    -10
      json.h
  18. +2
    -2
      locale_environment.cpp
  19. +6
    -8
      locale_pool.cpp
  20. +2
    -3
      locale_pool.h
  21. +100
    -16
      service.cpp
  22. +7
    -2
      service.h
  23. +2
    -2
      service_impl.h
  24. +13
    -0
      tests/json_test.cpp

+ 2
- 2
Makefile.am View File

@@ -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





+ 1
- 1
application.cpp View File

@@ -57,7 +57,7 @@ cppcms::service &application::service()
return *d->service;
}

cppcms_config const &application::settings()
json::value const &application::settings()
{
return service().settings();
}


+ 4
- 2
application.h View File

@@ -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
- 2
applications_pool.cpp View File

@@ -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)


+ 3
- 3
cgi_api.cpp View File

@@ -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


+ 44
- 0
config.js View File

@@ -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"
}
}

+ 3
- 1
config.txt View File

@@ -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


+ 2
- 2
fastcgi_api.cpp View File

@@ -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()
{


+ 0
- 434
global_config.cpp View File

@@ -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

+ 0
- 69
global_config.h View File

@@ -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
- 4
http_api.cpp View File

@@ -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++) {



+ 1
- 1
http_context.cpp View File

@@ -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();
}


+ 2
- 3
http_context.h View File

@@ -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();



+ 7
- 7
http_response.cpp View File

@@ -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
- 4
internal_file_server.cpp View File

@@ -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);


+ 57
- 12
json.cpp View File

@@ -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;
}





+ 41
- 10
json.h View File

@@ -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
- 2
locale_environment.cpp View File

@@ -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();
}



+ 6
- 8
locale_pool.cpp View File

@@ -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());



+ 2
- 3
locale_pool.h View File

@@ -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;


+ 100
- 16
service.cpp View File

@@ -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_;
}


+ 7
- 2
service.h View File

@@ -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
- 2
service_impl.h View File

@@ -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_;


+ 13
- 0
tests/json_test.cpp View File

@@ -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)


Loading…
Cancel
Save