Compare commits

..

2 Commits

Author SHA1 Message Date
DanyLE
a78815c3b6 Allow enable/disable plugin on each port
All checks were successful
gitea-sync/ant-http/pipeline/head This commit looks good
2023-01-09 19:51:21 +01:00
DanyLE
4e1c220b39 Allow specific configuration for plugins 2023-01-09 16:31:59 +01:00
7 changed files with 165 additions and 73 deletions

View File

@ -30,6 +30,8 @@ ssl.cipher=ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA
; enable compression ; enable compression
gzip_enable = 1 gzip_enable = 1
gzip_types = text\/.*,.*\/css,.*\/json,.*\/javascript gzip_types = text\/.*,.*\/css,.*\/json,.*\/javascript
debug_enable = 1
; 0 to disable
; a configuration each port ; a configuration each port
@ -52,6 +54,8 @@ ssl.enable=0
[PORT:80] [PORT:80]
htdocs=/opt/www/htdocs htdocs=/opt/www/htdocs
; enable specific plugin
plugins=lua,tunnel
; enable or disable SSL ; enable or disable SSL
ssl.enable=0 ssl.enable=0
; ^\/os\/+(.*)$ = /proxy/http://localhost:443/test.html?<query> ; ^\/os\/+(.*)$ = /proxy/http://localhost:443/test.html?<query>
@ -95,22 +99,17 @@ application/x-font-woff=woff,woff2
application/x-font-otf=otf application/x-font-otf=otf
audio/mpeg=mp3,mpeg audio/mpeg=mp3,mpeg
[FILEHANDLER]
; specify a plugin for handling
; a file type
; lua page script
ls = lua
; pure lua script
lua = lua
; php and o ther scripting languages can be
; handled by the cgi plugin
; php = cgi
; Example of plugin configurations
; This enable some plugins to be initialised at server startup [PLUGIN:php]
; this section shall always at the end of the ; theses configurations is understandable by the server
; configuration file ; the name of the plugin in plugin dir
[AUTOSTART] name = fastcgi
; to start a plugin at server statup use: ; run this plugin at startup
;plugin = plugin_name_1 autoload = true
;plugin = plugin_name_2, etc ; file handle
file_type = php,pp
; pluggin specific configurations here, for example
socket = /var/php.sock
bin = /usr/bin/phpfcgi
; etc

View File

