Browse Source

Replaced callback by more generic function

master
Artyom Beilis 14 years ago
parent
commit
4f9a852878
27 changed files with 78 additions and 2238 deletions
  1. +0
    -6
      CMakeLists.txt
  2. +2
    -2
      aio_timer.h
  3. +0
    -29
      callback.h
  4. +0
    -121
      callback0.h
  5. +0
    -121
      callback1.h
  6. +0
    -121
      callback2.h
  7. +0
    -119
      callback3.h
  8. +0
    -119
      callback4.h
  9. +2
    -2
      cgi_api.cpp
  10. +5
    -6
      cgi_api.h
  11. +22
    -3
      function.h
  12. +0
    -158
      http_connection_scgi.h
  13. +1
    -1
      http_context.cpp
  14. +3
    -5
      http_context.h
  15. +0
    -738
      manager.cpp
  16. +0
    -262
      manager.h
  17. +5
    -5
      mem_bind.h
  18. +2
    -2
      service.cpp
  19. +3
    -3
      service.h
  20. +1
    -1
      service_impl.h
  21. +0
    -46
      signal0.h
  22. +18
    -0
      tests/function_test.cpp
  23. +6
    -5
      thread_pool.cpp
  24. +2
    -2
      thread_pool.h
  25. +6
    -6
      url_dispatcher.h
  26. +0
    -234
      worker_thread.cpp
  27. +0
    -121
      worker_thread.h

+ 0
- 6
CMakeLists.txt View File

