ant-http/config.c

407 lines
12 KiB
C

#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "lib/ini.h"
#include "lib/utils.h"
#include "config.h"
#include "plugin_manager.h"
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
extern config_t g_server_config;
// define all basic mime here
static mime_t _mimes[] = {
{"image/bmp", "bmp"},
{"image/jpeg", "jpg,jpeg"},
{"text/css", "css"},
{"text/markdown", "md"},
{"text/csv", "csv"},
{"application/pdf", "pdf"},
{"image/gif", "gif"},
{"text/html", "html"},
{"application/json", "json"},
{"application/javascript", "js"},
{"image/png", "png"},
{"text/plain", "txt"},
{"application/xhtml+xml", "xhtml"},
{"application/xml", "xml"},
{"image/svg+xml", "svg"},
{NULL, NULL}};
static void init_plugins()
{
chain_t it, it2;
dictionary_t config;
const char *value;
for_each_assoc(it, g_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(g_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: auto loading...", it->key);
UNUSED(antd_plugin_load(it->key));
}
}
}
}
static int config_handler(void *conf, const char *section, const char *name,
const char *value)
{
config_t *pconfig = (config_t *)conf;
regmatch_t regex_matches[2];
char buf[255];
char *tmp;
struct stat st;
// trim(section, ' ');
// trim(value,' ');
// trim(name,' ');
// char * ppath = NULL;
if (MATCH("SERVER", "plugins"))
{
if (stat(value, &st) == -1)
mkdirp(value, 0755);
tmp = realpath(value, NULL);
if (!tmp)
{
ERROR("Unable to query real path for %s: %s", value, strerror(errno));
}
else
{
if (pconfig->plugins_dir)
free(pconfig->plugins_dir);
pconfig->plugins_dir = tmp;
LOG("Plugin root is %s", pconfig->plugins_dir);
}
}
else if (MATCH("SERVER", "plugins_ext"))
{
if (pconfig->plugins_ext)
free(pconfig->plugins_ext);
pconfig->plugins_ext = strdup(value);
}
else if (MATCH("SERVER", "tmpdir"))
{
if (stat(value, &st) == -1)
{
mkdirp(value, 0755);
}
else
{
removeAll(value, 0);
}
tmp = realpath(value, NULL);
if (!tmp)
{
ERROR("Unable to query real path for %s: %s", value, strerror(errno));
}
else
{
if (pconfig->tmpdir)
free(pconfig->tmpdir);
pconfig->tmpdir = tmp;
LOG("TMP root is %s", pconfig->tmpdir);
}
}
else if (MATCH("SERVER", "statistic_fifo"))
{
if (pconfig->stat_fifo_path)
free(pconfig->stat_fifo_path);
pconfig->stat_fifo_path = strdup(value);
}
else if (MATCH("SERVER", "max_upload_size"))
{
pconfig->max_upload_size = atoi(value);
}
else if (MATCH("SERVER", "maxcon"))
{
pconfig->maxcon = atoi(value);
}
else if (MATCH("SERVER", "backlog"))
{
pconfig->backlog = atoi(value);
}
else if (MATCH("SERVER", "workers"))
{
pconfig->n_workers = atoi(value);
}
else if (MATCH("SERVER", "debug_enable"))
{
(void)setenv("ANTD_DEBUG", value, 1);
pconfig->debug_enable = atoi(value);
}
else if (MATCH("SERVER", "scheduler_timeout"))
{
pconfig->scheduler_timeout = atoi(value);
}
#ifdef USE_ZLIB
else if (MATCH("SERVER", "gzip_enable"))
{
pconfig->gzip_enable = atoi(value);
}
else if (MATCH("SERVER", "gzip_types"))
{
pconfig->gzip_types = split(value, ",");
}
#endif
#ifdef USE_OPENSSL
else if (MATCH("SERVER", "ssl.cert"))
{
if (pconfig->sslcert)
free(pconfig->sslcert);
pconfig->sslcert = strdup(value);
}
else if (MATCH("SERVER", "ssl.key"))
{
if (pconfig->sslkey)
free(pconfig->sslkey);
pconfig->sslkey = strdup(value);
}
else if (MATCH("SERVER", "ssl.cipher"))
{
if (pconfig->ssl_cipher)
free(pconfig->ssl_cipher);
pconfig->ssl_cipher = strdup(value);
}
#endif
else if (strcmp(section, "MIMES") == 0)
{
dput(pconfig->mimes, name, strdup(value));
}
else if (regex_match("PORT:\\s*([0-9]+)", 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);
port_config_t *p = dvalue(pconfig->ports, buf);
if (!p)
{
p = (port_config_t *)malloc(sizeof(port_config_t));
p->htdocs = NULL;
p->plugins = NULL;
p->sock = -1;
p->type = ANTD_PROTO_ALL;
p->rules = dict_n(1);
dput(pconfig->ports, buf, p);
p->port = atoi(buf);
}
if (strcmp(name, "htdocs") == 0)
{
if (stat(value, &st) == -1)
{
mkdirp(value, 0755);
}
p->htdocs = realpath(value, NULL);
if (!p->htdocs)
{
ERROR("Unable to query real path for %s: %s", value, strerror(errno));
p->htdocs = strdup(value);
}
else
{
LOG("Server root is %s", p->htdocs);
}
}
else if (strcmp(name, "plugins") == 0)
{
p->plugins = strdup(value);
}
else if (strcmp(name, "ssl.enable") == 0)
{
p->usessl = atoi(value);
if (p->usessl)
pconfig->enable_ssl = 1;
}
else if (strcmp(name, "protocol") == 0)
{
if (strcmp(value, "ipv4") == 0)
{
p->type = ANTD_PROTO_IP_4;
}
else if (strcmp(value, "ipv6") == 0)
{
p->type = ANTD_PROTO_IP_6;
}
else
{
ERROR("Unknown IP protocol setting %s. Enable both.", value);
}
}
else
{
// other thing should be rules
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
{
return 0; /* unknown section/name, error */
}
return 1;
}
void load_config(const char *file)
{
g_server_config.ports = dict();
g_server_config.plugins = dict();
g_server_config.plugins_dir = strdup("plugins/");
g_server_config.plugins_ext = strdup(".so");
g_server_config.db_path = strdup("databases/");
// g_server_config.htdocs = "htdocs/";
g_server_config.tmpdir = strdup("/tmp/");
g_server_config.stat_fifo_path = strdup("");
g_server_config.n_workers = 4;
g_server_config.backlog = 1000;
g_server_config.handlers = dict();
g_server_config.maxcon = 100;
g_server_config.max_upload_size = 10000000; // 10Mb
g_server_config.connection = 0;
g_server_config.mimes = dict();
g_server_config.enable_ssl = 0;
g_server_config.sslcert = strdup("cert.pem");
g_server_config.sslkey = strdup("key.pem");
g_server_config.ssl_cipher = NULL;
g_server_config.gzip_enable = 0;
g_server_config.gzip_types = NULL;
g_server_config.debug_enable = 0;
g_server_config.scheduler_timeout = 30; // 30 s
// put it default mimes
for (int i = 0; _mimes[i].type != NULL; i++)
{
dput(g_server_config.mimes, _mimes[i].type, strdup(_mimes[i].ext));
}
if (ini_parse(file, config_handler, &g_server_config) < 0)
{
ERROR("Can't load '%s'. Used defaut configuration", file);
}
else
{
LOG("Using configuration : %s", file);
#ifdef USE_OPENSSL
LOG("SSL enable %d", g_server_config.enable_ssl);
LOG("SSL cert %s", g_server_config.sslcert);
LOG("SSL key %s", g_server_config.sslkey);
/*if(!g_server_config.ssl_cipher)
LOG("SSL Cipher suite: %s", "HIGH");
else
LOG("SSL Cipher suite: %s", g_server_config.ssl_cipher);*/
#endif
}
set_mimes_list(g_server_config.mimes);
#ifdef USE_ZLIB
if(g_server_config.gzip_enable && g_server_config.gzip_types != NULL)
{
set_gzip_types(g_server_config.gzip_types);
}
#endif
LOG("%d mimes entries found", g_server_config.mimes->size);
// Init plugins if necessary
init_plugins();
}
void destroy_config()
{
chain_t it;
freedict(g_server_config.handlers);
if (g_server_config.plugins_dir)
free(g_server_config.plugins_dir);
if (g_server_config.plugins_ext)
free(g_server_config.plugins_ext);
if (g_server_config.db_path)
free(g_server_config.db_path);
if (g_server_config.tmpdir)
free(g_server_config.tmpdir);
if (g_server_config.ssl_cipher)
free(g_server_config.ssl_cipher);
if (g_server_config.gzip_types)
{
list_free(&g_server_config.gzip_types);
#ifdef USE_ZLIB
set_gzip_types(g_server_config.gzip_types);
#endif
}
if (g_server_config.mimes)
{
freedict(g_server_config.mimes);
set_mimes_list(NULL);
}
if (g_server_config.stat_fifo_path)
free(g_server_config.stat_fifo_path);
if (g_server_config.plugins)
{
for_each_assoc(it, g_server_config.plugins)
{
freedict((dictionary_t)it->value);
it->value = NULL;
}
freedict(g_server_config.plugins);
}
if(g_server_config.sslcert)
{
free(g_server_config.sslcert);
}
if(g_server_config.sslkey)
{
free(g_server_config.sslkey);
}
if (g_server_config.ports)
{
port_config_t *cnf;
for_each_assoc(it, g_server_config.ports)
{
cnf = (port_config_t *)it->value;
if (cnf != NULL)
{
if (cnf->htdocs != NULL)
free(cnf->htdocs);
if (cnf->plugins)
free(cnf->plugins);
if (cnf->sock > 0)
{
close(cnf->sock);
}
freedict(cnf->rules);
}
}
freedict(g_server_config.ports);
}
LOG("Unclosed connection: %d", g_server_config.connection);
LOG("Config destroyed");
}