@ -58,6 +58,7 @@ config_t *config()
} }
void destroy_config() void destroy_config()
{ {
chain_t it;
freedict(server_config.handlers); freedict(server_config.handlers);
if (server_config.plugins_dir) if (server_config.plugins_dir)
free(server_config.plugins_dir); free(server_config.plugins_dir);
@ -75,9 +76,16 @@ void destroy_config()
freedict(server_config.mimes); freedict(server_config.mimes);
if (server_config.stat_fifo_path) if (server_config.stat_fifo_path)
free(server_config.stat_fifo_path); free(server_config.stat_fifo_path);
if(server_config.plugins)
{
for_each_assoc(it, server_config.plugins)
{
freedict((dictionary_t) it->value);
}
freedict(server_config.plugins);
}
if (server_config.ports) if (server_config.ports)
{ {
chain_t it;
port_config_t *cnf; port_config_t *cnf;
for_each_assoc(it, server_config.ports) for_each_assoc(it, server_config.ports)
{ {
@ -86,6 +94,8 @@ void destroy_config()
{ {
if (cnf->htdocs != NULL) if (cnf->htdocs != NULL)
free(cnf->htdocs); free(cnf->htdocs);
if(cnf->plugins)
free(cnf->plugins);
if (cnf->sock > 0) if (cnf->sock > 0)
{ {
close(cnf->sock); close(cnf->sock);
@ -102,7 +112,8 @@ static int config_handler(void *conf, const char *section, const char *name,
const char *value) const char *value)
{ {
config_t *pconfig = (config_t *)conf; config_t *pconfig = (config_t *)conf;
regmatch_t port_matches[2]; regmatch_t regex_matches[2];
char buf[255];
char * tmp; char * tmp;
struct stat st; struct stat st;
// trim(section, ' '); // trim(section, ' ');
@ -233,30 +244,20 @@ static int config_handler(void *conf, const char *section, const char *name,
pconfig->ssl_cipher = strdup(value); pconfig->ssl_cipher = strdup(value);
} }
#endif #endif
else if (strcmp(section, "FILEHANDLER") == 0)
{
dput(pconfig->handlers, name, strdup(value));
}
else if (strcmp(section, "AUTOSTART") == 0 || strcmp(section, "AUTOLOAD") == 0)
{
// The server section must be added before the autostart section
// auto start plugin
plugin_load((char *)value);
}
else if (strcmp(section, "MIMES") == 0) else if (strcmp(section, "MIMES") == 0)
{ {
dput(pconfig->mimes, name, strdup(value)); dput(pconfig->mimes, name, strdup(value));
} }
else if (regex_match("PORT:\\s*([0-9]+)", section, 2, port_matches)) else if (regex_match("PORT:\\s*([0-9]+)", section, 2, regex_matches))
{ {
char buf[20];
memset(buf, '\0', sizeof(buf)); memset(buf, '\0', sizeof(buf));
memcpy(buf, section + port_matches[1].rm_so, port_matches[1].rm_eo - port_matches[1].rm_so); memcpy(buf, section + regex_matches[1].rm_so, regex_matches[1].rm_eo - regex_matches[1].rm_so);
port_config_t *p = dvalue(pconfig->ports, buf); port_config_t *p = dvalue(pconfig->ports, buf);
if (!p) if (!p)
{ {
p = (port_config_t *)malloc(sizeof(port_config_t)); p = (port_config_t *)malloc(sizeof(port_config_t));
p->htdocs = NULL; p->htdocs = NULL;
p->plugins = NULL;
p->sock = -1; p->sock = -1;
p->rules = dict_n(1); p->rules = dict_n(1);
dput(pconfig->ports, buf, p); dput(pconfig->ports, buf, p);
@ -279,6 +280,10 @@ static int config_handler(void *conf, const char *section, const char *name,
LOG("Server root is %s", p->htdocs); LOG("Server root is %s", p->htdocs);
} }
} }
else if(strcmp(name, "plugins") == 0)
{
p->plugins = strdup(value);
}
else if (strcmp(name, "ssl.enable") == 0) else if (strcmp(name, "ssl.enable") == 0)
{ {
p->usessl = atoi(value); p->usessl = atoi(value);
@ -291,6 +296,19 @@ static int config_handler(void *conf, const char *section, const char *name,
dput(p->rules, name, strdup(value)); dput(p->rules, name, strdup(value));
} }
} }
// plugin configuration
else if (regex_match("PLUGIN:\\s*(.*)", section, 2, regex_matches))
{
memset(buf, '\0', sizeof(buf));
memcpy(buf, section + regex_matches[1].rm_so, regex_matches[1].rm_eo - regex_matches[1].rm_so);
dictionary_t p = dvalue(pconfig->plugins, buf);
if (!p)
{
p = dict();
dput(pconfig->plugins, buf, p);
}
dput(p, name, strdup(value));
}
else else
{ {
return 0; /* unknown section/name, error */ return 0; /* unknown section/name, error */
@ -298,9 +316,51 @@ static int config_handler(void *conf, const char *section, const char *name,
return 1; return 1;
} }
static void init_plugins()
{
chain_t it, it2;
dictionary_t config;
const char* value;
for_each_assoc(it, server_config.plugins)
{
config = (dictionary_t) it -> value;
if(config)
{
for_each_assoc(it2, config)
{
LOG("Plugin %s: [%s] -> [%s]", it->key, it2->key, (char*) it2->value);
if(strncmp(it2->key, "file_type", 9) == 0 && it2->value)
{
char* file_type = strdup((char*) it2->value);
char* token;
char *stringp = file_type;
while((token = strsep(&stringp,",")))
{
trim(token, ' ');
if(strlen(token) > 0)
{
dput(server_config.handlers,token, strdup((char*)it->key));
LOG("Plugin %s: support %s file", it->key, token);
}
}
free(file_type);
}
}
value = (char*)dvalue(config,"autoload");
if( value && (strncmp(value,"1", 1) == 0 || strncmp(value, "true", 3) == 0 ) )
{
// load the plugin
LOG("Plugin %s: autoloading...", it->key);
plugin_load(it->key, config);
}
}
}
}
void load_config(const char *file) void load_config(const char *file)
{ {
server_config.ports = dict(); server_config.ports = dict();
server_config.plugins = dict();
server_config.plugins_dir = strdup("plugins/"); server_config.plugins_dir = strdup("plugins/");
server_config.plugins_ext = strdup(".so"); server_config.plugins_ext = strdup(".so");
server_config.db_path = strdup("databases/"); server_config.db_path = strdup("databases/");
@ -345,6 +405,8 @@ void load_config(const char *file)
#endif #endif
} }
LOG("%d mimes entries found", server_config.mimes->size); LOG("%d mimes entries found", server_config.mimes->size);
// Init plugins if necessary
init_plugins();
} }
void *accept_request(void *data) void *accept_request(void *data)
@ -1626,22 +1688,34 @@ void *execute_plugin(void *data, const char *pname)
plugin_header_t *meta = NULL; plugin_header_t *meta = NULL;
struct plugin_entry *plugin; struct plugin_entry *plugin;
char *error; char *error;
char pattern[256];
antd_request_t *rq = (antd_request_t *)data; antd_request_t *rq = (antd_request_t *)data;
antd_task_t *task = antd_create_task(NULL, (void *)rq, NULL, rq->client->last_io); antd_task_t *task = antd_create_task(NULL, (void *)rq, NULL, rq->client->last_io);
antd_task_bind_event(task, rq->client->sock, 0, TASK_EVT_ON_WRITABLE | TASK_EVT_ON_READABLE); antd_task_bind_event(task, rq->client->sock, 0, TASK_EVT_ON_WRITABLE | TASK_EVT_ON_READABLE);
snprintf(pattern, sizeof(pattern), "\\b%s\\b", pname);
char *port_s = (char *)dvalue(rq->request, "SERVER_PORT");
port_config_t *pcnf = (port_config_t *)dvalue(server_config.ports, port_s);
// check if plugin is enabled on this port
if(!pcnf->plugins || !regex_match(pattern, pcnf->plugins , 0,NULL))
{
LOG("No plugin matched in [%s] using pattern [%s]", pcnf->plugins, pattern);
antd_error(rq->client, 403, "Access forbidden");
return task;
}
// LOG("Plugin name '%s'", pname); // LOG("Plugin name '%s'", pname);
rq->client->state = ANTD_CLIENT_PLUGIN_EXEC; rq->client->state = ANTD_CLIENT_PLUGIN_EXEC;
// load the plugin // load the plugin
if ((plugin = plugin_lookup((char *)pname)) == NULL) pthread_mutex_lock(&server_mux);
plugin = plugin_load((char *)pname, dvalue(server_config.plugins, pname));
pthread_mutex_unlock(&server_mux);
if (plugin == NULL)
{ {
pthread_mutex_lock(&server_mux); antd_error(rq->client, 503, "Requested service not found");
plugin = plugin_load((char *)pname); return task;
pthread_mutex_unlock(&server_mux);
if (plugin == NULL)
{
antd_error(rq->client, 503, "Requested service not found");
return task;
}
} }
// check if the plugin want rawbody or decoded body // check if the plugin want rawbody or decoded body
metafn = (plugin_header_t * (*)()) dlsym(plugin->handle, "meta"); metafn = (plugin_header_t * (*)()) dlsym(plugin->handle, "meta");
@ -1675,17 +1749,17 @@ dictionary_t mimes_list()
return server_config.mimes; return server_config.mimes;
} }
void dbdir(char *dest) void dbdir(char **dest)
{ {
strncpy(dest, server_config.db_path, 512); *dest = server_config.db_path;
} }
void tmpdir(char *dest) void tmpdir(char **dest)
{ {
strncpy(dest, server_config.tmpdir, 512); *dest = server_config.tmpdir;
} }
void plugindir(char *dest) void plugindir(char **dest)
{ {
strncpy(dest, server_config.plugins_dir, 512); *dest =server_config.plugins_dir;
} }
#ifdef USE_ZLIB #ifdef USE_ZLIB

View File

@ -115,15 +115,15 @@ void htdocs(antd_request_t *rq, char *dest)
strcpy(dest, www); strcpy(dest, www);
} }
} }
void dbdir(char *dest) void dbdir(char **dest)
{ {
UNUSED(dest); UNUSED(dest);
} }
void tmpdir(char *dest) void tmpdir(char **dest)
{ {
UNUSED(dest); UNUSED(dest);
} }
void plugindir(char *dest) void plugindir(char **dest)
{ {
UNUSED(dest); UNUSED(dest);
} }

View File

@ -42,6 +42,7 @@ typedef struct
unsigned int port; unsigned int port;
int usessl; int usessl;
char *htdocs; char *htdocs;
char* plugins;
int sock; int sock;
dictionary_t rules; dictionary_t rules;
} port_config_t; } port_config_t;
@ -98,23 +99,25 @@ typedef struct
list_t gzip_types; list_t gzip_types;
dictionary_t mimes; dictionary_t mimes;
dictionary_t ports; dictionary_t ports;
dictionary_t plugins;
// #endif // #endif
} config_t; } config_t;
typedef struct typedef struct
{ {
char name[128]; char name[128];
char dbpath[512]; char* dbpath;
char tmpdir[512]; char* tmpdir;
char pdir[512]; char* pdir;
dictionary_t config;
int raw_body; int raw_body;
} plugin_header_t; } plugin_header_t;
int __attribute__((weak)) require_plugin(const char *); int __attribute__((weak)) require_plugin(const char *);
void __attribute__((weak)) htdocs(antd_request_t *rq, char *dest); void __attribute__((weak)) htdocs(antd_request_t *rq, char *dest);
void __attribute__((weak)) dbdir(char *dest); void __attribute__((weak)) dbdir(char **dest);
void __attribute__((weak)) tmpdir(char *dest); void __attribute__((weak)) tmpdir(char **dest);
void __attribute__((weak)) plugindir(char *dest); void __attribute__((weak)) plugindir(char **dest);
int __attribute__((weak)) compressable(char *ctype); int __attribute__((weak)) compressable(char *ctype);