@@ -339,12 +339,6 @@ set(CPPCMS_PUBLIC_HEADERS
base_view.h
cache_interface.h
cache_pool.h
callback.h
callback0.h
callback1.h
callback2.h
callback3.h
callback4.h
clone_ptr.h
# connection_forwarder.h
copy_ptr.h


+ 2
- 2
aio_timer.h View File

@@ -21,7 +21,7 @@

#include "defs.h"
#include "noncopyable.h"
#include "callback1.h"
#include "function.h"
#include "hold_ptr.h"

namespace cppcms {
@@ -40,7 +40,7 @@ namespace cppcms {
timer(service &srv);
~timer();

typedef util::callback1<bool> handler;
typedef function<void(bool)> handler;

//
// true if was error or cancelation


+ 0
- 29
callback.h View File

@@ -1,29 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef CALLBACK_H
#define CALLBACK_H

#include "callback0.h"
#include "callback1.h"
#include "callback2.h"
#include "callback3.h"
#include "callback4.h"


#endif

+ 0
- 121
callback0.h View File

@@ -1,121 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCMS_UTIL_CALLBACK0_H
#define CPPCMS_UTIL_CALLBACK0_H
#include "clone_ptr.h"

namespace cppcms { namespace util {

///
/// \brief Function object, similar to C++0x std::function<void()>, or boost::function<void()>
///
/// Callback object, it can be created with any "function like object" -- a class with operator() or C function
/// with appropriate signature.
///

class callback0 {

struct callable {
virtual void call() = 0;
virtual callable *clone() const = 0;
virtual ~callable() {};
};

template<typename T>
struct callable_functor : public callable{
T func;
callable_functor(T f) : func(f) {}
virtual ~callable_functor() { }
virtual void call() { func(); }
virtual callable *clone() const { return new callable_functor<T>(func); }
};

clone_ptr<callable> call_ptr;
public:
typedef void result_type;

///
/// Call the assigned function, does nothing if function was not assigned
///
void operator()() const
{
if(call_ptr.get()) {
call_ptr->call();
}
}
///
/// Create an empty callback
///
callback0(){}


///
/// Copy constructor
///
callback0(callback0 const &other) : call_ptr(other.call_ptr)
{
}

///
/// Assignment operator
///

callback0 const &operator=(callback0 const &other)
{
if(this!=&other)
call_ptr = other.call_ptr;
return *this;
}
///
/// Create a callback and copy callable object T to it.
///
template<typename T>
callback0(T c) : call_ptr(new callable_functor<T>(c))
{
}
///
/// Assign a callable object to it
///
template<typename T>
callback0 const &operator=(T c)
{
call_ptr.reset(new callable_functor<T>(c));
return *this;
}

///
/// Swap two callbacks
///
void swap(callback0 &other)
{
call_ptr.swap(other.call_ptr);
}

};



}} // cppcms util


#endif

+ 0
- 121
callback1.h View File

@@ -1,121 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCMS_UTIL_CALLBACK1_H
#define CPPCMS_UTIL_CALLBACK1_H
#include "clone_ptr.h"

namespace cppcms { namespace util {

///
/// \brief Function object, similar to C++0x std::function<void(P1)>, or boost::function<void(P1)>
///
/// Callback object, it can be created with any "function like object" -- a class with operator()(P1) or C function
/// with appropriate signature.
///

template<typename P1>
class callback1 {

struct callable {
virtual void call(P1) = 0;
virtual callable *clone() const = 0;
virtual ~callable() {};
};

template<typename T>
struct callable_functor : public callable{
T func;
callable_functor(T f) : func(f) {}
virtual ~callable_functor() { }
virtual void call(P1 p1) { func(p1); }
virtual callable *clone() const { return new callable_functor<T>(func); }
};

clone_ptr<callable> call_ptr;
public:
typedef void result_type;
typedef P1 argument_type;

///
/// Call the assigned function, does nothing if function was not assigned
///
void operator()(P1 p1) const
{
if(call_ptr.get()) {
call_ptr->call(p1);
}
}

///
/// Create an empty callback
///
callback1(){}
///
/// Copy constructor
///
callback1(callback1 const &other) : call_ptr(other.call_ptr)
{
}

///
/// Assignment operator
///

callback1 const &operator=(callback1 const &other)
{
if(this!=&other)
call_ptr = other.call_ptr;
return *this;
}

///
/// Create a callback and copy callable object T to it.
///
template<typename T>
callback1(T c) : call_ptr(new callable_functor<T>(c))
{
}
///
/// Assign a callable object to it
///
template<typename T>
callback1 const &operator=(T c)
{
call_ptr.reset(new callable_functor<T>(c));
return *this;
}
///
/// Swap two callbacks
///
void swap(callback1 &other)
{
call_ptr.swap(other.call_ptr);
}

};



}} // cppcms util


#endif

+ 0
- 121
callback2.h View File

@@ -1,121 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCMS_UTIL_CALLBACK2_H
#define CPPCMS_UTIL_CALLBACK2_H
#include "clone_ptr.h"

namespace cppcms { namespace util {

///
/// \brief Function object, similar to C++0x std::function<void(P1,P2)>, or boost::function<void(P1,P2)>
///
/// Callback object, it can be created with any "function like object" -- a class with operator()(P1,P2) or C function
/// with appropriate signature.
///

template<typename P1,typename P2>
class callback2 {

struct callable {
virtual void call(P1,P2) = 0;
virtual callable *clone() const = 0;
virtual ~callable() {};
};

template<typename T>
struct callable_functor : public callable{
T func;
callable_functor(T f) : func(f) {}
virtual ~callable_functor() { }
virtual void call(P1 p1,P2 p2) { func(p1,p2); }
virtual callable *clone() const { return new callable_functor<T>(func); }
};

clone_ptr<callable> call_ptr;
public:
typedef void result_type;
typedef P1 first_argument_type;
typedef P2 second_argument_type;

///
/// Call the assigned function, does nothing if function was not assigned
///
void operator()(P1 p1,P2 p2) const
{
if(call_ptr.get()) {
call_ptr->call(p1,p2);
}
}

///
/// Create an empty callback
///
callback2(){}
///
/// Copy constructor
///
callback2(callback2 const &other) : call_ptr(other.call_ptr)
{
}

///
/// Assignment operator
///

callback2 const &operator=(callback2 const &other)
{
if(this!=&other)
call_ptr = other.call_ptr;
return *this;
}

///
/// Create a callback and copy callable object T to it.
///
template<typename T>
callback2(T c) : call_ptr(new callable_functor<T>(c))
{
}
///
/// Assign a callable object to it
///
template<typename T>
callback2 const &operator=(T c)
{
call_ptr.reset(new callable_functor<T>(c));
return *this;
}
///
/// Swap two callbacks
///
void swap(callback2 &other)
{
call_ptr.swap(other.call_ptr);
}

};



}} // cppcms util


#endif

+ 0
- 119
callback3.h View File

@@ -1,119 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCMS_UTIL_CALLBACK3_H
#define CPPCMS_UTIL_CALLBACK3_H
#include "clone_ptr.h"

namespace cppcms { namespace util {

///
/// \brief Function object, similar to C++0x std::function<void(P1,P2,P3)>, or boost::function<void(P1,P2,P3)>
///
/// Callback object, it can be created with any "function like object" -- a class with operator()(P1,P2,P3) or C function
/// with appropriate signature.
///

template<typename P1,typename P2,typename P3>
class callback3 {

struct callable {
virtual void call(P1,P2,P3) = 0;
virtual callable *clone() const = 0;
virtual ~callable() {};
};

template<typename T>
struct callable_functor : public callable{
T func;
callable_functor(T f) : func(f) {}
virtual ~callable_functor() { }
virtual void call(P1 p1,P2 p2,P3 p3) { func(p1,p2,p3); }
virtual callable *clone() const { return new callable_functor<T>(func); }
};

clone_ptr<callable> call_ptr;
public:
typedef void result_type;

///
/// Call the assigned function, does nothing if function was not assigned
///
void operator()(P1 p1,P2 p2,P3 p3) const
{
if(call_ptr.get()) {
call_ptr->call(p1,p2,p3);
}
}

///
/// Create an empty callback
///
callback3(){}
///
/// Copy constructor
///
callback3(callback3 const &other) : call_ptr(other.call_ptr)
{
}

///
/// Assignment operator
///

callback3 const &operator=(callback3 const &other)
{
if(this!=&other)
call_ptr = other.call_ptr;
return *this;
}

///
/// Create a callback and copy callable object T to it.
///
template<typename T>
callback3(T c) : call_ptr(new callable_functor<T>(c))
{
}
///
/// Assign a callable object to it
///
template<typename T>
callback3 const &operator=(T c)
{
call_ptr.reset(new callable_functor<T>(c));
return *this;
}

///
/// Swap two callbacks
///
void swap(callback3 &other)
{
call_ptr.swap(other.call_ptr);
}
};



}} // cppcms util


#endif

+ 0
- 119
callback4.h View File

@@ -1,119 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCMS_UTIL_CALLBACK4_H
#define CPPCMS_UTIL_CALLBACK4_H
#include "clone_ptr.h"

namespace cppcms { namespace util {

///
/// \brief Function object, similar to C++0x std::function<void(P1,P2,P3,P4)>, or boost::function<void(P1,P2,P3,P4)>
///
/// Callback object, it can be created with any "function like object" -- a class with operator()(P1,P2,P3,P4) or C function
/// with appropriate signature.
///

template<typename P1,typename P2,typename P3,typename P4>
class callback4 {

struct callable {
virtual void call(P1,P2,P3,P4) = 0;
virtual callable *clone() const = 0;
virtual ~callable() {};
};

template<typename T>
struct callable_functor : public callable{
T func;
callable_functor(T f) : func(f) {}
virtual ~callable_functor() { }
virtual void call(P1 p1,P2 p2,P3 p3,P4 p4) { func(p1,p2,p3,p4); }
virtual callable *clone() const { return new callable_functor<T>(func); }
};

clone_ptr<callable> call_ptr;
public:
typedef void result_type;

///
/// Call the assigned function, does nothing if function was not assigned
///
void operator()(P1 p1,P2 p2,P3 p3,P4 p4) const
{
if(call_ptr.get()) {
call_ptr->call(p1,p2,p3,p4);
}
}

///
/// Create an empty callback
///
callback4(){}
///
/// Copy constructor
///
callback4(callback4 const &other) : call_ptr(other.call_ptr)
{
}

///
/// Assignment operator
///

callback4 const &operator=(callback4 const &other)
{
if(this!=&other)
call_ptr = other.call_ptr;
return *this;
}

///
/// Create a callback and copy callable object T to it.
///
template<typename T>
callback4(T c) : call_ptr(new callable_functor<T>(c))
{
}
///
/// Assign a callable object to it
///
template<typename T>
callback4 const &operator=(T c)
{
call_ptr.reset(new callable_functor<T>(c));
return *this;
}

///
/// Swap two callbacks
///
void swap(callback4 &other)
{
call_ptr.swap(other.call_ptr);
}
};



}} // cppcms util


#endif

+ 2
- 2
cgi_api.cpp View File

@@ -258,12 +258,12 @@ intrusive_ptr<connection> connection::self()
}

void connection::async_prepare_request( http::request &request,
boost::function<void(bool)> const &h)
function<void(bool)> const &h)
{
async_read_headers(boost::bind(&connection::load_content,self(),_1,&request,h));
}

void connection::aync_wait_for_close_by_peer(boost::function<void()> const &on_eof)
void connection::aync_wait_for_close_by_peer(function<void()> const &on_eof)
{
async_read_eof(boost::bind(&connection::handle_eof,self(),on_eof));
}


+ 5
- 6
cgi_api.h View File

@@ -24,13 +24,12 @@
#include "intrusive_ptr.h"
#include <vector>
#include <map>
#include "function.h"
#include "config.h"
#ifdef CPPCMS_USE_EXTERNAL_BOOST
# include <boost/function.hpp>
# include <boost/system/error_code.hpp>
namespace boost { namespace asio { class io_service; } }
#else // Internal Boost
# include <cppcms_boost/function.hpp>
# include <cppcms_boost/system/error_code.hpp>
namespace cppcms_boost { namespace asio { class io_service; } }
namespace boost = cppcms_boost;
@@ -50,10 +49,10 @@ namespace cppcms {
namespace impl {
namespace cgi {

typedef boost::function<void(boost::system::error_code const &e)> handler;
typedef boost::function<void(boost::system::error_code const &e,size_t)> io_handler;
typedef boost::function<void()> callback;
typedef boost::function<void(bool)> ehandler;
typedef function<void(boost::system::error_code const &e)> handler;
typedef function<void(boost::system::error_code const &e,size_t)> io_handler;
typedef function<void()> callback;
typedef function<void(bool)> ehandler;

class acceptor : public util::noncopyable {
public:


+ 22
- 3
function.h View File

@@ -1,3 +1,21 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCMS_FUNCTION_H
#define CPPCMS_FUNCTION_H

@@ -23,7 +41,7 @@ namespace cppcms {
public: \
typedef Result result_type; \
struct callable { \
virtual Result call(CPPCMS_TYPE_PARAMS) const=0; \
virtual Result call(CPPCMS_TYPE_PARAMS) =0; \
virtual callable *clone() const = 0; \
virtual ~callable(){} \
}; \
@@ -32,7 +50,7 @@ namespace cppcms {
struct callable_impl : public callable { \
F func; \
callable_impl(F f) : func(f){} \
virtual R call(CPPCMS_TYPE_PARAMS) const \
virtual R call(CPPCMS_TYPE_PARAMS) \
{ return func(CPPCMS_CALL_PARAMS); } \
virtual callable *clone() const \
{ return new callable_impl<R,F>(func); } \
@@ -41,7 +59,7 @@ namespace cppcms {
struct callable_impl<void,F> : public callable { \
F func; \
callable_impl(F f) : func(f){} \
virtual void call(CPPCMS_TYPE_PARAMS) const \
virtual void call(CPPCMS_TYPE_PARAMS) \
{ func(CPPCMS_CALL_PARAMS); } \
virtual callable *clone() const \
{ return new callable_impl<void,F>(func); } \
@@ -62,6 +80,7 @@ namespace cppcms {
return call_ptr->call(CPPCMS_CALL_PARAMS); \
} \
bool empty() const { return call_ptr.get()==0; } \
void swap(function &other) { call_ptr.swap(other.call_ptr); } \
private: \
util::clone_ptr<callable> call_ptr; \
}; \


+ 0
- 158
http_connection_scgi.h View File

@@ -1,158 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCMS_HTP_CONNECTION_SCGI_H
#define CPPCMS_HTP_CONNECTION_SCGI_H
#include "http_connection.h"
#include "asio_config.h"
namespace cppcms { namespace http {

template<typename Socket>
class scgi_connection : public connection {
aio::streambuf buf_;
std::vector<char> data_;
std::map<std::string,std::string> env_;
Socket socket_;

void on_done(error_code const &e,boost::fuction<void(bool>) callback)
{
callback(bool(e));
}
int check_size(aio::buffer &buf)
{
std::istream s(&buf);
size_t n;
s>>n;
if(s.failbit())
return -1;
return n;
}
bool parse_env(std::vector<char> const &s)
{
if(s.back()!=',')
return false;
std::vector<char>::const_iterator b,e,p;
b=s.begin(); e=s.begin()+s.size()-1;
while(b!=e) {
p=std::find(b,e,0);
if(p==e)
return false;
std::string key(b,p);
b=p+1;
p=std::find(b,e,0);
if(p==e)
return false;
std::string val(b,p);
b=p+1;
env_.insert(std::make_pair(key,val));
}
if(env_.find("CONTENT_LENGTH")==env_.end())
return false;
return true;
}
public:
virtual bool keep_alive() { return false; }

virtual size_t read(void *buffer,size_t s)
{
return aio::read(socket_,aio::buffer(buffer,s));
}
virtual size_t write(void const *buffer,size_t s)
{
return aio::write(socket_,aio::buffer(buffer,s));
}
virtual bool prepare()
{
try {
aio::read_until(socket_,buf_,':');
int n=check_size(buf);
if(n<0)
return false;
data_.resize(n+1,0);
if(aio::read(socket_,aio::buffer(data))!=n+1)
return false;
if(!parse_env(data))
return false;

}
catch(std::exception const &e) {
return false;
}
return true;
}
virtual aio::io_service &io_service()
{
return socket_.io_service();
}
virtual void async_read(void *buffer,size_t s,boost::function<void(bool)> c)
{
aio::async_read(socket_,aio::buffer(buffer,s),
boost::bind(&scgi_connection<Socket>::on_done,shared_from_this(),aio::placeholders::error,c));
}
virtual void async_write(void const *buffer,size_t s,boost::function<void(bool)> c)
{
aio::async_write(socket_,aio::buffer(buffer,s),
boost::bind(&scgi_connection<Socket>::on_done,shared_from_this(),aio::placeholders::error,c));
}
virtual void async_prepare(boost::function<void(bool)> c)
{
aio::async_read_until(socket_,buf_,':',
boost::bind(&scgi_connection<Socket>::on_net_read,shared_from_this(),aio::placeholders::error,c));
}
private:
void on_net_read(error_code const &e,boost::function<void(bool)> c)
{
if(e) {
c(false);
return;
}
int n=check_size(buf);
if(n<0) {
c(false) ;
return;
}
data_.resize(n+1,0);
aio::async_read(socket_,aio::buffer(data_),
boost::bind(&scgi_connection<Socket>::on_env_read,aio::placeholders::error,c));
}
void on_env_read(error_code const &e,boost::function<void(bool)>)
{
if(e) {
c(false);
return;
}
if(!parse_env(data)) {
c(false);
return;
}
c(true);
}
public:
virtual std::string getenv(std::string const &key)
{
std::map<std::string,std::string>::iterator p;
p=env_.find(key);
if(p==env_.end())
return std::string();
return p->second;
}

}; // connection_scgi

} }
#endif

+ 1
- 1
http_context.cpp View File

@@ -185,7 +185,7 @@ context::~context()
{
}

void context::async_on_peer_reset(util::callback0 const &h)
void context::async_on_peer_reset(function<void()> const &h)
{
// For some wired can't go without bind on SunCC
conn_->aync_wait_for_close_by_peer(boost::bind(h));


+ 3
- 5
http_context.h View File

@@ -23,9 +23,7 @@
#include "hold_ptr.h"
#include "intrusive_ptr.h"
#include "refcounted.h"
#include "callback0.h"
#include "callback1.h"

#include "function.h"
#include <locale>

namespace cppcms {
@@ -138,7 +136,7 @@ namespace cppcms {
operation_aborted ///< Asynchronous operation was canceled
} complition_type;

typedef util::callback1<complition_type> handler;
typedef function<void(complition_type)> handler;

///
/// Send all pending output data to the client and
@@ -167,7 +165,7 @@ namespace cppcms {
/// 2. If async_flush_output fails, this does not mean that
/// this handler would be called as well, so you need to check both
///
void async_on_peer_reset(util::callback0 const &h);
void async_on_peer_reset(function<void()> const &h);
private:
void on_request_ready(bool error);
static void dispatch(intrusive_ptr<application> app,std::string url,bool syncronous);


+ 0
- 738
manager.cpp View File

@@ -1,738 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "manager.h"
#include "cgicc_connection.h"

#if !defined(CPPCMS_EMBEDDED) || defined(CPPCMS_EMBEDDED_THREAD)

#include <dlfcn.h>
#include <dirent.h>
#include <poll.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <sys/types.h>
#include "config.h"
#ifdef CPPCMS_USE_EXTERNAL_BOOST
# include <boost/shared_ptr.hpp>
#else // Internal Boost
# include <cppcms_boost/shared_ptr.hpp>
namespace boost = cppcms_boost;
#endif
#include "thread_cache.h"

#endif

#include <algorithm>
#include <stdlib.h>
#include "scgi.h"
#include "cgi.h"
#include "session_cookies.h"
#include "session_file_storage.h"
#include "session_cache_backend.h"
#include "session_dual.h"

#ifdef EN_SQLITE_SESSIONS
# include "session_sqlite_storage.h"
#endif

#ifdef EN_FORK_CACHE

# include "process_cache.h"
#endif

#ifdef EN_FCGI_BACKEND
# include "fcgi.h"
#endif

#ifdef EN_TCP_CACHE
# include "tcp_cache.h"
# include "session_tcp_storage.h"
#endif


#if !defined(CPPCMS_EMBEDDED) || defined(CPPCMS_EMBEDDED_THREAD)

namespace {

void set_signal_handler(int sig,void (*handler)(int))
{
struct sigaction sac;
memset(&sac,0,sizeof(sac));
sac.sa_handler=handler;
sigaction(sig,&sac,NULL);
}

}

#endif

namespace cppcms {
namespace details {

class single_run : public web_application{
public:
single_run(manager &m) : web_application(m)
{
};
virtual void execute()
{
base_factory &factory=*app.workers;
auto_ptr<worker_thread> worker(factory(app));
cgi_session *session=app.api->accept_session();
if(session) {
try {
if(session->prepare()) {
worker->run(session->get_connection());
}
}
catch(...) {
delete session;
throw;
}
delete session;
}

}
};

#if !defined(CPPCMS_EMBEDDED) || defined(CPPCMS_EMBEDDED_THREAD)

fast_cgi_application *fast_cgi_application::handlers_owner=NULL;

fast_cgi_application::event_t fast_cgi_application::wait()
{
while(!the_end) {
struct pollfd fds;

fds.fd=app.api->get_socket();
fds.events=POLLIN | POLLERR;
fds.revents=0;

/* Wait for two events:
* 1. New connection and then do accept
* 2. Exit message - exit and do clean up */

if(poll(&fds,1,-1)<0) {
if(errno==EINTR && !the_end)
continue;
return EXIT;
}
else if(fds.revents) {
if(fds.revents & POLLERR)
return EXIT;
return ACCEPT;
}
}
return EXIT;
}

void fast_cgi_application::shutdown()
{
// Rise exit signal on
// the selfpipe
the_end=true;
}

void fast_cgi_application::handler(int id)
{
fast_cgi_application *ptr=fast_cgi_application::get_instance();
if(ptr) {
ptr->shutdown();
}
}

void fast_cgi_application::set_signal_handlers()
{
handlers_owner=this;
/* Signals defined by standard */
set_signal_handler(SIGTERM,handler);
set_signal_handler(SIGUSR1,handler);
/* Additional signal */
set_signal_handler(SIGINT,handler);
}

fast_cgi_single_threaded_app::fast_cgi_single_threaded_app(manager &m) :
fast_cgi_application( m)
{
base_factory &factory=*app.workers;
worker=factory(app);
}

bool fast_cgi_single_threaded_app::run()
{
// Blocking loop
event_t event=wait();

if(event==EXIT) {
return false;
} // ELSE event==ACCEPT

cgi_session *session=app.api->accept_session();
if(session) {
try {
if(session->prepare()) {
worker->run(session->get_connection());
}
}
catch(...) {
delete session;
throw;
}
delete session;
}
return true;
};


void fast_cgi_application::execute()
{
the_end=false;

set_signal_handlers();

while(run()){
/* Do Continue */
}
}

fast_cgi_multiple_threaded_app::fast_cgi_multiple_threaded_app(manager &m):
fast_cgi_application(m)
{
int threads_num=app.config.lval("server.threads",5);
int buffer=app.config.lval("server.buffer",10);

int i;

threads_info=NULL;
pids=NULL;

size=threads_num;

// Init Worker Threads
workers.resize(size,0);

base_factory &factory=*app.workers;
for(i=0;i<size;i++) {
workers[i]=factory(app).release();
}

// Setup Jobs Manager
jobs.init(buffer);

start_threads();
}

void *fast_cgi_multiple_threaded_app::thread_func(void *p)
{
info_t *params=(info_t *)p;

int id=params->first;
fast_cgi_multiple_threaded_app *self=params->second;

cgi_session *session;

while((session=self->jobs.pop())!=NULL) {
try{
if(session->prepare()){
self->workers[id]->run(session->get_connection());
}
}
catch(...){
delete session;
return NULL;
}
delete session;
}
return NULL;
}

void fast_cgi_multiple_threaded_app::start_threads()
{
int i;

pids = new pthread_t [size];
threads_info = new info_t [size];

for(i=0;i<size;i++) {

threads_info[i].first=i;
threads_info[i].second=this;

pthread_create(pids+i,NULL,thread_func,threads_info+i);
}
}

void fast_cgi_multiple_threaded_app::wait_threads()
{
int i;
for(i=0;i<size;i++) {
pthread_join(pids[i],NULL);
}
}

bool fast_cgi_multiple_threaded_app::run()
{
if(wait()==ACCEPT) {
cgi_session *session=app.api->accept_session();
if(session){
jobs.push(session);
}
return true;
}
else {// Exit event
int i;
for(i=0;i<size;i++) {
jobs.push(NULL);
}

wait_threads();

return false;
}
}


#endif // if !defined(CPPCMS_EMBEDDED) || defined(CPPCMS_EMBEDDED_THREAD)

#if !defined(CPPCMS_EMBEDDED)

// Single instance of prefork
prefork *prefork::self;

void prefork::parent_handler(int s_catched)
{
int i;
int s;
if(self->exit_flag==0) {
self->exit_flag=1;
s=SIGTERM;
}
else {
s=SIGKILL;
}

set_signal_handler(SIGALRM,parent_handler);
alarm(3);
for(i=0;i<self->procs;i++) {
kill(self->pids[i],s);
}
}

void prefork::chaild_handler(int s)
{
self->exit_flag=1;
set_signal_handler(SIGALRM,chaild_handler);
alarm(1);
}

void prefork::run()
{
/* Signals defined by standard */
set_signal_handler(SIGTERM,chaild_handler);
set_signal_handler(SIGUSR1,chaild_handler);
/* Additional signal */
set_signal_handler(SIGINT,chaild_handler);

base_factory &factory=*app.workers;
auto_ptr<worker_thread> worker=factory(app);

int limit=app.config.lval("server.iterations_limit",-1);
if(limit!=-1) {
srand(getpid());
limit=limit+(limit / 10 *(rand() % 100))/100;
}
int counter=0;
while(!exit_flag){
if(limit!=-1 && counter>limit)
return;
counter++;
auto_ptr<cgi_session> session;
try{
session.reset(app.api->accept_session());
if(session.get() && session->prepare()) {
worker->run(session->get_connection());
}
}
catch(exception const &e){
cerr<<e.what()<<endl;
}
}
}

prefork::prefork(manager &m) :
web_application(m)
{
procs=app.config.lval("server.procs",5);
exit_flag=0;
pids.resize(procs);
self=this;
}

void prefork::execute()
{
int i;

for(i=0;i<procs;i++) {
pid_t pid=fork();
if(pid<0) {
perror("fork:");
int j;
for(j=0;j<i;j++) {
kill(pids[j],SIGKILL);
wait(NULL);
}
exit(1);
}
if(pid>0) {
pids[i]=pid;
}
else { // pid==0
run();
return;
}
}
/* Signals defined by standard */
set_signal_handler(SIGTERM,parent_handler);
set_signal_handler(SIGUSR1,parent_handler);
/* Additional signal */
set_signal_handler(SIGINT,parent_handler);

while(!prefork::exit_flag) {
int stat;
pid_t pid=wait(&stat);
if(pid<0) {
continue;
}
if(exit_flag) break;
for(i=0;i<procs;i++) {
if(pids[i]==pid) {
if(!WIFEXITED(stat) || WEXITSTATUS(stat)!=0){
if(WIFEXITED(stat)) {
cerr<<"Chaild "<<pid<<" exited with "<<WEXITSTATUS(stat)<<endl;
}
else if(WIFSIGNALED(stat)) {
cerr<<"Chaild "<<pid<<" killed by "<<WTERMSIG(stat)<<endl;
}
else {
cerr<<"Chaild "<<pid<<" exited for unknown reason"<<endl;
}
}
pid=fork();
if(pid==0) {
run();
return;
}
pids[i]=pid;
break;
}
}
}

for(i=0;i<procs;i++) {
while(wait(NULL)<0 && errno==EINTR)
;
}
}

#endif //if !defined(CPPCMS_EMBEDDED)

} // END oF Details

cache_factory *manager::get_cache_factory()
{
#ifdef CPPCMS_EMBEDDED
return new cache_factory();
#else
string backend=config.sval("cache.backend","none");

if(backend=="none") {
return new cache_factory();
}
else if(backend=="threaded") {
int n=config.lval("cache.limit",100);
return new thread_cache_factory(n);
}
#ifdef EN_FORK_CACHE
else if(backend=="fork") {
#ifndef HAVE_PTHREADS_PSHARED
// without pshared mutexes fork cache uses fcnlt for locking
// and becomes not thread safe
if(config.sval("server.mod","")=="thread") {
throw cppcms_error("Can't use fork cache backend with mod_thread");
}
#endif
size_t s=config.lval("cache.memsize",64);
string f=config.sval("cache.file","");
return new process_cache_factory(s*1024U,f=="" ? NULL: f.c_str());
}
#endif
#ifdef EN_TCP_CACHE
else if(backend=="tcp") {
vector<int> const &ports=config.llist("cache.ports");
vector<string> const &ips=config.slist("cache.ips");
return new tcp_cache_factory(ips,ports);
}
#endif
else {
throw cppcms_error("Unkown cache backend:" + backend);
}
#endif // cppcms_embedded
}

cgi_api *manager::get_api()
{
#if defined(CPPCMS_EMBEDDED) && !defined(CPPCMS_EMBEDDED_THREAD)
return new cgi_cgi_api();
#else
string api=config.sval("server.api");

if(api=="cgi") {
return new cgi_cgi_api();
}

string socket=config.sval("server.socket","");
int backlog=config.lval("server.buffer",1);

if(api=="scgi" ) {
return new scgi_api(socket.c_str(),backlog);
}

#ifdef EN_FCGI_BACKEND
if(api=="fastcgi"){
return new fcgi_api(socket.c_str(),backlog);
}
#endif
throw cppcms_error("Unknown api:"+api);
#endif // ! CGI only
}

web_application *manager::get_mod()
{
#if defined(CPPCMS_EMBEDDED) && !defined(CPPCMS_EMBEDDED_THREAD)
return new details::single_run(*this);
#else
if(config.sval("server.api","")=="cgi") {
return new details::single_run(*this);
}

string mod=config.sval("server.mod");
#if !defined(CPPCMS_EMBEDDED) || defined(CPPCMS_EMBEDDED_THREAD)
if(mod=="process") {
return new details::fast_cgi_single_threaded_app(*this);
}
if(mod=="thread") {
return new details::fast_cgi_multiple_threaded_app(*this);
}
#endif
#if !defined(CPPCMS_EMBEDDED)
if(mod=="prefork") {
return new details::prefork(*this);
}
#endif
throw cppcms_error("Unknown mod:" + mod);
#endif
}

namespace {
struct empty_backend {
boost::shared_ptr<session_api> operator()(worker_thread &a)
{
return boost::shared_ptr<session_api>(); // EMPTY
}
};
}

session_backend_factory manager::get_sessions()
{
string lock=config.sval("session.location","none");
if(lock=="none")
return empty_backend();
session_backend_factory clnt;
session_backend_factory srv;
if(lock=="client" || lock=="both") {
clnt=session_cookies::factory();
}
if(lock=="server" || lock=="both") {
string srv_backend=config.sval("session.backend","files");
if(srv_backend=="cache")
srv=session_cache_backend::factory();
else if(srv_backend=="files")
srv=session_file_storage::factory(config);
#ifdef EN_SQLITE_SESSIONS
else if(srv_backend=="sqlite")
srv=session_sqlite_storage::factory(config);
#endif
#ifdef EN_TCP_CACHE
else if(srv_backend=="tcp")
srv=session_tcp_storage::factory(config);
#endif
else
throw cppcms_error("Unknown backend:"+srv_backend);
}

if(lock=="server")
return srv;
if(lock=="client")
return clnt;
if(lock=="both") {
int limit=config.ival("session.client_size_limit",2048);
return session_dual::factory(clnt,srv,limit);
}
throw cppcms_error("Unknown location:"+lock);
}

void manager::execute()
{
if(!workers.get()) {
throw cppcms_error("No workers factory set up");
}
if(!cache.get()) {
set_cache(get_cache_factory());
}
if(sessions.empty()) {
set_sessions(get_sessions());
}
if(!api.get()) {
set_api(get_api());
}
if(!gettext.get()){
set_gettext(get_gettext());
}
if(!web_app.get()) {
set_mod(get_mod());
}

load_templates();

web_app->execute();
}

void manager::load_templates()
{
#if !defined(CPPCMS_EMBEDDED)
string ext=config.sval("templates.ext",
#ifdef __CYGWIN__
".dll"
#else
".so"
#endif
);
// FIXME to something that works with autotools
unsigned len=ext.size();
vector<string> const &dirs=config.slist("templates.dirs");
for(vector<string>::const_iterator dir=dirs.begin();dir!=dirs.end();++dir) {
DIR *d=::opendir(dir->c_str());
if(!d) continue;
for(struct dirent *entry=::readdir(d);entry;entry=::readdir(d)) {
string filename=entry->d_name;
if( filename.size()>len &&
filename.substr(filename.size()-len,len) == ext )
{
void *handler=::dlopen((*dir + "/" + filename).c_str(),RTLD_LAZY);
if(handler) templates_list.push_back(handler);
}
}
::closedir(d);
}
#endif
}

manager::~manager()
{
#if !defined(CPPCMS_EMBEDDED)
for_each(templates_list.begin(),templates_list.end(),::dlclose);
#endif
}

void manager::set_sessions(session_backend_factory s)
{
sessions=s;
}

void manager::set_worker(base_factory *w)
{
workers=auto_ptr<base_factory>(w);
}

void manager::set_cache(cache_factory *c)
{
cache=auto_ptr<cache_factory>(c);
}

void manager::set_api(cgi_api *a)
{
api=auto_ptr<cgi_api>(get_api());
}

void manager::set_mod(web_application *m)
{
web_app=auto_ptr<web_application>(m);
}

transtext::trans_factory *manager::get_gettext()
{
transtext::trans_factory *tmp=NULL;
try{
tmp=new transtext::trans_factory();

tmp->load( config.sval ("locale.dir",""),
config.slist("locale.lang_list"),
config.sval ("locale.lang_default",""),
config.slist ("locale.domain_list"),
config.sval ("locale.domain_default",""));
return tmp;
}
catch(...){
delete tmp;
throw;
}
}

void manager::set_gettext(transtext::trans_factory *s)
{
gettext=auto_ptr<transtext::trans_factory>(s);
}

manager::manager(char const *f)
{
config.load(0,NULL,f);
}

manager::manager(int argc, char **argv,char const *file)
{
config.load(argc,argv,file);
}

manager::manager(int argc, char **argv)
{
config.load(argc,argv);
}


} // END OF CPPCMS

+ 0
- 262
manager.h View File

@@ -1,262 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCMS_MANAGER_H
#define CPPCMS_MANAGER_H

#include <pthread.h>
#include <string>
#include <memory>

#include "worker_thread.h"
#include "global_config.h"
#include "cache_interface.h"
#include "cgi_api.h"
#include "posix_mutex.h"
#include "transtext.h"
#include "session_backend_factory.h"

namespace cppcms {

class manager;


class base_factory {
public:
virtual std::auto_ptr<worker_thread> operator()(manager const &cf) const = 0;
virtual ~base_factory() {};
};

template<typename T>
class simple_factory : public base_factory {
public:
virtual std::auto_ptr<worker_thread> operator()(manager const &cf) const
{ return std::auto_ptr<worker_thread>(new T(cf)); };
};

template<typename T,typename P>
class one_param_factory : public base_factory {
P const &P1;
public:
one_param_factory(P const &p) : P1(p) {};
virtual std::auto_ptr<worker_thread> operator()(manager const &cf) const
{ return std::auto_ptr<worker_thread>(new T(cf,P1)); };
};

template<typename T,typename Pa,typename Pb>
class two_params_factory : public base_factory {
Pa const &P1;
Pb const &P2;
public:
two_params_factory(Pa const &p1,Pb const &p2) : P1(p1), P2(p2) {};
virtual std::auto_ptr<worker_thread> operator()(manager const &cf) const
{ return std::auto_ptr<worker_thread>(new T(cf,P1,P2)); };
};

class web_application {
public:
manager &app;
web_application(manager &m) : app(m) {};
virtual void execute() = 0;
virtual ~web_application() {};
};


namespace details {
#if !defined(CPPCMS_EMBEDDED) || defined(CPPCMS_EMBEDDED_THREAD)
class fast_cgi_application :public web_application {

static fast_cgi_application *handlers_owner;
protected:
// General control

bool the_end;

static void handler(int id);

typedef enum { EXIT , ACCEPT } event_t;
virtual event_t wait();
void set_signal_handlers();
static fast_cgi_application *get_instance() { return handlers_owner; };
public:
fast_cgi_application(manager &m) : web_application(m) {};
virtual ~fast_cgi_application() {};

void shutdown();
virtual bool run() { return false; };
virtual void execute();
};

class fast_cgi_single_threaded_app : public fast_cgi_application , public util::noncopyable {
std::auto_ptr<worker_thread> worker;
void setup();
public:
virtual bool run();
fast_cgi_single_threaded_app(manager &m);
virtual ~fast_cgi_single_threaded_app(){};
};

template <class T>
class sefe_set {
pthread_mutex_t access_mutex;
pthread_cond_t new_data_availible;
pthread_cond_t new_space_availible;
protected:
int max;
int size;
virtual T &get_int() = 0;
virtual void put_int(T &val) = 0;
public:
void init(int size){
pthread_mutex_init(&access_mutex,NULL);
pthread_cond_init(&new_data_availible,NULL);
pthread_cond_init(&new_space_availible,NULL);

max=size;
this->size=0;

};
sefe_set() {};
virtual ~sefe_set() {};
virtual void push(T val) {
mutex_lock lock(access_mutex);
while(size>=max) {
pthread_cond_wait(&new_space_availible,&access_mutex);
}
put_int(val);
pthread_cond_signal(&new_data_availible);
};
T pop() {
mutex_lock lock(access_mutex);
while(size==0) {
pthread_cond_wait(&new_data_availible,&access_mutex);
}

T data=get_int();
pthread_cond_signal(&new_space_availible);
return data;
};
};

template <class T>
class sefe_queue : public sefe_set<T>{
T *queue;
int head;
int tail;
int next(int x) { return (x+1)%this->max; };
protected:
virtual void put_int(T &val) {
queue[head]=val;
head=next(head);
this->size++;
}
virtual T &get_int() {
this->size--;
int ptr=tail;
tail=next(tail);
return queue[ptr];
}
public:
void init(int size) {
if(queue) return;
queue=new T [size];
sefe_set<T>::init(size);
}
sefe_queue() { queue = NULL; head=tail=0; };
virtual ~sefe_queue() { delete [] queue; };
};

class fast_cgi_multiple_threaded_app : public fast_cgi_application {
int size;
vector<worker_thread *> workers;
sefe_queue<cgi_session *> jobs;
typedef pair<int,fast_cgi_multiple_threaded_app*> info_t;

info_t *threads_info;
pthread_t *pids;

static void *thread_func(void *p);
void start_threads();
void wait_threads();
public:
fast_cgi_multiple_threaded_app(manager &m);
virtual bool run();
virtual ~fast_cgi_multiple_threaded_app() {
delete [] pids;
delete [] threads_info;
for(unsigned i=0;i<workers.size();i++)
delete workers[i];
};
};

#endif

#if !defined(CPPCMS_EMBEDDED)

class prefork : public web_application {
vector<pid_t> pids;
int procs;
int exit_flag;
static prefork *self;
static void parent_handler(int s);
static void chaild_handler(int s);
void run();
public:
prefork(manager &m);
virtual void execute();
};

#endif

} // END OF DETAILS

void run_application(int argc,char *argv[],base_factory const &factory);

class manager : private boost::noncopyable {
cache_factory *get_cache_factory();
cgi_api *get_api();
web_application *get_mod();
session_backend_factory get_sessions();
transtext::trans_factory *get_gettext();
list<void *> templates_list;
void load_templates();
public:
cppcms_config config;
auto_ptr<cache_factory> cache;
auto_ptr<cgi_api> api;
auto_ptr<base_factory> workers;
auto_ptr<web_application> web_app;
session_backend_factory sessions;
auto_ptr<transtext::trans_factory> gettext;

void set_worker(base_factory *w);
void set_cache(cache_factory *c);
void set_api(cgi_api *a);
void set_mod(web_application *m);
void set_gettext(transtext::trans_factory *);
void set_sessions(session_backend_factory);

manager(char const *file);
manager(int argc, char **argv);
manager(int argc, char **argv,char const *file);
~manager();
void execute();
};

}
#endif /* CPPCMS_MANAGER_H */

+ 5
- 5
mem_bind.h View File

@@ -26,31 +26,31 @@ namespace cppcms { namespace util {
struct binder0 {
void (C::*member)();
P object;
void operator()() { ((*object).*member)(); }
void operator()() const { ((*object).*member)(); }
};
template<typename C,typename P,typename P1>
struct binder1 {
void (C::*member)(P1);
P object;
void operator()(P1 p1) { ((*object).*member)(p1); }
void operator()(P1 p1) const { ((*object).*member)(p1); }
};
template<typename C,typename P,typename P1,typename P2>
struct binder2 {
void (C::*member)(P1,P2);
P object;
void operator()(P1 p1,P2 p2) { ((*object).*member)(p1,p2); }
void operator()(P1 p1,P2 p2) const { ((*object).*member)(p1,p2); }
};
template<typename C,typename P,typename P1,typename P2,typename P3>
struct binder3 {
void (C::*member)(P1,P2,P3);
P object;
void operator()(P1 p1,P2 p2,P3 p3) { ((*object).*member)(p1,p2,p3); }
void operator()(P1 p1,P2 p2,P3 p3) const { ((*object).*member)(p1,p2,p3); }
};
template<typename C,typename P,typename P1,typename P2,typename P3,typename P4>
struct binder4 {
void (C::*member)(P1,P2,P3,P4);
P object;
void operator()(P1 p1,P2 p2,P3 p3,P4 p4) { ((*object).*member)(p1,p2,p3,p4); }
void operator()(P1 p1,P2 p2,P3 p3,P4 p4) const { ((*object).*member)(p1,p2,p3,p4); }
};
}



+ 2
- 2
service.cpp View File

@@ -304,7 +304,7 @@ void service::shutdown()
#endif
}

void service::after_fork(util::callback0 const &cb)
void service::after_fork(function<void()> const &cb)
{
impl_->on_fork_.push_back(cb);
}
@@ -589,7 +589,7 @@ cppcms::impl::service &service::impl()
return *impl_;
}

void service::post(util::callback0 const &handler)
void service::post(function<void()> const &handler)
{
impl_->get_io_service().post(handler);
}


+ 3
- 3
service.h View File

@@ -22,7 +22,7 @@
#include "defs.h"
#include "noncopyable.h"
#include "hold_ptr.h"
#include "callback0.h"
#include "function.h"
#include <locale>


@@ -66,8 +66,8 @@ namespace cppcms {

cppcms::impl::service &impl();

void post(util::callback0 const &handler);
void after_fork(util::callback0 const &handler);
void post(function<void()> const &handler);
void after_fork(function<void()> const &handler);
int threads_no();
int procs_no();


+ 1
- 1
service_impl.h View File

@@ -59,7 +59,7 @@ namespace impl {
std::auto_ptr<session_pool> session_pool_;
std::locale default_locale_;

std::vector<util::callback0> on_fork_;
std::vector<function<void()> > on_fork_;

int id_;



+ 0
- 46
signal0.h View File

@@ -1,46 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCMS_UTIL_SIGNAL0_H
#define CPPCMS_UTIL_SIGNAL0_H

#include "callback0.h"
#include <list>


namespace cppcms { namespace util {
class signal0 {
typedef std::list<callback0> callbacks_type;
callbacks_type signals_;
public:
void connect(callback0 h)
{
signals_.push_back(callback0());
signals_.back().swap(h);
}
void operator()() const
{
for(callbacks_type::const_iterator p=signals_.begin();p!=signals_.end();++p) {
(*p)();
}
}
};

}} // cppcms::util

#endif

+ 18
- 0
tests/function_test.cpp View File

@@ -1,3 +1,21 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#include "function.h"
#include "test.h"
#include <iostream>


+ 6
- 5
thread_pool.cpp View File

@@ -52,7 +52,7 @@ namespace impl {
}
return false;
}
int post(util::callback0 const &job)
int post(function<void()> const &job)
{
boost::unique_lock<boost::mutex> lock(mutex_);
int id=job_id_++;
@@ -109,7 +109,7 @@ namespace impl {
void worker()
{
for(;;) {
util::callback0 job;
function<void()> job;

{
boost::unique_lock<boost::mutex> lock(mutex_);
@@ -124,7 +124,8 @@ namespace impl {
}
}

job();
if(!job.empty())
job();
}
}

@@ -134,7 +135,7 @@ namespace impl {

bool shut_down_;
int job_id_;
typedef std::list<std::pair<int,util::callback0> > queue_type;
typedef std::list<std::pair<int,function<void()> > > queue_type;
queue_type queue_;
std::vector<boost::shared_ptr<boost::thread> > workers_;

@@ -149,7 +150,7 @@ thread_pool::thread_pool(int n) :
{
}

int thread_pool::post(util::callback0 const &job)
int thread_pool::post(function<void()> const &job)
{
return impl_->post(job);
}


+ 2
- 2
thread_pool.h View File

@@ -21,7 +21,7 @@

#include "defs.h"
#include "noncopyable.h"
#include "callback0.h"
#include "function.h"
#include "hold_ptr.h"

namespace cppcms {
@@ -33,7 +33,7 @@ namespace cppcms {
class CPPCMS_API thread_pool : public util::noncopyable {
public:

int post(util::callback0 const &job);
int post(function<void()> const &job);
bool cancel(int id);
thread_pool(int threads);
void stop();


+ 6
- 6
url_dispatcher.h View File

@@ -21,7 +21,7 @@

#include "noncopyable.h"
#include "defs.h"
#include "callback.h"
#include "function.h"
#include "hold_ptr.h"
#include "mem_bind.h"
#include <string>
@@ -54,11 +54,11 @@ namespace cppcms {
class CPPCMS_API url_dispatcher : public util::noncopyable {
public:
// Handlers
typedef util::callback0 handler;
typedef util::callback1<std::string> handler1;
typedef util::callback2<std::string,std::string> handler2;
typedef util::callback3<std::string,std::string,std::string> handler3;
typedef util::callback4<std::string,std::string,std::string,std::string> handler4;
typedef function<void()> handler;
typedef function<void(std::string)> handler1;
typedef function<void(std::string,std::string)> handler2;
typedef function<void(std::string,std::string,std::string)> handler3;
typedef function<void(std::string,std::string,std::string,std::string)> handler4;

///
/// Assign \a handler to pattern \a regex thus if URL that matches


+ 0
- 234
worker_thread.cpp View File

@@ -1,234 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#define CPPCMS_SOURCE
#include "config.h"
#include "worker_thread.h"
#include "global_config.h"
#include "base_view.h"

#ifndef CPPCMS_EMBEDDED

#ifdef CPPCMS_USE_EXTERNAL_BOOST
# include <boost/iostreams/filtering_stream.hpp>
# include <boost/iostreams/filter/gzip.hpp>
#else // Internal Boost
# include <cppcms_boost/iostreams/filtering_stream.hpp>
# include <cppcms_boost/iostreams/filter/gzip.hpp>
namespace boost = cppcms_boost;
#endif

#endif

#include "manager.h"

using namespace cgicc;
namespace cppcms {

worker_thread::worker_thread(manager const &s) :
app(s),
cache(this),
cout(&(this->out_buf)),
on_start(),
on_end(),
session(*this)
{
caching_module=app.cache->get();
static const transtext::trans tr;
gt=&tr;
} ;

worker_thread::~worker_thread()
{
app.cache->del(caching_module);
}


void worker_thread::main()
{
on_start();
cout<<"<h1>Hello World</h2>\n";
on_end();
}
void worker_thread::set_header(HTTPHeader *h)
{
response_header=auto_ptr<HTTPHeader>(h);
};
void worker_thread::add_header(string s) {
other_headers.push_back(s);
};

void worker_thread::set_cookie(cgicc::HTTPCookie const &c)
{
response_header->setCookie(c);
}

void worker_thread::set_user_io()
{
ostream &cout=cgi_conn->cout();
for(list<string>::iterator h=other_headers.begin();h!=other_headers.end();h++) {
cout<<*h<<"\n";
}
session.save();
cout<<header();
user_io=true;
}

void worker_thread::set_lang(string const &s)
{
lang=s;
gt=&app.gettext->get(s,"");
}

transtext::trans const *worker_thread::domain_gettext(string const &domain)
{
return &app.gettext->get(lang,domain);
}

HTTPHeader &worker_thread::header()
{
return *response_header;
}

void worker_thread::run(cgicc_connection &cgi_conn)
{
cgi=&cgi_conn.cgi();
env=&(cgi->getEnvironment());
ostream &cgi_out=cgi_conn.cout();
other_headers.clear();
cache.reset();
set_lang("");
out_buf.str("");
this->cgi_conn=&cgi_conn;

set_header(new HTTPHTMLHeader);

gzip=gzip_done=false;
user_io=false;

#ifndef CPPCMS_EMBEDDED
string encoding;
if((encoding=cgi_conn.env("HTTP_ACCEPT_ENCODING"))!="") {
if(strstr(encoding.c_str(),"gzip")!=NULL) {
gzip=app.config.lval("gzip.enable",1);
}
}
#endif
if(app.config.lval("server.disable_xpowered_by",0)==0) {
add_header("X-Powered-By: " PACKAGE_NAME "/" PACKAGE_VERSION);
}

try {
/**********/
session.on_start();
main();
session.on_end();
/**********/
if(response_header.get() == NULL) {
throw cppcms_error("Looks like a bug");
}
}
catch(std::exception const &e) {
string msg=e.what();
cgi_out<<HTTPStatusHeader(500,msg);
cgi_out<<"<html><body><p>"+msg+"</p><body></html>";
gzip=gzip_done=false;
other_headers.clear();
out_buf.str("");
return;
}



if(user_io) {
// user controls it's IO
return;
}

for(list<string>::iterator h=other_headers.begin();h!=other_headers.end();h++) {
cgi_out<<*h<<"\n";
}

string out=out_buf.str();
out_buf.str("");
#ifndef CPPCMS_EMBEDDED
if(gzip) {
if(out.size()>0) {
if(gzip_done){
cgi_out<<"Content-Length: "<<out.size()<<"\n";
}
cgi_out<<"Content-Encoding: gzip\n";
cgi_out<<*response_header;
if(gzip_done) {
cgi_out<<out;
}
else{
int level=app.config.ival("gzip.level",-1);
int length=app.config.ival("gzip.buffer",-1);
deflate(out,cgi_out,level,length);
}
}
else {
cgi_out<<*response_header;
}
}
else
#endif
{
cgi_out<<"Content-Length: "<<out.size()<<"\n";
cgi_out<<*response_header;
cgi_out<<out;
}
}


void worker_thread::no_gzip()
{
gzip=false;
}

void worker_thread::render(string tmpl,string name,base_content &content,ostream &out )
{
using cppcms::details::views_storage;
base_view::settings s(this,&out);
auto_ptr<base_view> p(views_storage::instance().fetch_view(tmpl,name,s,&content));
if(!p.get()) throw cppcms_error("Template `"+name+"' not found in template set `" + tmpl +"'");
p->render();
};

void worker_thread::render(string tmpl,string name,base_content &content)
{
render(tmpl,name,content,cout);
};

void worker_thread::render(string name,base_content &content,ostream &o)
{
render(current_template,name,content,o);
};

void worker_thread::render(string name,base_content &content)
{
render(current_template,name,content,cout);
};



}




+ 0
- 121
worker_thread.h View File

@@ -1,121 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef _WORKER_THREAD_H_
#define _WORKER_THREAD_H_

#include <pthread.h>
#include <sstream>
#include <string>

#include <cgicc/Cgicc.h>
#include <cgicc/HTTPHTMLHeader.h>
#include <cgicc/HTTPStatusHeader.h>
#include <cgicc/HTMLClasses.h>
#include "noncopyable.h"
#include <memory>
#include "signal0.h"

#include "cppcms_error.h"
#include "url_dispatcher.h"
#include "cache_interface.h"
#include "base_cache.h"
#include "cgicc_connection.h"
#include "transtext.h"
#include "session_interface.h"

namespace cppcms {

class manager;
class base_content;

using namespace std;
using cgicc::CgiEnvironment;
using cgicc::Cgicc;
using cgicc::HTTPHeader;

class worker_thread: private util::noncopyable {
int id;
pthread_t pid;

friend class cache_iface;
friend class base_view;

list<string> other_headers;
base_cache *caching_module;
bool user_io;
bool gzip;
bool gzip_done;
stringbuf out_buf;

transtext::trans const *gt;
string lang;

auto_ptr<HTTPHeader> response_header;
string current_template;

public:

url_dispatcher url;
manager const &app;
Cgicc *cgi;
CgiEnvironment const *env;
cgicc_connection *cgi_conn;

cache_iface cache;
ostream cout;
util::signal0 on_start;
util::signal0 on_end;
session_interface session;

void set_header(HTTPHeader *h);
void add_header(string s);
void set_cookie(cgicc::HTTPCookie const &c);
void set_user_io();
void no_gzip();

HTTPHeader &header();

void set_lang();
void set_lang(string const &s);

inline void use_template(string s="") { current_template=s; };

void render(string name,base_content &content);
void render(string templ,string name,base_content &content);
void render(string name,base_content &content,ostream &);
void render(string templ,string name,base_content &content,ostream &);

virtual void main();

inline char const *gettext(char const *s) { return gt->gettext(s); };
inline char const *ngettext(char const *s,char const *p,int n) { return gt->ngettext(s,p,n); };

ostream &get_cout() { return cout; }

transtext::trans const *domain_gettext(string const &domain);

void run(cgicc_connection &);

worker_thread(manager const &s);
virtual ~worker_thread();
};

}

#endif

Loading…
Cancel
Save