mirror of
https://github.com/lxsang/ant-http
synced 2024-12-25 16:28:21 +01:00
refactor: refactoring base code
This commit is contained in:
parent
9c25e62c0a
commit
3bedc3ffb5
28
.drone.yml
28
.drone.yml
@ -1,28 +0,0 @@
|
|||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
type: exec
|
|
||||||
name: default
|
|
||||||
platform:
|
|
||||||
os: linux
|
|
||||||
arch: amd64
|
|
||||||
clone:
|
|
||||||
disable: true
|
|
||||||
steps:
|
|
||||||
- name: clone
|
|
||||||
commands:
|
|
||||||
- pwd
|
|
||||||
- git clone ssh://git@iohub.dev/lxsang/ant-http.git
|
|
||||||
- cd ./ant-http && git checkout master
|
|
||||||
- name: build
|
|
||||||
commands:
|
|
||||||
- cd ./ant-http
|
|
||||||
- libtoolize
|
|
||||||
- aclocal
|
|
||||||
- autoconf
|
|
||||||
- automake --add-missing
|
|
||||||
- ./configure --prefix=/usr
|
|
||||||
- make
|
|
||||||
- DESTDIR=/opt/cloud/artifacts make install
|
|
||||||
trigger:
|
|
||||||
branch:
|
|
||||||
- master
|
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -71,3 +71,4 @@ configure
|
|||||||
aclocal.m4
|
aclocal.m4
|
||||||
ltmain.sh
|
ltmain.sh
|
||||||
Makefile.in
|
Makefile.in
|
||||||
|
configure~
|
11
.travis.yml
11
.travis.yml
@ -1,11 +0,0 @@
|
|||||||
language: c
|
|
||||||
before_install:
|
|
||||||
- sudo apt-get -qq update
|
|
||||||
- sudo apt-get install libssl-dev libsqlite3-dev autotools-dev autoconf libtool libtool-bin
|
|
||||||
script:
|
|
||||||
- libtoolize
|
|
||||||
- aclocal
|
|
||||||
- autoconf
|
|
||||||
- automake --add-missing
|
|
||||||
- ./configure
|
|
||||||
- make
|
|
11
Makefile.am
11
Makefile.am
@ -38,16 +38,15 @@ pkginclude_HEADERS = lib/ini.h \
|
|||||||
|
|
||||||
|
|
||||||
EXTRA_DIST = plugin_manager.h http_server.h README.md LICENSE antd-config.ini ant-d antd.service
|
EXTRA_DIST = plugin_manager.h http_server.h README.md LICENSE antd-config.ini ant-d antd.service
|
||||||
# check for db
|
|
||||||
if DB
|
|
||||||
libantd_la_SOURCES += lib/dbhelper.c
|
|
||||||
pkginclude_HEADERS += lib/dbhelper.h
|
|
||||||
endif
|
|
||||||
|
|
||||||
# bin
|
# bin
|
||||||
bin_PROGRAMS = antd
|
bin_PROGRAMS = antd
|
||||||
# lib source files
|
# lib source files
|
||||||
antd_SOURCES = plugin_manager.c http_server.c httpd.c
|
antd_SOURCES = plugin_manager.c \
|
||||||
|
server.c \
|
||||||
|
config.c \
|
||||||
|
decode.c \
|
||||||
|
httpd.c
|
||||||
antd_LDADD = libantd.la
|
antd_LDADD = libantd.la
|
||||||
|
|
||||||
|
|
||||||
|
399
config.c
Normal file
399
config.c
Normal file
@ -0,0 +1,399 @@
|
|||||||
|
#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: autoloading...", it->key);
|
||||||
|
plugin_load(it->key, config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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", "database"))
|
||||||
|
{
|
||||||
|
if (stat(value, &st) == -1)
|
||||||
|
mkdirp(value, 0700);
|
||||||
|
tmp = realpath(value, NULL);
|
||||||
|
if (!tmp)
|
||||||
|
{
|
||||||
|
ERROR("Unable to query real path for %s: %s", value, strerror(errno));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (pconfig->db_path)
|
||||||
|
free(pconfig->db_path);
|
||||||
|
pconfig->db_path = tmp;
|
||||||
|
LOG("Database root is %s", pconfig->db_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
if (g_server_config.mimes)
|
||||||
|
freedict(g_server_config.mimes);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
freedict(g_server_config.plugins);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
52
config.h
Normal file
52
config.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#ifndef CONFIG_H
|
||||||
|
#define CONFIG_H
|
||||||
|
|
||||||
|
#include "lib/handle.h"
|
||||||
|
|
||||||
|
#ifndef CONFIG_FILE
|
||||||
|
#define CONFIG_FILE "antd-config.ini"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned int port;
|
||||||
|
int usessl;
|
||||||
|
char *htdocs;
|
||||||
|
char* plugins;
|
||||||
|
int sock;
|
||||||
|
antd_proto_t type;
|
||||||
|
dictionary_t rules;
|
||||||
|
} port_config_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
//int port;
|
||||||
|
char *plugins_dir;
|
||||||
|
char *plugins_ext;
|
||||||
|
char *db_path;
|
||||||
|
//char* htdocs;
|
||||||
|
char *tmpdir;
|
||||||
|
char *stat_fifo_path;
|
||||||
|
dictionary_t handlers;
|
||||||
|
int backlog;
|
||||||
|
int maxcon;
|
||||||
|
int connection;
|
||||||
|
int n_workers;
|
||||||
|
int scheduler_timeout;
|
||||||
|
int max_upload_size;
|
||||||
|
// ssl
|
||||||
|
int enable_ssl;
|
||||||
|
char *sslcert;
|
||||||
|
char *sslkey;
|
||||||
|
char *ssl_cipher;
|
||||||
|
int gzip_enable;
|
||||||
|
int debug_enable;
|
||||||
|
list_t gzip_types;
|
||||||
|
dictionary_t mimes;
|
||||||
|
dictionary_t ports;
|
||||||
|
dictionary_t plugins;
|
||||||
|
// #endif
|
||||||
|
} config_t;
|
||||||
|
void load_config(const char *file);
|
||||||
|
void destroy_config();
|
||||||
|
#endif
|
12
configure.ac
12
configure.ac
@ -10,17 +10,6 @@ AC_PROG_CC
|
|||||||
# libtool for linking
|
# libtool for linking
|
||||||
AC_PROG_LIBTOOL
|
AC_PROG_LIBTOOL
|
||||||
# check if sqlite3 header exists
|
# check if sqlite3 header exists
|
||||||
use_db=no
|
|
||||||
AC_CHECK_HEADER([sqlite3.h],[
|
|
||||||
AC_DEFINE([USE_DB], [1],[Use sqlite3])
|
|
||||||
use_db=yes
|
|
||||||
# check if the library exists
|
|
||||||
],[])
|
|
||||||
AC_CHECK_LIB([sqlite3],[sqlite3_open],[],[
|
|
||||||
if test "$use_db" = "yes"; then
|
|
||||||
AC_MSG_ERROR([Unable to find sqlite3 shared library])
|
|
||||||
fi
|
|
||||||
])
|
|
||||||
|
|
||||||
use_ssl=no
|
use_ssl=no
|
||||||
# check if libssl header exists
|
# check if libssl header exists
|
||||||
@ -101,7 +90,6 @@ esac
|
|||||||
# build_windows=yes
|
# build_windows=yes
|
||||||
# ;;
|
# ;;
|
||||||
# Pass the conditionals to automake
|
# Pass the conditionals to automake
|
||||||
AM_CONDITIONAL([DB], [test "$use_db" = "yes"])
|
|
||||||
AM_CONDITIONAL([LINUX], [test "$build_linux" = "yes"])
|
AM_CONDITIONAL([LINUX], [test "$build_linux" = "yes"])
|
||||||
AM_CONDITIONAL([WINDOWS], [test "$build_windows" = "yes"])
|
AM_CONDITIONAL([WINDOWS], [test "$build_windows" = "yes"])
|
||||||
AM_CONDITIONAL([OSX], [test "$build_mac" = "yes"])
|
AM_CONDITIONAL([OSX], [test "$build_mac" = "yes"])
|
||||||
|
777
decode.c
Normal file
777
decode.c
Normal file
@ -0,0 +1,777 @@
|
|||||||
|
#ifdef USE_OPENSSL
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
#else
|
||||||
|
#include "lib/sha1.h"
|
||||||
|
#endif
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "decode.h"
|
||||||
|
#include "lib/handle.h"
|
||||||
|
#include "lib/utils.h"
|
||||||
|
#include "lib/scheduler.h"
|
||||||
|
#include "server.h"
|
||||||
|
#include "lib/base64.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#define WS_MAGIC_STRING "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
|
||||||
|
#define HEADER_MAX_SIZE 8192
|
||||||
|
|
||||||
|
extern config_t g_server_config;
|
||||||
|
|
||||||
|
static int rule_check(const char *k, const char *v, const char *host, const char *_url, const char *_query, char *buf)
|
||||||
|
{
|
||||||
|
// first perfom rule check on host, if not success, perform on url
|
||||||
|
regmatch_t key_matches[10];
|
||||||
|
regmatch_t val_matches[2];
|
||||||
|
char *query = strdup(_query);
|
||||||
|
char *url = strdup(_url);
|
||||||
|
int ret;
|
||||||
|
char *target;
|
||||||
|
char *tmp, rep[10];
|
||||||
|
int idx = 0;
|
||||||
|
memset(rep, 0, 10);
|
||||||
|
LOG("Verify %s=%s on %s or %s", k, v, url, host);
|
||||||
|
// 1 group
|
||||||
|
if (!host || !(ret = regex_match(k, host, 10, key_matches)))
|
||||||
|
{
|
||||||
|
target = url;
|
||||||
|
ret = regex_match(k, url, 10, key_matches);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
target = (char *)host;
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
{
|
||||||
|
free(url);
|
||||||
|
free(query);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
LOG("Match found on %s", target);
|
||||||
|
tmp = (char *)v;
|
||||||
|
char *search = "<([a-zA-Z0-9]+)>";
|
||||||
|
while ((ret = regex_match(search, tmp, 2, val_matches)))
|
||||||
|
{
|
||||||
|
memcpy(buf + idx, tmp, val_matches[1].rm_so - 1);
|
||||||
|
idx += val_matches[1].rm_so - 1;
|
||||||
|
memcpy(rep, tmp + val_matches[1].rm_so, val_matches[1].rm_eo - val_matches[1].rm_so);
|
||||||
|
if (strcasecmp(rep, "url") == 0)
|
||||||
|
{
|
||||||
|
memcpy(buf + idx, url, strlen(url));
|
||||||
|
idx += strlen(url);
|
||||||
|
}
|
||||||
|
else if (strcasecmp(rep, "query") == 0)
|
||||||
|
{
|
||||||
|
memcpy(buf + idx, query, strlen(query));
|
||||||
|
idx += strlen(query);
|
||||||
|
}
|
||||||
|
else if (match_int(rep))
|
||||||
|
{
|
||||||
|
int i = atoi(rep);
|
||||||
|
memcpy(buf + idx, target + key_matches[i].rm_so, key_matches[i].rm_eo - key_matches[i].rm_so);
|
||||||
|
idx += key_matches[i].rm_eo - key_matches[i].rm_so;
|
||||||
|
}
|
||||||
|
else if (strcasecmp(rep, "break") == 0)
|
||||||
|
{
|
||||||
|
// ignore it
|
||||||
|
LOG("Found break command, will break after this rule");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // just keep it
|
||||||
|
memcpy(buf + idx, tmp + val_matches[1].rm_so - 1, val_matches[1].rm_eo + 2 - val_matches[1].rm_so);
|
||||||
|
idx += val_matches[1].rm_eo + 2 - val_matches[1].rm_so;
|
||||||
|
}
|
||||||
|
tmp += val_matches[1].rm_eo + 1;
|
||||||
|
// break;
|
||||||
|
}
|
||||||
|
// now modify the match 2 group
|
||||||
|
if (idx > 0)
|
||||||
|
{
|
||||||
|
if (tmp)
|
||||||
|
{
|
||||||
|
// copy the remainning of tmp
|
||||||
|
memcpy(buf + idx, tmp, strlen(tmp));
|
||||||
|
idx += strlen(tmp);
|
||||||
|
}
|
||||||
|
buf[idx] = '\0';
|
||||||
|
}
|
||||||
|
free(url);
|
||||||
|
free(query);
|
||||||
|
LOG("New URI is %s", buf);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *apply_rules(dictionary_t rules, const char *host, char *url)
|
||||||
|
{
|
||||||
|
// rule check
|
||||||
|
char *query_string = url;
|
||||||
|
while ((*query_string != '?') && (*query_string != '\0'))
|
||||||
|
query_string++;
|
||||||
|
if (*query_string == '?')
|
||||||
|
{
|
||||||
|
*query_string = '\0';
|
||||||
|
query_string++;
|
||||||
|
}
|
||||||
|
// char* oldurl = strdup(url);
|
||||||
|
chain_t it;
|
||||||
|
char *k;
|
||||||
|
char *v;
|
||||||
|
int should_break = 0;
|
||||||
|
for_each_assoc(it, rules)
|
||||||
|
{
|
||||||
|
k = it->key;
|
||||||
|
if (it->value)
|
||||||
|
{
|
||||||
|
v = (char *)it->value;
|
||||||
|
// 1 group
|
||||||
|
if (regex_match("<break>$", v, 0, NULL))
|
||||||
|
{
|
||||||
|
should_break = 1;
|
||||||
|
}
|
||||||
|
if (rule_check(k, v, host, url, query_string, url))
|
||||||
|
{
|
||||||
|
query_string = url;
|
||||||
|
|
||||||
|
while ((*query_string != '?') && (*query_string != '\0'))
|
||||||
|
query_string++;
|
||||||
|
if (*query_string == '?')
|
||||||
|
{
|
||||||
|
*query_string = '\0';
|
||||||
|
query_string++;
|
||||||
|
}
|
||||||
|
if (should_break)
|
||||||
|
{
|
||||||
|
i = rules->cap;
|
||||||
|
LOG("Break rule check as matched found at %s -> %s", k, v);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return strdup(query_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ws_confirm_request(void *client, const char *key)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
char rkey[128];
|
||||||
|
char sha_d[20];
|
||||||
|
char base64[64];
|
||||||
|
strncpy(rkey, key, sizeof(rkey) - 1);
|
||||||
|
int n = (int)sizeof(rkey) - (int)strlen(key);
|
||||||
|
if (n < 0)
|
||||||
|
n = 0;
|
||||||
|
strncat(rkey, WS_MAGIC_STRING, n);
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
|
SHA_CTX context;
|
||||||
|
#else
|
||||||
|
SHA1_CTX context;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SHA1_Init(&context);
|
||||||
|
SHA1_Update(&context, rkey, strlen(rkey));
|
||||||
|
SHA1_Final((uint8_t *)sha_d, &context);
|
||||||
|
Base64encode(base64, sha_d, 20);
|
||||||
|
// send accept to client
|
||||||
|
sprintf(buf, "HTTP/1.1 101 Switching Protocols\r\n");
|
||||||
|
antd_send(client, buf, strlen(buf));
|
||||||
|
sprintf(buf, "Upgrade: websocket\r\n");
|
||||||
|
antd_send(client, buf, strlen(buf));
|
||||||
|
sprintf(buf, "Connection: Upgrade\r\n");
|
||||||
|
antd_send(client, buf, strlen(buf));
|
||||||
|
sprintf(buf, "Sec-WebSocket-Accept: %s\r\n", base64);
|
||||||
|
antd_send(client, buf, strlen(buf));
|
||||||
|
sprintf(buf, "\r\n");
|
||||||
|
antd_send(client, buf, strlen(buf));
|
||||||
|
|
||||||
|
LOG("%s", "Websocket is now enabled for plugin");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *decode_request(void *data)
|
||||||
|
{
|
||||||
|
antd_request_t *rq = (antd_request_t *)data;
|
||||||
|
dictionary_t headers = dvalue(rq->request, "REQUEST_HEADER");
|
||||||
|
int ws = 0;
|
||||||
|
char *ws_key = NULL;
|
||||||
|
char *method = NULL;
|
||||||
|
char *tmp;
|
||||||
|
antd_task_t *task = NULL;
|
||||||
|
ws_key = (char *)dvalue(headers, "Sec-WebSocket-Key");
|
||||||
|
tmp = (char *)dvalue(headers, "Upgrade");
|
||||||
|
if (tmp && strcasecmp(tmp, "websocket") == 0)
|
||||||
|
ws = 1;
|
||||||
|
method = (char *)dvalue(rq->request, "METHOD");
|
||||||
|
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);
|
||||||
|
if (EQU(method, "GET"))
|
||||||
|
{
|
||||||
|
// if(ctype) free(ctype);
|
||||||
|
if (ws && ws_key != NULL)
|
||||||
|
{
|
||||||
|
ws_confirm_request(rq->client, ws_key);
|
||||||
|
// insert wsocket flag to request
|
||||||
|
// plugin should handle this ugraded connection
|
||||||
|
// not the server
|
||||||
|
dput(rq->request, "__web_socket__", strdup("1"));
|
||||||
|
}
|
||||||
|
// resolve task
|
||||||
|
task->handle = resolve_request;
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
else if (EQU(method, "HEAD") || EQU(method, "OPTIONS") || EQU(method, "DELETE"))
|
||||||
|
{
|
||||||
|
task->handle = resolve_request;
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
else if (EQU(method, "POST") || EQU(method, "PUT") || EQU(method, "PATCH"))
|
||||||
|
{
|
||||||
|
task->handle = resolve_request;
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
antd_error(rq->client, 501, "Request Method Not Implemented");
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the current request is e reverse proxy
|
||||||
|
* return a proxy task if this is the case
|
||||||
|
*/
|
||||||
|
static void *check_proxy(antd_request_t *rq, const char *path, const char *query)
|
||||||
|
{
|
||||||
|
char *pattern = "^(https?)://([^:]+):([0-9]+)(.*)$";
|
||||||
|
antd_task_t *task = antd_create_task(NULL, (void *)rq, NULL, rq->client->last_io);
|
||||||
|
char buff[256];
|
||||||
|
regmatch_t matches[5];
|
||||||
|
int ret, size;
|
||||||
|
ret = regex_match(pattern, path, 5, matches);
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matches[1].rm_eo - matches[1].rm_so == 5)
|
||||||
|
{
|
||||||
|
// https is not supported for now
|
||||||
|
// TODO add https support
|
||||||
|
antd_error(rq->client, 503, "Service Unavailable");
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
// http proxy request
|
||||||
|
size = matches[2].rm_eo - matches[2].rm_so < (int)sizeof(buff) ? matches[2].rm_eo - matches[2].rm_so : (int)sizeof(buff);
|
||||||
|
(void)memcpy(buff, path + matches[2].rm_so, size);
|
||||||
|
buff[size] = '\0';
|
||||||
|
dput(rq->request, "PROXY_HOST", strdup(buff));
|
||||||
|
|
||||||
|
size = matches[3].rm_eo - matches[3].rm_so < (int)sizeof(buff) ? matches[3].rm_eo - matches[3].rm_so : (int)sizeof(buff);
|
||||||
|
(void)memcpy(buff, path + matches[3].rm_so, size);
|
||||||
|
buff[size] = '\0';
|
||||||
|
dput(rq->request, "PROXY_PORT", strdup(buff));
|
||||||
|
|
||||||
|
dput(rq->request, "PROXY_PATH", strdup(path + matches[4].rm_so));
|
||||||
|
dput(rq->request, "PROXY_QUERY", strdup(query));
|
||||||
|
|
||||||
|
task->handle = proxify;
|
||||||
|
antd_task_bind_event(task, rq->client->sock, 0, TASK_EVT_ON_READABLE | TASK_EVT_ON_WRITABLE);
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode the cookie header to a dictionary
|
||||||
|
* @param client The client socket
|
||||||
|
* @return The Dictionary socket or NULL
|
||||||
|
*/
|
||||||
|
static void decode_cookie(const char *line, dictionary_t dic)
|
||||||
|
{
|
||||||
|
char *token, *token1;
|
||||||
|
char *cpstr = strdup(line);
|
||||||
|
char *orgcpy = cpstr;
|
||||||
|
trim(cpstr, ' ');
|
||||||
|
trim(cpstr, '\n');
|
||||||
|
trim(cpstr, '\r');
|
||||||
|
|
||||||
|
while ((token = strsep(&cpstr, ";")))
|
||||||
|
{
|
||||||
|
trim(token, ' ');
|
||||||
|
token1 = strsep(&token, "=");
|
||||||
|
if (token1 && token && strlen(token) > 0)
|
||||||
|
{
|
||||||
|
dput(dic, token1, strdup(token));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(orgcpy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode a query string (GET request or POST URL encoded) to
|
||||||
|
* a dictionary of key-value
|
||||||
|
* @param query : the query string
|
||||||
|
* @return a dictionary of key-value
|
||||||
|
*/
|
||||||
|
static void decode_url_request(const char *query, dictionary_t dic)
|
||||||
|
{
|
||||||
|
if (query == NULL)
|
||||||
|
return;
|
||||||
|
// str_copy = ;
|
||||||
|
char *token;
|
||||||
|
if (strlen(query) == 0)
|
||||||
|
return;
|
||||||
|
char *str_copy = strdup(query);
|
||||||
|
char *org_copy = str_copy;
|
||||||
|
// dictionary dic = dict();
|
||||||
|
while ((token = strsep(&str_copy, "&")))
|
||||||
|
{
|
||||||
|
char *key;
|
||||||
|
char *val = NULL;
|
||||||
|
if (strlen(token) > 0)
|
||||||
|
{
|
||||||
|
key = strsep(&token, "=");
|
||||||
|
if (key && strlen(key) > 0)
|
||||||
|
{
|
||||||
|
val = strsep(&token, "=");
|
||||||
|
if (!val)
|
||||||
|
val = "";
|
||||||
|
dput(dic, key, url_decode(val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(org_copy);
|
||||||
|
// return dic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode the HTTP request header
|
||||||
|
*/
|
||||||
|
|
||||||
|
void *decode_request_header(void *data)
|
||||||
|
{
|
||||||
|
antd_request_t *rq = (antd_request_t *)data;
|
||||||
|
rq->client->state = ANTD_CLIENT_HEADER_DECODE;
|
||||||
|
dictionary_t cookie = NULL;
|
||||||
|
char *line;
|
||||||
|
char *token;
|
||||||
|
char *query = NULL;
|
||||||
|
char *host = NULL;
|
||||||
|
char buf[2 * BUFFLEN];
|
||||||
|
int header_size = 0;
|
||||||
|
int ret;
|
||||||
|
char *url = (char *)dvalue(rq->request, "REQUEST_QUERY");
|
||||||
|
dictionary_t xheader = dvalue(rq->request, "REQUEST_HEADER");
|
||||||
|
dictionary_t request = dvalue(rq->request, "REQUEST_DATA");
|
||||||
|
char *port_s = (char *)dvalue(rq->request, "SERVER_PORT");
|
||||||
|
port_config_t *pcnf = (port_config_t *)dvalue(g_server_config.ports, port_s);
|
||||||
|
antd_task_t *task;
|
||||||
|
// first real all header
|
||||||
|
// this for check if web socket is enabled
|
||||||
|
|
||||||
|
while (((ret = read_buf(rq->client, buf, sizeof(buf))) > 0) && strcmp("\r\n", buf))
|
||||||
|
{
|
||||||
|
header_size += ret;
|
||||||
|
line = buf;
|
||||||
|
trim(line, '\n');
|
||||||
|
trim(line, '\r');
|
||||||
|
token = strsep(&line, ":");
|
||||||
|
trim(token, ' ');
|
||||||
|
trim(line, ' ');
|
||||||
|
if (token && line && strlen(line) > 0)
|
||||||
|
{
|
||||||
|
verify_header(token);
|
||||||
|
dput(xheader, token, strdup(line));
|
||||||
|
}
|
||||||
|
if (token != NULL && strcasecmp(token, "Cookie") == 0)
|
||||||
|
{
|
||||||
|
if (!cookie)
|
||||||
|
{
|
||||||
|
cookie = dict();
|
||||||
|
}
|
||||||
|
decode_cookie(line, cookie);
|
||||||
|
}
|
||||||
|
else if (token != NULL && strcasecmp(token, "Host") == 0)
|
||||||
|
{
|
||||||
|
host = strdup(line);
|
||||||
|
}
|
||||||
|
if (header_size > HEADER_MAX_SIZE)
|
||||||
|
{
|
||||||
|
antd_error(rq->client, 413, "Payload Too Large");
|
||||||
|
ERROR("Header size too large (%d): %d vs %d", rq->client->sock, header_size, HEADER_MAX_SIZE);
|
||||||
|
task = antd_create_task(NULL, (void *)rq, NULL, rq->client->last_io);
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
// antd_task_bind_event(task, rq->client->sock, 0, TASK_EVT_ON_WRITABLE | TASK_EVT_ON_READABLE);
|
||||||
|
task = antd_create_task(decode_request_header, (void *)rq, NULL, rq->client->last_io);
|
||||||
|
antd_task_bind_event(task, rq->client->sock, 0, TASK_EVT_ON_READABLE);
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
// check for content length size
|
||||||
|
line = (char *)dvalue(xheader, "Content-Length");
|
||||||
|
if (line)
|
||||||
|
{
|
||||||
|
int clen = atoi(line);
|
||||||
|
if (clen > g_server_config.max_upload_size)
|
||||||
|
{
|
||||||
|
antd_error(rq->client, 413, "Request body data is too large");
|
||||||
|
// dirty fix, wait for message to be sent
|
||||||
|
// 100 ms sleep
|
||||||
|
usleep(100000);
|
||||||
|
task = antd_create_task(NULL, (void *)rq, NULL, rq->client->last_io);
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_ZLIB
|
||||||
|
// check for gzip
|
||||||
|
line = (char *)dvalue(xheader, "Accept-Encoding");
|
||||||
|
if (line)
|
||||||
|
{
|
||||||
|
if (regex_match("gzip", line, 0, NULL))
|
||||||
|
{
|
||||||
|
rq->client->z_level = ANTD_CGZ;
|
||||||
|
}
|
||||||
|
else if (regex_match("deflate", line, 0, NULL))
|
||||||
|
{
|
||||||
|
rq->client->z_level = ANTD_CDEFL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rq->client->z_level = ANTD_CNONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rq->client->z_level = ANTD_CNONE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// if(line) free(line);
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
strncat(buf, url, sizeof(buf) - 1);
|
||||||
|
LOG("Original query (%d): %s", rq->client->sock, url);
|
||||||
|
query = apply_rules(pcnf->rules, host, buf);
|
||||||
|
LOG("Processed query: %s", query);
|
||||||
|
if (cookie)
|
||||||
|
dput(rq->request, "COOKIE", cookie);
|
||||||
|
if (host)
|
||||||
|
free(host);
|
||||||
|
|
||||||
|
// check if this is a reverse proxy ?
|
||||||
|
task = check_proxy(rq, buf, query);
|
||||||
|
if (task)
|
||||||
|
{
|
||||||
|
if (query)
|
||||||
|
free(query);
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
LOG("REQUEST_URI:%s", buf);
|
||||||
|
dput(rq->request, "REQUEST_URI", url_decode(buf));
|
||||||
|
if (query)
|
||||||
|
{
|
||||||
|
decode_url_request(query, request);
|
||||||
|
dput(rq->request, "REQUEST_QUERY", query);
|
||||||
|
//if(url)
|
||||||
|
// free(url);
|
||||||
|
}
|
||||||
|
// header ok, now checkmethod
|
||||||
|
task = antd_create_task(decode_request, (void *)rq, NULL, rq->client->last_io);
|
||||||
|
antd_task_bind_event(task, rq->client->sock, 0, TASK_EVT_ON_WRITABLE | TASK_EVT_ON_READABLE); //
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode post query string to string
|
||||||
|
*/
|
||||||
|
static char *post_data_decode(void *client, int len)
|
||||||
|
{
|
||||||
|
char *query = (char *)malloc((len + 1) * sizeof(char));
|
||||||
|
char *ptr = query;
|
||||||
|
int readlen = len > BUFFLEN ? BUFFLEN : len;
|
||||||
|
int read = 0, stat = 1;
|
||||||
|
while (readlen > 0 && stat >= 0)
|
||||||
|
{
|
||||||
|
stat = antd_recv_upto(client, ptr + read, readlen);
|
||||||
|
if (stat > 0)
|
||||||
|
{
|
||||||
|
read += stat;
|
||||||
|
readlen = (len - read) > BUFFLEN ? BUFFLEN : (len - read);
|
||||||
|
}
|
||||||
|
if (stat == 0)
|
||||||
|
{
|
||||||
|
if (difftime(time(NULL), ((antd_client_t *)client)->last_io) > MAX_IO_WAIT_TIME)
|
||||||
|
{
|
||||||
|
stat = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
usleep(POLL_EVENT_TO * 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read > 0)
|
||||||
|
query[read] = '\0';
|
||||||
|
else
|
||||||
|
{
|
||||||
|
free(query);
|
||||||
|
query = NULL;
|
||||||
|
}
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *decode_multi_part_request_data(void *data)
|
||||||
|
{
|
||||||
|
// loop through each part separated by the boundary
|
||||||
|
char *line;
|
||||||
|
char *part_name = NULL;
|
||||||
|
char *part_file = NULL;
|
||||||
|
char *file_path;
|
||||||
|
char buf[BUFFLEN];
|
||||||
|
char *field;
|
||||||
|
int len;
|
||||||
|
// dictionary dic = NULL;
|
||||||
|
int fd = -1;
|
||||||
|
char *token, *keytoken, *valtoken;
|
||||||
|
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_bind_event(task, rq->client->sock, 0, TASK_EVT_ON_WRITABLE | TASK_EVT_ON_READABLE);
|
||||||
|
char *boundary = (char *)dvalue(rq->request, "MULTI_PART_BOUNDARY");
|
||||||
|
dictionary_t dic = (dictionary_t)dvalue(rq->request, "REQUEST_DATA");
|
||||||
|
// search for content disposition:
|
||||||
|
while (((len = read_buf(rq->client, buf, sizeof(buf))) > 0) && !strstr(buf, "Content-Disposition:"))
|
||||||
|
;
|
||||||
|
;
|
||||||
|
if (len <= 0 || !strstr(buf, "Content-Disposition:"))
|
||||||
|
{
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
char *boundend = __s("%s--", boundary);
|
||||||
|
line = buf;
|
||||||
|
// extract parameters from header
|
||||||
|
while ((token = strsep(&line, ";")))
|
||||||
|
{
|
||||||
|
keytoken = strsep(&token, "=");
|
||||||
|
if (keytoken && strlen(keytoken) > 0)
|
||||||
|
{
|
||||||
|
trim(keytoken, ' ');
|
||||||
|
valtoken = strsep(&token, "=");
|
||||||
|
if (valtoken)
|
||||||
|
{
|
||||||
|
trim(valtoken, ' ');
|
||||||
|
trim(valtoken, '\n');
|
||||||
|
trim(valtoken, '\r');
|
||||||
|
trim(valtoken, '\"');
|
||||||
|
if (strcmp(keytoken, "name") == 0)
|
||||||
|
{
|
||||||
|
part_name = strdup(valtoken);
|
||||||
|
}
|
||||||
|
else if (strcmp(keytoken, "filename") == 0)
|
||||||
|
{
|
||||||
|
part_file = strdup(valtoken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
line = NULL;
|
||||||
|
// get the binary data
|
||||||
|
LOG("Part file: %s part name: %s", part_file, part_name);
|
||||||
|
if (part_name != NULL)
|
||||||
|
{
|
||||||
|
// go to the beginning of data bock
|
||||||
|
while ((len = read_buf(rq->client, buf, sizeof(buf))) > 0 && strncmp(buf, "\r\n", 2) != 0)
|
||||||
|
;
|
||||||
|
;
|
||||||
|
|
||||||
|
if (part_file == NULL)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* WARNING:
|
||||||
|
* This allow only 1024 bytes of data (max),
|
||||||
|
* out of this range, the data is cut out.
|
||||||
|
* Need an efficient way to handle this
|
||||||
|
*/
|
||||||
|
len = read_buf(rq->client, buf, sizeof(buf));
|
||||||
|
if (len > 0)
|
||||||
|
{
|
||||||
|
line = buf;
|
||||||
|
trim(line, '\n');
|
||||||
|
trim(line, '\r');
|
||||||
|
trim(line, ' ');
|
||||||
|
dput(dic, part_name, strdup(line));
|
||||||
|
}
|
||||||
|
// find the next boundary
|
||||||
|
while ((len = read_buf(rq->client, buf, sizeof(buf))) > 0 && !strstr(buf, boundary))
|
||||||
|
{
|
||||||
|
line = buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
file_path = __s("%s/%s.%u", g_server_config.tmpdir, part_file, (unsigned)time(NULL));
|
||||||
|
fd = open(file_path, O_WRONLY | O_CREAT, 0600);
|
||||||
|
if (fd > 0)
|
||||||
|
{
|
||||||
|
int totalsize = 0, len = 0;
|
||||||
|
// read until the next boundary
|
||||||
|
// TODO: this is not efficient for big file
|
||||||
|
// need a solution
|
||||||
|
while ((len = read_buf(rq->client, buf, sizeof(buf))) > 0 && !strstr(buf, boundary))
|
||||||
|
{
|
||||||
|
len = guard_write(fd, buf, len);
|
||||||
|
totalsize += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove \r\n at the end
|
||||||
|
lseek(fd, 0, SEEK_SET);
|
||||||
|
// fseek(fp,-2, SEEK_CUR);
|
||||||
|
totalsize -= 2;
|
||||||
|
int stat = ftruncate(fd, totalsize);
|
||||||
|
LOG("Write %d bytes to %s", totalsize, file_path);
|
||||||
|
UNUSED(stat);
|
||||||
|
close(fd);
|
||||||
|
line = buf;
|
||||||
|
|
||||||
|
field = __s("%s.file", part_name);
|
||||||
|
dput(dic, field, strdup(part_file));
|
||||||
|
free(field);
|
||||||
|
field = __s("%s.tmp", part_name);
|
||||||
|
dput(dic, field, strdup(file_path));
|
||||||
|
free(field);
|
||||||
|
field = __s("%s.size", part_name);
|
||||||
|
dput(dic, field, __s("%d", totalsize));
|
||||||
|
free(field);
|
||||||
|
field = __s("%s.ext", part_name);
|
||||||
|
dput(dic, field, ext(part_file));
|
||||||
|
free(field);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERROR("Cannot write file to :%s", file_path);
|
||||||
|
}
|
||||||
|
free(file_path);
|
||||||
|
free(part_file);
|
||||||
|
}
|
||||||
|
free(part_name);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* The upload procedure may take time, the task access time should be updated
|
||||||
|
* after the procedure finish
|
||||||
|
*/
|
||||||
|
task->access_time = rq->client->last_io;
|
||||||
|
// check if end of request
|
||||||
|
if (line && strstr(line, boundend))
|
||||||
|
{
|
||||||
|
// LOG("End request %s", boundend);
|
||||||
|
free(boundend);
|
||||||
|
// antd_task_bind_event(task, rq->client->sock, 0, TASK_EVT_ON_WRITABLE);
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
free(boundend);
|
||||||
|
if (line && strstr(line, boundary))
|
||||||
|
{
|
||||||
|
// continue upload
|
||||||
|
// antd_task_bind_event(task, rq->client->sock, 0, TASK_EVT_ON_READABLE);
|
||||||
|
task->handle = decode_multi_part_request_data;
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
// antd_task_bind_event(task, rq->client->sock, 0, TASK_EVT_ON_WRITABLE);
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Decode the multi-part form data from the POST request
|
||||||
|
* If it is a file upload, copy the file to tmp dir
|
||||||
|
*/
|
||||||
|
static void *decode_multi_part_request(void *data, const char *ctype)
|
||||||
|
{
|
||||||
|
char *boundary;
|
||||||
|
char line[BUFFLEN];
|
||||||
|
char *str_copy = (char *)ctype;
|
||||||
|
int len;
|
||||||
|
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_bind_event(task, rq->client->sock, 0, );
|
||||||
|
antd_task_bind_event(task, rq->client->sock, 0, TASK_EVT_ON_WRITABLE | TASK_EVT_ON_READABLE);
|
||||||
|
// dictionary dic = NULL;
|
||||||
|
boundary = strsep(&str_copy, "="); // discard first part
|
||||||
|
boundary = str_copy;
|
||||||
|
if (boundary && strlen(boundary) > 0)
|
||||||
|
{
|
||||||
|
// dic = dict();
|
||||||
|
trim(boundary, ' ');
|
||||||
|
dput(rq->request, "MULTI_PART_BOUNDARY", strdup(boundary));
|
||||||
|
// find first boundary
|
||||||
|
while (((len = read_buf(rq->client, line, sizeof(line))) > 0) && !strstr(line, boundary))
|
||||||
|
;
|
||||||
|
if (len > 0)
|
||||||
|
{
|
||||||
|
task->handle = decode_multi_part_request_data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *decode_post_request(void *data)
|
||||||
|
{
|
||||||
|
antd_request_t *rq = (antd_request_t *)data;
|
||||||
|
rq->client->state = ANTD_CLIENT_RQ_DATA_DECODE;
|
||||||
|
dictionary_t request = dvalue(rq->request, "REQUEST_DATA");
|
||||||
|
dictionary_t headers = dvalue(rq->request, "REQUEST_HEADER");
|
||||||
|
char *ctype = NULL;
|
||||||
|
int clen = -1;
|
||||||
|
char *tmp;
|
||||||
|
antd_task_t *task = NULL;
|
||||||
|
ctype = (char *)dvalue(headers, "Content-Type");
|
||||||
|
tmp = (char *)dvalue(headers, "Content-Length");
|
||||||
|
if (tmp)
|
||||||
|
clen = atoi(tmp);
|
||||||
|
char *method = (char *)dvalue(rq->request, "METHOD");
|
||||||
|
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);
|
||||||
|
if (!method || (!EQU(method, "POST") && !EQU(method, "PUT") && !EQU(method, "PATCH")))
|
||||||
|
return task;
|
||||||
|
if (ctype == NULL || clen == -1)
|
||||||
|
{
|
||||||
|
antd_error(rq->client, 400, "Bad Request, missing content description");
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
// decide what to do with the data
|
||||||
|
if (strstr(ctype, FORM_URL_ENCODE))
|
||||||
|
{
|
||||||
|
char *pquery = post_data_decode(rq->client, clen);
|
||||||
|
if (pquery)
|
||||||
|
{
|
||||||
|
decode_url_request(pquery, request);
|
||||||
|
free(pquery);
|
||||||
|
}
|
||||||
|
else if (clen > 0)
|
||||||
|
{
|
||||||
|
// WARN: this may not work on ssl socket
|
||||||
|
// antd_task_bind_event(task, rq->client->sock, 0, TASK_EVT_ON_READABLE | TASK_EVT_ON_WRITABLE);
|
||||||
|
// task->handle = decode_post_request;
|
||||||
|
antd_error(rq->client, 400, "Bad Request, missing content data");
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strstr(ctype, FORM_MULTI_PART))
|
||||||
|
{
|
||||||
|
free(task);
|
||||||
|
return decode_multi_part_request(rq, ctype);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*let plugin hande this data as we dont known how to deal with it*/
|
||||||
|
dput(request, "HAS_RAW_BODY", strdup("true"));
|
||||||
|
}
|
||||||
|
antd_task_bind_event(task, rq->client->sock, 0, TASK_EVT_ON_WRITABLE);
|
||||||
|
return task;
|
||||||
|
}
|
7
decode.h
Normal file
7
decode.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#ifndef DECODE_H
|
||||||
|
#define DECODE_H
|
||||||
|
|
||||||
|
void *decode_request_header(void *data);
|
||||||
|
void *decode_post_request(void *data);
|
||||||
|
|
||||||
|
#endif
|
1827
http_server.c
1827
http_server.c
File diff suppressed because it is too large
Load Diff
@ -1,40 +0,0 @@
|
|||||||
#ifndef HTTP_SERVER
|
|
||||||
#define HTTP_SERVER
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "lib/handle.h"
|
|
||||||
|
|
||||||
#define PLUGIN_HANDLER "handle"
|
|
||||||
#define WS_MAGIC_STRING "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
|
|
||||||
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
|
|
||||||
#ifndef CONFIG_FILE
|
|
||||||
#define CONFIG_FILE "antd-config.ini"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
config_t *config();
|
|
||||||
void destroy_config();
|
|
||||||
void load_config(const char *file);
|
|
||||||
void *accept_request(void *);
|
|
||||||
void *finish_request(void *);
|
|
||||||
void cat(void *, FILE *);
|
|
||||||
void cannot_execute(void *);
|
|
||||||
//int get_line(int, char *, int);
|
|
||||||
void *serve_file(void *);
|
|
||||||
int startup(unsigned *, int);
|
|
||||||
int rule_check(const char *, const char *, const char *, const char *, const char *, char *);
|
|
||||||
void ws_confirm_request(void *, const char *);
|
|
||||||
char *post_url_decode(void *client, int len);
|
|
||||||
void decode_url_request(const char *query, dictionary_t);
|
|
||||||
void *decode_request_header(void *data);
|
|
||||||
void *decode_request(void *data);
|
|
||||||
void *decode_post_request(void *data);
|
|
||||||
void *resolve_request(void *data);
|
|
||||||
void *decode_multi_part_request(void *, const char *);
|
|
||||||
void *decode_multi_part_request_data(void *data);
|
|
||||||
void decode_cookie(const char *, dictionary_t d);
|
|
||||||
char *post_data_decode(void *, int);
|
|
||||||
void set_nonblock(int);
|
|
||||||
void *execute_plugin(void *data, const char *path);
|
|
||||||
|
|
||||||
#endif
|
|
61
httpd.c
61
httpd.c
@ -9,18 +9,21 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "http_server.h"
|
#include "server.h"
|
||||||
#include "lib/ini.h"
|
|
||||||
#include "lib/scheduler.h"
|
#include "lib/scheduler.h"
|
||||||
#include "plugin_manager.h"
|
|
||||||
#include "lib/utils.h"
|
#include "lib/utils.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "plugin_manager.h"
|
||||||
|
|
||||||
#define SEND_STAT(fd, buff, ret, ...) \
|
#define SEND_STAT(fd, buff, ret, ...) \
|
||||||
snprintf(buff, BUFFLEN, ##__VA_ARGS__); \
|
snprintf(buff, BUFFLEN, ##__VA_ARGS__); \
|
||||||
ret = write(fd, buff, strlen(buff));
|
ret = write(fd, buff, strlen(buff));
|
||||||
|
|
||||||
|
extern config_t g_server_config;
|
||||||
|
|
||||||
static antd_scheduler_t *scheduler;
|
static antd_scheduler_t *scheduler;
|
||||||
|
|
||||||
#ifdef USE_OPENSSL
|
#ifdef USE_OPENSSL
|
||||||
@ -97,8 +100,7 @@ static void configure_context(SSL_CTX *ctx)
|
|||||||
SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_SSLv2 | SSL_OP_NO_TICKET);
|
SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_SSLv2 | SSL_OP_NO_TICKET);
|
||||||
SSL_CTX_set_session_id_context(ctx, (void *)&ssl_session_ctx_id, sizeof(ssl_session_ctx_id));
|
SSL_CTX_set_session_id_context(ctx, (void *)&ssl_session_ctx_id, sizeof(ssl_session_ctx_id));
|
||||||
// set the cipher suit
|
// set the cipher suit
|
||||||
config_t *cnf = config();
|
const char *suit = g_server_config.ssl_cipher ? g_server_config.ssl_cipher : CIPHER_SUIT;
|
||||||
const char *suit = cnf->ssl_cipher ? cnf->ssl_cipher : CIPHER_SUIT;
|
|
||||||
LOG("Cirpher suit used: %s", suit);
|
LOG("Cirpher suit used: %s", suit);
|
||||||
if (SSL_CTX_set_cipher_list(ctx, suit) != 1)
|
if (SSL_CTX_set_cipher_list(ctx, suit) != 1)
|
||||||
{
|
{
|
||||||
@ -109,16 +111,16 @@ static void configure_context(SSL_CTX *ctx)
|
|||||||
/* Set the key and cert */
|
/* Set the key and cert */
|
||||||
/* use the full chain bundle of certificate */
|
/* use the full chain bundle of certificate */
|
||||||
// if (SSL_CTX_use_certificate_file(ctx, server_config->sslcert, SSL_FILETYPE_PEM) <= 0) {
|
// if (SSL_CTX_use_certificate_file(ctx, server_config->sslcert, SSL_FILETYPE_PEM) <= 0) {
|
||||||
if (SSL_CTX_use_certificate_chain_file(ctx, cnf->sslcert) <= 0)
|
if (SSL_CTX_use_certificate_chain_file(ctx, g_server_config.sslcert) <= 0)
|
||||||
{
|
{
|
||||||
ERROR("Fail to read SSL certificate chain file: %s", cnf->sslcert);
|
ERROR("Fail to read SSL certificate chain file: %s", g_server_config.sslcert);
|
||||||
ERR_print_errors_fp(stderr);
|
ERR_print_errors_fp(stderr);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SSL_CTX_use_PrivateKey_file(ctx, cnf->sslkey, SSL_FILETYPE_PEM) <= 0)
|
if (SSL_CTX_use_PrivateKey_file(ctx, g_server_config.sslkey, SSL_FILETYPE_PEM) <= 0)
|
||||||
{
|
{
|
||||||
ERROR("Fail to read SSL private file: %s", cnf->sslkey);
|
ERROR("Fail to read SSL private file: %s", g_server_config.sslkey);
|
||||||
ERR_print_errors_fp(stderr);
|
ERR_print_errors_fp(stderr);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
@ -169,10 +171,9 @@ static void antd_monitor(port_config_t *pcnf, int sock)
|
|||||||
{
|
{
|
||||||
antd_task_t *task = NULL;
|
antd_task_t *task = NULL;
|
||||||
int client_sock = -1;
|
int client_sock = -1;
|
||||||
struct sockaddr_in client_name;
|
antd_sockaddr_t client_name;
|
||||||
socklen_t client_name_len = sizeof(client_name);
|
socklen_t client_name_len = sizeof(client_name);
|
||||||
char *client_ip = NULL;
|
char client_ip[INET6_ADDRSTRLEN] = {0};
|
||||||
config_t *conf = config();
|
|
||||||
if (sock > 0)
|
if (sock > 0)
|
||||||
{
|
{
|
||||||
client_sock = accept(sock, (struct sockaddr *)&client_name, &client_name_len);
|
client_sock = accept(sock, (struct sockaddr *)&client_name, &client_name_len);
|
||||||
@ -194,9 +195,16 @@ static void antd_monitor(port_config_t *pcnf, int sock)
|
|||||||
/*
|
/*
|
||||||
get the remote IP
|
get the remote IP
|
||||||
*/
|
*/
|
||||||
if (client_name.sin_family == AF_INET)
|
if ( pcnf->type == ANTD_PROTO_IP_4 && client_name.addr4.sin_family == AF_INET)
|
||||||
|
{
|
||||||
|
inet_ntop(AF_INET,&client_name.addr4,client_ip,INET6_ADDRSTRLEN);
|
||||||
|
}
|
||||||
|
else if(client_name.addr6.sin6_family == AF_INET6)
|
||||||
|
{
|
||||||
|
inet_ntop(AF_INET6,&client_name.addr6,client_ip,INET6_ADDRSTRLEN);
|
||||||
|
}
|
||||||
|
if(client_ip[0] != '\0')
|
||||||
{
|
{
|
||||||
client_ip = inet_ntoa(client_name.sin_addr);
|
|
||||||
LOG("Connect to client IP: %s on port:%d (%d)", client_ip, pcnf->port, client_sock);
|
LOG("Connect to client IP: %s on port:%d (%d)", client_ip, pcnf->port, client_sock);
|
||||||
// ip address
|
// ip address
|
||||||
dput(request->request, "REMOTE_ADDR", (void *)strdup(client_ip));
|
dput(request->request, "REMOTE_ADDR", (void *)strdup(client_ip));
|
||||||
@ -236,7 +244,7 @@ static void antd_monitor(port_config_t *pcnf, int sock)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
antd_scheduler_lock(scheduler);
|
antd_scheduler_lock(scheduler);
|
||||||
conf->connection++;
|
g_server_config.connection++;
|
||||||
antd_scheduler_unlock(scheduler);
|
antd_scheduler_unlock(scheduler);
|
||||||
// create callback for the server
|
// create callback for the server
|
||||||
task = antd_create_task(accept_request, (void *)request, finish_request, client->last_io);
|
task = antd_create_task(accept_request, (void *)request, finish_request, client->last_io);
|
||||||
@ -307,8 +315,7 @@ void antd_scheduler_destroy_data(void *data)
|
|||||||
|
|
||||||
int antd_scheduler_validate_data(antd_task_t *task)
|
int antd_scheduler_validate_data(antd_task_t *task)
|
||||||
{
|
{
|
||||||
config_t *conf = config();
|
return !(difftime(time(NULL), task->access_time) > g_server_config.scheduler_timeout);
|
||||||
return !(difftime(time(NULL), task->access_time) > conf->scheduler_timeout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int antd_task_data_id(void *data)
|
int antd_task_data_id(void *data)
|
||||||
@ -344,10 +351,8 @@ int main(int argc, char *argv[])
|
|||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
signal(SIGABRT, SIG_IGN);
|
signal(SIGABRT, SIG_IGN);
|
||||||
signal(SIGINT, stop_serve);
|
signal(SIGINT, stop_serve);
|
||||||
|
|
||||||
config_t *conf = config();
|
|
||||||
// start syslog
|
// start syslog
|
||||||
if (conf->debug_enable == 1)
|
if (g_server_config.debug_enable == 1)
|
||||||
{
|
{
|
||||||
setlogmask(LOG_UPTO(LOG_NOTICE));
|
setlogmask(LOG_UPTO(LOG_NOTICE));
|
||||||
}
|
}
|
||||||
@ -358,7 +363,7 @@ int main(int argc, char *argv[])
|
|||||||
openlog(SERVER_NAME, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_DAEMON);
|
openlog(SERVER_NAME, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_DAEMON);
|
||||||
|
|
||||||
#ifdef USE_OPENSSL
|
#ifdef USE_OPENSSL
|
||||||
if (conf->enable_ssl == 1)
|
if (g_server_config.enable_ssl == 1)
|
||||||
{
|
{
|
||||||
init_openssl();
|
init_openssl();
|
||||||
ctx = create_context();
|
ctx = create_context();
|
||||||
@ -369,7 +374,7 @@ int main(int argc, char *argv[])
|
|||||||
#endif
|
#endif
|
||||||
// enable scheduler
|
// enable scheduler
|
||||||
// default to 4 workers
|
// default to 4 workers
|
||||||
scheduler = antd_scheduler_init(conf->n_workers, conf->stat_fifo_path);
|
scheduler = antd_scheduler_init(g_server_config.n_workers, g_server_config.stat_fifo_path);
|
||||||
if (scheduler == NULL)
|
if (scheduler == NULL)
|
||||||
{
|
{
|
||||||
ERROR("Unable to initialise scheduler. Exit");
|
ERROR("Unable to initialise scheduler. Exit");
|
||||||
@ -377,18 +382,18 @@ int main(int argc, char *argv[])
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
FD_ZERO(&master_set);
|
FD_ZERO(&master_set);
|
||||||
for_each_assoc(it, conf->ports)
|
for_each_assoc(it, g_server_config.ports)
|
||||||
{
|
{
|
||||||
pcnf = (port_config_t *)it->value;
|
pcnf = (port_config_t *)it->value;
|
||||||
if (pcnf)
|
if (pcnf)
|
||||||
{
|
{
|
||||||
if(pcnf->type == ANTD_PROTO_IP_4)
|
if(pcnf->type == ANTD_PROTO_IP_4)
|
||||||
{
|
{
|
||||||
pcnf->sock = startup(&pcnf->port,0);
|
pcnf->sock = antd_listen(&pcnf->port,0,g_server_config.backlog);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pcnf->sock = startup(&pcnf->port,1);
|
pcnf->sock = antd_listen(&pcnf->port,1,g_server_config.backlog);
|
||||||
}
|
}
|
||||||
if (pcnf->sock > 0)
|
if (pcnf->sock > 0)
|
||||||
{
|
{
|
||||||
@ -424,9 +429,9 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
while (antd_scheduler_ok(scheduler))
|
while (antd_scheduler_ok(scheduler))
|
||||||
{
|
{
|
||||||
if (conf->connection > conf->maxcon)
|
if (g_server_config.connection > g_server_config.maxcon)
|
||||||
{
|
{
|
||||||
// ERROR("Reach max connection %d", conf->connection);
|
// ERROR("Reach max connection %d", g_server_config.connection);
|
||||||
timeout.tv_sec = 0;
|
timeout.tv_sec = 0;
|
||||||
timeout.tv_usec = 10000; // 5 ms
|
timeout.tv_usec = 10000; // 5 ms
|
||||||
select(0, NULL, NULL, NULL, &timeout);
|
select(0, NULL, NULL, NULL, &timeout);
|
||||||
@ -445,7 +450,7 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for_each_assoc(it, conf->ports)
|
for_each_assoc(it, g_server_config.ports)
|
||||||
{
|
{
|
||||||
pcnf = (port_config_t *)it->value;
|
pcnf = (port_config_t *)it->value;
|
||||||
if (pcnf && pcnf->sock > 0 && FD_ISSET(pcnf->sock, &working_set))
|
if (pcnf && pcnf->sock > 0 && FD_ISSET(pcnf->sock, &working_set))
|
||||||
|
264
lib/dbhelper.c
264
lib/dbhelper.c
@ -1,264 +0,0 @@
|
|||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "dbhelper.h"
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
sqlite3 * database(const char* file)
|
|
||||||
{
|
|
||||||
sqlite3* db;
|
|
||||||
int rc = sqlite3_open(file,&db);
|
|
||||||
if (rc != SQLITE_OK) {
|
|
||||||
ERROR( "Cannot open database: %s %s",file, sqlite3_errmsg(db));
|
|
||||||
sqlite3_close(db);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return db;
|
|
||||||
}
|
|
||||||
void dbclose(sqlite3* db)
|
|
||||||
{
|
|
||||||
sqlite3_close(db);
|
|
||||||
}
|
|
||||||
int dbquery(sqlite3* db,const char* sql, int (*call_back)())
|
|
||||||
{
|
|
||||||
char *err_msg = 0;
|
|
||||||
sqlite3_mutex_enter(sqlite3_db_mutex(db));
|
|
||||||
int rc = sqlite3_exec(db,sql,call_back,0,&err_msg);
|
|
||||||
sqlite3_mutex_leave(sqlite3_db_mutex(db));
|
|
||||||
if(rc != SQLITE_OK)
|
|
||||||
{
|
|
||||||
ERROR("Cannot query : '%s' [%s]", sql,err_msg);
|
|
||||||
sqlite3_free(err_msg);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
dbfield __field()
|
|
||||||
{
|
|
||||||
dbfield ret = malloc(sizeof *ret);
|
|
||||||
ret->name = NULL;
|
|
||||||
ret->value = NULL;
|
|
||||||
ret->next = NULL;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
dbrecord __record()
|
|
||||||
{
|
|
||||||
dbrecord ret = malloc(sizeof *ret);
|
|
||||||
ret->fields = NULL;
|
|
||||||
ret->idx = 0;
|
|
||||||
ret->next = NULL;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* __name_list(const dbfield f)
|
|
||||||
{
|
|
||||||
char* sql = f->name;
|
|
||||||
for(dbfield p=f->next;p!=NULL;p=p->next)
|
|
||||||
{
|
|
||||||
sql = __s("%s,%s",sql,p->name);
|
|
||||||
}
|
|
||||||
return sql;
|
|
||||||
}
|
|
||||||
char* __value_list(const dbfield f)
|
|
||||||
{
|
|
||||||
char* sql = __s("'%s'",f->value);
|
|
||||||
for(dbfield p=f->next;p!=NULL;p=p->next)
|
|
||||||
{
|
|
||||||
sql = __s("%s,'%s'",sql,p->value);
|
|
||||||
}
|
|
||||||
return sql;
|
|
||||||
}
|
|
||||||
char* __name_value_list(const dbfield f)
|
|
||||||
{
|
|
||||||
char* sql = __s("%s='%s'", f->name,f->value);
|
|
||||||
for(dbfield p=f->next;p!=NULL;p=p->next)
|
|
||||||
{
|
|
||||||
sql = __s("%s,%s='%s'",sql, p->name,f->value);
|
|
||||||
}
|
|
||||||
return sql;
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_record(dbrecord* r,dbfield f)
|
|
||||||
{
|
|
||||||
dbrecord new_r = malloc(sizeof *new_r);
|
|
||||||
new_r->fields = f;
|
|
||||||
new_r->idx = 1;
|
|
||||||
new_r->next = NULL;
|
|
||||||
if((*r)->idx == 0)
|
|
||||||
{
|
|
||||||
freerecord(&(*r));
|
|
||||||
*r = new_r;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dbrecord* temp;
|
|
||||||
for(temp = r;(*temp)->next!=NULL;temp=&((*temp)->next))
|
|
||||||
{
|
|
||||||
(*temp)->idx++;
|
|
||||||
}
|
|
||||||
(*temp)->next = new_r;
|
|
||||||
}
|
|
||||||
//new_r->next = *r;
|
|
||||||
//*r = new_r;
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_field(dbfield* field,const char* name, const char* value)
|
|
||||||
{
|
|
||||||
dbfield new_field = malloc(sizeof *new_field);
|
|
||||||
new_field->name = strdup(name);
|
|
||||||
new_field->value = strdup(value);
|
|
||||||
new_field->next = *field;
|
|
||||||
*field = new_field;
|
|
||||||
}
|
|
||||||
char* value_of(const dbfield f,const char* key)
|
|
||||||
{
|
|
||||||
for(dbfield t = f; t != NULL; t=t->next)
|
|
||||||
if(strcmp(t->name,key)==0)
|
|
||||||
return t->value;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
int dbinsert(sqlite3* db,const char* table, const dbfield fields)
|
|
||||||
{
|
|
||||||
char* sqlprefix = "INSERT INTO %s (%s) VALUES (%s)";
|
|
||||||
char* name_list = __name_list(fields);
|
|
||||||
char* value_list = __value_list(fields);
|
|
||||||
char* sql = __s(sqlprefix,table,name_list,value_list);
|
|
||||||
int ret = dbquery(db,sql,NULL);
|
|
||||||
free(name_list);
|
|
||||||
free(value_list);
|
|
||||||
free(sql);
|
|
||||||
|
|
||||||
if(ret == 0)
|
|
||||||
return -1;
|
|
||||||
return sqlite3_last_insert_rowid(db);
|
|
||||||
}
|
|
||||||
dbrecord dball(sqlite3* db,const char* table)
|
|
||||||
{
|
|
||||||
return dbselect(db,table,"1=%s","1");
|
|
||||||
}
|
|
||||||
dbrecord dbselect(sqlite3* db, const char* table, const char* fname,const char* fstring,...)
|
|
||||||
{
|
|
||||||
char* sql;
|
|
||||||
char* prefix = "SELECT %s FROM %s WHERE %s";
|
|
||||||
char* cond;
|
|
||||||
va_list arguments;
|
|
||||||
int dlen;
|
|
||||||
sqlite3_stmt *statement;
|
|
||||||
dbrecord records = __record();
|
|
||||||
|
|
||||||
va_start( arguments, fstring);
|
|
||||||
dlen = vsnprintf(0,0,fstring,arguments) + 1;
|
|
||||||
va_end(arguments);
|
|
||||||
cond = (char*) malloc(dlen*sizeof(char));
|
|
||||||
va_start(arguments, fstring);
|
|
||||||
vsnprintf(cond, dlen, fstring, arguments);
|
|
||||||
va_end(arguments);
|
|
||||||
sql = __s(prefix, fname,table,cond);
|
|
||||||
|
|
||||||
if(sqlite3_prepare_v2(db, sql, -1, &statement, 0) == SQLITE_OK)
|
|
||||||
{
|
|
||||||
int cols = sqlite3_column_count(statement);
|
|
||||||
int result = 0;
|
|
||||||
while((result = sqlite3_step(statement)) == SQLITE_ROW)
|
|
||||||
{
|
|
||||||
dbfield fields = __field();
|
|
||||||
for(int col = 0; col < cols; col++)
|
|
||||||
{
|
|
||||||
const char *value = (const char*)sqlite3_column_text(statement, col);
|
|
||||||
const char *name = sqlite3_column_name(statement, col);
|
|
||||||
add_field(&fields,name,(value!=0)?value:"");
|
|
||||||
}
|
|
||||||
add_record(&records,fields);
|
|
||||||
}
|
|
||||||
sqlite3_finalize(statement);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG("Can not select:%s [%s]\n",sql,sqlite3_errmsg(db));
|
|
||||||
}
|
|
||||||
|
|
||||||
free(cond);
|
|
||||||
free(sql);
|
|
||||||
return records;
|
|
||||||
}
|
|
||||||
int hastable(sqlite3* db,const char* table)
|
|
||||||
{
|
|
||||||
//char * prefix = __s("type='table' and name='%s'",table);
|
|
||||||
dbrecord rc = dbselect(db,"sqlite_master","*","type='table' and name='%s'", table);
|
|
||||||
//free(prefix);
|
|
||||||
if(!rc) return 0;
|
|
||||||
if(!rc->fields)
|
|
||||||
{
|
|
||||||
freerecord(&rc);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
freerecord(&rc);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
int dbupdate(sqlite3* db,const char* table,const dbfield field,const char* fstring,...)
|
|
||||||
{
|
|
||||||
char* sql;
|
|
||||||
char* prefix = "UPDATE %s SET %s WHERE (%s)";
|
|
||||||
char* cond;
|
|
||||||
char* list;
|
|
||||||
va_list arguments;
|
|
||||||
int dlen;
|
|
||||||
va_start( arguments, fstring);
|
|
||||||
dlen = vsnprintf(0,0,fstring,arguments) + 1;
|
|
||||||
va_end(arguments);
|
|
||||||
cond = (char*) malloc(dlen*sizeof(char));
|
|
||||||
va_start(arguments, fstring);
|
|
||||||
vsnprintf(cond, dlen, fstring, arguments);
|
|
||||||
va_end(arguments);
|
|
||||||
|
|
||||||
list = __name_value_list(field);
|
|
||||||
sql = __s(prefix,table,list,cond);
|
|
||||||
int ret = dbquery(db,sql,NULL);
|
|
||||||
free(cond);
|
|
||||||
free(list);
|
|
||||||
free(sql);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int dbdelete(sqlite3* db,const char* table,const char* fstring,...)
|
|
||||||
{
|
|
||||||
char* sql;
|
|
||||||
char* prefix = "DELETE FROM %s WHERE (%s)";
|
|
||||||
char* cond;
|
|
||||||
va_list arguments;
|
|
||||||
int dlen;
|
|
||||||
va_start( arguments, fstring);
|
|
||||||
dlen = vsnprintf(0,0,fstring,arguments) + 1;
|
|
||||||
va_end(arguments);
|
|
||||||
cond = (char*) malloc(dlen*sizeof(char));
|
|
||||||
va_start(arguments, fstring);
|
|
||||||
vsnprintf(cond, dlen, fstring, arguments);
|
|
||||||
va_end(arguments);
|
|
||||||
sql = __s(prefix,table,cond);
|
|
||||||
int ret = dbquery(db,sql,NULL);
|
|
||||||
free(cond);
|
|
||||||
free(sql);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void freerecord(dbrecord * r)
|
|
||||||
{
|
|
||||||
dbrecord curr;
|
|
||||||
while ((curr = (*r)) != NULL) {
|
|
||||||
(*r) = (*r)->next;
|
|
||||||
if(curr->fields)
|
|
||||||
freefield(&(curr->fields));
|
|
||||||
free (curr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void freefield(dbfield *f)
|
|
||||||
{
|
|
||||||
dbfield curr;
|
|
||||||
while( (curr = (*f)) != NULL )
|
|
||||||
{
|
|
||||||
(*f) = (*f)->next;
|
|
||||||
if(curr->name) free(curr->name);
|
|
||||||
if(curr->value) free(curr->value);
|
|
||||||
free(curr);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
#ifndef DB_HELPER
|
|
||||||
#define DB_HELPER
|
|
||||||
#include <sqlite3.h>
|
|
||||||
|
|
||||||
sqlite3 * database(const char*);
|
|
||||||
typedef struct _dbfield
|
|
||||||
{
|
|
||||||
char* name;
|
|
||||||
char* value;
|
|
||||||
struct _dbfield* next;
|
|
||||||
} *dbfield ;
|
|
||||||
|
|
||||||
typedef struct _dbrecord
|
|
||||||
{
|
|
||||||
dbfield fields;
|
|
||||||
int idx;
|
|
||||||
struct _dbrecord* next;
|
|
||||||
} * dbrecord;
|
|
||||||
|
|
||||||
int dbquery(sqlite3*,const char*, int (*)());
|
|
||||||
int dbinsert(sqlite3*,const char*,const dbfield);
|
|
||||||
int hastable(sqlite3*,const char*);
|
|
||||||
int dbupdate(sqlite3*,const char*,const dbfield,const char*,...);
|
|
||||||
dbrecord dbselect(sqlite3*, const char*, const char*,const char*,...);
|
|
||||||
dbrecord dball(sqlite3*,const char*);
|
|
||||||
int dbdelete(sqlite3*,const char*,const char*,...);
|
|
||||||
dbfield __field();
|
|
||||||
dbrecord __record();
|
|
||||||
char* __name_list(const dbfield);
|
|
||||||
char* __value_list(const dbfield);
|
|
||||||
char* __name_value_list(const dbfield);
|
|
||||||
char* value_of(const dbfield,const char*);
|
|
||||||
void add_field(dbfield*,const char*, const char*);
|
|
||||||
void add_record(dbrecord*,dbfield);
|
|
||||||
void dbclose(sqlite3*);
|
|
||||||
void freerecord(dbrecord *);
|
|
||||||
void freefield(dbfield *);
|
|
||||||
#endif
|
|
47
lib/handle.h
47
lib/handle.h
@ -40,25 +40,13 @@ typedef enum
|
|||||||
ANTD_CNONE
|
ANTD_CNONE
|
||||||
} antd_compress_t;
|
} antd_compress_t;
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ANTD_PROTO_IP_4,
|
ANTD_PROTO_IP_4,
|
||||||
ANTD_PROTO_IP_6,
|
ANTD_PROTO_IP_6,
|
||||||
ANTD_PROTO_ALL
|
ANTD_PROTO_ALL
|
||||||
} antd_proto_t;
|
} antd_proto_t;
|
||||||
|
|
||||||
//extern config_t server_config;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
unsigned int port;
|
|
||||||
int usessl;
|
|
||||||
char *htdocs;
|
|
||||||
char* plugins;
|
|
||||||
int sock;
|
|
||||||
antd_proto_t type;
|
|
||||||
dictionary_t rules;
|
|
||||||
} port_config_t;
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
int sock;
|
int sock;
|
||||||
@ -85,36 +73,6 @@ typedef struct
|
|||||||
|
|
||||||
} antd_response_header_t;
|
} antd_response_header_t;
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
//int port;
|
|
||||||
char *plugins_dir;
|
|
||||||
char *plugins_ext;
|
|
||||||
char *db_path;
|
|
||||||
//char* htdocs;
|
|
||||||
char *tmpdir;
|
|
||||||
char *stat_fifo_path;
|
|
||||||
dictionary_t handlers;
|
|
||||||
int backlog;
|
|
||||||
int maxcon;
|
|
||||||
int connection;
|
|
||||||
int n_workers;
|
|
||||||
int scheduler_timeout;
|
|
||||||
int max_upload_size;
|
|
||||||
// ssl
|
|
||||||
int enable_ssl;
|
|
||||||
char *sslcert;
|
|
||||||
char *sslkey;
|
|
||||||
char *ssl_cipher;
|
|
||||||
int gzip_enable;
|
|
||||||
int debug_enable;
|
|
||||||
list_t gzip_types;
|
|
||||||
dictionary_t mimes;
|
|
||||||
dictionary_t ports;
|
|
||||||
dictionary_t plugins;
|
|
||||||
// #endif
|
|
||||||
} config_t;
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
char name[MAX_PATH_LEN];
|
char name[MAX_PATH_LEN];
|
||||||
@ -124,10 +82,9 @@ typedef struct
|
|||||||
dictionary_t config;
|
dictionary_t config;
|
||||||
int raw_body;
|
int raw_body;
|
||||||
int status;
|
int status;
|
||||||
|
void *instance_data;
|
||||||
} plugin_header_t;
|
} plugin_header_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void set_nonblock(int socket);
|
void set_nonblock(int socket);
|
||||||
//void set_block(int socket);
|
//void set_block(int socket);
|
||||||
|
|
||||||
|
29
lib/plugin.h
29
lib/plugin.h
@ -6,19 +6,8 @@
|
|||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "handle.h"
|
#include "handle.h"
|
||||||
#include "dbhelper.h"
|
|
||||||
|
|
||||||
|
|
||||||
//typedef void(*call)();
|
|
||||||
#ifdef USE_DB
|
|
||||||
typedef sqlite3* sqldb;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef USE_DB
|
|
||||||
sqldb getdb();
|
|
||||||
sqldb __getdb(char *name);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
char* config_dir();
|
char* config_dir();
|
||||||
/*Default function for plugin*/
|
/*Default function for plugin*/
|
||||||
@ -49,24 +38,6 @@ void use_raw_body()
|
|||||||
{
|
{
|
||||||
__plugin__.raw_body = 1;
|
__plugin__.raw_body = 1;
|
||||||
}
|
}
|
||||||
#ifdef USE_DB
|
|
||||||
sqldb __getdb(char *name)
|
|
||||||
{
|
|
||||||
int plen = strlen(name)+strlen(__plugin__.dbpath)+4;
|
|
||||||
char* path = (char*) malloc(plen*sizeof(char));
|
|
||||||
strcpy(path,__plugin__.dbpath);
|
|
||||||
strcat(path,name);
|
|
||||||
strcat(path,".db");
|
|
||||||
//LOG("database: %s\n", path);
|
|
||||||
sqldb ret = (sqldb)database(path);
|
|
||||||
free(path);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
sqldb getdb()
|
|
||||||
{
|
|
||||||
return __getdb(__plugin__.name);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
plugin_header_t* meta()
|
plugin_header_t* meta()
|
||||||
{
|
{
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <semaphore.h>
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "bst.h"
|
#include "bst.h"
|
||||||
|
@ -77,6 +77,8 @@ A million repetitions of "a"
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* #define SHA1HANDSOFF */
|
/* #define SHA1HANDSOFF */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include "sha1.h"
|
#include "sha1.h"
|
||||||
|
|
||||||
void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
|
void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
|
||||||
|
@ -3,8 +3,6 @@
|
|||||||
|
|
||||||
#ifndef __SHA1_H
|
#ifndef __SHA1_H
|
||||||
#define __SHA1_H
|
#define __SHA1_H
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
407
lib/utils.c
407
lib/utils.c
@ -43,64 +43,64 @@ THE SOFTWARE.
|
|||||||
#include "sha1.h"
|
#include "sha1.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#include "dictionary.h"
|
#include "dictionary.h"
|
||||||
// #include <time.h>
|
// #include <time.h>
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trim a string by a character on both ends
|
* Trim a string by a character on both ends
|
||||||
* @param str The target string
|
* @param str The target string
|
||||||
* @param delim the delim
|
* @param delim the delim
|
||||||
*/
|
*/
|
||||||
void trim(char* str, const char delim)
|
void trim(char *str, const char delim)
|
||||||
{
|
{
|
||||||
if(!str || strlen(str) == 0) return;
|
if (!str || strlen(str) == 0)
|
||||||
char * p = str;
|
return;
|
||||||
|
char *p = str;
|
||||||
int l = strlen(p);
|
int l = strlen(p);
|
||||||
while(l > 0 && p[l - 1] == delim)
|
while (l > 0 && p[l - 1] == delim)
|
||||||
p[--l] = 0;
|
p[--l] = 0;
|
||||||
while(* p && (* p) == delim ) ++p, --l;
|
while (*p && (*p) == delim)
|
||||||
|
++p, --l;
|
||||||
memmove(str, p, l + 1);
|
memmove(str, p, l + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeAll(const char* path,int mode)
|
void removeAll(const char *path, int mode)
|
||||||
{
|
{
|
||||||
DIR *d;
|
DIR *d;
|
||||||
struct dirent *dir;
|
struct dirent *dir;
|
||||||
char* file;
|
char *file;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if( stat(path, &st) == 0)
|
if (stat(path, &st) == 0)
|
||||||
{
|
{
|
||||||
if(S_ISDIR(st.st_mode))
|
if (S_ISDIR(st.st_mode))
|
||||||
{
|
{
|
||||||
d = opendir(path);
|
d = opendir(path);
|
||||||
if(d)
|
if (d)
|
||||||
{
|
{
|
||||||
while ((dir = readdir(d)) != NULL)
|
while ((dir = readdir(d)) != NULL)
|
||||||
{
|
{
|
||||||
if(strcmp(dir->d_name,".") == 0 || strcmp(dir->d_name,"..")==0) continue;
|
if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0)
|
||||||
file = __s("%s/%s",path,dir->d_name);
|
continue;
|
||||||
|
file = __s("%s/%s", path, dir->d_name);
|
||||||
|
|
||||||
removeAll(file,1);
|
removeAll(file, 1);
|
||||||
free(file);
|
free(file);
|
||||||
}
|
}
|
||||||
closedir(d);
|
closedir(d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(mode)
|
if (mode)
|
||||||
remove(path);
|
remove(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WARNING:
|
// WARNING:
|
||||||
// TODO: remove it, this function is not thread-safe
|
// TODO: remove it, this function is not thread-safe
|
||||||
|
|
||||||
void timestr(time_t time, char* buf,int len,char* format, int gmt)
|
void timestr(time_t time, char *buf, int len, char *format, int gmt)
|
||||||
{
|
{
|
||||||
struct tm t;
|
struct tm t;
|
||||||
if(gmt)
|
if (gmt)
|
||||||
{
|
{
|
||||||
gmtime_r(&time, &t);
|
gmtime_r(&time, &t);
|
||||||
}
|
}
|
||||||
@ -110,50 +110,53 @@ void timestr(time_t time, char* buf,int len,char* format, int gmt)
|
|||||||
}
|
}
|
||||||
strftime(buf, len, format, &t);
|
strftime(buf, len, format, &t);
|
||||||
}
|
}
|
||||||
void server_time(char* buf, int len)
|
void server_time(char *buf, int len)
|
||||||
{
|
{
|
||||||
timestr(time(NULL), buf, len ,"%a, %d %b %Y %H:%M:%S", 0);
|
timestr(time(NULL), buf, len, "%a, %d %b %Y %H:%M:%S", 0);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Get extension of a file name
|
* Get extension of a file name
|
||||||
* @param file The file name
|
* @param file The file name
|
||||||
* @return the extension
|
* @return the extension
|
||||||
*/
|
*/
|
||||||
char* ext(const char* file)
|
char *ext(const char *file)
|
||||||
{
|
{
|
||||||
char* token,*ltoken = "";
|
char *token, *ltoken = "";
|
||||||
if(file == NULL) return NULL;
|
if (file == NULL)
|
||||||
char* str_cpy = strdup(file);
|
return NULL;
|
||||||
char* str_org = str_cpy;
|
char *str_cpy = strdup(file);
|
||||||
if(!strstr(str_cpy,"."))
|
char *str_org = str_cpy;
|
||||||
|
if (!strstr(str_cpy, "."))
|
||||||
{
|
{
|
||||||
free(str_org);
|
free(str_org);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if(*file == '.')
|
if (*file == '.')
|
||||||
trim(str_cpy,'.');
|
trim(str_cpy, '.');
|
||||||
|
|
||||||
while((token = strsep(&str_cpy,".")) && strlen(token)>0) {ltoken = token;}
|
while ((token = strsep(&str_cpy, ".")) && strlen(token) > 0)
|
||||||
char* ext = strdup(ltoken);
|
{
|
||||||
|
ltoken = token;
|
||||||
|
}
|
||||||
|
char *ext = strdup(ltoken);
|
||||||
free(str_org);
|
free(str_org);
|
||||||
return ext;
|
return ext;
|
||||||
|
|
||||||
}
|
}
|
||||||
/*get mime file info from extension*/
|
/*get mime file info from extension*/
|
||||||
mime_t mime_from_ext(const char* ex)
|
mime_t mime_from_ext(const char *ex)
|
||||||
{
|
{
|
||||||
dictionary_t mime_list = mimes_list();
|
dictionary_t mime_list = mimes_list();
|
||||||
mime_t ret = (mime_t){"application/octet-stream",NULL};
|
mime_t ret = (mime_t){"application/octet-stream", NULL};
|
||||||
if(!mime_list)
|
if (!mime_list)
|
||||||
return ret;
|
return ret;
|
||||||
chain_t it;
|
chain_t it;
|
||||||
char * pattern = __s("(^\\s*%s\\s*,)|(\\s*,\\s*%s\\s*,\\s*)|(^\\s*%s\\s*$)|(,\\s*%s\\s*$)", ex, ex, ex, ex);
|
char *pattern = __s("(^\\s*%s\\s*,)|(\\s*,\\s*%s\\s*,\\s*)|(^\\s*%s\\s*$)|(,\\s*%s\\s*$)", ex, ex, ex, ex);
|
||||||
if(pattern)
|
if (pattern)
|
||||||
{
|
{
|
||||||
for_each_assoc(it,mime_list)
|
for_each_assoc(it, mime_list)
|
||||||
{
|
{
|
||||||
|
|
||||||
if(regex_match(pattern,it->value,0, NULL))
|
if (regex_match(pattern, it->value, 0, NULL))
|
||||||
{
|
{
|
||||||
ret.type = it->key;
|
ret.type = it->key;
|
||||||
ret.ext = it->value;
|
ret.ext = it->value;
|
||||||
@ -166,18 +169,17 @@ mime_t mime_from_ext(const char* ex)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void verify_header(char* k)
|
void verify_header(char *k)
|
||||||
{
|
{
|
||||||
k[0] = toupper(k[0]);
|
k[0] = toupper(k[0]);
|
||||||
int len = strlen(k);
|
int len = strlen(k);
|
||||||
for (int i = 0; i < len; i++)
|
for (int i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
if(k[i] == '-' && i < len-1)
|
if (k[i] == '-' && i < len - 1)
|
||||||
{
|
{
|
||||||
k[i+1] = toupper(k[i+1]);
|
k[i + 1] = toupper(k[i + 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dictionary_t mimes_list()
|
dictionary_t mimes_list()
|
||||||
@ -185,14 +187,14 @@ dictionary_t mimes_list()
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
/*get mime file info from type*/
|
/*get mime file info from type*/
|
||||||
mime_t mime_from_type(const char* type)
|
mime_t mime_from_type(const char *type)
|
||||||
{
|
{
|
||||||
dictionary_t mime_list = mimes_list();
|
dictionary_t mime_list = mimes_list();
|
||||||
mime_t ret = (mime_t){NULL,NULL};
|
mime_t ret = (mime_t){NULL, NULL};
|
||||||
if(!mime_list)
|
if (!mime_list)
|
||||||
return ret;
|
return ret;
|
||||||
chain_t it = dlookup(mime_list, type);
|
chain_t it = dlookup(mime_list, type);
|
||||||
if(it)
|
if (it)
|
||||||
{
|
{
|
||||||
ret.type = it->key;
|
ret.type = it->key;
|
||||||
ret.ext = it->value;
|
ret.ext = it->value;
|
||||||
@ -206,25 +208,26 @@ mime_t mime_from_type(const char* type)
|
|||||||
* @param file File name
|
* @param file File name
|
||||||
* @return The HTTP Mime Type
|
* @return The HTTP Mime Type
|
||||||
*/
|
*/
|
||||||
char* mime(const char* file)
|
char *mime(const char *file)
|
||||||
{
|
{
|
||||||
char * ex = ext(file);
|
char *ex = ext(file);
|
||||||
if(!ex) return "application/octet-stream";
|
if (!ex)
|
||||||
|
return "application/octet-stream";
|
||||||
mime_t m = mime_from_ext(ex);
|
mime_t m = mime_from_ext(ex);
|
||||||
if(ex)
|
if (ex)
|
||||||
{
|
{
|
||||||
free(ex);
|
free(ex);
|
||||||
}
|
}
|
||||||
return (char*)m.type;
|
return (char *)m.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
int match_int(const char* search)
|
int match_int(const char *search)
|
||||||
{
|
{
|
||||||
return regex_match("^[-+]?[0-9]+$",search,0, NULL);
|
return regex_match("^[-+]?[0-9]+$", search, 0, NULL);
|
||||||
}
|
}
|
||||||
int match_float(const char* search)
|
int match_float(const char *search)
|
||||||
{
|
{
|
||||||
return regex_match("^[+-]?[0-9]*\\.[0-9]+$",search,0,NULL);
|
return regex_match("^[+-]?[0-9]*\\.[0-9]+$", search, 0, NULL);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
regmatch_t matches[MAX_MATCHES];
|
regmatch_t matches[MAX_MATCHES];
|
||||||
@ -233,7 +236,7 @@ if (regexec(&exp, sz, MAX_MATCHES, matches, 0) == 0) {
|
|||||||
printf("group1: %s\n", buff);
|
printf("group1: %s\n", buff);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
int regex_match(const char* expr,const char* search, int msize, regmatch_t* matches)
|
int regex_match(const char *expr, const char *search, int msize, regmatch_t *matches)
|
||||||
{
|
{
|
||||||
regex_t regex;
|
regex_t regex;
|
||||||
int reti;
|
int reti;
|
||||||
@ -241,49 +244,60 @@ int regex_match(const char* expr,const char* search, int msize, regmatch_t* matc
|
|||||||
int ret;
|
int ret;
|
||||||
/* Compile regular expression */
|
/* Compile regular expression */
|
||||||
reti = regcomp(®ex, expr, REG_ICASE | REG_EXTENDED);
|
reti = regcomp(®ex, expr, REG_ICASE | REG_EXTENDED);
|
||||||
if( reti ){
|
if (reti)
|
||||||
//ERROR("Could not compile regex: %s",expr);
|
{
|
||||||
|
// ERROR("Could not compile regex: %s",expr);
|
||||||
regerror(reti, ®ex, msgbuf, sizeof(msgbuf));
|
regerror(reti, ®ex, msgbuf, sizeof(msgbuf));
|
||||||
ERROR("Regex match failed: %s", msgbuf);
|
ERROR("Regex match failed: %s", msgbuf);
|
||||||
//return 0;
|
// return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Execute regular expression */
|
/* Execute regular expression */
|
||||||
reti = regexec(®ex, search, msize, matches, 0);
|
reti = regexec(®ex, search, msize, matches, 0);
|
||||||
if( !reti ){
|
if (!reti)
|
||||||
//LOG("Match");
|
{
|
||||||
|
// LOG("Match");
|
||||||
ret = 1;
|
ret = 1;
|
||||||
}
|
}
|
||||||
else if( reti == REG_NOMATCH ){
|
else if (reti == REG_NOMATCH)
|
||||||
//LOG("No match");
|
{
|
||||||
|
// LOG("No match");
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
else{
|
else
|
||||||
|
{
|
||||||
regerror(reti, ®ex, msgbuf, sizeof(msgbuf));
|
regerror(reti, ®ex, msgbuf, sizeof(msgbuf));
|
||||||
//ERROR("Regex match failed: %s\n", msgbuf);
|
// ERROR("Regex match failed: %s\n", msgbuf);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
regfree(®ex);
|
regfree(®ex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
char *url_decode(const char *str) {
|
char *url_decode(const char *str)
|
||||||
if(!str)
|
{
|
||||||
|
if (!str)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
char *pstr = (char*)str, *buf = malloc(strlen(str) + 1), *pbuf = buf;
|
char *pstr = (char *)str, *buf = malloc(strlen(str) + 1), *pbuf = buf;
|
||||||
|
|
||||||
while (*pstr) {
|
while (*pstr)
|
||||||
if (*pstr == '%') {
|
{
|
||||||
if (pstr[1] && pstr[2]) {
|
if (*pstr == '%')
|
||||||
|
{
|
||||||
|
if (pstr[1] && pstr[2])
|
||||||
|
{
|
||||||
*pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
|
*pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
|
||||||
pstr += 2;
|
pstr += 2;
|
||||||
}
|
}
|
||||||
} else if (*pstr == '+') {
|
}
|
||||||
|
else if (*pstr == '+')
|
||||||
|
{
|
||||||
*pbuf++ = ' ';
|
*pbuf++ = ' ';
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
*pbuf++ = *pstr;
|
*pbuf++ = *pstr;
|
||||||
}
|
}
|
||||||
pstr++;
|
pstr++;
|
||||||
@ -293,9 +307,11 @@ char *url_decode(const char *str) {
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *url_encode(const char *str) {
|
char *url_encode(const char *str)
|
||||||
char *pstr = (char*)str, *buf = malloc(strlen(str) * 3 + 1), *pbuf = buf;
|
{
|
||||||
while (*pstr) {
|
char *pstr = (char *)str, *buf = malloc(strlen(str) * 3 + 1), *pbuf = buf;
|
||||||
|
while (*pstr)
|
||||||
|
{
|
||||||
if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~')
|
if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~')
|
||||||
*pbuf++ = *pstr;
|
*pbuf++ = *pstr;
|
||||||
else if (*pstr == ' ')
|
else if (*pstr == ' ')
|
||||||
@ -308,50 +324,55 @@ char *url_encode(const char *str) {
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
char from_hex(char ch) {
|
char from_hex(char ch)
|
||||||
|
{
|
||||||
return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
|
return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
char to_hex(char code) {
|
char to_hex(char code)
|
||||||
|
{
|
||||||
static char hex[] = "0123456789abcdef";
|
static char hex[] = "0123456789abcdef";
|
||||||
return hex[code & 15];
|
return hex[code & 15];
|
||||||
}
|
}
|
||||||
unsigned hash(const char* key, int hash_size)
|
unsigned hash(const char *key, int hash_size)
|
||||||
{
|
{
|
||||||
unsigned hashval = simple_hash(key);
|
unsigned hashval = simple_hash(key);
|
||||||
return hashval % hash_size;
|
return hashval % hash_size;
|
||||||
}
|
}
|
||||||
unsigned simple_hash(const char* key)
|
unsigned simple_hash(const char *key)
|
||||||
{
|
{
|
||||||
unsigned hashval;
|
unsigned hashval;
|
||||||
for (hashval = 0; *key != '\0'; key++)
|
for (hashval = 0; *key != '\0'; key++)
|
||||||
hashval = *key + 31 * hashval;
|
hashval = *key + 31 * hashval;
|
||||||
return hashval;
|
return hashval;
|
||||||
}
|
}
|
||||||
int _exist(const char* f)
|
int _exist(const char *f)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
return !(stat(f, &st) == -1);
|
return !(stat(f, &st) == -1);
|
||||||
}
|
}
|
||||||
int is_file(const char* f)
|
int is_file(const char *f)
|
||||||
{
|
{
|
||||||
int st = is_dir(f);
|
int st = is_dir(f);
|
||||||
if(st == -1) return -1;
|
if (st == -1)
|
||||||
else return st==0;
|
return -1;
|
||||||
|
else
|
||||||
|
return st == 0;
|
||||||
}
|
}
|
||||||
int is_dir(const char* f)
|
int is_dir(const char *f)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if(stat(f, &st) == -1)
|
if (stat(f, &st) == -1)
|
||||||
return -1; // unknow
|
return -1; // unknow
|
||||||
else if(st.st_mode & S_IFDIR)
|
else if (st.st_mode & S_IFDIR)
|
||||||
return 1;
|
return 1;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// These vars will contain the hash
|
// These vars will contain the hash
|
||||||
|
|
||||||
void md5(uint8_t *initial_msg, size_t initial_len, char* buff) {
|
void md5(uint8_t *initial_msg, size_t initial_len, char *buff)
|
||||||
|
{
|
||||||
uint32_t h0, h1, h2, h3;
|
uint32_t h0, h1, h2, h3;
|
||||||
char tmp[80];
|
char tmp[80];
|
||||||
uint8_t *msg = NULL;
|
uint8_t *msg = NULL;
|
||||||
@ -384,16 +405,17 @@ void md5(uint8_t *initial_msg, size_t initial_len, char* buff) {
|
|||||||
h3 = 0x10325476;
|
h3 = 0x10325476;
|
||||||
|
|
||||||
// Pre-processing: adding a single 1 bit
|
// Pre-processing: adding a single 1 bit
|
||||||
//append "1" bit to message
|
// append "1" bit to message
|
||||||
/* Notice: the input bytes are considered as bits strings,
|
/* Notice: the input bytes are considered as bits strings,
|
||||||
where the first bit is the most significant bit of the byte.[37] */
|
where the first bit is the most significant bit of the byte.[37] */
|
||||||
|
|
||||||
// Pre-processing: padding with zeros
|
// Pre-processing: padding with zeros
|
||||||
//append "0" bit until message length in bit ≡ 448 (mod 512)
|
// append "0" bit until message length in bit ≡ 448 (mod 512)
|
||||||
//append length mod (2 pow 64) to message
|
// append length mod (2 pow 64) to message
|
||||||
|
|
||||||
int new_len;
|
int new_len;
|
||||||
for(new_len = initial_len*8 + 1; new_len%512!=448; new_len++);
|
for (new_len = initial_len * 8 + 1; new_len % 512 != 448; new_len++)
|
||||||
|
;
|
||||||
new_len /= 8;
|
new_len /= 8;
|
||||||
|
|
||||||
msg = calloc(new_len + 64, 1); // also appends "0" bits
|
msg = calloc(new_len + 64, 1); // also appends "0" bits
|
||||||
@ -401,16 +423,17 @@ void md5(uint8_t *initial_msg, size_t initial_len, char* buff) {
|
|||||||
memcpy(msg, initial_msg, initial_len);
|
memcpy(msg, initial_msg, initial_len);
|
||||||
msg[initial_len] = 128; // write the "1" bit
|
msg[initial_len] = 128; // write the "1" bit
|
||||||
|
|
||||||
uint32_t bits_len = 8*initial_len; // note, we append the len
|
uint32_t bits_len = 8 * initial_len; // note, we append the len
|
||||||
memcpy(msg + new_len, &bits_len, 4); // in bits at the end of the buffer
|
memcpy(msg + new_len, &bits_len, 4); // in bits at the end of the buffer
|
||||||
|
|
||||||
// Process the message in successive 512-bit chunks:
|
// Process the message in successive 512-bit chunks:
|
||||||
//for each 512-bit chunk of message:
|
// for each 512-bit chunk of message:
|
||||||
int offset;
|
int offset;
|
||||||
for(offset=0; offset<new_len; offset += (512/8)) {
|
for (offset = 0; offset < new_len; offset += (512 / 8))
|
||||||
|
{
|
||||||
|
|
||||||
// break chunk into sixteen 32-bit words w[j], 0 ≤ j ≤ 15
|
// break chunk into sixteen 32-bit words w[j], 0 ≤ j ≤ 15
|
||||||
uint32_t *w = (uint32_t *) (msg + offset);
|
uint32_t *w = (uint32_t *)(msg + offset);
|
||||||
|
|
||||||
// Initialize hash value for this chunk:
|
// Initialize hash value for this chunk:
|
||||||
uint32_t a = h0;
|
uint32_t a = h0;
|
||||||
@ -420,31 +443,38 @@ void md5(uint8_t *initial_msg, size_t initial_len, char* buff) {
|
|||||||
|
|
||||||
// Main loop:
|
// Main loop:
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
for(i = 0; i<64; i++) {
|
for (i = 0; i < 64; i++)
|
||||||
|
{
|
||||||
|
|
||||||
uint32_t f, g;
|
uint32_t f, g;
|
||||||
|
|
||||||
if (i < 16) {
|
if (i < 16)
|
||||||
|
{
|
||||||
f = (b & c) | ((~b) & d);
|
f = (b & c) | ((~b) & d);
|
||||||
g = i;
|
g = i;
|
||||||
} else if (i < 32) {
|
}
|
||||||
|
else if (i < 32)
|
||||||
|
{
|
||||||
f = (d & b) | ((~d) & c);
|
f = (d & b) | ((~d) & c);
|
||||||
g = (5*i + 1) % 16;
|
g = (5 * i + 1) % 16;
|
||||||
} else if (i < 48) {
|
}
|
||||||
|
else if (i < 48)
|
||||||
|
{
|
||||||
f = b ^ c ^ d;
|
f = b ^ c ^ d;
|
||||||
g = (3*i + 5) % 16;
|
g = (3 * i + 5) % 16;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
f = c ^ (b | (~d));
|
f = c ^ (b | (~d));
|
||||||
g = (7*i) % 16;
|
g = (7 * i) % 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t temp = d;
|
uint32_t temp = d;
|
||||||
d = c;
|
d = c;
|
||||||
c = b;
|
c = b;
|
||||||
//printf("rotateLeft(%x + %x + %x + %x, %d)\n", a, f, k[i], w[g], r[i]);
|
// printf("rotateLeft(%x + %x + %x + %x, %d)\n", a, f, k[i], w[g], r[i]);
|
||||||
b = b + LEFTROTATE((a + f + k[i] + w[g]), r[i]);
|
b = b + LEFTROTATE((a + f + k[i] + w[g]), r[i]);
|
||||||
a = temp;
|
a = temp;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add this chunk's hash to result so far:
|
// Add this chunk's hash to result so far:
|
||||||
@ -453,28 +483,26 @@ void md5(uint8_t *initial_msg, size_t initial_len, char* buff) {
|
|||||||
h1 += b;
|
h1 += b;
|
||||||
h2 += c;
|
h2 += c;
|
||||||
h3 += d;
|
h3 += d;
|
||||||
|
|
||||||
}
|
}
|
||||||
uint8_t *p;
|
uint8_t *p;
|
||||||
p=(uint8_t *)&h0;
|
p = (uint8_t *)&h0;
|
||||||
sprintf(tmp,"%02x%02x%02x%02x", p[0], p[1], p[2], p[3]);//, h0
|
sprintf(tmp, "%02x%02x%02x%02x", p[0], p[1], p[2], p[3]); //, h0
|
||||||
strcpy(buff, tmp);
|
strcpy(buff, tmp);
|
||||||
p=(uint8_t *)&h1;
|
p = (uint8_t *)&h1;
|
||||||
sprintf(tmp,"%02x%02x%02x%02x", p[0], p[1], p[2], p[3]); //, h1)
|
sprintf(tmp, "%02x%02x%02x%02x", p[0], p[1], p[2], p[3]); //, h1)
|
||||||
strcat(buff,tmp);
|
strcat(buff, tmp);
|
||||||
p=(uint8_t *)&h2;
|
p = (uint8_t *)&h2;
|
||||||
sprintf(tmp,"%02x%02x%02x%02x", p[0], p[1], p[2], p[3]); // , h2
|
sprintf(tmp, "%02x%02x%02x%02x", p[0], p[1], p[2], p[3]); // , h2
|
||||||
strcat(buff,tmp);
|
strcat(buff, tmp);
|
||||||
p=(uint8_t *)&h3;
|
p = (uint8_t *)&h3;
|
||||||
sprintf(tmp,"%02x%02x%02x%02x", p[0], p[1], p[2], p[3]); // , h3
|
sprintf(tmp, "%02x%02x%02x%02x", p[0], p[1], p[2], p[3]); // , h3
|
||||||
strcat(buff,tmp);
|
strcat(buff, tmp);
|
||||||
// cleanup
|
// cleanup
|
||||||
free(msg);
|
free(msg);
|
||||||
|
|
||||||
}
|
}
|
||||||
void sha1(const char* text, char* out)
|
void sha1(const char *text, char *out)
|
||||||
{
|
{
|
||||||
uint8_t d [20];
|
uint8_t d[20];
|
||||||
#ifdef USE_OPENSSL
|
#ifdef USE_OPENSSL
|
||||||
SHA_CTX context;
|
SHA_CTX context;
|
||||||
#else
|
#else
|
||||||
@ -483,32 +511,32 @@ void sha1(const char* text, char* out)
|
|||||||
SHA1_Init(&context);
|
SHA1_Init(&context);
|
||||||
SHA1_Update(&context, text, strlen(text));
|
SHA1_Update(&context, text, strlen(text));
|
||||||
SHA1_Final(d, &context);
|
SHA1_Final(d, &context);
|
||||||
digest_to_hex(d,out);
|
digest_to_hex(d, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *__s(const char *fstring, ...)
|
||||||
char* __s(const char* fstring,...)
|
|
||||||
{
|
{
|
||||||
char* data;
|
char *data;
|
||||||
va_list arguments;
|
va_list arguments;
|
||||||
int dlen;
|
int dlen;
|
||||||
va_start( arguments, fstring);
|
va_start(arguments, fstring);
|
||||||
dlen = vsnprintf(0,0,fstring,arguments) + 1;
|
dlen = vsnprintf(0, 0, fstring, arguments) + 1;
|
||||||
va_end(arguments);
|
va_end(arguments);
|
||||||
if ((data = (char*)malloc(dlen*sizeof(char))) != 0)
|
if ((data = (char *)malloc(dlen * sizeof(char))) != 0)
|
||||||
{
|
{
|
||||||
va_start(arguments, fstring);
|
va_start(arguments, fstring);
|
||||||
vsnprintf(data, dlen, fstring, arguments);
|
vsnprintf(data, dlen, fstring, arguments);
|
||||||
va_end(arguments);
|
va_end(arguments);
|
||||||
return data;
|
return data;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
int mkdirp(const char* path, mode_t mode)
|
int mkdirp(const char *path, mode_t mode)
|
||||||
{
|
{
|
||||||
char tmp[BUFFLEN];
|
char tmp[BUFFLEN];
|
||||||
if(strlen(path) > BUFFLEN)
|
if (strlen(path) > BUFFLEN)
|
||||||
{
|
{
|
||||||
ERROR("mkdirp: Path is too long %s", path);
|
ERROR("mkdirp: Path is too long %s", path);
|
||||||
return -1;
|
return -1;
|
||||||
@ -516,16 +544,17 @@ int mkdirp(const char* path, mode_t mode)
|
|||||||
char *p = NULL;
|
char *p = NULL;
|
||||||
size_t len;
|
size_t len;
|
||||||
int stat;
|
int stat;
|
||||||
snprintf(tmp, sizeof(tmp),"%s",path);
|
snprintf(tmp, sizeof(tmp), "%s", path);
|
||||||
len = strlen(tmp);
|
len = strlen(tmp);
|
||||||
if(tmp[len - 1] == '/')
|
if (tmp[len - 1] == '/')
|
||||||
tmp[len - 1] = 0;
|
tmp[len - 1] = 0;
|
||||||
for(p = tmp + 1; *p; p++)
|
for (p = tmp + 1; *p; p++)
|
||||||
|
{
|
||||||
|
if (*p == '/')
|
||||||
{
|
{
|
||||||
if(*p == '/') {
|
|
||||||
*p = 0;
|
*p = 0;
|
||||||
stat = mkdir(tmp, mode);
|
stat = mkdir(tmp, mode);
|
||||||
if(stat == -1 && errno != EEXIST)
|
if (stat == -1 && errno != EEXIST)
|
||||||
return stat;
|
return stat;
|
||||||
*p = '/';
|
*p = '/';
|
||||||
}
|
}
|
||||||
@ -533,22 +562,21 @@ int mkdirp(const char* path, mode_t mode)
|
|||||||
return mkdir(path, mode);
|
return mkdir(path, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int guard_read(int fd, void *buffer, size_t size)
|
||||||
int guard_read(int fd, void* buffer, size_t size)
|
|
||||||
{
|
{
|
||||||
int n = 0;
|
int n = 0;
|
||||||
int read_len;
|
int read_len;
|
||||||
int st;
|
int st;
|
||||||
while(n != (int)size)
|
while (n != (int)size)
|
||||||
{
|
{
|
||||||
read_len = (int)size - n;
|
read_len = (int)size - n;
|
||||||
st = read(fd,buffer + n,read_len);
|
st = read(fd, buffer + n, read_len);
|
||||||
if(st == -1)
|
if (st == -1)
|
||||||
{
|
{
|
||||||
ERROR( "Unable to read from #%d: %s", fd, strerror(errno));
|
ERROR("Unable to read from #%d: %s", fd, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(st == 0)
|
if (st == 0)
|
||||||
{
|
{
|
||||||
ERROR("Endpoint %d is closed", fd);
|
ERROR("Endpoint %d is closed", fd);
|
||||||
return -1;
|
return -1;
|
||||||
@ -558,21 +586,21 @@ int guard_read(int fd, void* buffer, size_t size)
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
int guard_write(int fd, void* buffer, size_t size)
|
int guard_write(int fd, void *buffer, size_t size)
|
||||||
{
|
{
|
||||||
int n = 0;
|
int n = 0;
|
||||||
int write_len;
|
int write_len;
|
||||||
int st;
|
int st;
|
||||||
while(n != (int)size)
|
while (n != (int)size)
|
||||||
{
|
{
|
||||||
write_len = (int)size - n;
|
write_len = (int)size - n;
|
||||||
st = write(fd,buffer + n,write_len);
|
st = write(fd, buffer + n, write_len);
|
||||||
if(st == -1)
|
if (st == -1)
|
||||||
{
|
{
|
||||||
ERROR("Unable to write to #%d: %s", fd, strerror(errno));
|
ERROR("Unable to write to #%d: %s", fd, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(st == 0)
|
if (st == 0)
|
||||||
{
|
{
|
||||||
ERROR("Endpoint %d is closed", fd);
|
ERROR("Endpoint %d is closed", fd);
|
||||||
return -1;
|
return -1;
|
||||||
@ -585,11 +613,11 @@ int guard_write(int fd, void* buffer, size_t size)
|
|||||||
/*
|
/*
|
||||||
send a request
|
send a request
|
||||||
*/
|
*/
|
||||||
int request_socket(const char *ip, int port)
|
int antd_request_socket(const char *ip, int port)
|
||||||
{
|
{
|
||||||
int sockfd;
|
int sockfd;
|
||||||
struct sockaddr_in dest;
|
struct sockaddr_in dest;
|
||||||
if(!ip)
|
if (!ip)
|
||||||
{
|
{
|
||||||
ERROR("Invalid IP address");
|
ERROR("Invalid IP address");
|
||||||
return -1;
|
return -1;
|
||||||
@ -608,7 +636,7 @@ int request_socket(const char *ip, int port)
|
|||||||
dest.sin_port = htons(port);
|
dest.sin_port = htons(port);
|
||||||
if (inet_aton(ip, &dest.sin_addr) == 0)
|
if (inet_aton(ip, &dest.sin_addr) == 0)
|
||||||
{
|
{
|
||||||
perror(ip);
|
ERROR("[%s] inet_aton: %s", ip, strerror(errno));
|
||||||
close(sockfd);
|
close(sockfd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -621,12 +649,12 @@ int request_socket(const char *ip, int port)
|
|||||||
return sockfd;
|
return sockfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* ip_from_hostname(const char *hostname)
|
char *ip_from_hostname(const char *hostname)
|
||||||
{
|
{
|
||||||
struct hostent *he;
|
struct hostent *he;
|
||||||
struct in_addr **addr_list;
|
struct in_addr **addr_list;
|
||||||
int i;
|
int i;
|
||||||
if(!hostname)
|
if (!hostname)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -640,8 +668,75 @@ char* ip_from_hostname(const char *hostname)
|
|||||||
|
|
||||||
for (i = 0; addr_list[i] != NULL; i++)
|
for (i = 0; addr_list[i] != NULL; i++)
|
||||||
{
|
{
|
||||||
//Return the first one;
|
// Return the first one;
|
||||||
return inet_ntoa(*addr_list[i]);
|
return inet_ntoa(*addr_list[i]);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int antd_listen(unsigned *port, int ipv6, int backlog)
|
||||||
|
{
|
||||||
|
int httpd = 0;
|
||||||
|
antd_sockaddr_t name;
|
||||||
|
memset(&name, 0, sizeof(name));
|
||||||
|
struct sockaddr *ptr;
|
||||||
|
// TODO: allow to set listen address
|
||||||
|
if (ipv6)
|
||||||
|
{
|
||||||
|
name.addr6.sin6_port = htons(*port);
|
||||||
|
name.addr6.sin6_family = AF_INET6;
|
||||||
|
name.addr6.sin6_addr = in6addr_any;
|
||||||
|
httpd = socket(AF_INET6, SOCK_STREAM, 0);
|
||||||
|
ptr = (struct sockaddr *)&name.addr6;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
name.addr4.sin_port = htons(*port);
|
||||||
|
name.addr4.sin_family = AF_INET;
|
||||||
|
name.addr4.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
httpd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
ptr = (struct sockaddr *)&name.addr4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (httpd == -1)
|
||||||
|
{
|
||||||
|
ERROR("Port %d - socket: %s", *port, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setsockopt(httpd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) == -1)
|
||||||
|
{
|
||||||
|
ERROR("Unable to set reuse address on port %d - setsockopt: %s", *port, strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bind(httpd, ptr, sizeof(name)) < 0)
|
||||||
|
{
|
||||||
|
ERROR("Port %d -bind: %s", *port, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (*port == 0) /* if dynamically allocating a port */
|
||||||
|
{
|
||||||
|
socklen_t namelen = sizeof(name);
|
||||||
|
if (getsockname(httpd, (struct sockaddr *)&name, &namelen) == -1)
|
||||||
|
{
|
||||||
|
ERROR("Port %d - getsockname: %s", *port, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (ipv6)
|
||||||
|
{
|
||||||
|
*port = ntohs(name.addr6.sin6_port);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*port = ntohs(name.addr4.sin_port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(httpd, backlog) < 0)
|
||||||
|
{
|
||||||
|
ERROR("Port %d - listen: %s", *port, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
LOG("%s Listen on port %d", ipv6 ? "IPv6" : "IPv4", *port);
|
||||||
|
return (httpd);
|
||||||
|
}
|
||||||
|
11
lib/utils.h
11
lib/utils.h
@ -30,6 +30,7 @@ THE SOFTWARE.
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
#include "dictionary.h"
|
#include "dictionary.h"
|
||||||
|
|
||||||
@ -58,6 +59,12 @@ typedef struct{
|
|||||||
const char* ext;
|
const char* ext;
|
||||||
} mime_t;
|
} mime_t;
|
||||||
|
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
struct sockaddr_in6 addr6;
|
||||||
|
struct sockaddr_in addr4;
|
||||||
|
} antd_sockaddr_t;
|
||||||
|
|
||||||
dictionary_t __attribute__((weak)) mimes_list();
|
dictionary_t __attribute__((weak)) mimes_list();
|
||||||
char* __s(const char*,...);
|
char* __s(const char*,...);
|
||||||
void trim(char*,const char);
|
void trim(char*,const char);
|
||||||
@ -87,6 +94,8 @@ void digest_to_hex(const uint8_t *, char *);
|
|||||||
void verify_header(char* k);
|
void verify_header(char* k);
|
||||||
int guard_read(int fd, void* buffer, size_t size);
|
int guard_read(int fd, void* buffer, size_t size);
|
||||||
int guard_write(int fd, void* buffer, size_t size);
|
int guard_write(int fd, void* buffer, size_t size);
|
||||||
int request_socket(const char *ip, int port);
|
|
||||||
char* ip_from_hostname(const char *hostname);
|
char* ip_from_hostname(const char *hostname);
|
||||||
|
|
||||||
|
int antd_request_socket(const char *ip, int port);
|
||||||
|
int antd_listen(unsigned *port, int ipv6, int backlog);
|
||||||
#endif
|
#endif
|
||||||
|
123
lib/ws.c
123
lib/ws.c
@ -15,6 +15,13 @@
|
|||||||
#include "handle.h"
|
#include "handle.h"
|
||||||
|
|
||||||
#include "ws.h"
|
#include "ws.h"
|
||||||
|
#define CONN_TIME_OUT_S 3
|
||||||
|
#define BITV(v, i) ((v & (1 << i)) >> i)
|
||||||
|
#define MAX_BUFF 1024
|
||||||
|
#define PREFERRED_WS_CIPHERS "HIGH:!aNULL:!kRSA:!SRP:!PSK:!CAMELLIA:!RC4:!MD5:!DSS"
|
||||||
|
#define CLIENT_RQ "GET /%s HTTP/1.1\r\nHost: %s\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\n\r\n"
|
||||||
|
#define SERVER_WS_KEY "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="
|
||||||
|
|
||||||
static void ws_gen_mask_key(ws_msg_header_t *header)
|
static void ws_gen_mask_key(ws_msg_header_t *header)
|
||||||
{
|
{
|
||||||
int r = rand();
|
int r = rand();
|
||||||
@ -24,10 +31,10 @@ static void ws_gen_mask_key(ws_msg_header_t *header)
|
|||||||
header->mask_key[3] = r & 0xFF;
|
header->mask_key[3] = r & 0xFF;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Read a frame header
|
* Read a frame header
|
||||||
* based on this header, we'll decide
|
* based on this header, we'll decide
|
||||||
* the appropriate handle for frame data
|
* the appropriate handle for frame data
|
||||||
*/
|
*/
|
||||||
ws_msg_header_t *ws_read_header(void *client)
|
ws_msg_header_t *ws_read_header(void *client)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -41,7 +48,7 @@ ws_msg_header_t *ws_read_header(void *client)
|
|||||||
if (BITV(byte, 6) || BITV(byte, 5) || BITV(byte, 4))
|
if (BITV(byte, 6) || BITV(byte, 5) || BITV(byte, 4))
|
||||||
goto fail; // all RSV bit must be 0
|
goto fail; // all RSV bit must be 0
|
||||||
|
|
||||||
//printf("FIN: %d, RSV1: %d, RSV2: %d, RSV3:%d, opcode:%d\n", BITV(byte,7), BITV(byte,6), BITV(byte,5), BITV(byte,4),(byte & 0x0F) );
|
// printf("FIN: %d, RSV1: %d, RSV2: %d, RSV3:%d, opcode:%d\n", BITV(byte,7), BITV(byte,6), BITV(byte,5), BITV(byte,4),(byte & 0x0F) );
|
||||||
// find and opcode
|
// find and opcode
|
||||||
header->fin = BITV(byte, 7);
|
header->fin = BITV(byte, 7);
|
||||||
header->opcode = (byte & 0x0F);
|
header->opcode = (byte & 0x0F);
|
||||||
@ -50,7 +57,7 @@ ws_msg_header_t *ws_read_header(void *client)
|
|||||||
if (antd_recv(client, &byte, sizeof(byte)) <= 0)
|
if (antd_recv(client, &byte, sizeof(byte)) <= 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
//printf("MASK: %d paylen:%d\n", BITV(byte,7), (byte & 0x7F));
|
// printf("MASK: %d paylen:%d\n", BITV(byte,7), (byte & 0x7F));
|
||||||
// check mask bit, should be 1
|
// check mask bit, should be 1
|
||||||
header->mask = BITV(byte, 7);
|
header->mask = BITV(byte, 7);
|
||||||
/*if(!BITV(byte,7))
|
/*if(!BITV(byte,7))
|
||||||
@ -73,28 +80,28 @@ ws_msg_header_t *ws_read_header(void *client)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//read only last 4 byte
|
// read only last 4 byte
|
||||||
if (antd_recv(client, bytes, 8 * sizeof(uint8_t)) <= 0)
|
if (antd_recv(client, bytes, 8 * sizeof(uint8_t)) <= 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
header->plen = (bytes[4] << 24) + (bytes[5] << 16) + (bytes[6] << 8) + bytes[7];
|
header->plen = (bytes[4] << 24) + (bytes[5] << 16) + (bytes[6] << 8) + bytes[7];
|
||||||
}
|
}
|
||||||
//printf("len: %d\n", header->plen);
|
// printf("len: %d\n", header->plen);
|
||||||
// last step is to get the maskey
|
// last step is to get the maskey
|
||||||
if (header->mask)
|
if (header->mask)
|
||||||
if (antd_recv(client, header->mask_key, 4 * sizeof(uint8_t)) <= 0)
|
if (antd_recv(client, header->mask_key, 4 * sizeof(uint8_t)) <= 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
//printf("key 0: %d key 1: %d key2:%d, key3: %d\n",header->mask_key[0],header->mask_key[1],header->mask_key[2], header->mask_key[3] );
|
// printf("key 0: %d key 1: %d key2:%d, key3: %d\n",header->mask_key[0],header->mask_key[1],header->mask_key[2], header->mask_key[3] );
|
||||||
|
|
||||||
// check wheather it is a ping or a close message
|
// check wheather it is a ping or a close message
|
||||||
// process it and return NULL
|
// process it and return NULL
|
||||||
//otherwise return the header
|
// otherwise return the header
|
||||||
//return the header
|
// return the header
|
||||||
switch (header->opcode)
|
switch (header->opcode)
|
||||||
{
|
{
|
||||||
case WS_CLOSE: // client requests to close the connection
|
case WS_CLOSE: // client requests to close the connection
|
||||||
// send back a close message
|
// send back a close message
|
||||||
UNUSED(ws_send_close(client, 1000, header->mask ? 0 : 1));
|
UNUSED(ws_send_close(client, 1000, header->mask ? 0 : 1));
|
||||||
//goto fail;
|
// goto fail;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WS_PING: // client send a ping
|
case WS_PING: // client send a ping
|
||||||
@ -112,9 +119,9 @@ fail:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Read data from client
|
* Read data from client
|
||||||
* and unmask data using the key
|
* and unmask data using the key
|
||||||
*/
|
*/
|
||||||
int ws_read_data(void *client, ws_msg_header_t *header, int len, uint8_t *data)
|
int ws_read_data(void *client, ws_msg_header_t *header, int len, uint8_t *data)
|
||||||
{
|
{
|
||||||
// if len == -1 ==> read all remaining data to 'data';
|
// if len == -1 ==> read all remaining data to 'data';
|
||||||
@ -137,14 +144,14 @@ int _send_header(void *client, ws_msg_header_t header)
|
|||||||
uint8_t bytes[8];
|
uint8_t bytes[8];
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
bytes[i] = 0;
|
bytes[i] = 0;
|
||||||
//first byte |FIN|000|opcode|
|
// first byte |FIN|000|opcode|
|
||||||
byte = (header.fin << 7) + header.opcode;
|
byte = (header.fin << 7) + header.opcode;
|
||||||
//printf("BYTE: %d\n", byte);
|
// printf("BYTE: %d\n", byte);
|
||||||
if (antd_send(client, &byte, 1) != 1)
|
if (antd_send(client, &byte, 1) != 1)
|
||||||
return -1;
|
return -1;
|
||||||
// second byte, payload length
|
// second byte, payload length
|
||||||
// mask may be 0 or 1
|
// mask may be 0 or 1
|
||||||
//if(header.mask == 1)
|
// if(header.mask == 1)
|
||||||
// printf("Data is masked\n");
|
// printf("Data is masked\n");
|
||||||
if (header.plen <= 125)
|
if (header.plen <= 125)
|
||||||
{
|
{
|
||||||
@ -183,8 +190,8 @@ int _send_header(void *client, ws_msg_header_t header)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Send a frame to client
|
* Send a frame to client
|
||||||
*/
|
*/
|
||||||
int ws_send_frame(void *client, uint8_t *data, ws_msg_header_t header)
|
int ws_send_frame(void *client, uint8_t *data, ws_msg_header_t header)
|
||||||
{
|
{
|
||||||
uint8_t *masked;
|
uint8_t *masked;
|
||||||
@ -212,8 +219,8 @@ int ws_send_frame(void *client, uint8_t *data, ws_msg_header_t header)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* send a text data frame to client
|
* send a text data frame to client
|
||||||
*/
|
*/
|
||||||
int ws_send_text(void *client, const char *data, int mask)
|
int ws_send_text(void *client, const char *data, int mask)
|
||||||
{
|
{
|
||||||
ws_msg_header_t header;
|
ws_msg_header_t header;
|
||||||
@ -222,13 +229,13 @@ int ws_send_text(void *client, const char *data, int mask)
|
|||||||
header.mask = mask;
|
header.mask = mask;
|
||||||
header.plen = strlen(data);
|
header.plen = strlen(data);
|
||||||
//_send_header(client,header);
|
//_send_header(client,header);
|
||||||
//send(client, data, header.plen,0);
|
// send(client, data, header.plen,0);
|
||||||
return ws_send_frame(client, (uint8_t *)data, header);
|
return ws_send_frame(client, (uint8_t *)data, header);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* send a single binary data fram to client
|
* send a single binary data fram to client
|
||||||
* not tested yet, but should work
|
* not tested yet, but should work
|
||||||
*/
|
*/
|
||||||
int ws_send_binary(void *client, uint8_t *data, int l, int mask)
|
int ws_send_binary(void *client, uint8_t *data, int l, int mask)
|
||||||
{
|
{
|
||||||
ws_msg_header_t header;
|
ws_msg_header_t header;
|
||||||
@ -238,11 +245,11 @@ int ws_send_binary(void *client, uint8_t *data, int l, int mask)
|
|||||||
header.mask = mask;
|
header.mask = mask;
|
||||||
return ws_send_frame(client, data, header);
|
return ws_send_frame(client, data, header);
|
||||||
//_send_header(client,header);
|
//_send_header(client,header);
|
||||||
//send(client, data, header.plen,0);
|
// send(client, data, header.plen,0);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* send a file as binary data
|
* send a file as binary data
|
||||||
*/
|
*/
|
||||||
int ws_send_file(void *client, const char *file, int mask)
|
int ws_send_file(void *client, const char *file, int mask)
|
||||||
{
|
{
|
||||||
uint8_t buff[1024];
|
uint8_t buff[1024];
|
||||||
@ -257,7 +264,7 @@ int ws_send_file(void *client, const char *file, int mask)
|
|||||||
size_t size;
|
size_t size;
|
||||||
int first_frame = 1;
|
int first_frame = 1;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
//ws_send_frame(client,buff,header);
|
// ws_send_frame(client,buff,header);
|
||||||
header.mask = mask;
|
header.mask = mask;
|
||||||
while (!feof(ptr))
|
while (!feof(ptr))
|
||||||
{
|
{
|
||||||
@ -275,7 +282,7 @@ int ws_send_file(void *client, const char *file, int mask)
|
|||||||
else
|
else
|
||||||
header.opcode = 0;
|
header.opcode = 0;
|
||||||
header.plen = size;
|
header.plen = size;
|
||||||
//printf("FIN: %d OC:%d\n", header.fin, header.opcode);
|
// printf("FIN: %d OC:%d\n", header.fin, header.opcode);
|
||||||
ret += ws_send_frame(client, buff, header);
|
ret += ws_send_frame(client, buff, header);
|
||||||
}
|
}
|
||||||
fclose(ptr);
|
fclose(ptr);
|
||||||
@ -286,9 +293,9 @@ int ws_send_file(void *client, const char *file, int mask)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Not tested yet
|
* Not tested yet
|
||||||
* but should work
|
* but should work
|
||||||
*/
|
*/
|
||||||
int ws_pong(void *client, ws_msg_header_t *oheader, int mask)
|
int ws_pong(void *client, ws_msg_header_t *oheader, int mask)
|
||||||
{
|
{
|
||||||
ws_msg_header_t pheader;
|
ws_msg_header_t pheader;
|
||||||
@ -310,7 +317,7 @@ int ws_pong(void *client, ws_msg_header_t *oheader, int mask)
|
|||||||
ret = ws_send_frame(client, data, pheader);
|
ret = ws_send_frame(client, data, pheader);
|
||||||
free(data);
|
free(data);
|
||||||
//_send_header(client, pheader);
|
//_send_header(client, pheader);
|
||||||
//send(client, data, len, 0);
|
// send(client, data, len, 0);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
int ws_ping(void *client, const char *echo, int mask)
|
int ws_ping(void *client, const char *echo, int mask)
|
||||||
@ -323,11 +330,11 @@ int ws_ping(void *client, const char *echo, int mask)
|
|||||||
return ws_send_frame(client, (uint8_t *)echo, pheader);
|
return ws_send_frame(client, (uint8_t *)echo, pheader);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Not tested yet, but should work
|
* Not tested yet, but should work
|
||||||
*/
|
*/
|
||||||
int ws_send_close(void *client, unsigned int status, int mask)
|
int ws_send_close(void *client, unsigned int status, int mask)
|
||||||
{
|
{
|
||||||
//printf("CLOSED\n");
|
// printf("CLOSED\n");
|
||||||
ws_msg_header_t header;
|
ws_msg_header_t header;
|
||||||
header.fin = 1;
|
header.fin = 1;
|
||||||
header.opcode = WS_CLOSE;
|
header.opcode = WS_CLOSE;
|
||||||
@ -345,7 +352,7 @@ int ws_send_close(void *client, unsigned int status, int mask)
|
|||||||
}*/
|
}*/
|
||||||
return ws_send_frame(client, bytes, header);
|
return ws_send_frame(client, bytes, header);
|
||||||
//_send_header(client, header);
|
//_send_header(client, header);
|
||||||
//send(client,bytes,2,0);
|
// send(client,bytes,2,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ws_client_close(ws_client_t *wsclient)
|
void ws_client_close(ws_client_t *wsclient)
|
||||||
@ -368,13 +375,13 @@ void ws_client_close(ws_client_t *wsclient)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//this is for the client side, not use for now
|
// this is for the client side, not use for now
|
||||||
int ws_client_connect(ws_client_t *wsclient, port_config_t pcnf)
|
int ws_client_connect(ws_client_t *wsclient, ws_port_config_t pcnf)
|
||||||
{
|
{
|
||||||
char* ip = ip_from_hostname(wsclient->host);
|
char *ip = ip_from_hostname(wsclient->host);
|
||||||
if (ip == NULL)
|
if (ip == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
int sock = request_socket(ip, pcnf.port);
|
int sock = antd_request_socket(ip, pcnf.port);
|
||||||
if (sock <= 0)
|
if (sock <= 0)
|
||||||
{
|
{
|
||||||
ERROR("Cannot request socket");
|
ERROR("Cannot request socket");
|
||||||
@ -383,7 +390,7 @@ int ws_client_connect(ws_client_t *wsclient, port_config_t pcnf)
|
|||||||
// time out setting
|
// time out setting
|
||||||
struct timeval timeout;
|
struct timeval timeout;
|
||||||
timeout.tv_sec = CONN_TIME_OUT_S;
|
timeout.tv_sec = CONN_TIME_OUT_S;
|
||||||
timeout.tv_usec = 0; //3 s
|
timeout.tv_usec = 0; // 3 s
|
||||||
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0)
|
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0)
|
||||||
ERROR("setsockopt failed:%s", strerror(errno));
|
ERROR("setsockopt failed:%s", strerror(errno));
|
||||||
|
|
||||||
@ -427,7 +434,7 @@ int ws_client_connect(ws_client_t *wsclient, port_config_t pcnf)
|
|||||||
SSL_CTX_set_options(wsclient->ssl_ctx, SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_SSLv2 | SSL_OP_NO_TICKET);
|
SSL_CTX_set_options(wsclient->ssl_ctx, SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_SSLv2 | SSL_OP_NO_TICKET);
|
||||||
// set the cipher suit
|
// set the cipher suit
|
||||||
const char *suit = wsclient->ciphersuit ? wsclient->ciphersuit : PREFERRED_WS_CIPHERS;
|
const char *suit = wsclient->ciphersuit ? wsclient->ciphersuit : PREFERRED_WS_CIPHERS;
|
||||||
//const char* suit = "AES128-SHA";
|
// const char* suit = "AES128-SHA";
|
||||||
if (SSL_CTX_set_cipher_list(wsclient->ssl_ctx, suit) != 1)
|
if (SSL_CTX_set_cipher_list(wsclient->ssl_ctx, suit) != 1)
|
||||||
{
|
{
|
||||||
ssl_err = ERR_get_error();
|
ssl_err = ERR_get_error();
|
||||||
@ -514,7 +521,7 @@ int ws_open_handshake(ws_client_t *client)
|
|||||||
char buf[MAX_BUFF];
|
char buf[MAX_BUFF];
|
||||||
// now send ws request handshake
|
// now send ws request handshake
|
||||||
sprintf(buf, CLIENT_RQ, client->resource, client->host);
|
sprintf(buf, CLIENT_RQ, client->resource, client->host);
|
||||||
//printf("Send %s\n", buf);
|
// printf("Send %s\n", buf);
|
||||||
int size = antd_send(client->antdsock, buf, strlen(buf));
|
int size = antd_send(client->antdsock, buf, strlen(buf));
|
||||||
if (size != (int)strlen(buf))
|
if (size != (int)strlen(buf))
|
||||||
{
|
{
|
||||||
@ -538,7 +545,7 @@ int ws_open_handshake(ws_client_t *client)
|
|||||||
trim(token, '\r');
|
trim(token, '\r');
|
||||||
if (strcasecmp(token, SERVER_WS_KEY) == 0)
|
if (strcasecmp(token, SERVER_WS_KEY) == 0)
|
||||||
{
|
{
|
||||||
//LOG("Handshake sucessfull\n");
|
// LOG("Handshake sucessfull\n");
|
||||||
done = 1;
|
done = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -547,30 +554,10 @@ int ws_open_handshake(ws_client_t *client)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//if(line) free(line);
|
// if(line) free(line);
|
||||||
size = read_buf(client->antdsock, buf, MAX_BUFF);
|
size = read_buf(client->antdsock, buf, MAX_BUFF);
|
||||||
}
|
}
|
||||||
if (done)
|
if (done)
|
||||||
return 0;
|
return 0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
char *get_ip_address()
|
|
||||||
{
|
|
||||||
struct ifaddrs *addrs;
|
|
||||||
getifaddrs(&addrs);
|
|
||||||
struct ifaddrs *tmp = addrs;
|
|
||||||
char *ip;
|
|
||||||
while (tmp)
|
|
||||||
{
|
|
||||||
if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET)
|
|
||||||
{
|
|
||||||
struct sockaddr_in *pAddr = (struct sockaddr_in *)tmp->ifa_addr;
|
|
||||||
ip = inet_ntoa(pAddr->sin_addr);
|
|
||||||
if (strcmp(ip, "127.0.0.1") != 0)
|
|
||||||
return ip;
|
|
||||||
}
|
|
||||||
tmp = tmp->ifa_next;
|
|
||||||
}
|
|
||||||
freeifaddrs(addrs);
|
|
||||||
return "127.0.0.1";
|
|
||||||
}
|
|
19
lib/ws.h
19
lib/ws.h
@ -3,10 +3,6 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "handle.h"
|
|
||||||
|
|
||||||
#define CONN_TIME_OUT_S 3
|
|
||||||
#define BITV(v, i) ((v & (1 << i)) >> i)
|
|
||||||
#define WS_TEXT 0x1
|
#define WS_TEXT 0x1
|
||||||
#define WS_BIN 0x2
|
#define WS_BIN 0x2
|
||||||
#define WS_CLOSE 0x8
|
#define WS_CLOSE 0x8
|
||||||
@ -16,11 +12,14 @@
|
|||||||
#define ws_b(c, d, z) (ws_send_binary(c, d, z, 0))
|
#define ws_b(c, d, z) (ws_send_binary(c, d, z, 0))
|
||||||
#define ws_f(c, f) (ws_send_file(c, f, 0))
|
#define ws_f(c, f) (ws_send_file(c, f, 0))
|
||||||
#define ws_close(c, r) (ws_send_close(c, r, 0))
|
#define ws_close(c, r) (ws_send_close(c, r, 0))
|
||||||
#define MAX_BUFF 1024
|
|
||||||
|
|
||||||
#define PREFERRED_WS_CIPHERS "HIGH:!aNULL:!kRSA:!SRP:!PSK:!CAMELLIA:!RC4:!MD5:!DSS"
|
typedef struct
|
||||||
#define CLIENT_RQ "GET /%s HTTP/1.1\r\nHost: %s\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\n\r\n"
|
{
|
||||||
#define SERVER_WS_KEY "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="
|
unsigned int port;
|
||||||
|
int usessl;
|
||||||
|
int sock;
|
||||||
|
antd_proto_t type;
|
||||||
|
} ws_port_config_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@ -57,12 +56,10 @@ int ws_send_file(void *client, const char *file, int mask);
|
|||||||
int ws_send_binary(void *client, uint8_t *data, int l, int mask);
|
int ws_send_binary(void *client, uint8_t *data, int l, int mask);
|
||||||
|
|
||||||
int ws_read_data(void *, ws_msg_header_t *, int, uint8_t *);
|
int ws_read_data(void *, ws_msg_header_t *, int, uint8_t *);
|
||||||
//int ws_open_hand_shake(const char* host, int port, const char* resource);
|
|
||||||
char *get_ip_address();
|
|
||||||
|
|
||||||
// client
|
// client
|
||||||
|
|
||||||
void ws_client_close(ws_client_t *wsclient);
|
void ws_client_close(ws_client_t *wsclient);
|
||||||
int ws_client_connect(ws_client_t *wsclient, port_config_t pcnf);
|
int ws_client_connect(ws_client_t *wsclient, ws_port_config_t pcnf);
|
||||||
int ws_open_handshake(ws_client_t *client);
|
int ws_open_handshake(ws_client_t *client);
|
||||||
#endif
|
#endif
|
@ -4,10 +4,14 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/sendfile.h>
|
#include <sys/sendfile.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include "plugin_manager.h"
|
#include "plugin_manager.h"
|
||||||
#include "lib/utils.h"
|
#include "lib/utils.h"
|
||||||
#include "lib/handle.h"
|
#include "lib/handle.h"
|
||||||
#include "http_server.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
extern config_t g_server_config;
|
||||||
|
|
||||||
static void unload_plugin_by_name(const char *);
|
static void unload_plugin_by_name(const char *);
|
||||||
static void *plugin_from_file(char *name, char *path, dictionary_t conf);
|
static void *plugin_from_file(char *name, char *path, dictionary_t conf);
|
||||||
|
|
||||||
@ -25,7 +29,7 @@ struct plugin_entry *plugin_lookup(char *s)
|
|||||||
{
|
{
|
||||||
struct plugin_entry *np;
|
struct plugin_entry *np;
|
||||||
for (np = plugin_table[hash(s, HASHSIZE)]; np != NULL; np = np->next)
|
for (np = plugin_table[hash(s, HASHSIZE)]; np != NULL; np = np->next)
|
||||||
if (strcmp(s, np->pname) == 0)
|
if (strcmp(s, np->name) == 0)
|
||||||
return np; /* found */
|
return np; /* found */
|
||||||
return NULL; /* not found */
|
return NULL; /* not found */
|
||||||
}
|
}
|
||||||
@ -45,7 +49,6 @@ struct plugin_entry *plugin_load(char *name, dictionary_t pconf)
|
|||||||
unsigned hashval;
|
unsigned hashval;
|
||||||
plugin_header_t *(*metafn)();
|
plugin_header_t *(*metafn)();
|
||||||
plugin_header_t *meta = NULL;
|
plugin_header_t *meta = NULL;
|
||||||
config_t *sconf = config();
|
|
||||||
int fromfd, tofd;
|
int fromfd, tofd;
|
||||||
char *error;
|
char *error;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
@ -65,11 +68,11 @@ struct plugin_entry *plugin_load(char *name, dictionary_t pconf)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)snprintf(path, sizeof(path), "%s/%s%s", sconf->plugins_dir, name, sconf->plugins_ext);
|
(void)snprintf(path, sizeof(path), "%s/%s%s", g_server_config.plugins_dir, name, g_server_config.plugins_ext);
|
||||||
if (pname && strcmp(name, pname) != 0)
|
if (pname && strcmp(name, pname) != 0)
|
||||||
{
|
{
|
||||||
// copy plugin file to tmpdir
|
// copy plugin file to tmpdir
|
||||||
(void)snprintf(path, sizeof(path), "%s/%s%s", sconf->plugins_dir, pname, sconf->plugins_ext);
|
(void)snprintf(path, sizeof(path), "%s/%s%s", g_server_config.plugins_dir, pname, g_server_config.plugins_ext);
|
||||||
LOG("Original plugin file: %s", path);
|
LOG("Original plugin file: %s", path);
|
||||||
if ((fromfd = open(path, O_RDONLY)) < 0)
|
if ((fromfd = open(path, O_RDONLY)) < 0)
|
||||||
{
|
{
|
||||||
@ -82,7 +85,7 @@ struct plugin_entry *plugin_load(char *name, dictionary_t pconf)
|
|||||||
ERROR("Unable to get file stat %s: %s", path, strerror(errno));
|
ERROR("Unable to get file stat %s: %s", path, strerror(errno));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
(void)snprintf(path, sizeof(path), "%s/%s%s", sconf->tmpdir, name, sconf->plugins_ext);
|
(void)snprintf(path, sizeof(path), "%s/%s%s", g_server_config.tmpdir, name, g_server_config.plugins_ext);
|
||||||
LOG("TMP plugin file: %s", path);
|
LOG("TMP plugin file: %s", path);
|
||||||
if ((tofd = open(path, O_WRONLY | O_CREAT, 0600)) < 0)
|
if ((tofd = open(path, O_WRONLY | O_CREAT, 0600)) < 0)
|
||||||
{
|
{
|
||||||
@ -100,16 +103,17 @@ struct plugin_entry *plugin_load(char *name, dictionary_t pconf)
|
|||||||
is_tmp = 1;
|
is_tmp = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
np->pname = strdup(name);
|
np->name = strdup(name);
|
||||||
np->handle = plugin_from_file(name, path, pconf);
|
np->handle = plugin_from_file(name, path, pconf);
|
||||||
if (is_tmp)
|
if (is_tmp)
|
||||||
{
|
{
|
||||||
|
//TODO change this
|
||||||
(void)remove(path);
|
(void)remove(path);
|
||||||
}
|
}
|
||||||
if (np->handle == NULL)
|
if (np->handle == NULL)
|
||||||
{
|
{
|
||||||
if (np->pname)
|
if (np->name)
|
||||||
free(np->pname);
|
free(np->name);
|
||||||
if (np)
|
if (np)
|
||||||
free(np);
|
free(np);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -152,7 +156,6 @@ static void *plugin_from_file(char *name, char *path, dictionary_t conf)
|
|||||||
{
|
{
|
||||||
void *lib_handle;
|
void *lib_handle;
|
||||||
char *error;
|
char *error;
|
||||||
config_t *cnf = config();
|
|
||||||
void (*fn)(plugin_header_t *, dictionary_t);
|
void (*fn)(plugin_header_t *, dictionary_t);
|
||||||
lib_handle = dlopen(path, RTLD_LAZY | RTLD_LOCAL /*| RTLD_NODELETE*/);
|
lib_handle = dlopen(path, RTLD_LAZY | RTLD_LOCAL /*| RTLD_NODELETE*/);
|
||||||
if (!lib_handle)
|
if (!lib_handle)
|
||||||
@ -160,7 +163,6 @@ static void *plugin_from_file(char *name, char *path, dictionary_t conf)
|
|||||||
ERROR("Cannot load plugin '%s' : '%s'", name, dlerror());
|
ERROR("Cannot load plugin '%s' : '%s'", name, dlerror());
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
// set database path
|
|
||||||
fn = (void (*)(plugin_header_t *, dictionary_t))dlsym(lib_handle, "__init_plugin__");
|
fn = (void (*)(plugin_header_t *, 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);
|
||||||
@ -168,9 +170,9 @@ static void *plugin_from_file(char *name, char *path, dictionary_t conf)
|
|||||||
{
|
{
|
||||||
plugin_header_t header;
|
plugin_header_t header;
|
||||||
strncpy(header.name, name, MAX_PATH_LEN - 1);
|
strncpy(header.name, name, MAX_PATH_LEN - 1);
|
||||||
strncpy(header.dbpath, cnf->db_path, MAX_PATH_LEN - 1);
|
strncpy(header.dbpath, g_server_config.db_path, MAX_PATH_LEN - 1);
|
||||||
strncpy(header.tmpdir, cnf->tmpdir, MAX_PATH_LEN - 1);
|
strncpy(header.tmpdir, g_server_config.tmpdir, MAX_PATH_LEN - 1);
|
||||||
strncpy(header.pdir, cnf->plugins_dir, MAX_PATH_LEN - 1);
|
strncpy(header.pdir, g_server_config.plugins_dir, MAX_PATH_LEN - 1);
|
||||||
header.config = conf;
|
header.config = conf;
|
||||||
header.raw_body = 0;
|
header.raw_body = 0;
|
||||||
header.status = ANTD_PLUGIN_INIT;
|
header.status = ANTD_PLUGIN_INIT;
|
||||||
@ -188,17 +190,17 @@ void unload_plugin(struct plugin_entry *np)
|
|||||||
fn = (void (*)())dlsym(np->handle, "__release__");
|
fn = (void (*)())dlsym(np->handle, "__release__");
|
||||||
if ((error = dlerror()) != NULL)
|
if ((error = dlerror()) != NULL)
|
||||||
{
|
{
|
||||||
ERROR("Cant not release plugin %s : %s", np->pname, error);
|
ERROR("Cant not release plugin %s : %s", np->name, error);
|
||||||
}
|
}
|
||||||
if (fn)
|
if (fn)
|
||||||
{
|
{
|
||||||
(*fn)();
|
(*fn)();
|
||||||
}
|
}
|
||||||
dlclose(np->handle);
|
dlclose(np->handle);
|
||||||
LOG("Unloaded %s", np->pname);
|
LOG("Unloaded %s", np->name);
|
||||||
// free((void *) np->handle);
|
// free((void *) np->handle);
|
||||||
if (np->pname)
|
if (np->name)
|
||||||
free((void *)np->pname);
|
free((void *)np->name);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
Unload a plugin by its name
|
Unload a plugin by its name
|
||||||
@ -208,7 +210,7 @@ void unload_plugin_by_name(const char *name)
|
|||||||
struct plugin_entry *np;
|
struct plugin_entry *np;
|
||||||
int hasval = hash(name, HASHSIZE);
|
int hasval = hash(name, HASHSIZE);
|
||||||
np = plugin_table[hasval];
|
np = plugin_table[hasval];
|
||||||
if (strcmp(np->pname, name) == 0)
|
if (strcmp(np->name, name) == 0)
|
||||||
{
|
{
|
||||||
unload_plugin(np);
|
unload_plugin(np);
|
||||||
plugin_table[hasval] = np->next;
|
plugin_table[hasval] = np->next;
|
||||||
@ -217,7 +219,7 @@ void unload_plugin_by_name(const char *name)
|
|||||||
{
|
{
|
||||||
for (np = plugin_table[hasval]; np != NULL; np = np->next)
|
for (np = plugin_table[hasval]; np != NULL; np = np->next)
|
||||||
{
|
{
|
||||||
if (np->next != NULL && strcmp(name, np->next->pname) == 0)
|
if (np->next != NULL && strcmp(name, np->next->name) == 0)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,17 @@
|
|||||||
|
|
||||||
#include "lib/dictionary.h"
|
#include "lib/dictionary.h"
|
||||||
|
|
||||||
|
#define PLUGIN_HANDLER "handle"
|
||||||
|
|
||||||
struct plugin_entry {
|
struct plugin_entry {
|
||||||
struct plugin_entry *next;
|
struct plugin_entry *next;
|
||||||
char *pname;
|
char *name;
|
||||||
void *handle;
|
void *handle;
|
||||||
|
dictionary_t instances;
|
||||||
};
|
};
|
||||||
/* lookup: look for s in hashtab */
|
/* lookup: look for s in hashtable */
|
||||||
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 hashtable */
|
||||||
struct plugin_entry *plugin_load(char *name, dictionary_t config);
|
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*);
|
||||||
|
618
server.c
Normal file
618
server.c
Normal file
@ -0,0 +1,618 @@
|
|||||||
|
#ifndef _GNU_SOURCE
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#endif
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
//#include <limits.h>
|
||||||
|
//#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "server.h"
|
||||||
|
#include "lib/handle.h"
|
||||||
|
#include "plugin_manager.h"
|
||||||
|
#include "lib/scheduler.h"
|
||||||
|
#include "lib/utils.h"
|
||||||
|
#include "decode.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
|
||||||
|
static pthread_mutex_t server_mux = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
config_t g_server_config;
|
||||||
|
|
||||||
|
void *execute_plugin(void *data, const char *pname);
|
||||||
|
void *serve_file(void *data);
|
||||||
|
|
||||||
|
void *accept_request(void *data)
|
||||||
|
{
|
||||||
|
char buf[BUFFLEN];
|
||||||
|
char *token = NULL;
|
||||||
|
char *line = NULL;
|
||||||
|
antd_task_t *task;
|
||||||
|
antd_request_t *rq = (antd_request_t *)data;
|
||||||
|
|
||||||
|
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);
|
||||||
|
// first verify if the socket is ready
|
||||||
|
antd_client_t *client = (antd_client_t *)rq->client;
|
||||||
|
|
||||||
|
struct pollfd pfd[1];
|
||||||
|
|
||||||
|
pfd[0].fd = client->sock;
|
||||||
|
pfd[0].events = POLLIN | POLLOUT;
|
||||||
|
|
||||||
|
int sel = poll(pfd, 1, POLL_EVENT_TO);
|
||||||
|
if (sel == -1)
|
||||||
|
{
|
||||||
|
antd_error(rq->client, 400, "Bad request");
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
if (pfd[0].revents & POLLERR || pfd[0].revents & POLLHUP)
|
||||||
|
{
|
||||||
|
antd_error(rq->client, 400, "Bad request");
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
if (sel == 0 || (!(pfd[0].revents & POLLIN) && !(pfd[0].revents & POLLOUT)))
|
||||||
|
{
|
||||||
|
task->handle = accept_request;
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
// perform the ssl handshake if enabled
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
|
int ret = -1, stat;
|
||||||
|
if (client->ssl && client->state == ANTD_CLIENT_ACCEPT)
|
||||||
|
{
|
||||||
|
// LOG("Atttempt %d\n", client->attempt);
|
||||||
|
if (SSL_accept((SSL *)client->ssl) == -1)
|
||||||
|
{
|
||||||
|
stat = SSL_get_error((SSL *)client->ssl, ret);
|
||||||
|
switch (stat)
|
||||||
|
{
|
||||||
|
case SSL_ERROR_WANT_READ:
|
||||||
|
case SSL_ERROR_WANT_WRITE:
|
||||||
|
case SSL_ERROR_NONE:
|
||||||
|
task->handle = accept_request;
|
||||||
|
return task;
|
||||||
|
default:
|
||||||
|
ERROR("Error performing SSL handshake %d %d %s", stat, ret, ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
antd_error(rq->client, 400, "Invalid SSL request");
|
||||||
|
// server_config.connection++;
|
||||||
|
ERR_print_errors_fp(stderr);
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
client->state = ANTD_CLIENT_HANDSHAKE;
|
||||||
|
task->handle = accept_request;
|
||||||
|
// LOG("Handshake finish for %d\n", client->sock);
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!((pfd[0].revents & POLLIN)))
|
||||||
|
{
|
||||||
|
task->handle = accept_request;
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// LOG("Ready for reading %d\n", client->sock);
|
||||||
|
// server_config.connection++;
|
||||||
|
client->state = ANTD_CLIENT_PROTO_CHECK;
|
||||||
|
read_buf(rq->client, buf, sizeof(buf));
|
||||||
|
line = buf;
|
||||||
|
LOG("Request (%d): %s", rq->client->sock, line);
|
||||||
|
// get the method string
|
||||||
|
token = strsep(&line, " ");
|
||||||
|
if (!line)
|
||||||
|
{
|
||||||
|
// LOG("No method found");
|
||||||
|
antd_error(rq->client, 405, "No method found");
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
trim(token, ' ');
|
||||||
|
trim(line, ' ');
|
||||||
|
dput(rq->request, "METHOD", strdup(token));
|
||||||
|
// get the request
|
||||||
|
token = strsep(&line, " ");
|
||||||
|
if (!line)
|
||||||
|
{
|
||||||
|
// LOG("No request found");
|
||||||
|
antd_error(rq->client, 400, "Bad request");
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
trim(token, ' ');
|
||||||
|
trim(line, ' ');
|
||||||
|
trim(line, '\n');
|
||||||
|
trim(line, '\r');
|
||||||
|
dput(rq->request, "PROTOCOL", strdup(line));
|
||||||
|
dput(rq->request, "REQUEST_QUERY", strdup(token));
|
||||||
|
line = token;
|
||||||
|
token = strsep(&line, "?");
|
||||||
|
dput(rq->request, "REQUEST_PATH", url_decode(token));
|
||||||
|
// decode request
|
||||||
|
// now return the task
|
||||||
|
task->handle = decode_request_header;
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *resolve_request(void *data)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
char path[2 * BUFFLEN];
|
||||||
|
antd_request_t *rq = (antd_request_t *)data;
|
||||||
|
antd_task_t *task = antd_create_task(NULL, (void *)rq, NULL, rq->client->last_io);
|
||||||
|
char *url = (char *)dvalue(rq->request, "REQUEST_URI");
|
||||||
|
char *newurl = NULL;
|
||||||
|
char *rqp = NULL;
|
||||||
|
char *oldrqp = NULL;
|
||||||
|
rq->client->state = ANTD_CLIENT_RESOLVE_REQUEST;
|
||||||
|
char * root = (char *)dvalue(rq->request, "SERVER_WWW_ROOT");
|
||||||
|
snprintf(path, sizeof(path), "%s/%s", root, url);
|
||||||
|
LOG("URL is : %s", url);
|
||||||
|
LOG("Resource Path is : %s", path);
|
||||||
|
// if (path[strlen(path) - 1] == '/')
|
||||||
|
// strcat(path, "index.html");
|
||||||
|
if (stat(path, &st) == -1)
|
||||||
|
{
|
||||||
|
free(task);
|
||||||
|
rqp = strdup(url);
|
||||||
|
oldrqp = rqp;
|
||||||
|
trim(rqp, '/');
|
||||||
|
newurl = strsep(&rqp, "/");
|
||||||
|
if (!rqp)
|
||||||
|
rqp = strdup("/");
|
||||||
|
else
|
||||||
|
rqp = strdup(rqp);
|
||||||
|
dput(rq->request, "REQUEST_URI", rqp);
|
||||||
|
dput(rq->request, "RESOURCE_PATH", __s("%s/%s", root,rqp));
|
||||||
|
LOG("Execute plugin %s", newurl);
|
||||||
|
task = execute_plugin(rq, newurl);
|
||||||
|
free(oldrqp);
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (S_ISDIR(st.st_mode))
|
||||||
|
{
|
||||||
|
strcat(path, "/index.html");
|
||||||
|
if (stat(path, &st) == -1)
|
||||||
|
{
|
||||||
|
chain_t it;
|
||||||
|
newurl = NULL;
|
||||||
|
for_each_assoc(it, g_server_config.handlers)
|
||||||
|
{
|
||||||
|
memset(path, 0, sizeof(path));
|
||||||
|
snprintf(path, sizeof(path), "%s/%s/index.%s", root, url, it->key);
|
||||||
|
if (stat(path, &st) == 0)
|
||||||
|
{
|
||||||
|
i = g_server_config.handlers->cap;
|
||||||
|
newurl = path;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!newurl)
|
||||||
|
{
|
||||||
|
antd_error(rq->client, 404, "Resource Not Found");
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dput(rq->request, "RESOURCE_PATH", strdup(path));
|
||||||
|
// check if the mime is supported
|
||||||
|
// if the mime is not supported
|
||||||
|
// find an handler plugin to process it
|
||||||
|
// if the plugin is not found, forbidden access to the file should be sent
|
||||||
|
char *mime_type = mime(path);
|
||||||
|
dput(rq->request, "RESOURCE_MIME", strdup(mime_type));
|
||||||
|
if (strcmp(mime_type, "application/octet-stream") == 0)
|
||||||
|
{
|
||||||
|
char *ex = ext(path);
|
||||||
|
char *h = NULL;
|
||||||
|
if (ex)
|
||||||
|
{
|
||||||
|
h = dvalue(g_server_config.handlers, ex);
|
||||||
|
free(ex);
|
||||||
|
}
|
||||||
|
if (h)
|
||||||
|
{
|
||||||
|
// sprintf(path,"/%s%s",h,url);
|
||||||
|
// LOG("WARNING::::Access octetstream via handle %s", h);
|
||||||
|
// if(execute_plugin(client,buf,method,rq) < 0)
|
||||||
|
// cannot_execute(client);
|
||||||
|
free(task);
|
||||||
|
return execute_plugin(rq, h);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
antd_error(rq->client, 403, "Access forbidden");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// discard all request data
|
||||||
|
dictionary_t headers = (dictionary_t)dvalue(rq->request, "REQUEST_HEADER");
|
||||||
|
if (headers)
|
||||||
|
{
|
||||||
|
char *sclen = (char *)dvalue(headers, "Content-Length");
|
||||||
|
unsigned clen = 0;
|
||||||
|
unsigned read = 0;
|
||||||
|
int count;
|
||||||
|
if (sclen)
|
||||||
|
{
|
||||||
|
clen = atoi(sclen);
|
||||||
|
while (read < clen)
|
||||||
|
{
|
||||||
|
count = antd_recv(rq->client, path, sizeof(path) < clen ? sizeof(path) : clen);
|
||||||
|
if (count <= 0)
|
||||||
|
break;
|
||||||
|
read += count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
antd_task_bind_event(task, rq->client->sock, 0, TASK_EVT_ON_WRITABLE);
|
||||||
|
task->handle = serve_file;
|
||||||
|
}
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *finish_request(void *data)
|
||||||
|
{
|
||||||
|
if (!data)
|
||||||
|
return NULL;
|
||||||
|
destroy_request(data);
|
||||||
|
g_server_config.connection--;
|
||||||
|
LOG("Remaining connection %d", g_server_config.connection);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void *serve_file(void *data)
|
||||||
|
{
|
||||||
|
antd_request_t *rq = (antd_request_t *)data;
|
||||||
|
antd_task_t *task = antd_create_task(NULL, (void *)rq, NULL, rq->client->last_io);
|
||||||
|
char *path = (char *)dvalue(rq->request, "RESOURCE_PATH");
|
||||||
|
char *mime_type = (char *)dvalue(rq->request, "RESOURCE_MIME");
|
||||||
|
rq->client->state = ANTD_CLIENT_SERVE_FILE;
|
||||||
|
struct stat st;
|
||||||
|
int s = stat(path, &st);
|
||||||
|
|
||||||
|
if (s == -1)
|
||||||
|
{
|
||||||
|
antd_error(rq->client, 404, "File not found");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// check if it is modified
|
||||||
|
dictionary_t header = (dictionary_t)dvalue(rq->request, "REQUEST_HEADER");
|
||||||
|
char *last_modif_since = (char *)dvalue(header, "If-Modified-Since");
|
||||||
|
time_t t = st.st_ctime;
|
||||||
|
struct tm tm;
|
||||||
|
if (last_modif_since)
|
||||||
|
{
|
||||||
|
strptime(last_modif_since, "%a, %d %b %Y %H:%M:%S GMT", &tm);
|
||||||
|
t = timegm(&tm);
|
||||||
|
// t = mktime(localtime(&t));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last_modif_since && st.st_ctime == t)
|
||||||
|
{
|
||||||
|
// return the not changed
|
||||||
|
antd_error(rq->client, 304, "");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int size = (int)st.st_size;
|
||||||
|
char ibuf[64];
|
||||||
|
snprintf(ibuf, sizeof(ibuf), "%d", size);
|
||||||
|
antd_response_header_t rhd;
|
||||||
|
rhd.cookie = NULL;
|
||||||
|
rhd.status = 200;
|
||||||
|
rhd.header = dict();
|
||||||
|
dput(rhd.header, "Content-Type", strdup(mime_type));
|
||||||
|
#ifdef USE_ZLIB
|
||||||
|
if (!compressable(mime_type) || rq->client->z_level == ANTD_CNONE)
|
||||||
|
#endif
|
||||||
|
dput(rhd.header, "Content-Length", strdup(ibuf));
|
||||||
|
gmtime_r(&st.st_ctime, &tm);
|
||||||
|
strftime(ibuf, 64, "%a, %d %b %Y %H:%M:%S GMT", &tm);
|
||||||
|
dput(rhd.header, "Last-Modified", strdup(ibuf));
|
||||||
|
dput(rhd.header, "Cache-Control", strdup("no-cache"));
|
||||||
|
antd_send_header(rq->client, &rhd);
|
||||||
|
|
||||||
|
__f(rq->client, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *proxy_monitor(void *data)
|
||||||
|
{
|
||||||
|
antd_request_t *rq = (antd_request_t *)data;
|
||||||
|
rq->client->state = ANTD_CLIENT_PROXY_MONITOR;
|
||||||
|
antd_client_t *proxy = (antd_client_t *)dvalue(rq->request, "PROXY_HANDLE");
|
||||||
|
antd_task_t *task = antd_create_task(NULL, data, NULL, rq->client->last_io);
|
||||||
|
int pret, ret, sz1 = 0, sz2 = 0;
|
||||||
|
char *buf = NULL;
|
||||||
|
buf = (char *)malloc(BUFFLEN);
|
||||||
|
struct pollfd pfd[1];
|
||||||
|
memset(pfd, 0, sizeof(pfd));
|
||||||
|
pfd[0].fd = proxy->sock;
|
||||||
|
pfd[0].events = POLLIN;
|
||||||
|
ret = 1;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
sz1 = antd_recv_upto(rq->client, buf, BUFFLEN);
|
||||||
|
|
||||||
|
if ((sz1 < 0) || (sz1 > 0 && antd_send(proxy, buf, sz1) != sz1))
|
||||||
|
{
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pret = poll(pfd, 1, 0);
|
||||||
|
if (pret < 0)
|
||||||
|
{
|
||||||
|
(void)close(proxy->sock);
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
sz2 = 0;
|
||||||
|
if (pret > 0 && (pfd[0].revents & POLLIN))
|
||||||
|
{
|
||||||
|
sz2 = antd_recv_upto(proxy, buf, BUFFLEN);
|
||||||
|
if (sz2 <= 0 || (sz2 > 0 && antd_send(rq->client, buf, sz2) != sz2))
|
||||||
|
{
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((pret > 0) && (pfd[0].revents & POLLERR ||
|
||||||
|
pfd[0].revents & POLLRDHUP ||
|
||||||
|
pfd[0].revents & POLLHUP ||
|
||||||
|
pfd[0].revents & POLLNVAL))
|
||||||
|
{
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (sz1 > 0 || sz2 > 0);
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
(void)close(proxy->sock);
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pfd[0].revents & POLLIN)
|
||||||
|
{
|
||||||
|
antd_task_bind_event(task, proxy->sock, 0, TASK_EVT_ON_READABLE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
antd_task_bind_event(task, proxy->sock, 50u, TASK_EVT_ON_TIMEOUT);
|
||||||
|
}
|
||||||
|
task->handle = proxy_monitor;
|
||||||
|
task->access_time = rq->client->last_io;
|
||||||
|
|
||||||
|
antd_task_bind_event(task, rq->client->sock, 0, TASK_EVT_ON_READABLE);
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *proxify(void *data)
|
||||||
|
{
|
||||||
|
int sock_fd, size, ret;
|
||||||
|
char *str = NULL;
|
||||||
|
chain_t it;
|
||||||
|
antd_request_t *rq = (antd_request_t *)data;
|
||||||
|
antd_client_t *proxy = NULL;
|
||||||
|
rq->client->state = ANTD_CLIENT_RESOLVE_REQUEST;
|
||||||
|
char *host = dvalue(rq->request, "PROXY_HOST");
|
||||||
|
int port = atoi(dvalue(rq->request, "PROXY_PORT"));
|
||||||
|
char *path = dvalue(rq->request, "PROXY_PATH");
|
||||||
|
char *query = dvalue(rq->request, "PROXY_QUERY");
|
||||||
|
char *ptr, *ip;
|
||||||
|
dictionary_t xheader = dvalue(rq->request, "REQUEST_HEADER");
|
||||||
|
antd_task_t *task = antd_create_task(NULL, data, NULL, rq->client->last_io);
|
||||||
|
if (!xheader)
|
||||||
|
{
|
||||||
|
antd_error(rq->client, 400, "Badd Request");
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
pthread_mutex_lock(&server_mux);
|
||||||
|
ip = NULL;
|
||||||
|
// ip_from_host is not threadsafe, need to lock it
|
||||||
|
ptr = ip_from_hostname(host);
|
||||||
|
if (ptr)
|
||||||
|
{
|
||||||
|
ip = strdup(ptr);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&server_mux);
|
||||||
|
|
||||||
|
if (!ip)
|
||||||
|
{
|
||||||
|
antd_error(rq->client, 502, "Badd address");
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
// TODO support ipv6
|
||||||
|
sock_fd = antd_request_socket(ip, port);
|
||||||
|
free(ip);
|
||||||
|
if (sock_fd == -1)
|
||||||
|
{
|
||||||
|
antd_error(rq->client, 503, "Service Unavailable");
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
set_nonblock(sock_fd);
|
||||||
|
/*struct timeval timeout;
|
||||||
|
timeout.tv_sec = 2;
|
||||||
|
timeout.tv_usec = 0; //POLL_EVENT_TO*1000;
|
||||||
|
if (setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0)
|
||||||
|
{
|
||||||
|
ERROR("setsockopt failed:%s", strerror(errno));
|
||||||
|
antd_error(rq->client, 500, "Internal proxy error");
|
||||||
|
(void)close(sock_fd);
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setsockopt(sock_fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout)) < 0)
|
||||||
|
{
|
||||||
|
ERROR("setsockopt failed:%s", strerror(errno));
|
||||||
|
antd_error(rq->client, 500, "Internal proxy error");
|
||||||
|
(void)close(sock_fd);
|
||||||
|
return task;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
proxy = (antd_client_t *)malloc(sizeof(antd_client_t));
|
||||||
|
proxy->sock = sock_fd;
|
||||||
|
proxy->ssl = NULL;
|
||||||
|
proxy->zstream = NULL;
|
||||||
|
proxy->z_level = ANTD_CNONE;
|
||||||
|
time(&proxy->last_io);
|
||||||
|
|
||||||
|
// store content length here
|
||||||
|
dput(rq->request, "PROXY_HANDLE", proxy);
|
||||||
|
|
||||||
|
str = __s("%s %s?%s HTTP/1.1\r\n", (char *)dvalue(rq->request, "METHOD"), path, query);
|
||||||
|
size = strlen(str);
|
||||||
|
ret = antd_send(proxy, str, size);
|
||||||
|
free(str);
|
||||||
|
if (ret != size)
|
||||||
|
{
|
||||||
|
antd_error(rq->client, 500, "");
|
||||||
|
(void)close(sock_fd);
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
for_each_assoc(it, xheader)
|
||||||
|
{
|
||||||
|
str = __s("%s: %s\r\n", it->key, (char *)it->value);
|
||||||
|
size = strlen(str);
|
||||||
|
ret = antd_send(proxy, str, size);
|
||||||
|
free(str);
|
||||||
|
if (ret != size)
|
||||||
|
{
|
||||||
|
antd_error(rq->client, 500, "");
|
||||||
|
(void)close(sock_fd);
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(void)antd_send(proxy, "\r\n", 2);
|
||||||
|
// now monitor the proxy
|
||||||
|
task->handle = proxy_monitor;
|
||||||
|
task->access_time = rq->client->last_io;
|
||||||
|
// register event
|
||||||
|
antd_task_bind_event(task, proxy->sock, 0, TASK_EVT_ON_READABLE | TASK_EVT_ON_WRITABLE);
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a plugin based on the http requeset
|
||||||
|
* First decode the http request header to find the correct plugin
|
||||||
|
* and the correct function on the plugin
|
||||||
|
* Second, decode all parameters necessary of the request and pass it
|
||||||
|
* to the callback function.
|
||||||
|
* Execute the callback function if sucess
|
||||||
|
* @param client soket client
|
||||||
|
* @param path request path
|
||||||
|
* @param method request method
|
||||||
|
* @param query_string GET query string
|
||||||
|
* @return -1 if failure
|
||||||
|
* 1 if sucess
|
||||||
|
*/
|
||||||
|
void *execute_plugin(void *data, const char *pname)
|
||||||
|
{
|
||||||
|
void *(*fn)(void *);
|
||||||
|
plugin_header_t *(*metafn)();
|
||||||
|
plugin_header_t *meta = NULL;
|
||||||
|
struct plugin_entry *plugin;
|
||||||
|
char *error;
|
||||||
|
char pattern[256];
|
||||||
|
|
||||||
|
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_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(g_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);
|
||||||
|
rq->client->state = ANTD_CLIENT_PLUGIN_EXEC;
|
||||||
|
// load the plugin
|
||||||
|
pthread_mutex_lock(&server_mux);
|
||||||
|
plugin = plugin_load((char *)pname, dvalue(g_server_config.plugins, pname));
|
||||||
|
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
|
||||||
|
metafn = (plugin_header_t * (*)()) dlsym(plugin->handle, "meta");
|
||||||
|
if ((error = dlerror()) == NULL)
|
||||||
|
{
|
||||||
|
meta = metafn();
|
||||||
|
}
|
||||||
|
// load the function
|
||||||
|
fn = (void *(*)(void *))dlsym(plugin->handle, PLUGIN_HANDLER);
|
||||||
|
if ((error = dlerror()) != NULL)
|
||||||
|
{
|
||||||
|
ERROR("Problem when finding %s method from %s : %s", PLUGIN_HANDLER, pname, error);
|
||||||
|
antd_error(rq->client, 503, "Requested service not found");
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
// check if we need the raw data or not
|
||||||
|
if (meta && meta->raw_body == 1)
|
||||||
|
{
|
||||||
|
task->handle = fn;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
free(task);
|
||||||
|
task = antd_create_task(decode_post_request, (void *)rq, fn, rq->client->last_io);
|
||||||
|
}
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
dictionary_t mimes_list()
|
||||||
|
{
|
||||||
|
return g_server_config.mimes;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_ZLIB
|
||||||
|
int compressable(char *ctype)
|
||||||
|
{
|
||||||
|
if (!g_server_config.gzip_enable || g_server_config.gzip_types == NULL)
|
||||||
|
return 0;
|
||||||
|
item_t it;
|
||||||
|
list_for_each(it, g_server_config.gzip_types)
|
||||||
|
{
|
||||||
|
if (it->type == LIST_TYPE_POINTER && it->value.ptr && regex_match((const char *)it->value.ptr, ctype, 0, NULL))
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user