From 95f63fc0cf629258263498618f4f2265dd63a6a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Tue, 4 Jun 2013 17:13:58 +0200 Subject: [PATCH] [core] add global named fetch pool; all backends have to return strings. implement a simple backend. --- include/lighttpd/base.h | 1 + include/lighttpd/server.h | 9 +++ include/lighttpd/utils.h | 5 ++ src/main/plugin_core.c | 145 ++++++++++++++++++++++++++++++++++++++ src/main/server.c | 36 ++++++++++ 5 files changed, 196 insertions(+) diff --git a/include/lighttpd/base.h b/include/lighttpd/base.h index f2b5824..8472849 100644 --- a/include/lighttpd/base.h +++ b/include/lighttpd/base.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include diff --git a/include/lighttpd/server.h b/include/lighttpd/server.h index 297d934..16985fd 100644 --- a/include/lighttpd/server.h +++ b/include/lighttpd/server.h @@ -99,6 +99,10 @@ struct liServer { GMutex *action_mutex; /** used to synchronize action creation/destruction */ + /** const gchar* => (liFetchDatabase*), database must return GString* entries */ + GHashTable *fetch_backends; + GMutex *fetch_backends_mutex; + gboolean exiting; /** atomic access */ liLogServerData logs; @@ -152,4 +156,9 @@ LI_API void li_server_state_wait(liServer *srv, liServerStateWait *sw); */ LI_API void li_server_register_prepare_cb(liServer *srv, liServerPrepareCallbackCB cb, gpointer data); +/* will acquire a new reference itself if needed. returns TRUE if db was inserted */ +LI_API gboolean li_server_register_fetch_database(liServer *srv, const gchar *name, liFetchDatabase *db); +/* returns a new reference */ +LI_API liFetchDatabase* li_server_get_fetch_database(liServer *srv, const gchar *name); + #endif diff --git a/include/lighttpd/utils.h b/include/lighttpd/utils.h index 9abbebd..617d23f 100644 --- a/include/lighttpd/utils.h +++ b/include/lighttpd/utils.h @@ -83,6 +83,7 @@ LI_API void li_safe_crypt(GString *dest, const GString *password, const GString INLINE GString* _li_g_string_append_len(GString *s, const gchar *val, gssize len); INLINE void li_g_string_clear(GString *s); +INLINE void li_g_string_free(gpointer data); /* src will be empty after the merge, and dest' = dest (++) src */ LI_API void li_g_queue_merge(GQueue *dest, GQueue *src); @@ -146,4 +147,8 @@ INLINE void li_g_string_clear(GString *s) { s->str[0] = '\0'; } +INLINE void li_g_string_free(gpointer data) { + g_string_free((GString*) data, TRUE); +} + #endif diff --git a/src/main/plugin_core.c b/src/main/plugin_core.c index 801af01..12dd5f4 100644 --- a/src/main/plugin_core.c +++ b/src/main/plugin_core.c @@ -1856,6 +1856,150 @@ static liAction* core_map(liServer *srv, liWorker *wrk, liPlugin* p, liValue *va return li_action_new_function(core_handle_map, NULL, core_map_free, md); } +static void fetch_files_static_lookup(liFetchDatabase* db, gpointer data, liFetchEntry *entry) { + GHashTable *stringdb = (GHashTable*) data; + UNUSED(db); + entry->data = g_hash_table_lookup(stringdb, entry->key); + li_fetch_entry_ready(entry); +} +static gboolean fetch_files_static_revalidate(liFetchDatabase* db, gpointer data, liFetchEntry *entry) { + UNUSED(db); UNUSED(data); UNUSED(entry); + return TRUE; +} +static void fetch_files_static_refresh(liFetchDatabase* db, gpointer data, liFetchEntry *cur_entry, liFetchEntry *new_entry) { + UNUSED(db); UNUSED(data); UNUSED(cur_entry); + li_fetch_entry_refresh_skip(new_entry); +} +static void fetch_files_static_free_db(gpointer data) { + GHashTable *stringdb = (GHashTable*) data; + g_hash_table_destroy(stringdb); +} + +static const liFetchCallbacks fetch_files_static_callbacks = { + fetch_files_static_lookup, + fetch_files_static_revalidate, + fetch_files_static_refresh, + /* fetch_files_static_free_entry */ NULL, + fetch_files_static_free_db +}; + +static gboolean core_register_fetch_files_static(liServer *srv, liPlugin* p, liValue *val, gpointer userdata) { + const gchar *name; + gchar *wildcard, *tmp; + const gchar *_entry; + GString *pattern; + GString *basedir = NULL, *subfile = NULL; + GString *prefix = NULL, *suffix = NULL; + GString *filename = NULL; + GDir *dir = NULL; + GError *err = NULL; + gboolean result = FALSE; + GHashTable *stringdb = NULL; + liFetchDatabase *db = NULL; + UNUSED(p); UNUSED(userdata); + + if (LI_VALUE_LIST != val->type || 2 != val->data.list->len + || LI_VALUE_STRING != g_array_index(val->data.list, liValue*, 0)->type + || LI_VALUE_STRING != g_array_index(val->data.list, liValue*, 1)->type) { + ERROR(srv, "%s", "fetch.files_static expects a two strings as parameter: \"\" => \"/path/abc_*.d/file\""); + goto out; + } + + name = g_array_index(val->data.list, liValue*, 0)->data.string->str; + pattern = g_array_index(val->data.list, liValue*, 1)->data.string; + + wildcard = strchr(pattern->str, '*'); + if (NULL == wildcard || NULL != strchr(wildcard + 1, '*')) { + ERROR(srv, "%s", "fetch.files_static file pattern doesn't contain exactly one wildcard"); + goto out; + } + + for (tmp = wildcard; tmp >= pattern->str; --tmp) { + if ('/' == *tmp) break; + } + if (tmp >= pattern->str) { /* found '/' before '*' */ + basedir = g_string_new_len(pattern->str, tmp - pattern->str); + prefix = g_string_new_len(tmp + 1, wildcard - tmp - 1); + } else { + prefix = g_string_new_len(pattern->str, wildcard - pattern->str); + } + if (NULL != (tmp = strchr(wildcard, '/'))) { + subfile = g_string_new(tmp); + suffix = g_string_new_len(wildcard + 1, tmp - wildcard - 1); + } else { + suffix = g_string_new(wildcard + 1); + } + + filename = g_string_sized_new(127); + dir = g_dir_open(NULL != basedir ? basedir->str : ".", 0, &err); + if (NULL == dir) { + ERROR(srv, "fetch.files_static: couldn't open basedir '%s': %s", NULL != basedir ? basedir->str : ".", err->message); + goto out; + } + + stringdb = g_hash_table_new_full((GHashFunc) g_string_hash, (GEqualFunc) g_string_equal, li_g_string_free, li_g_string_free); + while (NULL != (_entry = g_dir_read_name(dir))) { + GString entry = li_const_gstring(_entry, strlen(_entry)); + if (entry.len <= prefix->len + suffix->len) continue; + if (li_string_prefix(&entry, GSTR_LEN(prefix)) && li_string_suffix(&entry, GSTR_LEN(suffix))) { + GString *key; + GString *file; + gchar *file_contents; + gsize file_len; + + g_string_truncate(filename, 0); + if (NULL != basedir) { + g_string_append_len(filename, GSTR_LEN(basedir)); + li_path_append_slash(filename); + } + g_string_append_len(filename, GSTR_LEN(&entry)); + if (NULL != subfile) { + li_path_append_slash(filename); + g_string_append_len(filename, GSTR_LEN(subfile)); + } + + if (!g_file_test(filename->str, G_FILE_TEST_IS_REGULAR)) continue; + + if (!g_file_get_contents(filename->str, &file_contents, &file_len, &err)) { + ERROR(srv, "fetch.files_static: couldn't read file '%s': %s", filename->str, err->message); + goto out; + } + + key = g_string_new_len(entry.str + prefix->len, entry.len - prefix->len - suffix->len); + file = g_string_new_len(file_contents, file_len); + g_free(file_contents); + + g_hash_table_insert(stringdb, key, file); + } + } + + db = li_fetch_database_new(&fetch_files_static_callbacks, stringdb, g_hash_table_size(stringdb), 0); + stringdb = NULL; /* now owned by db */ + + if (!li_server_register_fetch_database(srv, name, db)) { + ERROR(srv, "fetch.files_static: duplicate name: can't register another backend for name '%s'", name); + goto out; + } + + result = TRUE; + +out: + if (NULL != basedir) g_string_free(basedir, TRUE); + if (NULL != subfile) g_string_free(basedir, TRUE); + if (NULL != prefix) g_string_free(prefix, TRUE); + if (NULL != suffix) g_string_free(suffix, TRUE); + if (NULL != filename) g_string_free(filename, TRUE); + if (NULL != dir) g_dir_close(dir); + if (NULL != err) g_error_free(err); + if (NULL != stringdb) g_hash_table_destroy(stringdb); + if (NULL != db) li_fetch_database_release(db); + return result; +} + + + + + static void core_warmup(liServer *srv, liPlugin *p, gint32 id, GString *data) { UNUSED(p); UNUSED(id); @@ -1956,6 +2100,7 @@ static const liPluginSetup setups[] = { { "tasklet_pool.threads", core_tasklet_pool_threads, NULL }, { "log", core_setup_log, NULL }, { "log.timestamp", core_setup_log_timestamp, NULL }, + { "fetch.files_static", core_register_fetch_files_static, NULL }, { NULL, NULL, NULL } }; diff --git a/src/main/server.c b/src/main/server.c index e31f5ed..e61e922 100644 --- a/src/main/server.c +++ b/src/main/server.c @@ -60,6 +60,10 @@ static void server_setup_free(gpointer _ss) { g_slice_free(liServerSetup, _ss); } +static void server_fetch_db_free(gpointer db) { + li_fetch_database_release((liFetchDatabase*) db); +} + static void sigint_cb(liEventBase *watcher, int events) { liEventSignal *sig = li_event_signal_from(watcher); liEventLoop *loop = li_event_get_loop(sig); @@ -117,6 +121,9 @@ liServer* li_server_new(const gchar *module_dir, gboolean module_resident) { srv->action_mutex = g_mutex_new(); + srv->fetch_backends = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, server_fetch_db_free); + srv->fetch_backends_mutex = g_mutex_new(); + srv->exiting = FALSE; srv->ts_formats = g_array_new(FALSE, TRUE, sizeof(GString*)); @@ -228,6 +235,8 @@ void li_server_free(liServer* srv) { g_ptr_array_free(srv->sockets, TRUE); } + g_hash_table_remove_all(srv->fetch_backends); + /* release modules */ li_modules_free(srv->modules); @@ -264,6 +273,9 @@ void li_server_free(liServer* srv) { srv->prepare_callbacks = NULL; } + g_hash_table_destroy(srv->fetch_backends); + g_mutex_free(srv->fetch_backends_mutex); + g_mutex_free(srv->action_mutex); #ifdef LIGHTY_OS_LINUX @@ -914,3 +926,27 @@ void li_server_register_prepare_cb(liServer *srv, liServerPrepareCallbackCB cb, g_array_append_val(srv->prepare_callbacks, cbd); } } + +gboolean li_server_register_fetch_database(liServer *srv, const gchar *name, liFetchDatabase *db) { + gboolean inserted = FALSE; + + g_mutex_lock(srv->fetch_backends_mutex); + if (NULL == g_hash_table_lookup(srv->fetch_backends, name)) { + inserted = TRUE; + li_fetch_database_acquire(db); + g_hash_table_insert(srv->fetch_backends, g_strdup(name), db); + } + g_mutex_unlock(srv->fetch_backends_mutex); + return inserted; +} + +liFetchDatabase* li_server_get_fetch_database(liServer *srv, const gchar *name) { + liFetchDatabase *db; + + g_mutex_lock(srv->fetch_backends_mutex); + if (NULL != (db = g_hash_table_lookup(srv->fetch_backends, name))) { + li_fetch_database_acquire(db); + } + g_mutex_unlock(srv->fetch_backends_mutex); + return db; +}