@@ -20,6 +20,9 @@ option(DISABLE_STATIC "Disable static libraries build" OFF) | |||
option(DISABLE_ICONV "Disable usage iconv library - use ICU for conversion" OFF) | |||
option(DISABLE_GCRYPT "Disable usage of gcrypt library, no AES cookies encryption would be available" OFF) | |||
option(USE_EXTERNAL_BOOST "Use external Boost library and not internal one, boost version provided by BOOST_SUFFIX variable" OFF) | |||
option(DISABLE_FCGI "Disable fastcgi web server api" OFF) | |||
option(DISABLE_SCGI "Disable scgi web server api" OFF) | |||
option(DISABLE_HTTP "Disable http web server" OFF) | |||
############################################################################# | |||
# | |||
@@ -154,6 +157,8 @@ include_directories(${CMAKE_SOURCE_DIR}) | |||
include_directories(localization) | |||
set(CPPCMS_LIBRARY_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}) | |||
set(CPPCMS_LIBRARY_PREFIX ${CMAKE_SHARED_LIBRARY_PREFIX}) | |||
check_cxx_source_compiles( | |||
@@ -274,7 +279,6 @@ set(CPPCMS_PUBLIC_HEADERS | |||
filters.h | |||
form.h | |||
hold_ptr.h | |||
http_connection.h | |||
http_context.h | |||
http_cookie.h | |||
http_file.h | |||
@@ -350,9 +354,6 @@ set(CPPCMS_SOURCES | |||
base_view.cpp | |||
views_pool.cpp | |||
internal_file_server.cpp | |||
scgi_api.cpp | |||
fastcgi_api.cpp | |||
http_api.cpp | |||
atomic_counter.cpp | |||
aio_timer.cpp | |||
json.cpp | |||
@@ -380,6 +381,23 @@ if(NOT DISABLE_GCRYPT) | |||
find_library(LIB_GCRYPT gcrypt) | |||
endif(NOT DISABLE_GCRYPT) | |||
if(NOT DISABLE_FCGI) | |||
set(CPPCMS_SOURCES ${CPPCMS_SOURCES} fastcgi_api.cpp) | |||
set(CPPCMS_HAS_FCGI 1) | |||
endif() | |||
if(NOT DISABLE_SCGI) | |||
set(CPPCMS_SOURCES ${CPPCMS_SOURCES} scgi_api.cpp) | |||
set(CPPCMS_HAS_SCGI 1) | |||
endif() | |||
if(NOT DISABLE_HTTP) | |||
set(CPPCMS_SOURCES ${CPPCMS_SOURCES} http_api.cpp) | |||
set(CPPCMS_HAS_HTTP 1) | |||
endif() | |||
if(LIB_GCRYPT) | |||
set(CPPCMS_SOURCES ${CPPCMS_SOURCES} aes_encryptor.cpp) | |||
set(HAVE_GCRYPT 1) | |||
@@ -1,9 +1,8 @@ | |||
- form.* | |||
Implement, Select, Radio, Date-Time | |||
Date-Time | |||
- http_request.*, cgi_api.* | |||
Implement File Upload | |||
- Implement Asynchronous API | |||
- Implement JSON-RPC | |||
- Reintergrate Sessions over TCP/IP | |||
- Reintegrate Cache Support over TCP/IP and shared_memory | |||
- Update cppcms_tmpl_cc according to new code |
@@ -52,12 +52,6 @@ application::~application() | |||
} | |||
} | |||
long application::refs() | |||
{ | |||
return refs_; | |||
} | |||
cppcms::service &application::service() | |||
{ | |||
return *d->service; | |||
@@ -233,8 +233,17 @@ namespace cppcms { | |||
/// Returns true if current application was created as asynchronous application. | |||
/// | |||
bool is_asynchronous(); | |||
long refs(); | |||
/// | |||
/// This is main function of the application that is called when it is matched | |||
/// according to the regular expression in the applications_pool class. | |||
/// | |||
/// By default, main calls dispatcher().dispatch(url). And if the last fails, it | |||
/// creates 404 Error page. This allows developers to create its own hooks for | |||
/// reaction on incoming URL as, initialization and cleanup of general resources, | |||
/// Custom 404 and error handlers etc. | |||
/// | |||
virtual void main(std::string url); | |||
private: | |||
@@ -48,6 +48,8 @@ namespace cppcms { | |||
/// Mount an application factory \a aps for processing of any incoming requests. Application | |||
/// would receive PATH_INFO CGI variable for URL matching. | |||
/// | |||
/// This member function is thread safe. | |||
/// | |||
void mount(std::auto_ptr<factory> aps); | |||
/// | |||
@@ -55,42 +57,56 @@ namespace cppcms { | |||
/// matches the regular expression \a path_info. The marched part of an regular expression \a select would | |||
/// be passed for URL matching. | |||
/// | |||
/// This member function is thread safe. | |||
/// | |||
void mount(std::auto_ptr<factory> aps,std::string path_info,int select); | |||
/// | |||
/// Mount an application factory \a aps for processing of requests for which CGI SCRIPT_NAME exactly | |||
/// matches \a script_name parameter. CGI PATH_INFO is passed to application for URL matching. | |||
/// | |||
/// This member function is thread safe. | |||
/// | |||
void mount(std::auto_ptr<factory> aps,std::string script_name); | |||
/// | |||
/// Mount an application factory \a aps for processing of requests for which CGI SCRIPT_NAME exactly | |||
/// matches \a script_name parameter. And PATH_INFO patches regular expression \a path_info. | |||
/// The matched part \a select is passed to application for URL matching. | |||
/// | |||
/// This member function is thread safe. | |||
/// | |||
void mount(std::auto_ptr<factory> aps,std::string script_name,std::string path_info, int select); | |||
/// | |||
/// Mount an asynchronous application \a app for processing of any incoming requests. Application | |||
/// would receive PATH_INFO CGI variable for URL matching. | |||
/// | |||
/// This member function is thread safe. | |||
/// | |||
void mount(intrusive_ptr<application> app); | |||
/// | |||
/// Mount an asynchronous application \a app for processing of requests for which CGI PATH_INFO | |||
/// matches the regular expression \a path_info. The marched part of an regular expression \a select would | |||
/// be passed for URL matching. | |||
/// | |||
/// This member function is thread safe. | |||
/// | |||
void mount(intrusive_ptr<application> app,std::string path_info,int select); | |||
/// | |||
/// Mount an asynchronous application \a app for processing of requests for which CGI SCRIPT_NAME exactly | |||
/// matches \a script_name parameter. And PATH_INFO patches regular expression \a path_info. | |||
/// The matched part \a select is passed to application for URL matching. | |||
/// | |||
/// This member function is thread safe. | |||
/// | |||
void mount(intrusive_ptr<application> app,std::string script_name); | |||
/// | |||
/// Mount an asynchronous application \a app for processing of requests for which CGI SCRIPT_NAME exactly | |||
/// matches \a script_name parameter. And PATH_INFO patches regular expression \a path_info. | |||
/// The matched part \a select is passed to application for URL matching. | |||
/// | |||
/// This member function is thread safe. | |||
/// | |||
void mount(intrusive_ptr<application> app,std::string script_name,std::string path_info, int select); | |||
/// | |||
@@ -5,7 +5,7 @@ | |||
namespace cppcms { | |||
/// | |||
/// \brief This is a simple polymorphic class that every content for templates rendering should be dervided from it. | |||
/// \brief This is a simple polymorphic class that every content for templates rendering should be derided from it. | |||
/// It does not carry much information with exception of RTTI that allows type-safe casting of user provided | |||
/// content instances to target content class that is used by specific template. | |||
/// | |||
@@ -21,14 +21,14 @@ namespace cppcms { | |||
/// \brief This class is base class for all views (skins) rendered by CppCMS template engine. | |||
/// | |||
/// Users are not expected to derive from this class or use it directly. CppCMS template compiler | |||
/// create skins that are useable with template engine and each template is derived from the \a base_view | |||
/// create skins that are usable with template engine and each template is derived from the \a base_view | |||
/// class. | |||
/// | |||
class CPPCMS_API base_view : util::noncopyable { | |||
public: | |||
/// | |||
/// The main randering function -- render the main HTML page. It is usually overriden in template engine. | |||
/// The main rendering function -- render the main HTML page. It is usually overridden in template engine. | |||
/// | |||
virtual void render(); | |||
virtual ~base_view(); | |||
@@ -66,6 +66,10 @@ namespace cppcms { | |||
class CPPCMS_API cache_interface : public util::noncopyable { | |||
public: | |||
/// | |||
/// Internal API, don't use it | |||
/// | |||
cache_interface(http::context &context); | |||
~cache_interface(); | |||
@@ -22,6 +22,202 @@ | |||
namespace cppcms { namespace impl { namespace cgi { | |||
/* | |||
class multipart_separator { | |||
public: | |||
multipart_separator(std::vector<char> &body,unsigned &body_ptr,std::string boundary) : | |||
body_(body), | |||
body_ptr_(body_ptr) | |||
{ | |||
boundary_ = "--" + boundary; | |||
pos_ = 0; | |||
last_ = false; | |||
} | |||
int getc() | |||
{ | |||
if(body_ptr_ < body_.size()) { | |||
return body_[body_ptr_++]; | |||
} | |||
else { | |||
body_.clear(); | |||
body_ptr_=0; | |||
return -1; | |||
} | |||
} | |||
enum { incomplete, last_chunk, chunk }; | |||
int next() | |||
{ | |||
for(;;){ | |||
int c=getc(); | |||
if(c < 0) | |||
return incomplete; | |||
if(pos_ < bodundary_.size()) { | |||
if(c == boundary_[pos_]) { | |||
pos_++; | |||
} | |||
else { | |||
if(pos_ != 0) | |||
output_.append(boundary_.substr(0,pos_)); | |||
output_.append(char(c)); | |||
pos_ = 0; | |||
} | |||
} | |||
else if(pos_ == boundary_.size()) { | |||
c == '-'; | |||
last_ = true; | |||
pos_ = 0x10001; | |||
} | |||
else { | |||
unsigned diff = pos_ & 0xFFFF; | |||
if(last_){ | |||
if(last_ending[diff]==c) { | |||
pos_ ++; | |||
diff ++ ; | |||
} | |||
else { | |||
output_.append(last_ending,diff); | |||
output_.append(char(c)); | |||
pos_ = 0; | |||
last_ = false; | |||
} | |||
if(diff == 4) | |||
return last_chunk; | |||
} | |||
else { | |||
if(ending[diff] == c) { | |||
pos_ ++; | |||
diff ++; | |||
} | |||
else { | |||
output_.append(ending,diff); | |||
output_.append(char(c)); | |||
pos_ = 0; | |||
} | |||
if(diff == 2) { | |||
pos_ = 0; | |||
return chunk; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
private: | |||
static char const last_ending[]="--\r\n" | |||
static char const ending[]="\r\n" | |||
}; | |||
class multipart_parser : public util::noncopyable { | |||
public: | |||
multipart_parser(std::vector<char> &body, unsigned &ptr) : | |||
separator_(body,ptr), | |||
parser_(body,ptr) | |||
{ | |||
} | |||
struct none{}; | |||
struct eof{}; | |||
typedef std::pair<std::string,std::string> pair_type; | |||
typedef boost::shared_ptr<http::file> file_type; | |||
typedef enum { none, eof, error } result_type; | |||
typedef boost::variant<result_type,pair_type,file_type,eof> variant_type; | |||
void append(bool final = false) | |||
{ | |||
if(result_.which() == 1) { | |||
std::string &last=boost::get<pair_type>(result_).second; | |||
last.append(separator_.output()); | |||
} | |||
else if(result_.which() == 2) { | |||
file_type &file == boost::get<file_type>(result_); | |||
file.write(separator_.output()); | |||
if(final) | |||
file.close(); | |||
} | |||
} | |||
variant_type next() | |||
{ | |||
switch(state:) { | |||
case done: | |||
return eof; | |||
case reading_data: | |||
switch(separator_.next()) { | |||
case multipart_separator::incomplete: | |||
append(); | |||
return none; | |||
case multipart_separator::chunk; | |||
{ | |||
append(final); | |||
variant_type tmp = result_; | |||
result_=none; | |||
state_ = reading_headers; | |||
return tmp; | |||
} | |||
case multipart_separator::last_chunk; | |||
{ | |||
append(final); | |||
variant_type tmp = result_; | |||
result_=none; | |||
state_ = done; | |||
return tmp; | |||
} | |||
default: | |||
throw cppcms_error( | |||
(boost::format("Internal error at " __FILE__ "line %d") % __LINE__).str()); | |||
} | |||
break; | |||
case reading_headers: | |||
switch(parser_.step()) | |||
case parset::mode_data: | |||
return none; | |||
case parser::error_observerd: | |||
return error; | |||
case parser::end_of_headers: | |||
if(result_.which() == 0) | |||
return error; | |||
state_ = reading_data; | |||
return none; | |||
case parser::got_header: | |||
{ | |||
std::string const header = parser.header_; | |||
parser.header_.clean(); | |||
std::string::const_iterator m,p=header.begin(); | |||
std::string::const_iterator e=header.end(); | |||
p=http::protocol::skip_ws(p,e); | |||
m=p; | |||
p=http::protocol::tocken(p,e); | |||
std::string type(m,p); | |||
if(http::protocol::compare("Content-Disposition",type)==0) | |||
{ | |||
while(p!=e) { | |||
if(http::protocol::separator(*p)) { | |||
++p; | |||
continue; | |||
} | |||
m=p; | |||
if((p=http::protocol::tocken(p,e))!=m) { | |||
if(http::protocol::compare(std::string(m,p),"name")) | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
private: | |||
multipart_separator separator_; | |||
cppcms::http::impl::parser parser_; | |||
}; | |||
*/ | |||
connection::connection(cppcms::service &srv) : | |||
service_(&srv), | |||
@@ -95,6 +95,10 @@ | |||
#cmakedefine CPPCMS_USE_EXTERNAL_BOOST | |||
#cmakedefine CPPCMS_HAS_FCGI | |||
#cmakedefine CPPCMS_HAS_SCGI | |||
#cmakedefine CPPCMS_HAS_HTTP | |||
/* Version number of package */ | |||
#define VERSION PACKAGE_VERSION | |||
@@ -298,14 +298,32 @@ namespace impl{ | |||
predefined_["iso-8859-8"]=&iso_8859_8_valid<char const *>; | |||
predefined_["iso-8859-11"]=&iso_8859_11_valid<char const *>; | |||
predefined_["cp1250"]=predefined_["windows-1250"]=&windows_1250_valid<char const *>; | |||
predefined_["cp1251"]=predefined_["windows-1251"]=&windows_1251_valid<char const *>; | |||
predefined_["cp1252"]=predefined_["windows-1252"]=&windows_1252_valid<char const *>; | |||
predefined_["cp1253"]=predefined_["windows-1253"]=&windows_1253_valid<char const *>; | |||
predefined_["cp1255"]=predefined_["windows-1255"]=&windows_1255_valid<char const *>; | |||
predefined_["cp1256"]=predefined_["windows-1256"]=&windows_1256_valid<char const *>; | |||
predefined_["cp1257"]=predefined_["windows-1257"]=&windows_1257_valid<char const *>; | |||
predefined_["cp1258"]=predefined_["windows-1258"]=&windows_1258_valid<char const *>; | |||
predefined_["windows-1250"]=&windows_1250_valid<char const *>; | |||
predefined_["windows-1251"]=&windows_1251_valid<char const *>; | |||
predefined_["windows-1252"]=&windows_1252_valid<char const *>; | |||
predefined_["windows-1253"]=&windows_1253_valid<char const *>; | |||
predefined_["windows-1255"]=&windows_1255_valid<char const *>; | |||
predefined_["windows-1256"]=&windows_1256_valid<char const *>; | |||
predefined_["windows-1257"]=&windows_1257_valid<char const *>; | |||
predefined_["windows-1258"]=&windows_1258_valid<char const *>; | |||
predefined_["cp1250"]=&windows_1250_valid<char const *>; | |||
predefined_["cp1251"]=&windows_1251_valid<char const *>; | |||
predefined_["cp1252"]=&windows_1252_valid<char const *>; | |||
predefined_["cp1253"]=&windows_1253_valid<char const *>; | |||
predefined_["cp1255"]=&windows_1255_valid<char const *>; | |||
predefined_["cp1256"]=&windows_1256_valid<char const *>; | |||
predefined_["cp1257"]=&windows_1257_valid<char const *>; | |||
predefined_["cp1258"]=&windows_1258_valid<char const *>; | |||
predefined_["1250"]=&windows_1250_valid<char const *>; | |||
predefined_["1251"]=&windows_1251_valid<char const *>; | |||
predefined_["1252"]=&windows_1252_valid<char const *>; | |||
predefined_["1253"]=&windows_1253_valid<char const *>; | |||
predefined_["1255"]=&windows_1255_valid<char const *>; | |||
predefined_["1256"]=&windows_1256_valid<char const *>; | |||
predefined_["1257"]=&windows_1257_valid<char const *>; | |||
predefined_["1258"]=&windows_1258_valid<char const *>; | |||
predefined_["koi8r"]=predefined_["koi8-r"]=&koi8_valid<char const *>; | |||
predefined_["koi8u"]=predefined_["koi8-u"]=&koi8_valid<char const *>; | |||
@@ -279,6 +279,9 @@ namespace cppcms { | |||
streamable obj_; | |||
struct data; | |||
util::copy_ptr<data> d; | |||
}; | |||
inline std::ostream &operator<<(std::ostream &out,raw const &obj) | |||
@@ -286,7 +289,12 @@ namespace cppcms { | |||
obj(out); | |||
return out; | |||
} | |||
/// | |||
/// \brief Format date to ouput stream | |||
/// | |||
/// Formats date to the stream, date is represented as time_t | |||
/// | |||
class CPPCMS_API date { | |||
@@ -310,6 +318,11 @@ namespace cppcms { | |||
return out; | |||
} | |||
/// | |||
/// \brief Format time to ouput stream | |||
/// | |||
/// Formats time to the stream, time is represented as time_t | |||
/// | |||
class CPPCMS_API time { | |||
public: | |||
time(); | |||
@@ -330,6 +343,11 @@ namespace cppcms { | |||
obj(out); | |||
return out; | |||
} | |||
/// | |||
/// \brief Format date and time to ouput stream | |||
/// | |||
/// Formats date and time to the stream, date and time is represented as time_t | |||
/// | |||
class CPPCMS_API datetime { | |||
public: | |||
datetime(); | |||
@@ -1,4 +1,5 @@ | |||
#define CPPCMS_SOURCE | |||
//#define DEBUG_HTTP_PARSER | |||
#include "asio_config.h" | |||
#include "cgi_api.h" | |||
#include "cgi_acceptor.h" | |||
@@ -6,7 +7,7 @@ | |||
#include "service_impl.h" | |||
#include "cppcms_error_category.h" | |||
#include "json.h" | |||
#include "http_protocol.h" | |||
#include "http_parser.h" | |||
#include "config.h" | |||
#include <string.h> | |||
#include <iostream> | |||
@@ -18,7 +19,6 @@ | |||
namespace boost = cppcms_boost; | |||
#endif | |||
//#define DEBUG_HTTP_PARSER | |||
namespace cppcms { | |||
@@ -85,7 +85,7 @@ namespace cgi { | |||
input_body_.resize(n); | |||
for(;;) { | |||
using ::cppcms::http::impl::parser; | |||
switch(input_parser_.step()) { | |||
case parser::more_data: | |||
// Assuming body_ptr == body.size() | |||
@@ -215,6 +215,8 @@ namespace cgi { | |||
char const *ptr=reinterpret_cast<char const *>(p); | |||
output_body_.insert(output_body_.end(),ptr,ptr+s); | |||
using cppcms::http::impl::parser; | |||
for(;;) { | |||
switch(output_parser_.step()) { | |||
case parser::more_data: | |||
@@ -388,187 +390,6 @@ namespace cgi { | |||
return true; | |||
} | |||
class parser { | |||
enum { | |||
idle, | |||
input_observed, | |||
last_lf_exptected, | |||
lf_exptected, | |||
space_or_other_exptected, | |||
quote_expected, | |||
pass_quote_exptected, | |||
closing_bracket_expected, | |||
pass_closing_bracket_expected | |||
} state_; | |||
unsigned bracket_counter_; | |||
std::vector<char> &body_; | |||
unsigned &body_ptr_; | |||
inline int getc() | |||
{ | |||
if(body_ptr_ < body_.size()) { | |||
return body_[body_ptr_++]; | |||
} | |||
else { | |||
body_.clear(); | |||
body_ptr_=0; | |||
return -1; | |||
} | |||
} | |||
inline void ungetc(int c) | |||
{ | |||
if(body_ptr_ > 0) { | |||
body_ptr_--; | |||
body_[body_ptr_]=c; | |||
} | |||
else { | |||
body_.insert(body_.begin(),c); | |||
} | |||
} | |||
// Non copyable | |||
parser(parser const &); | |||
parser const &operator=(parser const &); | |||
public: | |||
std::string header_; | |||
parser(std::vector<char> &body,unsigned &body_ptr) : | |||
state_(idle), | |||
bracket_counter_(0), | |||
body_(body), | |||
body_ptr_(body_ptr) | |||
{ | |||
} | |||
enum { more_data, got_header, end_of_headers , error_observerd }; | |||
int step() | |||
{ | |||
#ifdef DEBUG_HTTP_PARSER | |||
static char const *states[]= { | |||
"idle", | |||
"input_observed", | |||
"last_lf_exptected", | |||
"lf_exptected", | |||
"space_or_other_exptected", | |||
"quote_expected", | |||
"pass_quote_exptected", | |||
"closing_bracket_expected", | |||
"pass_closing_bracket_expected" | |||
}; | |||
#endif | |||
for(;;) { | |||
int c=getc(); | |||
#if defined DEBUG_HTTP_PARSER | |||
std::cerr<<"Step("<<body_ptr_<<":"<<body_.size()<<": "<<std::flush; | |||
if(c>=32) | |||
std::cerr<<"["<<char(c)<<"] "<<states[state_]<<std::endl; | |||
else | |||
std::cerr<<c<<" "<<states[state_]<<std::endl; | |||
#endif | |||
if(c<0) | |||
return more_data; | |||
switch(state_) { | |||
case idle: | |||
header_.clear(); | |||
switch(c) { | |||
case '\r': | |||
state_=last_lf_exptected; | |||
break; | |||
case '"': | |||
state_=quote_expected; | |||
break; | |||
case '(': | |||
state_=closing_bracket_expected; | |||
bracket_counter_++; | |||
break; | |||
default: | |||
state_=input_observed; | |||
} | |||
break; | |||
case last_lf_exptected: | |||
if(c!='\n') return error_observerd; | |||
header_.clear(); | |||
return end_of_headers; | |||
case lf_exptected: | |||
if(c!='\n') return error_observerd; | |||
state_=space_or_other_exptected; | |||
break; | |||
case space_or_other_exptected: | |||
if(c==' ' || c=='\t') { | |||
// Convert LWS to space as required by | |||
// RFC, so remove last CRLF | |||
header_.resize(header_.size() - 2); | |||
state_=input_observed; | |||
break; | |||
} | |||
ungetc(c); | |||
header_.resize(header_.size()-2); | |||
state_=idle; | |||
#ifdef DEBUG_HTTP_PARSER | |||
std::cerr<<"["<<header_<<"]"<<std::endl; | |||
#endif | |||
return got_header; | |||
case input_observed: | |||
switch(c) { | |||
case '\r': | |||
state_=lf_exptected; | |||
break; | |||
case '"': | |||
state_=quote_expected; | |||
break; | |||
case '(': | |||
state_=closing_bracket_expected; | |||
bracket_counter_++; | |||
break; | |||
default: | |||
state_=input_observed; | |||
} | |||
break; | |||
case quote_expected: | |||
switch(c) { | |||
case '"': | |||
state_=input_observed; | |||
break; | |||
case '\\': | |||
state_=pass_quote_exptected; | |||
break; | |||
} | |||
break; | |||
case pass_quote_exptected: | |||
if(c < 0 || c >=127) | |||
return error_observerd; | |||
state_=quote_expected; | |||
break; | |||
case closing_bracket_expected: | |||
switch(c) { | |||
case ')': | |||
bracket_counter_--; | |||
if(bracket_counter_==0) | |||
state_=input_observed; | |||
break; | |||
case '\\': | |||
state_=pass_closing_bracket_expected; | |||
break; | |||
} | |||
break; | |||
case pass_closing_bracket_expected: | |||
if(c < 0 || c >=127) | |||
return error_observerd; | |||
state_=closing_bracket_expected; | |||
break; | |||
} | |||
header_+=char(c); | |||
} | |||
} | |||
}; | |||
intrusive_ptr<http> self() | |||
{ | |||
@@ -581,10 +402,10 @@ namespace cgi { | |||
std::vector<char> input_body_; | |||
unsigned input_body_ptr_; | |||
parser input_parser_; | |||
::cppcms::http::impl::parser input_parser_; | |||
std::vector<char> output_body_; | |||
unsigned output_body_ptr_; | |||
parser output_parser_; | |||
::cppcms::http::impl::parser output_parser_; | |||
std::map<std::string,std::string> env_; | |||
@@ -23,32 +23,102 @@ namespace cppcms { | |||
class request; | |||
class response; | |||
/// | |||
/// \brief context is a central class that holds all specific connection related information. | |||
/// It encapsulates CGI request and response, cache, session and locale information | |||
/// | |||
/// Instance of this class is created upon client requests, it provides access to all | |||
/// connection related interfaces. This class is unique per each applications hierarchy | |||
/// and destroyed when HTTP request/response is completed | |||
/// | |||
class CPPCMS_API context : public refcounted | |||
{ | |||
public: | |||
/// | |||
/// Internal API, don't use it | |||
/// | |||
context(intrusive_ptr<impl::cgi::connection> conn); | |||
/// | |||
/// Destructor. | |||
~context(); | |||
/// | |||
/// Internal API, don't use it | |||
/// | |||
impl::cgi::connection &connection(); | |||
/// | |||
/// Get an interface to HTTP request | |||
/// | |||
http::request &request(); | |||
/// | |||
/// Get an interface to HTTP response | |||
/// | |||
http::response &response(); | |||
/// | |||
/// Get global settings. Same as cppcms::service::settings | |||
/// | |||
json::value const &settings(); | |||
/// | |||
/// Get an interface to CppCMS Cache | |||
/// | |||
cache_interface &cache(); | |||
/// | |||
/// Get an interface to current session | |||
/// | |||
/// Note, when using asynchronous CppCMS applications, session data is not fetched | |||
/// and is not updated, because session access may be not cheap, So when using | |||
/// session_interface in asynchronous application make sure you call session_inerface::load | |||
/// member function | |||
/// | |||
session_interface &session(); | |||
/// | |||
/// Get current context locale | |||
/// | |||
std::locale locale(); | |||
/// | |||
/// Set locale explicitly. Note, it changes the locale of the response().out() stream as | |||
/// well | |||
/// | |||
void locale(std::locale const &new_locale); | |||
/// | |||
/// Set locale by name. Similar to locale(service().generator(name)). | |||
/// | |||
/// Note: it changes the locale of the response().out() stream as well | |||
/// | |||
void locale(std::string const &name); | |||
/// | |||
/// Get the central service instance | |||
/// | |||
cppcms::service &service(); | |||
/// | |||
/// Get current views skin name | |||
/// | |||
std::string skin(); | |||
/// | |||
/// Set current views skin name | |||
/// | |||
void skin(std::string const &name); | |||
/// | |||
/// Internal API, Don't use it | |||
/// | |||
void run(); | |||
typedef enum { | |||
operation_completed, | |||
operation_aborted | |||
} complition_type; | |||
operation_completed, ///< Asynchronous operation completed successfully | |||
operation_aborted ///< Asynchronous operation was canceled | |||
} complition_type; | |||
typedef util::callback1<complition_type> handler; | |||
@@ -12,39 +12,104 @@ namespace cppcms { namespace http { | |||
class cookie; | |||
std::ostream CPPCMS_API &operator<<(std::ostream &,cookie const &); | |||
/// | |||
/// \brief Class that represents single HTTP Cookie | |||
/// Generally used in context of http::request and http::response | |||
/// | |||
class CPPCMS_API cookie { | |||
public: | |||
/// | |||
/// Cookie's Name | |||
/// | |||
std::string name() const; | |||
/// | |||
/// Cookie's value | |||
/// | |||
std::string value() const; | |||
/// | |||
/// Cookie's path | |||
/// | |||
std::string path() const; | |||
/// | |||
/// Cookie's domain | |||
/// | |||
std::string domain() const; | |||
/// | |||
/// Cookie's comment | |||
/// | |||
std::string comment() const; | |||
/// | |||
/// Check if the cookie is transferred over secure connection only | |||
/// | |||
bool secure() const; | |||
/// | |||
/// Set cookie's name | |||
/// | |||
void name(std::string n); | |||
/// | |||
/// Set cookie's value | |||
/// | |||
void value(std::string v); | |||
/// | |||
/// Set cookie's path | |||
/// | |||
void path(std::string p); | |||
/// | |||
/// Set cookie's domain | |||
/// | |||
void domain(std::string); | |||
/// | |||
/// Set cookie's comment | |||
/// | |||
void comment(std::string); | |||
/// | |||
/// Set max cookie's age | |||
/// | |||
void max_age(unsigned a); | |||
/// | |||
/// Set age according to browser's session (i.e. no Max-Age) | |||
/// | |||
void browser_age(); | |||
/// | |||
/// Set secure property on the cookies | |||
/// | |||
void secure(bool v); | |||
// Mandatory set | |||
cookie(); | |||
~cookie(); | |||
cookie(cookie const &); | |||
cookie const &operator=(cookie const &); | |||
// Additional | |||
/// | |||
/// Create cookie with name and value, age - browser, rest properties undefined. | |||
/// | |||
cookie(std::string name,std::string value); | |||
/// | |||
/// Create cookies with name, value and max-age, rest properties undefined. | |||
/// | |||
cookie(std::string name,std::string value,unsigned age); | |||
/// | |||
/// Create cookie with name, value, max-age, path, domain and command | |||
/// | |||
cookie(std::string name,std::string value,unsigned age,std::string path,std::string domain = std::string(),std::string comment=std::string()); | |||
/// | |||
/// Create cookie with name, value, path, domain and comment, age - browser. | |||
cookie(std::string name,std::string value,std::string path,std::string domain=std::string(),std::string comment=std::string()); | |||
private: | |||
friend std::ostream &operator<<(std::ostream &,cookie const &); | |||
void write(std::ostream &) const; | |||
// for future use | |||
struct data; | |||
@@ -0,0 +1,224 @@ | |||
#ifndef CPPCMS_HTTP_PARSER_H | |||
#define CPPCMS_HTTP_PARSER_H | |||
#include "http_protocol.h" | |||
#include <vector> | |||
#include <string> | |||
namespace cppcms { | |||
namespace http { | |||
namespace impl { | |||
class parser { | |||
enum { | |||
idle, | |||
input_observed, | |||
last_lf_exptected, | |||
lf_exptected, | |||
space_or_other_exptected, | |||
quote_expected, | |||
pass_quote_exptected, | |||
closing_bracket_expected, | |||
pass_closing_bracket_expected | |||
} state_; | |||
unsigned bracket_counter_; | |||
std::vector<char> &body_; | |||
unsigned &body_ptr_; | |||
// Non copyable | |||
parser(parser const &); | |||
parser const &operator=(parser const &); | |||
protected: | |||
inline int getc() | |||
{ | |||
if(body_ptr_ < body_.size()) { | |||
return body_[body_ptr_++]; | |||
} | |||
else { | |||
body_.clear(); | |||
body_ptr_=0; | |||
return -1; | |||
} | |||
} | |||
inline void ungetc(int c) | |||
{ | |||
if(body_ptr_ > 0) { | |||
body_ptr_--; | |||
body_[body_ptr_]=c; | |||
} | |||
else { | |||
body_.insert(body_.begin(),c); | |||
} | |||
} | |||
public: | |||
std::string header_; | |||
parser(std::vector<char> &body,unsigned &body_ptr) : | |||
state_(idle), | |||
bracket_counter_(0), | |||
body_(body), | |||
body_ptr_(body_ptr) | |||
{ | |||
} | |||
void reset() | |||
{ | |||
state_ = idle; | |||
bracket_counter_ = 0; | |||
header_.clear(); | |||
} | |||
enum { more_data, got_header, end_of_headers , error_observerd }; | |||
int step() | |||
{ | |||
#ifdef DEBUG_HTTP_PARSER | |||
static char const *states[]= { | |||
"idle", | |||
"input_observed", | |||
"last_lf_exptected", | |||
"lf_exptected", | |||
"space_or_other_exptected", | |||
"quote_expected", | |||
"pass_quote_exptected", | |||
"closing_bracket_expected", | |||
"pass_closing_bracket_expected" | |||
}; | |||
#endif | |||
for(;;) { | |||
int c=getc(); | |||
#if defined DEBUG_HTTP_PARSER | |||
std::cerr<<"Step("<<body_ptr_<<":"<<body_.size()<<": "<<std::flush; | |||
if(c>=32) | |||
std::cerr<<"["<<char(c)<<"] "<<states[state_]<<std::endl; | |||
else | |||
std::cerr<<c<<" "<<states[state_]<<std::endl; | |||
#endif | |||
if(c<0) | |||
return more_data; | |||
switch(state_) { | |||
case idle: | |||
header_.clear(); | |||
switch(c) { | |||
case '\r': | |||
state_=last_lf_exptected; | |||
break; | |||
case '"': | |||
state_=quote_expected; | |||
break; | |||
case '(': | |||
state_=closing_bracket_expected; | |||
bracket_counter_++; | |||
break; | |||
default: | |||
state_=input_observed; | |||
} | |||
break; | |||
case last_lf_exptected: | |||
if(c!='\n') return error_observerd; | |||
header_.clear(); | |||
return end_of_headers; | |||
case lf_exptected: | |||
if(c!='\n') return error_observerd; | |||
state_=space_or_other_exptected; | |||
break; | |||
case space_or_other_exptected: | |||
if(c==' ' || c=='\t') { | |||
// Convert LWS to space as required by | |||
// RFC, so remove last CRLF | |||
header_.resize(header_.size() - 2); | |||
state_=input_observed; | |||
break; | |||
} | |||
ungetc(c); | |||
header_.resize(header_.size()-2); | |||
state_=idle; | |||
#ifdef DEBUG_HTTP_PARSER | |||
std::cerr<<"["<<header_<<"]"<<std::endl; | |||
#endif | |||
return got_header; | |||
case input_observed: | |||
switch(c) { | |||
case '\r': | |||
state_=lf_exptected; | |||
break; | |||
case '"': | |||
state_=quote_expected; | |||
break; | |||
case '(': | |||
state_=closing_bracket_expected; | |||
bracket_counter_++; | |||
break; | |||
default: | |||
state_=input_observed; | |||
} | |||
break; | |||
case quote_expected: | |||
switch(c) { | |||
case '"': | |||
state_=input_observed; | |||
break; | |||
case '\\': | |||
state_=pass_quote_exptected; | |||
break; | |||
} | |||
break; | |||
case pass_quote_exptected: | |||
if(c < 0 || c >=127) | |||
return error_observerd; | |||
state_=quote_expected; | |||
break; | |||
case closing_bracket_expected: | |||
switch(c) { | |||
case ')': | |||
bracket_counter_--; | |||
if(bracket_counter_==0) | |||
state_=input_observed; | |||
break; | |||
case '\\': | |||
state_=pass_closing_bracket_expected; | |||
break; | |||
} | |||
break; | |||
case pass_closing_bracket_expected: | |||
if(c < 0 || c >=127) | |||
return error_observerd; | |||
state_=closing_bracket_expected; | |||
break; | |||
} | |||
header_+=char(c); | |||
/* switch(state_) { | |||
case idle: | |||
case input_observed: | |||
case last_lf_exptected: | |||
case lf_exptected: | |||
case space_or_other_exptected: | |||
if(separator(c)) { | |||
parsed_.push_back(element_type(c,std::string())); | |||
} | |||
else if(0x20 <= c && c<=0x7E) { | |||
if(parsed_.empty() || parsed_.back().first != token_element) { | |||
parsed.push_back(element_type(token_element,std::string())); | |||
} | |||
parsed.back().second+=c; | |||
} | |||
break; | |||
default: | |||
; // Nothing | |||
}*/ | |||
} | |||
} | |||
}; // class parser | |||
}}} // cppcms::http::impl | |||
#endif |
@@ -107,6 +107,8 @@ namespace protocol { | |||
} | |||
if(lsize<rsize) | |||
return -1; | |||
if(lsize>rsize) | |||
return 1; | |||
return 0; | |||
} | |||
@@ -0,0 +1,209 @@ | |||
#define CPPCMS_SOURCE | |||
#include "logger.h" | |||
#include "cppcms_error.h" | |||
#include "config.h" | |||
#ifdef CPPCMS_USE_EXTERNAL_BOOST | |||
# include <boost/format.hpp> | |||
# include <boost/thread.hpp> | |||
# include <boost/shared_ptr.hpp> | |||
#else // Internal Boost | |||
# include <cppcms_boost/format.hpp> | |||
# include <cppcms_boost/thread.hpp> | |||
# include <cppcms_boost/shared_ptr.hpp> | |||
namespace boost = cppcms_boost; | |||
#endif | |||
#include <sstream> | |||
#include <fstream> | |||
namespace cppcms { | |||
namespace impl { | |||
class log_device : public util::noncopyable { | |||
public: | |||
virtual void write(std::string const &msg) = 0; | |||
virtual ~log_device() {} | |||
}; | |||
class file_log_device : public log_device { | |||
public: | |||
file_log_device(std::string const &file_name,logger::open_mode_type how) | |||
{ | |||
switch(how) { | |||
case logger::overwrite: | |||
output_.open(file_name.c_str()); | |||
break; | |||
case logger::append: | |||
default: | |||
output_.open(file_name.c_str(),std::fstream::app); | |||
} | |||
if(!output_) | |||
throw cppcms_error("Failed to open log file:" + file_name); | |||
} | |||
virtual void write(std::string const &msg) | |||
{ | |||
output_ << msg <<std::endl; | |||
} | |||
private: | |||
std::ofstream output_; | |||
}; | |||
class stream_log_device : public log_device { | |||
public: | |||
stream_log_device(std::ostream &out) : output_(out) | |||
{ | |||
} | |||
virtual void write(std::string const &msg) | |||
{ | |||
output_ << msg <<std::endl; | |||
} | |||
private: | |||
std::ostream &output_; | |||
}; | |||
} /// impl | |||
struct logger::data { | |||
boost::shared_mutex lock; | |||
logger::level_type global_level; | |||
bool empty_map; | |||
typedef std::map<std::string,logger::level_type> module_level_type; | |||
module_level_type module_level; | |||
std::auto_ptr<std::fstream> output; | |||
std::vector<boost::shared_ptr<impl::log_device> > devices; | |||
}; | |||
logger::level_type logger::module_level(char const *module) | |||
{ | |||
if(d->empty_map) { | |||
return d->global_level; | |||
} | |||
else { | |||
boost::shared_lock<boost::shared_mutex> guard(d->lock); | |||
data::module_level_type::const_iterator p; | |||
if((p=d->module_level.find(module)) != d->module_level.end()) | |||
return p->second; | |||
return d->global_level; | |||
} | |||
} | |||
void logger::module_level(char const *module,level_type l) | |||
{ | |||
boost::shared_lock<boost::shared_mutex> guard(d->lock); | |||
d->module_level[module] = l; | |||
d->empty_map = false; | |||
} | |||
void logger::reset_module_level(char const *module) | |||
{ | |||
boost::shared_lock<boost::shared_mutex> guard(d->lock); | |||
d->module_level.erase(module); | |||
d->empty_map = d->module_level.empty(); | |||
} | |||
bool logger::level(level_type l,char const *module) | |||
{ | |||
return l <= module_level(module); | |||
} | |||
void logger::default_level(level_type l) | |||
{ | |||
d->global_level = l; | |||
} | |||
logger::level_type logger::default_level() | |||
{ | |||
return d->global_level; | |||
} | |||
logger::ostream_proxy logger::proxy(level_type l,char const *module,char const *file,int line) | |||
{ | |||
ostream_proxy proxy(l,module,file,line,this); | |||
return proxy; | |||
} | |||
logger &logger::instance() | |||
{ | |||
static std::auto_ptr<logger> instance_ptr; | |||
static boost::once_flag flag; | |||
boost::call_once(flag,boost::bind(init,boost::ref(instance_ptr))); | |||
} | |||
void logger::init(std::auto_ptr<logger> &logger_ref) | |||
{ | |||
logger_ref.reset(new logger()); | |||
} | |||
logger::ostream_proxy::ostream_proxy() : | |||
level_(all), | |||
line_(0), | |||
file_(""), | |||
module_(""), | |||
log_(&logger::instance()), | |||
output_(new std::ostringstream) | |||
{ | |||
} | |||
logger::ostream_proxy::ostream_proxy(level_type lv,char const *m,char const *f,int line,logger *log) : | |||
level_(lv), | |||
line_(line), | |||
file_(f), | |||
module_(m), | |||
log_(log), | |||
output_(new std::ostringstream) | |||
{ | |||
} | |||
logger::ostream_proxy::ostream_proxy(logger::ostream_proxy &other) : | |||
level_(other.level_), | |||
line_(other.line_), | |||
file_(other.file_), | |||
module_(other.module_), | |||
log_(other.log_) | |||
{ | |||
output_ = other.output_; | |||
} | |||
logger::ostream_proxy &logger::ostream_proxy::operator=(logger::ostream_proxy &other) | |||
{ | |||
if(&other!=this) { | |||
level_ = other.level_; | |||
line_ = other.line_; | |||
file_ = other.file_; | |||
module_ = other.module_; | |||
log_ = other.log_; | |||
output_ = other.output_; | |||
} | |||
return *this; | |||
} | |||
std::ostream &logger::ostream_proxy::out() | |||
{ | |||
return *output_; | |||
} | |||
logger::ostream_proxy::~ostream_proxy() | |||
{ | |||
try { | |||
log_->write_to_log(level_,module_,file_,line_,output_->str()); | |||
} | |||
catch(...) | |||
{ | |||
} | |||
} | |||
void logger::write_to_log(level_type l,char const *module,char const *file,int line,std::string const &msg) | |||
{ | |||
switch(l) { | |||
case fatal: level = "fatal"; break; | |||
case critical: level = "critical"; break; | |||
case error: level = "error"; break; | |||
case warning: level = "warning"; break; | |||
case message: level = "message"; break; | |||
case info: level = "info"; break; | |||
case debug: level = "debug"; break; | |||
default: | |||
level="unknown"; | |||
} | |||
std::string result = (boost::format("%1%, %2%:%3% %4%:%5%") | |||
<<module << file << line << level << msg).str(); | |||
for(unsigned i=0;i<d->devices.size();i++) | |||
d->devices[i]->write(result); | |||
} | |||
} // cppcms |
@@ -1,27 +1,18 @@ | |||
#ifndef CPPCMS_LOGGER_H | |||
#define CPPCMS_LOGGER_H | |||
#include "defs.h" | |||
#include <iosfwd> | |||
#include <memory> | |||
#include "copy_ptr.h" | |||
#include "hold_ptr.h" | |||
#include "noncopyable.h" | |||
namespace cppcms { | |||
class CPPCMS_API logger { | |||
class CPPCMS_API logger : public util::noncopyable { | |||
public: | |||
class CPPCMS_API ostream_proxy { | |||
public: | |||
ostream_proxy(level_type level,char const *module); | |||
~ostream_proxy() | |||
ostream_proxy(ostream_proxy const &other); | |||
ostream_proxy const &operator=(ostream_proxy const &other); | |||
template<typename T> | |||
ostream_proxy &operator<<(T const &v) const | |||
{ | |||
output() << v; | |||
} | |||
private: | |||
struct data; | |||
intrusive_ptr<data> d; | |||
}; | |||
typedef enum { | |||
none = 0, | |||
fatal = 10, | |||
critical= 20, | |||
error = 30, | |||
@@ -32,14 +23,57 @@ namespace cppcms { | |||
all = 100 | |||
} level_type; | |||
class CPPCMS_API ostream_proxy { | |||
public: | |||
ostream_proxy(); | |||
ostream_proxy(level_type level,char const *module,char const *file,int line,logger *log); | |||
~ostream_proxy(); | |||
ostream_proxy(ostream_proxy &other); | |||
ostream_proxy &operator=(ostream_proxy &other); | |||
std::ostream &out(); | |||
private: | |||
level_type level_; | |||
int line_; | |||
char const *file_; | |||
char const *module_; | |||
logger *log_; | |||
struct data; | |||
util::copy_ptr<data> d; | |||
std::auto_ptr<std::ostringstream> output_; | |||
}; | |||
void write_to_log(level_type l,char const *module,char const *file,int line,std::string const &message); | |||
bool level(level_type l,char const *module); | |||
ostream_proxy proxy(level_type l,char const *module); | |||
ostream_proxy proxy(level_type l,char const *module,char const *file,int line); | |||
void default_level(level_type l); | |||
level_type default_level(); | |||
void module_level(char const *module,level_type l); | |||
level_type module_level(char const *module); | |||
void reset_module_level(char const *module); | |||
typedef enum { | |||
overwrite = 0, | |||
append = 1 | |||
} open_mode_type; | |||
void log_to_file(std::string const &file_name,open_mode_type mode = append); | |||
void log_to_stdout(); | |||
void log_to_stderr(); | |||
static logger &instance(); | |||
private: | |||
static void init(std::auto_ptr<logger> &logger_ref); | |||
struct data; | |||
util::hold_ptr<data> d; | |||
}; | |||
#define CPPCMS_LOG(_l,_m) \ | |||
::cppcms::logger::instance().level(::cppcms::logger::_l,_m) \ | |||
&& ::cppcms::logger::instance().proxy(::cppcms::logger::_l,_m) | |||
#define CPPCMS_LOG(_l,_m) \ | |||
::cppcms::logger::instance().level(::cppcms::logger::_l,_m) \ | |||
&& ::cppcms::logger::instance().proxy(::cppcms::logger::_l,_m,__FILE__,__LINE__).out() | |||
#define CPPCMS_FATAL(_m) CPPCMS_LOG(fatal,_m) | |||
#define CPPCMS_CRITICAL(_m) CPPCMS_LOG(critical,_m) | |||
@@ -49,6 +83,7 @@ namespace cppcms { | |||
#define CPPCMS_INFO(_m) CPPCMS_LOG(info,_m) | |||
#define CPPCMS_DEBUG(_m) CPPCMS_LOG(debug,_m) | |||
} | |||
} // CppCMS | |||
#endif |
@@ -11,6 +11,7 @@ | |||
namespace cppcms { namespace util { | |||
struct regex_result::data { | |||
std::string str; | |||
boost::cmatch match; | |||
}; | |||
regex_result::regex_result() : d(new data) | |||
@@ -37,7 +38,11 @@ namespace cppcms { namespace util { | |||
} | |||
bool regex::match(std::string const &str,regex_result &res) const | |||
{ | |||
return boost::regex_match(str.c_str(),res.d->match,d->r); | |||
// | |||
// Make sure that cmatch is valid, even if original string already is not | |||
// | |||
res.d->str = str; | |||
return boost::regex_match(res.d->str.c_str(),res.d->match,d->r); | |||
} | |||
bool regex::match(std::string const &str) const | |||
{ | |||
@@ -14,10 +14,17 @@ | |||
#include "cppcms_error.h" | |||
#include "cgi_acceptor.h" | |||
#include "cgi_api.h" | |||
#include "scgi_api.h" | |||
#include "http_api.h" | |||
#ifdef CPPCMS_HAS_SCGI | |||
# include "scgi_api.h" | |||
#endif | |||
#ifdef CPPCMS_HAS_HTTP | |||
# include "http_api.h" | |||
#endif | |||
#ifdef CPPCMS_HAS_FCGI | |||
# include "fastcgi_api.h" | |||
#endif | |||
#include "cache_pool.h" | |||
#include "fastcgi_api.h" | |||
#include "internal_file_server.h" | |||
#include "json.h" | |||
#include "localization.h" | |||
@@ -468,16 +475,21 @@ void service::start_acceptor() | |||
tcp=false; | |||
} | |||
impl_->acceptor_.reset(); | |||
if(tcp) { | |||
#ifdef CPPCMS_HAS_SCGI | |||
if(api=="scgi") | |||
impl_->acceptor_ = scgi_api_tcp_socket_factory(*this,ip,port,backlog); | |||
else if(api=="fastcgi") | |||
#endif | |||
#ifdef CPPCMS_HAS_FCGI | |||
if(api=="fastcgi") | |||
impl_->acceptor_ = fastcgi_api_tcp_socket_factory(*this,ip,port,backlog); | |||
else if(api=="http") | |||
#endif | |||
#ifdef CPPCMS_HAS_HTTP | |||
if(api=="http") | |||
impl_->acceptor_ = http_api_factory(*this,ip,port,backlog); | |||
else | |||
throw cppcms_error("Unknown service.api: " + api); | |||
#endif | |||
} | |||
else { | |||
#ifdef CPPCMS_WIN_NATIVE | |||
@@ -485,22 +497,32 @@ void service::start_acceptor() | |||
#elif defined CPPCMS_CYGWIN | |||
throw cppcms_error("CppCMS uses native Win32 sockets under cygwin, so Unix sockets are not supported"); | |||
#else | |||
if(api=="scgi") | |||
#ifdef CPPCMS_HAS_SCGI | |||
if(api=="scgi") { | |||
if(socket=="stdin") | |||
impl_->acceptor_ = scgi_api_unix_socket_factory(*this,backlog); | |||
else | |||
impl_->acceptor_ = scgi_api_unix_socket_factory(*this,socket,backlog); | |||
else if(api=="fastcgi") | |||
} | |||
#endif | |||
#ifdef CPPCMS_HAS_FCGI | |||
if(api=="fastcgi") { | |||
if(socket=="stdin") | |||
impl_->acceptor_ = fastcgi_api_unix_socket_factory(*this,backlog); | |||
else | |||
impl_->acceptor_ = fastcgi_api_unix_socket_factory(*this,socket,backlog); | |||
else if(api=="http") | |||
} | |||
#endif | |||
#ifdef CPPCMS_HAS_HTTP | |||
if(api=="http") | |||
throw cppcms_error("HTTP API is not supported over Unix Domain sockets"); | |||
else | |||
throw cppcms_error("Unknown service.api: " + api); | |||
#endif | |||
#endif | |||
} | |||
if(!impl_->acceptor_.get()) | |||
throw cppcms_error("Unknown service.api: " + api); | |||
} | |||
@@ -0,0 +1,24 @@ | |||
#!/usr/bin/env python | |||
# coding=UTF-8 | |||
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 | |||
def toscgi(text): | |||
def to_headers(): | |||
res = [] | |||
hdr = text[:text.find('\n\n')] | |||
for element in hrd.split('\n'): | |||
[key,value]=element.split(':') | |||
res.append((key.upper().replace('-','_'),value)) | |||
return res | |||
def to_body() | |||
return text[text.find('\n\n')+2:] | |||
def format_headers(headers): | |||
result = '' | |||
for [key,value] in headers: | |||
result+=key+'\0'+value+'\0' | |||
return result | |||
headers=to_headers(text) | |||
body=to_body(text) | |||
headers = [('CONTENT_LENGTH',len(body))] + headers | |||
headers=format_headers(headers) | |||
return str(len(headers))+':' + headers +',' + body |
@@ -7,9 +7,28 @@ | |||
namespace cppcms { | |||
namespace util { | |||
/// | |||
/// Escape string for inclusion in HTML page, i.e. | |||
/// < --- < | |||
/// > --- > | |||
/// & --- & | |||
/// " --- " | |||
/// | |||
/// Note, this function does not deal with encodings, so it's up to you to | |||
/// provide valid text encoding | |||
/// | |||
std::string CPPCMS_API escape(std::string const &s); | |||
/// | |||
/// Encode string for URL (percent encoding) | |||
/// | |||
std::string CPPCMS_API urlencode(std::string const &s); | |||
/// | |||
/// Decode string from URL-encoding (percent-encoding) | |||
/// | |||
std::string CPPCMS_API urldecode(std::string const &s); | |||
/// | |||
/// Decode text in range [begin,end) from URL-encoding (percent-encoding) | |||
/// | |||
std::string CPPCMS_API urldecode(char const *begin,char const *end); | |||
} | |||
} | |||