Project

General

Profile

Feature #2297 ยป lighttpd-1.4.28-dbi.patch

ver, 2011-02-14 08:50

View differences:

lighttpd-1.4.28-dbi/configure.ac 2011-02-13 20:58:11.860358947 -0700
AC_SUBST(MYSQL_LIBS)
AC_SUBST(MYSQL_INCLUDE)
dnl Checks for libdbi library for vhost-by-database storage.
DBI_INCLUDE=""
DBI_LIBS=""
AC_MSG_CHECKING(for LibDBI support)
AC_ARG_WITH(dbi,
AC_HELP_STRING([--with-dbi@<:@=PATH@:>@],[Include DBI support in PATH/include/dbi.h and PATH/lib]),
[WITH_DBI=$withval],[WITH_DBI=no])
if test "$WITH_DBI" != "no"; then
AC_MSG_RESULT(yes)
if test "$WITH_DBI" != "yes"; then
DBI_CFLAGS="-I$WITH_LIBDBI/include"
DBI_LIBS="-L$WITH_LIBDBI/lib -ldbi"
else
AC_CHECK_HEADERS([dbi/dbi.h],[
AC_CHECK_LIB([dbi], [dbi_version], [
DBI_CFLAGS=""
DBI_LIBS="-ldbi"
],[
AC_MSG_ERROR([LibDBI not found])
]
)],[
AC_MSG_ERROR([LibDBI not found])
]
)
fi
AC_DEFINE([HAVE_DBI], [1], [LibDBI support])
else
AC_MSG_RESULT(no)
fi
AC_SUBST(DBI_LIBS)
AC_SUBST(DBI_CFLAGS)
dnl Check for LDAP
AC_MSG_CHECKING(for LDAP support)
AC_ARG_WITH(ldap, AC_HELP_STRING([--with-ldap],[enable LDAP support]),
......
do_build="$do_build $plugins"
else
no_build="$no_build $plugins"
fi
plugins="mod_dbi_vhost"
if test ! "x$DBI_LIBS" = x; then
do_build="$do_build $plugins"
else
no_build="$no_build $plugins"
fi
plugins="mod_cml mod_magnet"
lighttpd-1.4.28-dbi/src/Makefile.am 2011-02-13 20:57:38.324347972 -0700
mod_mysql_vhost_la_LIBADD = $(MYSQL_LIBS) $(common_libadd)
mod_mysql_vhost_la_CPPFLAGS = $(MYSQL_INCLUDE)
lib_LTLIBRARIES += mod_dbi_vhost.la
mod_dbi_vhost_la_SOURCES = mod_dbi_vhost.c
mod_dbi_vhost_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_dbi_vhost_la_LIBADD = $(DBI_LIBS) $(common_libadd)
mod_dbi_vhost_la_CFLAGS = $(DBI_CFLAGS)
lib_LTLIBRARIES += mod_cgi.la
mod_cgi_la_SOURCES = mod_cgi.c
mod_cgi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
lighttpd-1.4.28-dbi/src/mod_dbi_vhost.c 2011-02-14 00:09:54.048358228 -0700
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <strings.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_DBI
#include <dbi/dbi.h>
#endif
#include "plugin.h"
#include "log.h"
#include "stat_cache.h"
#ifdef DEBUG_MOD_DBI_VHOST
#define DEBUG
#endif
/*
* Plugin for lighttpd to use DBI
* for domain to directory lookups,
* i.e virtual hosts (vhosts).
*
* Optionally sets fcgi_offset and fcgi_arg
* in preparation for fcgi.c to handle
* per-user fcgi chroot jails.
*/
#ifdef HAVE_DBI
typedef struct {
/* linked list */
array *options;
buffer *dbi_pre;
buffer *dbi_post;
short reconnect_count;
server *srv;
dbi_conn conn;
} plugin_config;
/* global plugin data */
typedef struct {
PLUGIN_DATA;
buffer *tmp_buf;
plugin_config **config_storage;
plugin_config conf;
} plugin_data;
/* per connection plugin data */
typedef struct {
buffer *server_name;
buffer *document_root;
buffer *fcgi_arg;
unsigned fcgi_offset;
} plugin_connection_data;
/* init the plugin data */
INIT_FUNC(mod_dbi_vhost_init) {
plugin_data *p;
p = calloc(1, sizeof(*p));
p->tmp_buf = buffer_init();
return p;
}
/* cleanup the plugin data */
SERVER_FUNC(mod_dbi_vhost_cleanup) {
plugin_data *p = p_d;
UNUSED(srv);
#ifdef DEBUG
log_error_write(srv, __FILE__, __LINE__, "ss",
"mod_dbi_vhost_cleanup", p ? "yes" : "NO");
#endif
if (!p) return HANDLER_GO_ON;
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
if (!s) continue;
dbi_conn_close(s->conn);
array_free(s->options);
free(s);
}
free(p->config_storage);
}
buffer_free(p->tmp_buf);
free(p);
return HANDLER_GO_ON;
}
/* handle the plugin per connection data */
static void* mod_dbi_vhost_connection_data(server *srv, connection *con, void *p_d)
{
plugin_data *p = p_d;
plugin_connection_data *c = con->plugin_ctx[p->id];
UNUSED(srv);
#ifdef DEBUG
log_error_write(srv, __FILE__, __LINE__, "ss",
"mod_dbi_connection_data", c ? "old" : "NEW");
#endif
if (c) return c;
c = calloc(1, sizeof(*c));
c->server_name = buffer_init();
c->document_root = buffer_init();
c->fcgi_arg = buffer_init();
c->fcgi_offset = 0;
return con->plugin_ctx[p->id] = c;
}
/* used to reconnect to the database when we get disconnected. */
void mod_dbi_error_callback(dbi_conn conn, void *udata) {
plugin_config *s = (plugin_config *)udata;
if (s->reconnect_count++ < 3) {
// retry our connection.
dbi_conn_connect(conn);
} else {
const char *errormsg = NULL;
dbi_conn_error(s->conn, &errormsg);
log_error_write(s->srv, __FILE__, __LINE__, "ss",
"mod_dbi_error_callback", errormsg);
}
}
/* destroy the plugin per connection data */
CONNECTION_FUNC(mod_dbi_vhost_handle_connection_close) {
plugin_data *p = p_d;
plugin_connection_data *c = con->plugin_ctx[p->id];
UNUSED(srv);
#ifdef DEBUG
log_error_write(srv, __FILE__, __LINE__, "ss",
"mod_dbi_vhost_handle_connection_close", c ? "yes" : "NO");
#endif
if (!c) return HANDLER_GO_ON;
buffer_free(c->server_name);
buffer_free(c->document_root);
buffer_free(c->fcgi_arg);
c->fcgi_offset = 0;
free(c);
con->plugin_ctx[p->id] = NULL;
return HANDLER_GO_ON;
}
/* set configuration values */
SERVER_FUNC(mod_dbi_vhost_set_defaults) {
plugin_data *p = p_d;
char *qmark;
size_t i = 0, j;
config_values_t cv[] = {
{ "vhost.dbi", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_SERVER },
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
/* required, not passed to driver instance. */
buffer *sql = NULL;
buffer *dbtype = NULL;
/* required and passed to driver instance. */
buffer *dbase = NULL;
s = calloc(1, sizeof(plugin_config));
s->options = array_init();
cv[0].destination = s->options;
s->conn = NULL;
s->reconnect_count = 0;
s->srv = srv;
s->dbi_pre = buffer_init();
s->dbi_post = buffer_init();
p->config_storage[i] = s;
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
for (j = 0; j < s->options->used; j ++) {
const buffer *opt_name = s->options->data[j]->key;
const data_unset *opt_value = s->options->data[j];
if (opt_name->used && opt_value->type == TYPE_STRING) {
const data_string *value = (const data_string *)opt_value;
if (strcasecmp(opt_name->ptr, "sql") == 0) {
sql = value->value;
} else if (strcasecmp(opt_name->ptr, "dbtype") == 0) {
dbtype = value->value;
} else if (strcasecmp(opt_name->ptr, "dbname") == 0) {
dbase = value->value;
}
}
}
if (sql && sql->used && (qmark = strchr(sql->ptr, '?'))) {
*qmark = '\0';
buffer_copy_string(s->dbi_pre, sql->ptr);
buffer_copy_string(s->dbi_post, qmark+1);
} else if (sql) {
buffer_copy_string_buffer(s->dbi_pre, sql);
}
/* required:
* - dbtype
* - database
*
* optional:
* - username, some databases don't require this (sqlite)
* - password, default: empty
* - socket, default: database type default
* - hostname, if set overrides socket
* - port, default: database default
* - encoding, default: database default
*/
/* must to be set */
if (!buffer_is_empty(dbase) && !buffer_is_empty(dbtype)) {
/* create/initialise database */
if (!buffer_is_empty(dbtype)) {
s->conn = dbi_conn_new(dbtype->ptr);
}
if (!s->conn) {
log_error_write(srv, __FILE__, __LINE__, "s", "dbi_conn_new() failed. Do you have the DBD for this database type installed?");
return HANDLER_ERROR;
}
/* used to automatically reconnect to the database */
dbi_conn_error_handler(s->conn, mod_dbi_error_callback, s);
/* set options */
for (j = 0; j < s->options->used; j ++) {
const buffer *opt_name = s->options->data[j]->key;
if (opt_name->used && opt_name != sql && opt_name != dbtype) {
if (s->options->data[j]->type == TYPE_INTEGER) {
data_integer *di = (data_integer *)s->options->data[j];
dbi_conn_set_option_numeric(s->conn, opt_name->ptr, di->value);
} else if (s->options->data[j]->type == TYPE_STRING) {
data_string *ds = (data_string *)s->options->data[j];
dbi_conn_set_option(s->conn, opt_name->ptr, ds->value->ptr);
}
}
}
if (dbi_conn_connect(s->conn) < 0) {
const char *errmsg;
dbi_conn_error(s->conn, &errmsg);
log_error_write(srv, __FILE__, __LINE__, "ss", "dbi_conn_connect(): Failed to connect: ", errmsg);
return HANDLER_ERROR;
}
#ifdef FD_CLOEXEC
fcntl(dbi_conn_get_socket(s->conn), F_SETFD, FD_CLOEXEC);
#endif
}
}
return HANDLER_GO_ON;
}
#define PATCH(x) \
p->conf.x = s->x;
static int mod_dbi_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
PATCH(dbi_pre);
PATCH(dbi_post);
PATCH(conn);
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
if (buffer_is_equal_string(du->key, CONST_STR_LEN("dbi-vhost.sql"))) {
PATCH(dbi_pre);
PATCH(dbi_post);
}
}
if (s->conn) {
PATCH(conn);
}
}
return 0;
}
#undef PATCH
/* handle document root request */
CONNECTION_FUNC(mod_dbi_vhost_handle_docroot) {
plugin_data *p = p_d;
plugin_connection_data *c;
stat_cache_entry *sce;
dbi_result result = NULL;
const char *errmsg;
unsigned cols;
short try_count = 0;
/* no host specified? */
if (!con->uri.authority->used) return HANDLER_GO_ON;
mod_dbi_vhost_patch_connection(srv, con, p);
if (!p->conf.conn) return HANDLER_GO_ON;
/* sets up connection data if not done yet */
c = mod_dbi_vhost_connection_data(srv, con, p_d);
/* check if cached this connection */
if (c->server_name->used && /* con->uri.authority->used && */
buffer_is_equal(c->server_name, con->uri.authority)) goto GO_ON;
/* build and run SQL query */
buffer_copy_string_buffer(p->tmp_buf, p->conf.dbi_pre);
if (p->conf.dbi_post->used) {
buffer_append_string_buffer(p->tmp_buf, con->uri.authority);
buffer_append_string_buffer(p->tmp_buf, p->conf.dbi_post);
}
/* reset our reconnect-attempt counter, this is a new query. */
p->conf.reconnect_count = 0;
/* point our server handle to this server context so we log correctly. */
p->conf.srv = srv;
TRYAGAIN: result = dbi_conn_query(p->conf.conn, p->tmp_buf->ptr);
if (!result) {
try_count++;
if (try_count < 2) {
goto TRYAGAIN;
}
dbi_conn_error(p->conf.conn, &errmsg);
log_error_write(srv, __FILE__, __LINE__, "s", errmsg);
goto ERR500;
}
cols = dbi_result_get_numfields(result);
if (!dbi_result_next_row(result)) {
/* no such virtual host */
dbi_result_free(result);
return HANDLER_GO_ON;
}
/* sanity check that really is a directory */
buffer_copy_string(p->tmp_buf, dbi_result_get_string_idx(result, 1));
BUFFER_APPEND_SLASH(p->tmp_buf);
if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
goto ERR500;
}
if (!S_ISDIR(sce->st.st_mode)) {
log_error_write(srv, __FILE__, __LINE__, "sb", "Not a directory", p->tmp_buf);
goto ERR500;
}
/* cache the data */
buffer_copy_string_buffer(c->server_name, con->uri.authority);
buffer_copy_string_buffer(c->document_root, p->tmp_buf);
/* fcgi_offset and fcgi_arg are optional */
if (cols > 1) {
const char *field_value = dbi_result_get_string_idx(result, 2);
c->fcgi_offset = atoi(field_value);
if (cols > 2) {
buffer_copy_string(c->fcgi_arg, dbi_result_get_string_idx(result, 3));
} else {
c->fcgi_arg->used = 0;
}
} else {
c->fcgi_offset = c->fcgi_arg->used = 0;
}
dbi_result_free(result);
/* fix virtual server and docroot */
GO_ON: buffer_copy_string_buffer(con->server_name, c->server_name);
buffer_copy_string_buffer(con->physical.doc_root, c->document_root);
#ifdef DEBUG
log_error_write(srv, __FILE__, __LINE__, "sbbdb",
result ? "NOT CACHED" : "cached",
con->server_name, con->physical.doc_root,
c->fcgi_offset, c->fcgi_arg);
#endif
return HANDLER_GO_ON;
ERR500: if (result) dbi_result_free(result);
con->http_status = 500; /* Internal Error */
con->mode = DIRECT;
return HANDLER_FINISHED;
}
/* this function is called at dlopen() time and inits the callbacks */
int mod_dbi_vhost_plugin_init(plugin *p);
int mod_dbi_vhost_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("dbi_vhost");
p->init = mod_dbi_vhost_init;
p->cleanup = mod_dbi_vhost_cleanup;
p->connection_reset = mod_dbi_vhost_handle_connection_close;
p->set_defaults = mod_dbi_vhost_set_defaults;
p->handle_docroot = mod_dbi_vhost_handle_docroot;
dbi_initialize(NULL);
return 0;
}
#else
/* we don't have mysql support, this plugin does nothing */
int mod_dbi_vhost_plugin_init(plugin *p);
int mod_dbi_vhost_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("dbi_vhost");
return 0;
}
#endif
    (1-1/1)