Project

General

Profile

CppHelperClasses » plugin.hpp

The core plugin types - hazzadous, 2009-04-08 00:42

 
/**
* Base class for deriving C++ plugins from. Possibly useful if you
* like this sort of thing. Otherwise just make use you extern the
* appropriate functions (i.e. the plugin init function) to have C symbols.
*/
#ifndef _LIGHTTPD_PLUGIN_HPP_
#define _LIGHTTPD_PLUGIN_HPP_

#include <cstddef>

#include "c++-compat/plugin.h"

#include "handler_helpers.hpp"
#include "datatype_helpers.hpp"

/**
* Abstract base class for C++ lighty plugins. Not sure if its worth it
* yet, lets see how useful it is. Really there shouldn't be any
* significant performance hit with these wrappers, only a small increase
* in memory usage per plugin (irrelivant). Other hit due to function
* calling convensions for which I do not know the details.
*
* Things that need encapsulating:
*
* Plugin house keeping:
* - set which part of the request flow we handle. i.e. _plugin_init
* - populate plugin config. i.e. set_defaults
* - clean up allocated memory we used. i.e. cleanup
*
* The request flow:
* - HTTP request recieved, i.e. protocol, method, uri_raw,
* headers (see http_req.h)
* - "Clean" uri_raw -> uri_clean i.e. mod_rewrite
* - Map the clean request to an appropriate docroot.
* - Get the physical path to the requested file.
* - Do untold horrors to the requested file.
* - More things here.
* - Send a response back maybe.
*
* Lighty allows plugins to hook in to multiple points of this flow,
* i.e. one type of plugin, but their effects at certain levels may be NULL.
* Serves as an easy method of sharing data between points of flow. Perhaps
* theres something in trying to abstract this shared data out, and removing
* this hardcoded sharing within a plugin. Don't know, just a gut feeling.
*
*/

/**
* Absolute base for plugins.
*/
class plugin_base
{
protected:
// We always have a reference to the C plugin structure
// lighty handles the freeing of p
plugin_base( const char* name, const std::size_t version, plugin& p )
: p( p ), srv( 0 ) // don't know srv yet, need initialize
{
p.name = buffer_init_string( name );
p.version = version;
p.data = reinterpret_cast< void* >( this );

// We don't have enough infomation to call init.
// Instead, call it from set_defaults_wrapper

// p.init = &plugin_base::initialize_wrapper;
p.set_defaults = &plugin_base::set_defaults_wrapper;
}

plugin& p;
const server* srv;

public:

// Here we have functions that are required by (almost) all plugins

// For set defaults, we just call set defaults on all config_options
// in the current translation unit.
handler_t set_defaults( )
{
return config_option_base::set_all_defaults( );
}

static handler_t set_defaults_wrapper( server* s, void* p_d )
{
plugin_base& p = reinterpret_cast< plugin_base& >( p_d );
initialize_wrapper( s, p_d );
return p.set_defaults( );
}

// Set srv and return this. There are quite a few inconsistencies here I know,
// this should really be called directly and return a newly allocated plugin.
// Its a tug of war between C and C++ ways. I choose to init the plugin in
// create_plugin and set p->data in the plugin_base constructor.
void* initialize( const server& s )
{
srv = &s;
return reinterpret_cast< void* >( this );
}

static void* initialize_wrapper( server* s, void* p_d )
{
plugin_base& p = reinterpret_cast< plugin_base& >( p_d );
return p.initialize( *s );
}
};

/**
* Abstract plugin base-class for plugins, non-constructable, hidden from C
* compilers. An alternative would be to have a plugin type derived from
* this for each handler type.
*/
template< typename MostDerived >
class Plugin : public plugin_base
{
typedef plugin_base super_type;

protected:
// Private constructor for setting plugin name.
// Could say this is a part of the traditional lighty init function
Plugin( const char* name, const std::size_t version, plugin& p )
: plugin_base( name, version, p )
{
// The handler setter to use to configure hooks in plugin p below.
typedef typename handlers_setter< MostDerived >::type setter;

// use for_each to set the appropriate function pointers
// in the plugin structure, dependend on the type "handlers"
// defined in a derived class.
setter::set( p );
}

public:
// This is to be called after entry, i.e. from _plugin_init.
// We can't really eliminate the need to implement _plugin_init in
// derived modules as we have to have the correct function name.
// use the DEFINE_MODULE macro to create the appropriate entry function.
static int create_plugin( plugin& p )
{
// Make sure exceptions do not propergate to C code
try
{
new MostDerived( p );
return 0;
}
catch( ... )
{
return 1;
}
}
};

// A list of defined interfaces.
// The first argument specifies a typedef handle to the handler types,
// the second specifies the handle name as seen in the plugin structure.
// This macro is only for handlers that take just the connection.
MAKE_HANDLER( UriRawHandler, handle_uri_raw );
MAKE_HANDLER( UriCleanHandler, handle_uri_clean );
MAKE_HANDLER( DocRootHandler, handle_docroot );
MAKE_HANDLER( PhysicalHandler, handle_physical );
MAKE_HANDLER( StartBackendHandler, handle_start_backend );

// This is defined in handler_helpers.hpp . It should not be used by derived plugins.
#undef MAKE_HANDLER

// Given your plugin name, this will create the entry point for lighttpd to use.
// To be used in your plugins cpp file.
#define MAKE_PLUGIN( name ) \
extern "C" \
{ \
static int name##_plugin_init( plugin* p ) \
{ \
return Plugin< name >::create_plugin( *p ); \
} \
}

#endif // _LIGHTTPD_PLUGIN_HPP_

(3-3/10)