View File

@ -35,11 +35,12 @@ STATIC PART, should be included in any plugin
#ifdef PLUGIN_IMPLEMENT #ifdef PLUGIN_IMPLEMENT
static plugin_header_t __plugin__; static plugin_header_t __plugin__;
// private function // private function
void __init_plugin__(const char* pl){ void __init_plugin__(const char* pl, dictionary_t* conf){
strcpy(__plugin__.name,pl); strcpy(__plugin__.name,pl);
dbdir(__plugin__.dbpath); dbdir(&__plugin__.dbpath);
plugindir(__plugin__.pdir); plugindir(&__plugin__.pdir);
tmpdir(__plugin__.tmpdir); tmpdir(&__plugin__.tmpdir);
__plugin__.config = conf;
__plugin__.raw_body = 0; __plugin__.raw_body = 0;
init(); init();
}; };

View File

@ -4,6 +4,10 @@
#include "lib/utils.h" #include "lib/utils.h"
#include "lib/handle.h" #include "lib/handle.h"
#include "http_server.h" #include "http_server.h"
static void unload_plugin_by_name(const char*);
static void * plugin_from_file(char* name, dictionary_t conf);
/** /**
* Plugin table to store the loaded plugin * Plugin table to store the loaded plugin
*/ */
@ -25,7 +29,7 @@ struct plugin_entry *plugin_lookup(char *s)
int require_plugin(const char* name) int require_plugin(const char* name)
{ {
struct plugin_entry* ptr = plugin_load((char*)name); struct plugin_entry* ptr = plugin_load((char*)name, NULL);
return ptr != NULL; return ptr != NULL;
} }
@ -33,13 +37,24 @@ int require_plugin(const char* name)
* Load a plugin to the plugin table * Load a plugin to the plugin table
* Only load when not available in the plugin table * Only load when not available in the plugin table
* @param name plugin name * @param name plugin name
* @param config: plugin configuration
* @return pointer to the loaded plugin * @return pointer to the loaded plugin
*/ */
struct plugin_entry *plugin_load(char *name) struct plugin_entry *plugin_load(char *name, dictionary_t config)
{ {
char* pname = NULL;
struct plugin_entry *np; struct plugin_entry *np;
unsigned hashval; unsigned hashval;
if(config)
{
pname = dvalue(config, "name");
}
if(!pname)
{
pname = name;
}
if ((np = plugin_lookup(name)) == NULL) { /* not found */ if ((np = plugin_lookup(name)) == NULL) { /* not found */
LOG("Loading plugin: %s -> %s", name, pname);
np = (struct plugin_entry *) malloc(sizeof(*np)); np = (struct plugin_entry *) malloc(sizeof(*np));
if (np == NULL || name == NULL) if (np == NULL || name == NULL)
{ {
@ -47,7 +62,7 @@ struct plugin_entry *plugin_load(char *name)
return NULL; return NULL;
} }
np->pname = strdup(name); np->pname = strdup(name);
if ((np->handle = plugin_from_file(name)) == NULL) if ((np->handle = plugin_from_file(pname,config)) == NULL)
{ {
if(np->pname) free(np->pname); if(np->pname) free(np->pname);
if(np) free(np); if(np) free(np);
@ -68,12 +83,12 @@ struct plugin_entry *plugin_load(char *name)
* @param name Name of the plugin * @param name Name of the plugin
* @return * @return
*/ */
void * plugin_from_file(char* name) static void * plugin_from_file(char* name, dictionary_t conf)
{ {
void *lib_handle; void *lib_handle;
char* error; char* error;
char* path = __s("%s/%s%s",config()->plugins_dir,name,config()->plugins_ext); char* path = __s("%s/%s%s",config()->plugins_dir,name,config()->plugins_ext);
void (*fn)(const char*); void (*fn)(const char*, dictionary_t);
lib_handle = dlopen(path, RTLD_LAZY); lib_handle = dlopen(path, RTLD_LAZY);
if (!lib_handle) if (!lib_handle)
{ {
@ -83,11 +98,11 @@ void * plugin_from_file(char* name)
return NULL; return NULL;
} }
// set database path // set database path
fn = (void (*)(const char *))dlsym(lib_handle, "__init_plugin__"); fn = (void (*)(const char*, dictionary_t))dlsym(lib_handle, "__init_plugin__");
if ((error = dlerror()) != NULL) if ((error = dlerror()) != NULL)
ERROR("Problem when finding plugin init function for %s : %s", name,error); ERROR("Problem when finding plugin init function for %s : %s", name,error);
else else
(*fn)(name); (*fn)(name, conf);
if(path) if(path)
free(path); free(path);
return lib_handle; return lib_handle;

View File

@ -1,5 +1,8 @@
#ifndef PLUGIN_MANAGER_H #ifndef PLUGIN_MANAGER_H
#define PLUGIN_MANAGER_H #define PLUGIN_MANAGER_H
#include "lib/dictionary.h"
struct plugin_entry { struct plugin_entry {
struct plugin_entry *next; struct plugin_entry *next;
char *pname; char *pname;
@ -8,10 +11,7 @@ struct plugin_entry {
/* lookup: look for s in hashtab */ /* lookup: look for s in hashtab */
struct plugin_entry *plugin_lookup(char *s); struct plugin_entry *plugin_lookup(char *s);
/* install: put (name, defn) in hashtab */ /* install: put (name, defn) in hashtab */
struct plugin_entry *plugin_load(char *name); struct plugin_entry *plugin_load(char *name, dictionary_t config);
void unload_all_plugin(); void unload_all_plugin();
void unload_plugin(struct plugin_entry*); void unload_plugin(struct plugin_entry*);
void unload_plugin_by_name(const char*);
void * plugin_from_file(char* name);
#endif #endif