From bb9bc9051629c3319c56785c2f4ae0e605d76329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Sat, 21 Nov 2015 14:51:17 +0100 Subject: Initial import of bitz-server version 0.1.6-1 --- modules/Makefile.am | 3 + modules/echo/Makefile.am | 9 ++ modules/echo/echo.cpp | 55 ++++++++ modules/echo/echo.h | 54 ++++++++ modules/modpy/Makefile.am | 18 +++ modules/modpy/interface.cpp | 160 +++++++++++++++++++++++ modules/modpy/interface.h | 39 ++++++ modules/modpy/modules/Makefile.am | 11 ++ modules/modpy/modules/modpy.py | 42 ++++++ modules/modpy/py.cpp | 265 ++++++++++++++++++++++++++++++++++++++ modules/modpy/py.h | 70 ++++++++++ 11 files changed, 726 insertions(+) create mode 100644 modules/Makefile.am create mode 100644 modules/echo/Makefile.am create mode 100644 modules/echo/echo.cpp create mode 100644 modules/echo/echo.h create mode 100644 modules/modpy/Makefile.am create mode 100644 modules/modpy/interface.cpp create mode 100644 modules/modpy/interface.h create mode 100644 modules/modpy/modules/Makefile.am create mode 100644 modules/modpy/modules/modpy.py create mode 100644 modules/modpy/py.cpp create mode 100644 modules/modpy/py.h (limited to 'modules') diff --git a/modules/Makefile.am b/modules/Makefile.am new file mode 100644 index 0000000..c52d720 --- /dev/null +++ b/modules/Makefile.am @@ -0,0 +1,3 @@ +## modules/ +SUBDIRS = echo modpy + diff --git a/modules/echo/Makefile.am b/modules/echo/Makefile.am new file mode 100644 index 0000000..3236ad7 --- /dev/null +++ b/modules/echo/Makefile.am @@ -0,0 +1,9 @@ +# modules/echo +AM_CPPFLAGS = -I$(top_srcdir)/lib -I$(top_srcdir)/src + +modlibdir = $(pkglibdir)/modules +modlib_LTLIBRARIES = mod_echo.la +mod_echo_la_LDFLAGS = -module -avoid-version +mod_echo_la_SOURCES = \ + echo.h echo.cpp + diff --git a/modules/echo/echo.cpp b/modules/echo/echo.cpp new file mode 100644 index 0000000..a8496c5 --- /dev/null +++ b/modules/echo/echo.cpp @@ -0,0 +1,55 @@ +/* + * bitz-server, An ICAP server implementation in C++ + * Copyright (C) 2012 Uditha Atukorala + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "echo.h" + + +namespace bitz { + + Echo::Echo() : Modifier() { } + Echo::~Echo() { } + + + icap::Response * Echo::modify( icap::Request * request ) throw() { + + icap::Response * response; + icap::payload_t payload; + + // copy payload from request + payload.req_header = request->payload().req_header; + payload.req_body = request->payload().req_body; + payload.res_header = request->payload().res_header; + payload.res_body = request->payload().res_body; + + + response = new icap::Response( icap::ResponseHeader::OK ); + response->payload( payload ); + + return response; + + } + + + icap::Response * Echo::preview( icap::Request * request ) throw() { + // 100 - continue always + return new icap::Response( icap::ResponseHeader::CONTINUE ); + } + +} /* end of namespace bitz */ + diff --git a/modules/echo/echo.h b/modules/echo/echo.h new file mode 100644 index 0000000..87df312 --- /dev/null +++ b/modules/echo/echo.h @@ -0,0 +1,54 @@ +/* + * bitz-server, An ICAP server implementation in C++ + * Copyright (C) 2012 Uditha Atukorala + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef BITZ_ECHO_H +#define BITZ_ECHO_H + +#include + + +namespace bitz { + + class Echo : public Modifier { + public: + Echo(); + virtual ~Echo(); + + icap::Response * modify( icap::Request * request ) throw(); + icap::Response * preview( icap::Request * request ) throw(); + + private: + + }; + +} /* end of namespace bitz */ + + +/* class factories */ + +extern "C" bitz::Modifier * create() { + return new bitz::Echo; +} + +extern "C" void destroy( bitz::Modifier * m ) { + delete m; +} + +#endif /* !BITZ_ECHO_H */ + diff --git a/modules/modpy/Makefile.am b/modules/modpy/Makefile.am new file mode 100644 index 0000000..eccb2a2 --- /dev/null +++ b/modules/modpy/Makefile.am @@ -0,0 +1,18 @@ +# modules/modpy + +SUBDIRS = modules + +if MODPY +modlibdir = $(pkglibdir)/modules +modlib_LTLIBRARIES = mod_py.la +mod_py_la_LDFLAGS = -module -avoid-version +mod_py_la_SOURCES = \ + py.h py.cpp \ + interface.h interface.cpp + +AM_CPPFLAGS = -I$(top_srcdir)/lib -I$(top_srcdir)/src \ + ${PYTHON_INCLUDES} ${libconfig_CFLAGS} ${log4cpp_CFLAGS} + +mod_py_la_LIBADD = ${PYTHON_LIBS} +endif + diff --git a/modules/modpy/interface.cpp b/modules/modpy/interface.cpp new file mode 100644 index 0000000..948fa5c --- /dev/null +++ b/modules/modpy/interface.cpp @@ -0,0 +1,160 @@ +/* + * bitz-server, An ICAP server implementation in C++ + * Copyright (C) 2012 Uditha Atukorala + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "interface.h" + +#include +#include +#include +#include + + +PyObject * bitz_get_request( PyObject * self, PyObject * pyrequest ) { + + PyObject * pyreturn; + PyObject * pypayload; + icap::Request * request; + + // logger + bitz::Logger &logger = bitz::Logger::instance(); + logger.debug( "[modpy.interface] get_request()" ); + + // initialise return dictionary + pyreturn = PyDict_New(); + + // grab the request object pointer from args + void * p = PyCapsule_GetPointer( pyrequest, "request" ); + + // sanity check + if ( p != NULL ) { + + // construct the request + request = static_cast(p); + + PyDict_SetItemString( pyreturn, "request", PyString_FromString( request->header()->method().c_str() ) ); + PyDict_SetItemString( pyreturn, "uri", PyString_FromString( request->header()->uri().c_str() ) ); + PyDict_SetItemString( pyreturn, "protocol", PyString_FromString( request->header()->protocol().c_str() ) ); + + // payload dictionary + pypayload = PyDict_New(); + PyDict_SetItemString( pypayload, "req_header", PyString_FromStringAndSize( request->payload().req_header.c_str(), request->payload().req_header.size() ) ); + PyDict_SetItemString( pypayload, "req_body", PyString_FromStringAndSize( request->payload().req_body.c_str(), request->payload().req_body.size() ) ); + PyDict_SetItemString( pypayload, "res_header", PyString_FromStringAndSize( request->payload().res_header.c_str(), request->payload().res_header.size() ) ); + PyDict_SetItemString( pypayload, "res_body", PyString_FromStringAndSize( request->payload().res_body.c_str(), request->payload().res_body.size() ) ); + PyDict_SetItemString( pypayload, "ieof", PyBool_FromLong( request->payload().ieof ) ); + + PyDict_SetItemString( pyreturn, "payload", pypayload ); + + // cleanup + Py_DECREF( pypayload ); + + } else { + logger.warn( "[modpy.interface] failed to get request object pointer" ); + } + + return pyreturn; + +} + + +PyObject * bitz_get_response_from_status( PyObject * self, PyObject * args ) { + + PyObject * pyresponse; + icap::Response * response; + + unsigned int resp_status; + + // logger + bitz::Logger &logger = bitz::Logger::instance(); + logger.debug( "[modpy.interface] get_response_from_status()" ); + + // parse args + if ( PyArg_ParseTuple( args, "I", &resp_status ) ) { + response = new icap::Response( (icap::ResponseHeader::status_t) resp_status ); + } else { + logger.warn( "[modpy.interface] failed to parse arguments" ); + response = new icap::Response( icap::ResponseHeader::SERVER_ERROR ); + } + + // convert the response into a capsule + pyresponse = PyCapsule_New( (void *) response, "response", NULL ); + + return pyresponse; + +} + + +PyObject * bitz_get_response( PyObject * self, PyObject * args ) { + + PyObject * pyresponse; + PyObject * pypayload; + icap::Response * response = NULL; + + unsigned int resp_status; + icap::payload_t payload; + + // vars to ferry across strings from python dictionary to c++ + char * pybuffer; + Py_ssize_t pybuflen; + + + // logger + bitz::Logger &logger = bitz::Logger::instance(); + logger.debug( "[modpy.interface] get_response()" ); + + // parse args + if ( PyArg_ParseTuple( args, "IO!", &resp_status, &PyDict_Type, &pypayload ) ) { + + // copy strings from python dictionary + PyString_AsStringAndSize( PyDict_GetItemString( pypayload, "req_header" ), &pybuffer, &pybuflen ); + payload.req_header.assign( pybuffer, pybuflen ); + + PyString_AsStringAndSize( PyDict_GetItemString( pypayload, "req_body" ), &pybuffer, &pybuflen ); + payload.req_body.assign( pybuffer, pybuflen ); + + PyString_AsStringAndSize( PyDict_GetItemString( pypayload, "res_header" ), &pybuffer, &pybuflen ); + payload.res_header.assign( pybuffer, pybuflen ); + + PyString_AsStringAndSize( PyDict_GetItemString( pypayload, "res_body" ), &pybuffer, &pybuflen ); + payload.res_body.assign( pybuffer, pybuflen ); + + // copy other data types from python dictionary + payload.ieof = PyBool_Check( PyDict_GetItemString( pypayload, "ieof" ) ); + + // construct the response object + response = new icap::Response( (icap::ResponseHeader::status_t) resp_status ); + response->payload( payload ); + + } else { + logger.warn( "[modpy.interface] failed to parse arguments" ); + } + + // sanity check + if ( response == NULL ) { + response = new icap::Response( icap::ResponseHeader::SERVER_ERROR ); + } + + // convert the response into a capsule + pyresponse = PyCapsule_New( (void *) response, "response", NULL ); + + return pyresponse; + +} + + diff --git a/modules/modpy/interface.h b/modules/modpy/interface.h new file mode 100644 index 0000000..315a2f6 --- /dev/null +++ b/modules/modpy/interface.h @@ -0,0 +1,39 @@ +/* + * bitz-server, An ICAP server implementation in C++ + * Copyright (C) 2012 Uditha Atukorala + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef BITZ_MODPY_INTERFACE_H +#define BITZ_MODPY_INTERFACE_H + +#include +#include + + +PyObject * bitz_get_request( PyObject * self, PyObject * pyrequest ); +PyObject * bitz_get_response( PyObject * self, PyObject * args ); +PyObject * bitz_get_response_from_status( PyObject * self, PyObject * args); + +static PyMethodDef bitz_methods[] = { + { "get_request", bitz_get_request, METH_O, "Convert a capsule request into a python dictionary" }, + { "get_response", bitz_get_response, METH_VARARGS, "Get a response capsule (takes in status and payload dictionary as args)" }, + { "get_response_from_status", bitz_get_response_from_status, METH_VARARGS, "Get a response capsule from a response status" }, + { NULL, NULL, 0, NULL } +}; + +#endif /* !BITZ_MODPY_INTERFACE_H */ + diff --git a/modules/modpy/modules/Makefile.am b/modules/modpy/modules/Makefile.am new file mode 100644 index 0000000..9292d1d --- /dev/null +++ b/modules/modpy/modules/Makefile.am @@ -0,0 +1,11 @@ +# modules/modpy/modules + +# extra dist files +EXTRA_DIST = \ + modpy.py + +if MODPY +modpydir = $(pkglibdir)/modules/modpy +modpy_DATA = modpy.py +endif + diff --git a/modules/modpy/modules/modpy.py b/modules/modpy/modules/modpy.py new file mode 100644 index 0000000..9a5e578 --- /dev/null +++ b/modules/modpy/modules/modpy.py @@ -0,0 +1,42 @@ +# +# modpy.py +# Copyright (c) 2013 Uditha Atukorala +# + +import bitz + +def init(): + print "init() called"; + +def cleanup(): + print "cleanup() called"; + +def preview( request ): + request = bitz.get_request( request ); + req_payload = request['payload']; + print "preview payload: \r\n", req_payload; + + # response + if req_payload['ieof']: + response = bitz.get_response_from_status( 204 ); + else: + response = bitz.get_response_from_status( 100 ); + + return response; + +def modify( request ): + request = bitz.get_request( request ); + req_payload = request['payload']; + print "modify payload: \r\n", req_payload; + + # response + resp_payload = {}; + resp_payload['req_header'] = req_payload['req_header']; + resp_payload['req_body'] = req_payload['req_body']; + resp_payload['res_header'] = req_payload['res_header']; + resp_payload['res_body'] = req_payload['res_body']; + resp_payload['ieof'] = True; + + response = bitz.get_response( 200, resp_payload ); + return response; + diff --git a/modules/modpy/py.cpp b/modules/modpy/py.cpp new file mode 100644 index 0000000..51cb38f --- /dev/null +++ b/modules/modpy/py.cpp @@ -0,0 +1,265 @@ +/* + * bitz-server, An ICAP server implementation in C++ + * Copyright (C) 2012 Uditha Atukorala + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "py.h" +#include "interface.h" + +#include +#include + + +namespace bitz { + + Py::Py() : Modifier() { + + // defaults + _pymodule = NULL; + + // initialise Py::config_t values + _config.module_name = "modpy"; + _config.module_path = ""; + + // load configs + load_configs(); + + // initialise python + init_python(); + + } + + + Py::~Py() { + + // cleanup python + cleanup_python(); + + } + + + icap::Response * Py::modify( icap::Request * request ) throw() { + + // get the modify response + return python_response( request, "modify" ); + + } + + + icap::Response * Py::preview( icap::Request * request ) throw() { + + // get the preview response + return python_response( request, "preview" ); + + } + + + void Py::load_configs() throw() { + + std::string s; + Config &server_config = Config::instance(); + + // interface module name + s = server_config.module_config( "modpy", "module_name" ); + if ( s != "" ) { + _config.module_name = s; + } + + // module lookup path + _config.module_path = server_config.module_config( "modpy", "module_path" ); + + } + + + void Py::init_python() throw() { + + PyObject * sys_path; + PyObject * pymodule_path, * pymodule_name; + PyObject * pymethod; + PyObject * pyreturn; + + // logger + Logger &logger = Logger::instance(); + + // python core + Py_Initialize(); + + // bitz python module + if ( Py_InitModule( "bitz", bitz_methods ) == NULL ) { + logger.warn( "[modpy] failed to init C interface module: bitz" ); + } + + // setup python environment + if ( _config.module_path != "" ) { + + logger.debug( std::string( "[modpy] appending to sys.path, module_path: " ).append( _config.module_path ) ); + + sys_path = PySys_GetObject( (char *) "path" ); + pymodule_path = PyString_FromString( _config.module_path.c_str() ); + PyList_Append( sys_path, pymodule_path ); + + } + + // load the interface module + logger.debug( std::string( "[modpy] interface module: " ).append( _config.module_name ) ); + + pymodule_name = PyString_FromString( _config.module_name.c_str() ); + _pymodule = PyImport_Import( pymodule_name ); + + if ( _pymodule != NULL ) { + + logger.debug( "[modpy] interface module loaded successfully" ); + + // call init() in the interface module + pymethod = PyObject_GetAttrString( _pymodule, "init" ); + + if ( pymethod && PyCallable_Check( pymethod ) ) { + pyreturn = PyObject_CallObject( pymethod, NULL ); + Py_DECREF( pyreturn ); + } else { + logger.warn ( "[modpy] failed to call init() in interface module" ); + } + + Py_DECREF( pymethod ); + + } else { + logger.warn( "[modpy] failed to load interface module" ); + } + + + // cleanup + Py_DECREF( pymodule_name ); + Py_DECREF( pymodule_path ); + Py_DECREF( sys_path ); + + } + + + void Py::cleanup_python() throw() { + + PyObject * pymethod; + PyObject * pyreturn; + + // logger + Logger &logger = Logger::instance(); + + + // cleanup + if ( _pymodule != NULL ) { + + // call cleanup() in the interface module + pymethod = PyObject_GetAttrString( _pymodule, "cleanup" ); + + if ( pymethod && PyCallable_Check( pymethod ) ) { + pyreturn = PyObject_CallObject( pymethod, NULL ); + Py_DECREF( pyreturn ); + } else { + logger.warn ( "[modpy] failed to call cleanup() in interface module" ); + } + + Py_DECREF( pymethod ); + Py_DECREF( _pymodule ); + + } + + // finalise python core + Py_Finalize(); + + } + + + icap::Response * Py::python_response( icap::Request * request, const std::string &method ) throw() { + + /* + * notes: + * + pass icap::Request to python module as a PyCapsule object + * so it can be used to grab the data needed using the C/C++ interface. + * + process data (within the python module) and use the C/C++ interface + * to create a icap::Response and pass it back to this method + * using a PyCapsule object + */ + + icap::Response * response; + + PyObject * pymethod; + PyObject * pyargs; + PyObject * pyrequest, * pyresponse; + + // logger + Logger &logger = Logger::instance(); + + // initialise the response object + response = NULL; + + // check for the interface module + if ( _pymodule != NULL ) { + + /* call the [method]() in the interface module */ + pymethod = PyObject_GetAttrString( _pymodule, method.c_str() ); + pyargs = PyTuple_New( 1 ); + pyrequest = PyCapsule_New( (void *) request, "request", NULL ); + PyTuple_SetItem( pyargs, 0, pyrequest ); + + if ( pymethod && PyCallable_Check( pymethod ) ) { + + // get the response capsule + pyresponse = PyObject_CallObject( pymethod, pyargs ); + + // sanity check + if ( pyresponse != NULL ) { + + void * p = PyCapsule_GetPointer( pyresponse, "response" ); + + // sanity check + if ( p != NULL ) { + + // construct the response + response = static_cast(p); + + } else { + logger.warn( std::string( "[modpy] invalid capsule response, method: " ).append( method ) ); + } + + Py_DECREF( pyresponse ); + + } else { + logger.warn( std::string( "[modpy] response is NULL, method: " ).append( method ) ); + } + + + } else { + logger.warn ( std::string( "[modpy] failed to call the method in interface module, method: " ).append( method ) ); + } + + // cleanup + // pyrequest is created from the reference passed in + Py_DECREF( pyargs ); + Py_DECREF( pymethod ); + + } + + // sanity check + if ( response == NULL ) { + response = new icap::Response( icap::ResponseHeader::SERVER_ERROR ); + } + + return response; + + } + +} /* end of namespace bitz */ + diff --git a/modules/modpy/py.h b/modules/modpy/py.h new file mode 100644 index 0000000..358c36f --- /dev/null +++ b/modules/modpy/py.h @@ -0,0 +1,70 @@ +/* + * bitz-server, An ICAP server implementation in C++ + * Copyright (C) 2012 Uditha Atukorala + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef BITZ_PY_H +#define BITZ_PY_H + +#include + +#include + + +namespace bitz { + + class Py : public Modifier { + public: + + struct config_t { + std::string module_path; + std::string module_name; + }; + + Py(); + virtual ~Py(); + + icap::Response * modify( icap::Request * request ) throw(); + icap::Response * preview( icap::Request * request ) throw(); + + private: + config_t _config; + PyObject * _pymodule; + + void load_configs() throw(); + void init_python() throw(); + void cleanup_python() throw(); + + icap::Response * python_response( icap::Request * request, const std::string &method ) throw(); + + }; + +} /* end of namespace bitz */ + + +/* class factories */ + +extern "C" bitz::Modifier * create() { + return new bitz::Py; +} + +extern "C" void destroy( bitz::Modifier * m ) { + delete m; +} + +#endif /* !BITZ_PY_H */ + -- cgit v1.2.3