summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/array.h2
-rw-r--r--src/base.h143
-rw-r--r--src/buffer.h3
-rw-r--r--src/configfile-glue.c320
-rw-r--r--src/configfile.c197
-rw-r--r--src/configfile.h33
-rw-r--r--src/connections-glue.c2
-rw-r--r--src/connections.c63
-rw-r--r--src/fdevent_solaris_devpoll.c5
-rw-r--r--src/fdevent_solaris_port.c2
-rw-r--r--src/http-header-glue.c37
-rw-r--r--src/http_header.c25
-rw-r--r--src/http_kv.c2
-rw-r--r--src/mod_access.c257
-rw-r--r--src/mod_accesslog.c895
-rw-r--r--src/mod_alias.c241
-rw-r--r--src/mod_auth.c271
-rw-r--r--src/mod_authn_file.c168
-rw-r--r--src/mod_authn_gssapi.c156
-rw-r--r--src/mod_authn_ldap.c520
-rw-r--r--src/mod_authn_mysql.c470
-rw-r--r--src/mod_authn_pam.c129
-rw-r--r--src/mod_authn_sasl.c244
-rw-r--r--src/mod_cgi.c270
-rw-r--r--src/mod_cml.c355
-rw-r--r--src/mod_cml.h31
-rw-r--r--src/mod_cml_lua.c22
-rw-r--r--src/mod_compress.c395
-rw-r--r--src/mod_deflate.c440
-rw-r--r--src/mod_dirlisting.c707
-rw-r--r--src/mod_evasive.c173
-rw-r--r--src/mod_evhost.c345
-rw-r--r--src/mod_expire.c303
-rw-r--r--src/mod_extforward.c632
-rw-r--r--src/mod_fastcgi.c9
-rw-r--r--src/mod_flv_streaming.c169
-rw-r--r--src/mod_geoip.c270
-rw-r--r--src/mod_indexfile.c217
-rw-r--r--src/mod_magnet.c236
-rw-r--r--src/mod_magnet_cache.c12
-rw-r--r--src/mod_magnet_cache.h2
-rw-r--r--src/mod_maxminddb.c404
-rw-r--r--src/mod_mysql_vhost.c407
-rw-r--r--src/mod_openssl.c11
-rw-r--r--src/mod_proxy.c13
-rw-r--r--src/mod_redirect.c242
-rw-r--r--src/mod_rewrite.c35
-rw-r--r--src/mod_rrdtool.c9
-rw-r--r--src/mod_scgi.c9
-rw-r--r--src/mod_secdownload.c316
-rw-r--r--src/mod_setenv.c473
-rw-r--r--src/mod_simple_vhost.c335
-rw-r--r--src/mod_skeleton.c163
-rw-r--r--src/mod_sockproxy.c9
-rw-r--r--src/mod_ssi.c213
-rw-r--r--src/mod_ssi.h12
-rw-r--r--src/mod_staticfile.c212
-rw-r--r--src/mod_status.c269
-rw-r--r--src/mod_trigger_b4_dl.c729
-rw-r--r--src/mod_uploadprogress.c203
-rw-r--r--src/mod_userdir.c558
-rw-r--r--src/mod_usertrack.c341
-rw-r--r--src/mod_vhostdb.c147
-rw-r--r--src/mod_vhostdb_dbi.c166
-rw-r--r--src/mod_vhostdb_ldap.c162
-rw-r--r--src/mod_vhostdb_mysql.c161
-rw-r--r--src/mod_vhostdb_pgsql.c161
-rw-r--r--src/mod_webdav.c404
-rw-r--r--src/mod_wstunnel.c9
-rw-r--r--src/plugin.c370
-rw-r--r--src/plugin.h45
-rw-r--r--src/response.c4
-rw-r--r--src/response.h4
-rw-r--r--src/server.c13
-rw-r--r--src/stream.c6
-rw-r--r--src/stream.h4
-rw-r--r--src/t/test_mod_evhost.c26
-rw-r--r--src/t/test_request.c19
-rw-r--r--tests/fastcgi-10.conf4
-rw-r--r--tests/fastcgi-responder.conf2
-rw-r--r--tests/lighttpd.conf2
81 files changed, 7649 insertions, 7796 deletions
diff --git a/src/array.h b/src/array.h
index 31b50527..cdcf7fe1 100644
--- a/src/array.h
+++ b/src/array.h
@@ -13,7 +13,7 @@ struct data_methods {
void (*print)(const struct data_unset *p, int depth);
};
-typedef enum { TYPE_UNSET, TYPE_STRING, TYPE_OTHER, TYPE_ARRAY, TYPE_INTEGER, TYPE_DONOTUSE, TYPE_CONFIG } data_type_t;
+typedef enum { TYPE_STRING, TYPE_ARRAY, TYPE_INTEGER, TYPE_CONFIG, TYPE_OTHER } data_type_t;
#define DATA_UNSET \
buffer key; \
const struct data_methods *fn; /* function table */ \
diff --git a/src/base.h b/src/base.h
index 5c9efcdc..af95dc30 100644
--- a/src/base.h
+++ b/src/base.h
@@ -36,7 +36,7 @@ typedef struct {
buffer *http_host; /* not alloced */
unsigned int htags; /* bitfield of flagged headers present in request */
- array *headers;
+ array headers;
/* CONTENT */
off_t content_length; /* returned by strtoll() */
@@ -49,7 +49,7 @@ typedef struct {
typedef struct {
off_t content_length;
unsigned int htags; /* bitfield of flagged headers present in response */
- array *headers;
+ array headers;
int send_chunked;
} response;
@@ -243,22 +243,21 @@ struct connection {
off_t bytes_read; /* used by mod_accesslog, mod_rrd */
off_t bytes_header;
- int http_status;
-
sock_addr dst_addr;
buffer *dst_addr_buf;
/* request */
+ int http_status;
+ uint32_t header_len;
+
request request;
request_uri uri;
physical physical;
response response;
- uint32_t header_len;
-
- array *environment; /* used to pass lighttpd internal stuff to the FastCGI/CGI apps, setenv does that */
+ array environment; /* used to pass lighttpd internal stuff to the FastCGI/CGI apps, setenv does that */
- unsigned int mode; /* DIRECT (0) or plugin id */
+ int mode; /* DIRECT (0) or plugin id */
int async_callback;
log_error_st *errh;
@@ -294,7 +293,7 @@ typedef struct {
typedef struct {
time_t mtime; /* the key */
- buffer *str; /* a buffer for the string represenation */
+ buffer str; /* buffer for the string represenation */
} mtime_cache_type;
typedef struct {
@@ -304,54 +303,51 @@ typedef struct {
} buffer_plugin;
typedef struct {
- unsigned short port;
- buffer *bindhost;
-
- buffer *errorlog_file;
- unsigned short errorlog_use_syslog;
- buffer *breakagelog_file;
-
- unsigned short dont_daemonize;
- unsigned short preflight_check;
- buffer *changeroot;
- buffer *username;
- buffer *groupname;
-
- buffer *pid_file;
-
- buffer *event_handler;
-
- buffer *modules_dir;
- buffer *network_backend;
- array *modules;
- array *upload_tempdirs;
- unsigned int upload_temp_file_size;
unsigned int max_request_field_size;
- unsigned short max_worker;
- unsigned short max_fds;
- unsigned short max_conns;
-
- unsigned short log_request_header_on_error;
- unsigned short log_state_handling;
-
- int stat_cache_engine;
- unsigned short enable_cores;
- unsigned short reject_expect_100_with_417;
- buffer *xattr_name;
-
unsigned short http_header_strict;
unsigned short http_host_strict;
unsigned short http_host_normalize;
unsigned short http_url_normalize;
unsigned short http_method_get_body;
unsigned short high_precision_timestamps;
+
+ unsigned short max_worker;
+ unsigned short max_fds;
+ unsigned short max_conns;
+
+ unsigned short log_state_handling;
+ unsigned short log_request_header_on_error;
+ unsigned short port;
+
time_t loadts;
double loadavg[3];
- buffer *syslog_facility;
+ int stat_cache_engine;
+
+ unsigned int upload_temp_file_size;
+ array *upload_tempdirs;
+ buffer *xattr_name;
+
+ unsigned short dont_daemonize;
+ unsigned short preflight_check;
+ unsigned short enable_cores;
+ unsigned short reject_expect_100_with_417; /*(ignored)*/
unsigned short compat_module_load;
unsigned short systemd_socket_activation;
+ unsigned short errorlog_use_syslog;
+ buffer *errorlog_file;
+ buffer *breakagelog_file;
+ buffer *syslog_facility;
+ buffer *bindhost;
+ buffer *changeroot;
+ buffer *username;
+ buffer *groupname;
+ buffer *pid_file;
+ buffer *event_handler;
+ buffer *modules_dir;
+ buffer *network_backend;
+ array *modules;
} server_config;
typedef struct server_socket {
@@ -373,12 +369,20 @@ typedef struct {
} server_socket_array;
struct server {
- server_socket_array srv_sockets;
+ void *plugin_slots;
+ struct stat_cache *stat_cache;
struct fdevents *ev;
+ int (* network_backend_write)(struct server *srv, int fd, chunkqueue *cq, off_t max_bytes);
+ handler_t (* request_env)(struct server *srv, connection *con);
- buffer_plugin plugins;
- void *plugin_slots;
+ /* buffers */
+ buffer *tmp_buf;
+ buffer *tmp_chunk_len;
+
+ connections conns;
+ connections joblist;
+ connections fdwaitqueue;
/* counters */
int con_opened;
@@ -394,41 +398,18 @@ struct server {
uint32_t max_conns;
- /* buffers */
- buffer *tmp_buf;
- buffer *tmp_chunk_len;
-
- /* caches */
- mtime_cache_type mtime_cache[FILE_CACHE_MAX];
-
- log_error_st *errh;
-
/* Timestamps */
time_t cur_ts;
time_t last_generated_date_ts;
time_t last_generated_debug_ts;
- time_t startup_ts;
- buffer *ts_debug_str;
buffer *ts_date_str;
+ log_error_st *errh;
/* config-file */
- array *config_touched;
-
array *config_context;
specific_config **config_storage;
- server_config srvconf;
-
- short int config_deprecated;
- short int config_unsupported;
-
- connections conns;
- connections joblist;
- connections fdwaitqueue;
-
- struct stat_cache *stat_cache;
-
/**
* The status array can carry all the status information you want
* the key to the array is <module-prefix>.<name>
@@ -444,16 +425,26 @@ struct server {
*/
array *status;
- int event_handler;
+ server_config srvconf;
- int (* network_backend_write)(struct server *srv, int fd, chunkqueue *cq, off_t max_bytes);
- handler_t (* request_env)(struct server *srv, connection *con);
+ /* caches */
+ mtime_cache_type mtime_cache[FILE_CACHE_MAX];
+
+ /* members used at start-up or rarely used */
+ server_socket_array srv_sockets;
+ server_socket_array srv_sockets_inherited;
+ buffer_plugin plugins;
+
+ array *config_touched;
+ short int config_deprecated;
+ short int config_unsupported;
+
+ int event_handler;
+ time_t startup_ts;
uid_t uid;
gid_t gid;
pid_t pid;
-
- server_socket_array srv_sockets_inherited;
};
diff --git a/src/buffer.h b/src/buffer.h
index 4f6f9345..ee335597 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -214,7 +214,8 @@ void buffer_append_path_len(buffer *b, const char *a, size_t alen); /* join stri
#define BUFFER_INTLEN_PTR(x) (x)->used ? (int)((x)->used - 1) : 0, (x)->ptr
-#define CONST_STR_LEN(x) x, (x) ? sizeof(x) - 1 : 0
+#define CONST_LEN_STR(x) (uint32_t)sizeof(x)-1, x
+#define CONST_STR_LEN(x) x, (uint32_t)sizeof(x) - 1
#define CONST_BUF_LEN(x) ((x) ? (x)->ptr : NULL), buffer_string_length(x)
diff --git a/src/configfile-glue.c b/src/configfile-glue.c
index 0f1e4e88..22735c2b 100644
--- a/src/configfile-glue.c
+++ b/src/configfile-glue.c
@@ -8,6 +8,7 @@
#include "sock_addr.h"
#include "configfile.h"
+#include "plugin.h"
#include <string.h>
#include <stdlib.h> /* strtol */
@@ -24,6 +25,221 @@
*/
+int config_plugin_values_init(server * const srv, void *p_d, const config_plugin_keys_t * const cpk, const char * const mname) {
+ plugin_data_base * const p = (plugin_data_base *)p_d;
+ array * const touched = srv->config_touched;
+ unsigned char matches[4096]; /*directives matches (4k is way too many!)*/
+ unsigned short contexts[4096]; /*conditions matches (4k is way too many!)*/
+ uint32_t n = 0;
+ int rc = 1; /* default is success */
+ force_assert(sizeof(matches) >= srv->config_context->used);
+
+ /* traverse config contexts twice: once to count, once to store matches */
+
+ for (uint32_t u = 0; u < srv->config_context->used; ++u) {
+ const array *ca =
+ ((data_config const *)srv->config_context->data[u])->value;
+
+ matches[n] = 0;
+ for (int i = 0; cpk[i].ktype != T_CONFIG_UNSET; ++i) {
+ data_unset * const du =
+ array_get_element_klen(ca, cpk[i].k, cpk[i].klen);
+ if (NULL == du) continue; /* not found */
+
+ ++matches[n];
+
+ array_set_key_value(touched,cpk[i].k,cpk[i].klen,CONST_STR_LEN(""));
+
+ if (cpk[i].scope == T_CONFIG_SCOPE_SERVER && 0 != u) {
+ /* server scope options should be set only in server scope */
+ log_error(srv->errh, __FILE__, __LINE__,
+ "DEPRECATED: do not set server options in conditionals, "
+ "variable: %s", cpk[i].k);
+ }
+ }
+ if (matches[n]) contexts[n++] = (unsigned short)u;
+ }
+
+ uint32_t elts = 0;
+ for (uint32_t u = 0; u < n; ++u) elts += matches[u];
+ p->nconfig = n;
+ /*(+1 to include global scope, whether or not any directives exist)*/
+ /*(+n for extra element to end each list)*/
+ p->cvlist = (config_plugin_value_t *)
+ calloc(1+n+n+elts, sizeof(config_plugin_value_t));
+ force_assert(p->cvlist);
+
+ elts = 1+n;
+ /* shift past first element if no directives in global scope */
+ const uint32_t shft = (0 != n && 0 != contexts[0]);
+ if (shft) ++p->nconfig;
+ for (uint32_t u = 0; u < n; ++u) {
+ config_plugin_value_t * const cpv = p->cvlist+shft+u;
+ cpv->k_id = (int)contexts[u];
+ cpv->v.u2[0] = elts;
+ cpv->v.u2[1] = matches[u];
+ elts += matches[u]+1; /* +1 to end list with cpv->k_id = -1 */
+ }
+
+ for (uint32_t u = 0; u < n; ++u) {
+ const array *ca =
+ ((data_config const *)srv->config_context->data[contexts[u]])->value;
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[shft+u].v.u2[0];
+
+ for (int i = 0; cpk[i].ktype != T_CONFIG_UNSET; ++i) {
+ data_unset * const du =
+ array_get_element_klen(ca, cpk[i].k, cpk[i].klen);
+ if (NULL == du) continue; /* not found */
+
+ cpv->k_id = i;
+ cpv->vtype = cpk[i].ktype;
+
+ switch (cpk[i].ktype) {
+ case T_CONFIG_ARRAY:
+ if (du->type == TYPE_ARRAY) {
+ cpv->v.a = &((const data_array *)du)->value;
+ /* future: might provide modifiers to perform one of
+ * array_is_{vlist,kvany,kvarray,kvstring}() tests
+ * and provide generic error message if mismatch */
+ }
+ else {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "%s should have been an array of strings like "
+ "... = ( \"...\" )", cpk[i].k);
+ rc = 0;
+ continue;
+ }
+ break;
+ case T_CONFIG_STRING:
+ if (du->type == TYPE_STRING) {
+ cpv->v.b = &((const data_string *)du)->value;
+ }
+ else {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "%s should have been a string like ... = \"...\"",
+ cpk[i].k);
+ rc = 0;
+ continue;
+ }
+ break;
+ case T_CONFIG_SHORT:
+ switch(du->type) {
+ case TYPE_INTEGER:
+ cpv->v.shrt =
+ (unsigned short)((const data_integer *)du)->value;
+ break;
+ case TYPE_STRING: {
+ /* If the value came from an environment variable, then it
+ * is a data_string, although it may contain a number in
+ * ASCII decimal format. We try to interpret the string as
+ * a decimal short before giving up, in order to support
+ * setting numeric values with environment variables
+ * (e.g. port number).
+ */
+ const char * const v = ((const data_string *)du)->value.ptr;
+ if (v && *v) {
+ char *e;
+ long l = strtol(v, &e, 10);
+ if (e != v && !*e && l >= 0 && l <= 65535) {
+ cpv->v.shrt = (unsigned short)l;
+ break;
+ }
+ }
+ log_error(srv->errh, __FILE__, __LINE__,
+ "got a string but expected a short: %s %s", cpk[i].k, v);
+ rc = 0;
+ continue;
+ }
+ default:
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected type for key: %s %d expected a short integer,"
+ " range 0 ... 65535", cpk[i].k, du->type);
+ rc = 0;
+ continue;
+ }
+ break;
+ case T_CONFIG_INT:
+ switch(du->type) {
+ case TYPE_INTEGER:
+ cpv->v.u = ((const data_integer *)du)->value;
+ break;
+ case TYPE_STRING: {
+ const char * const v = ((const data_string *)du)->value.ptr;
+ if (v && *v) {
+ char *e;
+ long l = strtol(v, &e, 10);
+ if (e != v && !*e && l >= 0) {
+ cpv->v.shrt = (unsigned int)l;
+ break;
+ }
+ }
+ log_error(srv->errh, __FILE__, __LINE__,
+ "got a string but expected an integer: %s %s",cpk[i].k,v);
+ rc = 0;
+ continue;
+ }
+ default:
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected type for key: %s %d expected an integer, "
+ "range 0 ... 4294967295", cpk[i].k, du->type);
+ rc = 0;
+ continue;
+ }
+ break;
+ case T_CONFIG_BOOL:
+ if (du->type == TYPE_STRING) {
+ const buffer *b = &((const data_string *)du)->value;
+ if (buffer_eq_icase_slen(b, CONST_STR_LEN("enable"))
+ || buffer_eq_icase_slen(b, CONST_STR_LEN("true"))) {
+ cpv->v.u = 1;
+ }
+ else if (buffer_eq_icase_slen(b, CONST_STR_LEN("disable"))
+ || buffer_eq_icase_slen(b,CONST_STR_LEN("false"))){
+ cpv->v.u = 0;
+ }
+ else {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "ERROR: unexpected value for key: %s %s "
+ "(enable|disable)", cpk[i].k, b->ptr);
+ rc = 0;
+ continue;
+ }
+ }
+ else if (du->type == TYPE_INTEGER) {
+ cpv->v.u = (0 != ((const data_integer *)du)->value);
+ }
+ else {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "ERROR: unexpected type for key: %s (string) "
+ "\"(enable|disable)\"", cpk[i].k);
+ rc = 0;
+ continue;
+ }
+ break;
+ case T_CONFIG_LOCAL:
+ case T_CONFIG_UNSET:
+ continue;
+ case T_CONFIG_UNSUPPORTED:
+ log_error(srv->errh, __FILE__, __LINE__,
+ "ERROR: found unsupported key: %s (%s)", cpk[i].k, mname);
+ srv->config_unsupported = 1;
+ continue;
+ case T_CONFIG_DEPRECATED:
+ log_error(srv->errh, __FILE__, __LINE__,
+ "ERROR: found deprecated key: %s (%s)", cpk[i].k, mname);
+ srv->config_deprecated = 1;
+ continue;
+ }
+
+ ++cpv;
+ }
+
+ cpv->k_id = -1; /* indicate list end */
+ }
+
+ return rc;
+}
+
/* handle global options */
/* parse config array */
@@ -203,14 +419,45 @@ int config_insert_values_global(server *srv, const array *ca, const config_value
}
__attribute_cold__
-static const char* cond_result_to_string(cond_result_t cond_result) {
- switch (cond_result) {
- case COND_RESULT_UNSET: return "unset";
- case COND_RESULT_SKIP: return "skipped";
- case COND_RESULT_FALSE: return "false";
- case COND_RESULT_TRUE: return "true";
- default: return "invalid cond_result_t";
- }
+__attribute_noinline__
+static void config_cond_result_trace(connection *con, const data_config *dc, int cached) {
+ cond_cache_t * const cache = &con->cond_cache[dc->context_ndx];
+ const char *msg;
+ switch (cache->result) {
+ case COND_RESULT_UNSET: msg = "unset"; break;
+ case COND_RESULT_SKIP: msg = "skipped"; break;
+ case COND_RESULT_FALSE: msg = "false"; break;
+ case COND_RESULT_TRUE: msg = "true"; break;
+ default: msg = "invalid cond_result_t"; break;
+ }
+ log_error(con->errh, __FILE__, __LINE__, "%d (%s) result: %s",
+ dc->context_ndx, "uncached"+(cached ? 2 : 0), msg);
+}
+
+static cond_result_t config_check_cond_nocache(connection *con, const data_config *dc, int debug_cond, cond_cache_t *cache);
+
+static cond_result_t config_check_cond_nocache_calc(connection *con, const data_config *dc, int debug_cond, cond_cache_t *cache) {
+ cache->result = config_check_cond_nocache(con, dc, debug_cond, cache);
+ switch (cache->result) {
+ case COND_RESULT_FALSE:
+ case COND_RESULT_TRUE:
+ /* remember result of local condition for a partial reset */
+ cache->local_result = cache->result;
+ break;
+ default:
+ break;
+ }
+ if (debug_cond) config_cond_result_trace(con, dc, 0);
+ return cache->result;
+}
+
+static cond_result_t config_check_cond_cached(connection *con, const data_config *dc, const int debug_cond) {
+ cond_cache_t * const cache = &con->cond_cache[dc->context_ndx];
+ if (COND_RESULT_UNSET != cache->result) {
+ if (debug_cond) config_cond_result_trace(con, dc, 1);
+ return cache->result;
+ }
+ return config_check_cond_nocache_calc(con, dc, debug_cond, cache);
}
static int config_addrstr_eq_remote_ip_mask(connection *con, const char *addrstr, int nm_bits, sock_addr *rmt) {
@@ -266,9 +513,7 @@ static int config_addrbuf_eq_remote_ip_mask(connection *con, const buffer *strin
static int data_config_pcre_exec(const data_config *dc, cond_cache_t *cache, const buffer *b);
-static cond_result_t config_check_cond_cached(connection *con, const data_config *dc, const int debug_cond);
-
-static cond_result_t config_check_cond_nocache(connection *con, const data_config *dc, const int debug_cond) {
+static cond_result_t config_check_cond_nocache(connection *con, const data_config *dc, const int debug_cond, cond_cache_t * const cache) {
static struct const_char_buffer {
const char *ptr;
uint32_t used;
@@ -335,7 +580,6 @@ static cond_result_t config_check_cond_nocache(connection *con, const data_confi
}
/* if we had a real result before and weren't cleared just return it */
- cond_cache_t * const cache = &con->cond_cache[dc->context_ndx];
switch (cache->local_result) {
case COND_RESULT_TRUE:
case COND_RESULT_FALSE:
@@ -475,32 +719,25 @@ static cond_result_t config_check_cond_nocache(connection *con, const data_confi
return COND_RESULT_FALSE;
}
-static cond_result_t config_check_cond_cached(connection *con, const data_config *dc, const int debug_cond) {
- cond_cache_t * const cache = &con->cond_cache[dc->context_ndx];
- int offset = 2;
-
- if (COND_RESULT_UNSET == cache->result) {
- offset = 0;
- cache->result = config_check_cond_nocache(con, dc, debug_cond);
- switch (cache->result) {
- case COND_RESULT_FALSE:
- case COND_RESULT_TRUE:
- /* remember result of local condition for a partial reset */
- cache->local_result = cache->result;
- break;
- default:
- break;
- }
- }
-
- if (debug_cond) {
- log_error(con->errh, __FILE__, __LINE__, "%d (%s) result: %s",
- dc->context_ndx,
- "uncached"+offset,
- cond_result_to_string(cache->result));
- }
+__attribute_noinline__
+static cond_result_t config_check_cond_calc(connection *con, const int context_ndx, cond_cache_t * const cache) {
+ const data_config * const dc = (const data_config *)
+ con->srv->config_context->data[context_ndx];
+ const int debug_cond = con->conf.log_condition_handling;
+ if (debug_cond) {
+ log_error(con->errh, __FILE__, __LINE__,
+ "=== start of condition block ===");
+ }
+ return config_check_cond_nocache_calc(con, dc, debug_cond, cache);
+}
- return cache->result;
+/* future: might make static inline in header for plugins */
+int config_check_cond(connection * const con, const int context_ndx) {
+ cond_cache_t * const cache = &con->cond_cache[context_ndx];
+ return COND_RESULT_TRUE
+ == (COND_RESULT_UNSET != cache->result
+ ? cache->result
+ : config_check_cond_calc(con, context_ndx, cache));
}
/* if we reset the cache result for a node, we also need to clear all
@@ -567,15 +804,6 @@ void config_cond_cache_reset(server *srv, connection *con) {
}
}
-int config_check_cond(server *srv, connection *con, const data_config *dc) {
- UNUSED(srv);
- const int debug_cond = con->conf.log_condition_handling;
- if (debug_cond) {
- log_error(con->errh, __FILE__, __LINE__, "=== start of condition block ===");
- }
- return (config_check_cond_cached(con, dc, debug_cond) == COND_RESULT_TRUE);
-}
-
#ifdef HAVE_PCRE_H
#include <pcre.h>
#endif
diff --git a/src/configfile.c b/src/configfile.c
index 8fb3754c..f9a0af40 100644
--- a/src/configfile.c
+++ b/src/configfile.c
@@ -667,29 +667,17 @@ static int config_insert(server *srv) {
}
-
-void config_setup_connection(server *srv, connection *con) {
- /* initialize specific_config (con->conf) from top-level specific_config */
- specific_config * const s = srv->config_storage[0];
- const size_t len = /* offsetof() */
- (uintptr_t)&((specific_config *)0)->global_bytes_per_second_cnt_ptr;
- con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
- con->server_name = s->server_name;
- memcpy(&con->conf, s, len);
-}
-
#define PATCH(x) con->conf.x = s->x
void config_patch_connection(server *srv, connection *con) {
size_t i, j;
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
+ if (!config_check_cond(con, i)) continue; /* condition not matched */
+
data_config *dc = (data_config *)srv->config_context->data[i];
specific_config *s = srv->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];
@@ -777,7 +765,7 @@ void config_patch_connection(server *srv, connection *con) {
#undef PATCH
typedef struct {
- const buffer *source;
+ const char *source;
const char *input;
size_t offset;
size_t size;
@@ -791,43 +779,6 @@ typedef struct {
int simulate_eol;
} tokenizer_t;
-#if 0
-static int tokenizer_open(server *srv, tokenizer_t *t, buffer *basedir, const char *fn) {
- if (buffer_string_is_empty(basedir) ||
- (fn[0] == '/' || fn[0] == '\\') ||
- (fn[0] == '.' && (fn[1] == '/' || fn[1] == '\\'))) {
- t->file = buffer_init_string(fn);
- } else {
- t->file = buffer_init_buffer(basedir);
- buffer_append_string(t->file, fn);
- }
-
- if (0 != stream_open(&(t->s), t->file)) {
- log_error_write(srv, __FILE__, __LINE__, "sbss",
- "opening configfile ", t->file, "failed:", strerror(errno));
- buffer_free(t->file);
- return -1;
- }
-
- t->input = t->s.start;
- t->offset = 0;
- t->size = t->s.size;
- t->line = 1;
- t->line_pos = 1;
-
- t->in_key = 1;
- t->in_brace = 0;
- t->in_cond = 0;
- return 0;
-}
-
-static int tokenizer_close(server *srv, tokenizer_t *t) {
- UNUSED(srv);
-
- buffer_free(t->file);
- return stream_close(&(t->s));
-}
-#endif
static int config_skip_newline(tokenizer_t *t) {
int skipped = 1;
force_assert(t->input[t->offset] == '\r' || t->input[t->offset] == '\n');
@@ -849,6 +800,13 @@ static int config_skip_comment(tokenizer_t *t) {
return i;
}
+__attribute_cold__
+static int config_tokenizer_err(server *srv, const char *file, unsigned int line, tokenizer_t *t, const char *msg) {
+ log_error(srv->errh, file, line, "source: %s line: %d pos: %d %s",
+ t->source, t->line, t->line_pos, msg);
+ return -1;
+}
+
static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *token) {
int tid = 0;
size_t i;
@@ -874,11 +832,8 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
tid = TK_ARRAY_ASSIGN;
} else {
- log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
- "source:", t->source,
- "line:", t->line, "pos:", t->line_pos,
+ return config_tokenizer_err(srv, __FILE__, __LINE__, t,
"use => for assignments in arrays");
- return -1;
}
} else if (t->in_cond) {
if (t->input[t->offset + 1] == '=') {
@@ -894,11 +849,8 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
tid = TK_MATCH;
} else {
- log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
- "source:", t->source,
- "line:", t->line, "pos:", t->line_pos,
+ return config_tokenizer_err(srv, __FILE__, __LINE__, t,
"only =~ and == are allowed in the condition");
- return -1;
}
t->in_key = 1;
t->in_cond = 0;
@@ -910,11 +862,8 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
t->offset++;
t->line_pos++;
} else {
- log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
- "source:", t->source,
- "line:", t->line, "pos:", t->line_pos,
+ return config_tokenizer_err(srv, __FILE__, __LINE__, t,
"unexpected equal-sign: =");
- return -1;
}
break;
@@ -933,20 +882,14 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
tid = TK_NOMATCH;
} else {
- log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
- "source:", t->source,
- "line:", t->line, "pos:", t->line_pos,
+ return config_tokenizer_err(srv, __FILE__, __LINE__, t,
"only !~ and != are allowed in the condition");
- return -1;
}
t->in_key = 1;
t->in_cond = 0;
} else {
- log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
- "source:", t->source,
- "line:", t->line, "pos:", t->line_pos,
+ return config_tokenizer_err(srv, __FILE__, __LINE__, t,
"unexpected exclamation-marks: !");
- return -1;
}
break;
@@ -1030,14 +973,8 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
}
if (t->input[t->offset + i] == '\0') {
- /* ERROR */
-
- log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
- "source:", t->source,
- "line:", t->line, "pos:", t->line_pos,
+ return config_tokenizer_err(srv, __FILE__, __LINE__, t,
"missing closing quote");
-
- return -1;
}
t->offset += i + 1;
@@ -1089,12 +1026,8 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
tid = TK_FORCE_ASSIGN;
buffer_copy_string_len(token, CONST_STR_LEN(":="));
} else {
- /* ERROR */
- log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
- "source:", t->source,
- "line:", t->line, "pos:", t->line_pos,
+ return config_tokenizer_err(srv, __FILE__, __LINE__, t,
"unexpected character ':'");
- return -1;
}
break;
@@ -1165,12 +1098,8 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
t->offset += i;
t->line_pos += i;
} else {
- /* ERROR */
- log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
- "source:", t->source,
- "line:", t->line, "pos:", t->line_pos,
+ return config_tokenizer_err(srv, __FILE__, __LINE__, t,
"invalid character in condition");
- return -1;
}
} else if (isdigit((unsigned char)c)) {
/* take all digits */
@@ -1212,12 +1141,8 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
t->offset += i;
t->line_pos += i;
} else {
- /* ERROR */
- log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
- "source:", t->source,
- "line:", t->line, "pos:", t->line_pos,
+ return config_tokenizer_err(srv, __FILE__, __LINE__, t,
"invalid character in variable name");
- return -1;
}
}
break;
@@ -1226,13 +1151,6 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
if (tid) {
*token_id = tid;
-#if 0
- log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd",
- "source:", t->source,
- "line:", t->line, "pos:", t->line_pos,
- token, token->used - 1, tid);
-#endif
-
return 1;
} else if (t->offset < t->size) {
log_error_write(srv, __FILE__, __LINE__, "Dsb", tid, ",", token);
@@ -1240,17 +1158,30 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
return 0;
}
-static int config_parse(server *srv, config_t *context, tokenizer_t *t) {
+static int config_parse(server *srv, config_t *context, const char *source, const char *input, size_t isize) {
void *pParser;
- int token_id;
buffer *token, *lasttoken;
+ int token_id = 0;
int ret;
+ tokenizer_t t;
+
+ t.source = source;
+ t.input = input;
+ t.size = isize;
+ t.offset = 0;
+ t.line = 1;
+ t.line_pos = 1;
+
+ t.in_key = 1;
+ t.in_brace = 0;
+ t.in_cond = 0;
+ t.simulate_eol = 0;
pParser = configparserAlloc( malloc );
force_assert(pParser);
lasttoken = buffer_init();
token = buffer_init();
- while((1 == (ret = config_tokenizer(srv, t, &token_id, token))) && context->ok) {
+ while((1 == (ret = config_tokenizer(srv, &t, &token_id, token))) && context->ok) {
buffer_copy_buffer(lasttoken, token);
configparser(pParser, token_id, token, context);
@@ -1268,13 +1199,12 @@ static int config_parse(server *srv, config_t *context, tokenizer_t *t) {
configparserFree(pParser, free);
if (ret == -1) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "configfile parser failed at:", lasttoken);
+ log_error(srv->errh, __FILE__, __LINE__,
+ "configfile parser failed at: %s", lasttoken->ptr);
} else if (context->ok == 0) {
- log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb",
- "source:", t->source,
- "line:", t->line, "pos:", t->line_pos,
- "parser failed somehow near here:", lasttoken);
+ log_error(srv->errh, __FILE__, __LINE__, "source: %s line: %d pos: %d "
+ "parser failed somehow near here: %s",
+ t.source, t.line, t.line_pos, lasttoken->ptr);
ret = -1;
}
buffer_free(lasttoken);
@@ -1282,43 +1212,22 @@ static int config_parse(server *srv, config_t *context, tokenizer_t *t) {
return ret == -1 ? -1 : 0;
}
-static int tokenizer_init(tokenizer_t *t, const buffer *source, const char *input, size_t size) {
-
- t->source = source;
- t->input = input;
- t->size = size;
- t->offset = 0;
- t->line = 1;
- t->line_pos = 1;
-
- t->in_key = 1;
- t->in_brace = 0;
- t->in_cond = 0;
- t->simulate_eol = 0;
- return 0;
-}
-
-static int config_parse_file_stream(server *srv, config_t *context, const buffer *filename) {
- tokenizer_t t;
+static int config_parse_file_stream(server *srv, config_t *context, const char *fn) {
stream s;
- int ret;
- if (0 != stream_open(&s, filename)) {
- log_error_write(srv, __FILE__, __LINE__, "sbss",
- "opening configfile ", filename, "failed:", strerror(errno));
+ if (0 != stream_open(&s, fn)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "opening configfile %s failed: %s", fn, strerror(errno));
return -1;
- } else {
- tokenizer_init(&t, filename, s.start, s.size);
- ret = config_parse(srv, context, &t);
}
+ int ret = config_parse(srv, context, fn, s.start, (size_t)s.size);
stream_close(&s);
return ret;
}
int config_parse_file(server *srv, config_t *context, const char *fn) {
buffer *filename;
- size_t i;
int ret = -1;
#ifdef GLOB_BRACE
int flags = GLOB_BRACE;
@@ -1338,9 +1247,8 @@ int config_parse_file(server *srv, config_t *context, const char *fn) {
switch (glob(filename->ptr, flags, NULL, &gl)) {
case 0:
- for (i = 0; i < gl.gl_pathc; ++i) {
- buffer_copy_string(filename, gl.gl_pathv[i]);
- ret = config_parse_file_stream(srv, context, filename);
+ for (size_t i = 0; i < gl.gl_pathc; ++i) {
+ ret = config_parse_file_stream(srv, context, gl.gl_pathv[i]);
if (0 != ret) break;
}
globfree(&gl);
@@ -1450,11 +1358,7 @@ int config_parse_cmd(server *srv, config_t *context, const char *cmd) {
}
if (-1 != ret) {
- buffer *source = buffer_init_string(cmd);
- tokenizer_t t;
- tokenizer_init(&t, source, CONST_BUF_LEN(out));
- ret = config_parse(srv, context, &t);
- buffer_free(source);
+ ret = config_parse(srv, context, cmd, CONST_BUF_LEN(out));
}
buffer_free(out);
}
@@ -1488,7 +1392,6 @@ int config_read(server *srv, const char *fn) {
buffer *dcwd;
int ret;
char *pos;
- buffer *filename;
context_init(srv, &context);
context.all_configs = srv->config_context;
@@ -1520,9 +1423,7 @@ int config_read(server *srv, const char *fn) {
array_set_key_value(dc->value, CONST_STR_LEN("var.CWD"), CONST_BUF_LEN(dcwd));
}
- filename = buffer_init_string(fn);
- ret = config_parse_file_stream(srv, &context, filename);
- buffer_free(filename);
+ ret = config_parse_file_stream(srv, &context, fn);
/* remains nothing if parser is ok */
force_assert(!(0 == ret && context.ok && 0 != context.configs_stack.used));
diff --git a/src/configfile.h b/src/configfile.h
index 5f38ba06..b161cf71 100644
--- a/src/configfile.h
+++ b/src/configfile.h
@@ -116,7 +116,6 @@ int config_parse_file(server *srv, config_t *context, const char *fn);
__attribute_cold__
int config_parse_cmd(server *srv, config_t *context, const char *cmd);
-void config_setup_connection(server *srv, connection *con);
void config_patch_connection(server *srv, connection *con);
void config_cond_cache_reset(server *srv, connection *con);
@@ -126,12 +125,13 @@ typedef enum { T_CONFIG_UNSET,
T_CONFIG_STRING,
T_CONFIG_SHORT,
T_CONFIG_INT,
- T_CONFIG_BOOLEAN,
+ T_CONFIG_BOOL,
T_CONFIG_ARRAY,
T_CONFIG_LOCAL,
T_CONFIG_DEPRECATED,
T_CONFIG_UNSUPPORTED
} config_values_type_t;
+#define T_CONFIG_BOOLEAN T_CONFIG_BOOL
typedef enum { T_CONFIG_SCOPE_UNSET,
T_CONFIG_SCOPE_SERVER,
@@ -139,6 +139,33 @@ typedef enum { T_CONFIG_SCOPE_UNSET,
} config_scope_type_t;
typedef struct {
+ int k_id;
+ config_values_type_t vtype;
+ union v_u {
+ void *v;
+ const array *a;
+ const buffer *b;
+ const char *s;
+ unsigned int u;
+ unsigned short int shrt;
+ double d;
+ off_t o;
+ uint32_t u2[2];
+ } v;
+} config_plugin_value_t;
+
+typedef struct {
+ const char *k;
+ uint32_t klen;
+ /*uint32_t k_id;*//*(array index is used for k_id)*/
+ config_values_type_t ktype;
+ config_scope_type_t scope;
+} config_plugin_keys_t;
+
+__attribute_cold__
+int config_plugin_values_init(server *srv, void *p_d, const config_plugin_keys_t *cpk, const char *mname);
+
+typedef struct {
const char *key;
void *destination;
@@ -152,6 +179,6 @@ int config_insert_values_global(server *srv, const array *ca, const config_value
__attribute_cold__
int config_insert_values_internal(server *srv, const array *ca, const config_values_t *cv, config_scope_type_t scope);
-int config_check_cond(server *srv, connection *con, const data_config *dc);
+int config_check_cond(connection *con, int context_ndx);
#endif
diff --git a/src/connections-glue.c b/src/connections-glue.c
index 60fd36fb..11c186e4 100644
--- a/src/connections-glue.c
+++ b/src/connections-glue.c
@@ -503,6 +503,6 @@ void connection_response_reset(server *srv, connection *con) {
buffer_clear(con->physical.etag);
}
con->response.htags = 0;
- array_reset_data_strings(con->response.headers);
+ array_reset_data_strings(&con->response.headers);
http_response_body_clear(con, 0);
}
diff --git a/src/connections.c b/src/connections.c
index e75b48ca..68e01bb7 100644
--- a/src/connections.c
+++ b/src/connections.c
@@ -37,10 +37,6 @@
#define connection_set_state(con, n) ((con)->state = (n))
-typedef struct {
- PLUGIN_DATA;
-} plugin_data;
-
__attribute_cold__
static connection *connection_init(server *srv);
@@ -106,6 +102,19 @@ static int connection_del(server *srv, connection *con) {
return 0;
}
+__attribute_cold__
+static void connection_plugin_ctx_check(server *srv, connection *con) {
+ /* plugins should have cleaned themselves up */
+ for (uint32_t i = 0; i < srv->plugins.used; ++i) {
+ plugin *p = ((plugin **)(srv->plugins.ptr))[i];
+ plugin_data_base *pd = p->data;
+ if (!pd || NULL == con->plugin_ctx[pd->id]) continue;
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "missing cleanup in", p->name);
+ con->plugin_ctx[pd->id] = NULL;
+ }
+}
+
static int connection_close(server *srv, connection *con) {
if (con->fd < 0) con->fd = -con->fd;
@@ -141,12 +150,10 @@ static int connection_close(server *srv, connection *con) {
/* plugins should have cleaned themselves up */
for (uint32_t i = 0; i < srv->plugins.used; ++i) {
- plugin *p = ((plugin **)(srv->plugins.ptr))[i];
- plugin_data *pd = p->data;
- if (!pd || NULL == con->plugin_ctx[pd->id]) continue;
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "missing cleanup in", p->name);
- con->plugin_ctx[pd->id] = NULL;
+ if (NULL != con->plugin_ctx[i]) {
+ connection_plugin_ctx_check(srv, con);
+ break;
+ }
}
connection_del(srv, con);
@@ -263,7 +270,7 @@ static void connection_handle_errdoc_init(connection *con) {
buffer_reset(con->physical.path);
con->response.htags = 0;
- array_reset_data_strings(con->response.headers);
+ array_reset_data_strings(&con->response.headers);
http_response_body_clear(con, 0);
if (NULL != www_auth) {
@@ -528,6 +535,16 @@ static void connection_handle_write_state(server *srv, connection *con) {
}
+static void connection_reset_config(server *srv, connection *con) {
+ /* initialize specific_config (con->conf) from top-level specific_config */
+ specific_config * const s = srv->config_storage[0];
+ const size_t len = /* offsetof() */
+ (uintptr_t)&((specific_config *)0)->global_bytes_per_second_cnt_ptr;
+ con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
+ con->server_name = s->server_name;
+ memcpy(&con->conf, s, len);
+}
+
__attribute_cold__
static connection *connection_init(server *srv) {
@@ -575,10 +592,6 @@ static connection *connection_init(server *srv) {
con->read_queue = chunkqueue_init();
con->request_content_queue = chunkqueue_init();
- con->request.headers = array_init();
- con->response.headers = array_init();
- con->environment = array_init();
-
/* init plugin specific connection structures */
con->plugin_ctx = calloc(1, (srv->plugins.used + 1) * sizeof(void *));
@@ -586,7 +599,7 @@ static connection *connection_init(server *srv) {
con->cond_cache = calloc(srv->config_context->used, sizeof(cond_cache_t));
force_assert(NULL != con->cond_cache);
- config_setup_connection(srv, con);
+ connection_reset_config(srv, con);
return con;
}
@@ -601,9 +614,9 @@ void connections_free(server *srv) {
chunkqueue_free(con->write_queue);
chunkqueue_free(con->read_queue);
chunkqueue_free(con->request_content_queue);
- array_free(con->request.headers);
- array_free(con->response.headers);
- array_free(con->environment);
+ array_free_data(&con->request.headers);
+ array_free_data(&con->response.headers);
+ array_free_data(&con->environment);
#define CLEAN(x) \
buffer_free(con->x);
@@ -680,12 +693,12 @@ static int connection_reset(server *srv, connection *con) {
con->request.htags = 0;
if (con->header_len <= BUFFER_MAX_REUSE_SIZE)
- con->request.headers->used = 0;
+ con->request.headers.used = 0;
else
- array_reset_data_strings(con->request.headers);
+ array_reset_data_strings(&con->request.headers);
con->header_len = 0;
- if (0 != con->environment->used)
- array_reset_data_strings(con->environment);
+ if (0 != con->environment.used)
+ array_reset_data_strings(&con->environment);
chunkqueue_reset(con->request_content_queue);
@@ -697,7 +710,7 @@ static int connection_reset(server *srv, connection *con) {
/*con->error_handler_saved_method = HTTP_METHOD_UNSET;*/
/*(error_handler_saved_method value is not valid unless error_handler_saved_status is set)*/
- config_setup_connection(srv, con);
+ connection_reset_config(srv, con);
return 0;
}
@@ -1223,7 +1236,7 @@ static int connection_handle_request(server *srv, connection *con) {
break;
case HANDLER_COMEBACK:
if (con->mode == DIRECT && buffer_is_empty(con->physical.path)) {
- config_setup_connection(srv, con);
+ connection_reset_config(srv, con);
}
return 1;
case HANDLER_ERROR:
diff --git a/src/fdevent_solaris_devpoll.c b/src/fdevent_solaris_devpoll.c
index ddc6b90e..39feadbc 100644
--- a/src/fdevent_solaris_devpoll.c
+++ b/src/fdevent_solaris_devpoll.c
@@ -33,6 +33,9 @@ static int fdevent_solaris_devpoll_event_del(fdevents *ev, fdnode *fdn) {
static int fdevent_solaris_devpoll_event_set(fdevents *ev, fdnode *fdn, int events) {
struct pollfd pfd;
pfd.fd = fdn->fde_ndx = fdn->fd;
+ #ifndef POLLRDHUP
+ events &= ~FDEVENT_RDHUP;
+ #endif
pfd.events = events;
pfd.revents = 0;
return (-1 != write(ev->devpoll_fd, &pfd, sizeof(pfd))) ? 0 : -1;
@@ -75,7 +78,9 @@ int fdevent_solaris_devpoll_init(fdevents *ev) {
force_assert(POLLERR == FDEVENT_ERR);
force_assert(POLLHUP == FDEVENT_HUP);
force_assert(POLLNVAL == FDEVENT_NVAL);
+ #ifdef POLLRDHUP
force_assert(POLLRDHUP == FDEVENT_RDHUP);
+ #endif
ev->type = FDEVENT_HANDLER_SOLARIS_DEVPOLL;
ev->event_set = fdevent_solaris_devpoll_event_set;
diff --git a/src/fdevent_solaris_port.c b/src/fdevent_solaris_port.c
index a083d784..ac50bb60 100644
--- a/src/fdevent_solaris_port.c
+++ b/src/fdevent_solaris_port.c
@@ -84,7 +84,9 @@ int fdevent_solaris_port_init(fdevents *ev) {
force_assert(POLLERR == FDEVENT_ERR);
force_assert(POLLHUP == FDEVENT_HUP);
force_assert(POLLNVAL == FDEVENT_NVAL);
+ #ifdef POLLRDHUP
force_assert(POLLRDHUP == FDEVENT_RDHUP);
+ #endif
ev->type = FDEVENT_HANDLER_SOLARIS_PORT;
ev->event_set = fdevent_solaris_port_event_set;
diff --git a/src/http-header-glue.c b/src/http-header-glue.c
index 8c175c01..176634a4 100644
--- a/src/http-header-glue.c
+++ b/src/http-header-glue.c
@@ -117,25 +117,26 @@ int http_response_redirect_to_directory(server *srv, connection *con, int status
return 0;
}
-buffer * strftime_cache_get(server *srv, time_t last_mod) {
+const buffer * strftime_cache_get(server *srv, time_t last_mod) {
static int i;
- struct tm *tm;
+ mtime_cache_type * const mtime_cache = srv->mtime_cache;
for (int j = 0; j < FILE_CACHE_MAX; ++j) {
- if (srv->mtime_cache[j].mtime == last_mod)
- return srv->mtime_cache[j].str; /* found cache-entry */
+ if (mtime_cache[j].mtime == last_mod)
+ return &mtime_cache[j].str; /* found cache-entry */
}
if (++i == FILE_CACHE_MAX) {
i = 0;
}
- srv->mtime_cache[i].mtime = last_mod;
- tm = gmtime(&(srv->mtime_cache[i].mtime));
- buffer_clear(srv->mtime_cache[i].str);
- buffer_append_strftime(srv->mtime_cache[i].str, "%a, %d %b %Y %H:%M:%S GMT", tm);
+ mtime_cache[i].mtime = last_mod;
+ buffer * const b = &mtime_cache[i].str;
+ buffer_clear(b);
+ buffer_append_strftime(b, "%a, %d %b %Y %H:%M:%S GMT",
+ gmtime(&(mtime_cache[i].mtime)));
- return srv->mtime_cache[i].str;
+ return b;
}
@@ -632,7 +633,7 @@ static void http_response_xsendfile (server *srv, connection *con, buffer *path,
* - xdocroot should have trailing slash appended at config time
* - con->conf.force_lowercase_filenames is not a server-wide setting,
* and so can not be definitively applied to xdocroot at config time*/
- if (xdocroot->used) {
+ if (xdocroot) {
size_t i, xlen = buffer_string_length(path);
for (i = 0; i < xdocroot->used; ++i) {
data_string *ds = (data_string *)xdocroot->data[i];
@@ -644,7 +645,7 @@ static void http_response_xsendfile (server *srv, connection *con, buffer *path,
break;
}
}
- if (i == xdocroot->used) {
+ if (i == xdocroot->used && 0 != i) {
log_error_write(srv, __FILE__, __LINE__, "SBs",
"X-Sendfile (", path,
") not under configured x-sendfile-docroot(s)");
@@ -706,7 +707,7 @@ static void http_response_xsendfile2(server *srv, connection *con, const buffer
if (con->conf.force_lowercase_filenames) {
buffer_to_lower(b);
}
- if (xdocroot->used) {
+ if (xdocroot) {
size_t i, xlen = buffer_string_length(b);
for (i = 0; i < xdocroot->used; ++i) {
data_string *ds = (data_string *)xdocroot->data[i];
@@ -718,7 +719,7 @@ static void http_response_xsendfile2(server *srv, connection *con, const buffer
break;
}
}
- if (i == xdocroot->used) {
+ if (i == xdocroot->used && 0 != i) {
log_error_write(srv, __FILE__, __LINE__, "SBs",
"X-Sendfile2 (", b,
") not under configured x-sendfile-docroot(s)");
@@ -887,7 +888,7 @@ static handler_t http_response_process_local_redir(server *srv, connection *con,
&& vb->ptr[ulen] != '?'))
&& 0 == blen
&& !(con->response.htags & HTTP_HEADER_STATUS) /*no "Status" or NPH response*/
- && 1 == con->response.headers->used) {
+ && 1 == con->response.headers.used) {
if (++con->loops_per_request > 5) {
log_error_write(srv, __FILE__, __LINE__, "sb",
"too many internal loops while processing request:",
@@ -1530,8 +1531,8 @@ int http_cgi_headers (server *srv, connection *con, http_cgi_opts *opts, http_cg
li_utostrn(buf, sizeof(buf), sock_addr_get_port(&con->dst_addr));
rc |= cb(vdata, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
- for (n = 0; n < con->request.headers->used; n++) {
- data_string *ds = (data_string *)con->request.headers->data[n];
+ for (n = 0; n < con->request.headers.used; n++) {
+ data_string *ds = (data_string *)con->request.headers.data[n];
if (!buffer_string_is_empty(&ds->value) && !buffer_is_empty(&ds->key)) {
/* Security: Do not emit HTTP_PROXY in environment.
* Some executables use HTTP_PROXY to configure
@@ -1549,8 +1550,8 @@ int http_cgi_headers (server *srv, connection *con, http_cgi_opts *opts, http_cg
srv->request_env(srv, con);
- for (n = 0; n < con->environment->used; n++) {
- data_string *ds = (data_string *)con->environment->data[n];
+ for (n = 0; n < con->environment.used; n++) {
+ data_string *ds = (data_string *)con->environment.data[n];
if (!buffer_is_empty(&ds->value) && !buffer_is_empty(&ds->key)) {
buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf,
CONST_BUF_LEN(&ds->key), 0);
diff --git a/src/http_header.c b/src/http_header.c
index b140530f..15b927df 100644
--- a/src/http_header.c
+++ b/src/http_header.c
@@ -19,7 +19,6 @@ typedef struct keyvlenvalue {
int8_t http_headers_off[] = {
-1, -1, -1, -1, 0, 4, 5, 9, 10, 11, 12, -1, 15, 16, 20, 21, 23, 25
};
-#define CONST_LEN_STR(x) (unsigned int)(sizeof(x)-1), x
static const keyvlenvalue http_headers[] = {
{ HTTP_HEADER_HOST, CONST_LEN_STR("Host") }
,{ HTTP_HEADER_DATE, CONST_LEN_STR("Date") }
@@ -100,14 +99,14 @@ static inline buffer * http_header_generic_get_ifnotempty(const array * const a,
buffer * http_header_response_get(connection *con, enum http_header_e id, const char *k, size_t klen) {
return (id <= HTTP_HEADER_OTHER || (con->response.htags & id))
- ? http_header_generic_get_ifnotempty(con->response.headers, k, klen)
+ ? http_header_generic_get_ifnotempty(&con->response.headers, k, klen)
: NULL;
}
void http_header_response_unset(connection *con, enum http_header_e id, const char *k, size_t klen) {
if (id <= HTTP_HEADER_OTHER || (con->response.htags & id)) {
if (id > HTTP_HEADER_OTHER) con->response.htags &= ~id;
- array_set_key_value(con->response.headers, k, klen, CONST_STR_LEN(""));
+ array_set_key_value(&con->response.headers, k, klen, CONST_STR_LEN(""));
}
}
@@ -118,20 +117,20 @@ void http_header_response_set(connection *con, enum http_header_e id, const char
*/
if (id > HTTP_HEADER_OTHER)
(vlen) ? (con->response.htags |= id) : (con->response.htags &= ~id);
- array_set_key_value(con->response.headers, k, klen, v, vlen);
+ array_set_key_value(&con->response.headers, k, klen, v, vlen);
}
void http_header_response_append(connection *con, enum http_header_e id, const char *k, size_t klen, const char *v, size_t vlen) {
if (0 == vlen) return;
if (id > HTTP_HEADER_OTHER) con->response.htags |= id;
- buffer * const vb = array_get_buf_ptr(con->response.headers, k, klen);
+ buffer * const vb = array_get_buf_ptr(&con->response.headers, k, klen);
http_header_token_append(vb, v, vlen);
}
void http_header_response_insert(connection *con, enum http_header_e id, const char *k, size_t klen, const char *v, size_t vlen) {
if (0 == vlen) return;
if (id > HTTP_HEADER_OTHER) con->response.htags |= id;
- buffer * const vb = array_get_buf_ptr(con->response.headers, k, klen);
+ buffer * const vb = array_get_buf_ptr(&con->response.headers, k, klen);
if (!buffer_string_is_empty(vb)) { /* append value */
buffer_append_string_len(vb, CONST_STR_LEN("\r\n"));
buffer_append_string_len(vb, k, klen);
@@ -143,14 +142,14 @@ void http_header_response_insert(connection *con, enum http_header_e id, const c
buffer * http_header_request_get(connection *con, enum http_header_e id, const char *k, size_t klen) {
return (id <= HTTP_HEADER_OTHER || (con->request.htags & id))
- ? http_header_generic_get_ifnotempty(con->request.headers, k, klen)
+ ? http_header_generic_get_ifnotempty(&con->request.headers, k, klen)
: NULL;
}
void http_header_request_unset(connection *con, enum http_header_e id, const char *k, size_t klen) {
if (id <= HTTP_HEADER_OTHER || (con->request.htags & id)) {
if (id > HTTP_HEADER_OTHER) con->request.htags &= ~id;
- array_set_key_value(con->request.headers, k, klen, CONST_STR_LEN(""));
+ array_set_key_value(&con->request.headers, k, klen, CONST_STR_LEN(""));
}
}
@@ -161,28 +160,28 @@ void http_header_request_set(connection *con, enum http_header_e id, const char
*/
if (id > HTTP_HEADER_OTHER)
(vlen) ? (con->request.htags |= id) : (con->request.htags &= ~id);
- array_set_key_value(con->request.headers, k, klen, v, vlen);
+ array_set_key_value(&con->request.headers, k, klen, v, vlen);
}
void http_header_request_append(connection *con, enum http_header_e id, const char *k, size_t klen, const char *v, size_t vlen) {
if (0 == vlen) return;
if (id > HTTP_HEADER_OTHER) con->request.htags |= id;
- buffer * const vb = array_get_buf_ptr(con->request.headers, k, klen);
+ buffer * const vb = array_get_buf_ptr(&con->request.headers, k, klen);
http_header_token_append(vb, v, vlen);
}
buffer * http_header_env_get(connection *con, const char *k, size_t klen) {
- return http_header_generic_get_ifnotempty(con->environment, k, klen);
+ return http_header_generic_get_ifnotempty(&con->environment, k, klen);
}
void http_header_env_set(connection *con, const char *k, size_t klen, const char *v, size_t vlen) {
- array_set_key_value(con->environment, k, klen, v, vlen);
+ array_set_key_value(&con->environment, k, klen, v, vlen);
}
void http_header_env_append(connection *con, const char *k, size_t klen, const char *v, size_t vlen) {
/*if (0 == vlen) return;*//* skip check; permit env var w/ blank value */
- buffer * const vb = array_get_buf_ptr(con->environment, k, klen);
+ buffer * const vb = array_get_buf_ptr(&con->environment, k, klen);
if (0 == vlen) return;
http_header_token_append(vb, v, vlen);
}
diff --git a/src/http_kv.c b/src/http_kv.c
index 2eb29649..b77ab6bf 100644
--- a/src/http_kv.c
+++ b/src/http_kv.c
@@ -5,8 +5,6 @@
#include <string.h>
-#define CONST_LEN_STR(x) (unsigned int)sizeof(x)-1, (x)
-
typedef struct {
int key;
unsigned int vlen;
diff --git a/src/mod_access.c b/src/mod_access.c
index 9dcaf1bb..4281e3c1 100644
--- a/src/mod_access.c
+++ b/src/mod_access.c
@@ -1,8 +1,9 @@
#include "first.h"
#include "base.h"
-#include "log.h"
+#include "array.h"
#include "buffer.h"
+#include "log.h"
#include "plugin.h"
@@ -10,141 +11,134 @@
#include <string.h>
typedef struct {
- array *access_allow;
- array *access_deny;
+ const array *access_allow;
+ const array *access_deny;
} plugin_config;
typedef struct {
- PLUGIN_DATA;
-
- plugin_config **config_storage;
-
- plugin_config conf;
+ PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
} plugin_data;
INIT_FUNC(mod_access_init) {
- plugin_data *p;
-
- p = calloc(1, sizeof(*p));
-
- return p;
+ return calloc(1, sizeof(plugin_data));
}
FREE_FUNC(mod_access_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+ UNUSED(srv);
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
+ free(p->cvlist);
+ free(p);
- if (NULL == s) continue;
-
- array_free(s->access_allow);
- array_free(s->access_deny);
+ return HANDLER_GO_ON;
+}
- free(s);
- }
- free(p->config_storage);
- }
+static void mod_access_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* url.access-deny */
+ pconf->access_deny = cpv->v.a;
+ break;
+ case 1: /* url.access-allow */
+ pconf->access_allow = cpv->v.a;
+ break;
+ default:/* should not happen */
+ return;
+ }
+}
- free(p);
+static void mod_access_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_access_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- return HANDLER_GO_ON;
+static void mod_access_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_access_merge_config(&p->conf, p->cvlist + p->cvlist[i].v.u2[0]);
+ }
}
SETDEFAULTS_FUNC(mod_access_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { "url.access-deny", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
- { "url.access-allow", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->access_deny = array_init();
- s->access_allow = array_init();
-
- cv[0].destination = s->access_deny;
- cv[1].destination = s->access_allow;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
-
- if (!array_is_vlist(s->access_deny)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected value for url.access-deny; expected list of \"suffix\"");
- return HANDLER_ERROR;
- }
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("url.access-deny"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("url.access-allow"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_access"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* url.access-deny */
+ case 1: /* url.access-allow */
+ if (!array_is_vlist(cpv->v.a)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s; "
+ "expected list of \"suffix\"", cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+ }
- if (!array_is_vlist(s->access_allow)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected value for url.access-allow; expected list of \"suffix\"");
- return HANDLER_ERROR;
- }
- }
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_access_merge_config(&p->defaults, cpv);
+ }
- return HANDLER_GO_ON;
+ return HANDLER_GO_ON;
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_access_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(access_allow);
- PATCH(access_deny);
-
- /* 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("url.access-deny"))) {
- PATCH(access_deny);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("url.access-allow"))) {
- PATCH(access_allow);
- }
- }
- }
+__attribute_cold__
+static handler_t mod_access_reject (connection * const con, plugin_data * const p) {
+ if (con->conf.log_request_handling) {
+ if (p->conf.access_allow && p->conf.access_allow->used)
+ log_error(con->errh, __FILE__, __LINE__,
+ "url denied as failed to match any from access_allow %s",
+ con->uri.path->ptr);
+ else
+ log_error(con->errh, __FILE__, __LINE__,
+ "url denied as we match access_deny %s",
+ con->uri.path->ptr);
+ }
- return 0;
+ con->http_status = 403;
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
}
-#undef PATCH
static int mod_access_check (const array *allow, const array *deny, const buffer *urlpath, const int lc) {
- if (allow->used) {
+ if (allow && allow->used) {
const buffer *match = (!lc)
? array_match_value_suffix(allow, urlpath)
: array_match_value_suffix_nc(allow, urlpath);
return (match != NULL); /* allowed if match; denied if none matched */
}
- if (deny->used) {
+ if (deny && deny->used) {
const buffer *match = (!lc)
? array_match_value_suffix(deny, urlpath)
: array_match_value_suffix_nc(deny, urlpath);
@@ -164,45 +158,32 @@ static int mod_access_check (const array *allow, const array *deny, const buffer
* this handles the issue of trailing slashes
*/
URIHANDLER_FUNC(mod_access_uri_handler) {
- plugin_data *p = p_d;
- if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
-
- mod_access_patch_connection(srv, con, p);
-
- if (0 == p->conf.access_allow->used && 0 == p->conf.access_deny->used) {
- return HANDLER_GO_ON; /* access allowed; nothing to match */
- }
-
- if (con->conf.log_request_handling) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "-- mod_access_uri_handler called");
- }
-
- if (mod_access_check(p->conf.access_allow, p->conf.access_deny,
- con->uri.path, con->conf.force_lowercase_filenames)) {
- return HANDLER_GO_ON; /* access allowed */
- }
-
- /* (else) access denied */
- if (con->conf.log_request_handling) {
- if (p->conf.access_allow->used) {
- log_error_write(srv, __FILE__, __LINE__, "sb", "url denied as failed to match any from access_allow", con->uri.path);
- }
- else {
- log_error_write(srv, __FILE__, __LINE__, "sb", "url denied as we match access_deny", con->uri.path);
- }
- }
-
- con->http_status = 403;
- con->mode = DIRECT;
- return HANDLER_FINISHED;
+ plugin_data *p = p_d;
+ if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
+ UNUSED(srv);
+
+ mod_access_patch_config(con, p);
+
+ if (NULL == p->conf.access_allow && NULL == p->conf.access_deny) {
+ return HANDLER_GO_ON; /* access allowed; nothing to match */
+ }
+
+ if (con->conf.log_request_handling) {
+ log_error(con->errh, __FILE__, __LINE__,
+ "-- mod_access_uri_handler called");
+ }
+
+ return mod_access_check(p->conf.access_allow, p->conf.access_deny,
+ con->uri.path, con->conf.force_lowercase_filenames)
+ ? HANDLER_GO_ON /* access allowed */
+ : mod_access_reject(con, p); /* access denied */
}
int mod_access_plugin_init(plugin *p);
int mod_access_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("access");
+ p->name = "access";
p->init = mod_access_init;
p->set_defaults = mod_access_set_defaults;
@@ -210,7 +191,5 @@ int mod_access_plugin_init(plugin *p) {
p->handle_subrequest_start = mod_access_uri_handler;
p->cleanup = mod_access_free;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_accesslog.c b/src/mod_accesslog.c
index a06aa145..d9beb549 100644
--- a/src/mod_accesslog.c
+++ b/src/mod_accesslog.c
@@ -130,72 +130,69 @@ enum e_optflags_port {
typedef struct {
- enum { FIELD_UNSET, FIELD_STRING, FIELD_FORMAT } type;
-
- buffer *string;
- int field;
- int opt;
+ enum { FIELD_UNSET, FIELD_STRING, FIELD_FORMAT } type;
+ int field;
+ int opt;
+ buffer string;
} format_field;
typedef struct {
- format_field **ptr;
-
- size_t used;
- size_t size;
+ time_t last_generated_accesslog_ts;
+ buffer ts_accesslog_str;
+ #if defined(__STDC_VERSION__) && __STDC_VERSION__-0 >= 199901L /* C99 */
+ format_field ptr[]; /* C99 VLA */
+ #else
+ format_field ptr[1];
+ #endif
} format_fields;
typedef struct {
- buffer *access_logfile;
int log_access_fd;
- buffer *access_logbuffer; /* each logfile has a separate buffer */
-
- unsigned short use_syslog; /* syslog has global buffer */
+ char use_syslog; /* syslog has global buffer */
+ char piped_logger;
unsigned short syslog_level;
-
- buffer *format;
-
- time_t last_generated_accesslog_ts;
- time_t *last_generated_accesslog_ts_ptr;
-
- buffer *ts_accesslog_str;
+ buffer *access_logbuffer; /* each logfile has a separate buffer */
+ const buffer *access_logfile;
format_fields *parsed_format;
} plugin_config;
typedef struct {
- PLUGIN_DATA;
+ int log_access_fd;
+ char piped_logger;
+ const buffer *access_logfile;
+ buffer access_logbuffer; /* each logfile has a separate buffer */
+} accesslog_st;
- plugin_config **config_storage;
- plugin_config conf;
+typedef struct {
+ PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
- buffer *syslog_logbuffer; /* syslog has global buffer. no caching, always written directly */
+ buffer syslog_logbuffer; /* syslog has global buffer. no caching, always written directly */
+ log_error_st *errh; /* copy of srv->errh */
+ format_fields *default_format;/* allocated if default format */
} plugin_data;
INIT_FUNC(mod_accesslog_init) {
- plugin_data *p;
-
- p = calloc(1, sizeof(*p));
- p->syslog_logbuffer = buffer_init();
-
- return p;
+ return calloc(1, sizeof(plugin_data));
}
-static void accesslog_write_all(server *srv, const buffer *filename, int fd, const void* buf, size_t count) {
- if (-1 == write_all(fd, buf, count)) {
- log_error_write(srv, __FILE__, __LINE__, "sbs",
- "writing access log entry failed:", filename, strerror(errno));
- }
+static int accesslog_write_all(const int fd, buffer * const b) {
+ const ssize_t wr = (fd >= 0) ? write_all(fd, CONST_BUF_LEN(b)) : 0;
+ buffer_clear(b); /*(clear buffer, even if fd < 0)*/
+ return (-1 != wr);
}
-static void accesslog_append_escaped(buffer *dest, const buffer *str) {
+static void accesslog_append_escaped_str(buffer *dest, char *str, size_t len) {
char *ptr, *start, *end;
/* replaces non-printable chars with \xHH where HH is the hex representation of the byte */
/* exceptions: " => \", \ => \\, whitespace chars => \n \t etc. */
- if (buffer_string_is_empty(str)) return;
- buffer_string_prepare_append(dest, buffer_string_length(str));
+ if (0 == len) return;
+ buffer_string_prepare_append(dest, len);
- for (ptr = start = str->ptr, end = str->ptr + buffer_string_length(str); ptr < end; ptr++) {
+ for (ptr = start = str, end = str+len; ptr < end; ++ptr) {
unsigned char const c = (unsigned char) *ptr;
if (c >= ' ' && c <= '~' && c != '"' && c != '\\') {
/* nothing to change, add later as one block */
@@ -247,67 +244,82 @@ static void accesslog_append_escaped(buffer *dest, const buffer *str) {
}
}
-static int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) {
+static void accesslog_append_escaped(buffer *dest, const buffer *str) {
+ accesslog_append_escaped_str(dest, CONST_BUF_LEN(str));
+}
+
+__attribute_cold__
+static format_fields * accesslog_parse_format_err(server *srv, const char *file, unsigned int line, format_field *f, const char *msg) {
+ log_error(srv->errh, file, line, "%s", msg);
+ for (; f->type != FIELD_UNSET; ++f) free(f->string.ptr);
+ return NULL;
+}
+
+static format_fields * accesslog_parse_format(server *srv, const char *format, const size_t flen) {
+ /* common log format (the default) results in 18 elements,
+ * so 127 should be enough except for obscene custom usage */
size_t i, j, k = 0, start = 0;
+ uint32_t used = 0;
+ const uint32_t sz = 127;
+ format_field *f;
+ format_field fptr[sz+1]; /* (128 elements takes 4k on stack in 64-bit) */
+ memset(fptr, 0, sizeof(fptr));
+ if (0 != FIELD_UNSET) return NULL;
+
+ if (0 == flen) return NULL;
- if (buffer_is_empty(format)) return -1;
+ for (i = 0; i < flen; ++i) {
+ if (format[i] != '%') continue;
- for (i = 0; i < buffer_string_length(format); i++) {
- switch(format->ptr[i]) {
- case '%':
if (i > 0 && start != i) {
/* copy the string before this % */
- if (fields->used == fields->size) {
- fields->size += 16;
- fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_field * ));
- }
-
- fields->ptr[fields->used] = malloc(sizeof(format_field));
- fields->ptr[fields->used]->type = FIELD_STRING;
- fields->ptr[fields->used]->string = buffer_init();
+ if (used == sz)
+ return accesslog_parse_format_err(srv, __FILE__, __LINE__, fptr,
+ "too many fields (>= 127) in accesslog.format");
- buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
+ f = fptr+used;
+ f->type = FIELD_STRING;
+ memset(&f->string, 0, sizeof(buffer));
+ buffer_copy_string_len(&f->string, format + start, i - start);
- fields->used++;
+ ++used;
}
/* we need a new field */
-
- if (fields->used == fields->size) {
- fields->size += 16;
- fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_field * ));
- }
+ if (used == sz)
+ return accesslog_parse_format_err(srv, __FILE__, __LINE__, fptr,
+ "too many fields (>= 127) in accesslog.format");
/* search for the terminating command */
- switch (format->ptr[i+1]) {
+ switch (format[i+1]) {
case '>':
case '<':
/* after the } has to be a character */
- if (format->ptr[i+2] == '\0') {
- log_error_write(srv, __FILE__, __LINE__, "s", "%< and %> have to be followed by a format-specifier");
- return -1;
+ if (format[i+2] == '\0') {
+ return accesslog_parse_format_err(srv, __FILE__, __LINE__, fptr,
+ "%< and %> have to be followed by a format-specifier");
}
for (j = 0; fmap[j].key != '\0'; j++) {
- if (fmap[j].key != format->ptr[i+2]) continue;
+ if (fmap[j].key != format[i+2]) continue;
/* found key */
- fields->ptr[fields->used] = malloc(sizeof(format_field));
- fields->ptr[fields->used]->type = FIELD_FORMAT;
- fields->ptr[fields->used]->field = fmap[j].type;
- fields->ptr[fields->used]->string = NULL;
- fields->ptr[fields->used]->opt = 0;
+ f = fptr+used;
+ f->type = FIELD_FORMAT;
+ f->field = fmap[j].type;
+ f->opt = 0;
+ f->string.ptr = NULL;
- fields->used++;
+ ++used;
break;
}
if (fmap[j].key == '\0') {
- log_error_write(srv, __FILE__, __LINE__, "s", "%< and %> have to be followed by a valid format-specifier");
- return -1;
+ return accesslog_parse_format_err(srv, __FILE__, __LINE__, fptr,
+ "%< and %> have to be followed by a valid format-specifier");
}
start = i + 3;
@@ -317,47 +329,46 @@ static int accesslog_parse_format(server *srv, format_fields *fields, buffer *fo
case '{':
/* go forward to } */
- for (k = i+2; k < buffer_string_length(format); k++) {
- if (format->ptr[k] == '}') break;
+ for (k = i+2; k < flen; ++k) {
+ if (format[k] == '}') break;
}
- if (k == buffer_string_length(format)) {
- log_error_write(srv, __FILE__, __LINE__, "s", "%{ has to be terminated by a }");
- return -1;
+ if (k == flen) {
+ return accesslog_parse_format_err(srv, __FILE__, __LINE__, fptr,
+ "%{ has to be terminated by a }");
}
/* after the } has to be a character */
- if (format->ptr[k+1] == '\0') {
- log_error_write(srv, __FILE__, __LINE__, "s", "%{...} has to be followed by a format-specifier");
- return -1;
+ if (format[k+1] == '\0') {
+ return accesslog_parse_format_err(srv, __FILE__, __LINE__, fptr,
+ "%{...} has to be followed by a format-specifier");
}
if (k == i + 2) {
- log_error_write(srv, __FILE__, __LINE__, "s", "%{...} has to contain a string");
- return -1;
+ return accesslog_parse_format_err(srv, __FILE__, __LINE__, fptr,
+ "%{...} has to contain a string");
}
for (j = 0; fmap[j].key != '\0'; j++) {
- if (fmap[j].key != format->ptr[k+1]) continue;
+ if (fmap[j].key != format[k+1]) continue;
/* found key */
- fields->ptr[fields->used] = malloc(sizeof(format_field));
- fields->ptr[fields->used]->type = FIELD_FORMAT;
- fields->ptr[fields->used]->field = fmap[j].type;
- fields->ptr[fields->used]->string = buffer_init();
- fields->ptr[fields->used]->opt = 0;
+ f = fptr+used;
+ f->type = FIELD_FORMAT;
+ f->field = fmap[j].type;
+ f->opt = 0;
+ memset(&f->string, 0, sizeof(buffer));
+ buffer_copy_string_len(&f->string, format + i + 2, k - (i + 2));
- buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + i + 2, k - (i + 2));
-
- fields->used++;
+ ++used;
break;
}
if (fmap[j].key == '\0') {
- log_error_write(srv, __FILE__, __LINE__, "s", "%{...} has to be followed by a valid format-specifier");
- return -1;
+ return accesslog_parse_format_err(srv, __FILE__, __LINE__, fptr,
+ "%{...} has to be followed by a valid format-specifier");
}
start = k + 2;
@@ -366,30 +377,30 @@ static int accesslog_parse_format(server *srv, format_fields *fields, buffer *fo
break;
default:
/* after the % has to be a character */
- if (format->ptr[i+1] == '\0') {
- log_error_write(srv, __FILE__, __LINE__, "s", "% has to be followed by a format-specifier");
- return -1;
+ if (format[i+1] == '\0') {
+ return accesslog_parse_format_err(srv, __FILE__, __LINE__, fptr,
+ "% has to be followed by a format-specifier");
}
for (j = 0; fmap[j].key != '\0'; j++) {
- if (fmap[j].key != format->ptr[i+1]) continue;
+ if (fmap[j].key != format[i+1]) continue;
/* found key */
- fields->ptr[fields->used] = malloc(sizeof(format_field));
- fields->ptr[fields->used]->type = FIELD_FORMAT;
- fields->ptr[fields->used]->field = fmap[j].type;
- fields->ptr[fields->used]->string = NULL;
- fields->ptr[fields->used]->opt = 0;
+ f = fptr+used;
+ f->type = FIELD_FORMAT;
+ f->field = fmap[j].type;
+ f->string.ptr = NULL;
+ f->opt = 0;
- fields->used++;
+ ++used;
break;
}
if (fmap[j].key == '\0') {
- log_error_write(srv, __FILE__, __LINE__, "s", "% has to be followed by a valid format-specifier");
- return -1;
+ return accesslog_parse_format_err(srv, __FILE__, __LINE__, fptr,
+ "% has to be followed by a valid format-specifier");
}
start = i + 2;
@@ -397,151 +408,242 @@ static int accesslog_parse_format(server *srv, format_fields *fields, buffer *fo
break;
}
-
- break;
- }
}
if (start < i) {
/* copy the string */
- if (fields->used == fields->size) {
- fields->size += 16;
- fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_field * ));
- }
-
- fields->ptr[fields->used] = malloc(sizeof(format_field));
- fields->ptr[fields->used]->type = FIELD_STRING;
- fields->ptr[fields->used]->string = buffer_init();
+ if (used == sz)
+ return accesslog_parse_format_err(srv, __FILE__, __LINE__, fptr,
+ "too many fields (>= 127) in accesslog.format");
- buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
+ f = fptr+used;
+ f->type = FIELD_STRING;
+ memset(&f->string, 0, sizeof(buffer));
+ buffer_copy_string_len(&f->string, format + start, i - start);
- fields->used++;
+ ++used;
}
- return 0;
+ format_fields * const fields =
+ malloc(sizeof(format_fields) + ((used+1) * sizeof(format_field)));
+ force_assert(fields);
+ memset(fields, 0, sizeof(format_fields));
+ memcpy(fields->ptr, fptr, (used+1) * sizeof(format_field));
+ return fields;
}
-FREE_FUNC(mod_accesslog_free) {
- plugin_data *p = p_d;
- size_t i;
-
- if (!p) return HANDLER_GO_ON;
-
- if (p->config_storage) {
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- if (NULL == s) continue;
-
- if (!buffer_string_is_empty(s->access_logbuffer)) {
- if (s->log_access_fd != -1) {
- accesslog_write_all(srv, s->access_logfile, s->log_access_fd, CONST_BUF_LEN(s->access_logbuffer));
- }
- }
-
- if (s->log_access_fd != -1) {
- if (buffer_string_is_empty(s->access_logfile) || *s->access_logfile->ptr != '|') {
- close(s->log_access_fd);
- } /*(else piped loggers closed in fdevent_close_logger_pipes())*/
- }
-
- buffer_free(s->ts_accesslog_str);
- buffer_free(s->access_logbuffer);
- buffer_free(s->format);
- buffer_free(s->access_logfile);
-
- if (s->parsed_format) {
- size_t j;
- for (j = 0; j < s->parsed_format->used; j++) {
- if (s->parsed_format->ptr[j]->string) buffer_free(s->parsed_format->ptr[j]->string);
- free(s->parsed_format->ptr[j]);
- }
- free(s->parsed_format->ptr);
- free(s->parsed_format);
- }
-
- free(s);
- }
-
- free(p->config_storage);
- }
-
- if (p->syslog_logbuffer) buffer_free(p->syslog_logbuffer);
- free(p);
-
- return HANDLER_GO_ON;
+static void mod_accesslog_free_accesslog(accesslog_st * const x, plugin_data *p) {
+ /*(piped loggers are closed in fdevent_close_logger_pipes())*/
+ if (!x->piped_logger && -1 != x->log_access_fd) {
+ if (!accesslog_write_all(x->log_access_fd, &x->access_logbuffer)) {
+ log_error(p->errh, __FILE__, __LINE__,
+ "writing access log entry failed: %s %s",
+ x->access_logfile->ptr, strerror(errno));
+ }
+ close(x->log_access_fd);
+ }
+ free(x->access_logbuffer.ptr);
}
-SETDEFAULTS_FUNC(log_access_open) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { "accesslog.filename", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "accesslog.use-syslog", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
- { "accesslog.format", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "accesslog.syslog-level", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->access_logfile = buffer_init();
- s->format = buffer_init();
- s->access_logbuffer = buffer_init();
- s->ts_accesslog_str = buffer_init();
- s->log_access_fd = -1;
- s->last_generated_accesslog_ts = 0;
- s->last_generated_accesslog_ts_ptr = &(s->last_generated_accesslog_ts);
- s->syslog_level = LOG_INFO;
-
-
- cv[0].destination = s->access_logfile;
- cv[1].destination = &(s->use_syslog);
- cv[2].destination = s->format;
- cv[3].destination = &(s->syslog_level);
+static void mod_accesslog_free_format_fields(format_fields * const ff) {
+ for (format_field *f = ff->ptr; f->type != FIELD_UNSET; ++f)
+ free(f->string.ptr);
+ free(ff->ts_accesslog_str.ptr);
+ free(ff);
+}
- p->config_storage[i] = s;
+static void mod_accesslog_free_config(plugin_data * const p) {
+ if (NULL == p->cvlist) return;
+ /* (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ if (cpv->vtype != T_CONFIG_LOCAL || NULL == cpv->v.v) continue;
+ switch (cpv->k_id) {
+ case 0: /* accesslog.filename */
+ mod_accesslog_free_accesslog(cpv->v.v, p);
+ break;
+ case 1: /* accesslog.format */
+ mod_accesslog_free_format_fields(cpv->v.v);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (NULL != p->default_format) {
+ mod_accesslog_free_format_fields(p->default_format);
+ }
+}
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
+FREE_FUNC(mod_accesslog_free) {
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+ UNUSED(srv);
- if (i == 0 && buffer_string_is_empty(s->format)) {
- /* set a default logfile string */
+ mod_accesslog_free_config(p);
- buffer_copy_string_len(s->format, CONST_STR_LEN("%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""));
- }
+ free(p->syslog_logbuffer.ptr);
+ free(p->cvlist);
+ free(p);
- /* parse */
+ return HANDLER_GO_ON;
+}
- if (!buffer_is_empty(s->format)) {
- size_t j, tcount = 0;
+static void mod_accesslog_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0:{/* accesslog.filename */
+ if (cpv->vtype != T_CONFIG_LOCAL) break;
+ accesslog_st * const x = cpv->v.v;
+ pconf->log_access_fd = x->log_access_fd;
+ pconf->piped_logger = x->piped_logger;
+ pconf->access_logfile = x->access_logfile;
+ pconf->access_logbuffer = &x->access_logbuffer;
+ break;
+ }
+ case 1:{/* accesslog.format */
+ if (cpv->vtype != T_CONFIG_LOCAL) break;
+ pconf->parsed_format = cpv->v.v;
+ break;
+ }
+ case 2: /* accesslog.use-syslog */
+ pconf->use_syslog = (int)cpv->v.u;
+ break;
+ case 3: /* accesslog.syslog-level */
+ pconf->syslog_level = cpv->v.shrt;
+ break;
+ default:/* should not happen */
+ return;
+ }
+}
- s->parsed_format = calloc(1, sizeof(*(s->parsed_format)));
+static void mod_accesslog_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_accesslog_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- if (-1 == accesslog_parse_format(srv, s->parsed_format, s->format)) {
+static void mod_accesslog_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_accesslog_merge_config(&p->conf, p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "parsing accesslog-definition failed:", s->format);
+static format_fields * mod_accesslog_process_format(server * const srv, const char * const format, const size_t flen);
+
+SETDEFAULTS_FUNC(mod_accesslog_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("accesslog.filename"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("accesslog.format"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("accesslog.use-syslog"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("accesslog.syslog-level"),
+ T_CONFIG_SHORT,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ p->errh = srv->errh;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_accesslog"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ int use_syslog = 0;
+ accesslog_st *x = NULL;
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* accesslog.filename */
+ x = calloc(1, sizeof(accesslog_st));
+ force_assert(x);
+ x->log_access_fd = -1;
+ x->piped_logger = (cpv->v.b->ptr[0] == '|');
+ x->access_logfile = cpv->v.b;
+ cpv->vtype = T_CONFIG_LOCAL;
+ cpv->v.v = x;
+ break;
+ case 1: /* accesslog.format */
+ cpv->v.v =
+ mod_accesslog_process_format(srv, CONST_BUF_LEN(cpv->v.b));
+ if (NULL == cpv->v.v) return HANDLER_ERROR;
+ cpv->vtype = T_CONFIG_LOCAL;
+ break;
+ case 2: /* accesslog.use-syslog */
+ use_syslog = (int)cpv->v.u;
+ break;
+ case 3: /* accesslog.syslog-level */
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+
+ if (srv->srvconf.preflight_check) continue;
+
+ if (use_syslog) continue; /* ignore the next checks */
+ if (buffer_string_is_empty(x->access_logfile)) continue;
+
+ x->log_access_fd = fdevent_open_logger(x->access_logfile->ptr);
+ if (-1 == x->log_access_fd) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "opening log '%s' failed: %s",
+ x->access_logfile->ptr, strerror(errno));
+ return HANDLER_ERROR;
+ }
+ }
+
+ p->defaults.log_access_fd = -1;
+ p->defaults.syslog_level = LOG_INFO;
+
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_accesslog_merge_config(&p->defaults, cpv);
+ }
+
+ if (NULL == p->defaults.parsed_format) {
+ /* (set default format even if p->use_syslog since
+ * some other condition might enable logfile) */
+ static const char fmt[] =
+ "%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"";
+ p->defaults.parsed_format = p->default_format =
+ mod_accesslog_process_format(srv, CONST_STR_LEN(fmt));
+ if (NULL == p->default_format) return HANDLER_ERROR;
+ }
+
+ return HANDLER_GO_ON;
+}
- return HANDLER_ERROR;
+static format_fields * mod_accesslog_process_format(server * const srv, const char * const format, const size_t flen) {
+ format_fields * const parsed_format =
+ accesslog_parse_format(srv, format, flen);
+ if (NULL == parsed_format) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "parsing accesslog-definition failed: %s", format);
+ return NULL;
}
- for (j = 0; j < s->parsed_format->used; ++j) {
- format_field * const f = s->parsed_format->ptr[j];
+ uint32_t tcount = 0;
+ for (format_field *f = parsed_format->ptr; f->type != FIELD_UNSET; ++f) {
+ const buffer * const fstr = &f->string;
if (FIELD_FORMAT != f->type) continue;
if (FORMAT_TIMESTAMP == f->field) {
- if (!buffer_string_is_empty(f->string)) {
- const char *ptr = f->string->ptr;
+ if (!buffer_string_is_empty(fstr)) {
+ const char *ptr = fstr->ptr;
if (0 == strncmp(ptr, "begin:", sizeof("begin:")-1)) {
f->opt |= FORMAT_FLAG_TIME_BEGIN;
ptr += sizeof("begin:")-1;
@@ -557,20 +659,20 @@ SETDEFAULTS_FUNC(log_access_open) {
else if (0 == strcmp(ptr, "usec_frac")) f->opt |= FORMAT_FLAG_TIME_USEC_FRAC;
else if (0 == strcmp(ptr, "nsec_frac")) f->opt |= FORMAT_FLAG_TIME_NSEC_FRAC;
else if (NULL == strchr(ptr, '%')) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "constant string for time format (misspelled token? or missing '%'):", s->format);
-
- return HANDLER_ERROR;
+ log_error(srv->errh, __FILE__, __LINE__,
+ "constant string for time format (misspelled token? or missing '%%'): %s", format);
+ mod_accesslog_free_format_fields(parsed_format);
+ return NULL;
}
}
/* make sure they didn't try to send the timestamp in twice
- * (would invalidate s->ts_accesslog_str cache of timestamp str) */
+ * (would invalidate pconf->parsed_format.ts_accesslog_str cache of timestamp str) */
if (!(f->opt & ~(FORMAT_FLAG_TIME_BEGIN|FORMAT_FLAG_TIME_END|FORMAT_FLAG_TIME_SEC)) && ++tcount > 1) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "you may not use strftime timestamp format %{}t twice in the same access log:", s->format);
-
- return HANDLER_ERROR;
+ log_error(srv->errh, __FILE__, __LINE__,
+ "you may not use strftime timestamp format %%{}t twice in the same access log: %s", format);
+ mod_accesslog_free_format_fields(parsed_format);
+ return NULL;
}
if (f->opt & FORMAT_FLAG_TIME_BEGIN) srv->srvconf.high_precision_timestamps = 1;
@@ -578,202 +680,133 @@ SETDEFAULTS_FUNC(log_access_open) {
f->opt |= FORMAT_FLAG_TIME_USEC;
srv->srvconf.high_precision_timestamps = 1;
} else if (FORMAT_TIME_USED == f->field) {
- if (buffer_string_is_empty(f->string)
- || buffer_is_equal_string(f->string, CONST_STR_LEN("s"))
- || buffer_is_equal_string(f->string, CONST_STR_LEN("sec"))) f->opt |= FORMAT_FLAG_TIME_SEC;
- else if (buffer_is_equal_string(f->string, CONST_STR_LEN("ms"))
- || buffer_is_equal_string(f->string, CONST_STR_LEN("msec"))) f->opt |= FORMAT_FLAG_TIME_MSEC;
- else if (buffer_is_equal_string(f->string, CONST_STR_LEN("us"))
- || buffer_is_equal_string(f->string, CONST_STR_LEN("usec"))) f->opt |= FORMAT_FLAG_TIME_USEC;
- else if (buffer_is_equal_string(f->string, CONST_STR_LEN("ns"))
- || buffer_is_equal_string(f->string, CONST_STR_LEN("nsec"))) f->opt |= FORMAT_FLAG_TIME_NSEC;
+ if (buffer_string_is_empty(fstr)
+ || buffer_is_equal_string(fstr, CONST_STR_LEN("s"))
+ || buffer_is_equal_string(fstr, CONST_STR_LEN("sec"))) f->opt |= FORMAT_FLAG_TIME_SEC;
+ else if (buffer_is_equal_string(fstr, CONST_STR_LEN("ms"))
+ || buffer_is_equal_string(fstr, CONST_STR_LEN("msec"))) f->opt |= FORMAT_FLAG_TIME_MSEC;
+ else if (buffer_is_equal_string(fstr, CONST_STR_LEN("us"))
+ || buffer_is_equal_string(fstr, CONST_STR_LEN("usec"))) f->opt |= FORMAT_FLAG_TIME_USEC;
+ else if (buffer_is_equal_string(fstr, CONST_STR_LEN("ns"))
+ || buffer_is_equal_string(fstr, CONST_STR_LEN("nsec"))) f->opt |= FORMAT_FLAG_TIME_NSEC;
else {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "invalid time unit in %{UNIT}T:", s->format);
-
- return HANDLER_ERROR;
+ log_error(srv->errh, __FILE__, __LINE__,
+ "invalid time unit in %%{UNIT}T: %s", format);
+ mod_accesslog_free_format_fields(parsed_format);
+ return NULL;
}
if (f->opt & ~(FORMAT_FLAG_TIME_SEC)) srv->srvconf.high_precision_timestamps = 1;
} else if (FORMAT_COOKIE == f->field) {
- if (buffer_string_is_empty(f->string)) f->type = FIELD_STRING; /*(blank)*/
+ if (buffer_string_is_empty(fstr)) f->type = FIELD_STRING; /*(blank)*/
} else if (FORMAT_SERVER_PORT == f->field) {
- if (buffer_string_is_empty(f->string))
+ if (buffer_string_is_empty(fstr))
f->opt |= FORMAT_FLAG_PORT_LOCAL;
- else if (buffer_is_equal_string(f->string, CONST_STR_LEN("canonical")))
+ else if (buffer_is_equal_string(fstr, CONST_STR_LEN("canonical")))
f->opt |= FORMAT_FLAG_PORT_LOCAL;
- else if (buffer_is_equal_string(f->string, CONST_STR_LEN("local")))
+ else if (buffer_is_equal_string(fstr, CONST_STR_LEN("local")))
f->opt |= FORMAT_FLAG_PORT_LOCAL;
- else if (buffer_is_equal_string(f->string, CONST_STR_LEN("remote")))
+ else if (buffer_is_equal_string(fstr, CONST_STR_LEN("remote")))
f->opt |= FORMAT_FLAG_PORT_REMOTE;
else {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "invalid format %{canonical,local,remote}p:", s->format);
-
- return HANDLER_ERROR;
+ log_error(srv->errh, __FILE__, __LINE__,
+ "invalid format %%{canonical,local,remote}p: %s", format);
+ mod_accesslog_free_format_fields(parsed_format);
+ return NULL;
}
}
}
-#if 0
- /* debugging */
- for (j = 0; j < s->parsed_format->used; j++) {
- switch (s->parsed_format->ptr[j]->type) {
- case FIELD_FORMAT:
- log_error_write(srv, __FILE__, __LINE__, "ssds",
- "config:", "format", s->parsed_format->ptr[j]->field,
- s->parsed_format->ptr[j]->string ?
- s->parsed_format->ptr[j]->string->ptr : "" );
- break;
- case FIELD_STRING:
- log_error_write(srv, __FILE__, __LINE__, "ssbs", "config:", "string '", s->parsed_format->ptr[j]->string, "'");
- break;
- default:
- break;
- }
- }
-#endif
- }
-
- if (s->use_syslog) {
- /* ignore the next checks */
- continue;
- }
-
- if (buffer_string_is_empty(s->access_logfile)) continue;
-
- if (srv->srvconf.preflight_check) continue;
-
- if (-1 == (s->log_access_fd = fdevent_open_logger(s->access_logfile->ptr))) {
- log_error_write(srv, __FILE__, __LINE__, "SBSS",
- "opening log '", s->access_logfile,
- "' failed: ", strerror(errno));
- return HANDLER_ERROR;
- }
- }
-
- return HANDLER_GO_ON;
+ return parsed_format;
}
-static void log_access_flush(server *srv, void *p_d) {
- plugin_data *p = p_d;
- size_t i;
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- if (!buffer_string_is_empty(s->access_logbuffer)) {
- if (s->log_access_fd != -1) {
- accesslog_write_all(srv, s->access_logfile, s->log_access_fd, CONST_BUF_LEN(s->access_logbuffer));
- }
-
- buffer_clear(s->access_logbuffer);
- }
- }
+static void log_access_flush(plugin_data * const p) {
+ /* future: might be slightly faster to have allocated array of open files
+ * rather than walking config, but only might matter with many directives */
+ /* (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* accesslog.filename */
+ if (cpv->vtype == T_CONFIG_LOCAL && NULL != cpv->v.v) {
+ accesslog_st * const x = cpv->v.v;
+ if (buffer_string_is_empty(&x->access_logbuffer)) continue;
+ if (!accesslog_write_all(x->log_access_fd,
+ &x->access_logbuffer)) {
+ log_error(p->errh, __FILE__, __LINE__,
+ "writing access log entry failed: %s %s",
+ x->access_logfile->ptr, strerror(errno));
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
}
TRIGGER_FUNC(log_access_periodic_flush) {
/* flush buffered access logs every 4 seconds */
- if (0 == (srv->cur_ts & 3)) log_access_flush(srv, p_d);
+ if (0 == (srv->cur_ts & 3)) log_access_flush((plugin_data *)p_d);
return HANDLER_GO_ON;
}
SIGHUP_FUNC(log_access_cycle) {
- plugin_data *p = p_d;
- size_t i;
-
- if (!p->config_storage) return HANDLER_GO_ON;
-
- log_access_flush(srv, p);
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
- if (s->use_syslog == 0
- && !buffer_string_is_empty(s->access_logfile)
- && s->access_logfile->ptr[0] != '|') {
-
- if (-1 == fdevent_cycle_logger(s->access_logfile->ptr, &s->log_access_fd)) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "cycling access-log failed:", strerror(errno));
- return HANDLER_ERROR;
- }
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_accesslog_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(access_logfile);
- PATCH(log_access_fd);
- PATCH(last_generated_accesslog_ts_ptr);
- PATCH(access_logbuffer);
- PATCH(ts_accesslog_str);
- PATCH(parsed_format);
- PATCH(use_syslog);
- PATCH(syslog_level);
-
- /* 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("accesslog.filename"))) {
- PATCH(access_logfile);
- PATCH(log_access_fd);
- PATCH(access_logbuffer);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("accesslog.format"))) {
- PATCH(parsed_format);
- PATCH(last_generated_accesslog_ts_ptr);
- PATCH(ts_accesslog_str);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("accesslog.use-syslog"))) {
- PATCH(use_syslog);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("accesslog.syslog-level"))) {
- PATCH(syslog_level);
- }
- }
- }
-
- return 0;
+ plugin_data * const p = p_d;
+
+ log_access_flush(p);
+
+ /* future: might be slightly faster to have allocated array of open files
+ * rather than walking config, but only might matter with many directives */
+ /* (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ if (cpv->vtype != T_CONFIG_LOCAL || NULL == cpv->v.v) continue;
+ switch (cpv->k_id) {
+ case 0:{/* accesslog.filename */
+ accesslog_st * const x = cpv->v.v;
+ if (x->piped_logger) continue;
+ if (buffer_string_is_empty(x->access_logfile)) continue;
+ if (-1 == fdevent_cycle_logger(x->access_logfile->ptr,
+ &x->log_access_fd)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "cycling access log failed: %s %s",
+ x->access_logfile->ptr, strerror(errno));
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+
+ return HANDLER_GO_ON;
}
-#undef PATCH
REQUESTDONE_FUNC(log_access_write) {
plugin_data *p = p_d;
- buffer *b;
- size_t j;
-
- int newts = 0;
- const buffer *vb;
- struct timespec ts = { 0, 0 };
-
- mod_accesslog_patch_connection(srv, con, p);
+ mod_accesslog_patch_config(con, p);
/* No output device, nothing to do */
if (!p->conf.use_syslog && p->conf.log_access_fd == -1) return HANDLER_GO_ON;
- if (p->conf.use_syslog) {
- b = p->syslog_logbuffer;
- } else {
- b = p->conf.access_logbuffer;
- }
+ buffer * const b = (p->conf.use_syslog)
+ ? &p->syslog_logbuffer
+ : p->conf.access_logbuffer;
+
+ const buffer *vb;
+ struct timespec ts = { 0, 0 };
+
+ int flush = p->conf.piped_logger;
- for (j = 0; j < p->conf.parsed_format->used; j++) {
- const format_field * const f = p->conf.parsed_format->ptr[j];
+ for (const format_field *f = p->conf.parsed_format->ptr; f->type != FIELD_UNSET; ++f) {
switch(f->type) {
case FIELD_STRING:
- buffer_append_string_buffer(b, f->string);
+ buffer_append_string_buffer(b, &f->string);
break;
case FIELD_FORMAT:
switch(f->field) {
@@ -829,9 +862,9 @@ REQUESTDONE_FUNC(log_access_write) {
for (ptr = b->ptr + buffer_string_length(b); ns > 0; ns /= 10)
*--ptr = (ns % 10) + '0';
}
- } else if (!(f->opt & FORMAT_FLAG_TIME_BEGIN) && srv->cur_ts == *(p->conf.last_generated_accesslog_ts_ptr)) {
- buffer_append_string_buffer(b, p->conf.ts_accesslog_str);
} else {
+ format_fields * const parsed_format = p->conf.parsed_format;
+ buffer * const ts_accesslog_str = &parsed_format->ts_accesslog_str;
/* cache the generated timestamp (only if ! FORMAT_FLAG_TIME_BEGIN) */
struct tm *tmptr;
time_t t;
@@ -846,8 +879,12 @@ REQUESTDONE_FUNC(log_access_write) {
#endif /* HAVE_STRUCT_TM_GMTOFF */
if (!(f->opt & FORMAT_FLAG_TIME_BEGIN)) {
- t = *(p->conf.last_generated_accesslog_ts_ptr) = srv->cur_ts;
- newts = 1;
+ if (parsed_format->last_generated_accesslog_ts == srv->cur_ts) {
+ buffer_append_string_buffer(b, ts_accesslog_str);
+ break;
+ }
+ t = parsed_format->last_generated_accesslog_ts = srv->cur_ts;
+ flush = 1;
} else {
t = con->request_start;
}
@@ -866,33 +903,33 @@ REQUESTDONE_FUNC(log_access_write) {
# endif /* HAVE_GMTIME_R */
#endif /* HAVE_STRUCT_TM_GMTOFF */
- buffer_clear(p->conf.ts_accesslog_str);
+ buffer_clear(ts_accesslog_str);
- if (buffer_string_is_empty(f->string)) {
+ if (buffer_string_is_empty(&f->string)) {
#if defined(HAVE_STRUCT_TM_GMTOFF)
long scd, hrs, min;
- buffer_append_strftime(p->conf.ts_accesslog_str, "[%d/%b/%Y:%H:%M:%S ", tmptr);
- buffer_append_string_len(p->conf.ts_accesslog_str, tmptr->tm_gmtoff >= 0 ? "+" : "-", 1);
+ buffer_append_strftime(ts_accesslog_str, "[%d/%b/%Y:%H:%M:%S ", tmptr);
+ buffer_append_string_len(ts_accesslog_str, tmptr->tm_gmtoff >= 0 ? "+" : "-", 1);
scd = labs(tmptr->tm_gmtoff);
hrs = scd / 3600;
min = (scd % 3600) / 60;
/* hours */
- if (hrs < 10) buffer_append_string_len(p->conf.ts_accesslog_str, CONST_STR_LEN("0"));
- buffer_append_int(p->conf.ts_accesslog_str, hrs);
+ if (hrs < 10) buffer_append_string_len(ts_accesslog_str, CONST_STR_LEN("0"));
+ buffer_append_int(ts_accesslog_str, hrs);
- if (min < 10) buffer_append_string_len(p->conf.ts_accesslog_str, CONST_STR_LEN("0"));
- buffer_append_int(p->conf.ts_accesslog_str, min);
- buffer_append_string_len(p->conf.ts_accesslog_str, CONST_STR_LEN("]"));
+ if (min < 10) buffer_append_string_len(ts_accesslog_str, CONST_STR_LEN("0"));
+ buffer_append_int(ts_accesslog_str, min);
+ buffer_append_string_len(ts_accesslog_str, CONST_STR_LEN("]"));
#else
- buffer_append_strftime(p->conf.ts_accesslog_str, "[%d/%b/%Y:%H:%M:%S +0000]", tmptr);
+ buffer_append_strftime(ts_accesslog_str, "[%d/%b/%Y:%H:%M:%S +0000]", tmptr);
#endif /* HAVE_STRUCT_TM_GMTOFF */
} else {
- buffer_append_strftime(p->conf.ts_accesslog_str, f->string->ptr, tmptr);
+ buffer_append_strftime(ts_accesslog_str, f->string.ptr, tmptr);
}
- buffer_append_string_buffer(b, p->conf.ts_accesslog_str);
+ buffer_append_string_buffer(b, ts_accesslog_str);
}
break;
case FORMAT_TIME_USED:
@@ -954,14 +991,14 @@ REQUESTDONE_FUNC(log_access_write) {
}
break;
case FORMAT_HEADER:
- if (NULL != (vb = http_header_request_get(con, HTTP_HEADER_UNSPECIFIED, CONST_BUF_LEN(f->string)))) {
+ if (NULL != (vb = http_header_request_get(con, HTTP_HEADER_UNSPECIFIED, CONST_BUF_LEN(&f->string)))) {
accesslog_append_escaped(b, vb);
} else {
buffer_append_string_len(b, CONST_STR_LEN("-"));
}
break;
case FORMAT_RESPONSE_HEADER:
- if (NULL != (vb = http_header_response_get(con, HTTP_HEADER_UNSPECIFIED, CONST_BUF_LEN(f->string)))) {
+ if (NULL != (vb = http_header_response_get(con, HTTP_HEADER_UNSPECIFIED, CONST_BUF_LEN(&f->string)))) {
accesslog_append_escaped(b, vb);
} else {
buffer_append_string_len(b, CONST_STR_LEN("-"));
@@ -969,7 +1006,7 @@ REQUESTDONE_FUNC(log_access_write) {
break;
case FORMAT_ENV:
case FORMAT_NOTE:
- if (NULL != (vb = http_header_env_get(con, CONST_BUF_LEN(f->string)))) {
+ if (NULL != (vb = http_header_env_get(con, CONST_BUF_LEN(&f->string)))) {
accesslog_append_escaped(b, vb);
} else {
buffer_append_string_len(b, CONST_STR_LEN("-"));
@@ -1083,22 +1120,18 @@ REQUESTDONE_FUNC(log_access_write) {
case FORMAT_COOKIE:
if (NULL != (vb = http_header_request_get(con, HTTP_HEADER_COOKIE, CONST_STR_LEN("Cookie")))) {
char *str = vb->ptr;
- size_t len = buffer_string_length(f->string);
+ size_t len = buffer_string_length(&f->string);
do {
while (*str == ' ' || *str == '\t') ++str;
- if (0 == strncmp(str, f->string->ptr, len) && str[len] == '=') {
+ if (0 == strncmp(str, f->string.ptr, len) && str[len] == '=') {
char *v = str+len+1;
- buffer *bstr;
for (str = v; *str != '\0' && *str != ';'; ++str) ;
if (str == v) break;
do { --str; } while (str > v && (*str == ' ' || *str == '\t'));
- bstr = buffer_init();
- buffer_copy_string_len(bstr, v, str - v + 1);
- accesslog_append_escaped(b, bstr);
- buffer_free(bstr);
+ accesslog_append_escaped_str(b, v, str - v + 1);
break;
} else {
- do { ++str; } while (*str != ' ' && *str != '\t' && *str != '\0');
+ while (*str != ';' && *str != ' ' && *str != '\t' && *str != '\0') ++str;
}
while (*str == ' ' || *str == '\t') ++str;
} while (*str++ == ';');
@@ -1121,18 +1154,16 @@ REQUESTDONE_FUNC(log_access_write) {
}
#endif
buffer_clear(b);
- return HANDLER_GO_ON;
}
+ else {
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
- buffer_append_string_len(b, CONST_STR_LEN("\n"));
-
- if ((!buffer_string_is_empty(p->conf.access_logfile) && p->conf.access_logfile->ptr[0] == '|') || /* pipes don't cache */
- newts ||
- buffer_string_length(b) >= BUFFER_MAX_REUSE_SIZE) {
- if (p->conf.log_access_fd >= 0) {
- accesslog_write_all(srv, p->conf.access_logfile, p->conf.log_access_fd, CONST_BUF_LEN(b));
+ if (flush || buffer_string_length(b) >= BUFFER_MAX_REUSE_SIZE) {
+ if (!accesslog_write_all(p->conf.log_access_fd, b)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "writing access log entry failed:", p->conf.access_logfile, strerror(errno));
+ }
}
- buffer_clear(b);
}
return HANDLER_GO_ON;
@@ -1142,17 +1173,15 @@ REQUESTDONE_FUNC(log_access_write) {
int mod_accesslog_plugin_init(plugin *p);
int mod_accesslog_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("accesslog");
+ p->name = "accesslog";
p->init = mod_accesslog_init;
- p->set_defaults= log_access_open;
+ p->set_defaults= mod_accesslog_set_defaults;
p->cleanup = mod_accesslog_free;
p->handle_request_done = log_access_write;
p->handle_trigger = log_access_periodic_flush;
p->handle_sighup = log_access_cycle;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_alias.c b/src/mod_alias.c
index 55b591ca..3862ee79 100644
--- a/src/mod_alias.c
+++ b/src/mod_alias.c
@@ -1,161 +1,138 @@
#include "first.h"
#include "base.h"
-#include "log.h"
+#include "array.h"
#include "buffer.h"
+#include "log.h"
#include "plugin.h"
#include <stdlib.h>
#include <string.h>
-/* plugin config for all request/connections */
typedef struct {
- array *alias;
+ const array *alias;
} plugin_config;
typedef struct {
- PLUGIN_DATA;
-
- plugin_config **config_storage;
-
- plugin_config conf;
+ PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
} plugin_data;
-/* init the plugin data */
INIT_FUNC(mod_alias_init) {
- plugin_data *p;
-
- p = calloc(1, sizeof(*p));
-
-
-
- return p;
+ return calloc(1, sizeof(plugin_data));
}
-/* detroy the plugin data */
FREE_FUNC(mod_alias_free) {
- plugin_data *p = p_d;
-
- 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];
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+ UNUSED(srv);
- if (NULL == s) continue;
+ free(p->cvlist);
+ free(p);
- array_free(s->alias);
-
- free(s);
- }
- free(p->config_storage);
- }
-
- free(p);
-
- return HANDLER_GO_ON;
+ return HANDLER_GO_ON;
}
-/* handle plugin config and check values */
-
-SETDEFAULTS_FUNC(mod_alias_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { "alias.url", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->alias = array_init();
- cv[0].destination = s->alias;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
-
- if (!array_is_kvstring(s->alias)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected value for alias.url; expected list of \"urlpath\" => \"filepath\"");
- return HANDLER_ERROR;
- }
-
- if (s->alias->used >= 2) {
- const array *a = s->alias;
- size_t j, k;
-
- for (j = 0; j < a->used; j ++) {
- const buffer *prefix = &a->sorted[j]->key;
- for (k = j + 1; k < a->used; k ++) {
- const buffer *key = &a->sorted[k]->key;
-
- if (buffer_string_length(key) < buffer_string_length(prefix)) {
- break;
- }
- if (memcmp(key->ptr, prefix->ptr, buffer_string_length(prefix)) != 0) {
- break;
- }
- /* ok, they have same prefix. check position */
- const data_unset *dj = a->sorted[j];
- const data_unset *dk = a->sorted[k];
- const data_unset **data = (const data_unset **)a->data;
- while (*data != dj && *data != dk) ++data;
- if (*data == dj) {
- log_error_write(srv, __FILE__, __LINE__, "SBSBS",
- "url.alias: `", key, "' will never match as `", prefix, "' matched first");
- return HANDLER_ERROR;
- }
- }
- }
- }
- }
-
- return HANDLER_GO_ON;
+static void mod_alias_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* alias.url */
+ pconf->alias = cpv->v.a;
+ break;
+ default:/* should not happen */
+ return;
+ }
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_alias_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(alias);
-
- /* 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;
+static void mod_alias_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_alias_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- /* merge config */
- for (j = 0; j < dc->value->used; j++) {
- data_unset *du = dc->value->data[j];
+static void mod_alias_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_alias_merge_config(&p->conf, p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
- if (buffer_is_equal_string(&du->key, CONST_STR_LEN("alias.url"))) {
- PATCH(alias);
- }
- }
- }
+static int mod_alias_check_order(server * const srv, const array * const a) {
+ for (uint32_t j = 0; j < a->used; ++j) {
+ const buffer * const prefix = &a->sorted[j]->key;
+ const size_t plen = buffer_string_length(prefix);
+ for (uint32_t k = j + 1; k < a->used; ++k) {
+ const buffer * const key = &a->sorted[k]->key;
+ if (buffer_string_length(key) < plen) {
+ break;
+ }
+ if (memcmp(key->ptr, prefix->ptr, plen) != 0) {
+ break;
+ }
+ /* ok, they have same prefix. check position */
+ const data_unset *dj = a->sorted[j];
+ const data_unset *dk = a->sorted[k];
+ const data_unset **data = (const data_unset **)a->data;
+ while (*data != dj && *data != dk) ++data;
+ if (*data == dj) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "url.alias: `%s' will never match as `%s' matched first",
+ key->ptr, prefix->ptr);
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
- return 0;
+SETDEFAULTS_FUNC(mod_alias_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("alias.url"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_alias"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* alias.url */
+ if (!array_is_kvstring(cpv->v.a)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s; "
+ "expected list of \"urlpath\" => \"filepath\"",
+ cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ if (cpv->v.a->used >= 2 && !mod_alias_check_order(srv,cpv->v.a))
+ return HANDLER_ERROR;
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+ }
+
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_alias_merge_config(&p->defaults, cpv);
+ }
+
+ return HANDLER_GO_ON;
}
-#undef PATCH
PHYSICALPATH_FUNC(mod_alias_physical_handler) {
plugin_data *p = p_d;
@@ -166,7 +143,8 @@ PHYSICALPATH_FUNC(mod_alias_physical_handler) {
if (0 == uri_len) return HANDLER_GO_ON;
- mod_alias_patch_connection(srv, con, p);
+ mod_alias_patch_config(con, p);
+ if (NULL == p->conf.alias) return HANDLER_GO_ON;
/* do not include trailing slash on basedir */
basedir_len = buffer_string_length(con->physical.basedir);
@@ -205,19 +183,16 @@ PHYSICALPATH_FUNC(mod_alias_physical_handler) {
return HANDLER_GO_ON;
}
-/* this function is called at dlopen() time and inits the callbacks */
int mod_alias_plugin_init(plugin *p);
int mod_alias_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("alias");
+ p->name = "alias";
p->init = mod_alias_init;
p->handle_physical= mod_alias_physical_handler;
p->set_defaults = mod_alias_set_defaults;
p->cleanup = mod_alias_free;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_auth.c b/src/mod_auth.c
index 0ebb5a36..ee3b4556 100644
--- a/src/mod_auth.c
+++ b/src/mod_auth.c
@@ -19,21 +19,15 @@
*/
typedef struct {
- /* auth */
- array *auth_require;
- buffer *auth_backend_conf;
- unsigned short auth_extern_authn;
-
- /* generated */
- const http_auth_backend_t *auth_backend;
+ const http_auth_backend_t *auth_backend;
+ const array *auth_require;
+ unsigned int auth_extern_authn;
} plugin_config;
typedef struct {
- PLUGIN_DATA;
-
- plugin_config **config_storage;
-
- plugin_config conf;
+ PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
} plugin_data;
static handler_t mod_auth_check_basic(server *srv, connection *con, void *p_d, const struct http_auth_require_t *require, const struct http_auth_backend_t *backend);
@@ -56,31 +50,34 @@ INIT_FUNC(mod_auth_init) {
return p;
}
-FREE_FUNC(mod_auth_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- 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 (NULL == s) continue;
-
- array_free(s->auth_require);
- buffer_free(s->auth_backend_conf);
+static void mod_auth_free_config(plugin_data * const p) {
+ if (NULL == p->cvlist) return;
+ /* (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ if (cpv->vtype != T_CONFIG_LOCAL || NULL == cpv->v.v) continue;
+ switch (cpv->k_id) {
+ case 1: /* auth.require */
+ array_free(cpv->v.v);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
- free(s);
- }
- free(p->config_storage);
- }
+FREE_FUNC(mod_auth_free) {
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
- free(p);
+ mod_auth_free_config(p);
- return HANDLER_GO_ON;
+ free(p->cvlist);
+ free(p);
+ UNUSED(srv);
+ return HANDLER_GO_ON;
}
/* data type for mod_auth structured data
@@ -268,63 +265,11 @@ static int mod_auth_require_parse (server *srv, http_auth_require_t * const requ
return 1; /* success */
}
-SETDEFAULTS_FUNC(mod_auth_set_defaults) {
- plugin_data *p = p_d;
- size_t i;
-
- config_values_t cv[] = {
- { "auth.backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { "auth.require", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { "auth.extern-authn", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },/* 2 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
- size_t n;
- const data_array *da;
-
- s = calloc(1, sizeof(plugin_config));
- s->auth_backend_conf = buffer_init();
-
- s->auth_require = array_init();
-
- cv[0].destination = s->auth_backend_conf;
- cv[1].destination = s->auth_require; /* T_CONFIG_LOCAL; not modified by config_insert_values_global() */
- cv[2].destination = &s->auth_extern_authn;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
-
- if (!buffer_string_is_empty(s->auth_backend_conf)) {
- s->auth_backend = http_auth_backend_get(s->auth_backend_conf);
- if (NULL == s->auth_backend) {
- log_error_write(srv, __FILE__, __LINE__, "sb", "auth.backend not supported:", s->auth_backend_conf);
-
- return HANDLER_ERROR;
- }
- }
-
- /* no auth.require for this section */
- if (NULL == (da = (const data_array *)array_get_element_klen(config->value, CONST_STR_LEN("auth.require")))) continue;
-
- if (da->type != TYPE_ARRAY || !array_is_kvarray(&da->value)) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "unexpected value for auth.require; expected ",
- "auth.require = ( \"urlpath\" => ( \"option\" => \"value\" ) )");
- return HANDLER_ERROR;
- }
-
-
- for (n = 0; n < da->value.used; n++) {
+static handler_t mod_auth_require_parse_array(server *srv, const array *value, array * const auth_require)
+{
+ for (uint32_t n = 0; n < value->used; ++n) {
size_t m;
- data_array *da_file = (data_array *)da->value.data[n];
+ data_array *da_file = (data_array *)value->data[n];
const buffer *method = NULL, *realm = NULL, *require = NULL;
const http_auth_scheme_t *auth_scheme;
buffer *algos = NULL;
@@ -417,55 +362,125 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) {
dauth->fn->free((data_unset *)dauth);
return HANDLER_ERROR;
}
- array_insert_unique(s->auth_require, (data_unset *)dauth);
+ array_insert_unique(auth_require, (data_unset *)dauth);
}
}
- }
return HANDLER_GO_ON;
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_auth_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(auth_backend);
- PATCH(auth_require);
- PATCH(auth_extern_authn);
-
- /* 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("auth.backend"))) {
- PATCH(auth_backend);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.require"))) {
- PATCH(auth_require);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.extern-authn"))) {
- PATCH(auth_extern_authn);
- }
- }
- }
+static void mod_auth_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* auth.backend */
+ if (cpv->vtype == T_CONFIG_LOCAL)
+ pconf->auth_backend = cpv->v.v;
+ break;
+ case 1: /* auth.require */
+ if (cpv->vtype == T_CONFIG_LOCAL)
+ pconf->auth_require = cpv->v.v;
+ break;
+ case 2: /* auth.extern-authn */
+ pconf->auth_extern_authn = cpv->v.u;
+ default:/* should not happen */
+ return;
+ }
+}
- return 0;
+static void mod_auth_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_auth_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
+
+static void mod_auth_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_auth_merge_config(&p->conf, p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
+
+SETDEFAULTS_FUNC(mod_auth_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("auth.backend"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.require"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.extern-authn"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_auth"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* auth.backend */
+ if (!buffer_string_is_empty(cpv->v.b)) {
+ const http_auth_backend_t * const auth_backend =
+ http_auth_backend_get(cpv->v.b);
+ if (NULL == auth_backend) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "auth.backend not supported: %s", cpv->v.b->ptr);
+ return HANDLER_ERROR;
+ }
+ *(const http_auth_backend_t **)&cpv->v.v = auth_backend;
+ cpv->vtype = T_CONFIG_LOCAL;
+ }
+ break;
+ case 1: /* auth.require */
+ if (array_is_kvarray(cpv->v.a)) {
+ array * const a = array_init();
+ if (HANDLER_GO_ON !=
+ mod_auth_require_parse_array(srv, cpv->v.a, a)) {
+ array_free(a);
+ return HANDLER_ERROR;
+ }
+ cpv->v.a = a;
+ cpv->vtype = T_CONFIG_LOCAL;
+ }
+ else {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s; expected "
+ "%s = ( \"urlpath\" => ( \"option\" => \"value\" ) )",
+ cpk[cpv->k_id].k, cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ break;
+ case 2: /* auth.extern-authn */
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+ }
+
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_auth_merge_config(&p->defaults, cpv);
+ }
+
+ return HANDLER_GO_ON;
}
-#undef PATCH
static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) {
plugin_data *p = p_d;
data_auth *dauth;
- mod_auth_patch_connection(srv, con, p);
+ mod_auth_patch_config(con, p);
if (p->conf.auth_require == NULL) return HANDLER_GO_ON;
@@ -491,14 +506,12 @@ static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) {
int mod_auth_plugin_init(plugin *p);
int mod_auth_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("auth");
+ p->name = "auth";
p->init = mod_auth_init;
p->set_defaults = mod_auth_set_defaults;
p->handle_uri_clean = mod_auth_uri_handler;
p->cleanup = mod_auth_free;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_authn_file.c b/src/mod_authn_file.c
index 01142230..d7c149a2 100644
--- a/src/mod_authn_file.c
+++ b/src/mod_authn_file.c
@@ -47,15 +47,15 @@
*/
typedef struct {
- buffer *auth_plain_groupfile;
- buffer *auth_plain_userfile;
- buffer *auth_htdigest_userfile;
- buffer *auth_htpasswd_userfile;
+ const buffer *auth_plain_groupfile;
+ const buffer *auth_plain_userfile;
+ const buffer *auth_htdigest_userfile;
+ const buffer *auth_htpasswd_userfile;
} plugin_config;
typedef struct {
PLUGIN_DATA;
- plugin_config **config_storage;
+ plugin_config defaults;
plugin_config conf;
} plugin_data;
@@ -91,111 +91,81 @@ INIT_FUNC(mod_authn_file_init) {
FREE_FUNC(mod_authn_file_free) {
plugin_data *p = p_d;
-
- UNUSED(srv);
-
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 (NULL == s) continue;
-
- buffer_free(s->auth_plain_groupfile);
- buffer_free(s->auth_plain_userfile);
- buffer_free(s->auth_htdigest_userfile);
- buffer_free(s->auth_htpasswd_userfile);
+ free(p->cvlist);
+ free(p);
+ UNUSED(srv);
+ return HANDLER_GO_ON;
+}
- free(s);
- }
- free(p->config_storage);
+static void mod_authn_file_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* auth.backend.plain.groupfile */
+ pconf->auth_plain_groupfile = cpv->v.b;
+ break;
+ case 1: /* auth.backend.plain.userfile */
+ pconf->auth_plain_userfile = cpv->v.b;
+ break;
+ case 2: /* auth.backend.htdigest.userfile */
+ pconf->auth_htdigest_userfile = cpv->v.b;
+ break;
+ case 3: /* auth.backend.htpasswd.userfile */
+ pconf->auth_htpasswd_userfile = cpv->v.b;
+ break;
+ default:/* should not happen */
+ return;
}
+}
- free(p);
+static void mod_authn_file_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_authn_file_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- return HANDLER_GO_ON;
+static void mod_authn_file_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_authn_file_merge_config(&p->conf,
+ p->cvlist + p->cvlist[i].v.u2[0]);
+ }
}
SETDEFAULTS_FUNC(mod_authn_file_set_defaults) {
- plugin_data *p = p_d;
- size_t i;
-
- config_values_t cv[] = {
- { "auth.backend.plain.groupfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { "auth.backend.plain.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { "auth.backend.htdigest.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
- { "auth.backend.htpasswd.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("auth.backend.plain.groupfile"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.plain.userfile"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.htdigest.userfile"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.htpasswd.userfile"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
};
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->auth_plain_groupfile = buffer_init();
- s->auth_plain_userfile = buffer_init();
- s->auth_htdigest_userfile = buffer_init();
- s->auth_htpasswd_userfile = buffer_init();
-
- cv[0].destination = s->auth_plain_groupfile;
- cv[1].destination = s->auth_plain_userfile;
- cv[2].destination = s->auth_htdigest_userfile;
- cv[3].destination = s->auth_htpasswd_userfile;
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_authn_file"))
+ return HANDLER_ERROR;
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_authn_file_merge_config(&p->defaults, cpv);
}
return HANDLER_GO_ON;
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_authn_file_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(auth_plain_groupfile);
- PATCH(auth_plain_userfile);
- PATCH(auth_htdigest_userfile);
- PATCH(auth_htpasswd_userfile);
-
- /* 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("auth.backend.plain.groupfile"))) {
- PATCH(auth_plain_groupfile);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.plain.userfile"))) {
- PATCH(auth_plain_userfile);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.htdigest.userfile"))) {
- PATCH(auth_htdigest_userfile);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.htpasswd.userfile"))) {
- PATCH(auth_htpasswd_userfile);
- }
- }
- }
-
- return 0;
-}
-#undef PATCH
-
@@ -315,7 +285,7 @@ static int mod_authn_file_htdigest_get(server *srv, connection *con, void *p_d,
const buffer *auth_fn;
FILE *fp;
- mod_authn_file_patch_connection(srv, con, p);
+ mod_authn_file_patch_config(con, p);
auth_fn = p->conf.auth_htdigest_userfile;
if (buffer_string_is_empty(auth_fn)) return -1;
@@ -426,7 +396,7 @@ static handler_t mod_authn_file_plain_digest(server *srv, connection *con, void
plugin_data *p = (plugin_data *)p_d;
buffer *password_buf = buffer_init();/* password-string from auth-backend */
int rc;
- mod_authn_file_patch_connection(srv, con, p);
+ mod_authn_file_patch_config(con, p);
rc = mod_authn_file_htpasswd_get(srv, p->conf.auth_plain_userfile, ai->username, ai->ulen, password_buf);
if (0 == rc) {
/* generate password from plain-text */
@@ -440,7 +410,7 @@ static handler_t mod_authn_file_plain_basic(server *srv, connection *con, void *
plugin_data *p = (plugin_data *)p_d;
buffer *password_buf = buffer_init();/* password-string from auth-backend */
int rc;
- mod_authn_file_patch_connection(srv, con, p);
+ mod_authn_file_patch_config(con, p);
rc = mod_authn_file_htpasswd_get(srv, p->conf.auth_plain_userfile, CONST_BUF_LEN(username), password_buf);
if (0 == rc) {
rc = http_auth_const_time_memeq_pad(CONST_BUF_LEN(password_buf), pw, strlen(pw)) ? 0 : -1;
@@ -664,7 +634,7 @@ static handler_t mod_authn_file_htpasswd_basic(server *srv, connection *con, voi
plugin_data *p = (plugin_data *)p_d;
buffer *password = buffer_init();/* password-string from auth-backend */
int rc;
- mod_authn_file_patch_connection(srv, con, p);
+ mod_authn_file_patch_config(con, p);
rc = mod_authn_file_htpasswd_get(srv, p->conf.auth_htpasswd_userfile, CONST_BUF_LEN(username), password);
if (0 == rc) {
char sample[256];
@@ -770,12 +740,10 @@ static handler_t mod_authn_file_htpasswd_basic(server *srv, connection *con, voi
int mod_authn_file_plugin_init(plugin *p);
int mod_authn_file_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("authn_file");
+ p->name = "authn_file";
p->init = mod_authn_file_init;
p->set_defaults= mod_authn_file_set_defaults;
p->cleanup = mod_authn_file_free;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_authn_gssapi.c b/src/mod_authn_gssapi.c
index d23d03b2..936f5aa9 100644
--- a/src/mod_authn_gssapi.c
+++ b/src/mod_authn_gssapi.c
@@ -39,14 +39,14 @@
#include <unistd.h>
typedef struct {
- buffer *auth_gssapi_keytab;
- buffer *auth_gssapi_principal;
- unsigned short int auth_gssapi_store_creds;
+ const buffer *auth_gssapi_keytab;
+ const buffer *auth_gssapi_principal;
+ unsigned int auth_gssapi_store_creds;
} plugin_config;
typedef struct {
PLUGIN_DATA;
- plugin_config **config_storage;
+ plugin_config defaults;
plugin_config conf;
} plugin_data;
@@ -71,105 +71,78 @@ INIT_FUNC(mod_authn_gssapi_init) {
FREE_FUNC(mod_authn_gssapi_free) {
plugin_data *p = p_d;
-
- UNUSED(srv);
-
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 (NULL == s) continue;
-
- buffer_free(s->auth_gssapi_keytab);
- buffer_free(s->auth_gssapi_principal);
+ free(p->cvlist);
+ free(p);
+ UNUSED(srv);
+ return HANDLER_GO_ON;
+}
- free(s);
- }
- free(p->config_storage);
+static void mod_authn_gssapi_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* auth.backend.gssapi.keytab */
+ pconf->auth_gssapi_keytab = cpv->v.b;
+ break;
+ case 1: /* auth.backend.gssapi.principal */
+ pconf->auth_gssapi_principal = cpv->v.b;
+ break;
+ case 2: /* auth.backend.gssapi.store-creds */
+ pconf->auth_gssapi_store_creds = cpv->v.u;
+ break;
+ default:/* should not happen */
+ return;
}
+}
- free(p);
+static void mod_authn_gssapi_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_authn_gssapi_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- return HANDLER_GO_ON;
+static void mod_authn_gssapi_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_authn_gssapi_merge_config(&p->conf,
+ p->cvlist + p->cvlist[i].v.u2[0]);
+ }
}
SETDEFAULTS_FUNC(mod_authn_gssapi_set_defaults) {
- plugin_data *p = p_d;
- size_t i;
- config_values_t cv[] = {
- { "auth.backend.gssapi.keytab", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.gssapi.principal", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.gssapi.store-creds",NULL, T_CONFIG_BOOLEAN,T_CONFIG_SCOPE_CONNECTION },
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("auth.backend.gssapi.keytab"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.gssapi.principal"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.gssapi.store-creds"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
};
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_authn_gssapi"))
+ return HANDLER_ERROR;
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
+ /* default enabled for backwards compatibility; disable in future */
+ p->defaults.auth_gssapi_store_creds = 1;
- s = calloc(1, sizeof(plugin_config));
-
- s->auth_gssapi_keytab = buffer_init();
- s->auth_gssapi_principal = buffer_init();
-
- cv[0].destination = s->auth_gssapi_keytab;
- cv[1].destination = s->auth_gssapi_principal;
- cv[2].destination = &s->auth_gssapi_store_creds;
- /* default enabled for backwards compatibility; disable in future */
- s->auth_gssapi_store_creds = 1;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_authn_gssapi_merge_config(&p->defaults, cpv);
}
return HANDLER_GO_ON;
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_authn_gssapi_patch_connection(server *srv, connection *con, plugin_data *p)
-{
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(auth_gssapi_keytab);
- PATCH(auth_gssapi_principal);
- PATCH(auth_gssapi_store_creds);
-
- /* 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("auth.backend.gssapi.keytab"))) {
- PATCH(auth_gssapi_keytab);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.gssapi.principal"))) {
- PATCH(auth_gssapi_principal);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.gssapi.store-creds"))) {
- PATCH(auth_gssapi_store_creds);
- }
- }
- }
-
- return 0;
-}
-#undef PATCH
-
static handler_t mod_authn_gssapi_send_400_bad_request (server *srv, connection *con)
{
UNUSED(srv);
@@ -358,7 +331,7 @@ static handler_t mod_authn_gssapi_check_spnego(server *srv, connection *con, plu
return mod_authn_gssapi_send_400_bad_request(srv, con);
}
- mod_authn_gssapi_patch_connection(srv, con, p);
+ mod_authn_gssapi_patch_config(con, p);
{
/* ??? Should code = krb5_kt_resolve(kcontext, p->conf.auth_gssapi_keytab->ptr, &keytab);
@@ -662,7 +635,7 @@ static handler_t mod_authn_gssapi_basic(server *srv, connection *con, void *p_d,
return mod_authn_gssapi_send_401_unauthorized_basic(con);
}
- mod_authn_gssapi_patch_connection(srv, con, p);
+ mod_authn_gssapi_patch_config(con, p);
code = krb5_init_context(&kcontext);
if (code) {
@@ -670,6 +643,11 @@ static handler_t mod_authn_gssapi_basic(server *srv, connection *con, void *p_d,
return mod_authn_gssapi_send_401_unauthorized_basic(con); /*(well, should be 500)*/
}
+ if (buffer_string_is_empty(p->conf.auth_gssapi_keytab)) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "auth.backend.gssapi.keytab not configured");
+ return mod_authn_gssapi_send_401_unauthorized_basic(con); /*(well, should be 500)*/
+ }
+
code = krb5_kt_resolve(kcontext, p->conf.auth_gssapi_keytab->ptr, &keytab);
if (code) {
log_error_write(srv, __FILE__, __LINE__, "sdb", "krb5_kt_resolve():", code, p->conf.auth_gssapi_keytab);
@@ -811,13 +789,11 @@ CONNECTION_FUNC(mod_authn_gssapi_handle_reset) {
int mod_authn_gssapi_plugin_init(plugin *p);
int mod_authn_gssapi_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("authn_gssapi");
+ p->name = "authn_gssapi";
p->init = mod_authn_gssapi_init;
p->set_defaults= mod_authn_gssapi_set_defaults;
p->cleanup = mod_authn_gssapi_free;
p->connection_reset = mod_authn_gssapi_handle_reset;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_authn_ldap.c b/src/mod_authn_ldap.c
index fd4d5eb1..0c7699e6 100644
--- a/src/mod_authn_ldap.c
+++ b/src/mod_authn_ldap.c
@@ -14,24 +14,32 @@
typedef struct {
LDAP *ldap;
server *srv;
+ const char *auth_ldap_hostname;
+ const char *auth_ldap_binddn;
+ const char *auth_ldap_bindpw;
+ const char *auth_ldap_cafile;
+ int auth_ldap_starttls;
+} plugin_config_ldap;
- buffer *auth_ldap_hostname;
- buffer *auth_ldap_basedn;
- buffer *auth_ldap_binddn;
- buffer *auth_ldap_bindpw;
- buffer *auth_ldap_filter;
- buffer *auth_ldap_cafile;
- buffer *auth_ldap_groupmember;
- unsigned short auth_ldap_starttls;
- unsigned short auth_ldap_allow_empty_pw;
+typedef struct {
+ plugin_config_ldap *ldc;
+ const char *auth_ldap_basedn;
+ const buffer *auth_ldap_filter;
+ const buffer *auth_ldap_groupmember;
+ int auth_ldap_allow_empty_pw;
+
+ int auth_ldap_starttls;
+ const char *auth_ldap_binddn;
+ const char *auth_ldap_bindpw;
+ const char *auth_ldap_cafile;
} plugin_config;
typedef struct {
PLUGIN_DATA;
- plugin_config **config_storage;
- plugin_config conf, *anon_conf; /* this is only used as long as no handler_ctx is setup */
+ plugin_config defaults;
+ plugin_config conf;
- buffer *ldap_filter;
+ buffer ldap_filter;
} plugin_data;
static handler_t mod_authn_ldap_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw);
@@ -40,7 +48,6 @@ INIT_FUNC(mod_authn_ldap_init) {
static http_auth_backend_t http_auth_backend_ldap =
{ "ldap", mod_authn_ldap_basic, NULL, NULL };
plugin_data *p = calloc(1, sizeof(*p));
- p->ldap_filter = buffer_init();
/* register http_auth_backend_ldap */
http_auth_backend_ldap.p_d = p;
@@ -49,39 +56,89 @@ INIT_FUNC(mod_authn_ldap_init) {
return p;
}
+static void mod_authn_ldap_free_config(plugin_data *p) {
+ if (NULL == p->cvlist) return;
+ /* (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* auth.backend.ldap.hostname */
+ if (cpv->vtype == T_CONFIG_LOCAL) {
+ plugin_config_ldap *s = cpv->v.v;
+ if (NULL != s->ldap) ldap_unbind_ext_s(s->ldap, NULL, NULL);
+ free(s);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
FREE_FUNC(mod_authn_ldap_free) {
plugin_data *p = p_d;
-
- UNUSED(srv);
-
if (!p) return HANDLER_GO_ON;
- buffer_free(p->ldap_filter);
-
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- if (NULL == s) continue;
+ mod_authn_ldap_free_config(p);
+ free(p->ldap_filter.ptr);
- buffer_free(s->auth_ldap_hostname);
- buffer_free(s->auth_ldap_basedn);
- buffer_free(s->auth_ldap_binddn);
- buffer_free(s->auth_ldap_bindpw);
- buffer_free(s->auth_ldap_filter);
- buffer_free(s->auth_ldap_cafile);
- buffer_free(s->auth_ldap_groupmember);
+ free(p->cvlist);
+ free(p);
+ UNUSED(srv);
+ return HANDLER_GO_ON;
+}
- if (NULL != s->ldap) ldap_unbind_ext_s(s->ldap, NULL, NULL);
- free(s);
- }
- free(p->config_storage);
+static void mod_authn_ldap_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* auth.backend.ldap.hostname */
+ if (cpv->vtype == T_CONFIG_LOCAL)
+ pconf->ldc = cpv->v.v;
+ break;
+ case 1: /* auth.backend.ldap.base-dn */
+ if (cpv->vtype == T_CONFIG_LOCAL)
+ pconf->auth_ldap_basedn = cpv->v.v;
+ break;
+ case 2: /* auth.backend.ldap.filter */
+ pconf->auth_ldap_filter = cpv->v.v;
+ break;
+ case 3: /* auth.backend.ldap.ca-file */
+ pconf->auth_ldap_cafile = cpv->v.v;
+ break;
+ case 4: /* auth.backend.ldap.starttls */
+ pconf->auth_ldap_starttls = (int)cpv->v.u;
+ break;
+ case 5: /* auth.backend.ldap.bind-dn */
+ pconf->auth_ldap_binddn = cpv->v.v;
+ break;
+ case 6: /* auth.backend.ldap.bind-pw */
+ pconf->auth_ldap_bindpw = cpv->v.v;
+ break;
+ case 7: /* auth.backend.ldap.allow-empty-pw */
+ pconf->auth_ldap_allow_empty_pw = (int)cpv->v.u;
+ break;
+ case 8: /* auth.backend.ldap.groupmember */
+ pconf->auth_ldap_groupmember = cpv->v.b;
+ break;
+ default:/* should not happen */
+ return;
}
+}
- free(p);
+static void mod_authn_ldap_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_authn_ldap_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- return HANDLER_GO_ON;
+static void mod_authn_ldap_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_authn_ldap_merge_config(&p->conf,
+ p->cvlist + p->cvlist[i].v.u2[0]);
+ }
}
/*(copied from mod_vhostdb_ldap.c)*/
@@ -118,134 +175,155 @@ static void mod_authn_add_scheme (server *srv, buffer *host)
}
SETDEFAULTS_FUNC(mod_authn_ldap_set_defaults) {
- plugin_data *p = p_d;
- size_t i;
-config_values_t cv[] = {
- { "auth.backend.ldap.hostname", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { "auth.backend.ldap.base-dn", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { "auth.backend.ldap.filter", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
- { "auth.backend.ldap.ca-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
- { "auth.backend.ldap.starttls", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
- { "auth.backend.ldap.bind-dn", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
- { "auth.backend.ldap.bind-pw", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
- { "auth.backend.ldap.allow-empty-pw", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
- { "auth.backend.ldap.groupmember", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("auth.backend.ldap.hostname"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.ldap.base-dn"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.ldap.filter"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.ldap.ca-file"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.ldap.starttls"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.ldap.bind-dn"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.ldap.bind-pw"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.ldap.allow-empty-pw"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.ldap.groupmember"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
};
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
-
- s->auth_ldap_hostname = buffer_init();
- s->auth_ldap_basedn = buffer_init();
- s->auth_ldap_binddn = buffer_init();
- s->auth_ldap_bindpw = buffer_init();
- s->auth_ldap_filter = buffer_init();
- s->auth_ldap_cafile = buffer_init();
- s->auth_ldap_groupmember = buffer_init_string("memberUid");
- s->auth_ldap_starttls = 0;
- s->ldap = NULL;
-
- cv[0].destination = s->auth_ldap_hostname;
- cv[1].destination = s->auth_ldap_basedn;
- cv[2].destination = s->auth_ldap_filter;
- cv[3].destination = s->auth_ldap_cafile;
- cv[4].destination = &(s->auth_ldap_starttls);
- cv[5].destination = s->auth_ldap_binddn;
- cv[6].destination = s->auth_ldap_bindpw;
- cv[7].destination = &(s->auth_ldap_allow_empty_pw);
- cv[8].destination = s->auth_ldap_groupmember;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_authn_ldap"))
+ return HANDLER_ERROR;
- if (!buffer_string_is_empty(s->auth_ldap_filter)) {
- if (*s->auth_ldap_filter->ptr != ',') {
- /*(translate '$' to '?' for consistency with other modules)*/
- char *d = s->auth_ldap_filter->ptr;
- for (; NULL != (d = strchr(d, '$')); ++d) *d = '?';
- if (NULL == strchr(s->auth_ldap_filter->ptr, '?')) {
- log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.filter is missing a replace-operator '?'");
- return HANDLER_ERROR;
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ plugin_config_ldap *ldc = NULL;
+ char *binddn = NULL, *bindpw = NULL, *cafile = NULL;
+ int starttls = 0;
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* auth.backend.ldap.hostname */
+ if (!buffer_string_is_empty(cpv->v.b)) {
+ buffer *b;
+ *(const buffer **)&b = cpv->v.b;
+ mod_authn_add_scheme(srv, b);
+ ldc = malloc(sizeof(plugin_config_ldap));
+ force_assert(ldc);
+ ldc->srv = srv;
+ ldc->auth_ldap_hostname = b->ptr;
+ cpv->v.v = ldc;
+ }
+ else {
+ cpv->v.v = NULL;
+ }
+ cpv->vtype = T_CONFIG_LOCAL;
+ break;
+ case 1: /* auth.backend.ldap.base-dn */
+ cpv->vtype = T_CONFIG_LOCAL;
+ cpv->v.v = !buffer_string_is_empty(cpv->v.b)
+ ? cpv->v.b->ptr
+ : NULL;
+ break;
+ case 2: /* auth.backend.ldap.filter */
+ if (!buffer_string_is_empty(cpv->v.b)) {
+ buffer *b;
+ *(const buffer **)&b = cpv->v.b;
+ if (*b->ptr != ',') {
+ /*(translate $ to ? for consistency w/ other modules)*/
+ char *d = b->ptr;
+ for (; NULL != (d = strchr(d, '$')); ++d) *d = '?';
+ if (NULL == strchr(b->ptr, '?')) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "ldap: %s is missing a replace-operator '?'",
+ cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ }
+ cpv->v.v = b;
+ }
+ else {
+ cpv->v.v = NULL;
}
+ cpv->vtype = T_CONFIG_LOCAL;
+ break;
+ case 3: /* auth.backend.ldap.ca-file */
+ cafile = !buffer_string_is_empty(cpv->v.b)
+ ? cpv->v.b->ptr
+ : NULL;
+ cpv->vtype = T_CONFIG_LOCAL;
+ cpv->v.v = cafile;
+ break;
+ case 4: /* auth.backend.ldap.starttls */
+ starttls = (int)cpv->v.u;
+ break;
+ case 5: /* auth.backend.ldap.bind-dn */
+ binddn = !buffer_string_is_empty(cpv->v.b)
+ ? cpv->v.b->ptr
+ : NULL;
+ cpv->vtype = T_CONFIG_LOCAL;
+ cpv->v.v = binddn;
+ break;
+ case 6: /* auth.backend.ldap.bind-pw */
+ cpv->vtype = T_CONFIG_LOCAL;
+ cpv->v.v = bindpw = cpv->v.b->ptr;
+ break;
+ case 7: /* auth.backend.ldap.allow-empty-pw */
+ case 8: /* auth.backend.ldap.groupmember */
+ break;
+ default:/* should not happen */
+ break;
}
}
- mod_authn_add_scheme(srv, s->auth_ldap_hostname);
+ if (ldc) {
+ ldc->auth_ldap_binddn = binddn;
+ ldc->auth_ldap_bindpw = bindpw;
+ ldc->auth_ldap_cafile = cafile;
+ ldc->auth_ldap_starttls = starttls;
+ }
}
- return HANDLER_GO_ON;
-}
+ static const struct { const char *ptr; uint32_t used; uint32_t size; }
+ memberUid = { "memberUid", sizeof("memberUid"), 0 };
+ *(const buffer **)&p->defaults.auth_ldap_groupmember =
+ (const buffer *)&memberUid;
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_authn_ldap_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(auth_ldap_hostname);
- PATCH(auth_ldap_basedn);
- PATCH(auth_ldap_binddn);
- PATCH(auth_ldap_bindpw);
- PATCH(auth_ldap_filter);
- PATCH(auth_ldap_cafile);
- PATCH(auth_ldap_starttls);
- PATCH(auth_ldap_allow_empty_pw);
- PATCH(auth_ldap_groupmember);
- p->anon_conf = s;
-
- /* 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("auth.backend.ldap.hostname"))) {
- PATCH(auth_ldap_hostname);
- p->anon_conf = s;
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.ldap.base-dn"))) {
- PATCH(auth_ldap_basedn);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.ldap.filter"))) {
- PATCH(auth_ldap_filter);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.ldap.ca-file"))) {
- PATCH(auth_ldap_cafile);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.ldap.starttls"))) {
- PATCH(auth_ldap_starttls);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.ldap.bind-dn"))) {
- PATCH(auth_ldap_binddn);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.ldap.bind-pw"))) {
- PATCH(auth_ldap_bindpw);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.ldap.allow-empty-pw"))) {
- PATCH(auth_ldap_allow_empty_pw);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.ldap.groupmember"))) {
- PATCH(auth_ldap_groupmember);
- }
- }
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_authn_ldap_merge_config(&p->defaults, cpv);
}
- return 0;
+ return HANDLER_GO_ON;
}
-#undef PATCH
+__attribute_cold__
static void mod_authn_ldap_err(server *srv, const char *file, unsigned long line, const char *fn, int err)
{
log_error_write(srv,file,line,"sSss","ldap:",fn,":",ldap_err2string(err));
}
+__attribute_cold__
static void mod_authn_ldap_opt_err(server *srv, const char *file, unsigned long line, const char *fn, LDAP *ld)
{
int err;
@@ -384,13 +462,13 @@ static void mod_authn_append_ldap_filter_escape(buffer * const filter, const buf
}
}
-static LDAP * mod_authn_ldap_host_init(server *srv, plugin_config *s) {
+static LDAP * mod_authn_ldap_host_init(server *srv, plugin_config_ldap *s) {
LDAP *ld;
int ret;
- if (buffer_string_is_empty(s->auth_ldap_hostname)) return NULL;
+ if (NULL == s->auth_ldap_hostname) return NULL;
- if (LDAP_SUCCESS != ldap_initialize(&ld, s->auth_ldap_hostname->ptr)) {
+ if (LDAP_SUCCESS != ldap_initialize(&ld, s->auth_ldap_hostname)) {
log_error_write(srv, __FILE__, __LINE__, "sss", "ldap:",
"ldap_initialize():", strerror(errno));
return NULL;
@@ -410,9 +488,9 @@ static LDAP * mod_authn_ldap_host_init(server *srv, plugin_config *s) {
if (s->auth_ldap_starttls) {
/* if no CA file is given, it is ok, as we will use encryption
* if the server requires a CAfile it will tell us */
- if (!buffer_string_is_empty(s->auth_ldap_cafile)) {
+ if (s->auth_ldap_cafile) {
ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
- s->auth_ldap_cafile->ptr);
+ s->auth_ldap_cafile);
if (LDAP_OPT_SUCCESS != ret) {
mod_authn_ldap_err(srv, __FILE__, __LINE__,
"ldap_set_option(LDAP_OPT_X_TLS_CACERTFILE)",
@@ -456,18 +534,18 @@ static int mod_authn_ldap_bind(server *srv, LDAP *ld, const char *dn, const char
}
static int mod_authn_ldap_rebind_proc (LDAP *ld, LDAP_CONST char *url, ber_tag_t ldap_request, ber_int_t msgid, void *params) {
- plugin_config *s = (plugin_config *)params;
+ const plugin_config_ldap *s = (const plugin_config_ldap *)params;
UNUSED(url);
UNUSED(ldap_request);
UNUSED(msgid);
- return !buffer_string_is_empty(s->auth_ldap_binddn)
+ return s->auth_ldap_binddn
? mod_authn_ldap_bind(s->srv, ld,
- s->auth_ldap_binddn->ptr,
- s->auth_ldap_bindpw->ptr)
+ s->auth_ldap_binddn,
+ s->auth_ldap_bindpw)
: mod_authn_ldap_bind(s->srv, ld, NULL, NULL);
}
-static LDAPMessage * mod_authn_ldap_search(server *srv, plugin_config *s, char *base, char *filter) {
+static LDAPMessage * mod_authn_ldap_search(server *srv, plugin_config_ldap *s, const char *base, const char *filter) {
LDAPMessage *lm = NULL;
char *attrs[] = { LDAP_NO_ATTRS, NULL };
int ret;
@@ -522,7 +600,7 @@ static LDAPMessage * mod_authn_ldap_search(server *srv, plugin_config *s, char *
return lm;
}
-static char * mod_authn_ldap_get_dn(server *srv, plugin_config *s, char *base, char *filter) {
+static char * mod_authn_ldap_get_dn(server *srv, plugin_config_ldap *s, const char *base, const char *filter) {
LDAP *ld;
LDAPMessage *lm, *first;
char *dn;
@@ -577,11 +655,12 @@ static handler_t mod_authn_ldap_memberOf(server *srv, plugin_config *s, const ht
}
buffer_append_string_len(filter, CONST_STR_LEN(")"));
+ plugin_config_ldap * const ldc = s->ldc;
for (size_t i = 0; i < groups->used; ++i) {
- char *base = groups->data[i]->key.ptr;
- LDAPMessage *lm = mod_authn_ldap_search(srv, s, base, filter->ptr);
+ const char *base = groups->data[i]->key.ptr;
+ LDAPMessage *lm = mod_authn_ldap_search(srv, ldc, base, filter->ptr);
if (NULL != lm) {
- int count = ldap_count_entries(s->ldap, lm);
+ int count = ldap_count_entries(ldc->ldap, lm);
ldap_msgfree(lm);
if (count > 0) {
rc = HANDLER_GO_ON;
@@ -598,100 +677,111 @@ static handler_t mod_authn_ldap_basic(server *srv, connection *con, void *p_d, c
plugin_data *p = (plugin_data *)p_d;
LDAP *ld;
char *dn;
- buffer *template;
- handler_t rc;
- mod_authn_ldap_patch_connection(srv, con, p);
- p->anon_conf->srv = srv;
- p->conf.srv = srv;
+ mod_authn_ldap_patch_config(con, p);
if (pw[0] == '\0' && !p->conf.auth_ldap_allow_empty_pw)
return HANDLER_ERROR;
- template = p->conf.auth_ldap_filter;
- if (buffer_string_is_empty(template)) {
+ const buffer * const template = p->conf.auth_ldap_filter;
+ if (NULL == template)
return HANDLER_ERROR;
- }
/* build filter to get DN for uid = username */
- buffer_clear(p->ldap_filter);
+ buffer * const ldap_filter = &p->ldap_filter;
+ buffer_clear(ldap_filter);
if (*template->ptr == ',') {
/* special-case filter template beginning with ',' to be explicit DN */
- buffer_append_string_len(p->ldap_filter, CONST_STR_LEN("uid="));
- mod_authn_append_ldap_dn_escape(p->ldap_filter, username);
- buffer_append_string_buffer(p->ldap_filter, template);
- dn = p->ldap_filter->ptr;
- } else {
- for (char *b = template->ptr, *d; *b; b = d+1) {
+ buffer_append_string_len(ldap_filter, CONST_STR_LEN("uid="));
+ mod_authn_append_ldap_dn_escape(ldap_filter, username);
+ buffer_append_string_buffer(ldap_filter, template);
+ dn = ldap_filter->ptr;
+ }
+ else {
+ for (const char *b = template->ptr, *d; *b; b = d+1) {
if (NULL != (d = strchr(b, '?'))) {
- buffer_append_string_len(p->ldap_filter, b, (size_t)(d - b));
- mod_authn_append_ldap_filter_escape(p->ldap_filter, username);
- } else {
+ buffer_append_string_len(ldap_filter, b, (size_t)(d - b));
+ mod_authn_append_ldap_filter_escape(ldap_filter, username);
+ }
+ else {
d = template->ptr + buffer_string_length(template);
- buffer_append_string_len(p->ldap_filter, b, (size_t)(d - b));
+ buffer_append_string_len(ldap_filter, b, (size_t)(d - b));
break;
}
}
/* ldap_search for DN (synchronous; blocking) */
- dn = mod_authn_ldap_get_dn(srv, p->anon_conf,
- p->conf.auth_ldap_basedn->ptr,
- p->ldap_filter->ptr);
- if (NULL == dn) {
- return HANDLER_ERROR;
- }
+ dn = mod_authn_ldap_get_dn(srv, p->conf.ldc,
+ p->conf.auth_ldap_basedn, ldap_filter->ptr);
+ if (NULL == dn) return HANDLER_ERROR;
}
- /* auth against LDAP server (synchronous; blocking) */
-
- ld = mod_authn_ldap_host_init(srv, &p->conf);
- if (NULL == ld) {
- if (dn != p->ldap_filter->ptr) ldap_memfree(dn);
- return HANDLER_ERROR;
+ /*(Check ldc here rather than further up to preserve historical behavior
+ * where p->conf.ldc above (was p->anon_conf above) is set of directives in
+ * same context as auth_ldap_hostname. Preference: admin intentions are
+ * clearer if directives are always together in a set in same context)*/
+
+ plugin_config_ldap * const ldc_base = p->conf.ldc;
+ plugin_config_ldap ldc_custom;
+
+ if ( p->conf.ldc->auth_ldap_starttls != p->conf.auth_ldap_starttls
+ || p->conf.ldc->auth_ldap_binddn != p->conf.auth_ldap_binddn
+ || p->conf.ldc->auth_ldap_bindpw != p->conf.auth_ldap_bindpw
+ || p->conf.ldc->auth_ldap_cafile != p->conf.auth_ldap_cafile ) {
+ ldc_custom.ldap = NULL;
+ ldc_custom.srv = srv;
+ ldc_custom.auth_ldap_hostname = ldc_base->auth_ldap_hostname;
+ ldc_custom.auth_ldap_starttls = p->conf.auth_ldap_starttls;
+ ldc_custom.auth_ldap_binddn = p->conf.auth_ldap_binddn;
+ ldc_custom.auth_ldap_bindpw = p->conf.auth_ldap_bindpw;
+ ldc_custom.auth_ldap_cafile = p->conf.auth_ldap_cafile;
+ p->conf.ldc = &ldc_custom;
}
- /* Disable referral tracking. Target user should be in provided scope */
- {
+ handler_t rc = HANDLER_ERROR;
+ do {
+ /* auth against LDAP server (synchronous; blocking) */
+
+ ld = mod_authn_ldap_host_init(srv, p->conf.ldc);
+ if (NULL == ld)
+ break;
+
+ /* Disable referral tracking; target user should be in provided scope */
int ret = ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
if (LDAP_OPT_SUCCESS != ret) {
mod_authn_ldap_err(srv,__FILE__,__LINE__,"ldap_set_option()",ret);
- ldap_destroy(ld);
- if (dn != p->ldap_filter->ptr) ldap_memfree(dn);
- return HANDLER_ERROR;
+ break;
}
- }
- if (LDAP_SUCCESS != mod_authn_ldap_bind(srv, ld, dn, pw)) {
- ldap_destroy(ld);
- if (dn != p->ldap_filter->ptr) ldap_memfree(dn);
- return HANDLER_ERROR;
- }
+ if (LDAP_SUCCESS != mod_authn_ldap_bind(srv, ld, dn, pw))
+ break;
- ldap_unbind_ext_s(ld, NULL, NULL); /* disconnect */
+ ldap_unbind_ext_s(ld, NULL, NULL); /* disconnect */
+ ld = NULL;
- if (http_auth_match_rules(require, username->ptr, NULL, NULL)) {
- rc = HANDLER_GO_ON; /* access granted */
- } else {
- rc = HANDLER_ERROR;
- if (require->group->used) {
- /*(must not re-use p->ldap_filter, since it might be used for dn)*/
- rc = mod_authn_ldap_memberOf(srv, &p->conf, require, username, dn);
+ if (http_auth_match_rules(require, username->ptr, NULL, NULL)) {
+ rc = HANDLER_GO_ON; /* access granted */
}
- }
+ else if (require->group->used) {
+ /*(must not re-use ldap_filter, since it might be used for dn)*/
+ rc = mod_authn_ldap_memberOf(srv,&p->conf,require,username,dn);
+ }
+ } while (0);
- if (dn != p->ldap_filter->ptr) ldap_memfree(dn);
+ if (NULL != ld) ldap_destroy(ld);
+ if (ldc_base != p->conf.ldc && NULL != p->conf.ldc->ldap)
+ ldap_unbind_ext_s(p->conf.ldc->ldap, NULL, NULL);
+ if (dn != ldap_filter->ptr) ldap_memfree(dn);
return rc;
}
int mod_authn_ldap_plugin_init(plugin *p);
int mod_authn_ldap_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("authn_ldap");
+ p->name = "authn_ldap";
p->init = mod_authn_ldap_init;
p->set_defaults = mod_authn_ldap_set_defaults;
p->cleanup = mod_authn_ldap_free;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_authn_mysql.c b/src/mod_authn_mysql.c
index 11339160..1195aad8 100644
--- a/src/mod_authn_mysql.c
+++ b/src/mod_authn_mysql.c
@@ -39,99 +39,105 @@
#endif
typedef struct {
- MYSQL *mysql_conn;
- buffer *mysql_conn_host;
- buffer *mysql_conn_user;
- buffer *mysql_conn_pass;
- buffer *mysql_conn_db;
- int mysql_conn_port;
int auth_mysql_port;
- buffer *auth_mysql_host;
- buffer *auth_mysql_user;
- buffer *auth_mysql_pass;
- buffer *auth_mysql_db;
- buffer *auth_mysql_socket;
- buffer *auth_mysql_users_table;
- buffer *auth_mysql_col_user;
- buffer *auth_mysql_col_pass;
- buffer *auth_mysql_col_realm;
+ const char *auth_mysql_host;
+ const char *auth_mysql_user;
+ const char *auth_mysql_pass;
+ const char *auth_mysql_db;
+ const char *auth_mysql_socket;
+ const char *auth_mysql_users_table;
+ const char *auth_mysql_col_user;
+ const char *auth_mysql_col_pass;
+ const char *auth_mysql_col_realm;
} plugin_config;
typedef struct {
PLUGIN_DATA;
- plugin_config **config_storage;
+ plugin_config defaults;
plugin_config conf;
+
+ MYSQL *mysql_conn;
+ const char *mysql_conn_host;
+ const char *mysql_conn_user;
+ const char *mysql_conn_pass;
+ const char *mysql_conn_db;
+ int mysql_conn_port;
} plugin_data;
-static void mod_authn_mysql_sock_close(plugin_config *pconf) {
- if (NULL != pconf->mysql_conn) {
- mysql_close(pconf->mysql_conn);
- pconf->mysql_conn = NULL;
+static void mod_authn_mysql_sock_close(plugin_data *p) {
+ if (NULL != p->mysql_conn) {
+ mysql_close(p->mysql_conn);
+ p->mysql_conn = NULL;
}
}
-static MYSQL * mod_authn_mysql_sock_connect(server *srv, plugin_config *pconf) {
- if (NULL != pconf->mysql_conn) {
+static MYSQL * mod_authn_mysql_sock_connect(server *srv, plugin_data *p) {
+ plugin_config * const pconf = &p->conf;
+ if (NULL != p->mysql_conn) {
/* reuse open db connection if same ptrs to host user pass db port */
- if ( pconf->mysql_conn_host == pconf->auth_mysql_host
- && pconf->mysql_conn_user == pconf->auth_mysql_user
- && pconf->mysql_conn_pass == pconf->auth_mysql_pass
- && pconf->mysql_conn_db == pconf->auth_mysql_db
- && pconf->mysql_conn_port == pconf->auth_mysql_port) {
- return pconf->mysql_conn;
+ if ( p->mysql_conn_host == pconf->auth_mysql_host
+ && p->mysql_conn_user == pconf->auth_mysql_user
+ && p->mysql_conn_pass == pconf->auth_mysql_pass
+ && p->mysql_conn_db == pconf->auth_mysql_db
+ && p->mysql_conn_port == pconf->auth_mysql_port) {
+ return p->mysql_conn;
}
- mod_authn_mysql_sock_close(pconf);
+ mod_authn_mysql_sock_close(p);
}
/* !! mysql_init() is not thread safe !! (see MySQL doc) */
- pconf->mysql_conn = mysql_init(NULL);
- if (mysql_real_connect(pconf->mysql_conn,
- pconf->auth_mysql_host->ptr,
- pconf->auth_mysql_user->ptr,
- pconf->auth_mysql_pass->ptr,
- pconf->auth_mysql_db->ptr,
+ p->mysql_conn = mysql_init(NULL);
+ if (mysql_real_connect(p->mysql_conn,
+ pconf->auth_mysql_host,
+ pconf->auth_mysql_user,
+ pconf->auth_mysql_pass,
+ pconf->auth_mysql_db,
pconf->auth_mysql_port,
- !buffer_string_is_empty(pconf->auth_mysql_socket)
- ? pconf->auth_mysql_socket->ptr
+ (pconf->auth_mysql_socket && *pconf->auth_mysql_socket)
+ ? pconf->auth_mysql_socket
: NULL,
CLIENT_IGNORE_SIGPIPE)) {
- /* (copy ptrs to config data (has lifetime until server shutdown)) */
- pconf->mysql_conn_host = pconf->auth_mysql_host;
- pconf->mysql_conn_user = pconf->auth_mysql_user;
- pconf->mysql_conn_pass = pconf->auth_mysql_pass;
- pconf->mysql_conn_db = pconf->auth_mysql_db;
- pconf->mysql_conn_port = pconf->auth_mysql_port;
- return pconf->mysql_conn;
+ /* (copy ptrs to plugin data (has lifetime until server shutdown)) */
+ p->mysql_conn_host = pconf->auth_mysql_host;
+ p->mysql_conn_user = pconf->auth_mysql_user;
+ p->mysql_conn_pass = pconf->auth_mysql_pass;
+ p->mysql_conn_db = pconf->auth_mysql_db;
+ p->mysql_conn_port = pconf->auth_mysql_port;
+ return p->mysql_conn;
}
else {
- /*(note: any of these params might be buffers with b->ptr == NULL)*/
- log_error_write(srv, __FILE__, __LINE__, "sbsb"/*sb*/"sbss",
- "opening connection to mysql:", pconf->auth_mysql_host,
- "user:", pconf->auth_mysql_user,
- /*"pass:", pconf->auth_mysql_pass,*//*(omit from logs)*/
- "db:", pconf->auth_mysql_db,
- "failed:", mysql_error(pconf->mysql_conn));
- mod_authn_mysql_sock_close(pconf);
+ /*(note: any of these params might be NULL)*/
+ log_error_write(srv, __FILE__, __LINE__, "ssss"/*ss*/"ssss",
+ "opening connection to mysql:",
+ pconf->auth_mysql_host ? pconf->auth_mysql_host : NULL,
+ "user:",
+ pconf->auth_mysql_user ? pconf->auth_mysql_user : NULL,
+ /*"pass:",*//*(omit pass from logs)*/
+ /*pconf->auth_mysql_pass ? pconf->auth_mysql_pass : NULL,*/
+ "db:",
+ pconf->auth_mysql_db ? pconf->auth_mysql_db : NULL,
+ "failed:", mysql_error(p->mysql_conn));
+ mod_authn_mysql_sock_close(p);
return NULL;
}
}
-static MYSQL * mod_authn_mysql_sock_acquire(server *srv, plugin_config *pconf) {
- return mod_authn_mysql_sock_connect(srv, pconf);
+static MYSQL * mod_authn_mysql_sock_acquire(server *srv, plugin_data *p) {
+ return mod_authn_mysql_sock_connect(srv, p);
}
-static void mod_authn_mysql_sock_release(server *srv, plugin_config *pconf) {
+static void mod_authn_mysql_sock_release(server *srv, plugin_data *p) {
UNUSED(srv);
- UNUSED(pconf);
+ UNUSED(p);
/*(empty; leave db connection open)*/
/* Note: mod_authn_mysql_result() calls mod_authn_mysql_sock_error()
* on error, so take that into account if making changes here.
- * Must check if (NULL == pconf->mysql_conn) */
+ * Must check if (NULL == p->mysql_conn) */
}
-static void mod_authn_mysql_sock_error(server *srv, plugin_config *pconf) {
+static void mod_authn_mysql_sock_error(server *srv, plugin_data *p) {
UNUSED(srv);
- mod_authn_mysql_sock_close(pconf);
+ mod_authn_mysql_sock_close(p);
}
static handler_t mod_authn_mysql_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw);
@@ -151,186 +157,151 @@ INIT_FUNC(mod_authn_mysql_init) {
FREE_FUNC(mod_authn_mysql_free) {
plugin_data *p = p_d;
-
- UNUSED(srv);
-
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];
+ mod_authn_mysql_sock_close(p);
- if (NULL == s) continue;
-
- buffer_free(s->auth_mysql_host);
- buffer_free(s->auth_mysql_user);
- buffer_free(s->auth_mysql_pass);
- buffer_free(s->auth_mysql_db);
- buffer_free(s->auth_mysql_socket);
- buffer_free(s->auth_mysql_users_table);
- buffer_free(s->auth_mysql_col_user);
- buffer_free(s->auth_mysql_col_pass);
- buffer_free(s->auth_mysql_col_realm);
-
- if (s->mysql_conn) mod_authn_mysql_sock_close(s);
+ free(p->cvlist);
+ free(p);
+ UNUSED(srv);
+ return HANDLER_GO_ON;
+}
- free(s);
- }
- free(p->config_storage);
+static void mod_authn_mysql_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* auth.backend.mysql.host */
+ pconf->auth_mysql_host = cpv->v.b->ptr;
+ break;
+ case 1: /* auth.backend.mysql.user */
+ pconf->auth_mysql_user = cpv->v.b->ptr;
+ break;
+ case 2: /* auth.backend.mysql.pass */
+ pconf->auth_mysql_pass = cpv->v.b->ptr;
+ break;
+ case 3: /* auth.backend.mysql.db */
+ pconf->auth_mysql_db = cpv->v.b->ptr;
+ break;
+ case 4: /* auth.backend.mysql.port */
+ pconf->auth_mysql_port = (int)cpv->v.shrt;
+ break;
+ case 5: /* auth.backend.mysql.socket */
+ pconf->auth_mysql_socket = cpv->v.b->ptr;
+ break;
+ case 6: /* auth.backend.mysql.users_table */
+ pconf->auth_mysql_users_table = cpv->v.b->ptr;
+ break;
+ case 7: /* auth.backend.mysql.col_user */
+ pconf->auth_mysql_col_user = cpv->v.b->ptr;
+ break;
+ case 8: /* auth.backend.mysql.col_pass */
+ pconf->auth_mysql_col_pass = cpv->v.b->ptr;
+ break;
+ case 9: /* auth.backend.mysql.col_realm */
+ pconf->auth_mysql_col_realm = cpv->v.b->ptr;
+ break;
+ default:/* should not happen */
+ return;
}
- mod_authn_mysql_sock_close(&p->conf);
+}
- free(p);
+static void mod_authn_mysql_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_authn_mysql_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- return HANDLER_GO_ON;
+static void mod_authn_mysql_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_authn_mysql_merge_config(&p->conf,
+ p->cvlist + p->cvlist[i].v.u2[0]);
+ }
}
SETDEFAULTS_FUNC(mod_authn_mysql_set_defaults) {
- plugin_data *p = p_d;
- size_t i;
- config_values_t cv[] = {
- { "auth.backend.mysql.host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.mysql.user", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.mysql.pass", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.mysql.db", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.mysql.port", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.mysql.socket", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.mysql.users_table", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.mysql.col_user", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.mysql.col_pass", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.mysql.col_realm", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("auth.backend.mysql.host"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.mysql.user"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.mysql.pass"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.mysql.db"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.mysql.port"),
+ T_CONFIG_SHORT,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.mysql.socket"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.mysql.users_table"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.mysql.col_user"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.mysql.col_pass"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("auth.backend.mysql.col_realm"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
};
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
-
- s->mysql_conn = NULL;
- s->auth_mysql_host = buffer_init();
- s->auth_mysql_user = buffer_init();
- s->auth_mysql_pass = buffer_init();
- s->auth_mysql_db = buffer_init();
- s->auth_mysql_socket = buffer_init();
- s->auth_mysql_users_table = buffer_init();
- s->auth_mysql_col_user = buffer_init();
- s->auth_mysql_col_pass = buffer_init();
- s->auth_mysql_col_realm = buffer_init();
-
- cv[0].destination = s->auth_mysql_host;
- cv[1].destination = s->auth_mysql_user;
- cv[2].destination = s->auth_mysql_pass;
- cv[3].destination = s->auth_mysql_db;
- cv[4].destination = &s->auth_mysql_port;
- cv[5].destination = s->auth_mysql_socket;
- cv[6].destination = s->auth_mysql_users_table;
- cv[7].destination = s->auth_mysql_col_user;
- cv[8].destination = s->auth_mysql_col_pass;
- cv[9].destination = s->auth_mysql_col_realm;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
-
- if (!buffer_is_empty(s->auth_mysql_col_user)
- && buffer_string_is_empty(s->auth_mysql_col_user)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "auth.backend.mysql.col_user must not be blank");
- return HANDLER_ERROR;
- }
- if (!buffer_is_empty(s->auth_mysql_col_pass)
- && buffer_string_is_empty(s->auth_mysql_col_pass)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "auth.backend.mysql.col_pass must not be blank");
- return HANDLER_ERROR;
- }
- if (!buffer_is_empty(s->auth_mysql_col_realm)
- && buffer_string_is_empty(s->auth_mysql_col_realm)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "auth.backend.mysql.col_realm must not be blank");
- return HANDLER_ERROR;
- }
- }
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_authn_mysql"))
+ return HANDLER_ERROR;
- if (p->config_storage[0]) { /*(always true)*/
- plugin_config *s = p->config_storage[0];
- if (buffer_is_empty(s->auth_mysql_col_user)) {
- buffer_copy_string_len(s->auth_mysql_col_user, CONST_STR_LEN("user"));
- }
- if (buffer_is_empty(s->auth_mysql_col_pass)) {
- buffer_copy_string_len(s->auth_mysql_col_pass, CONST_STR_LEN("password"));
- }
- if (buffer_is_empty(s->auth_mysql_col_realm)) {
- buffer_copy_string_len(s->auth_mysql_col_realm, CONST_STR_LEN("realm"));
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* auth.backend.mysql.host */
+ case 1: /* auth.backend.mysql.user */
+ case 2: /* auth.backend.mysql.pass */
+ case 3: /* auth.backend.mysql.db */
+ case 4: /* auth.backend.mysql.port */
+ case 5: /* auth.backend.mysql.socket */
+ case 6: /* auth.backend.mysql.users_table */
+ break;
+ case 7: /* auth.backend.mysql.col_user */
+ case 8: /* auth.backend.mysql.col_pass */
+ case 9: /* auth.backend.mysql.col_realm */
+ if (buffer_string_is_empty(cpv->v.b)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "%s must not be blank", cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ break;
+ default:/* should not happen */
+ break;
+ }
}
}
- return HANDLER_GO_ON;
-}
+ p->defaults.auth_mysql_col_user = "user";
+ p->defaults.auth_mysql_col_pass = "password";
+ p->defaults.auth_mysql_col_realm = "realm";
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_authn_mysql_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(auth_mysql_host);
- PATCH(auth_mysql_user);
- PATCH(auth_mysql_pass);
- PATCH(auth_mysql_db);
- PATCH(auth_mysql_port);
- PATCH(auth_mysql_socket);
- PATCH(auth_mysql_users_table);
- PATCH(auth_mysql_col_user);
- PATCH(auth_mysql_col_pass);
- PATCH(auth_mysql_col_realm);
-
- /* 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("auth.backend.mysql.host"))) {
- PATCH(auth_mysql_host);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.mysql.user"))) {
- PATCH(auth_mysql_user);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.mysql.pass"))) {
- PATCH(auth_mysql_pass);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.mysql.db"))) {
- PATCH(auth_mysql_db);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.mysql.port"))) {
- PATCH(auth_mysql_port);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.mysql.socket"))) {
- PATCH(auth_mysql_socket);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.mysql.users_table"))) {
- PATCH(auth_mysql_users_table);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.mysql.col_user"))) {
- PATCH(auth_mysql_col_user);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.mysql.col_pass"))) {
- PATCH(auth_mysql_col_pass);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.mysql.col_realm"))) {
- PATCH(auth_mysql_col_realm);
- }
- }
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_authn_mysql_merge_config(&p->defaults, cpv);
}
- return 0;
+ return HANDLER_GO_ON;
}
-#undef PATCH
static int mod_authn_mysql_password_cmp(const char *userpw, unsigned long userpwlen, const char *reqpw) {
#if defined(HAVE_CRYPT_R) || defined(HAVE_CRYPT)
@@ -388,7 +359,7 @@ static int mod_authn_mysql_password_cmp(const char *userpw, unsigned long userpw
}
static int mod_authn_mysql_result(server *srv, plugin_data *p, http_auth_info_t *ai, const char *pw) {
- MYSQL_RES *result = mysql_store_result(p->conf.mysql_conn);
+ MYSQL_RES *result = mysql_store_result(p->mysql_conn);
int rc = -1;
my_ulonglong num_rows;
@@ -396,9 +367,9 @@ static int mod_authn_mysql_result(server *srv, plugin_data *p, http_auth_info_t
/*(future: might log mysql_error() string)*/
#if 0
log_error_write(srv, __FILE__, __LINE__, "ss", "mysql_store_result:",
- mysql_error(p->conf.mysql_conn));
+ mysql_error(p->mysql_conn));
#endif
- mod_authn_mysql_sock_error(srv, &p->conf);
+ mod_authn_mysql_sock_error(srv, p);
return -1;
}
@@ -435,9 +406,9 @@ static handler_t mod_authn_mysql_query(server *srv, connection *con, void *p_d,
plugin_data *p = (plugin_data *)p_d;
int rc = -1;
- mod_authn_mysql_patch_connection(srv, con, p);
+ mod_authn_mysql_patch_config(con, p);
- if (buffer_string_is_empty(p->conf.auth_mysql_users_table)) {
+ if (NULL == p->conf.auth_mysql_users_table) {
/*(auth.backend.mysql.host, auth.backend.mysql.db might be NULL; do not log)*/
log_error_write(srv, __FILE__, __LINE__, "sb",
"auth config missing auth.backend.mysql.users_table for uri:",
@@ -454,35 +425,35 @@ static handler_t mod_authn_mysql_query(server *srv, connection *con, void *p_d,
if (ai->rlen > sizeof(urealm)/2-1)
return HANDLER_ERROR;
- if (!mod_authn_mysql_sock_acquire(srv, &p->conf)) {
+ if (!mod_authn_mysql_sock_acquire(srv, p)) {
return HANDLER_ERROR;
}
#if 0
- mrc = mysql_real_escape_string_quote(p->conf.mysql_conn, uname,
+ mrc = mysql_real_escape_string_quote(p->mysql_conn, uname,
ai->username, ai->ulen, '\'');
if ((unsigned long)~0 == mrc) break;
- mrc = mysql_real_escape_string_quote(p->conf.mysql_conn, urealm,
+ mrc = mysql_real_escape_string_quote(p->mysql_conn, urealm,
ai->realm, ai->rlen, '\'');
if ((unsigned long)~0 == mrc) break;
#else
- mrc = mysql_real_escape_string(p->conf.mysql_conn, uname,
+ mrc = mysql_real_escape_string(p->mysql_conn, uname,
ai->username, ai->ulen);
if ((unsigned long)~0 == mrc) break;
- mrc = mysql_real_escape_string(p->conf.mysql_conn, urealm,
+ mrc = mysql_real_escape_string(p->mysql_conn, urealm,
ai->realm, ai->rlen);
if ((unsigned long)~0 == mrc) break;
#endif
rc = snprintf(q, sizeof(q),
"SELECT %s FROM %s WHERE %s='%s' AND %s='%s'",
- p->conf.auth_mysql_col_pass->ptr,
- p->conf.auth_mysql_users_table->ptr,
- p->conf.auth_mysql_col_user->ptr,
+ p->conf.auth_mysql_col_pass,
+ p->conf.auth_mysql_users_table,
+ p->conf.auth_mysql_col_user,
uname,
- p->conf.auth_mysql_col_realm->ptr,
+ p->conf.auth_mysql_col_realm,
urealm);
if (rc >= (int)sizeof(q)) {
@@ -491,23 +462,26 @@ static handler_t mod_authn_mysql_query(server *srv, connection *con, void *p_d,
}
/* for now we stay synchronous */
- if (0 != mysql_query(p->conf.mysql_conn, q)) {
+ if (0 != mysql_query(p->mysql_conn, q)) {
/* reconnect to db and retry once if query error occurs */
- mod_authn_mysql_sock_error(srv, &p->conf);
- if (!mod_authn_mysql_sock_acquire(srv, &p->conf)) {
+ mod_authn_mysql_sock_error(srv, p);
+ if (!mod_authn_mysql_sock_acquire(srv, p)) {
rc = -1;
break;
}
- if (0 != mysql_query(p->conf.mysql_conn, q)) {
+ if (0 != mysql_query(p->mysql_conn, q)) {
/*(note: any of these params might be bufs w/ b->ptr == NULL)*/
- log_error_write(srv, __FILE__, __LINE__, "sbsb"/*sb*/"sbssss",
- "mysql_query host:", p->conf.auth_mysql_host,
- "user:", p->conf.auth_mysql_user,
- /*(omit pass from logs)*/
- /*"pass:", p->conf.auth_mysql_pass,*/
- "db:", p->conf.auth_mysql_db,
- "query:", q,
- "failed:", mysql_error(p->conf.mysql_conn));
+ log_error_write(srv, __FILE__, __LINE__, "ssss"/*ss*/"ssssss",
+ "mysql_query host:",
+ p->conf.auth_mysql_host ? p->conf.auth_mysql_host : NULL,
+ "user:",
+ p->conf.auth_mysql_user ? p->conf.auth_mysql_user : NULL,
+ /*"pass:",*//*(omit pass from logs)*/
+ /*p->conf.auth_mysql_pass ? p->conf.auth_mysql_pass : NULL,*/
+ "db:",
+ p->conf.auth_mysql_db ? p->conf.auth_mysql_db : NULL,
+ "query:", q,
+ "failed:", mysql_error(p->mysql_conn));
rc = -1;
break;
}
@@ -517,7 +491,7 @@ static handler_t mod_authn_mysql_query(server *srv, connection *con, void *p_d,
} while (0);
- mod_authn_mysql_sock_release(srv, &p->conf);
+ mod_authn_mysql_sock_release(srv, p);
return (0 == rc) ? HANDLER_GO_ON : HANDLER_ERROR;
}
@@ -545,12 +519,10 @@ static handler_t mod_authn_mysql_digest(server *srv, connection *con, void *p_d,
int mod_authn_mysql_plugin_init(plugin *p);
int mod_authn_mysql_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("authn_mysql");
+ p->name = "authn_mysql";
p->init = mod_authn_mysql_init;
p->set_defaults= mod_authn_mysql_set_defaults;
p->cleanup = mod_authn_mysql_free;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_authn_pam.c b/src/mod_authn_pam.c
index 0ce1fb3c..61925e80 100644
--- a/src/mod_authn_pam.c
+++ b/src/mod_authn_pam.c
@@ -22,13 +22,12 @@
#include <string.h>
typedef struct {
- array *opts;
const char *service;
} plugin_config;
typedef struct {
PLUGIN_DATA;
- plugin_config **config_storage;
+ plugin_config defaults;
plugin_config conf;
} plugin_data;
@@ -50,82 +49,83 @@ FREE_FUNC(mod_authn_pam_free) {
plugin_data *p = p_d;
if (!p) return HANDLER_GO_ON;
- if (p->config_storage) {
- for (size_t i = 0; i < srv->config_context->used; ++i) {
- plugin_config *s = p->config_storage[i];
- if (NULL == s) continue;
- array_free(s->opts);
- free(s);
- }
- free(p->config_storage);
- }
+ free(p->cvlist);
free(p);
UNUSED(srv);
return HANDLER_GO_ON;
}
-SETDEFAULTS_FUNC(mod_authn_pam_set_defaults) {
- plugin_data *p = p_d;
- config_values_t cv[] = {
- { "auth.backend.pam.opts", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
+static void mod_authn_pam_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* auth.backend.pam.opts */
+ if (cpv->vtype == T_CONFIG_LOCAL)
+ pconf->service = cpv->v.v;
+ break;
+ default:/* should not happen */
+ return;
+ }
+}
- for (size_t i = 0; i < srv->config_context->used; ++i) {
- data_config const *config = (data_config const*)srv->config_context->data[i];
- const data_string *ds;
- plugin_config *s = calloc(1, sizeof(plugin_config));
- s->opts = array_init();
+static void mod_authn_pam_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_authn_pam_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- cv[0].destination = s->opts;
+static void mod_authn_pam_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_authn_pam_merge_config(&p->conf,
+ p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
- p->config_storage[i] = s;
+SETDEFAULTS_FUNC(mod_authn_pam_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("auth.backend.pam.opts"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_authn_pam"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* auth.backend.pam.opts */
+ if (cpv->v.a->used) {
+ const data_string *ds = (const data_string *)
+ array_get_element_klen(cpv->v.a,CONST_STR_LEN("service"));
+ cpv->v.v = (NULL != ds) ? ds->value.ptr : "http";
+ cpv->vtype = T_CONFIG_LOCAL;
+ }
+ break;
+ default:/* should not happen */
+ break;
+ }
}
-
- if (0 == s->opts->used) continue;
-
- ds = (const data_string *)
- array_get_element_klen(s->opts, CONST_STR_LEN("service"));
- s->service = (NULL != ds) ? ds->value.ptr : "http";
}
- if (p->config_storage[0]->service == NULL)
- p->config_storage[0]->service = "http";
+ p->defaults.service = "http";
- return HANDLER_GO_ON;
-}
-
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_authn_pam_patch_connection(server *srv, connection *con, plugin_data *p) {
- plugin_config *s = p->config_storage[0];
- PATCH(service);
-
- /* skip the first, the global context */
- for (size_t i = 1; i < srv->config_context->used; ++i) {
- data_config *dc = (data_config *)srv->config_context->data[i];
-
- /* condition didn't match */
- if (!config_check_cond(srv, con, dc)) continue;
-
- /* merge config */
- s = p->config_storage[i];
- for (size_t j = 0; j < dc->value->used; ++j) {
- data_unset *du = dc->value->data[j];
- if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.pam.opts"))) {
- PATCH(service);
- }
- }
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_authn_pam_merge_config(&p->defaults, cpv);
}
- return 0;
+ return HANDLER_GO_ON;
}
-#undef PATCH
static int mod_authn_pam_fn_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) {
const char * const pw = (char *)appdata_ptr;
@@ -150,7 +150,7 @@ static handler_t mod_authn_pam_query(server *srv, connection *con, void *p_d, co
UNUSED(realm);
*(const char **)&conv.appdata_ptr = pw; /*(cast away const)*/
- mod_authn_pam_patch_connection(srv, con, p);
+ mod_authn_pam_patch_config(con, p);
rc = pam_start(p->conf.service, username->ptr, &conv, &pamh);
if (PAM_SUCCESS != rc
@@ -175,8 +175,7 @@ static handler_t mod_authn_pam_basic(server *srv, connection *con, void *p_d, co
int mod_authn_pam_plugin_init(plugin *p);
int mod_authn_pam_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("authn_pam");
- p->data = NULL;
+ p->name = "authn_pam";
p->init = mod_authn_pam_init;
p->cleanup = mod_authn_pam_free;
p->set_defaults= mod_authn_pam_set_defaults;
diff --git a/src/mod_authn_sasl.c b/src/mod_authn_sasl.c
index 949ba481..deafde30 100644
--- a/src/mod_authn_sasl.c
+++ b/src/mod_authn_sasl.c
@@ -19,12 +19,10 @@
#include "plugin.h"
#include <sys/utsname.h>
-#include <errno.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
- array *opts;
const char *service;
const char *fqdn;
const buffer *pwcheck_method;
@@ -33,9 +31,9 @@ typedef struct {
typedef struct {
PLUGIN_DATA;
- plugin_config **config_storage;
+ plugin_config defaults;
plugin_config conf;
- buffer *fqdn;
+
int initonce;
} plugin_data;
@@ -53,134 +51,164 @@ INIT_FUNC(mod_authn_sasl_init) {
return p;
}
+static void mod_authn_sasl_free_config(plugin_data * const p) {
+ if (NULL == p->cvlist) return;
+ /* (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* auth.backend.sasl.opts */
+ if (cpv->vtype == T_CONFIG_LOCAL) free(cpv->v.v);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
FREE_FUNC(mod_authn_sasl_free) {
plugin_data *p = p_d;
if (!p) return HANDLER_GO_ON;
if (p->initonce) sasl_done();
- if (p->config_storage) {
- for (size_t i = 0; i < srv->config_context->used; ++i) {
- plugin_config *s = p->config_storage[i];
- if (NULL == s) continue;
- array_free(s->opts);
- free(s);
- }
- free(p->config_storage);
- }
- buffer_free(p->fqdn);
+ mod_authn_sasl_free_config(p);
+
+ free(p->cvlist);
free(p);
UNUSED(srv);
return HANDLER_GO_ON;
}
-SETDEFAULTS_FUNC(mod_authn_sasl_set_defaults) {
- plugin_data *p = p_d;
- size_t i;
- config_values_t cv[] = {
- { "auth.backend.sasl.opts", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const *config = (data_config const*)srv->config_context->data[i];
- const data_string *ds;
- plugin_config *s = calloc(1, sizeof(plugin_config));
- s->opts = array_init();
-
- cv[0].destination = s->opts;
+static void mod_authn_sasl_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* auth.backend.sasl.opts */
+ if (cpv->vtype == T_CONFIG_LOCAL)
+ memcpy(pconf, cpv->v.v, sizeof(plugin_config));
+ break;
+ default:/* should not happen */
+ return;
+ }
+}
- p->config_storage[i] = s;
+static void mod_authn_sasl_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_authn_sasl_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
+static void mod_authn_sasl_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_authn_sasl_merge_config(&p->conf,
+ p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
- if (0 == s->opts->used) continue;
-
- ds = (const data_string *)
- array_get_element_klen(s->opts, CONST_STR_LEN("service"));
- s->service = (NULL != ds) ? ds->value.ptr : "http";
-
- ds = (const data_string *)
- array_get_element_klen(s->opts, CONST_STR_LEN("fqdn"));
- if (NULL != ds) s->fqdn = ds->value.ptr;
- if (NULL == s->fqdn) {
- if (NULL == p->fqdn) {
- struct utsname uts;
- if (0 != uname(&uts)) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "uname():", strerror(errno));
- return HANDLER_ERROR;
- }
- p->fqdn = buffer_init_string(uts.nodename);
+static plugin_config * mod_authn_sasl_parse_opts(server *srv, const array * const opts) {
+ const data_string *ds;
+ const char *service = NULL;
+ const char *fqdn = NULL;
+ const buffer *pwcheck_method = NULL;
+ const buffer *sasldb_path = NULL;
+
+ ds = (const data_string *)
+ array_get_element_klen(opts, CONST_STR_LEN("service"));
+ service = (NULL != ds) ? ds->value.ptr : "http";
+
+ ds = (const data_string *)
+ array_get_element_klen(opts, CONST_STR_LEN("fqdn"));
+ if (NULL != ds) fqdn = ds->value.ptr;
+ if (NULL == fqdn) {
+ static struct utsname uts;
+ if (uts.nodename[0] == '\0') {
+ if (0 != uname(&uts)) {
+ log_perror(srv->errh, __FILE__, __LINE__, "uname()");
+ return NULL;
}
- s->fqdn = p->fqdn->ptr;
}
+ fqdn = uts.nodename;
+ }
- ds = (const data_string *)
- array_get_element_klen(s->opts, CONST_STR_LEN("pwcheck_method"));
- if (NULL != ds) {
- s->pwcheck_method = &ds->value;
- if (!buffer_is_equal_string(&ds->value, CONST_STR_LEN("saslauthd"))
- && !buffer_is_equal_string(&ds->value, CONST_STR_LEN("auxprop"))
- && !buffer_is_equal_string(&ds->value, CONST_STR_LEN("sasldb"))){
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "sasl pwcheck_method must be one of saslauthd, "
- "sasldb, or auxprop, not:", &ds->value);
- return HANDLER_ERROR;
- }
- if (buffer_is_equal_string(&ds->value, CONST_STR_LEN("sasldb"))) {
- /* Cyrus libsasl2 expects "auxprop" instead of "sasldb"
- * (mod_authn_sasl_cb_getopt auxprop_plugin returns "sasldb") */
- buffer *pwcheck_method =
- array_get_buf_ptr(s->opts, CONST_STR_LEN("pwcheck_method"));
- buffer_copy_string_len(pwcheck_method, CONST_STR_LEN("auxprop"));
- }
+ ds = (const data_string *)
+ array_get_element_klen(opts, CONST_STR_LEN("pwcheck_method"));
+ if (NULL != ds) {
+ pwcheck_method = &ds->value;
+ if (!buffer_is_equal_string(&ds->value, CONST_STR_LEN("saslauthd"))
+ && !buffer_is_equal_string(&ds->value, CONST_STR_LEN("auxprop"))
+ && !buffer_is_equal_string(&ds->value, CONST_STR_LEN("sasldb"))){
+ log_error(srv->errh, __FILE__, __LINE__,
+ "sasl pwcheck_method must be one of saslauthd, "
+ "sasldb, or auxprop, not: %s", ds->value.ptr);
+ return NULL;
+ }
+ if (buffer_is_equal_string(&ds->value, CONST_STR_LEN("sasldb"))) {
+ /* Cyrus libsasl2 expects "auxprop" instead of "sasldb"
+ * (mod_authn_sasl_cb_getopt auxprop_plugin returns "sasldb") */
+ buffer *b;
+ *(const buffer **)&b = &ds->value;
+ buffer_copy_string_len(b, CONST_STR_LEN("auxprop"));
}
-
- ds = (const data_string *)
- array_get_element_klen(s->opts, CONST_STR_LEN("sasldb_path"));
- if (NULL != ds) s->sasldb_path = &ds->value;
}
- return HANDLER_GO_ON;
+ ds = (const data_string *)
+ array_get_element_klen(opts, CONST_STR_LEN("sasldb_path"));
+ if (NULL != ds) sasldb_path = &ds->value;
+
+ plugin_config *pconf = malloc(sizeof(plugin_config));
+ force_assert(pconf);
+ pconf->service = service;
+ pconf->fqdn = fqdn;
+ pconf->pwcheck_method = pwcheck_method;
+ pconf->sasldb_path = sasldb_path;
+ return pconf;
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_authn_sasl_patch_connection(server *srv, connection *con, plugin_data *p) {
- plugin_config *s = p->config_storage[0];
- PATCH(service);
- PATCH(fqdn);
- PATCH(pwcheck_method);
- PATCH(sasldb_path);
-
- /* skip the first, the global context */
- for (size_t i = 1; i < srv->config_context->used; ++i) {
- data_config *dc = (data_config *)srv->config_context->data[i];
-
- /* condition didn't match */
- if (!config_check_cond(srv, con, dc)) continue;
-
- /* merge config */
- s = p->config_storage[i];
- for (size_t j = 0; j < dc->value->used; ++j) {
- data_unset *du = dc->value->data[j];
- if (buffer_is_equal_string(&du->key, CONST_STR_LEN("auth.backend.sasl.opts"))) {
- PATCH(service);
- PATCH(fqdn);
- PATCH(pwcheck_method);
- PATCH(sasldb_path);
+SETDEFAULTS_FUNC(mod_authn_sasl_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("auth.backend.sasl.opts"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_authn_sasl"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* auth.backend.sasl.opts */
+ if (cpv->v.a->used) {
+ cpv->v.v = mod_authn_sasl_parse_opts(srv, cpv->v.a);
+ if (NULL == cpv->v.v) return HANDLER_ERROR;
+ cpv->vtype = T_CONFIG_LOCAL;
+ }
+ break;
+ default:/* should not happen */
+ break;
}
}
}
- return 0;
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_authn_sasl_merge_config(&p->defaults, cpv);
+ }
+
+ return HANDLER_GO_ON;
}
-#undef PATCH
static int mod_authn_sasl_cb_getopt(void *p_d, const char *plugin_name, const char *opt, const char **res, unsigned *len) {
plugin_data *p = (plugin_data *)p_d;
@@ -244,7 +272,7 @@ static handler_t mod_authn_sasl_query(server *srv, connection *con, void *p_d, c
};
int rc;
- mod_authn_sasl_patch_connection(srv, con, p);
+ mod_authn_sasl_patch_config(con, p);
if (!p->initonce) {
/* must be done once, but after fork() if multiple lighttpd workers */
@@ -275,12 +303,10 @@ static handler_t mod_authn_sasl_basic(server *srv, connection *con, void *p_d, c
int mod_authn_sasl_plugin_init(plugin *p);
int mod_authn_sasl_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("authn_sasl");
+ p->name = "authn_sasl";
p->init = mod_authn_sasl_init;
p->set_defaults= mod_authn_sasl_set_defaults;
p->cleanup = mod_authn_sasl_free;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_cgi.c b/src/mod_cgi.c
index b7c49d05..72f0e789 100644
--- a/src/mod_cgi.c
+++ b/src/mod_cgi.c
@@ -61,17 +61,17 @@ typedef struct {
} buffer_pid_t;
typedef struct {
- array *cgi;
+ const array *cgi;
unsigned short execute_x_only;
unsigned short local_redir;
unsigned short xsendfile_allow;
unsigned short upgrade;
- array *xsendfile_docroot;
+ const array *xsendfile_docroot;
} plugin_config;
typedef struct {
PLUGIN_DATA;
- plugin_config **config_storage;
+ plugin_config defaults;
plugin_config conf;
buffer_pid_t cgi_pid;
env_accum env;
@@ -135,26 +135,12 @@ INIT_FUNC(mod_cgi_init) {
FREE_FUNC(mod_cgi_free) {
plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+
buffer_pid_t *r = &(p->cgi_pid);
UNUSED(srv);
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- if (NULL == s) continue;
-
- array_free(s->cgi);
- array_free(s->xsendfile_docroot);
-
- free(s);
- }
- free(p->config_storage);
- }
-
-
if (r->ptr) free(r->ptr);
free(p->env.ptr);
free(p->env.offsets);
@@ -164,84 +150,136 @@ FREE_FUNC(mod_cgi_free) {
#ifdef __CYGWIN__
buffer_free(p->env.systemroot);
#endif
+
+ free(p->cvlist);
free(p);
return HANDLER_GO_ON;
}
-SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { "cgi.assign", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { "cgi.execute-x-only", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { "cgi.x-sendfile", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
- { "cgi.x-sendfile-docroot", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
- { "cgi.local-redir", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
- { "cgi.upgrade", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET}
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
- force_assert(p->config_storage);
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- force_assert(s);
-
- s->cgi = array_init();
- s->execute_x_only = 0;
- s->local_redir = 0;
- s->xsendfile_allow= 0;
- s->xsendfile_docroot = array_init();
- s->upgrade = 0;
-
- cv[0].destination = s->cgi;
- cv[1].destination = &(s->execute_x_only);
- cv[2].destination = &(s->xsendfile_allow);
- cv[3].destination = s->xsendfile_docroot;
- cv[4].destination = &(s->local_redir);
- cv[5].destination = &(s->upgrade);
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
+static void mod_cgi_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* cgi.assign */
+ pconf->cgi = cpv->v.a;
+ break;
+ case 1: /* cgi.execute-x-only */
+ pconf->execute_x_only = (unsigned short)cpv->v.u;
+ break;
+ case 2: /* cgi.x-sendfile */
+ pconf->xsendfile_allow = (unsigned short)cpv->v.u;
+ break;
+ case 3: /* cgi.x-sendfile-docroot */
+ pconf->xsendfile_docroot = cpv->v.a;
+ break;
+ case 4: /* cgi.local-redir */
+ pconf->local_redir = (unsigned short)cpv->v.u;
+ break;
+ case 5: /* cgi.upgrade */
+ pconf->upgrade = (unsigned short)cpv->v.u;
+ break;
+ default:/* should not happen */
+ return;
+ }
+}
- if (!array_is_kvstring(s->cgi)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected value for cgi.assign; expected list of \"ext\" => \"exepath\"");
- return HANDLER_ERROR;
- }
+static void mod_cgi_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_cgi_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- if (s->xsendfile_docroot->used) {
- size_t j;
- for (j = 0; j < s->xsendfile_docroot->used; ++j) {
- data_string *ds = (data_string *)s->xsendfile_docroot->data[j];
- if (ds->type != TYPE_STRING) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected type for key cgi.x-sendfile-docroot; expected: cgi.x-sendfile-docroot = ( \"/allowed/path\", ... )");
- return HANDLER_ERROR;
- }
- if (ds->value.ptr[0] != '/') {
- log_error_write(srv, __FILE__, __LINE__, "SBs",
- "cgi.x-sendfile-docroot paths must begin with '/'; invalid: \"", &ds->value, "\"");
- return HANDLER_ERROR;
- }
- buffer_path_simplify(&ds->value, &ds->value);
- buffer_append_slash(&ds->value);
- }
- }
- }
+static void mod_cgi_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_cgi_merge_config(&p->conf, p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
- return HANDLER_GO_ON;
+SETDEFAULTS_FUNC(mod_cgi_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("cgi.assign"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("cgi.execute-x-only"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("cgi.x-sendfile"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("cgi.x-sendfile-docroot"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("cgi.local-redir"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("cgi.upgrade"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_cgi"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* cgi.assign */
+ if (!array_is_kvstring(cpv->v.a)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s; "
+ "expected list of \"ext\" -> \"exepath\"",
+ cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ break;
+ case 1: /* cgi.execute-x-only */
+ case 2: /* cgi.x-sendfile */
+ break;
+ case 3: /* cgi.x-sendfile-docroot */
+ if (!array_is_vlist(cpv->v.a)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s; "
+ "expected: %s = ( \"/allowed/path\", ... )",
+ cpk[cpv->k_id].k, cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ for (uint32_t j = 0; j < cpv->v.a->used; ++j) {
+ data_string *ds = (data_string *)cpv->v.a->data[j];
+ if (ds->value.ptr[0] != '/') {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "%s paths must begin with '/'; invalid: \"%s\"",
+ cpk[cpv->k_id].k, ds->value.ptr);
+ return HANDLER_ERROR;
+ }
+ buffer_path_simplify(&ds->value, &ds->value);
+ buffer_append_slash(&ds->value);
+ }
+ break;
+ case 4: /* cgi.local-redir */
+ case 5: /* cgi.upgrade */
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+ }
+
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_cgi_merge_config(&p->defaults, cpv);
+ }
+
+ return HANDLER_GO_ON;
}
@@ -859,51 +897,6 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, handler_
}
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_cgi_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(cgi);
- PATCH(execute_x_only);
- PATCH(local_redir);
- PATCH(upgrade);
- PATCH(xsendfile_allow);
- PATCH(xsendfile_docroot);
-
- /* 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("cgi.assign"))) {
- PATCH(cgi);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("cgi.execute-x-only"))) {
- PATCH(execute_x_only);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("cgi.local-redir"))) {
- PATCH(local_redir);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("cgi.upgrade"))) {
- PATCH(upgrade);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("cgi.x-sendfile"))) {
- PATCH(xsendfile_allow);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("cgi.x-sendfile-docroot"))) {
- PATCH(xsendfile_docroot);
- }
- }
- }
-
- return 0;
-}
-#undef PATCH
-
URIHANDLER_FUNC(cgi_is_handled) {
plugin_data *p = p_d;
struct stat *st;
@@ -912,7 +905,8 @@ URIHANDLER_FUNC(cgi_is_handled) {
if (con->mode != DIRECT) return HANDLER_GO_ON;
if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
- mod_cgi_patch_connection(srv, con, p);
+ mod_cgi_patch_config(con, p);
+ if (NULL == p->conf.cgi) return HANDLER_GO_ON;
ds = (data_string *)array_match_key_suffix(p->conf.cgi, con->physical.path);
if (NULL == ds) return HANDLER_GO_ON;
@@ -1053,7 +1047,7 @@ static handler_t cgi_waitpid_cb(server *srv, void *p_d, pid_t pid, int status) {
int mod_cgi_plugin_init(plugin *p);
int mod_cgi_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("cgi");
+ p->name = "cgi";
p->connection_reset = cgi_connection_close_callback;
p->handle_subrequest_start = cgi_is_handled;
@@ -1061,9 +1055,7 @@ int mod_cgi_plugin_init(plugin *p) {
p->handle_waitpid = cgi_waitpid_cb;
p->init = mod_cgi_init;
p->cleanup = mod_cgi_free;
- p->set_defaults = mod_fastcgi_set_defaults;
-
- p->data = NULL;
+ p->set_defaults = mod_cgi_set_defaults;
return 0;
}
diff --git a/src/mod_cml.c b/src/mod_cml.c
index ee87a8f1..2d620d66 100644
--- a/src/mod_cml.c
+++ b/src/mod_cml.c
@@ -14,195 +14,189 @@
#include <string.h>
#include <errno.h>
-/* init the plugin data */
INIT_FUNC(mod_cml_init) {
- plugin_data *p;
-
- p = calloc(1, sizeof(*p));
+ return calloc(1, sizeof(plugin_data));
+}
- p->basedir = buffer_init();
- p->baseurl = buffer_init();
- p->trigger_handler = buffer_init();
+static void mod_cml_free_config(plugin_data * const p) {
+ if (NULL == p->cvlist) return;
+ #if defined(USE_MEMCACHED)
+ /* (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 1: /* cml.memcache-hosts */
+ if (cpv->vtype == T_CONFIG_LOCAL && NULL != cpv->v.v)
+ memcached_free(cpv->v.v); /* mod_cml_free_memcached() */
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ #endif
+}
- return p;
+static int mod_cml_init_memcached(server *srv, config_plugin_value_t * const cpv) {
+ const array * const mc_hosts = cpv->v.a;
+ if (0 == mc_hosts->used) {
+ cpv->v.v = NULL;
+ return 1;
+ }
+
+ #if defined(USE_MEMCACHED)
+
+ buffer * const opts = srv->tmp_buf;
+ buffer_clear(opts);
+ for (uint32_t k = 0; k < mc_hosts->used; ++k) {
+ const data_string * const ds = (const data_string *)mc_hosts->data[k];
+ buffer_append_string_len(opts, CONST_STR_LEN(" --SERVER="));
+ buffer_append_string_buffer(opts, &ds->value);
+ }
+
+ cpv->v.v = memcached(opts->ptr+1, buffer_string_length(opts)-1);
+
+ if (cpv->v.v) {
+ cpv->vtype = T_CONFIG_LOCAL;
+ return 1;
+ }
+ else {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "configuring memcached failed for option string: %s", opts->ptr);
+ return 0;
+ }
+
+ #else
+
+ log_error(srv->errh, __FILE__, __LINE__,
+ "memcache support is not compiled in but cml.memcache-hosts is set, "
+ "aborting");
+ return 0;
+
+ #endif
}
-/* detroy the plugin data */
FREE_FUNC(mod_cml_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
+ plugin_data * const p = p_d;
+ if (!p) return HANDLER_GO_ON;
+ UNUSED(srv);
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
+ free(p->trigger_handler.ptr);
+ free(p->basedir.ptr);
+ free(p->baseurl.ptr);
- if (NULL == s) continue;
+ mod_cml_free_config(p);
- buffer_free(s->ext);
-
- buffer_free(s->mc_namespace);
- buffer_free(s->power_magnet);
- array_free(s->mc_hosts);
-
-#if defined(USE_MEMCACHED)
- if (s->memc) memcached_free(s->memc);
-#endif
-
- free(s);
- }
- free(p->config_storage);
- }
+ free(p->cvlist);
+ free(p);
- buffer_free(p->trigger_handler);
- buffer_free(p->basedir);
- buffer_free(p->baseurl);
-
- free(p);
-
- return HANDLER_GO_ON;
+ return HANDLER_GO_ON;
}
-/* handle plugin config and check values */
-
-SETDEFAULTS_FUNC(mod_cml_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { "cml.extension", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { "cml.memcache-hosts", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { "cml.memcache-namespace", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
- { "cml.power-magnet", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->ext = buffer_init();
- s->mc_hosts = array_init();
- s->mc_namespace = buffer_init();
- s->power_magnet = buffer_init();
-#if defined(USE_MEMCACHED)
- s->memc = NULL;
-#endif
-
- cv[0].destination = s->ext;
- cv[1].destination = s->mc_hosts;
- cv[2].destination = s->mc_namespace;
- cv[3].destination = s->power_magnet;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
-
- if (!array_is_vlist(s->mc_hosts)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected value for cml.memcache-hosts; expected list of \"host\"");
- return HANDLER_ERROR;
- }
-
- if (s->mc_hosts->used) {
-#if defined(USE_MEMCACHED)
- buffer *option_string = buffer_init();
- size_t k;
-
- {
- data_string *ds = (data_string *)s->mc_hosts->data[0];
-
- buffer_append_string_len(option_string, CONST_STR_LEN("--SERVER="));
- buffer_append_string_buffer(option_string, &ds->value);
- }
-
- for (k = 1; k < s->mc_hosts->used; k++) {
- data_string *ds = (data_string *)s->mc_hosts->data[k];
-
- buffer_append_string_len(option_string, CONST_STR_LEN(" --SERVER="));
- buffer_append_string_buffer(option_string, &ds->value);
- }
-
- s->memc = memcached(CONST_BUF_LEN(option_string));
-
- if (NULL == s->memc) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "configuring memcached failed for option string:",
- option_string);
- }
- buffer_free(option_string);
-
- if (NULL == s->memc) return HANDLER_ERROR;
-#else
- log_error_write(srv, __FILE__, __LINE__, "s",
- "memcache support is not compiled in but cml.memcache-hosts is set, aborting");
- return HANDLER_ERROR;
-#endif
- }
- }
+static void mod_cml_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* cml.extension */
+ pconf->ext = cpv->v.b;
+ break;
+ case 1: /* cml.memcache-hosts *//* setdefaults inits memcached_st *memc */
+ #if defined(USE_MEMCACHED)
+ if (cpv->vtype != T_CONFIG_LOCAL) break;
+ pconf->memc = cpv->v.v;
+ #endif
+ break;
+ case 2: /* cml.memcache-namespace */
+ /*pconf->mc_namespace = cpv->v.b;*//*(unused)*/
+ break;
+ case 3: /* cml.power-magnet */
+ pconf->power_magnet = cpv->v.b;
+ break;
+ default:/* should not happen */
+ return;
+ }
+}
- return HANDLER_GO_ON;
+static void mod_cml_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_cml_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_cml_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(ext);
-#if defined(USE_MEMCACHED)
- PATCH(memc);
-#endif
- PATCH(mc_namespace);
- PATCH(power_magnet);
-
- /* 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("cml.extension"))) {
- PATCH(ext);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("cml.memcache-hosts"))) {
-#if defined(USE_MEMCACHED)
- PATCH(memc);
-#endif
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("cml.memcache-namespace"))) {
- PATCH(mc_namespace);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("cml.power-magnet"))) {
- PATCH(power_magnet);
- }
- }
- }
+static void mod_cml_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_cml_merge_config(&p->conf, p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
- return 0;
+SETDEFAULTS_FUNC(mod_cml_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("cml.extension"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("cml.memcache-hosts"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("cml.memcache-namespace"), /*(unused)*/
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("cml.power-magnet"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_cml"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* cml.extension */
+ break;
+ case 1: /* cml.memcache-hosts */ /* config converted to memc handles */
+ if (!array_is_vlist(cpv->v.a)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s; "
+ "expected list of \"host\"", cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ if (!mod_cml_init_memcached(srv, cpv)) {
+ return HANDLER_ERROR;
+ }
+ break;
+ case 2: /* cml.memcache-namespace *//*(unused)*/
+ case 3: /* cml.power-magnet */
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+ }
+
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_cml_merge_config(&p->defaults, cpv);
+ }
+
+ return HANDLER_GO_ON;
}
-#undef PATCH
-static int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer *cml_file) {
+static int cache_call_lua(server *srv, connection *con, plugin_data *p, const buffer *cml_file) {
buffer *b;
char *c;
/* cleanup basedir */
- b = p->baseurl;
+ b = &p->baseurl;
buffer_copy_buffer(b, con->uri.path);
for (c = b->ptr + buffer_string_length(b); c > b->ptr && *c != '/'; c--);
@@ -210,7 +204,7 @@ static int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer *
buffer_string_set_length(b, c - b->ptr + 1);
}
- b = p->basedir;
+ b = &p->basedir;
buffer_copy_buffer(b, con->physical.path);
for (c = b->ptr + buffer_string_length(b); c > b->ptr && *c != '/'; c--);
@@ -229,14 +223,14 @@ static int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer *
URIHANDLER_FUNC(mod_cml_power_magnet) {
plugin_data *p = p_d;
- mod_cml_patch_connection(srv, con, p);
-
- buffer_clear(p->basedir);
- buffer_clear(p->baseurl);
- buffer_clear(p->trigger_handler);
+ mod_cml_patch_config(con, p);
if (buffer_string_is_empty(p->conf.power_magnet)) return HANDLER_GO_ON;
+ buffer_clear(&p->basedir);
+ buffer_clear(&p->baseurl);
+ buffer_clear(&p->trigger_handler);
+
/*
* power-magnet:
* cml.power-magnet = server.docroot + "/rewrite.cml"
@@ -283,11 +277,7 @@ URIHANDLER_FUNC(mod_cml_is_handled) {
if (buffer_string_is_empty(con->physical.path)) return HANDLER_ERROR;
- mod_cml_patch_connection(srv, con, p);
-
- buffer_clear(p->basedir);
- buffer_clear(p->baseurl);
- buffer_clear(p->trigger_handler);
+ mod_cml_patch_config(con, p);
if (buffer_string_is_empty(p->conf.ext)) return HANDLER_GO_ON;
@@ -295,6 +285,10 @@ URIHANDLER_FUNC(mod_cml_is_handled) {
return HANDLER_GO_ON;
}
+ buffer_clear(&p->basedir);
+ buffer_clear(&p->baseurl);
+ buffer_clear(&p->trigger_handler);
+
switch(cache_call_lua(srv, con, p, con->physical.path)) {
case -1:
/* error */
@@ -322,10 +316,11 @@ URIHANDLER_FUNC(mod_cml_is_handled) {
}
}
+
int mod_cml_plugin_init(plugin *p);
int mod_cml_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("cache");
+ p->name = "cache";
p->init = mod_cml_init;
p->cleanup = mod_cml_free;
@@ -334,7 +329,5 @@ int mod_cml_plugin_init(plugin *p) {
p->handle_subrequest_start = mod_cml_is_handled;
p->handle_physical = mod_cml_power_magnet;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_cml.h b/src/mod_cml.h
index d1d0c52a..a2a4f0be 100644
--- a/src/mod_cml.h
+++ b/src/mod_cml.h
@@ -14,29 +14,24 @@
#define plugin_data mod_cache_plugin_data
typedef struct {
- buffer *ext;
-
- array *mc_hosts;
- buffer *mc_namespace;
-#if defined(USE_MEMCACHED)
- memcached_st *memc;
-#endif
- buffer *power_magnet;
+ const buffer *ext;
+ const buffer *power_magnet;
+ /*const buffer *mc_namespace;*//*(unused)*/
+ #if defined(USE_MEMCACHED)
+ memcached_st *memc;
+ #endif
} plugin_config;
typedef struct {
- PLUGIN_DATA;
-
- buffer *basedir;
- buffer *baseurl;
-
- buffer *trigger_handler;
-
- plugin_config **config_storage;
+ PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
- plugin_config conf;
+ buffer basedir;
+ buffer baseurl;
+ buffer trigger_handler;
} plugin_data;
-int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn);
+int cache_parse_lua(server *srv, connection *con, plugin_data *p, const buffer *fn);
#endif
diff --git a/src/mod_cml_lua.c b/src/mod_cml_lua.c
index ba786f33..41ea2842 100644
--- a/src/mod_cml_lua.c
+++ b/src/mod_cml_lua.c
@@ -101,7 +101,7 @@ static int cache_export_get_params(lua_State *L, int tbl, buffer *qrystr) {
return 0;
}
-int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
+int cache_parse_lua(server *srv, connection *con, plugin_data *p, const buffer *fn) {
lua_State *L;
int ret = -1;
buffer *b;
@@ -145,8 +145,8 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
c_to_lua_push(L, header_tbl, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
}
- c_to_lua_push(L, header_tbl, CONST_STR_LEN("CWD"), CONST_BUF_LEN(p->basedir));
- c_to_lua_push(L, header_tbl, CONST_STR_LEN("BASEURL"), CONST_BUF_LEN(p->baseurl));
+ c_to_lua_push(L, header_tbl, CONST_STR_LEN("CWD"), CONST_BUF_LEN(&p->basedir));
+ c_to_lua_push(L, header_tbl, CONST_STR_LEN("BASEURL"), CONST_BUF_LEN(&p->baseurl));
}
lua_setglobal(L, "request");
@@ -187,7 +187,7 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
lua_pop(L, 1);
/* fetch the data from lua */
- lua_to_c_get_string(L, "trigger_handler", p->trigger_handler);
+ lua_to_c_get_string(L, "trigger_handler", &p->trigger_handler);
if (0 == lua_to_c_get_string(L, "output_contenttype", b)) {
http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(b));
@@ -230,7 +230,7 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
/* the file is relative, make it absolute */
if (s[0] != '/') {
- buffer_copy_buffer(b, p->basedir);
+ buffer_copy_buffer(b, &p->basedir);
buffer_append_string(b, lua_tostring(L, -1));
} else {
buffer_copy_string(b, lua_tostring(L, -1));
@@ -243,7 +243,7 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
switch(errno) {
case ENOENT:
/* a file is missing, call the handler to generate it */
- if (!buffer_string_is_empty(p->trigger_handler)) {
+ if (!buffer_string_is_empty(&p->trigger_handler)) {
ret = 1; /* cache-miss */
log_error_write(srv, __FILE__, __LINE__, "s",
@@ -305,13 +305,13 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
}
}
- if (ret == 1 && !buffer_string_is_empty(p->trigger_handler)) {
+ if (ret == 1 && !buffer_string_is_empty(&p->trigger_handler)) {
/* cache-miss */
- buffer_copy_buffer(con->uri.path, p->baseurl);
- buffer_append_string_buffer(con->uri.path, p->trigger_handler);
+ buffer_copy_buffer(con->uri.path, &p->baseurl);
+ buffer_append_string_buffer(con->uri.path, &p->trigger_handler);
- buffer_copy_buffer(con->physical.path, p->basedir);
- buffer_append_string_buffer(con->physical.path, p->trigger_handler);
+ buffer_copy_buffer(con->physical.path, &p->basedir);
+ buffer_append_string_buffer(con->physical.path, &p->trigger_handler);
chunkqueue_reset(con->write_queue);
}
diff --git a/src/mod_compress.c b/src/mod_compress.c
index 61b0547d..8946c156 100644
--- a/src/mod_compress.c
+++ b/src/mod_compress.c
@@ -66,62 +66,41 @@ static void sigbus_handler(int sig) {
#endif
typedef struct {
- buffer *compress_cache_dir;
- array *compress;
- off_t compress_max_filesize; /** max filesize in kb */
- int allowed_encodings;
- double max_loadavg;
+ const array *compress;
+ const buffer *compress_cache_dir;
+ off_t compress_max_filesize; /** max filesize in kb */
+ double max_loadavg;
+ unsigned int allowed_encodings;
} plugin_config;
typedef struct {
- PLUGIN_DATA;
- buffer *ofn;
- buffer *b;
+ PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
- plugin_config **config_storage;
- plugin_config conf;
+ buffer *ofn;
+ buffer *b;
} plugin_data;
INIT_FUNC(mod_compress_init) {
- plugin_data *p;
-
- p = calloc(1, sizeof(*p));
-
- p->ofn = buffer_init();
- p->b = buffer_init();
-
- return p;
+ plugin_data * const p = calloc(1, sizeof(plugin_data));
+ p->ofn = buffer_init();
+ p->b = buffer_init();
+ return p;
}
FREE_FUNC(mod_compress_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- buffer_free(p->ofn);
- buffer_free(p->b);
-
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
-
- if (NULL == s) continue;
-
- array_free(s->compress);
- buffer_free(s->compress_cache_dir);
-
- free(s);
- }
- free(p->config_storage);
- }
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+ UNUSED(srv);
+ buffer_free(p->ofn);
+ buffer_free(p->b);
- free(p);
+ free(p->cvlist);
+ free(p);
- return HANDLER_GO_ON;
+ return HANDLER_GO_ON;
}
/* 0 on success, -1 for error */
@@ -168,118 +147,176 @@ static int mkdir_for_file(char *filename) {
return 0;
}
-SETDEFAULTS_FUNC(mod_compress_setdefaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { "compress.cache-dir", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "compress.filetype", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
- { "compress.max-filesize", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
- { "compress.allowed-encodings", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
- { "compress.max-loadavg", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
- array *encodings_arr = array_init();
-
- s = calloc(1, sizeof(plugin_config));
- s->compress_cache_dir = buffer_init();
- s->compress = array_init();
- s->compress_max_filesize = 0;
- s->allowed_encodings = 0;
- s->max_loadavg = 0.0;
-
- cv[0].destination = s->compress_cache_dir;
- cv[1].destination = s->compress;
- cv[2].destination = &(s->compress_max_filesize);
- cv[3].destination = encodings_arr; /* temp array for allowed encodings list */
- cv[4].destination = srv->tmp_buf;
- buffer_clear(srv->tmp_buf);
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
-
- if (!buffer_string_is_empty(srv->tmp_buf)) {
- s->max_loadavg = strtod(srv->tmp_buf->ptr, NULL);
- }
-
- if (!array_is_vlist(s->compress)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected value for compress.filetype; expected list of \"mimetype\"");
- return HANDLER_ERROR;
- }
-
- if (!array_is_vlist(encodings_arr)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected value for compress.allowed-encodings; expected list of \"encoding\"");
- return HANDLER_ERROR;
- }
-
- if (encodings_arr->used) {
- size_t j = 0;
- for (j = 0; j < encodings_arr->used; j++) {
-#if defined(USE_ZLIB) || defined(USE_BZ2LIB)
- data_string *ds = (data_string *)encodings_arr->data[j];
-#endif
-#ifdef USE_ZLIB
- if (NULL != strstr(ds->value.ptr, "gzip"))
- s->allowed_encodings |= HTTP_ACCEPT_ENCODING_GZIP | HTTP_ACCEPT_ENCODING_X_GZIP;
- if (NULL != strstr(ds->value.ptr, "x-gzip"))
- s->allowed_encodings |= HTTP_ACCEPT_ENCODING_X_GZIP;
- if (NULL != strstr(ds->value.ptr, "deflate"))
- s->allowed_encodings |= HTTP_ACCEPT_ENCODING_DEFLATE;
- /*
- if (NULL != strstr(ds->value.ptr, "compress"))
- s->allowed_encodings |= HTTP_ACCEPT_ENCODING_COMPRESS;
- */
-#endif
-#ifdef USE_BZ2LIB
- if (NULL != strstr(ds->value.ptr, "bzip2"))
- s->allowed_encodings |= HTTP_ACCEPT_ENCODING_BZIP2 | HTTP_ACCEPT_ENCODING_X_BZIP2;
- if (NULL != strstr(ds->value.ptr, "x-bzip2"))
- s->allowed_encodings |= HTTP_ACCEPT_ENCODING_X_BZIP2;
-#endif
- }
- } else {
- /* default encodings */
- s->allowed_encodings = 0
-#ifdef USE_ZLIB
- | HTTP_ACCEPT_ENCODING_GZIP | HTTP_ACCEPT_ENCODING_X_GZIP | HTTP_ACCEPT_ENCODING_DEFLATE
-#endif
-#ifdef USE_BZ2LIB
- | HTTP_ACCEPT_ENCODING_BZIP2 | HTTP_ACCEPT_ENCODING_X_BZIP2
-#endif
- ;
- }
-
- array_free(encodings_arr);
-
- if (!buffer_string_is_empty(s->compress_cache_dir)) {
- struct stat st;
- mkdir_recursive(s->compress_cache_dir->ptr);
+static void mod_compress_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* compress.filetype */
+ pconf->compress = cpv->v.a;
+ break;
+ case 1: /* compress.allowed-encodings */
+ pconf->allowed_encodings = cpv->v.u;
+ break;
+ case 2: /* compress.cache-dir */
+ pconf->compress_cache_dir = cpv->v.b;
+ break;
+ case 3: /* compress.max-filesize */
+ pconf->compress_max_filesize = cpv->v.o;
+ break;
+ case 4: /* compress.max-loadavg */
+ pconf->max_loadavg = cpv->v.d;
+ break;
+ default:/* should not happen */
+ return;
+ }
+}
- if (0 != stat(s->compress_cache_dir->ptr, &st)) {
- log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir",
- s->compress_cache_dir, strerror(errno));
+static void mod_compress_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_compress_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- return HANDLER_ERROR;
- }
- }
- }
+static void mod_compress_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_compress_merge_config(&p->conf, p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
- return HANDLER_GO_ON;
+static short mod_compress_encodings_to_flags(const array *encodings) {
+ short allowed_encodings = 0;
+ if (encodings->used) {
+ for (uint32_t j = 0; j < encodings->used; ++j) {
+ #if defined(USE_ZLIB) || defined(USE_BZ2LIB)
+ data_string *ds = (data_string *)encodings->data[j];
+ #endif
+ #ifdef USE_ZLIB
+ if (NULL != strstr(ds->value.ptr, "gzip"))
+ allowed_encodings |= HTTP_ACCEPT_ENCODING_GZIP
+ | HTTP_ACCEPT_ENCODING_X_GZIP;
+ if (NULL != strstr(ds->value.ptr, "x-gzip"))
+ allowed_encodings |= HTTP_ACCEPT_ENCODING_X_GZIP;
+ if (NULL != strstr(ds->value.ptr, "deflate"))
+ allowed_encodings |= HTTP_ACCEPT_ENCODING_DEFLATE;
+ /*
+ if (NULL != strstr(ds->value.ptr, "compress"))
+ allowed_encodings |= HTTP_ACCEPT_ENCODING_COMPRESS;
+ */
+ #endif
+ #ifdef USE_BZ2LIB
+ if (NULL != strstr(ds->value.ptr, "bzip2"))
+ allowed_encodings |= HTTP_ACCEPT_ENCODING_BZIP2
+ | HTTP_ACCEPT_ENCODING_X_BZIP2;
+ if (NULL != strstr(ds->value.ptr, "x-bzip2"))
+ allowed_encodings |= HTTP_ACCEPT_ENCODING_X_BZIP2;
+ #endif
+ }
+ }
+ else {
+ /* default encodings */
+ #ifdef USE_ZLIB
+ allowed_encodings |= HTTP_ACCEPT_ENCODING_GZIP
+ | HTTP_ACCEPT_ENCODING_X_GZIP
+ | HTTP_ACCEPT_ENCODING_DEFLATE;
+ #endif
+ #ifdef USE_BZ2LIB
+ allowed_encodings |= HTTP_ACCEPT_ENCODING_BZIP2
+ | HTTP_ACCEPT_ENCODING_X_BZIP2;
+ #endif
+ }
+ return allowed_encodings;
+}
+SETDEFAULTS_FUNC(mod_compress_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("compress.filetype"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("compress.allowed-encodings"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("compress.cache-dir"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("compress.max-filesize"),
+ T_CONFIG_SHORT,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("compress.max-loadavg"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_compress"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* compress.filetype */
+ if (!array_is_vlist(cpv->v.a)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s; "
+ "expected list of \"mimetype\"", cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ if (0 == cpv->v.a->used) cpv->v.a = NULL;
+ break;
+ case 1: /* compress.allowed-encodings */
+ if (!array_is_vlist(cpv->v.a)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s; "
+ "expected list of \"encoding\"", cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ cpv->v.u = (unsigned int)
+ mod_compress_encodings_to_flags(cpv->v.a);
+ cpv->vtype = T_CONFIG_INT;
+ break;
+ case 2: /* compress.cache-dir */
+ if (!buffer_string_is_empty(cpv->v.b)) {
+ struct stat st;
+ mkdir_recursive(cpv->v.b->ptr);
+ if (0 != stat(cpv->v.b->ptr, &st)) {
+ log_perror(srv->errh, __FILE__, __LINE__,
+ "can't stat %s %s", cpk[cpv->k_id].k, cpv->v.b->ptr);
+ return HANDLER_ERROR;
+ }
+ }
+ break;
+ case 3: /* compress.max-filesize */
+ cpv->v.o = ((off_t)cpv->v.shrt) << 10; /* KB to bytes */
+ break;
+ case 4: /* compress.max-loadavg */
+ cpv->v.d = (!buffer_string_is_empty(cpv->v.b))
+ ? strtod(cpv->v.b->ptr, NULL)
+ : 0.0;
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+ }
+
+ p->defaults.max_loadavg = 0.0;
+
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_compress_merge_config(&p->defaults, cpv);
+ }
+
+ return HANDLER_GO_ON;
}
+
#ifdef USE_ZLIB
static int deflate_file_to_buffer_gzip(server *srv, connection *con, plugin_data *p, char *start, off_t st_size, time_t mtime) {
unsigned char *c;
@@ -749,48 +786,6 @@ static int deflate_file_to_buffer(server *srv, connection *con, plugin_data *p,
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_compress_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(compress_cache_dir);
- PATCH(compress);
- PATCH(compress_max_filesize);
- PATCH(allowed_encodings);
- PATCH(max_loadavg);
-
- /* 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("compress.cache-dir"))) {
- PATCH(compress_cache_dir);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("compress.filetype"))) {
- PATCH(compress);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("compress.max-filesize"))) {
- PATCH(compress_max_filesize);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("compress.allowed-encodings"))) {
- PATCH(allowed_encodings);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("compress.max-loadavg"))) {
- PATCH(max_loadavg);
- }
- }
- }
-
- return 0;
-}
-#undef PATCH
-
static int mod_compress_contains_encoding(const char *headervalue, const char *encoding, size_t len) {
const char *m = headervalue;
do {
@@ -812,9 +807,8 @@ static int mod_compress_contains_encoding(const char *headervalue, const char *e
PHYSICALPATH_FUNC(mod_compress_physical) {
plugin_data *p = p_d;
size_t m;
- off_t max_fsize;
stat_cache_entry *sce = NULL;
- buffer *mtime = NULL;
+ const buffer *mtime = NULL;
buffer *content_type;
if (con->mode != DIRECT || con->http_status) return HANDLER_GO_ON;
@@ -829,9 +823,11 @@ PHYSICALPATH_FUNC(mod_compress_physical) {
return HANDLER_GO_ON;
}
- mod_compress_patch_connection(srv, con, p);
+ mod_compress_patch_config(con, p);
- max_fsize = p->conf.compress_max_filesize;
+ if (NULL == p->conf.compress) {
+ return HANDLER_GO_ON;
+ }
if (con->conf.log_request_handling) {
log_error_write(srv, __FILE__, __LINE__, "s", "-- handling file as static file");
@@ -853,7 +849,8 @@ PHYSICALPATH_FUNC(mod_compress_physical) {
}
/* don't compress files that are too large as we need to much time to handle them */
- if (max_fsize && (sce->st.st_size >> 10) > max_fsize) return HANDLER_GO_ON;
+ off_t max_fsize = p->conf.compress_max_filesize;
+ if (max_fsize && sce->st.st_size > max_fsize) return HANDLER_GO_ON;
/* don't try to compress files less than 128 bytes
*
@@ -1018,14 +1015,12 @@ PHYSICALPATH_FUNC(mod_compress_physical) {
int mod_compress_plugin_init(plugin *p);
int mod_compress_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("compress");
+ p->name = "compress";
p->init = mod_compress_init;
- p->set_defaults = mod_compress_setdefaults;
+ p->set_defaults = mod_compress_set_defaults;
p->handle_subrequest_start = mod_compress_physical;
p->cleanup = mod_compress_free;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_deflate.c b/src/mod_deflate.c
index aed374f8..08cb634f 100644
--- a/src/mod_deflate.c
+++ b/src/mod_deflate.c
@@ -169,24 +169,23 @@ static void sigbus_handler(int sig) {
#define GByte * 1024 MByte
typedef struct {
- array *mimetypes;
- int allowed_encodings;
+ const array *mimetypes;
unsigned int max_compress_size;
unsigned short min_compress_size;
unsigned short output_buffer_size;
unsigned short work_block_size;
unsigned short sync_flush;
short compression_level;
+ short allowed_encodings;
double max_loadavg;
} plugin_config;
typedef struct {
- PLUGIN_DATA;
- buffer *tmp_buf;
- array *encodings;
+ PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
- plugin_config **config_storage;
- plugin_config conf;
+ buffer tmp_buf;
} plugin_data;
typedef struct {
@@ -218,7 +217,7 @@ static handler_ctx *handler_ctx_init() {
static void handler_ctx_free(handler_ctx *hctx) {
#if 0
- if (hctx->output != p->tmp_buf) {
+ if (hctx->output != &p->tmp_buf) {
buffer_free(hctx->output);
}
#endif
@@ -227,170 +226,226 @@ static void handler_ctx_free(handler_ctx *hctx) {
}
INIT_FUNC(mod_deflate_init) {
- plugin_data *p;
-
- p = calloc(1, sizeof(*p));
-
- p->encodings = array_init();
- p->tmp_buf = buffer_init();
- buffer_string_prepare_copy(p->tmp_buf, 64 KByte);
-
- return p;
+ plugin_data * const p = calloc(1, sizeof(plugin_data));
+ buffer_string_prepare_copy(&p->tmp_buf, 64 KByte);
+ return p;
}
FREE_FUNC(mod_deflate_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- 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;
-
- array_free(s->mimetypes);
- free(s);
- }
- free(p->config_storage);
- }
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+ UNUSED(srv);
- buffer_free(p->tmp_buf);
- array_free(p->encodings);
+ free(p->tmp_buf.ptr);
- free(p);
+ free(p->cvlist);
+ free(p);
- return HANDLER_GO_ON;
+ return HANDLER_GO_ON;
}
-SETDEFAULTS_FUNC(mod_deflate_setdefaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { "deflate.mimetypes", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
- { "deflate.allowed-encodings", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
- { "deflate.max-compress-size", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION },
- { "deflate.min-compress-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
- { "deflate.compression-level", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
- { "deflate.output-buffer-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
- { "deflate.work-block-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
- { "deflate.max-loadavg", NULL, T_CONFIG_STRING,T_CONFIG_SCOPE_CONNECTION },
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->mimetypes = array_init();
- s->allowed_encodings = 0;
- s->max_compress_size = 128*1024; /*(128 MB measured as num KB)*/
- s->min_compress_size = 256;
- s->output_buffer_size = 0;
- s->work_block_size = 2048;
- s->sync_flush = 0;
- s->compression_level = -1;
- s->max_loadavg = 0.0;
-
- array_reset_data_strings(p->encodings); /* temp array for allowed encodings list */
-
- cv[0].destination = s->mimetypes;
- cv[1].destination = p->encodings;
- cv[2].destination = &(s->max_compress_size);
- cv[3].destination = &(s->min_compress_size);
- cv[4].destination = &(s->compression_level);
- cv[5].destination = &(s->output_buffer_size);
- cv[6].destination = &(s->work_block_size);
- cv[7].destination = p->tmp_buf;
- buffer_clear(p->tmp_buf);
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
-
- if ((s->compression_level < 1 || s->compression_level > 9) &&
- s->compression_level != -1) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "compression-level must be between 1 and 9:", s->compression_level);
- return HANDLER_ERROR;
- }
-
- if (!buffer_string_is_empty(p->tmp_buf)) {
- s->max_loadavg = strtod(p->tmp_buf->ptr, NULL);
- }
-
- if (!array_is_vlist(s->mimetypes)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected value for deflate.mimetypes; expected list of \"mimetype\"");
- return HANDLER_ERROR;
- }
-
- if (!array_is_vlist(p->encodings)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected value for deflate.allowed-encodings; expected list of \"encoding\"");
- return HANDLER_ERROR;
- }
+static void mod_deflate_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* deflate.mimetypes */
+ pconf->mimetypes = cpv->v.a;
+ break;
+ case 1: /* deflate.allowed-encodings */
+ pconf->allowed_encodings = (short)cpv->v.shrt;
+ break;
+ case 2: /* deflate.max-compress-size */
+ pconf->max_compress_size = cpv->v.u;
+ break;
+ case 3: /* deflate.min-compress-size */
+ pconf->min_compress_size = cpv->v.shrt;
+ break;
+ case 4: /* deflate.compression-level */
+ pconf->compression_level = (short)cpv->v.shrt;
+ break;
+ case 5: /* deflate.output-buffer-size */
+ pconf->output_buffer_size = cpv->v.shrt;
+ break;
+ case 6: /* deflate.work-block-size */
+ pconf->work_block_size = cpv->v.shrt;
+ break;
+ case 7: /* deflate.max-loadavg */
+ pconf->max_loadavg = cpv->v.d;
+ break;
+ default:/* should not happen */
+ return;
+ }
+}
- if (p->encodings->used) {
- size_t j = 0;
- for (j = 0; j < p->encodings->used; j++) {
-#if defined(USE_ZLIB) || defined(USE_BZ2LIB)
- data_string *ds = (data_string *)p->encodings->data[j];
-#endif
-#ifdef USE_ZLIB
- if (NULL != strstr(ds->value.ptr, "gzip"))
- s->allowed_encodings |= HTTP_ACCEPT_ENCODING_GZIP | HTTP_ACCEPT_ENCODING_X_GZIP;
- if (NULL != strstr(ds->value.ptr, "x-gzip"))
- s->allowed_encodings |= HTTP_ACCEPT_ENCODING_X_GZIP;
- if (NULL != strstr(ds->value.ptr, "deflate"))
- s->allowed_encodings |= HTTP_ACCEPT_ENCODING_DEFLATE;
- /*
- if (NULL != strstr(ds->value.ptr, "compress"))
- s->allowed_encodings |= HTTP_ACCEPT_ENCODING_COMPRESS;
- */
-#endif
-#ifdef USE_BZ2LIB
- if (NULL != strstr(ds->value.ptr, "bzip2"))
- s->allowed_encodings |= HTTP_ACCEPT_ENCODING_BZIP2 | HTTP_ACCEPT_ENCODING_X_BZIP2;
- if (NULL != strstr(ds->value.ptr, "x-bzip2"))
- s->allowed_encodings |= HTTP_ACCEPT_ENCODING_X_BZIP2;
-#endif
- }
- } else {
- /* default encodings */
-#ifdef USE_ZLIB
- s->allowed_encodings |= HTTP_ACCEPT_ENCODING_GZIP
- | HTTP_ACCEPT_ENCODING_X_GZIP
- | HTTP_ACCEPT_ENCODING_DEFLATE;
-#endif
-#ifdef USE_BZ2LIB
- s->allowed_encodings |= HTTP_ACCEPT_ENCODING_BZIP2
- | HTTP_ACCEPT_ENCODING_X_BZIP2;
-#endif
- }
+static void mod_deflate_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_deflate_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- /* mod_deflate matches mimetype as prefix of Content-Type
- * so ignore '*' at end of mimetype for end-user flexibility
- * in specifying trailing wildcard to grouping of mimetypes */
- for (size_t m = 0; m < s->mimetypes->used; ++m) {
- buffer *mimetype = &((data_string *)s->mimetypes->data[m])->value;
- size_t len = buffer_string_length(mimetype);
- if (len > 2 && mimetype->ptr[len-1] == '*') {
- buffer_string_set_length(mimetype, len-1);
- }
- }
- }
+static void mod_deflate_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_deflate_merge_config(&p->conf, p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
- return HANDLER_GO_ON;
+static short mod_deflate_encodings_to_flags(const array *encodings) {
+ short allowed_encodings = 0;
+ if (encodings->used) {
+ for (uint32_t j = 0; j < encodings->used; ++j) {
+ #if defined(USE_ZLIB) || defined(USE_BZ2LIB)
+ data_string *ds = (data_string *)encodings->data[j];
+ #endif
+ #ifdef USE_ZLIB
+ if (NULL != strstr(ds->value.ptr, "gzip"))
+ allowed_encodings |= HTTP_ACCEPT_ENCODING_GZIP
+ | HTTP_ACCEPT_ENCODING_X_GZIP;
+ if (NULL != strstr(ds->value.ptr, "x-gzip"))
+ allowed_encodings |= HTTP_ACCEPT_ENCODING_X_GZIP;
+ if (NULL != strstr(ds->value.ptr, "deflate"))
+ allowed_encodings |= HTTP_ACCEPT_ENCODING_DEFLATE;
+ /*
+ if (NULL != strstr(ds->value.ptr, "compress"))
+ allowed_encodings |= HTTP_ACCEPT_ENCODING_COMPRESS;
+ */
+ #endif
+ #ifdef USE_BZ2LIB
+ if (NULL != strstr(ds->value.ptr, "bzip2"))
+ allowed_encodings |= HTTP_ACCEPT_ENCODING_BZIP2
+ | HTTP_ACCEPT_ENCODING_X_BZIP2;
+ if (NULL != strstr(ds->value.ptr, "x-bzip2"))
+ allowed_encodings |= HTTP_ACCEPT_ENCODING_X_BZIP2;
+ #endif
+ }
+ }
+ else {
+ /* default encodings */
+ #ifdef USE_ZLIB
+ allowed_encodings |= HTTP_ACCEPT_ENCODING_GZIP
+ | HTTP_ACCEPT_ENCODING_X_GZIP
+ | HTTP_ACCEPT_ENCODING_DEFLATE;
+ #endif
+ #ifdef USE_BZ2LIB
+ allowed_encodings |= HTTP_ACCEPT_ENCODING_BZIP2
+ | HTTP_ACCEPT_ENCODING_X_BZIP2;
+ #endif
+ }
+ return allowed_encodings;
+}
+SETDEFAULTS_FUNC(mod_deflate_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("deflate.mimetypes"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("deflate.allow-encodings"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("deflate.max-compress-size"),
+ T_CONFIG_INT,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("deflate.min-compress-size"),
+ T_CONFIG_SHORT,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("deflate.compression-level"),
+ T_CONFIG_SHORT,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("deflate.output-buffer-size"),
+ T_CONFIG_SHORT,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("deflate.work-block-size"),
+ T_CONFIG_SHORT,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("deflate.max-loadavg"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_deflate"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* deflate.mimetypes */
+ if (!array_is_vlist(cpv->v.a)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s; "
+ "expected list of \"mimetype\"", cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ /* mod_deflate matches mimetype as prefix of Content-Type
+ * so ignore '*' at end of mimetype for end-user flexibility
+ * in specifying trailing wildcard to grouping of mimetypes */
+ for (uint32_t m = 0; m < cpv->v.a->used; ++m) {
+ buffer *mimetype=&((data_string *)cpv->v.a->data[m])->value;
+ size_t len = buffer_string_length(mimetype);
+ if (len > 2 && mimetype->ptr[len-1] == '*')
+ buffer_string_set_length(mimetype, len-1);
+ }
+ if (0 == cpv->v.a->used) cpv->v.a = NULL;
+ break;
+ case 1: /* deflate.allowed-encodings */
+ if (!array_is_vlist(cpv->v.a)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s; "
+ "expected list of \"encoding\"", cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ cpv->v.shrt = (unsigned short)
+ mod_deflate_encodings_to_flags(cpv->v.a);
+ cpv->vtype = T_CONFIG_SHORT;
+ break;
+ case 2: /* deflate.max-compress-size */
+ case 3: /* deflate.min-compress-size */
+ break;
+ case 4: /* deflate.compression-level */
+ if ((cpv->v.shrt < 1 || cpv->v.shrt > 9)
+ && *(short *)&cpv->v.shrt != -1) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "compression-level must be between 1 and 9: %hu",
+ cpv->v.shrt);
+ return HANDLER_ERROR;
+ }
+ break;
+ case 5: /* deflate.output-buffer-size */
+ case 6: /* deflate.work-block-size */
+ break;
+ case 7: /* deflate.max-loadavg */
+ cpv->v.d = (!buffer_string_is_empty(cpv->v.b))
+ ? strtod(cpv->v.b->ptr, NULL)
+ : 0.0;
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+ }
+
+ p->defaults.allowed_encodings = 0;
+ p->defaults.max_compress_size = 128*1024; /*(128 MB measured as num KB)*/
+ p->defaults.min_compress_size = 256;
+ p->defaults.compression_level = -1;
+ p->defaults.output_buffer_size = 0;
+ p->defaults.work_block_size = 2048;
+ p->defaults.max_loadavg = 0.0;
+ p->defaults.sync_flush = 0;
+
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_deflate_merge_config(&p->defaults, cpv);
+ }
+
+ return HANDLER_GO_ON;
}
@@ -938,57 +993,6 @@ static handler_t deflate_compress_response(server *srv, connection *con, handler
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_deflate_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(mimetypes);
- PATCH(allowed_encodings);
- PATCH(max_compress_size);
- PATCH(min_compress_size);
- PATCH(compression_level);
- PATCH(output_buffer_size);
- PATCH(work_block_size);
- PATCH(max_loadavg);
-
- /* 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("deflate.mimetypes"))) {
- PATCH(mimetypes);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("deflate.allowed-encodings"))) {
- PATCH(allowed_encodings);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("deflate.max-compress-size"))) {
- PATCH(max_compress_size);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("deflate.min-compress-size"))) {
- PATCH(min_compress_size);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("deflate.compression-level"))) {
- PATCH(compression_level);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("deflate.output-buffer-size"))) {
- PATCH(output_buffer_size);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("deflate.work-block-size"))) {
- PATCH(work_block_size);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("deflate.max-loadavg"))) {
- PATCH(max_loadavg);
- }
- }
- }
-
- return 0;
-}
-#undef PATCH
-
static int mod_deflate_choose_encoding (const char *value, plugin_data *p, const char **label) {
/* get client side support encodings */
int accept_encoding = 0;
@@ -1109,10 +1113,10 @@ CONNECTION_FUNC(mod_deflate_handle_response_start) {
break;
}
- mod_deflate_patch_connection(srv, con, p);
+ mod_deflate_patch_config(con, p);
/* check if deflate configured for any mimetypes */
- if (!p->conf.mimetypes->used) return HANDLER_GO_ON;
+ if (NULL == p->conf.mimetypes) return HANDLER_GO_ON;
/* check if size of response is below min-compress-size or exceeds max*/
/* (con->file_finished checked at top of routine) */
@@ -1229,8 +1233,8 @@ CONNECTION_FUNC(mod_deflate_handle_response_start) {
hctx->plugin_data = p;
hctx->compression_type = compression_type;
/* setup output buffer */
- buffer_clear(p->tmp_buf);
- hctx->output = p->tmp_buf;
+ buffer_clear(&p->tmp_buf);
+ hctx->output = &p->tmp_buf;
if (0 != mod_deflate_stream_init(hctx)) {
/*(should not happen unless ENOMEM)*/
handler_ctx_free(hctx);
@@ -1274,15 +1278,13 @@ static handler_t mod_deflate_cleanup(server *srv, connection *con, void *p_d) {
int mod_deflate_plugin_init(plugin *p);
int mod_deflate_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("deflate");
+ p->name = "deflate";
p->init = mod_deflate_init;
p->cleanup = mod_deflate_free;
- p->set_defaults = mod_deflate_setdefaults;
+ p->set_defaults = mod_deflate_set_defaults;
p->connection_reset = mod_deflate_cleanup;
p->handle_response_start = mod_deflate_handle_response_start;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_dirlisting.c b/src/mod_dirlisting.c
index 2663bfb1..754c7936 100644
--- a/src/mod_dirlisting.c
+++ b/src/mod_dirlisting.c
@@ -13,7 +13,6 @@
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
-#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
@@ -34,376 +33,336 @@
#include <sys/extattr.h>
#endif
-/* plugin config for all request/connections */
-
typedef struct {
-#ifdef HAVE_PCRE_H
- pcre *regex;
-#endif
- buffer *string;
-} excludes;
-
-typedef struct {
- excludes **ptr;
-
- size_t used;
- size_t size;
-} excludes_buffer;
-
-typedef struct {
- unsigned short dir_listing;
- unsigned short hide_dot_files;
- unsigned short hide_readme_file;
- unsigned short encode_readme;
- unsigned short hide_header_file;
- unsigned short encode_header;
- unsigned short auto_layout;
-
- excludes_buffer *excludes;
-
- buffer *show_readme;
- buffer *show_header;
- buffer *external_css;
- buffer *external_js;
- buffer *encoding;
- buffer *set_footer;
+ char dir_listing;
+ char hide_dot_files;
+ char hide_readme_file;
+ char encode_readme;
+ char hide_header_file;
+ char encode_header;
+ char auto_layout;
+
+ #ifdef HAVE_PCRE_H
+ pcre **excludes;
+ #else
+ void *excludes;
+ #endif
+
+ const buffer *show_readme;
+ const buffer *show_header;
+ const buffer *external_css;
+ const buffer *external_js;
+ const buffer *encoding;
+ const buffer *set_footer;
} plugin_config;
typedef struct {
PLUGIN_DATA;
-
- buffer *tmp_buf;
- buffer *content_charset;
-
- plugin_config **config_storage;
-
+ plugin_config defaults;
plugin_config conf;
-} plugin_data;
-
-static excludes_buffer *excludes_buffer_init(void) {
- excludes_buffer *exb;
-
- exb = calloc(1, sizeof(*exb));
- return exb;
-}
+ buffer tmp_buf;
+} plugin_data;
#ifdef HAVE_PCRE_H
-static int excludes_buffer_append(excludes_buffer *exb, buffer *string) {
- size_t i;
- const char *errptr;
- int erroff;
-
- if (!string) return -1;
-
- if (exb->used == exb->size) {
- exb->size += 4;
-
- exb->ptr = realloc(exb->ptr, exb->size * sizeof(*exb->ptr));
-
- for(i = exb->used; i < exb->size; i++) {
- exb->ptr[i] = calloc(1, sizeof(**exb->ptr));
- }
- }
+static pcre ** mod_dirlisting_parse_excludes(server *srv, const array *a) {
+ pcre **regexes = calloc(a->used + 1, sizeof(pcre *));
+ force_assert(regexes);
+ for (uint32_t j = 0; j < a->used; ++j) {
+ const data_string *ds = (const data_string *)a->data[j];
+ const char *errptr;
+ int erroff;
+ regexes[j] = pcre_compile(ds->value.ptr, 0, &errptr, &erroff, NULL);
+ if (NULL == regexes[j]) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "pcre_compile failed for: %s", ds->value.ptr);
+ for (pcre **regex = regexes; *regex; ++regex) pcre_free(*regex);
+ free(regexes);
+ return NULL;
+ }
+ }
+ return regexes;
+}
- if (NULL == (exb->ptr[exb->used]->regex = pcre_compile(string->ptr, 0,
- &errptr, &erroff, NULL))) {
- return -1;
- }
-
- exb->ptr[exb->used]->string = buffer_init();
- buffer_copy_buffer(exb->ptr[exb->used]->string, string);
-
- exb->used++;
-
- return 0;
+static int mod_dirlisting_exclude(server *srv, pcre **regex, const char *name, size_t len) {
+ for(; *regex; ++regex) {
+ #define N 10
+ int ovec[N * 3];
+ int n;
+ if ((n = pcre_exec(*regex, NULL, name, len, 0, 0, ovec, 3 * N)) < 0) {
+ if (n == PCRE_ERROR_NOMATCH) continue;
+
+ log_error(srv->errh, __FILE__, __LINE__,
+ "execution error while matching: %d", n);
+ /* aborting would require a lot of manual cleanup here.
+ * skip instead (to not leak names that break pcre matching)
+ */
+ }
+ return 1;
+ #undef N
+ }
+ return 0; /* no match */
}
-#endif
-static void excludes_buffer_free(excludes_buffer *exb) {
-#ifdef HAVE_PCRE_H
- size_t i;
+#else
- for (i = 0; i < exb->size; i++) {
- if (exb->ptr[i]->regex) pcre_free(exb->ptr[i]->regex);
- if (exb->ptr[i]->string) buffer_free(exb->ptr[i]->string);
- free(exb->ptr[i]);
- }
+#define mod_dirlisting_exclude(a, b, c, d) 0
- if (exb->ptr) free(exb->ptr);
#endif
- free(exb);
-}
-/* init the plugin data */
INIT_FUNC(mod_dirlisting_init) {
- plugin_data *p;
-
- p = calloc(1, sizeof(*p));
-
- p->tmp_buf = buffer_init();
- p->content_charset = buffer_init();
+ return calloc(1, sizeof(plugin_data));
+}
- return p;
+static void mod_dirlisting_free_config(plugin_data * const p) {
+ if (NULL == p->cvlist) return;
+ /* (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ #ifdef HAVE_PCRE_H
+ case 2: /* dir-listing.exclude */
+ if (cpv->vtype != T_CONFIG_LOCAL) continue;
+ for (pcre **regex = cpv->v.v; *regex; ++regex)
+ pcre_free(*regex);
+ free(cpv->v.v);
+ break;
+ #endif
+ default:
+ break;
+ }
+ }
+ }
}
-/* detroy the plugin data */
FREE_FUNC(mod_dirlisting_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- 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;
-
- excludes_buffer_free(s->excludes);
- buffer_free(s->show_readme);
- buffer_free(s->show_header);
- buffer_free(s->external_css);
- buffer_free(s->external_js);
- buffer_free(s->encoding);
- buffer_free(s->set_footer);
-
- free(s);
- }
- free(p->config_storage);
- }
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+ UNUSED(srv);
- buffer_free(p->tmp_buf);
- buffer_free(p->content_charset);
+ mod_dirlisting_free_config(p);
+ free(p->tmp_buf.ptr);
- free(p);
+ free(p->cvlist);
+ free(p);
- return HANDLER_GO_ON;
+ return HANDLER_GO_ON;
}
-/* handle plugin config and check values */
-
-#define CONFIG_EXCLUDE "dir-listing.exclude"
-#define CONFIG_ACTIVATE "dir-listing.activate"
-#define CONFIG_HIDE_DOTFILES "dir-listing.hide-dotfiles"
-#define CONFIG_EXTERNAL_CSS "dir-listing.external-css"
-#define CONFIG_EXTERNAL_JS "dir-listing.external-js"
-#define CONFIG_ENCODING "dir-listing.encoding"
-#define CONFIG_SHOW_README "dir-listing.show-readme"
-#define CONFIG_HIDE_README_FILE "dir-listing.hide-readme-file"
-#define CONFIG_SHOW_HEADER "dir-listing.show-header"
-#define CONFIG_HIDE_HEADER_FILE "dir-listing.hide-header-file"
-#define CONFIG_DIR_LISTING "server.dir-listing"
-#define CONFIG_SET_FOOTER "dir-listing.set-footer"
-#define CONFIG_ENCODE_README "dir-listing.encode-readme"
-#define CONFIG_ENCODE_HEADER "dir-listing.encode-header"
-#define CONFIG_AUTO_LAYOUT "dir-listing.auto-layout"
-
-
-SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { CONFIG_EXCLUDE, NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { CONFIG_ACTIVATE, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { CONFIG_HIDE_DOTFILES, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
- { CONFIG_EXTERNAL_CSS, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
- { CONFIG_ENCODING, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
- { CONFIG_SHOW_README, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
- { CONFIG_HIDE_README_FILE, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
- { CONFIG_SHOW_HEADER, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
- { CONFIG_HIDE_HEADER_FILE, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
- { CONFIG_DIR_LISTING, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
- { CONFIG_SET_FOOTER, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 10 */
- { CONFIG_ENCODE_README, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 11 */
- { CONFIG_ENCODE_HEADER, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
- { CONFIG_AUTO_LAYOUT, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 13 */
- { CONFIG_EXTERNAL_JS, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 14 */
-
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
- const data_unset *du_excludes;
-
- s = calloc(1, sizeof(plugin_config));
- s->excludes = excludes_buffer_init();
- s->dir_listing = 0;
- s->show_readme = buffer_init();
- s->show_header = buffer_init();
- s->external_css = buffer_init();
- s->external_js = buffer_init();
- s->hide_dot_files = 1;
- s->hide_readme_file = 0;
- s->hide_header_file = 0;
- s->encode_readme = 1;
- s->encode_header = 1;
- s->auto_layout = 1;
-
- s->encoding = buffer_init();
- s->set_footer = buffer_init();
-
- cv[0].destination = s->excludes;
- cv[1].destination = &(s->dir_listing);
- cv[2].destination = &(s->hide_dot_files);
- cv[3].destination = s->external_css;
- cv[4].destination = s->encoding;
- cv[5].destination = s->show_readme;
- cv[6].destination = &(s->hide_readme_file);
- cv[7].destination = s->show_header;
- cv[8].destination = &(s->hide_header_file);
- cv[9].destination = &(s->dir_listing); /* old name */
- cv[10].destination = s->set_footer;
- cv[11].destination = &(s->encode_readme);
- cv[12].destination = &(s->encode_header);
- cv[13].destination = &(s->auto_layout);
- cv[14].destination = s->external_js;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
-
- if (NULL != (du_excludes = array_get_element_klen(config->value, CONST_STR_LEN(CONFIG_EXCLUDE)))) {
- const array *excludes_list;
- excludes_list = &((const data_array*)du_excludes)->value;
-
- if (du_excludes->type != TYPE_ARRAY || !array_is_vlist(excludes_list)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected type for " CONFIG_EXCLUDE "; expected list of \"regex\"");
- return HANDLER_ERROR;
- }
-
-#ifndef HAVE_PCRE_H
- if (excludes_list->used > 0) {
- log_error_write(srv, __FILE__, __LINE__, "sss",
- "pcre support is missing for: ", CONFIG_EXCLUDE, ", please install libpcre and the headers");
- return HANDLER_ERROR;
- }
-#else
- for (size_t j = 0; j < excludes_list->used; ++j) {
- data_unset *du_exclude = excludes_list->data[j];
-
- if (du_exclude->type != TYPE_STRING) {
- log_error_write(srv, __FILE__, __LINE__, "sssbs",
- "unexpected type for key: ", CONFIG_EXCLUDE, "[",
- &du_exclude->key, "](string)");
- return HANDLER_ERROR;
- }
-
- if (0 != excludes_buffer_append(s->excludes, &((data_string*)(du_exclude))->value)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "pcre-compile failed for", &((data_string*)(du_exclude))->value);
- return HANDLER_ERROR;
- }
- }
-#endif
- }
-
- if (!buffer_string_is_empty(s->show_readme)) {
- if (buffer_is_equal_string(s->show_readme, CONST_STR_LEN("enable"))) {
- buffer_copy_string_len(s->show_readme, CONST_STR_LEN("README.txt"));
- }
- else if (buffer_is_equal_string(s->show_readme, CONST_STR_LEN("disable"))) {
- buffer_clear(s->show_readme);
- }
- }
-
- if (!buffer_string_is_empty(s->show_header)) {
- if (buffer_is_equal_string(s->show_header, CONST_STR_LEN("enable"))) {
- buffer_copy_string_len(s->show_header, CONST_STR_LEN("HEADER.txt"));
- }
- else if (buffer_is_equal_string(s->show_header, CONST_STR_LEN("disable"))) {
- buffer_clear(s->show_header);
- }
- }
- }
+static void mod_dirlisting_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* dir-listing.activate */
+ case 1: /* server.dir-listing *//*(historical)*/
+ pconf->dir_listing = (char)cpv->v.u;
+ break;
+ case 2: /* dir-listing.exclude */
+ if (cpv->vtype == T_CONFIG_LOCAL)
+ pconf->excludes = cpv->v.v;
+ break;
+ case 3: /* dir-listing.hide-dotfiles */
+ pconf->hide_dot_files = (char)cpv->v.u;
+ break;
+ case 4: /* dir-listing.external-css */
+ pconf->external_css = cpv->v.b;
+ break;
+ case 5: /* dir-listing.external-js */
+ pconf->external_js = cpv->v.b;
+ break;
+ case 6: /* dir-listing.encoding */
+ pconf->encoding = cpv->v.b;
+ break;
+ case 7: /* dir-listing.show-readme */
+ pconf->show_readme = cpv->v.b;
+ break;
+ case 8: /* dir-listing.hide-readme-file */
+ pconf->hide_readme_file = (char)cpv->v.u;
+ break;
+ case 9: /* dir-listing.show-header */
+ pconf->show_header = cpv->v.b;
+ break;
+ case 10:/* dir-listing.hide-header-file */
+ pconf->hide_header_file = (char)cpv->v.u;
+ break;
+ case 11:/* dir-listing.set-footer */
+ pconf->set_footer = cpv->v.b;
+ break;
+ case 12:/* dir-listing.encode-readme */
+ pconf->encode_readme = (char)cpv->v.u;
+ break;
+ case 13:/* dir-listing.encode-header */
+ pconf->encode_header = (char)cpv->v.u;
+ break;
+ case 14:/* dir-listing.auto-layout */
+ pconf->auto_layout = (char)cpv->v.u;
+ break;
+ default:/* should not happen */
+ return;
+ }
+}
- return HANDLER_GO_ON;
+static void mod_dirlisting_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_dirlisting_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_dirlisting_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(dir_listing);
- PATCH(external_css);
- PATCH(external_js);
- PATCH(hide_dot_files);
- PATCH(encoding);
- PATCH(show_readme);
- PATCH(hide_readme_file);
- PATCH(show_header);
- PATCH(hide_header_file);
- PATCH(excludes);
- PATCH(set_footer);
- PATCH(encode_readme);
- PATCH(encode_header);
- PATCH(auto_layout);
-
- /* 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(CONFIG_ACTIVATE)) ||
- buffer_is_equal_string(&du->key, CONST_STR_LEN(CONFIG_DIR_LISTING))) {
- PATCH(dir_listing);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN(CONFIG_HIDE_DOTFILES))) {
- PATCH(hide_dot_files);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN(CONFIG_EXTERNAL_CSS))) {
- PATCH(external_css);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN(CONFIG_EXTERNAL_JS))) {
- PATCH(external_js);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN(CONFIG_ENCODING))) {
- PATCH(encoding);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN(CONFIG_SHOW_README))) {
- PATCH(show_readme);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN(CONFIG_HIDE_README_FILE))) {
- PATCH(hide_readme_file);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN(CONFIG_SHOW_HEADER))) {
- PATCH(show_header);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN(CONFIG_HIDE_HEADER_FILE))) {
- PATCH(hide_header_file);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN(CONFIG_SET_FOOTER))) {
- PATCH(set_footer);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN(CONFIG_EXCLUDE))) {
- PATCH(excludes);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN(CONFIG_ENCODE_README))) {
- PATCH(encode_readme);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN(CONFIG_ENCODE_HEADER))) {
- PATCH(encode_header);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN(CONFIG_AUTO_LAYOUT))) {
- PATCH(auto_layout);
- }
- }
- }
+static void mod_dirlisting_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_dirlisting_merge_config(&p->conf, p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
- return 0;
+SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("dir-listing.activate"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("server.dir-listing"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("dir-listing.exclude"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("dir-listing.hide-dot-files"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("dir-listing.external-css"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("dir-listing.external-js"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("dir-listing.encoding"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("dir-listing.show-readme"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("dir-listing.hide-readme-file"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("dir-listing.show-header"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("dir-listing.hide-header-file"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("dir-listing.set-footer"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("dir-listing.encode-readme"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("dir-listing.encode-header"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("dir-listing.auto-layout"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_dirlisting"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* dir-listing.activate */
+ case 1: /* server.dir-listing *//*(historical)*/
+ break;
+ case 2: /* dir-listing.exclude */
+ if (!array_is_vlist(cpv->v.a)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s; "
+ "expected list of \"regex\"", cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ #ifndef HAVE_PCRE_H
+ if (cpv->v.a->used > 0) {
+ log_error_write(srv, __FILE__, __LINE__, "sss",
+ "pcre support is missing for: %s, "
+ "please install libpcre and the headers",
+ cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ #else
+ cpv->v.v = mod_dirlisting_parse_excludes(srv, cpv->v.a);
+ if (NULL == cpv->v.v) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s", cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ cpv->vtype = T_CONFIG_LOCAL;
+ #endif
+ break;
+ case 3: /* dir-listing.hide-dotfiles */
+ case 4: /* dir-listing.external-css */
+ case 5: /* dir-listing.external-js */
+ case 6: /* dir-listing.encoding */
+ case 7: /* dir-listing.show-readme */
+ if (!buffer_string_is_empty(cpv->v.b)) {
+ buffer *b;
+ *(const buffer **)&b = cpv->v.b;
+ if (buffer_is_equal_string(b, CONST_STR_LEN("enable")))
+ buffer_copy_string_len(b, CONST_STR_LEN("README.txt"));
+ else if (buffer_is_equal_string(b,CONST_STR_LEN("disable")))
+ buffer_clear(b);
+ }
+ break;
+ case 8: /* dir-listing.hide-readme-file */
+ break;
+ case 9: /* dir-listing.show-header */
+ if (!buffer_string_is_empty(cpv->v.b)) {
+ buffer *b;
+ *(const buffer **)&b = cpv->v.b;
+ if (buffer_is_equal_string(b, CONST_STR_LEN("enable")))
+ buffer_copy_string_len(b, CONST_STR_LEN("HEADER.txt"));
+ else if (buffer_is_equal_string(b,CONST_STR_LEN("disable")))
+ buffer_clear(b);
+ }
+ break;
+ case 10:/* dir-listing.hide-header-file */
+ case 11:/* dir-listing.set-footer */
+ case 12:/* dir-listing.encode-readme */
+ case 13:/* dir-listing.encode-header */
+ case 14:/* dir-listing.auto-layout */
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+ }
+
+ p->defaults.dir_listing = 0;
+ p->defaults.hide_dot_files = 1;
+ p->defaults.hide_readme_file = 0;
+ p->defaults.hide_header_file = 0;
+ p->defaults.encode_readme = 1;
+ p->defaults.encode_header = 1;
+ p->defaults.auto_layout = 1;
+
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_dirlisting_merge_config(&p->defaults, cpv);
+ }
+
+ return HANDLER_GO_ON;
}
-#undef PATCH
typedef struct {
size_t namelen;
@@ -490,7 +449,7 @@ static int http_list_directory_sizefmt(char *buf, size_t bufsz, off_t size) {
return buflen + 3;
}
-static void http_list_directory_include_file(buffer *out, int symlinks, buffer *path, const char *classname, int encode) {
+static void http_list_directory_include_file(buffer *out, int symlinks, const buffer *path, const char *classname, int encode) {
int fd = fdevent_open_cloexec(path->ptr, symlinks, O_RDONLY, 0);
ssize_t rd;
char buf[8192];
@@ -789,11 +748,11 @@ static void http_list_directory_header(server *srv, connection *con, plugin_data
if (!buffer_string_is_empty(p->conf.show_header)) {
/* if we have a HEADER file, display it in <pre class="header"></pre> */
- buffer *hb = p->conf.show_header;
+ const buffer *hb = p->conf.show_header;
if (hb->ptr[0] != '/') {
- buffer_copy_buffer(p->tmp_buf, con->physical.path);
- buffer_append_path_len(p->tmp_buf, CONST_BUF_LEN(p->conf.show_header));
- hb = p->tmp_buf;
+ hb = &p->tmp_buf;
+ buffer_copy_buffer(&p->tmp_buf, con->physical.path);
+ buffer_append_path_len(&p->tmp_buf, CONST_BUF_LEN(p->conf.show_header));
}
http_list_directory_include_file(out, con->conf.follow_symlink, hb, "header", p->conf.encode_header);
@@ -839,11 +798,11 @@ static void http_list_directory_footer(server *srv, connection *con, plugin_data
if (!buffer_string_is_empty(p->conf.show_readme)) {
/* if we have a README file, display it in <pre class="readme"></pre> */
- buffer *rb = p->conf.show_readme;
+ const buffer *rb = p->conf.show_readme;
if (rb->ptr[0] != '/') {
- buffer_copy_buffer(p->tmp_buf, con->physical.path);
- buffer_append_path_len(p->tmp_buf, CONST_BUF_LEN(p->conf.show_readme));
- rb = p->tmp_buf;
+ rb = &p->tmp_buf;
+ buffer_copy_buffer(&p->tmp_buf, con->physical.path);
+ buffer_append_path_len(&p->tmp_buf, CONST_BUF_LEN(p->conf.show_readme));
}
http_list_directory_include_file(out, con->conf.follow_symlink, rb, "readme", p->conf.encode_readme);
@@ -927,8 +886,8 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
path_file = path + i;
if (NULL == (dp = opendir(path))) {
- log_error_write(srv, __FILE__, __LINE__, "sbs",
- "opendir failed:", dir, strerror(errno));
+ log_error(con->errh, __FILE__, __LINE__,
+ "opendir failed: %s", dir->ptr);
free(path);
return -1;
@@ -944,10 +903,6 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
files.used = 0;
while ((dent = readdir(dp)) != NULL) {
-#ifdef HAVE_PCRE_H
- unsigned short exclude_match = 0;
-#endif
-
if (dent->d_name[0] == '.') {
if (hide_dotfiles)
continue;
@@ -966,41 +921,14 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
continue;
}
+ i = strlen(dent->d_name);
+
/* compare d_name against excludes array
* elements, skipping any that match.
*/
-#ifdef HAVE_PCRE_H
- for(i = 0; i < p->conf.excludes->used; i++) {
- int n;
-#define N 10
- int ovec[N * 3];
- pcre *regex = p->conf.excludes->ptr[i]->regex;
-
- if ((n = pcre_exec(regex, NULL, dent->d_name,
- strlen(dent->d_name), 0, 0, ovec, 3 * N)) < 0) {
- if (n != PCRE_ERROR_NOMATCH) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "execution error while matching:", n);
-
- /* aborting would require a lot of manual cleanup here.
- * skip instead (to not leak names that break pcre matching)
- */
- exclude_match = 1;
- break;
- }
- }
- else {
- exclude_match = 1;
- break;
- }
- }
-
- if (exclude_match) {
+ if (p->conf.excludes
+ && mod_dirlisting_exclude(srv, p->conf.excludes, dent->d_name, i))
continue;
- }
-#endif
-
- i = strlen(dent->d_name);
/* NOTE: the manual says, d_name is never more than NAME_MAX
* so this should actually not be a buffer-overflow-risk
@@ -1122,9 +1050,9 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
if (buffer_string_is_empty(p->conf.encoding)) {
http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
} else {
- buffer_copy_string_len(p->content_charset, CONST_STR_LEN("text/html; charset="));
- buffer_append_string_buffer(p->content_charset, p->conf.encoding);
- http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->content_charset));
+ buffer_copy_string_len(&p->tmp_buf, CONST_STR_LEN("text/html; charset="));
+ buffer_append_string_buffer(&p->tmp_buf, p->conf.encoding);
+ http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(&p->tmp_buf));
}
chunkqueue_append_buffer_commit(con->write_queue);
@@ -1156,7 +1084,7 @@ URIHANDLER_FUNC(mod_dirlisting_subrequest) {
if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
if (con->uri.path->ptr[buffer_string_length(con->uri.path) - 1] != '/') return HANDLER_GO_ON;
- mod_dirlisting_patch_connection(srv, con, p);
+ mod_dirlisting_patch_config(con, p);
if (!p->conf.dir_listing) return HANDLER_GO_ON;
@@ -1183,19 +1111,16 @@ URIHANDLER_FUNC(mod_dirlisting_subrequest) {
return HANDLER_FINISHED;
}
-/* this function is called at dlopen() time and inits the callbacks */
int mod_dirlisting_plugin_init(plugin *p);
int mod_dirlisting_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("dirlisting");
+ p->name = "dirlisting";
p->init = mod_dirlisting_init;
p->handle_subrequest_start = mod_dirlisting_subrequest;
p->set_defaults = mod_dirlisting_set_defaults;
p->cleanup = mod_dirlisting_free;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_evasive.c b/src/mod_evasive.c
index 93e86c2c..0c3847b3 100644
--- a/src/mod_evasive.c
+++ b/src/mod_evasive.c
@@ -27,131 +27,98 @@
*/
typedef struct {
- unsigned short max_conns;
- unsigned short silent;
- buffer *location;
+ unsigned short max_conns;
+ unsigned short silent;
+ const buffer *location;
} plugin_config;
typedef struct {
- PLUGIN_DATA;
-
- plugin_config **config_storage;
-
- plugin_config conf;
+ PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
} plugin_data;
INIT_FUNC(mod_evasive_init) {
- plugin_data *p;
-
- p = calloc(1, sizeof(*p));
-
- return p;
+ return calloc(1, sizeof(plugin_data));
}
FREE_FUNC(mod_evasive_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- 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 (NULL == s) continue;
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+ UNUSED(srv);
- buffer_free(s->location);
+ free(p->cvlist);
+ free(p);
- free(s);
- }
- free(p->config_storage);
- }
-
- free(p);
-
- return HANDLER_GO_ON;
+ return HANDLER_GO_ON;
}
-SETDEFAULTS_FUNC(mod_evasive_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { "evasive.max-conns-per-ip", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { "evasive.silent", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { "evasive.location", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->max_conns = 0;
- s->silent = 0;
- s->location = buffer_init();
-
- cv[0].destination = &(s->max_conns);
- cv[1].destination = &(s->silent);
- cv[2].destination = s->location;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
- }
+static void mod_evasive_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* evasive.max-conns-per-ip */
+ pconf->max_conns = cpv->v.shrt;
+ break;
+ case 1: /* evasive.silent */
+ pconf->silent = cpv->v.u;
+ break;
+ case 2: /* evasive.location */
+ pconf->location = cpv->v.b;
+ break;
+ default:/* should not happen */
+ return;
+ }
+}
- return HANDLER_GO_ON;
+static void mod_evasive_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_evasive_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_evasive_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(max_conns);
- PATCH(silent);
- PATCH(location);
-
- /* 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("evasive.max-conns-per-ip"))) {
- PATCH(max_conns);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("evasive.silent"))) {
- PATCH(silent);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("evasive.location"))) {
- PATCH(location);
- }
- }
- }
+static void mod_evasive_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_evasive_merge_config(&p->conf,p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
- return 0;
+SETDEFAULTS_FUNC(mod_evasive_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("evasive.max-conns-per-ip"),
+ T_CONFIG_SHORT,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("evasive.silent"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("evasive.location"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_evasive"))
+ return HANDLER_ERROR;
+
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_evasive_merge_config(&p->defaults, cpv);
+ }
+
+ return HANDLER_GO_ON;
}
-#undef PATCH
URIHANDLER_FUNC(mod_evasive_uri_handler) {
plugin_data *p = p_d;
if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
- mod_evasive_patch_connection(srv, con, p);
+ mod_evasive_patch_config(con, p);
/* no limit set, nothing to block */
if (p->conf.max_conns == 0) return HANDLER_GO_ON;
@@ -193,14 +160,12 @@ URIHANDLER_FUNC(mod_evasive_uri_handler) {
int mod_evasive_plugin_init(plugin *p);
int mod_evasive_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("evasive");
+ p->name = "evasive";
p->init = mod_evasive_init;
p->set_defaults = mod_evasive_set_defaults;
p->handle_uri_clean = mod_evasive_uri_handler;
p->cleanup = mod_evasive_free;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_evhost.c b/src/mod_evhost.c
index 4217ee02..e6facc19 100644
--- a/src/mod_evhost.c
+++ b/src/mod_evhost.c
@@ -9,179 +9,215 @@
#include <string.h>
#include <errno.h>
-typedef struct {
- /* unparsed pieces */
- buffer *path_pieces_raw;
+/**
+ *
+ * #
+ * # define a pattern for the host url finding
+ * # %% => % sign
+ * # %0 => domain name + tld
+ * # %1 => tld
+ * # %2 => domain name without tld
+ * # %3 => subdomain 1 name
+ * # %4 => subdomain 2 name
+ * # %_ => fqdn (without port info)
+ * #
+ * evhost.path-pattern = "/home/ckruse/dev/www/%3/htdocs/"
+ *
+ */
- /* pieces for path creation */
- size_t len;
- buffer **path_pieces;
+typedef struct {
+ /* pieces for path creation */
+ const buffer *path_pieces;
} plugin_config;
typedef struct {
- PLUGIN_DATA;
- plugin_config **config_storage;
- plugin_config conf;
- buffer *tmp_buf;
- array *split_vals;
+ PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
+
+ buffer tmp_buf;
+ array split_vals;
} plugin_data;
INIT_FUNC(mod_evhost_init) {
- plugin_data *p;
-
- p = calloc(1, sizeof(*p));
+ return calloc(1, sizeof(plugin_data));
+}
- p->tmp_buf = buffer_init();
- p->split_vals = array_init();
+static void mod_evhost_free_path_pieces(const buffer *path_pieces) {
+ buffer *b;
+ *(const buffer **)&b = path_pieces;
+ for (; path_pieces->ptr; ++path_pieces) free(path_pieces->ptr);
+ free(b);
+}
- return p;
+static void mod_evhost_free_config(plugin_data * const p) {
+ if (NULL == p->cvlist) return;
+ /* (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ if (cpv->vtype != T_CONFIG_LOCAL || NULL == cpv->v.v) continue;
+ switch (cpv->k_id) {
+ case 0: /* evhost.path-pattern */
+ mod_evhost_free_path_pieces(cpv->v.v);
+ break;
+ default:
+ break;
+ }
+ }
+ }
}
FREE_FUNC(mod_evhost_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+ UNUSED(srv);
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
+ mod_evhost_free_config(p);
- if (NULL == s) continue;
+ free(p->tmp_buf.ptr);
+ array_free_data(&p->split_vals);
- if(s->path_pieces) {
- size_t j;
- for (j = 0; j < s->len; j++) {
- buffer_free(s->path_pieces[j]);
- }
-
- free(s->path_pieces);
- }
+ free(p->cvlist);
+ free(p);
- buffer_free(s->path_pieces_raw);
-
- free(s);
- }
- free(p->config_storage);
- }
-
- buffer_free(p->tmp_buf);
- array_free(p->split_vals);
-
- free(p);
-
- return HANDLER_GO_ON;
+ return HANDLER_GO_ON;
}
-static int mod_evhost_parse_pattern(plugin_config *s) {
- char *ptr = s->path_pieces_raw->ptr,*pos;
+__attribute_cold__
+static buffer * mod_evhost_parse_pattern_err(buffer *bptr) {
+ mod_evhost_free_path_pieces(bptr);
+ return NULL;
+}
- s->path_pieces = NULL;
+static buffer * mod_evhost_parse_pattern(const char *ptr) {
+ uint32_t used = 0;
+ const uint32_t sz = 127;
+ const char *pos;
+ buffer bptr[sz+1]; /* (128 elements takes 2k on stack in 64-bit) */
+ memset(bptr, 0, sizeof(bptr));
for(pos=ptr;*ptr;ptr++) {
if(*ptr == '%') {
size_t len;
- s->path_pieces = realloc(s->path_pieces,(s->len+2) * sizeof(*s->path_pieces));
- s->path_pieces[s->len] = buffer_init();
- s->path_pieces[s->len+1] = buffer_init();
+ if (used >= sz-1) /* (should not happen) */
+ return mod_evhost_parse_pattern_err(bptr);
/* "%%" "%_" "%x" "%{x.y}" where x and y are *single digit* 0 - 9 */
if (ptr[1] == '%' || ptr[1] == '_' || light_isdigit(ptr[1])) {
len = 2;
} else if (ptr[1] == '{') {
- if (!light_isdigit(ptr[2])) return -1;
+ if (!light_isdigit(ptr[2]))
+ return mod_evhost_parse_pattern_err(bptr);
if (ptr[3] == '.') {
- if (!light_isdigit(ptr[4])) return -1;
- if (ptr[5] != '}') return -1;
+ if (!light_isdigit(ptr[4]))
+ return mod_evhost_parse_pattern_err(bptr);
+ if (ptr[5] != '}')
+ return mod_evhost_parse_pattern_err(bptr);
len = 6;
} else if (ptr[3] == '}') {
len = 4;
} else {
- return -1;
+ return mod_evhost_parse_pattern_err(bptr);
}
} else {
- return -1;
+ return mod_evhost_parse_pattern_err(bptr);
}
- buffer_copy_string_len(s->path_pieces[s->len],pos,ptr-pos);
+ buffer_copy_string_len(bptr+used, pos, ptr-pos);
pos = ptr + len;
- buffer_copy_string_len(s->path_pieces[s->len+1],ptr,len);
+ buffer_copy_string_len(bptr+used+1, ptr, len);
ptr += len - 1; /*(ptr++ in for() loop)*/
- s->len += 2;
+ used += 2;
}
}
if(*pos != '\0') {
- s->path_pieces = realloc(s->path_pieces,(s->len+1) * sizeof(*s->path_pieces));
- s->path_pieces[s->len] = buffer_init();
-
- buffer_copy_string_len(s->path_pieces[s->len],pos,ptr-pos);
-
- s->len += 1;
+ if (used >= sz) /* (should not happen) */
+ return mod_evhost_parse_pattern_err(bptr);
+ buffer_copy_string_len(bptr+used, pos, ptr-pos);
+ ++used;
}
- return 0;
+ buffer * const path_pieces =
+ malloc(sizeof(bptr) + ((used+1) * sizeof(buffer)));
+ force_assert(path_pieces);
+ return memcpy(path_pieces, bptr, (used+1) * sizeof(buffer));
}
-SETDEFAULTS_FUNC(mod_evhost_set_defaults) {
- plugin_data *p = p_d;
- size_t i;
-
- /**
- *
- * #
- * # define a pattern for the host url finding
- * # %% => % sign
- * # %0 => domain name + tld
- * # %1 => tld
- * # %2 => domain name without tld
- * # %3 => subdomain 1 name
- * # %4 => subdomain 2 name
- * # %_ => fqdn (without port info)
- * #
- * evhost.path-pattern = "/home/ckruse/dev/www/%3/htdocs/"
- *
- */
-
- config_values_t cv[] = {
- { "evhost.path-pattern", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->path_pieces_raw = buffer_init();
- s->path_pieces = NULL;
- s->len = 0;
-
- cv[0].destination = s->path_pieces_raw;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
+static void mod_evhost_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* evhost.path-pattern */
+ if (cpv->vtype == T_CONFIG_LOCAL)
+ pconf->path_pieces = cpv->v.v;
+ break;
+ default:/* should not happen */
+ return;
+ }
+}
- if (!buffer_string_is_empty(s->path_pieces_raw)) {
- if (0 != mod_evhost_parse_pattern(s)) {
- log_error_write(srv, __FILE__, __LINE__, "sb", "invalid evhost.path-pattern:", s->path_pieces_raw);
- return HANDLER_ERROR;
- }
- }
- }
+static void mod_evhost_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_evhost_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- return HANDLER_GO_ON;
+static void mod_evhost_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_evhost_merge_config(&p->conf, p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
+
+SETDEFAULTS_FUNC(mod_evhost_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("evhost.path-pattern"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_evhost"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* evhost.path-pattern */
+ if (!buffer_string_is_empty(cpv->v.b)) {
+ const char * const ptr = cpv->v.b->ptr;
+ cpv->v.v = mod_evhost_parse_pattern(ptr);
+ if (NULL == cpv->v.v) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "invalid evhost.path-pattern: %s", ptr);
+ return HANDLER_ERROR;
+ }
+ cpv->vtype = T_CONFIG_LOCAL;
+ }
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+ }
+
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_evhost_merge_config(&p->defaults, cpv);
+ }
+
+ return HANDLER_GO_ON;
}
/**
@@ -252,46 +288,12 @@ static void mod_evhost_parse_host(buffer *key, array *host, buffer *authority) {
}
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_evhost_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(path_pieces);
- PATCH(len);
-
- /* 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("evhost.path-pattern"))) {
- PATCH(path_pieces);
- PATCH(len);
- }
- }
- }
-
- return 0;
-}
-#undef PATCH
-
-
-static void mod_evhost_build_doc_root_path(buffer *b, array *parsed_host, buffer *authority, buffer **path_pieces, const size_t npieces) {
+static void mod_evhost_build_doc_root_path(buffer *b, array *parsed_host, buffer *authority, const buffer *path_pieces) {
array_reset_data_strings(parsed_host);
mod_evhost_parse_host(b, parsed_host, authority);
buffer_clear(b);
- for (size_t i = 0; i < npieces; ++i) {
- const char *ptr = path_pieces[i]->ptr;
+ for (const char *ptr; (ptr = path_pieces->ptr); ++path_pieces) {
if (*ptr == '%') {
const data_string *ds;
@@ -322,13 +324,13 @@ static void mod_evhost_build_doc_root_path(buffer *b, array *parsed_host, buffer
} else {
/* unhandled %-sequence */
}
- } else if (NULL != (ds = (data_string *)array_get_element_klen(parsed_host, CONST_BUF_LEN(path_pieces[i])))) {
+ } else if (NULL != (ds = (data_string *)array_get_element_klen(parsed_host, CONST_BUF_LEN(path_pieces)))) {
buffer_append_string_buffer(b, &ds->value);
} else {
/* unhandled %-sequence */
}
} else {
- buffer_append_string_buffer(b, path_pieces[i]);
+ buffer_append_string_buffer(b, path_pieces);
}
}
@@ -342,21 +344,20 @@ static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d)
/* not authority set */
if (buffer_string_is_empty(con->uri.authority)) return HANDLER_GO_ON;
- mod_evhost_patch_connection(srv, con, p);
+ mod_evhost_patch_config(con, p);
/* missing even default(global) conf */
- if (0 == p->conf.len) {
- return HANDLER_GO_ON;
- }
+ if (NULL == p->conf.path_pieces) return HANDLER_GO_ON;
- mod_evhost_build_doc_root_path(p->tmp_buf, p->split_vals, con->uri.authority, p->conf.path_pieces, p->conf.len);
+ buffer * const b = &p->tmp_buf;
+ mod_evhost_build_doc_root_path(b, &p->split_vals, con->uri.authority, p->conf.path_pieces);
- 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);
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, b, &sce)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), b);
} else if(!S_ISDIR(sce->st.st_mode)) {
- log_error_write(srv, __FILE__, __LINE__, "sb", "not a directory:", p->tmp_buf);
+ log_error_write(srv, __FILE__, __LINE__, "sb", "not a directory:", b);
} else {
- buffer_copy_buffer(con->physical.doc_root, p->tmp_buf);
+ buffer_copy_buffer(con->physical.doc_root, b);
}
return HANDLER_GO_ON;
@@ -365,15 +366,11 @@ static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d)
int mod_evhost_plugin_init(plugin *p);
int mod_evhost_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("evhost");
+ p->name = "evhost";
p->init = mod_evhost_init;
p->set_defaults = mod_evhost_set_defaults;
p->handle_docroot = mod_evhost_uri_handler;
p->cleanup = mod_evhost_free;
- p->data = NULL;
-
return 0;
}
-
-/* eof */
diff --git a/src/mod_expire.c b/src/mod_expire.c
index 5f494f17..4bc34c45 100644
--- a/src/mod_expire.c
+++ b/src/mod_expire.c
@@ -1,8 +1,9 @@
#include "first.h"
#include "base.h"
-#include "log.h"
+#include "array.h"
#include "buffer.h"
+#include "log.h"
#include "http_header.h"
#include "plugin.h"
@@ -13,70 +14,33 @@
#include <time.h>
/**
- * this is a expire module for a lighttpd
- *
- * set 'Expires:' HTTP Headers on demand
+ * set HTTP headers Cache-Control and Expires
*/
-
-
-/* plugin config for all request/connections */
-
typedef struct {
- array *expire_url;
- array *expire_mimetypes;
+ const array *expire_url;
+ const array *expire_mimetypes;
} plugin_config;
typedef struct {
- PLUGIN_DATA;
-
- buffer *expire_tstmp;
-
- plugin_config **config_storage;
-
- plugin_config conf;
+ PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
} plugin_data;
-/* init the plugin data */
INIT_FUNC(mod_expire_init) {
- plugin_data *p;
-
- p = calloc(1, sizeof(*p));
-
- p->expire_tstmp = buffer_init();
-
- buffer_string_prepare_copy(p->expire_tstmp, 255);
-
- return p;
+ return calloc(1, sizeof(plugin_data));
}
-/* detroy the plugin data */
FREE_FUNC(mod_expire_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- buffer_free(p->expire_tstmp);
-
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+ UNUSED(srv);
- if (NULL == s) continue;
+ free(p->cvlist);
+ free(p);
- array_free(s->expire_url);
- array_free(s->expire_mimetypes);
- free(s);
- }
- free(p->config_storage);
- }
-
- free(p);
-
- return HANDLER_GO_ON;
+ return HANDLER_GO_ON;
}
static int mod_expire_get_offset(server *srv, plugin_data *p, const buffer *expire, time_t *offset) {
@@ -211,118 +175,116 @@ static int mod_expire_get_offset(server *srv, plugin_data *p, const buffer *expi
return type;
}
-
-/* handle plugin config and check values */
-
-SETDEFAULTS_FUNC(mod_expire_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0, k;
-
- config_values_t cv[] = {
- { "expire.url", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { "expire.mimetypes", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->expire_url = array_init();
- s->expire_mimetypes = array_init();
-
- cv[0].destination = s->expire_url;
- cv[1].destination = s->expire_mimetypes;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
-
- if (!array_is_kvstring(s->expire_url)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected value for expire.url; expected list of \"urlpath\" => \"expiration\"");
- return HANDLER_ERROR;
- }
-
- for (k = 0; k < s->expire_url->used; k++) {
- data_string *ds = (data_string *)s->expire_url->data[k];
-
- /* parse lines */
- if (-1 == mod_expire_get_offset(srv, p, &ds->value, NULL)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "parsing expire.url failed:", &ds->value);
- return HANDLER_ERROR;
- }
- }
-
- if (!array_is_kvstring(s->expire_mimetypes)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected value for expire.mimetypes; expected list of \"mimetype\" => \"expiration\"");
- return HANDLER_ERROR;
- }
-
- for (k = 0; k < s->expire_mimetypes->used; k++) {
- data_string *ds = (data_string *)s->expire_mimetypes->data[k];
- size_t klen = buffer_string_length(&ds->key);
-
- /*(omit trailing '*', if present, from prefix match)*/
- /*(not usually a good idea to modify array keys
- * since doing so might break array_get_element_klen() search,
- * but array use in this module only walks array)*/
- if (klen && ds->key.ptr[klen-1] == '*') buffer_string_set_length(&ds->key, klen-1);
-
- /* parse lines */
- if (-1 == mod_expire_get_offset(srv, p, &ds->value, NULL)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "parsing expire.mimetypes failed:", &ds->value);
- return HANDLER_ERROR;
- }
- }
- }
-
-
- return HANDLER_GO_ON;
+static void mod_expire_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* expire.url */
+ pconf->expire_url = cpv->v.a;
+ break;
+ case 1: /* expire.mimetypes */
+ pconf->expire_mimetypes = cpv->v.a;
+ break;
+ default:/* should not happen */
+ return;
+ }
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_expire_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(expire_url);
- PATCH(expire_mimetypes);
-
- /* 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];
+static void mod_expire_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_expire_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- if (buffer_is_equal_string(&du->key, CONST_STR_LEN("expire.url"))) {
- PATCH(expire_url);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("expire.mimetypes"))) {
- PATCH(expire_mimetypes);
- }
- }
- }
+static void mod_expire_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_expire_merge_config(&p->conf, p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
- return 0;
+SETDEFAULTS_FUNC(mod_expire_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("expire.url"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("expire.mimetypes"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_expire"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* expire.url */
+ if (!array_is_kvstring(cpv->v.a)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s; "
+ "expected list of \"urlpath\" => \"expiration\"",
+ cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ for (uint32_t k = 0; k < cpv->v.a->used; ++k) {
+ /* parse lines */
+ data_string *ds = (data_string *)cpv->v.a->data[k];
+ if (-1 == mod_expire_get_offset(srv, p, &ds->value, NULL)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "parsing expire.url failed: %s", ds->value.ptr);
+ return HANDLER_ERROR;
+ }
+ }
+ break;
+ case 1: /* expire.mimetypes */
+ if (!array_is_kvstring(cpv->v.a)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s; "
+ "expected list of \"mimetype\" => \"expiration\"",
+ cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ for (uint32_t k = 0; k < cpv->v.a->used; ++k) {
+ data_string *ds = (data_string *)cpv->v.a->data[k];
+
+ /*(omit trailing '*', if present, from prefix match)*/
+ /*(not usually a good idea to modify array keys
+ * since doing so might break array_get_element_klen()
+ * search, but array use in this module only walks array)*/
+ size_t klen = buffer_string_length(&ds->key);
+ if (klen && ds->key.ptr[klen-1] == '*')
+ buffer_string_set_length(&ds->key, klen-1);
+
+ /* parse lines */
+ if (-1 == mod_expire_get_offset(srv, p, &ds->value, NULL)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "parsing expire.mimetypes failed: %s", ds->value.ptr);
+ return HANDLER_ERROR;
+ }
+ }
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+ }
+
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_expire_merge_config(&p->defaults, cpv);
+ }
+
+ return HANDLER_GO_ON;
}
-#undef PATCH
CONNECTION_FUNC(mod_expire_handler) {
plugin_data *p = p_d;
@@ -340,15 +302,18 @@ CONNECTION_FUNC(mod_expire_handler) {
if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
- mod_expire_patch_connection(srv, con, p);
+ mod_expire_patch_config(con, p);
/* check expire.url */
- ds = (const data_string *)array_match_key_prefix(p->conf.expire_url, con->uri.path);
+ ds = p->conf.expire_url
+ ? (const data_string *)array_match_key_prefix(p->conf.expire_url, con->uri.path)
+ : NULL;
if (NULL != ds) {
vb = &ds->value;
}
else {
/* check expire.mimetypes (if no match with expire.url) */
+ if (NULL == p->conf.expire_mimetypes) return HANDLER_GO_ON;
vb = http_header_response_get(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"));
ds = (NULL != vb)
? (const data_string *)array_match_key_prefix(p->conf.expire_mimetypes, vb)
@@ -387,17 +352,18 @@ CONNECTION_FUNC(mod_expire_handler) {
/* expires should be at least srv->cur_ts */
if (expires < srv->cur_ts) expires = srv->cur_ts;
- buffer_clear(p->expire_tstmp);
- buffer_append_strftime(p->expire_tstmp, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(expires)));
+ buffer * const b = srv->tmp_buf;
/* HTTP/1.0 */
- http_header_response_set(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Expires"), CONST_BUF_LEN(p->expire_tstmp));
+ buffer_clear(b);
+ buffer_append_strftime(b, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(expires)));
+ http_header_response_set(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Expires"), CONST_BUF_LEN(b));
/* HTTP/1.1 */
- buffer_copy_string_len(p->expire_tstmp, CONST_STR_LEN("max-age="));
- buffer_append_int(p->expire_tstmp, expires - srv->cur_ts); /* as expires >= srv->cur_ts the difference is >= 0 */
+ buffer_copy_string_len(b, CONST_STR_LEN("max-age="));
+ buffer_append_int(b, expires - srv->cur_ts); /* as expires >= srv->cur_ts the difference is >= 0 */
- http_header_response_set(con, HTTP_HEADER_CACHE_CONTROL, CONST_STR_LEN("Cache-Control"), CONST_BUF_LEN(p->expire_tstmp));
+ http_header_response_set(con, HTTP_HEADER_CACHE_CONTROL, CONST_STR_LEN("Cache-Control"), CONST_BUF_LEN(b));
return HANDLER_GO_ON;
}
@@ -406,19 +372,16 @@ CONNECTION_FUNC(mod_expire_handler) {
return HANDLER_GO_ON;
}
-/* this function is called at dlopen() time and inits the callbacks */
int mod_expire_plugin_init(plugin *p);
int mod_expire_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("expire");
+ p->name = "expire";
p->init = mod_expire_init;
p->handle_response_start = mod_expire_handler;
p->set_defaults = mod_expire_set_defaults;
p->cleanup = mod_expire_free;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_extforward.c b/src/mod_extforward.c
index 2668b005..c3700136 100644
--- a/src/mod_extforward.c
+++ b/src/mod_extforward.c
@@ -64,8 +64,6 @@
*/
-/* plugin config for all request/connections */
-
typedef enum {
PROXY_FORWARDED_NONE = 0x00,
PROXY_FORWARDED_FOR = 0x01,
@@ -80,29 +78,33 @@ struct sock_addr_mask {
int bits;
};
-struct sock_addr_masks {
- struct sock_addr_mask *addrs;
- size_t used;
- size_t sz;
+struct forwarder_cfg {
+ const array *forwarder;
+ int forward_all;
+ uint32_t addrs_used;
+ #if defined(__STDC_VERSION__) && __STDC_VERSION__-0 >= 199901L /* C99 */
+ struct sock_addr_mask addrs[];
+ #else
+ struct sock_addr_mask addrs[1];
+ #endif
};
typedef struct {
- array *forwarder;
- struct sock_addr_masks *forward_masks;
- array *headers;
- array *opts_params;
- unsigned int opts;
- unsigned short int hap_PROXY;
- unsigned short int hap_PROXY_ssl_client_verify;
- short int forward_all;
+ const array *forwarder;
+ int forward_all;
+ uint32_t forward_masks_used;
+ const struct sock_addr_mask *forward_masks;
+ const array *headers;
+ unsigned int opts;
+ char hap_PROXY;
+ char hap_PROXY_ssl_client_verify;
} plugin_config;
typedef struct {
- PLUGIN_DATA;
-
- plugin_config **config_storage;
-
- plugin_config conf;
+ PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
+ array *default_headers;
} plugin_data;
static plugin_data *mod_extforward_plugin_data_singleton;
@@ -128,6 +130,7 @@ typedef struct {
static handler_ctx * handler_ctx_init(void) {
handler_ctx * hctx;
hctx = calloc(1, sizeof(*hctx));
+ force_assert(hctx);
return hctx;
}
@@ -135,287 +138,341 @@ static void handler_ctx_free(handler_ctx *hctx) {
free(hctx);
}
-/* init the plugin data */
INIT_FUNC(mod_extforward_init) {
- plugin_data *p;
- p = calloc(1, sizeof(*p));
- mod_extforward_plugin_data_singleton = p;
- return p;
+ return calloc(1, sizeof(plugin_data));
+}
+
+static void mod_extforward_free_config(plugin_data * const p) {
+ if (NULL == p->cvlist) return;
+ /* (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* extforward.forwarder */
+ if (cpv->vtype == T_CONFIG_LOCAL) free(cpv->v.v);
+ break;
+ default:
+ break;
+ }
+ }
+ }
}
-/* destroy the plugin data */
FREE_FUNC(mod_extforward_free) {
- plugin_data *p = p_d;
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+ UNUSED(srv);
- UNUSED(srv);
+ mod_extforward_free_config(p);
+ array_free(p->default_headers);
- if (!p) return HANDLER_GO_ON;
+ free(p->cvlist);
+ free(p);
- if (p->config_storage) {
- size_t i;
+ return HANDLER_GO_ON;
+}
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
+static void mod_extforward_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* extforward.forwarder */
+ if (cpv->vtype == T_CONFIG_LOCAL) {
+ const struct forwarder_cfg * const fwd = cpv->v.v;
+ pconf->forwarder = fwd->forwarder;
+ pconf->forward_all = fwd->forward_all;
+ pconf->forward_masks_used = fwd->addrs_used;
+ pconf->forward_masks = fwd->addrs;
+ }
+ break;
+ case 1: /* extforward.headers */
+ pconf->headers = cpv->v.a;
+ break;
+ case 2: /* extforward.params */
+ if (cpv->vtype == T_CONFIG_LOCAL)
+ pconf->opts = cpv->v.u;
+ break;
+ case 3: /* extforward.hap-PROXY */
+ pconf->hap_PROXY = (char)cpv->v.u;
+ break;
+ case 4: /* extforward.hap-PROXY-ssl-client-verify */
+ pconf->hap_PROXY_ssl_client_verify = (char)cpv->v.u;
+ break;
+ default:/* should not happen */
+ return;
+ }
+}
- if (NULL == s) continue;
+static void mod_extforward_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_extforward_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- array_free(s->forwarder);
- array_free(s->headers);
- array_free(s->opts_params);
+static void mod_extforward_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_extforward_merge_config(&p->conf, p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
- if (s->forward_masks) {
- free(s->forward_masks->addrs);
- free(s->forward_masks);
- }
+static void * mod_extforward_parse_forwarder(server *srv, const array *forwarder) {
+ const data_string * const allds = (const data_string *)
+ array_get_element_klen(forwarder, CONST_STR_LEN("all"));
+ const int forward_all = (NULL == allds)
+ ? 0
+ : buffer_eq_icase_slen(&allds->value, CONST_STR_LEN("trust")) ? 1 : -1;
+ uint32_t nmasks = 0;
+ for (uint32_t j = 0; j < forwarder->used; ++j) {
+ data_string * const ds = (data_string *)forwarder->data[j];
+ char * const nm_slash = strchr(ds->key.ptr, '/');
+ if (NULL != nm_slash) ++nmasks;
+ if (!buffer_eq_icase_slen(&ds->value, CONST_STR_LEN("trust"))) {
+ if (!buffer_eq_icase_slen(&ds->value, CONST_STR_LEN("untrusted")))
+ log_error(srv->errh, __FILE__, __LINE__,
+ "ERROR: expect \"trust\", not \"%s\" => \"%s\"; "
+ "treating as untrusted", ds->key.ptr, ds->value.ptr);
+ if (NULL != nm_slash) {
+ /* future: consider adding member next to bits in sock_addr_mask
+ * with bool trusted/untrusted member */
+ --nmasks;
+ log_error(srv->errh, __FILE__, __LINE__,
+ "ERROR: untrusted CIDR masks are ignored (\"%s\" => \"%s\")",
+ ds->key.ptr, ds->value.ptr);
+ }
+ buffer_clear(&ds->value); /* empty is untrusted */
+ continue;
+ }
+ }
- free(s);
- }
- free(p->config_storage);
- }
+ struct forwarder_cfg * const fwd =
+ malloc(sizeof(struct forwarder_cfg)+sizeof(struct sock_addr_mask)*nmasks);
+ force_assert(fwd);
+ memset(fwd, 0,
+ sizeof(struct forwarder_cfg) + sizeof(struct sock_addr_mask)*nmasks);
+ fwd->forwarder = forwarder;
+ fwd->forward_all = forward_all;
+ fwd->addrs_used = 0;
+ for (uint32_t j = 0; j < forwarder->used; ++j) {
+ data_string * const ds = (data_string *)forwarder->data[j];
+ char * const nm_slash = strchr(ds->key.ptr, '/');
+ if (NULL == nm_slash) continue;
+ if (buffer_string_is_empty(&ds->value)) continue; /* ignored */
+
+ char *err;
+ const int nm_bits = strtol(nm_slash + 1, &err, 10);
+ int rc;
+ if (*err || nm_bits <= 0) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "ERROR: invalid netmask: %s %s", ds->key.ptr, err);
+ free(fwd);
+ return NULL;
+ }
+ struct sock_addr_mask * const sm = fwd->addrs + fwd->addrs_used++;
+ sm->bits = nm_bits;
+ *nm_slash = '\0';
+ rc = sock_addr_from_str_numeric(srv, &sm->addr, ds->key.ptr);
+ *nm_slash = '/';
+ if (1 != rc) {
+ free(fwd);
+ return NULL;
+ }
+ buffer_clear(&ds->value);
+ /* empty is untrusted,
+ * e.g. if subnet (incorrectly) appears in X-Forwarded-For */
+ }
+ return fwd;
+}
- free(p);
+static unsigned int mod_extforward_parse_opts(server *srv, const array *opts_params) {
+ unsigned int opts = 0;
+ for (uint32_t j = 0, used = opts_params->used; j < used; ++j) {
+ proxy_forwarded_t param;
+ data_unset *du = opts_params->data[j];
+ #if 0 /*("for" and "proto" historical behavior: always enabled)*/
+ if (buffer_eq_slen(&du->key, CONST_STR_LEN("by")))
+ param = PROXY_FORWARDED_BY;
+ else if (buffer_eq_slen(&du->key, CONST_STR_LEN("for")))
+ param = PROXY_FORWARDED_FOR;
+ else
+ #endif
+ if (buffer_eq_slen(&du->key, CONST_STR_LEN("host")))
+ param = PROXY_FORWARDED_HOST;
+ #if 0
+ else if (buffer_eq_slen(&du->key, CONST_STR_LEN("proto")))
+ param = PROXY_FORWARDED_PROTO;
+ #endif
+ else if (buffer_eq_slen(&du->key, CONST_STR_LEN("remote_user")))
+ param = PROXY_FORWARDED_REMOTE_USER;
+ else {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "extforward.params keys must be one of: "
+ "host, remote_user, but not: %s", du->key.ptr);
+ return HANDLER_ERROR;
+ }
- return HANDLER_GO_ON;
+ if (du->type == TYPE_STRING) {
+ data_string *ds = (data_string *)du;
+ if (buffer_eq_slen(&ds->value, CONST_STR_LEN("enable"))) {
+ opts |= param;
+ }
+ else if (!buffer_eq_slen(&ds->value, CONST_STR_LEN("disable"))) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "extforward.params values must be one of: "
+ "0, 1, enable, disable; error for key: %s", du->key.ptr);
+ return UINT_MAX;
+ }
+ }
+ else if (du->type == TYPE_INTEGER) {
+ data_integer *di = (data_integer *)du;
+ if (di->value) opts |= param;
+ }
+ else {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "extforward.params values must be one of: "
+ "0, 1, enable, disable; error for key: %s", du->key.ptr);
+ return UINT_MAX;
+ }
+ }
+ return opts;
}
-/* handle plugin config and check values */
-
SETDEFAULTS_FUNC(mod_extforward_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { "extforward.forwarder", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { "extforward.headers", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { "extforward.params", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
- { "extforward.hap-PROXY", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
- { "extforward.hap-PROXY-ssl-client-verify", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->forwarder = array_init();
- s->headers = array_init();
- s->opts_params = array_init();
- s->opts = PROXY_FORWARDED_NONE;
-
- cv[0].destination = s->forwarder;
- cv[1].destination = s->headers;
- cv[2].destination = s->opts_params;
- cv[3].destination = &s->hap_PROXY;
- cv[4].destination = &s->hap_PROXY_ssl_client_verify;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
-
- if (!array_is_kvstring(s->forwarder)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected value for extforward.forwarder; expected list of \"IPaddr\" => \"trust\"");
- return HANDLER_ERROR;
- }
-
- if (array_get_element_klen(config->value, CONST_STR_LEN("extforward.forwarder"))) {
- const data_string * const allds = (const data_string *)array_get_element_klen(s->forwarder, CONST_STR_LEN("all"));
- s->forward_all = (NULL == allds) ? 0 : buffer_eq_icase_slen(&allds->value, CONST_STR_LEN("trust")) ? 1 : -1;
- for (size_t j = 0; j < s->forwarder->used; ++j) {
- data_string * const ds = (data_string *)s->forwarder->data[j];
- char * const nm_slash = strchr(ds->key.ptr, '/');
- if (!buffer_eq_icase_slen(&ds->value, CONST_STR_LEN("trust"))) {
- if (!buffer_eq_icase_slen(&ds->value, CONST_STR_LEN("untrusted"))) {
- log_error_write(srv, __FILE__, __LINE__, "sbsbs", "ERROR: expect \"trust\", not \"", &ds->key, "\" => \"", &ds->value, "\"; treating as untrusted");
- }
- if (NULL != nm_slash) {
- log_error_write(srv, __FILE__, __LINE__, "sbsbs", "ERROR: untrusted CIDR masks are ignored (\"", &ds->key, "\" => \"", &ds->value, "\")");
- }
- buffer_clear(&ds->value); /* empty is untrusted */
- continue;
- }
- if (NULL != nm_slash) {
- struct sock_addr_mask *sm;
- char *err;
- const int nm_bits = strtol(nm_slash + 1, &err, 10);
- int rc;
- if (*err || nm_bits <= 0) {
- log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: invalid netmask:", &ds->key, err);
- return HANDLER_ERROR;
- }
- if (NULL == s->forward_masks) {
- s->forward_masks = calloc(1, sizeof(struct sock_addr_masks));
- force_assert(s->forward_masks);
- }
- if (s->forward_masks->used == s->forward_masks->sz) {
- s->forward_masks->sz += 2;
- s->forward_masks->addrs = realloc(s->forward_masks->addrs, s->forward_masks->sz * sizeof(struct sock_addr_mask));
- force_assert(s->forward_masks->addrs);
- }
- sm = s->forward_masks->addrs + s->forward_masks->used++;
- sm->bits = nm_bits;
- *nm_slash = '\0';
- rc = sock_addr_from_str_numeric(srv, &sm->addr, ds->key.ptr);
- *nm_slash = '/';
- if (1 != rc) return HANDLER_ERROR;
- buffer_clear(&ds->value); /* empty is untrusted, e.g. if subnet (incorrectly) appears in X-Forwarded-For */
- }
- }
- }
-
- if (!array_is_vlist(s->headers)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected value for extforward.headers; expected list of \"headername\"");
- return HANDLER_ERROR;
- }
-
- /* default to "X-Forwarded-For" or "Forwarded-For" if extforward.headers not specified or empty */
- if (!s->hap_PROXY && 0 == s->headers->used && (0 == i || NULL != array_get_element_klen(config->value, CONST_STR_LEN("extforward.headers")))) {
- array_insert_value(s->headers, CONST_STR_LEN("X-Forwarded-For"));
- array_insert_value(s->headers, CONST_STR_LEN("Forwarded-For"));
- }
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("extforward.forwarder"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("extforward.headers"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("extforward.params"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("extforward.hap-PROXY"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("extforward.hap-PROXY-ssl-client-verify"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_extforward"))
+ return HANDLER_ERROR;
+
+ int hap_PROXY = 0;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* extforward.forwarder */
+ if (!array_is_kvstring(cpv->v.a)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s; "
+ "expected list of \"IPaddr\" => \"trust\"",
+ cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ cpv->v.v = mod_extforward_parse_forwarder(srv, cpv->v.a);
+ if (NULL == cpv->v.v) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s", cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ cpv->vtype = T_CONFIG_LOCAL;
+ break;
+ case 1: /* extforward.headers */
+ if (!array_is_vlist(cpv->v.a)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s; "
+ "expected list of \"headername\"", cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ break;
+ case 2: /* extforward.params */
+ if (!array_is_kvany(cpv->v.a)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s; "
+ "expected list of \"param\" => \"value\"",
+ cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ cpv->v.u = mod_extforward_parse_opts(srv, cpv->v.a);
+ if (UINT_MAX == cpv->v.u)
+ return HANDLER_ERROR;
+ break;
+ case 3: /* extforward.hap-PROXY */
+ if (cpv->v.u) hap_PROXY = 1;
+ break;
+ case 4: /* extforward.hap-PROXY-ssl-client-verify */
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+ }
- if (!array_is_kvany(s->opts_params)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected value for extforward.params; expected ( \"param\" => \"value\" )");
- return HANDLER_ERROR;
- }
- for (size_t j = 0, used = s->opts_params->used; j < used; ++j) {
- proxy_forwarded_t param;
- data_unset *du = s->opts_params->data[j];
- #if 0 /*("for" and "proto" historical behavior: always enabled)*/
- if (buffer_is_equal_string(&du->key, CONST_STR_LEN("by"))) {
- param = PROXY_FORWARDED_BY;
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("for"))) {
- param = PROXY_FORWARDED_FOR;
- } else
- #endif
- if (buffer_is_equal_string(&du->key, CONST_STR_LEN("host"))) {
- param = PROXY_FORWARDED_HOST;
- #if 0
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("proto"))) {
- param = PROXY_FORWARDED_PROTO;
- #endif
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("remote_user"))) {
- param = PROXY_FORWARDED_REMOTE_USER;
- } else {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "extforward.params keys must be one of: host, remote_user, but not:", &du->key);
- return HANDLER_ERROR;
- }
- if (du->type == TYPE_STRING) {
- data_string *ds = (data_string *)du;
- if (buffer_is_equal_string(&ds->value, CONST_STR_LEN("enable"))) {
- s->opts |= param;
- } else if (!buffer_is_equal_string(&ds->value, CONST_STR_LEN("disable"))) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "extforward.params values must be one of: 0, 1, enable, disable; error for key:", &du->key);
- return HANDLER_ERROR;
- }
- } else if (du->type == TYPE_INTEGER) {
- data_integer *di = (data_integer *)du;
- if (di->value) s->opts |= param;
- } else {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "extforward.params values must be one of: 0, 1, enable, disable; error for key:", &du->key);
- return HANDLER_ERROR;
- }
- }
- }
+ mod_extforward_plugin_data_singleton = p;
+ p->defaults.opts = PROXY_FORWARDED_NONE;
- /* attempt to warn if mod_extforward is not last module loaded to hook
- * handle_connection_accept. (Nice to have, but remove this check if
- * it reaches too far into internals and prevents other code changes.)
- * While it would be nice to check connection_handle_accept plugin slot
- * to make sure mod_extforward is last, that info is private to plugin.c
- * so merely warn if mod_openssl is loaded after mod_extforward, though
- * future modules which hook connection_handle_accept might be missed.*/
- for (i = 0; i < srv->config_context->used; ++i) {
- plugin_config *s = p->config_storage[i];
- if (s->hap_PROXY) {
- size_t j;
- for (j = 0; j < srv->srvconf.modules->used; ++j) {
- data_string *ds = (data_string *)srv->srvconf.modules->data[j];
- if (buffer_is_equal_string(&ds->value, CONST_STR_LEN("mod_extforward"))) {
- break;
- }
- }
- for (; j < srv->srvconf.modules->used; ++j) {
- data_string *ds = (data_string *)srv->srvconf.modules->data[j];
- if (buffer_is_equal_string(&ds->value, CONST_STR_LEN("mod_openssl"))) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "mod_extforward must be loaded after mod_openssl in server.modules when extforward.hap-PROXY = \"enable\"");
- break;
- }
- }
- break;
- }
- }
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_extforward_merge_config(&p->defaults, cpv);
+ }
- for (i = 0; i < srv->srvconf.modules->used; i++) {
- data_string *ds = (data_string *)srv->srvconf.modules->data[i];
- if (buffer_is_equal_string(&ds->value, CONST_STR_LEN("mod_proxy"))) {
- extforward_check_proxy = 1;
- break;
- }
- }
+ /* default to "X-Forwarded-For" or "Forwarded-For" if extforward.headers
+ * is not specified or is empty (and not using hap_PROXY) */
+ if (!p->defaults.hap_PROXY
+ && (NULL == p->defaults.headers || 0 == p->defaults.headers->used)) {
+ p->defaults.headers = p->default_headers = array_init();
+ array_insert_value(p->default_headers,CONST_STR_LEN("X-Forwarded-For"));
+ array_insert_value(p->default_headers,CONST_STR_LEN("Forwarded-For"));
+ }
- return HANDLER_GO_ON;
-}
+ /* attempt to warn if mod_extforward is not last module loaded to hook
+ * handle_connection_accept. (Nice to have, but remove this check if
+ * it reaches too far into internals and prevents other code changes.)
+ * While it would be nice to check connection_handle_accept plugin slot
+ * to make sure mod_extforward is last, that info is private to plugin.c
+ * so merely warn if mod_openssl is loaded after mod_extforward, though
+ * future modules which hook connection_handle_accept might be missed.*/
+ if (hap_PROXY) {
+ uint32_t i;
+ for (i = 0; i < srv->srvconf.modules->used; ++i) {
+ data_string *ds = (data_string *)srv->srvconf.modules->data[i];
+ if (buffer_eq_slen(&ds->value, CONST_STR_LEN("mod_extforward")))
+ break;
+ }
+ for (; i < srv->srvconf.modules->used; ++i) {
+ data_string *ds = (data_string *)srv->srvconf.modules->data[i];
+ if (buffer_eq_slen(&ds->value, CONST_STR_LEN("mod_openssl"))) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "mod_extforward must be loaded after mod_openssl in "
+ "server.modules when extforward.hap-PROXY = \"enable\"");
+ break;
+ }
+ }
+ }
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_extforward_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(forwarder);
- PATCH(forward_masks);
- PATCH(headers);
- PATCH(opts);
- PATCH(hap_PROXY);
- PATCH(hap_PROXY_ssl_client_verify);
- PATCH(forward_all);
-
- /* 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("extforward.forwarder"))) {
- PATCH(forwarder);
- PATCH(forward_masks);
- PATCH(forward_all);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("extforward.headers"))) {
- PATCH(headers);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("extforward.params"))) {
- PATCH(opts);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("extforward.hap-PROXY"))) {
- PATCH(hap_PROXY);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("extforward.hap-PROXY-ssl-client-verify"))) {
- PATCH(hap_PROXY_ssl_client_verify);
- }
- }
- }
+ for (uint32_t i = 0; i < srv->srvconf.modules->used; ++i) {
+ data_string *ds = (data_string *)srv->srvconf.modules->data[i];
+ if (buffer_is_equal_string(&ds->value, CONST_STR_LEN("mod_proxy"))) {
+ extforward_check_proxy = 1;
+ break;
+ }
+ }
- return 0;
+ return HANDLER_GO_ON;
}
-#undef PATCH
/*
@@ -462,9 +519,9 @@ static int is_proxy_trusted(plugin_data *p, const char * const ip, size_t iplen)
(const data_string *)array_get_element_klen(p->conf.forwarder, ip, iplen);
if (NULL != ds) return !buffer_string_is_empty(&ds->value);
- if (p->conf.forward_masks) {
- const struct sock_addr_mask * const addrs =p->conf.forward_masks->addrs;
- const size_t aused = p->conf.forward_masks->used;
+ if (p->conf.forward_masks_used) {
+ const struct sock_addr_mask * const addrs = p->conf.forward_masks;
+ const uint32_t aused = p->conf.forward_masks_used;
sock_addr addr;
/* C funcs inet_aton(), inet_pton() require '\0'-terminated IP str */
char addrstr[64]; /*(larger than INET_ADDRSTRLEN and INET6_ADDRSTRLEN)*/
@@ -475,7 +532,7 @@ static int is_proxy_trusted(plugin_data *p, const char * const ip, size_t iplen)
if (1 != sock_addr_inet_pton(&addr, addrstr, AF_INET, 0)
&& 1 != sock_addr_inet_pton(&addr, addrstr, AF_INET6, 0)) return 0;
- for (size_t i = 0; i < aused; ++i) {
+ for (uint32_t i = 0; i < aused; ++i) {
if (sock_addr_is_addr_eq_bits(&addr, &addrs[i].addr, addrs[i].bits))
return 1;
}
@@ -1009,7 +1066,7 @@ URIHANDLER_FUNC(mod_extforward_uri_handler) {
handler_ctx *hctx = con->plugin_ctx[p->id];
int is_forwarded_header = 0;
- mod_extforward_patch_connection(srv, con, p);
+ mod_extforward_patch_config(con, p);
if (con->conf.log_request_handling) {
log_error_write(srv, __FILE__, __LINE__, "s",
@@ -1036,7 +1093,9 @@ URIHANDLER_FUNC(mod_extforward_uri_handler) {
}
}
- for (size_t k = 0; k < p->conf.headers->used && NULL == forwarded; ++k) {
+ if (NULL == p->conf.forwarder) return HANDLER_GO_ON;
+ if (NULL == p->conf.headers) return HANDLER_GO_ON;
+ for (uint32_t k = 0; k < p->conf.headers->used && NULL == forwarded; ++k) {
buffer *hdr = &((data_string *)p->conf.headers->data[k])->value;
forwarded = http_header_request_get(con, HTTP_HEADER_UNSPECIFIED, CONST_BUF_LEN(hdr));
if (forwarded) {
@@ -1075,7 +1134,7 @@ CONNECTION_FUNC(mod_extforward_handle_request_env) {
handler_ctx *hctx = con->plugin_ctx[p->id];
UNUSED(srv);
if (NULL == hctx || NULL == hctx->env) return HANDLER_GO_ON;
- for (size_t i=0; i < hctx->env->used; ++i) {
+ for (uint32_t i=0; i < hctx->env->used; ++i) {
/* note: replaces values which may have been set by mod_openssl
* (when mod_extforward is listed after mod_openssl in server.modules)*/
data_string *ds = (data_string *)hctx->env->data[i];
@@ -1145,8 +1204,9 @@ static int mod_extforward_network_read (server *srv, connection *con, chunkqueue
CONNECTION_FUNC(mod_extforward_handle_con_accept)
{
plugin_data *p = p_d;
- mod_extforward_patch_connection(srv, con, p);
+ mod_extforward_patch_config(con, p);
if (!p->conf.hap_PROXY) return HANDLER_GO_ON;
+ if (NULL == p->conf.forwarder) return HANDLER_GO_ON;
if (is_connection_trusted(con, p)) {
handler_ctx *hctx = handler_ctx_init();
con->plugin_ctx[p->id] = hctx;
@@ -1164,12 +1224,10 @@ CONNECTION_FUNC(mod_extforward_handle_con_accept)
}
-/* this function is called at dlopen() time and inits the callbacks */
-
int mod_extforward_plugin_init(plugin *p);
int mod_extforward_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("extforward");
+ p->name = "extforward";
p->init = mod_extforward_init;
p->handle_connection_accept = mod_extforward_handle_con_accept;
@@ -1181,8 +1239,6 @@ int mod_extforward_plugin_init(plugin *p) {
p->set_defaults = mod_extforward_set_defaults;
p->cleanup = mod_extforward_free;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_fastcgi.c b/src/mod_fastcgi.c
index c6fa1b6c..544750c7 100644
--- a/src/mod_fastcgi.c
+++ b/src/mod_fastcgi.c
@@ -452,12 +452,11 @@ static int fcgi_patch_connection(server *srv, connection *con, plugin_data *p) {
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
+ if (!config_check_cond(con, i)) continue; /* condition not matched */
+
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];
@@ -524,7 +523,7 @@ static handler_t fcgi_check_extension_2(server *srv, connection *con, void *p_d)
int mod_fastcgi_plugin_init(plugin *p);
int mod_fastcgi_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("fastcgi");
+ p->name = "fastcgi";
p->init = gw_init;
p->cleanup = gw_free;
@@ -536,7 +535,5 @@ int mod_fastcgi_plugin_init(plugin *p) {
p->handle_trigger = gw_handle_trigger;
p->handle_waitpid = gw_handle_waitpid_cb;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_flv_streaming.c b/src/mod_flv_streaming.c
index 950a485f..96e6cf71 100644
--- a/src/mod_flv_streaming.c
+++ b/src/mod_flv_streaming.c
@@ -1,8 +1,9 @@
#include "first.h"
#include "base.h"
-#include "log.h"
+#include "array.h"
#include "buffer.h"
+#include "log.h"
#include "http_chunk.h"
#include "http_header.h"
@@ -11,111 +12,99 @@
#include <stdlib.h>
#include <string.h>
-/* plugin config for all request/connections */
-
typedef struct {
- array *extensions;
+ const array *extensions;
} plugin_config;
typedef struct {
- PLUGIN_DATA;
- plugin_config **config_storage;
- plugin_config conf;
+ PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
} plugin_data;
-/* init the plugin data */
INIT_FUNC(mod_flv_streaming_init) {
- return calloc(1, sizeof(plugin_data));
+ return calloc(1, sizeof(plugin_data));
}
-/* detroy the plugin data */
FREE_FUNC(mod_flv_streaming_free) {
- plugin_data *p = p_d;
- if (!p) return HANDLER_GO_ON;
-
- if (p->config_storage) {
- for (size_t i = 0; i < srv->config_context->used; ++i) {
- plugin_config *s = p->config_storage[i];
- if (NULL == s) continue;
- array_free(s->extensions);
- free(s);
- }
- free(p->config_storage);
- }
- free(p);
- UNUSED(srv);
- return HANDLER_GO_ON;
-}
-
-/* handle plugin config and check values */
-
-SETDEFAULTS_FUNC(mod_flv_streaming_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { "flv-streaming.extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->extensions = array_init();
-
- cv[0].destination = s->extensions;
-
- p->config_storage[i] = s;
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+ UNUSED(srv);
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
+ free(p->cvlist);
+ free(p);
- if (!array_is_vlist(s->extensions)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected value for flv-streaming.extensions; expected list of \"ext\"");
- return HANDLER_ERROR;
- }
- }
-
- return HANDLER_GO_ON;
+ return HANDLER_GO_ON;
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_flv_streaming_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(extensions);
+static void mod_flv_streaming_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* flv-streaming.extensions */
+ pconf->extensions = cpv->v.a;
+ break;
+ default:/* should not happen */
+ return;
+ }
+}
- /* 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];
+static void mod_flv_streaming_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_flv_streaming_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- /* condition didn't match */
- if (!config_check_cond(srv, con, dc)) continue;
+static void mod_flv_streaming_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_flv_streaming_merge_config(&p->conf,
+ p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
- /* merge config */
- for (j = 0; j < dc->value->used; j++) {
- data_unset *du = dc->value->data[j];
+SETDEFAULTS_FUNC(mod_flv_streaming_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("flv-streaming.extensions"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_flv_streaming"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* flv-streaming.extensions */
+ if (!array_is_vlist(cpv->v.a)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s; "
+ "expected list of \"ext\"", cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+ }
- if (buffer_is_equal_string(&du->key, CONST_STR_LEN("flv-streaming.extensions"))) {
- PATCH(extensions);
- }
- }
- }
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_flv_streaming_merge_config(&p->defaults, cpv);
+ }
- return 0;
+ return HANDLER_GO_ON;
}
-#undef PATCH
static off_t get_param_value(buffer *qb, const char *m, size_t mlen) {
const char * const q = qb->ptr;
@@ -139,7 +128,8 @@ URIHANDLER_FUNC(mod_flv_streaming_path_handler) {
if (con->mode != DIRECT) return HANDLER_GO_ON;
if (buffer_string_is_empty(con->physical.path)) return HANDLER_GO_ON;
- mod_flv_streaming_patch_connection(srv, con, p);
+ mod_flv_streaming_patch_config(con, p);
+ if (NULL == p->conf.extensions) return HANDLER_GO_ON;
if (!array_match_value_suffix(p->conf.extensions, con->physical.path)) {
/* not found */
@@ -172,19 +162,16 @@ URIHANDLER_FUNC(mod_flv_streaming_path_handler) {
return HANDLER_FINISHED;
}
-/* this function is called at dlopen() time and inits the callbacks */
int mod_flv_streaming_plugin_init(plugin *p);
int mod_flv_streaming_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("flv_streaming");
+ p->name = "flv_streaming";
p->init = mod_flv_streaming_init;
p->handle_physical = mod_flv_streaming_path_handler;
p->set_defaults = mod_flv_streaming_set_defaults;
p->cleanup = mod_flv_streaming_free;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_geoip.c b/src/mod_geoip.c
index 69ffb8f1..b987bd9a 100644
--- a/src/mod_geoip.c
+++ b/src/mod_geoip.c
@@ -55,162 +55,162 @@
*/
-/* plugin config for all request/connections */
-
typedef struct {
- unsigned short mem_cache;
- buffer *db_name;
- GeoIP *gi;
+ GeoIP *gi;
} plugin_config;
typedef struct {
- PLUGIN_DATA;
-
- plugin_config **config_storage;
-
- plugin_config conf;
+ PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
} plugin_data;
-/* init the plugin data */
INIT_FUNC(mod_geoip_init) {
- plugin_data *p;
-
- p = calloc(1, sizeof(*p));
+ return calloc(1, sizeof(plugin_data));
+}
- return p;
+static void mod_geoip_free_config(plugin_data * const p) {
+ if (NULL == p->cvlist) return;
+ /* (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* geoip.db-filename */
+ if (cpv->vtype == T_CONFIG_LOCAL && NULL != cpv->v.v)
+ GeoIP_delete(cpv->v.v);
+ break;
+ default:
+ break;
+ }
+ }
+ }
}
-/* destroy the plugin data */
FREE_FUNC(mod_geoip_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- 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;
+ plugin_data * const p = p_d;
+ if (!p) return HANDLER_GO_ON;
+ UNUSED(srv);
- buffer_free(s->db_name);
+ mod_geoip_free_config(p);
- /* clean up */
- if (s->gi) GeoIP_delete(s->gi);
+ free(p->cvlist);
+ free(p);
- free(s);
- }
- free(p->config_storage);
- }
-
- free(p);
-
- return HANDLER_GO_ON;
+ return HANDLER_GO_ON;
}
-/* handle plugin config and check values */
-
-SETDEFAULTS_FUNC(mod_geoip_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { "geoip.db-filename", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { "geoip.memory-cache", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
- int mode;
-
- s = calloc(1, sizeof(plugin_config));
-
- s->db_name = buffer_init();
- s->mem_cache = 0; /* default: do not load db to cache */
- s->gi = NULL;
-
- cv[0].destination = s->db_name;
- cv[1].destination = &(s->mem_cache);
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
-
- mode = GEOIP_STANDARD | GEOIP_CHECK_CACHE;
-
- /* country db filename is requeried! */
- if (!buffer_is_empty(s->db_name)) {
-
- /* let's start cooking */
- if (s->mem_cache != 0)
- mode = GEOIP_MEMORY_CACHE | GEOIP_CHECK_CACHE;
+static int mod_geoip_open_db(server *srv, config_plugin_value_t * const cpv, int mem_cache) {
+ /* country db filename is required! */
+ if (buffer_is_empty(cpv->v.b)) {
+ cpv->v.v = NULL;
+ return 1;
+ }
- if (NULL == (s->gi = GeoIP_open(s->db_name->ptr, mode))) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "failed to open GeoIP database!!!");
+ /* let's start cooking */
+ const int mode = (mem_cache)
+ ? GEOIP_MEMORY_CACHE | GEOIP_CHECK_CACHE
+ : GEOIP_STANDARD | GEOIP_CHECK_CACHE;
- return HANDLER_ERROR;
- }
+ GeoIP *gi = GeoIP_open(cpv->v.b->ptr, mode);
+ if (NULL == gi) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "failed to open GeoIP database!!!");
+ return 0;
+ }
- /* is the db supported ? */
- if (s->gi->databaseType != GEOIP_COUNTRY_EDITION &&
- s->gi->databaseType != GEOIP_CITY_EDITION_REV0 &&
- s->gi->databaseType != GEOIP_CITY_EDITION_REV1) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "GeoIP database is of unsupported type!!!");
- }
- }
- }
+ /* is the db supported ? */
+ if ( gi->databaseType != GEOIP_COUNTRY_EDITION
+ && gi->databaseType != GEOIP_CITY_EDITION_REV0
+ && gi->databaseType != GEOIP_CITY_EDITION_REV1) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "GeoIP database is of unsupported type!!!");
+ GeoIP_delete(gi);
+ return 0;
+ }
- return HANDLER_GO_ON;
+ cpv->vtype = T_CONFIG_LOCAL;
+ cpv->v.v = gi;
+ return 1;
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_geoip_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(db_name);
- PATCH(mem_cache);
- PATCH(gi);
-
- /* 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];
+static void mod_geoip_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* geoip.db-filename */
+ if (cpv->vtype != T_CONFIG_LOCAL) break;
+ pconf->gi = cpv->v.v;
+ break;
+ case 1: /* geoip.memory-cache */
+ break;
+ default:/* should not happen */
+ return;
+ }
+}
- /* condition didn't match */
- if (!config_check_cond(srv, con, dc)) continue;
+static void mod_geoip_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_geoip_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- /* merge config */
- for (j = 0; j < dc->value->used; j++) {
- data_unset *du = dc->value->data[j];
+static void mod_geoip_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_geoip_merge_config(&p->conf, p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
- if (buffer_is_equal_string(&du->key, CONST_STR_LEN("geoip.db-filename"))) {
- PATCH(db_name);
- }
+SETDEFAULTS_FUNC(mod_geoip_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("geoip.db-filename"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("geoip.memory-cache"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_geoip"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ config_plugin_value_t *fn = NULL;
+ int mem_cache = 0;
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* geoip.db-filename */
+ fn = cpv;
+ break;
+ case 1: /* geoip.memory-cache */
+ mem_cache = cpv->v.u;
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+ if (fn) {
+ if (!mod_geoip_open_db(srv, fn, mem_cache))
+ return HANDLER_ERROR;
+ }
+ }
- if (buffer_is_equal_string(&du->key, CONST_STR_LEN("geoip.memory-cache"))) {
- PATCH(mem_cache);
- }
- }
- }
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_geoip_merge_config(&p->defaults, cpv);
+ }
- return 0;
+ return HANDLER_GO_ON;
}
-#undef PATCH
static handler_t mod_geoip_query (connection *con, plugin_data *p) {
GeoIPRecord *gir;
@@ -280,26 +280,22 @@ static handler_t mod_geoip_query (connection *con, plugin_data *p) {
}
CONNECTION_FUNC(mod_geoip_handle_request_env) {
- plugin_data *p = p_d;
- mod_geoip_patch_connection(srv, con, p);
- if (buffer_is_empty(p->conf.db_name)) return HANDLER_GO_ON;
-
- return mod_geoip_query(con, p);
+ UNUSED(srv);
+ plugin_data *p = p_d;
+ mod_geoip_patch_config(con, p);
+ return (p->conf.gi) ? mod_geoip_query(con, p) : HANDLER_GO_ON;
}
-/* this function is called at dlopen() time and inits the callbacks */
int mod_geoip_plugin_init(plugin *p);
int mod_geoip_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("geoip");
+ p->name = "geoip";
p->init = mod_geoip_init;
p->handle_request_env = mod_geoip_handle_request_env;
p->set_defaults = mod_geoip_set_defaults;
p->cleanup = mod_geoip_free;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_indexfile.c b/src/mod_indexfile.c
index eb0095bb..d3ba3442 100644
--- a/src/mod_indexfile.c
+++ b/src/mod_indexfile.c
@@ -16,144 +16,114 @@
/* plugin config for all request/connections */
typedef struct {
- array *indexfiles;
+ const array *indexfiles;
} plugin_config;
typedef struct {
- PLUGIN_DATA;
-
- buffer *tmp_buf;
-
- plugin_config **config_storage;
-
- plugin_config conf;
+ PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
} plugin_data;
/* init the plugin data */
INIT_FUNC(mod_indexfile_init) {
- plugin_data *p;
-
- p = calloc(1, sizeof(*p));
-
- p->tmp_buf = buffer_init();
-
- return p;
+ return calloc(1, sizeof(plugin_data));
}
-/* detroy the plugin data */
FREE_FUNC(mod_indexfile_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- 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 (NULL == s) continue;
-
- array_free(s->indexfiles);
-
- free(s);
- }
- free(p->config_storage);
- }
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+ UNUSED(srv);
- buffer_free(p->tmp_buf);
+ free(p->cvlist);
+ free(p);
- free(p);
-
- return HANDLER_GO_ON;
+ return HANDLER_GO_ON;
}
-/* handle plugin config and check values */
-
-SETDEFAULTS_FUNC(mod_indexfile_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { "index-file.names", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { "server.indexfiles", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->indexfiles = array_init();
-
- cv[0].destination = s->indexfiles;
- cv[1].destination = s->indexfiles; /* old name for [0] */
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
-
- if (!array_is_vlist(s->indexfiles)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected value for index-file.names; expected list of \"file\"");
- return HANDLER_ERROR;
- }
- }
-
- return HANDLER_GO_ON;
+static void mod_indexfile_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* index-file.names */
+ case 1: /* server.indexfiles */
+ pconf->indexfiles = cpv->v.a;
+ break;
+ default:/* should not happen */
+ return;
+ }
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_indexfile_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(indexfiles);
-
- /* 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];
+static void mod_indexfile_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_indexfile_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- if (buffer_is_equal_string(&du->key, CONST_STR_LEN("server.indexfiles"))) {
- PATCH(indexfiles);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("index-file.names"))) {
- PATCH(indexfiles);
- }
- }
- }
+static void mod_indexfile_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_indexfile_merge_config(&p->conf,p->cvlist+p->cvlist[i].v.u2[0]);
+ }
+}
- return 0;
+SETDEFAULTS_FUNC(mod_indexfile_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("index-file.names"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("server.indexfiles"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_indexfile"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* index-file.names */
+ case 1: /* server.indexfiles */
+ if (!array_is_vlist(cpv->v.a)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s; "
+ "expected list of \"file\"", cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+ }
+
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_indexfile_merge_config(&p->defaults, cpv);
+ }
+
+ return HANDLER_GO_ON;
}
-#undef PATCH
URIHANDLER_FUNC(mod_indexfile_subrequest) {
plugin_data *p = p_d;
- size_t k;
- stat_cache_entry *sce = NULL;
if (con->mode != DIRECT) return HANDLER_GO_ON;
if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
if (con->uri.path->ptr[buffer_string_length(con->uri.path) - 1] != '/') return HANDLER_GO_ON;
- mod_indexfile_patch_connection(srv, con, p);
+ mod_indexfile_patch_config(con, p);
+ if (NULL == p->conf.indexfiles) return HANDLER_GO_ON;
if (con->conf.log_request_handling) {
log_error_write(srv, __FILE__, __LINE__, "s", "-- handling the request as Indexfile");
@@ -161,39 +131,36 @@ URIHANDLER_FUNC(mod_indexfile_subrequest) {
}
/* indexfile */
- for (k = 0; k < p->conf.indexfiles->used; k++) {
- data_string *ds = (data_string *)p->conf.indexfiles->data[k];
+ buffer * const b = srv->tmp_buf;
+ for (uint32_t k = 0; k < p->conf.indexfiles->used; ++k) {
+ const data_string * const ds = (data_string *)p->conf.indexfiles->data[k];
if (ds->value.ptr[0] == '/') {
/* if the index-file starts with a prefix as use this file as
* index-generator */
- buffer_copy_buffer(p->tmp_buf, con->physical.doc_root);
+ buffer_copy_buffer(b, con->physical.doc_root);
} else {
- buffer_copy_buffer(p->tmp_buf, con->physical.path);
+ buffer_copy_buffer(b, con->physical.path);
}
- buffer_append_string_buffer(p->tmp_buf, &ds->value);
+ buffer_append_string_buffer(b, &ds->value);
- if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
+ stat_cache_entry *sce = NULL;
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, b, &sce)) {
if (errno == EACCES) {
con->http_status = 403;
buffer_reset(con->physical.path);
-
return HANDLER_FINISHED;
}
if (errno != ENOENT &&
errno != ENOTDIR) {
/* we have no idea what happend. let's tell the user so. */
-
con->http_status = 500;
-
log_error_write(srv, __FILE__, __LINE__, "ssbsb",
"file not found ... or so: ", strerror(errno),
con->uri.path,
"->", con->physical.path);
-
buffer_reset(con->physical.path);
-
return HANDLER_FINISHED;
}
continue;
@@ -208,8 +175,7 @@ URIHANDLER_FUNC(mod_indexfile_subrequest) {
buffer_append_string_buffer(con->uri.path, &ds->value);
}
- buffer_copy_buffer(con->physical.path, p->tmp_buf);
-
+ buffer_copy_buffer(con->physical.path, b);
return HANDLER_GO_ON;
}
@@ -217,19 +183,16 @@ URIHANDLER_FUNC(mod_indexfile_subrequest) {
return HANDLER_GO_ON;
}
-/* this function is called at dlopen() time and inits the callbacks */
int mod_indexfile_plugin_init(plugin *p);
int mod_indexfile_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("indexfile");
+ p->name = "indexfile";
p->init = mod_indexfile_init;
p->handle_subrequest_start = mod_indexfile_subrequest;
p->set_defaults = mod_indexfile_set_defaults;
p->cleanup = mod_indexfile_free;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_magnet.c b/src/mod_magnet.c
index 2d16d611..2c5f55b7 100644
--- a/src/mod_magnet.c
+++ b/src/mod_magnet.c
@@ -24,8 +24,6 @@
#define LUA_RIDX_LIGHTTPD_SERVER "lighty.srv"
#define LUA_RIDX_LIGHTTPD_CONNECTION "lighty.con"
-#define MAGNET_CONFIG_RAW_URL "magnet.attract-raw-url-to"
-#define MAGNET_CONFIG_PHYSICAL_PATH "magnet.attract-physical-path-to"
#define MAGNET_RESTART_REQUEST 99
/* plugin config for all request/connections */
@@ -33,143 +31,109 @@
static jmp_buf exceptionjmp;
typedef struct {
- array *url_raw;
- array *physical_path;
+ const array *url_raw;
+ const array *physical_path;
} plugin_config;
typedef struct {
- PLUGIN_DATA;
+ PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
- script_cache *cache;
-
- plugin_config **config_storage;
-
- plugin_config conf;
+ script_cache cache;
} plugin_data;
-/* init the plugin data */
INIT_FUNC(mod_magnet_init) {
- plugin_data *p;
-
- p = calloc(1, sizeof(*p));
-
- p->cache = script_cache_init();
-
- return p;
+ return calloc(1, sizeof(plugin_data));
}
-/* detroy the plugin data */
FREE_FUNC(mod_magnet_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- 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 (NULL == s) continue;
-
- array_free(s->url_raw);
- array_free(s->physical_path);
-
- free(s);
- }
- free(p->config_storage);
- }
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+ UNUSED(srv);
- script_cache_free(p->cache);
+ script_cache_free_data(&p->cache);
- free(p);
+ free(p->cvlist);
+ free(p);
- return HANDLER_GO_ON;
+ return HANDLER_GO_ON;
}
-/* handle plugin config and check values */
-
-SETDEFAULTS_FUNC(mod_magnet_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { MAGNET_CONFIG_RAW_URL, NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { MAGNET_CONFIG_PHYSICAL_PATH, NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->url_raw = array_init();
- s->physical_path = array_init();
-
- cv[0].destination = s->url_raw;
- cv[1].destination = s->physical_path;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
-
- if (!array_is_vlist(s->url_raw)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected value for magnet.attract-raw-url-to; expected list of \"scriptpath\"");
- return HANDLER_ERROR;
- }
-
- if (!array_is_vlist(s->physical_path)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected value for magnet.attract-physical-path-to; expected list \"scriptpath\"");
- return HANDLER_ERROR;
- }
- }
-
- return HANDLER_GO_ON;
+static void mod_magnet_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* magnet.attract-raw-url-to */
+ pconf->url_raw = cpv->v.a;
+ break;
+ case 1: /* magnet.attract-physical-path-to */
+ pconf->physical_path = cpv->v.a;
+ break;
+ default:/* should not happen */
+ return;
+ }
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_magnet_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(url_raw);
- PATCH(physical_path);
-
- /* 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];
+static void mod_magnet_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_magnet_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- /* condition didn't match */
- if (!config_check_cond(srv, con, dc)) continue;
+static void mod_magnet_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_magnet_merge_config(&p->conf, p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
- /* merge config */
- for (j = 0; j < dc->value->used; j++) {
- data_unset *du = dc->value->data[j];
+SETDEFAULTS_FUNC(mod_magnet_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("magnet.attract-raw-url-to"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("magnet.attract-physical-path-to"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_magnet"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* magnet.attract-raw-url-to */
+ case 1: /* magnet.attract-physical-path-to */
+ if (!array_is_vlist(cpv->v.a)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s; "
+ "expected list of \"scriptpath\"", cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+ }
- if (buffer_is_equal_string(&du->key, CONST_STR_LEN(MAGNET_CONFIG_RAW_URL))) {
- PATCH(url_raw);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN(MAGNET_CONFIG_PHYSICAL_PATH))) {
- PATCH(physical_path);
- }
- }
- }
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_magnet_merge_config(&p->defaults, cpv);
+ }
- return 0;
+ return HANDLER_GO_ON;
}
-#undef PATCH
#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 502
/* lua5.1 backward compat definition */
@@ -437,7 +401,7 @@ static int magnet_reqhdr_get(lua_State *L) {
static int magnet_reqhdr_pairs(lua_State *L) {
connection *con = magnet_get_connection(L);
- return magnet_array_pairs(L, con->request.headers);
+ return magnet_array_pairs(L, &con->request.headers);
}
static int magnet_status_get(lua_State *L) {
@@ -688,7 +652,7 @@ static int magnet_cgi_set(lua_State *L) {
static int magnet_cgi_pairs(lua_State *L) {
connection *con = magnet_get_connection(L);
- return magnet_array_pairs(L, con->environment);
+ return magnet_array_pairs(L, &con->environment);
}
@@ -832,7 +796,7 @@ static handler_t magnet_attract(server *srv, connection *con, plugin_data *p, bu
const int lighty_table_ndx = 2;
/* get the script-context */
- L = script_cache_get_script(srv, con, p->cache, name);
+ L = script_cache_get_script(srv, con, &p->cache, name);
if (lua_isstring(L, -1)) {
log_error_write(srv, __FILE__, __LINE__,
@@ -1049,19 +1013,23 @@ static handler_t magnet_attract(server *srv, connection *con, plugin_data *p, bu
}
}
-static handler_t magnet_attract_array(server *srv, connection *con, plugin_data *p, array *files) {
- size_t i;
- handler_t ret = HANDLER_GO_ON;
+static handler_t magnet_attract_array(server *srv, connection *con, plugin_data *p, int is_uri) {
+ mod_magnet_patch_config(con, p);
+
+ const array * const files = (is_uri)
+ ? p->conf.url_raw
+ : p->conf.physical_path;
/* no filename set */
- if (files->used == 0) return HANDLER_GO_ON;
+ if (NULL == files || files->used == 0) return HANDLER_GO_ON;
srv->request_env(srv, con);
/**
* execute all files and jump out on the first !HANDLER_GO_ON
*/
- for (i = 0; i < files->used && ret == HANDLER_GO_ON; i++) {
+ handler_t ret = HANDLER_GO_ON;
+ for (uint32_t i = 0; i < files->used && ret == HANDLER_GO_ON; ++i) {
data_string *ds = (data_string *)files->data[i];
if (buffer_string_is_empty(&ds->value)) continue;
@@ -1083,28 +1051,18 @@ static handler_t magnet_attract_array(server *srv, connection *con, plugin_data
}
URIHANDLER_FUNC(mod_magnet_uri_handler) {
- plugin_data *p = p_d;
-
- mod_magnet_patch_connection(srv, con, p);
-
- return magnet_attract_array(srv, con, p, p->conf.url_raw);
+ return magnet_attract_array(srv, con, p_d, 1);
}
URIHANDLER_FUNC(mod_magnet_physical) {
- plugin_data *p = p_d;
-
- mod_magnet_patch_connection(srv, con, p);
-
- return magnet_attract_array(srv, con, p, p->conf.physical_path);
+ return magnet_attract_array(srv, con, p_d, 0);
}
-/* this function is called at dlopen() time and inits the callbacks */
-
int mod_magnet_plugin_init(plugin *p);
int mod_magnet_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("magnet");
+ p->name = "magnet";
p->init = mod_magnet_init;
p->handle_uri_clean = mod_magnet_uri_handler;
@@ -1112,7 +1070,5 @@ int mod_magnet_plugin_init(plugin *p) {
p->set_defaults = mod_magnet_set_defaults;
p->cleanup = mod_magnet_free;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_magnet_cache.c b/src/mod_magnet_cache.c
index 9f09cca2..760ac8c9 100644
--- a/src/mod_magnet_cache.c
+++ b/src/mod_magnet_cache.c
@@ -33,15 +33,15 @@ static void script_free(script *sc) {
free(sc);
}
+#if 0
script_cache *script_cache_init() {
- script_cache *p;
-
- p = calloc(1, sizeof(*p));
-
+ script_cache *p = calloc(1, sizeof(script_cache));
+ force_assert(p);
return p;
}
+#endif
-void script_cache_free(script_cache *p) {
+void script_cache_free_data(script_cache *p) {
size_t i;
if (!p) return;
@@ -51,8 +51,6 @@ void script_cache_free(script_cache *p) {
}
free(p->ptr);
-
- free(p);
}
lua_State *script_cache_get_script(server *srv, connection *con, script_cache *cache, buffer *name) {
diff --git a/src/mod_magnet_cache.h b/src/mod_magnet_cache.h
index 04eb1ab1..661f2c0e 100644
--- a/src/mod_magnet_cache.h
+++ b/src/mod_magnet_cache.h
@@ -24,7 +24,7 @@ typedef struct {
} script_cache;
script_cache *script_cache_init(void);
-void script_cache_free(script_cache *cache);
+void script_cache_free_data(script_cache *cache);
lua_State *script_cache_get_script(server *srv, connection *con,
script_cache *cache, buffer *name);
diff --git a/src/mod_maxminddb.c b/src/mod_maxminddb.c
index d5e477e1..c72fe438 100644
--- a/src/mod_maxminddb.c
+++ b/src/mod_maxminddb.c
@@ -64,178 +64,287 @@
#include <maxminddb.h>
-SETDEFAULTS_FUNC(mod_maxmind_set_defaults);
-INIT_FUNC(mod_maxmind_init);
-FREE_FUNC(mod_maxmind_free);
-CONNECTION_FUNC(mod_maxmind_request_env_handler);
-CONNECTION_FUNC(mod_maxmind_handle_con_close);
+SETDEFAULTS_FUNC(mod_maxminddb_set_defaults);
+INIT_FUNC(mod_maxminddb_init);
+FREE_FUNC(mod_maxminddb_free);
+CONNECTION_FUNC(mod_maxminddb_request_env_handler);
+CONNECTION_FUNC(mod_maxminddb_handle_con_close);
int mod_maxminddb_plugin_init(plugin *p);
int mod_maxminddb_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("maxminddb");
+ p->name = "maxminddb";
- p->set_defaults = mod_maxmind_set_defaults;
- p->init = mod_maxmind_init;
- p->cleanup = mod_maxmind_free;
- p->handle_request_env = mod_maxmind_request_env_handler;
- p->handle_connection_close = mod_maxmind_handle_con_close;
-
- p->data = NULL;
+ p->set_defaults = mod_maxminddb_set_defaults;
+ p->init = mod_maxminddb_init;
+ p->cleanup = mod_maxminddb_free;
+ p->handle_request_env = mod_maxminddb_request_env_handler;
+ p->handle_connection_close = mod_maxminddb_handle_con_close;
return 0;
}
typedef struct {
int activate;
- array *env;
+ const array *env;
const char ***cenv;
struct MMDB_s *mmdb;
- buffer *db_name;
} plugin_config;
typedef struct {
PLUGIN_DATA;
- int nconfig;
- plugin_config **config_storage;
+ plugin_config defaults;
} plugin_data;
+typedef struct {
+ const array *env;
+ const char ***cenv;
+} plugin_config_env;
-INIT_FUNC(mod_maxmind_init)
+INIT_FUNC(mod_maxminddb_init)
{
return calloc(1, sizeof(plugin_data));
}
-FREE_FUNC(mod_maxmind_free)
+static void mod_maxminddb_free_config (plugin_data * const p)
{
- plugin_data *p = (plugin_data *)p_d;
- if (!p) return HANDLER_GO_ON;
-
- if (p->config_storage) {
- for (int i = 0; i < p->nconfig; ++i) {
- plugin_config * const s = p->config_storage[i];
- if (!s) continue;
- buffer_free(s->db_name);
- if (s->mmdb) { MMDB_close(s->mmdb); free(s->mmdb); }
- for (size_t k = 0, used = s->env->used; k < used; ++k)
- free(s->cenv[k]);
- free(s->cenv);
- array_free(s->env);
+ if (NULL == p->cvlist) return;
+ /* (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 1: /* maxminddb.db */
+ if (cpv->vtype == T_CONFIG_LOCAL && NULL != cpv->v.v) {
+ struct MMDB_s *mmdb;
+ *(struct MMDB_s **)&mmdb = cpv->v.v;
+ MMDB_close(mmdb);
+ free(mmdb);
+ }
+ break;
+ case 2: /* maxminddb.env */
+ if (cpv->vtype == T_CONFIG_LOCAL && NULL != cpv->v.v) {
+ plugin_config_env * const pcenv = cpv->v.v;
+ const array * const env = pcenv->env;
+ char ***cenv;
+ *(const char ****)&cenv = pcenv->cenv;
+ for (uint32_t k = 0, cused = env->used; k < cused; ++k)
+ free(cenv[k]);
+ free(cenv);
+ }
+ break;
+ default:
+ break;
+ }
}
- free(p->config_storage);
}
+}
- free(p);
+FREE_FUNC(mod_maxminddb_free)
+{
+ plugin_data * const p = p_d;
+ if (!p) return HANDLER_GO_ON;
UNUSED(srv);
+
+ mod_maxminddb_free_config(p);
+
+ free(p->cvlist);
+ free(p);
+
return HANDLER_GO_ON;
}
-SETDEFAULTS_FUNC(mod_maxmind_set_defaults)
+static MMDB_s *
+mod_maxminddb_open_db (server *srv, const buffer *db_name)
{
- static config_values_t cv[] = {
- { "maxminddb.activate", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
- { "maxminddb.db", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "maxminddb.env", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
+ if (db_name->used < sizeof(".mmdb")
+ || 0 != memcmp(db_name->ptr+db_name->used-sizeof(".mmdb"),
+ CONST_STR_LEN(".mmdb"))) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "GeoIP database is of unsupported type %.*s)",
+ BUFFER_INTLEN_PTR(db_name));
+ return NULL;
+ }
+
+ MMDB_s * const mmdb = (MMDB_s *)calloc(1, sizeof(MMDB_s));
+ int rc = MMDB_open(db_name->ptr, MMDB_MODE_MMAP, mmdb);
+ if (MMDB_SUCCESS == rc)
+ return mmdb;
+
+ if (MMDB_IO_ERROR == rc)
+ log_perror(srv->errh, __FILE__, __LINE__,
+ "failed to open GeoIP2 database (%.*s)",
+ BUFFER_INTLEN_PTR(db_name));
+ else
+ log_error(srv->errh, __FILE__, __LINE__,
+ "failed to open GeoIP2 database (%.*s): %s",
+ BUFFER_INTLEN_PTR(db_name), MMDB_strerror(rc));
+ free(mmdb);
+ return NULL;
+}
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
- plugin_data * const p = (plugin_data *)p_d;
- const size_t n_context = p->nconfig = srv->config_context->used;
- p->config_storage = calloc(p->nconfig, sizeof(plugin_config *));
- force_assert(p->config_storage);
-
- for (size_t i = 0; i < n_context; ++i) {
- plugin_config * const s = calloc(1, sizeof(plugin_config));
- force_assert(s);
- p->config_storage[i] = s;
- s->db_name = buffer_init();
- s->env = array_init();
-
- cv[0].destination = &s->activate;
- cv[1].destination = s->db_name;
- cv[2].destination = s->env;
-
- array * const ca = ((data_config *)srv->config_context->data[i])->value;
- if (0 != config_insert_values_global(srv, ca, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
+static plugin_config_env *
+mod_maxminddb_prep_cenv (server *srv, const array * const env)
+{
+ data_string ** const data = (data_string **)env->data;
+ char *** const cenv = calloc(env->used, sizeof(char **));
+ force_assert(cenv);
+ for (uint32_t j = 0, used = env->used; j < used; ++j) {
+ if (data[j]->type != TYPE_STRING) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "maxminddb.env must be a list of strings");
+ for (uint32_t k = 0; k < j; ++k) free(cenv[k]);
+ free(cenv);
+ return NULL;
+ }
+ buffer *value = &data[j]->value;
+ if (buffer_string_is_empty(value)
+ || '/' == value->ptr[0]
+ || '/' == value->ptr[buffer_string_length(value)-1]) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "maxminddb.env must be a list of non-empty "
+ "strings and must not begin or end with '/'");
+ for (uint32_t k = 0; k < j; ++k) free(cenv[k]);
+ free(cenv);
+ return NULL;
+ }
+ /* XXX: should strings be lowercased? */
+ unsigned int k = 2;
+ for (char *t = value->ptr; (t = strchr(t, '/')); ++t) ++k;
+ const char **keys = (const char **)(cenv[j] = calloc(k,sizeof(char *)));
+ force_assert(keys);
+ k = 0;
+ keys[k] = value->ptr;
+ for (char *t = value->ptr; (t = strchr(t, '/')); ) {
+ *t = '\0';
+ keys[++k] = ++t;
}
+ keys[++k] = NULL;
+ }
- if (!buffer_is_empty(s->db_name)) {
-
- if (s->db_name->used >= sizeof(".mmdb")
- && 0 == memcmp(s->db_name->ptr+s->db_name->used-sizeof(".mmdb"),
- CONST_STR_LEN(".mmdb"))) {
- MMDB_s * const mmdb = (MMDB_s *)calloc(1, sizeof(MMDB_s));
- int rc = MMDB_open(s->db_name->ptr, MMDB_MODE_MMAP, mmdb);
- if (MMDB_SUCCESS != rc) {
- if (MMDB_IO_ERROR == rc)
- log_perror(srv->errh, __FILE__, __LINE__,
- "failed to open GeoIP2 database (%.*s)",
- BUFFER_INTLEN_PTR(s->db_name));
- else
- log_error(srv->errh, __FILE__, __LINE__,
- "failed to open GeoIP2 database (%.*s): %s",
- BUFFER_INTLEN_PTR(s->db_name),
- MMDB_strerror(rc));
- free(mmdb);
- return HANDLER_ERROR;
- }
- s->mmdb = mmdb;
- }
- else {
- log_error(srv->errh, __FILE__, __LINE__,
- "GeoIP database is of unsupported type %.*s)",
- BUFFER_INTLEN_PTR(s->db_name));
- return HANDLER_ERROR;
- }
+ plugin_config_env * const pcenv = malloc(sizeof(plugin_config_env));
+ force_assert(pcenv);
+ pcenv->env = env;
+ pcenv->cenv = (const char ***)cenv;
+ return pcenv;
+}
+
+
+static void
+mod_maxminddb_merge_config_cpv(plugin_config * const pconf,
+ const config_plugin_value_t * const cpv)
+{
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* maxminddb.activate */
+ pconf->activate = (int)cpv->v.u;
+ break;
+ case 1: /* maxminddb.db */
+ if (cpv->vtype != T_CONFIG_LOCAL) break;
+ pconf->mmdb = cpv->v.v;
+ break;
+ case 2: /* maxminddb.env */
+ if (cpv->vtype == T_CONFIG_LOCAL) {
+ plugin_config_env * const pcenv = cpv->v.v;
+ pconf->env = pcenv->env;
+ pconf->cenv = pcenv->cenv;
}
+ break;
+ default:/* should not happen */
+ return;
+ }
+}
- if (s->env->used) {
- data_string **data = (data_string **)s->env->data;
- s->cenv = calloc(s->env->used, sizeof(char **));
- force_assert(s->cenv);
- for (size_t j = 0, used = s->env->used; j < used; ++j) {
- if (data[j]->type != TYPE_STRING) {
- log_error(srv->errh, __FILE__, __LINE__,
- "maxminddb.env must be a list of strings");
- return HANDLER_ERROR;
- }
- buffer *value = &data[j]->value;
- if (buffer_string_is_empty(value)
- || '/' == value->ptr[0]
- || '/' == value->ptr[buffer_string_length(value)-1]) {
- log_error(srv->errh, __FILE__, __LINE__,
- "maxminddb.env must be a list of non-empty "
- "strings and must not begin or end with '/'");
- return HANDLER_ERROR;
+
+static void
+mod_maxminddb_merge_config (plugin_config * const pconf,
+ const config_plugin_value_t *cpv)
+{
+ do {
+ mod_maxminddb_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
+
+
+static void
+mod_maxmind_patch_config (connection * const con,
+ const plugin_data * const p,
+ plugin_config * const pconf)
+{
+ memcpy(pconf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_maxminddb_merge_config(pconf, p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
+
+
+SETDEFAULTS_FUNC(mod_maxminddb_set_defaults)
+{
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("maxminddb.activate"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("maxminddb.db"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("maxminddb.env"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_maxminddb"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* maxminddb.activate */
+ break;
+ case 1: /* maxminddb.db */
+ if (!buffer_is_empty(cpv->v.b)) {
+ cpv->v.v = mod_maxminddb_open_db(srv, cpv->v.b);
+ if (NULL == cpv->v.v) return HANDLER_ERROR;
+ cpv->vtype = T_CONFIG_LOCAL;
}
- /* XXX: should strings be lowercased? */
- unsigned int k = 2;
- for (char *t = value->ptr; (t = strchr(t, '/')); ++t) ++k;
- const char **keys = s->cenv[j] = calloc(k, sizeof(char *));
- force_assert(keys);
- k = 0;
- keys[k] = value->ptr;
- for (char *t = value->ptr; (t = strchr(t, '/')); ) {
- *t = '\0';
- keys[++k] = ++t;
+ break;
+ case 2: /* maxminddb.env */
+ if (cpv->v.a->used) {
+ cpv->v.v = mod_maxminddb_prep_cenv(srv, cpv->v.a);
+ if (NULL == cpv->v.v) return HANDLER_ERROR;
+ cpv->vtype = T_CONFIG_LOCAL;
}
- keys[++k] = NULL;
+ break;
+ default:/* should not happen */
+ break;
}
}
}
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_maxminddb_merge_config(&p->defaults, cpv);
+ }
+
return HANDLER_GO_ON;
}
static void
-geoip2_env_set (array * const env, const char *k, size_t klen,
- MMDB_entry_data_s *data)
+geoip2_env_set (array * const env, const char * const k,
+ const size_t klen, MMDB_entry_data_s * const data)
{
/* GeoIP2 database interfaces return pointers directly into database,
* and these are valid until the database is closed.
@@ -295,8 +404,8 @@ geoip2_env_set (array * const env, const char *k, size_t klen,
static void
-mod_maxmind_geoip2 (array * const env, sock_addr *dst_addr,
- plugin_config *pconf)
+mod_maxmind_geoip2 (array * const env, sock_addr * const dst_addr,
+ plugin_config * const pconf)
{
MMDB_lookup_result_s res;
MMDB_entry_data_s data;
@@ -317,60 +426,17 @@ mod_maxmind_geoip2 (array * const env, sock_addr *dst_addr,
}
-static void
-mod_maxmind_patch_connection (server * const srv,
- connection * const con,
- const plugin_data * const p,
- plugin_config * const pconf)
-{
- const plugin_config *s = p->config_storage[0];
- memcpy(pconf, s, sizeof(*s));
- if (1 == p->nconfig)
- return;
-
- data_config ** const context_data =
- (data_config **)srv->config_context->data;
-
- s = p->config_storage[1]; /* base config (global context) copied above */
- for (size_t i = 1; i < srv->config_context->used; ++i) {
- data_config *dc = context_data[i];
- if (!config_check_cond(srv, con, dc))
- continue; /* condition did not match */
-
- s = p->config_storage[i];
-
- /* merge config */
- #define PATCH(x) pconf->x = s->x;
- for (size_t j = 0; j < dc->value->used; ++j) {
- data_unset *du = dc->value->data[j];
-
- if (buffer_is_equal_string(&du->key, CONST_STR_LEN("maxminddb.activate"))) {
- PATCH(activate);
- }
- else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("maxminddb.db"))) {
- /*PATCH(db_name);*//*(not used)*/
- PATCH(mmdb);
- }
- else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("maxminddb.env"))) {
- PATCH(env);
- PATCH(cenv);
- }
- }
- #undef PATCH
- }
-}
-
-
-CONNECTION_FUNC(mod_maxmind_request_env_handler)
+CONNECTION_FUNC(mod_maxminddb_request_env_handler)
{
const int sa_family = con->dst_addr.plain.sa_family;
if (sa_family != AF_INET && sa_family != AF_INET6) return HANDLER_GO_ON;
+ UNUSED(srv);
plugin_config pconf;
plugin_data *p = p_d;
- mod_maxmind_patch_connection(srv, con, p, &pconf);
+ mod_maxmind_patch_config(con, p, &pconf);
/* check that mod_maxmind is activated and env fields were requested */
- if (!pconf.activate || 0 == pconf.env->used) return HANDLER_GO_ON;
+ if (!pconf.activate || NULL == pconf.env) return HANDLER_GO_ON;
array *env = con->plugin_ctx[p->id];
if (NULL == env) {
@@ -391,7 +457,7 @@ CONNECTION_FUNC(mod_maxmind_request_env_handler)
}
-CONNECTION_FUNC(mod_maxmind_handle_con_close)
+CONNECTION_FUNC(mod_maxminddb_handle_con_close)
{
plugin_data *p = p_d;
array *env = con->plugin_ctx[p->id];
diff --git a/src/mod_mysql_vhost.c b/src/mod_mysql_vhost.c
index 4bf122f3..f8228a21 100644
--- a/src/mod_mysql_vhost.c
+++ b/src/mod_mysql_vhost.c
@@ -23,27 +23,17 @@
*/
typedef struct {
- MYSQL *mysql;
- buffer *mysql_query;
-
- buffer *mydb;
- buffer *myuser;
- buffer *mypass;
- buffer *mysock;
-
- buffer *hostname;
- unsigned short port;
+ MYSQL *mysql;
+ const buffer *mysql_query;
} plugin_config;
/* global plugin data */
typedef struct {
- PLUGIN_DATA;
-
- buffer *tmp_buf;
+ PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
- plugin_config **config_storage;
-
- plugin_config conf;
+ buffer tmp_buf;
} plugin_data;
/* per connection plugin data */
@@ -54,48 +44,41 @@ typedef struct {
/* init the plugin data */
INIT_FUNC(mod_mysql_vhost_init) {
- plugin_data *p;
-
- p = calloc(1, sizeof(*p));
-
- p->tmp_buf = buffer_init();
+ return calloc(1, sizeof(plugin_data));
+}
- return p;
+/* cleanup the mysql connections */
+static void mod_mysql_vhost_free_config(plugin_data * const p) {
+ if (NULL == p->cvlist) return;
+ /* (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ if (cpv->vtype != T_CONFIG_LOCAL || NULL == cpv->v.v) continue;
+ switch (cpv->k_id) {
+ case 1: /* mysql-vhost.db */
+ mysql_close(cpv->v.v);
+ break;
+ default:
+ break;
+ }
+ }
+ }
}
/* cleanup the plugin data */
-SERVER_FUNC(mod_mysql_vhost_cleanup) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- 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];
+FREE_FUNC(mod_mysql_vhost_cleanup) {
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
- if (!s) continue;
+ mod_mysql_vhost_free_config(p);
+ free(p->tmp_buf.ptr);
- mysql_close(s->mysql);
+ free(p->cvlist);
+ free(p);
- buffer_free(s->mysql_query);
- buffer_free(s->mydb);
- buffer_free(s->myuser);
- buffer_free(s->mypass);
- buffer_free(s->mysock);
- buffer_free(s->hostname);
-
- free(s);
- }
- free(p->config_storage);
- }
- buffer_free(p->tmp_buf);
-
- free(p);
-
- return HANDLER_GO_ON;
+ UNUSED(srv);
+ return HANDLER_GO_ON;
}
/* handle the plugin per connection data */
@@ -133,137 +116,174 @@ CONNECTION_FUNC(mod_mysql_vhost_handle_connection_reset) {
return HANDLER_GO_ON;
}
-/* set configuration values */
-SERVER_FUNC(mod_mysql_vhost_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { "mysql-vhost.db", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { "mysql-vhost.user", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { "mysql-vhost.pass", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
- { "mysql-vhost.sock", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
- { "mysql-vhost.sql", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
- { "mysql-vhost.hostname", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
- { "mysql-vhost.port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->mysql_query = buffer_init();
- s->mydb = buffer_init();
- s->myuser = buffer_init();
- s->mypass = buffer_init();
- s->mysock = buffer_init();
- s->hostname = buffer_init();
- s->port = 0; /* default port for mysql */
- s->mysql = NULL;
-
- cv[0].destination = s->mydb;
- cv[1].destination = s->myuser;
- cv[2].destination = s->mypass;
- cv[3].destination = s->mysock;
- cv[4].destination = s->mysql_query;
- cv[5].destination = s->hostname;
- cv[6].destination = &(s->port);
-
- p->config_storage[i] = s;
-
- if (config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
-
- /* required:
- * - username
- * - database
- *
- * optional:
- * - password, default: empty
- * - socket, default: mysql default
- * - hostname, if set overrides socket
- * - port, default: 3306
- */
-
- /* all have to be set */
- if (!(buffer_string_is_empty(s->myuser) ||
- buffer_string_is_empty(s->mydb))) {
-
- if (NULL == (s->mysql = mysql_init(NULL))) {
- log_error_write(srv, __FILE__, __LINE__, "s", "mysql_init() failed, exiting...");
- return HANDLER_ERROR;
- }
-
-#if MYSQL_VERSION_ID >= 50013
- /* in mysql versions above 5.0.3 the reconnect flag is off by default */
- {
- char reconnect = 1;
- mysql_options(s->mysql, MYSQL_OPT_RECONNECT, &reconnect);
- }
-#endif
-
-#define FOO(x) (buffer_string_is_empty(s->x) ? NULL : s->x->ptr)
-
-#if MYSQL_VERSION_ID >= 40100
- /* CLIENT_MULTI_STATEMENTS first appeared in 4.1 */
- if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(myuser), FOO(mypass),
- FOO(mydb), s->port, FOO(mysock), CLIENT_MULTI_STATEMENTS)) {
-#else
- if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(myuser), FOO(mypass),
- FOO(mydb), s->port, FOO(mysock), 0)) {
-#endif
- log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(s->mysql));
- return HANDLER_ERROR;
- }
-#undef FOO
-
- fdevent_setfd_cloexec(s->mysql->net.fd);
- }
- }
-
- return HANDLER_GO_ON;
+static void mod_mysql_vhost_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* mysql-vhost.sql */
+ pconf->mysql_query = cpv->v.b;
+ break;
+ case 1: /* mysql-vhost.db */
+ if (cpv->vtype == T_CONFIG_LOCAL)
+ pconf->mysql = cpv->v.v;
+ break;
+ case 2: /* mysql-vhost.user */
+ case 3: /* mysql-vhost.pass */
+ case 4: /* mysql-vhost.sock */
+ case 5: /* mysql-vhost.hostname */
+ case 6: /* mysql-vhost.port */
+ break;
+ default:/* should not happen */
+ return;
+ }
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_mysql_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(mysql_query);
- PATCH(mysql);
-
- /* 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("mysql-vhost.sql"))) {
- PATCH(mysql_query);
- }
- }
+static void mod_mysql_vhost_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_mysql_vhost_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- if (s->mysql) {
- PATCH(mysql);
- }
- }
+static void mod_mysql_vhost_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_mysql_vhost_merge_config(&p->conf,
+ p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
- return 0;
+static MYSQL * mod_mysql_vhost_db_setup (server *srv, const char *dbname, const char *user, const char *pass, const char *sock, const char *host, unsigned short port) {
+ /* required:
+ * - database
+ * - username
+ *
+ * optional:
+ * - password, default: empty
+ * - socket, default: mysql default
+ * - hostname, if set overrides socket
+ * - port, default: 3306
+ */
+
+ MYSQL * const my = mysql_init(NULL);
+ if (NULL == my) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "mysql_init() failed, exiting...");
+ return NULL;
+ }
+
+ #if MYSQL_VERSION_ID >= 50013
+ /* in mysql versions above 5.0.3 the reconnect flag is off by default */
+ char reconnect = 1;
+ mysql_options(my, MYSQL_OPT_RECONNECT, &reconnect);
+ #endif
+
+ unsigned long flags = 0;
+ #if MYSQL_VERSION_ID >= 40100
+ /* CLIENT_MULTI_STATEMENTS first appeared in 4.1 */
+ flags |= CLIENT_MULTI_STATEMENTS;
+ #endif
+
+ if (!mysql_real_connect(my, host, user, pass, dbname, port, sock, flags)) {
+ log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(my));
+ mysql_close(my);
+ return NULL;
+ }
+
+ fdevent_setfd_cloexec(my->net.fd);
+ return my;
}
-#undef PATCH
+/* set configuration values */
+SETDEFAULTS_FUNC(mod_mysql_vhost_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("mysql-vhost.sql"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("mysql-vhost.db"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("mysql-vhost.user"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("mysql-vhost.pass"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("mysql-vhost.sock"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("mysql-vhost.hostname"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("mysql-vhost.port"),
+ T_CONFIG_SHORT,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_mysql_vhost"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ const char *dbname=NULL, *user=NULL, *pass=NULL, *host=NULL, *sock=NULL;
+ unsigned short port = 0;
+ config_plugin_value_t *db = NULL;
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* mysql_vhost.sql */
+ break;
+ case 1: /* mysql_vhost.db */
+ if (!buffer_string_is_empty(cpv->v.b)) {
+ db = cpv;
+ dbname = cpv->v.b->ptr;
+ }
+ break;
+ case 2: /* mysql_vhost.user */
+ if (!buffer_string_is_empty(cpv->v.b))
+ user = cpv->v.b->ptr;
+ break;
+ case 3: /* mysql_vhost.pass */
+ if (!buffer_string_is_empty(cpv->v.b))
+ pass = cpv->v.b->ptr;
+ break;
+ case 4: /* mysql_vhost.sock */
+ if (!buffer_string_is_empty(cpv->v.b))
+ sock = cpv->v.b->ptr;
+ break;
+ case 5: /* mysql_vhost.hostname */
+ if (!buffer_string_is_empty(cpv->v.b))
+ host = cpv->v.b->ptr;
+ break;
+ case 6: /* mysql_vhost.port */
+ port = cpv->v.shrt;
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+
+ if (dbname && user) {
+ cpv = db;
+ cpv->v.v =
+ mod_mysql_vhost_db_setup(srv,dbname,user,pass,sock,host,port);
+ if (NULL == db->v.v) return HANDLER_ERROR;
+ cpv->vtype = T_CONFIG_LOCAL;
+ }
+ }
+
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_mysql_vhost_merge_config(&p->defaults, cpv);
+ }
+
+ return HANDLER_GO_ON;
+}
/* handle document root request */
CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
@@ -278,7 +298,7 @@ CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
/* no host specified? */
if (buffer_string_is_empty(con->uri.authority)) return HANDLER_GO_ON;
- mod_mysql_vhost_patch_connection(srv, con, p);
+ mod_mysql_vhost_patch_config(con, p);
if (!p->conf.mysql) return HANDLER_GO_ON;
if (buffer_string_is_empty(p->conf.mysql_query)) return HANDLER_GO_ON;
@@ -290,25 +310,26 @@ CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
if (buffer_is_equal(c->server_name, con->uri.authority)) goto GO_ON;
/* build and run SQL query */
- buffer_clear(p->tmp_buf);
- for (char *b = p->conf.mysql_query->ptr, *d; *b; b = d+1) {
- if (NULL != (d = strchr(b, '?'))) {
+ buffer * const b = &p->tmp_buf;
+ buffer_clear(b);
+ for (const char *ptr = p->conf.mysql_query->ptr, *d; *ptr; ptr = d+1) {
+ if (NULL != (d = strchr(ptr, '?'))) {
/* escape the uri.authority */
unsigned long to_len;
- buffer_append_string_len(p->tmp_buf, b, (size_t)(d - b));
- buffer_string_prepare_append(p->tmp_buf, buffer_string_length(con->uri.authority) * 2);
+ buffer_append_string_len(b, ptr, (size_t)(d - ptr));
+ buffer_string_prepare_append(b, buffer_string_length(con->uri.authority) * 2);
to_len = mysql_real_escape_string(p->conf.mysql,
- p->tmp_buf->ptr + buffer_string_length(p->tmp_buf),
+ b->ptr + buffer_string_length(b),
CONST_BUF_LEN(con->uri.authority));
if ((unsigned long)~0 == to_len) goto ERR500;
- buffer_commit(p->tmp_buf, to_len);
+ buffer_commit(b, to_len);
} else {
d = p->conf.mysql_query->ptr + buffer_string_length(p->conf.mysql_query);
- buffer_append_string_len(p->tmp_buf, b, (size_t)(d - b));
+ buffer_append_string_len(b, ptr, (size_t)(d - ptr));
break;
}
}
- if (mysql_real_query(p->conf.mysql, CONST_BUF_LEN(p->tmp_buf))) {
+ if (mysql_real_query(p->conf.mysql, CONST_BUF_LEN(b))) {
log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(p->conf.mysql));
goto ERR500;
}
@@ -325,21 +346,21 @@ CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
}
/* sanity check that really is a directory */
- buffer_copy_string(p->tmp_buf, row[0]);
- buffer_append_slash(p->tmp_buf);
+ buffer_copy_string(b, row[0]);
+ buffer_append_slash(b);
- 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);
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, b, &sce)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), b);
goto ERR500;
}
if (!S_ISDIR(sce->st.st_mode)) {
- log_error_write(srv, __FILE__, __LINE__, "sb", "Not a directory", p->tmp_buf);
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Not a directory", b);
goto ERR500;
}
/* cache the data */
buffer_copy_buffer(c->server_name, con->uri.authority);
- buffer_copy_buffer(c->document_root, p->tmp_buf);
+ buffer_copy_buffer(c->document_root, b);
mysql_free_result(result);
#if MYSQL_VERSION_ID >= 40100
@@ -368,7 +389,7 @@ ERR500:
int mod_mysql_vhost_plugin_init(plugin *p);
int mod_mysql_vhost_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("mysql_vhost");
+ p->name = "mysql_vhost";
p->init = mod_mysql_vhost_init;
p->cleanup = mod_mysql_vhost_cleanup;
diff --git a/src/mod_openssl.c b/src/mod_openssl.c
index 43b558ef..d6cd20b8 100644
--- a/src/mod_openssl.c
+++ b/src/mod_openssl.c
@@ -662,7 +662,7 @@ mod_openssl_alpn_select_cb (SSL *ssl, const unsigned char **out, unsigned char *
for (unsigned int i = 0, n; i < inlen; i += n) {
n = in[i++];
- if (i+n > inlen) break;
+ if (i+n > inlen || 0 == n) break;
switch (n) {
#if 0
case 2: /* "h2" */
@@ -1391,12 +1391,11 @@ mod_openssl_patch_connection (server *srv, connection *con, handler_ctx *hctx)
/* skip the first, the global context */
for (size_t i = 1; i < srv->config_context->used; ++i) {
+ if (!config_check_cond(con, i)) continue; /* condition not matched */
+
data_config *dc = (data_config *)srv->config_context->data[i];
s = plugin_data_singleton->config_storage[i];
- /* condition didn't match */
- if (!config_check_cond(srv, con, dc)) continue;
-
/* merge config */
for (size_t j = 0; j < dc->value->used; ++j) {
data_unset *du = dc->value->data[j];
@@ -2202,7 +2201,7 @@ int mod_openssl_plugin_init (plugin *p);
int mod_openssl_plugin_init (plugin *p)
{
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("openssl");
+ p->name = "openssl";
p->init = mod_openssl_init;
p->cleanup = mod_openssl_free;
p->priv_defaults= mod_openssl_set_defaults;
@@ -2214,7 +2213,5 @@ int mod_openssl_plugin_init (plugin *p)
p->handle_request_env = mod_openssl_handle_request_env;
p->connection_reset = mod_openssl_handle_request_reset;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_proxy.c b/src/mod_proxy.c
index 0fe8e619..b74ead44 100644
--- a/src/mod_proxy.c
+++ b/src/mod_proxy.c
@@ -767,8 +767,8 @@ static handler_t proxy_create_env(server *srv, gw_handler_ctx *gwhctx) {
}
/* request header */
- for (size_t i = 0, used = con->request.headers->used; i < used; ++i) {
- data_string *ds = (data_string *)con->request.headers->data[i];
+ for (size_t i = 0, used = con->request.headers.used; i < used; ++i) {
+ data_string *ds = (data_string *)con->request.headers.data[i];
const size_t klen = buffer_string_length(&ds->key);
size_t vlen;
switch (klen) {
@@ -890,12 +890,11 @@ static int mod_proxy_patch_connection(server *srv, connection *con, plugin_data
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
+ if (!config_check_cond(con, i)) continue; /* condition not matched */
+
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];
@@ -1022,7 +1021,7 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p
int mod_proxy_plugin_init(plugin *p);
int mod_proxy_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("proxy");
+ p->name = "proxy";
p->init = mod_proxy_init;
p->cleanup = mod_proxy_free;
@@ -1033,7 +1032,5 @@ int mod_proxy_plugin_init(plugin *p) {
p->handle_trigger = gw_handle_trigger;
p->handle_waitpid = gw_handle_waitpid_cb;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_redirect.c b/src/mod_redirect.c
index 37ede72e..0d8a5792 100644
--- a/src/mod_redirect.c
+++ b/src/mod_redirect.c
@@ -14,13 +14,13 @@
typedef struct {
pcre_keyvalue_buffer *redirect;
- data_config *context; /* to which apply me */
+ int context_ndx; /* to which apply me */
unsigned short redirect_code;
} plugin_config;
typedef struct {
PLUGIN_DATA;
- plugin_config **config_storage;
+ plugin_config defaults;
plugin_config conf;
} plugin_data;
@@ -28,122 +28,140 @@ INIT_FUNC(mod_redirect_init) {
return calloc(1, sizeof(plugin_data));
}
+static void mod_redirect_free_config(plugin_data * const p) {
+ if (NULL == p->cvlist) return;
+ /* (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* url.redirect */
+ if (cpv->vtype == T_CONFIG_LOCAL)
+ pcre_keyvalue_buffer_free(cpv->v.v);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
FREE_FUNC(mod_redirect_free) {
- plugin_data *p = p_d;
- 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 (NULL == s) continue;
- pcre_keyvalue_buffer_free(s->redirect);
- free(s);
- }
- free(p->config_storage);
- }
-
- free(p);
- return HANDLER_GO_ON;
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+ UNUSED(srv);
+
+ mod_redirect_free_config(p);
+
+ free(p->cvlist);
+ free(p);
+
+ return HANDLER_GO_ON;
}
-SETDEFAULTS_FUNC(mod_redirect_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { "url.redirect", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { "url.redirect-code", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- /* 0 */
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
- size_t j;
- const data_unset *du;
- const data_array *da;
-
- s = calloc(1, sizeof(plugin_config));
- s->redirect = pcre_keyvalue_buffer_init();
- s->redirect_code = 301;
-
- cv[0].destination = s->redirect;
- cv[1].destination = &(s->redirect_code);
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
-
- if (s->redirect_code < 100 || s->redirect_code >= 1000) s->redirect_code = 301;
-
- if (NULL == (du = array_get_element_klen(config->value, CONST_STR_LEN("url.redirect")))) {
- /* no url.redirect defined */
- continue;
- }
-
- da = (const data_array *)du;
-
- if (du->type != TYPE_ARRAY || !array_is_kvstring(&da->value)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected value for url.redirect; expected list of \"regex\" => \"redirect\"");
- return HANDLER_ERROR;
- }
-
- for (j = 0; j < da->value.used; j++) {
- data_string *ds = (data_string *)da->value.data[j];
- if (srv->srvconf.http_url_normalize) {
- pcre_keyvalue_burl_normalize_key(&ds->key, srv->tmp_buf);
- pcre_keyvalue_burl_normalize_value(&ds->value, srv->tmp_buf);
- }
- if (0 != pcre_keyvalue_buffer_append(srv, s->redirect, &ds->key, &ds->value)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "pcre-compile failed for", &ds->key);
- return HANDLER_ERROR;
- }
- }
- }
-
- return HANDLER_GO_ON;
+static void mod_redirect_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv, const int idx) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* url.redirect */
+ if (cpv->vtype == T_CONFIG_LOCAL) {
+ pconf->redirect = cpv->v.v;
+ pconf->context_ndx = idx;
+ }
+ break;
+ case 1: /* url.redirect-code */
+ pconf->redirect_code = cpv->v.shrt;
+ break;
+ default:/* should not happen */
+ return;
+ }
}
-static int mod_redirect_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
+static void mod_redirect_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv, const int idx) {
+ do {
+ mod_redirect_merge_config_cpv(pconf, cpv, idx);
+ } while ((++cpv)->k_id != -1);
+}
- p->conf.redirect = s->redirect;
- p->conf.redirect_code = s->redirect_code;
- p->conf.context = NULL;
+static void mod_redirect_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_redirect_merge_config(&p->conf,
+ p->cvlist + p->cvlist[i].v.u2[0], i);
+ }
+}
- /* 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];
+static pcre_keyvalue_buffer * mod_redirect_parse_list(server *srv, const array *a) {
+ pcre_keyvalue_buffer * const redirect = pcre_keyvalue_buffer_init();
+ for (uint32_t j = 0; j < a->used; j++) {
+ data_string *ds = (data_string *)a->data[j];
+ if (srv->srvconf.http_url_normalize) {
+ pcre_keyvalue_burl_normalize_key(&ds->key, srv->tmp_buf);
+ pcre_keyvalue_burl_normalize_value(&ds->value, srv->tmp_buf);
+ }
+ if (0 != pcre_keyvalue_buffer_append(srv,redirect,&ds->key,&ds->value)){
+ log_error(srv->errh, __FILE__, __LINE__,
+ "pcre-compile failed for %s", ds->key.ptr);
+ pcre_keyvalue_buffer_free(redirect);
+ return NULL;
+ }
+ }
+ return redirect;
+}
- /* condition didn't match */
- if (!config_check_cond(srv, con, dc)) continue;
+SETDEFAULTS_FUNC(mod_redirect_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("url.redirect"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("url.redirect-code"),
+ T_CONFIG_SHORT,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_redirect"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* url.redirect */
+ if (!array_is_kvstring(cpv->v.a)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s; "
+ "expected list of \"regex\" => \"redirect\"",
+ cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ cpv->v.v = mod_redirect_parse_list(srv, cpv->v.a);
+ if (NULL == cpv->v.v) return HANDLER_ERROR;
+ cpv->vtype = T_CONFIG_LOCAL;
+ break;
+ case 1: /* url.redirect-code */
+ if (cpv->v.shrt < 100 || cpv->v.shrt >= 1000) cpv->v.shrt = 301;
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+ }
- /* merge config */
- for (j = 0; j < dc->value->used; j++) {
- data_unset *du = dc->value->data[j];
+ p->defaults.redirect_code = 301;
- if (0 == strcmp(du->key.ptr, "url.redirect")) {
- p->conf.redirect = s->redirect;
- p->conf.context = dc;
- } else if (0 == strcmp(du->key.ptr, "url.redirect-code")) {
- p->conf.redirect_code = s->redirect_code;
- }
- }
- }
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_redirect_merge_config(&p->defaults, cpv, 0);
+ }
- return 0;
+ return HANDLER_GO_ON;
}
URIHANDLER_FUNC(mod_redirect_uri_handler) {
@@ -152,10 +170,10 @@ URIHANDLER_FUNC(mod_redirect_uri_handler) {
pcre_keyvalue_ctx ctx;
handler_t rc;
- mod_redirect_patch_connection(srv, con, p);
+ mod_redirect_patch_config(con, p);
if (!p->conf.redirect->used) return HANDLER_GO_ON;
- ctx.cache = p->conf.context
- ? &con->cond_cache[p->conf.context->context_ndx]
+ ctx.cache = p->conf.context_ndx
+ ? &con->cond_cache[p->conf.context_ndx]
: NULL;
ctx.burl = &burl;
burl.scheme = con->uri.scheme;
@@ -190,14 +208,12 @@ URIHANDLER_FUNC(mod_redirect_uri_handler) {
int mod_redirect_plugin_init(plugin *p);
int mod_redirect_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("redirect");
+ p->name = "redirect";
p->init = mod_redirect_init;
p->handle_uri_clean = mod_redirect_uri_handler;
p->set_defaults = mod_redirect_set_defaults;
p->cleanup = mod_redirect_free;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_rewrite.c b/src/mod_rewrite.c
index 951d773d..d9988232 100644
--- a/src/mod_rewrite.c
+++ b/src/mod_rewrite.c
@@ -15,7 +15,7 @@
typedef struct {
pcre_keyvalue_buffer *rewrite;
pcre_keyvalue_buffer *rewrite_NF;
- data_config *context, *context_NF; /* to which apply me */
+ int context_ndx, context_ndx_NF; /* to which apply me */
int rewrite_repeat_idx, rewrite_NF_repeat_idx;
} plugin_config;
@@ -166,46 +166,45 @@ static int mod_rewrite_patch_connection(server *srv, connection *con, plugin_dat
PATCH(rewrite);
PATCH(rewrite_NF);
- p->conf.context = NULL;
- p->conf.context_NF = NULL;
+ p->conf.context_ndx = 0;
+ p->conf.context_ndx_NF = 0;
PATCH(rewrite_repeat_idx);
PATCH(rewrite_NF_repeat_idx);
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
+ if (!config_check_cond(con, i)) continue; /* condition not matched */
+
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("url.rewrite"))) {
PATCH(rewrite);
- p->conf.context = dc;
+ p->conf.context_ndx = i;
PATCH(rewrite_repeat_idx);
} else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("url.rewrite-once"))) {
PATCH(rewrite);
- p->conf.context = dc;
+ p->conf.context_ndx = i;
PATCH(rewrite_repeat_idx);
} else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("url.rewrite-repeat"))) {
PATCH(rewrite);
- p->conf.context = dc;
+ p->conf.context_ndx = i;
PATCH(rewrite_repeat_idx);
} else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("url.rewrite-if-not-file"))) {
PATCH(rewrite_NF);
- p->conf.context_NF = dc;
+ p->conf.context_ndx_NF = i;
PATCH(rewrite_NF_repeat_idx);
} else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("url.rewrite-repeat-if-not-file"))) {
PATCH(rewrite_NF);
- p->conf.context_NF = dc;
+ p->conf.context_ndx_NF = i;
PATCH(rewrite_NF_repeat_idx);
} else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("url.rewrite-final"))) {
PATCH(rewrite);
- p->conf.context = dc;
+ p->conf.context_ndx = i;
PATCH(rewrite_repeat_idx);
}
}
@@ -237,12 +236,12 @@ static handler_t process_rewrite_rules(server *srv, connection *con, plugin_data
hctx = con->plugin_ctx[p->id];
if (hctx->loops++ > 100) {
- data_config *dc = p->conf.context;
- if (NULL == dc) {
+ if (0 == p->conf.context_ndx) {
log_error_write(srv, __FILE__, __LINE__, "s",
"ENDLESS LOOP IN rewrite-rule DETECTED ... aborting request");
return HANDLER_ERROR;
}
+ data_config *dc = (data_config *)srv->config_context->data[p->conf.context_ndx];
log_error_write(srv, __FILE__, __LINE__, "SbsSBS",
"ENDLESS LOOP IN rewrite-rule DETECTED ... aborting request, perhaps you want to use url.rewrite-once instead of url.rewrite-repeat ($", dc->comp_key, dc->op, "\"", &dc->string, "\")");
@@ -252,7 +251,7 @@ static handler_t process_rewrite_rules(server *srv, connection *con, plugin_data
if (hctx->state == REWRITE_STATE_FINISHED) return HANDLER_GO_ON;
}
- ctx.cache = p->conf.context ? &con->cond_cache[p->conf.context->context_ndx] : NULL;
+ ctx.cache = p->conf.context_ndx ? &con->cond_cache[p->conf.context_ndx] : NULL;
ctx.burl = &burl;
burl.scheme = con->uri.scheme;
burl.authority = con->uri.authority;
@@ -296,7 +295,7 @@ URIHANDLER_FUNC(mod_rewrite_physical) {
if (con->mode != DIRECT) return HANDLER_GO_ON;
mod_rewrite_patch_connection(srv, con, p);
- p->conf.context = p->conf.context_NF;
+ p->conf.context_ndx = p->conf.context_ndx_NF;
if (!p->conf.rewrite_NF->used) return HANDLER_GO_ON;
/* skip if physical.path is a regular file */
@@ -320,7 +319,7 @@ URIHANDLER_FUNC(mod_rewrite_uri_handler) {
int mod_rewrite_plugin_init(plugin *p);
int mod_rewrite_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("rewrite");
+ p->name = "rewrite";
p->init = mod_rewrite_init;
/* it has to stay _raw as we are matching on uri + querystring
@@ -332,7 +331,5 @@ int mod_rewrite_plugin_init(plugin *p) {
p->connection_reset = mod_rewrite_con_reset;
p->set_defaults = mod_rewrite_set_defaults;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_rrdtool.c b/src/mod_rrdtool.c
index 876dafa5..fb82424d 100644
--- a/src/mod_rrdtool.c
+++ b/src/mod_rrdtool.c
@@ -255,12 +255,11 @@ static int mod_rrd_patch_connection(server *srv, connection *con, plugin_data *p
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
+ if (!config_check_cond(con, i)) continue; /* condition not matched */
+
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];
@@ -466,7 +465,7 @@ REQUESTDONE_FUNC(mod_rrd_account) {
int mod_rrdtool_plugin_init(plugin *p);
int mod_rrdtool_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("rrd");
+ p->name = "rrd";
p->init = mod_rrd_init;
p->cleanup = mod_rrd_free;
@@ -476,7 +475,5 @@ int mod_rrdtool_plugin_init(plugin *p) {
p->handle_waitpid = mod_rrd_waitpid_cb;
p->handle_request_done = mod_rrd_account;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_scgi.c b/src/mod_scgi.c
index 80aa682d..13e33a43 100644
--- a/src/mod_scgi.c
+++ b/src/mod_scgi.c
@@ -241,12 +241,11 @@ static int scgi_patch_connection(server *srv, connection *con, plugin_data *p) {
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
+ if (!config_check_cond(con, i)) continue; /* condition not matched */
+
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];
@@ -309,7 +308,7 @@ static handler_t scgi_check_extension_2(server *srv, connection *con, void *p_d)
int mod_scgi_plugin_init(plugin *p);
int mod_scgi_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("scgi");
+ p->name = "scgi";
p->init = gw_init;
p->cleanup = gw_free;
@@ -321,7 +320,5 @@ int mod_scgi_plugin_init(plugin *p) {
p->handle_trigger = gw_handle_trigger;
p->handle_waitpid = gw_handle_waitpid_cb;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_secdownload.c b/src/mod_secdownload.c
index fba53c47..6d0f8130 100644
--- a/src/mod_secdownload.c
+++ b/src/mod_secdownload.c
@@ -82,22 +82,20 @@ typedef enum {
} secdl_algorithm;
typedef struct {
- buffer *doc_root;
- buffer *secret;
- buffer *uri_prefix;
- secdl_algorithm algorithm;
-
- unsigned int timeout;
- unsigned short path_segments;
- unsigned short hash_querystr;
+ const buffer *doc_root;
+ const buffer *secret;
+ const buffer *uri_prefix;
+ secdl_algorithm algorithm;
+
+ unsigned int timeout;
+ unsigned short path_segments;
+ unsigned short hash_querystr;
} plugin_config;
typedef struct {
- PLUGIN_DATA;
-
- plugin_config **config_storage;
-
- plugin_config conf;
+ PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
} plugin_data;
static int const_time_memeq(const char *a, const char *b, size_t len) {
@@ -117,7 +115,7 @@ static const char* secdl_algorithm_names[] = {
"hmac-sha256",
};
-static secdl_algorithm algorithm_from_string(buffer *name) {
+static secdl_algorithm algorithm_from_string(const buffer *name) {
size_t ndx;
if (buffer_string_is_empty(name)) return SECDL_INVALID;
@@ -227,117 +225,155 @@ static int secdl_verify_mac(server *srv, plugin_config *config, const char* prot
return 0;
}
-/* init the plugin data */
INIT_FUNC(mod_secdownload_init) {
- plugin_data *p;
-
- p = calloc(1, sizeof(*p));
-
- return p;
+ return calloc(1, sizeof(plugin_data));
}
-/* detroy the plugin data */
FREE_FUNC(mod_secdownload_free) {
- plugin_data *p = p_d;
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+ UNUSED(srv);
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
+ free(p->cvlist);
+ free(p);
- if (NULL == s) continue;
-
- buffer_free(s->secret);
- buffer_free(s->doc_root);
- buffer_free(s->uri_prefix);
+ return HANDLER_GO_ON;
+}
- free(s);
- }
- free(p->config_storage);
- }
+static int mod_secdownload_parse_algorithm(server * const srv, config_plugin_value_t * const cpv) {
+ secdl_algorithm algorithm = algorithm_from_string(cpv->v.b);
+ switch (algorithm) {
+ case SECDL_INVALID:
+ log_error(srv->errh, __FILE__, __LINE__,
+ "invalid secdownload.algorithm: %s", cpv->v.b->ptr);
+ return 0;
+ #ifndef USE_OPENSSL_CRYPTO
+ case SECDL_HMAC_SHA1:
+ case SECDL_HMAC_SHA256:
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unsupported secdownload.algorithm: %s", cpv->v.b->ptr);
+ /*return 0;*/
+ /* proceed to allow config to load for other tests */
+ /* (use of unsupported algorithm will result in failure at runtime) */
+ break;
+ #endif
+ default:
+ break;
+ }
+
+ cpv->vtype = T_CONFIG_INT;
+ cpv->v.u = algorithm;
+ return 1;
+}
- free(p);
+static void mod_secdownload_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* secdownload.secret */
+ pconf->secret = cpv->v.b;
+ break;
+ case 1: /* secdownload.document-root */
+ pconf->doc_root = cpv->v.b;
+ break;
+ case 2: /* secdownload.uri-prefix */
+ pconf->uri_prefix = cpv->v.b;
+ break;
+ case 3: /* secdownload.timeout */
+ pconf->timeout = cpv->v.u;
+ break;
+ case 4: /* secdownload.algorithm */
+ pconf->algorithm = cpv->v.u; /* mod_secdownload_parse_algorithm() */
+ break;
+ case 5: /* secdownload.path-segments */
+ pconf->path_segments = cpv->v.shrt;
+ break;
+ case 6: /* secdownload.hash-querystr */
+ pconf->hash_querystr = cpv->v.u;
+ break;
+ default:/* should not happen */
+ return;
+ }
+}
- return HANDLER_GO_ON;
+static void mod_secdownload_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_secdownload_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
}
-/* handle plugin config and check values */
+static void mod_secdownload_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_secdownload_merge_config(&p->conf, p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
SETDEFAULTS_FUNC(mod_secdownload_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { "secdownload.secret", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { "secdownload.document-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { "secdownload.uri-prefix", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
- { "secdownload.timeout", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
- { "secdownload.algorithm", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
- { "secdownload.path-segments", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
- { "secdownload.hash-querystr", NULL, T_CONFIG_BOOLEAN,T_CONFIG_SCOPE_CONNECTION }, /* 6 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
- buffer *algorithm = buffer_init();
-
- s = calloc(1, sizeof(plugin_config));
- s->secret = buffer_init();
- s->doc_root = buffer_init();
- s->uri_prefix = buffer_init();
- s->timeout = 60;
- s->path_segments = 0;
- s->hash_querystr = 0;
-
- cv[0].destination = s->secret;
- cv[1].destination = s->doc_root;
- cv[2].destination = s->uri_prefix;
- cv[3].destination = &(s->timeout);
- cv[4].destination = algorithm;
- cv[5].destination = &(s->path_segments);
- cv[6].destination = &(s->hash_querystr);
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- buffer_free(algorithm);
- return HANDLER_ERROR;
- }
-
- if (!buffer_is_empty(algorithm)) {
- s->algorithm = algorithm_from_string(algorithm);
- switch (s->algorithm) {
- case SECDL_INVALID:
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "invalid secdownload.algorithm:",
- algorithm);
- buffer_free(algorithm);
- return HANDLER_ERROR;
-#ifndef USE_OPENSSL_CRYPTO
- case SECDL_HMAC_SHA1:
- case SECDL_HMAC_SHA256:
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "unsupported secdownload.algorithm:",
- algorithm);
-#endif
- default:
- break;
- }
- }
-
- buffer_free(algorithm);
- }
-
- return HANDLER_GO_ON;
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("secdownload.secret"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("secdownload.document-root"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("secdownload.uri-prefix"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("secdownload.timeout"),
+ T_CONFIG_INT,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("secdownload.algorithm"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("secdownload.path-segments"),
+ T_CONFIG_SHORT,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("secdownload.hash-querystr"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_secdownload"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* secdownload.secret */
+ case 1: /* secdownload.document-root */
+ case 2: /* secdownload.uri-prefix */
+ case 3: /* secdownload.timeout */
+ break;
+ case 4: /* secdownload.algorithm */
+ if (!mod_secdownload_parse_algorithm(srv, cpv))
+ return HANDLER_ERROR;
+ break;
+ case 5: /* secdownload.path-segments */
+ case 6: /* secdownload.hash-querystr */
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+ }
+
+ p->defaults.timeout = 60;
+
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_secdownload_merge_config(&p->defaults, cpv);
+ }
+
+ return HANDLER_GO_ON;
}
/**
@@ -391,55 +427,6 @@ static int is_base64_len(const char *str, size_t len) {
return i == len;
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_secdownload_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(secret);
- PATCH(doc_root);
- PATCH(uri_prefix);
- PATCH(timeout);
- PATCH(algorithm);
- PATCH(path_segments);
- PATCH(hash_querystr);
-
- /* 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("secdownload.secret"))) {
- PATCH(secret);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("secdownload.document-root"))) {
- PATCH(doc_root);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("secdownload.uri-prefix"))) {
- PATCH(uri_prefix);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("secdownload.timeout"))) {
- PATCH(timeout);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("secdownload.algorithm"))) {
- PATCH(algorithm);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("secdownload.path-segments"))) {
- PATCH(path_segments);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("secdownload.hash-querystr"))) {
- PATCH(hash_querystr);
- }
- }
- }
-
- return 0;
-}
-#undef PATCH
-
-
URIHANDLER_FUNC(mod_secdownload_uri_handler) {
plugin_data *p = p_d;
const char *rel_uri, *ts_str, *mac_str, *protected_path;
@@ -450,7 +437,7 @@ URIHANDLER_FUNC(mod_secdownload_uri_handler) {
if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
- mod_secdownload_patch_connection(srv, con, p);
+ mod_secdownload_patch_config(con, p);
if (buffer_string_is_empty(p->conf.uri_prefix)) return HANDLER_GO_ON;
@@ -553,19 +540,16 @@ URIHANDLER_FUNC(mod_secdownload_uri_handler) {
return HANDLER_GO_ON;
}
-/* this function is called at dlopen() time and inits the callbacks */
int mod_secdownload_plugin_init(plugin *p);
int mod_secdownload_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("secdownload");
+ p->name = "secdownload";
p->init = mod_secdownload_init;
p->handle_physical = mod_secdownload_uri_handler;
p->set_defaults = mod_secdownload_set_defaults;
p->cleanup = mod_secdownload_free;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_setenv.c b/src/mod_setenv.c
index 6f5c6528..63197834 100644
--- a/src/mod_setenv.c
+++ b/src/mod_setenv.c
@@ -1,8 +1,9 @@
#include "first.h"
#include "base.h"
-#include "log.h"
+#include "array.h"
#include "buffer.h"
+#include "log.h"
#include "http_header.h"
#include "plugin.h"
@@ -10,294 +11,274 @@
#include <stdlib.h>
#include <string.h>
-/* plugin config for all request/connections */
-
typedef struct {
- array *request_header;
- array *set_request_header;
- array *response_header;
- array *set_response_header;
- array *environment;
- array *set_environment;
+ const array *request_header;
+ const array *set_request_header;
+ const array *response_header;
+ const array *set_response_header;
+ const array *environment;
+ const array *set_environment;
} plugin_config;
typedef struct {
- PLUGIN_DATA;
-
- plugin_config **config_storage;
-
- plugin_config conf;
+ PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
} plugin_data;
typedef struct {
- int handled; /* make sure that we only apply the headers once */
- plugin_config conf;
+ int handled; /* make sure that we only apply the headers once */
+ plugin_config conf;
} handler_ctx;
static handler_ctx * handler_ctx_init(void) {
- handler_ctx * hctx;
-
- hctx = calloc(1, sizeof(*hctx));
-
- hctx->handled = 0;
-
- return hctx;
+ handler_ctx * const hctx = calloc(1, sizeof(handler_ctx));
+ force_assert(hctx);
+ return hctx;
}
static void handler_ctx_free(handler_ctx *hctx) {
- free(hctx);
+ free(hctx);
}
-
-/* init the plugin data */
INIT_FUNC(mod_setenv_init) {
- plugin_data *p;
-
- p = calloc(1, sizeof(*p));
-
- return p;
+ return calloc(1, sizeof(plugin_data));
}
-/* detroy the plugin data */
FREE_FUNC(mod_setenv_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- 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];
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+ UNUSED(srv);
- if (NULL == s) continue;
+ free(p->cvlist);
+ free(p);
- array_free(s->request_header);
- array_free(s->response_header);
- array_free(s->environment);
- array_free(s->set_request_header);
- array_free(s->set_response_header);
- array_free(s->set_environment);
-
- free(s);
- }
- free(p->config_storage);
- }
-
- free(p);
-
- return HANDLER_GO_ON;
+ return HANDLER_GO_ON;
}
-/* handle plugin config and check values */
+static void mod_setenv_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* setenv.add-request-header */
+ pconf->request_header = cpv->v.a;
+ break;
+ case 1: /* setenv.add-response-header */
+ pconf->response_header = cpv->v.a;
+ break;
+ case 2: /* setenv.add-environment */
+ pconf->environment = cpv->v.a;
+ break;
+ case 3: /* setenv.set-request-header */
+ pconf->set_request_header = cpv->v.a;
+ break;
+ case 4: /* setenv.set-response-header */
+ pconf->set_response_header = cpv->v.a;
+ break;
+ case 5: /* setenv.set-environment */
+ pconf->set_environment = cpv->v.a;
+ break;
+ default:/* should not happen */
+ return;
+ }
+}
-SETDEFAULTS_FUNC(mod_setenv_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { "setenv.add-request-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { "setenv.add-response-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { "setenv.add-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
- { "setenv.set-request-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
- { "setenv.set-response-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
- { "setenv.set-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->request_header = array_init();
- s->response_header = array_init();
- s->environment = array_init();
- s->set_request_header = array_init();
- s->set_response_header = array_init();
- s->set_environment = array_init();
-
- cv[0].destination = s->request_header;
- cv[1].destination = s->response_header;
- cv[2].destination = s->environment;
- cv[3].destination = s->set_request_header;
- cv[4].destination = s->set_response_header;
- cv[5].destination = s->set_environment;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
-
- if ( !array_is_kvstring(s->request_header)
- || !array_is_kvstring(s->response_header)
- || !array_is_kvstring(s->environment)
- || !array_is_kvstring(s->set_request_header)
- || !array_is_kvstring(s->set_response_header)
- || !array_is_kvstring(s->set_environment)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected value for setenv.xxxxxx; expected list of \"envvar\" => \"value\"");
- return HANDLER_ERROR;
- }
-
- }
-
- return HANDLER_GO_ON;
+static void mod_setenv_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_setenv_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_setenv_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(request_header);
- PATCH(set_request_header);
- PATCH(response_header);
- PATCH(set_response_header);
- PATCH(environment);
- PATCH(set_environment);
-
- /* 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("setenv.add-request-header"))) {
- PATCH(request_header);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("setenv.set-request-header"))) {
- PATCH(set_request_header);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("setenv.add-response-header"))) {
- PATCH(response_header);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("setenv.set-response-header"))) {
- PATCH(set_response_header);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("setenv.add-environment"))) {
- PATCH(environment);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("setenv.set-environment"))) {
- PATCH(set_environment);
- }
- }
- }
+static void mod_setenv_patch_config(connection * const con, plugin_data * const p, plugin_config * const pconf) {
+ memcpy(pconf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_setenv_merge_config(pconf, p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
- return 0;
+SETDEFAULTS_FUNC(mod_setenv_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("setenv.add-request-header"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("setenv.add-response-header"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("setenv.add-environment"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("setenv.set-request-header"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("setenv.set-response-header"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("setenv.set-environment"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_setenv"))
+ return HANDLER_ERROR;
+
+ /* future: might create custom data structures here
+ * then look up and store http_header_e at config time
+ * enum http_header_e id = http_header_hkey_get(CONST_BUF_LEN(&ds->key));
+ */
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* setenv.add-request-header */
+ case 1: /* setenv.add-response-header */
+ case 2: /* setenv.add-environment */
+ case 3: /* setenv.set-request-header */
+ case 4: /* setenv.set-response-header */
+ case 5: /* setenv.set-environment */
+ if (!array_is_kvstring(cpv->v.a)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s; "
+ "expected list of \"key\" => \"value\"",cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+ }
+
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_setenv_merge_config(&p->defaults, cpv);
+ }
+
+ return HANDLER_GO_ON;
}
-#undef PATCH
URIHANDLER_FUNC(mod_setenv_uri_handler) {
- plugin_data *p = p_d;
- size_t k;
- handler_ctx *hctx;
-
- if (con->plugin_ctx[p->id]) {
- hctx = con->plugin_ctx[p->id];
- } else {
- hctx = handler_ctx_init();
-
- con->plugin_ctx[p->id] = hctx;
- }
-
- if (hctx->handled) {
- return HANDLER_GO_ON;
- }
-
- hctx->handled = 1;
-
- mod_setenv_patch_connection(srv, con, p);
- memcpy(&hctx->conf, &p->conf, sizeof(plugin_config));
-
- for (k = 0; k < p->conf.request_header->used; k++) {
- data_string *ds = (data_string *)p->conf.request_header->data[k];
- enum http_header_e id = http_header_hkey_get(CONST_BUF_LEN(&ds->key));
- http_header_request_append(con, id, CONST_BUF_LEN(&ds->key), CONST_BUF_LEN(&ds->value));
- }
-
- for (k = 0; k < hctx->conf.set_request_header->used; ++k) {
- data_string *ds = (data_string *)hctx->conf.set_request_header->data[k];
- enum http_header_e id = http_header_hkey_get(CONST_BUF_LEN(&ds->key));
- !buffer_string_is_empty(&ds->value)
- ? http_header_request_set(con, id, CONST_BUF_LEN(&ds->key), CONST_BUF_LEN(&ds->value))
- : http_header_request_unset(con, id, CONST_BUF_LEN(&ds->key));
- }
-
- return HANDLER_GO_ON;
+ plugin_data *p = p_d;
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+ if (!hctx)
+ con->plugin_ctx[p->id] = hctx = handler_ctx_init();
+ else if (hctx->handled)
+ return HANDLER_GO_ON;
+ hctx->handled = 1;
+ UNUSED(srv);
+
+ mod_setenv_patch_config(con, p, &hctx->conf);
+
+ const array * const aa = hctx->conf.request_header;
+ const array * const as = hctx->conf.set_request_header;
+
+ if (aa) {
+ for (uint32_t k = 0; k < aa->used; ++k) {
+ const data_string * const ds = (const data_string *)aa->data[k];
+ const enum http_header_e id =
+ http_header_hkey_get(CONST_BUF_LEN(&ds->key));
+ http_header_request_append(con, id, CONST_BUF_LEN(&ds->key),
+ CONST_BUF_LEN(&ds->value));
+ }
+ }
+
+ if (as) {
+ for (uint32_t k = 0; k < as->used; ++k) {
+ const data_string * const ds = (const data_string *)as->data[k];
+ const enum http_header_e id =
+ http_header_hkey_get(CONST_BUF_LEN(&ds->key));
+ !buffer_string_is_empty(&ds->value)
+ ? http_header_request_set(con, id, CONST_BUF_LEN(&ds->key),
+ CONST_BUF_LEN(&ds->value))
+ : http_header_request_unset(con, id, CONST_BUF_LEN(&ds->key));
+ }
+ }
+
+ return HANDLER_GO_ON;
}
CONNECTION_FUNC(mod_setenv_handle_request_env) {
- plugin_data *p = p_d;
- handler_ctx *hctx = con->plugin_ctx[p->id];
- if (NULL == hctx) return HANDLER_GO_ON;
- if (hctx->handled > 1) return HANDLER_GO_ON;
- hctx->handled = 2;
- UNUSED(srv);
-
- for (size_t k = 0; k < hctx->conf.environment->used; ++k) {
- data_string *ds = (data_string *)hctx->conf.environment->data[k];
- http_header_env_append(con, CONST_BUF_LEN(&ds->key), CONST_BUF_LEN(&ds->value));
- }
-
- for (size_t k = 0; k < hctx->conf.set_environment->used; ++k) {
- data_string *ds = (data_string *)hctx->conf.set_environment->data[k];
- http_header_env_set(con, CONST_BUF_LEN(&ds->key), CONST_BUF_LEN(&ds->value));
- }
-
- return HANDLER_GO_ON;
+ plugin_data *p = p_d;
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+ if (NULL == hctx) return HANDLER_GO_ON;
+ if (hctx->handled > 1) return HANDLER_GO_ON;
+ hctx->handled = 2;
+ UNUSED(srv);
+
+ const array * const aa = hctx->conf.environment;
+ const array * const as = hctx->conf.set_environment;
+
+ if (aa) {
+ for (uint32_t k = 0; k < hctx->conf.environment->used; ++k) {
+ const data_string * const ds = (const data_string *)aa->data[k];
+ http_header_env_append(con, CONST_BUF_LEN(&ds->key),
+ CONST_BUF_LEN(&ds->value));
+ }
+ }
+
+ if (as) {
+ for (uint32_t k = 0; k < as->used; ++k) {
+ const data_string * const ds = (const data_string *)as->data[k];
+ http_header_env_set(con, CONST_BUF_LEN(&ds->key),
+ CONST_BUF_LEN(&ds->value));
+ }
+ }
+
+ return HANDLER_GO_ON;
}
CONNECTION_FUNC(mod_setenv_handle_response_start) {
- plugin_data *p = p_d;
- handler_ctx *hctx = con->plugin_ctx[p->id];
- if (NULL == hctx) return HANDLER_GO_ON;
- UNUSED(srv);
-
- for (size_t k = 0; k < hctx->conf.response_header->used; ++k) {
- data_string *ds = (data_string *)hctx->conf.response_header->data[k];
- enum http_header_e id = http_header_hkey_get(CONST_BUF_LEN(&ds->key));
- http_header_response_insert(con, id, CONST_BUF_LEN(&ds->key), CONST_BUF_LEN(&ds->value));
- }
-
- for (size_t k = 0; k < hctx->conf.set_response_header->used; ++k) {
- data_string *ds = (data_string *)hctx->conf.set_response_header->data[k];
- enum http_header_e id = http_header_hkey_get(CONST_BUF_LEN(&ds->key));
- !buffer_string_is_empty(&ds->value)
- ? http_header_response_set(con, id, CONST_BUF_LEN(&ds->key), CONST_BUF_LEN(&ds->value))
- : http_header_response_unset(con, id, CONST_BUF_LEN(&ds->key));
- }
-
- return HANDLER_GO_ON;
+ plugin_data *p = p_d;
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+ if (NULL == hctx) return HANDLER_GO_ON;
+ UNUSED(srv);
+
+ const array * const aa = hctx->conf.response_header;
+ const array * const as = hctx->conf.set_response_header;
+
+ if (aa) {
+ for (uint32_t k = 0; k < aa->used; ++k) {
+ const data_string * const ds = (const data_string *)aa->data[k];
+ const enum http_header_e id =
+ http_header_hkey_get(CONST_BUF_LEN(&ds->key));
+ http_header_response_insert(con, id, CONST_BUF_LEN(&ds->key),
+ CONST_BUF_LEN(&ds->value));
+ }
+ }
+
+ if (as) {
+ for (uint32_t k = 0; k < as->used; ++k) {
+ const data_string * const ds = (const data_string *)as->data[k];
+ const enum http_header_e id =
+ http_header_hkey_get(CONST_BUF_LEN(&ds->key));
+ !buffer_string_is_empty(&ds->value)
+ ? http_header_response_set(con, id, CONST_BUF_LEN(&ds->key),
+ CONST_BUF_LEN(&ds->value))
+ : http_header_response_unset(con, id, CONST_BUF_LEN(&ds->key));
+ }
+ }
+
+ return HANDLER_GO_ON;
}
CONNECTION_FUNC(mod_setenv_reset) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (con->plugin_ctx[p->id]) {
- handler_ctx_free(con->plugin_ctx[p->id]);
- con->plugin_ctx[p->id] = NULL;
- }
-
- return HANDLER_GO_ON;
+ void ** const hctx = con->plugin_ctx + ((plugin_data_base *)p_d)->id;
+ if (*hctx) { handler_ctx_free(*hctx); *hctx = NULL; }
+ UNUSED(srv);
+ return HANDLER_GO_ON;
}
-/* this function is called at dlopen() time and inits the callbacks */
-
int mod_setenv_plugin_init(plugin *p);
int mod_setenv_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("setenv");
+ p->name = "setenv";
p->init = mod_setenv_init;
p->handle_uri_clean = mod_setenv_uri_handler;
@@ -308,7 +289,5 @@ int mod_setenv_plugin_init(plugin *p) {
p->connection_reset = mod_setenv_reset;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_simple_vhost.c b/src/mod_simple_vhost.c
index ef456c4f..a238fe18 100644
--- a/src/mod_simple_vhost.c
+++ b/src/mod_simple_vhost.c
@@ -12,124 +12,130 @@
#include <errno.h>
typedef struct {
- buffer *server_root;
- buffer *default_host;
- buffer *document_root;
-
- buffer *docroot_cache_key;
- buffer *docroot_cache_value;
- buffer *docroot_cache_servername;
-
- unsigned short debug;
+ const buffer *server_root;
+ const buffer *default_host;
+ const buffer *document_root;
+ unsigned short debug;
} plugin_config;
typedef struct {
- PLUGIN_DATA;
-
- buffer *doc_root;
+ PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
- plugin_config **config_storage;
- plugin_config conf;
+ buffer tmp_buf;
+ buffer last_root;
} plugin_data;
INIT_FUNC(mod_simple_vhost_init) {
- plugin_data *p;
-
- p = calloc(1, sizeof(*p));
-
- p->doc_root = buffer_init();
-
- return p;
+ return calloc(1, sizeof(plugin_data));
}
FREE_FUNC(mod_simple_vhost_free) {
- plugin_data *p = p_d;
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+ UNUSED(srv);
- UNUSED(srv);
+ free(p->tmp_buf.ptr);
+ free(p->last_root.ptr);
- if (!p) return HANDLER_GO_ON;
+ free(p->cvlist);
+ free(p);
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
- if (NULL == s) continue;
-
- buffer_free(s->document_root);
- buffer_free(s->default_host);
- buffer_free(s->server_root);
-
- buffer_free(s->docroot_cache_key);
- buffer_free(s->docroot_cache_value);
- buffer_free(s->docroot_cache_servername);
-
- free(s);
- }
-
- free(p->config_storage);
- }
+ return HANDLER_GO_ON;
+}
- buffer_free(p->doc_root);
+static void mod_simple_vhost_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* simple-vhost.server-root */
+ pconf->server_root = cpv->v.b;
+ break;
+ case 1: /* simple-vhost.default-host */
+ pconf->default_host = cpv->v.b;
+ break;
+ case 2: /* simple-vhost.document-root */
+ pconf->document_root = cpv->v.b;
+ break;
+ case 3: /* simple-vhost.debug */
+ pconf->debug = cpv->v.shrt;
+ break;
+ default:/* should not happen */
+ return;
+ }
+}
- free(p);
+static void mod_simple_vhost_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_simple_vhost_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- return HANDLER_GO_ON;
+static void mod_simple_vhost_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_simple_vhost_merge_config(&p->conf,
+ p->cvlist + p->cvlist[i].v.u2[0]);
+ }
}
SETDEFAULTS_FUNC(mod_simple_vhost_set_defaults) {
- plugin_data *p = p_d;
- size_t i;
-
- config_values_t cv[] = {
- { "simple-vhost.server-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "simple-vhost.default-host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "simple-vhost.document-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "simple-vhost.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
-
- s->server_root = buffer_init();
- s->default_host = buffer_init();
- s->document_root = buffer_init();
-
- s->docroot_cache_key = buffer_init();
- s->docroot_cache_value = buffer_init();
- s->docroot_cache_servername = buffer_init();
-
- s->debug = 0;
-
- cv[0].destination = s->server_root;
- cv[1].destination = s->default_host;
- cv[2].destination = s->document_root;
- cv[3].destination = &(s->debug);
-
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
-
- if (!buffer_string_is_empty(s->server_root))
- buffer_append_slash(s->server_root);
- if (!buffer_string_is_empty(s->document_root))
- buffer_append_slash(s->document_root);
- }
-
- return HANDLER_GO_ON;
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("simple-vhost.server-root"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("simple-vhost.default-host"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("simple-vhost.document-root"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("simple-vhost.debug"),
+ T_CONFIG_SHORT,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_simple_vhost"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* simple-vhost.server-root */
+ case 2: /* simple-vhost.document-root */
+ if (!buffer_string_is_empty(cpv->v.b)) {
+ buffer *b;
+ *(const buffer **)&b = cpv->v.b;
+ buffer_append_slash(b);
+ }
+ break;
+ case 1: /* simple-vhost.default-host */
+ case 3: /* simple-vhost.debug */
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+ }
+
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_simple_vhost_merge_config(&p->defaults, cpv);
+ }
+
+ return HANDLER_GO_ON;
}
-static void build_doc_root_path(buffer *out, buffer *sroot, buffer *host, buffer *droot) {
+static void build_doc_root_path(buffer *out, const buffer *sroot, const buffer *host, const buffer *droot) {
force_assert(!buffer_string_is_empty(sroot));
buffer_copy_buffer(out, sroot);
@@ -153,138 +159,61 @@ static void build_doc_root_path(buffer *out, buffer *sroot, buffer *host, buffer
}
}
-static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *out, buffer *host) {
+static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *out, const buffer *host) {
stat_cache_entry *sce = NULL;
build_doc_root_path(out, p->conf.server_root, host, p->conf.document_root);
+ /* one-element cache (postive cache, not negative cache) */
+ if (buffer_is_equal(out, &p->last_root)) return 1;
+
if (HANDLER_ERROR == stat_cache_get_entry(srv, con, out, &sce)) {
if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "sb",
strerror(errno), out);
}
- return -1;
+ return 0;
} else if (!S_ISDIR(sce->st.st_mode)) {
- return -1;
+ return 0;
}
- return 0;
+ buffer_copy_buffer(&p->last_root, out);
+ return 1;
}
-
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_simple_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(server_root);
- PATCH(default_host);
- PATCH(document_root);
-
- PATCH(docroot_cache_key);
- PATCH(docroot_cache_value);
- PATCH(docroot_cache_servername);
-
- PATCH(debug);
-
- /* 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("simple-vhost.server-root"))) {
- PATCH(server_root);
- PATCH(docroot_cache_key);
- PATCH(docroot_cache_value);
- PATCH(docroot_cache_servername);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("simple-vhost.default-host"))) {
- PATCH(default_host);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("simple-vhost.document-root"))) {
- PATCH(document_root);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("simple-vhost.debug"))) {
- PATCH(debug);
- }
- }
- }
-
- return 0;
-}
-#undef PATCH
-
static handler_t mod_simple_vhost_docroot(server *srv, connection *con, void *p_data) {
- plugin_data *p = p_data;
-
- /*
- * cache the last successfull translation from hostname (authority) to docroot
- * - this saves us a stat() call
- *
- */
-
- mod_simple_vhost_patch_connection(srv, con, p);
-
- /* build_doc_root() requires a server_root; skip module if simple-vhost.server-root is not set
- * or set to an empty string (especially don't cache any results!)
- */
- if (buffer_string_is_empty(p->conf.server_root)) return HANDLER_GO_ON;
-
- if (!buffer_string_is_empty(p->conf.docroot_cache_key) &&
- !buffer_string_is_empty(con->uri.authority) &&
- buffer_is_equal(p->conf.docroot_cache_key, con->uri.authority)) {
- /* cache hit */
- con->server_name = con->server_name_buf;
- buffer_copy_buffer(con->server_name_buf, p->conf.docroot_cache_servername);
- buffer_copy_buffer(con->physical.doc_root, p->conf.docroot_cache_value);
- } else {
- /* build document-root */
- if (buffer_string_is_empty(con->uri.authority) ||
- build_doc_root(srv, con, p, p->doc_root, con->uri.authority)) {
- /* not found, fallback the default-host */
- if (0 == build_doc_root(srv, con, p,
- p->doc_root,
- p->conf.default_host)) {
- /* default host worked */
- con->server_name = con->server_name_buf;
- buffer_copy_buffer(con->server_name_buf, p->conf.default_host);
- buffer_copy_buffer(con->physical.doc_root, p->doc_root);
- /* do not cache default host */
- }
- return HANDLER_GO_ON;
- }
-
- /* found host */
- con->server_name = con->server_name_buf;
- buffer_copy_buffer(con->server_name_buf, con->uri.authority);
- buffer_copy_buffer(con->physical.doc_root, p->doc_root);
-
- /* copy to cache */
- buffer_copy_buffer(p->conf.docroot_cache_key, con->uri.authority);
- buffer_copy_buffer(p->conf.docroot_cache_value, p->doc_root);
- buffer_copy_buffer(p->conf.docroot_cache_servername, con->server_name);
- }
-
- return HANDLER_GO_ON;
+ plugin_data * const p = p_data;
+ mod_simple_vhost_patch_config(con, p);
+ if (buffer_string_is_empty(p->conf.server_root)) return HANDLER_GO_ON;
+ /* build_doc_root() requires p->conf.server_root;
+ * skip module if simple-vhost.server-root not set or set to empty string */
+
+ /* (default host and HANDLER_GO_ON instead of HANDLER_ERROR (on error)
+ * are the two differences between mod_simple_vhost and mod_vhostdb) */
+
+ /* build document-root */
+ buffer * const b = &p->tmp_buf;
+ const buffer *host = con->uri.authority;
+ if ((!buffer_string_is_empty(host) && build_doc_root(srv, con, p, b, host))
+ || build_doc_root(srv, con, p, b, (host = p->conf.default_host))) {
+ con->server_name = con->server_name_buf;
+ buffer_copy_buffer(con->server_name_buf, host);
+ buffer_copy_buffer(con->physical.doc_root, b);
+ }
+
+ return HANDLER_GO_ON;
}
int mod_simple_vhost_plugin_init(plugin *p);
int mod_simple_vhost_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("simple_vhost");
+ p->name = "simple_vhost";
p->init = mod_simple_vhost_init;
p->set_defaults = mod_simple_vhost_set_defaults;
p->handle_docroot = mod_simple_vhost_docroot;
p->cleanup = mod_simple_vhost_free;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_skeleton.c b/src/mod_skeleton.c
index c10954f1..93ef9c80 100644
--- a/src/mod_skeleton.c
+++ b/src/mod_skeleton.c
@@ -25,13 +25,13 @@
/* plugin config for all request/connections */
typedef struct {
- array *match;
+ const array *match;
} plugin_config;
typedef struct {
- PLUGIN_DATA;
- plugin_config **config_storage;
- plugin_config conf;
+ PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
} plugin_data;
@@ -56,94 +56,91 @@ static void handler_ctx_free(handler_ctx *hctx) {
/* init the plugin data */
INIT_FUNC(mod_skeleton_init) {
- return calloc(1, sizeof(plugin_data));
+ return calloc(1, sizeof(plugin_data));
}
/* destroy the plugin data */
FREE_FUNC(mod_skeleton_free) {
- plugin_data *p = p_d;
- UNUSED(srv);
- if (!p) return HANDLER_GO_ON;
- if (p->config_storage) {
- for (size_t i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
- if (NULL == s) continue;
- array_free(s->match);
- free(s);
- }
- free(p->config_storage);
- }
- free(p);
- return HANDLER_GO_ON;
-}
-
-/* handle plugin config and check values */
-SETDEFAULTS_FUNC(mod_skeleton_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { "skeleton.array", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
- force_assert(p->config_storage);
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s = calloc(1, sizeof(plugin_config));
- force_assert(s);
- s->match = array_init();
-
- cv[0].destination = s->match;
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+ UNUSED(srv);
- p->config_storage[i] = s;
+ free(p->cvlist);
+ free(p);
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
-
- if (!array_is_vlist(s->match)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected value for skeleton.array; expected list of \"urlpath\"");
- return HANDLER_ERROR;
- }
- }
-
- return HANDLER_GO_ON;
+ return HANDLER_GO_ON;
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_skeleton_patch_connection(server *srv, connection *con, plugin_data *p) {
- plugin_config *s = p->config_storage[0];
-
- PATCH(match);
-
- /* skip the first, the global context */
- for (size_t i = 1; i < srv->config_context->used; ++i) {
- data_config *dc = (data_config *)srv->config_context->data[i];
- s = p->config_storage[i];
+/* handle plugin config and check values */
- /* condition didn't match */
- if (!config_check_cond(srv, con, dc)) continue;
+static void mod_skeleton_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* skeleton.array */
+ pconf->match = cpv->v.a;
+ break;
+ default:/* should not happen */
+ return;
+ }
+}
- /* merge config */
- for (size_t j = 0; j < dc->value->used; ++j) {
- data_unset *du = dc->value->data[j];
+static void mod_skeleton_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_skeleton_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- if (buffer_is_equal_string(&du->key, CONST_STR_LEN("skeleton.array"))) {
- PATCH(match);
- }
- }
- }
+static void mod_skeleton_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_skeleton_merge_config(&p->conf,
+ p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
- return 0;
+SETDEFAULTS_FUNC(mod_skeleton_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("skeleton.array"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_skeleton"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* static-file.exclude-extensions */
+ if (!array_is_vlist(cpv->v.a)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s; "
+ "expected list of \"url-path\"", cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+ }
+
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_skeleton_merge_config(&p->defaults, cpv);
+ }
+
+ return HANDLER_GO_ON;
}
-#undef PATCH
URIHANDLER_FUNC(mod_skeleton_uri_handler) {
plugin_data *p = p_d;
@@ -155,9 +152,10 @@ URIHANDLER_FUNC(mod_skeleton_uri_handler) {
if (buffer_string_is_empty(con->uri.path)) return HANDLER_GO_ON;
/* get module config for request */
- mod_skeleton_patch_connection(srv, con, p);
+ mod_skeleton_patch_config(con, p);
- if (NULL == array_match_value_suffix(p->conf.match, con->uri.path)) {
+ if (NULL == p->conf.match
+ || NULL == array_match_value_suffix(p->conf.match, con->uri.path)) {
return HANDLER_GO_ON;
}
@@ -171,8 +169,7 @@ URIHANDLER_FUNC(mod_skeleton_uri_handler) {
int mod_skeleton_plugin_init(plugin *p);
int mod_skeleton_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("skeleton");
- p->data = NULL;
+ p->name = "skeleton";
p->init = mod_skeleton_init;
p->cleanup = mod_skeleton_free;
p->set_defaults= mod_skeleton_set_defaults;
diff --git a/src/mod_sockproxy.c b/src/mod_sockproxy.c
index 4e5b62b3..f365babe 100644
--- a/src/mod_sockproxy.c
+++ b/src/mod_sockproxy.c
@@ -107,12 +107,11 @@ static int mod_sockproxy_patch_connection(server *srv, connection *con, plugin_d
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
+ if (!config_check_cond(con, i)) continue; /* condition not matched */
+
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];
@@ -163,7 +162,7 @@ static handler_t mod_sockproxy_connection_accept(server *srv, connection *con, v
int mod_sockproxy_plugin_init(plugin *p);
int mod_sockproxy_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("sockproxy");
+ p->name = "sockproxy";
p->init = gw_init;
p->cleanup = gw_free;
@@ -174,7 +173,5 @@ int mod_sockproxy_plugin_init(plugin *p) {
p->handle_trigger = gw_handle_trigger;
p->handle_waitpid = gw_handle_waitpid_cb;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_ssi.c b/src/mod_ssi.c
index 4f9dfa0b..f264ce1f 100644
--- a/src/mod_ssi.c
+++ b/src/mod_ssi.c
@@ -55,11 +55,11 @@ static void handler_ctx_free(handler_ctx *hctx) {
/* The newest modified time of included files for include statement */
static volatile time_t include_file_last_mtime = 0;
-/* init the plugin data */
INIT_FUNC(mod_ssi_init) {
plugin_data *p;
p = calloc(1, sizeof(*p));
+ force_assert(p);
p->timefmt = buffer_init();
p->stat_fn = buffer_init();
@@ -70,88 +70,120 @@ INIT_FUNC(mod_ssi_init) {
return p;
}
-/* detroy the plugin data */
FREE_FUNC(mod_ssi_free) {
plugin_data *p = p_d;
UNUSED(srv);
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 (NULL == s) continue;
-
- array_free(s->ssi_extension);
- buffer_free(s->content_type);
-
- free(s);
- }
- free(p->config_storage);
- }
-
array_free(p->ssi_vars);
array_free(p->ssi_cgi_env);
buffer_free(p->timefmt);
buffer_free(p->stat_fn);
+ free(p->cvlist);
free(p);
return HANDLER_GO_ON;
}
-/* handle plugin config and check values */
-
-SETDEFAULTS_FUNC(mod_ssi_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { "ssi.extension", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { "ssi.content-type", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { "ssi.conditional-requests", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
- { "ssi.exec", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
- { "ssi.recursion-max", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->ssi_extension = array_init();
- s->content_type = buffer_init();
- s->conditional_requests = 0;
- s->ssi_exec = 1;
- s->ssi_recursion_max = 0;
-
- cv[0].destination = s->ssi_extension;
- cv[1].destination = s->content_type;
- cv[2].destination = &(s->conditional_requests);
- cv[3].destination = &(s->ssi_exec);
- cv[4].destination = &(s->ssi_recursion_max);
-
- p->config_storage[i] = s;
+static void mod_ssi_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* ssi.extension */
+ pconf->ssi_extension = cpv->v.a;
+ break;
+ case 1: /* ssi.content-type */
+ pconf->content_type = cpv->v.b;
+ break;
+ case 2: /* ssi.conditional-requests */
+ pconf->conditional_requests = cpv->v.u;
+ break;
+ case 3: /* ssi.exec */
+ pconf->ssi_exec = cpv->v.u;
+ break;
+ case 4: /* ssi.recursion-max */
+ pconf->ssi_recursion_max = cpv->v.shrt;
+ break;
+ default:/* should not happen */
+ return;
+ }
+}
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
+static void mod_ssi_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_ssi_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- if (!array_is_vlist(s->ssi_extension)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected value for ssi.extension; expected list of \"ext\"");
- return HANDLER_ERROR;
- }
- }
+static void mod_ssi_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_ssi_merge_config(&p->conf, p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
- return HANDLER_GO_ON;
+SETDEFAULTS_FUNC(mod_ssi_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("ssi.extension"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("ssi.content-type"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("ssi.conditional-requests"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("ssi.exec"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("ssi.recursion-max"),
+ T_CONFIG_SHORT,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_ssi"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* ssi.extension */
+ if (!array_is_vlist(cpv->v.a)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s; "
+ "expected list of \"ext\"", cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ break;
+ case 1: /* ssi.content-type */
+ case 2: /* ssi.conditional-requests */
+ case 3: /* ssi.exec */
+ case 4: /* ssi.recursion-max */
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+ }
+
+ p->defaults.ssi_exec = 1;
+
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_ssi_merge_config(&p->defaults, cpv);
+ }
+
+ return HANDLER_GO_ON;
}
@@ -1228,7 +1260,7 @@ static int mod_ssi_handle_request(server *srv, connection *con, handler_ctx *p)
if (p->conf.conditional_requests) {
/* Generate "ETag" & "Last-Modified" headers */
- buffer *mtime = NULL;
+ const buffer *mtime = NULL;
/* use most recently modified include file for ETag and Last-Modified */
if (st.st_mtime < include_file_last_mtime)
@@ -1258,55 +1290,15 @@ static int mod_ssi_handle_request(server *srv, connection *con, handler_ctx *p)
return 0;
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_ssi_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(ssi_extension);
- PATCH(content_type);
- PATCH(conditional_requests);
- PATCH(ssi_exec);
- PATCH(ssi_recursion_max);
-
- /* 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("ssi.extension"))) {
- PATCH(ssi_extension);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("ssi.content-type"))) {
- PATCH(content_type);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("ssi.conditional-requests"))) {
- PATCH(conditional_requests);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("ssi.exec"))) {
- PATCH(ssi_exec);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("ssi.recursion-max"))) {
- PATCH(ssi_recursion_max);
- }
- }
- }
-
- return 0;
-}
-#undef PATCH
-
URIHANDLER_FUNC(mod_ssi_physical_path) {
plugin_data *p = p_d;
+ UNUSED(srv);
if (con->mode != DIRECT) return HANDLER_GO_ON;
if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
- mod_ssi_patch_connection(srv, con, p);
+ mod_ssi_patch_config(con, p);
+ if (NULL == p->conf.ssi_extension) return HANDLER_GO_ON;
if (array_match_value_suffix(p->conf.ssi_extension, con->physical.path)) {
con->plugin_ctx[p->id] = handler_ctx_init(p);
@@ -1350,12 +1342,11 @@ static handler_t mod_ssi_connection_reset(server *srv, connection *con, void *p_
return HANDLER_GO_ON;
}
-/* this function is called at dlopen() time and inits the callbacks */
int mod_ssi_plugin_init(plugin *p);
int mod_ssi_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("ssi");
+ p->name = "ssi";
p->init = mod_ssi_init;
p->handle_subrequest_start = mod_ssi_physical_path;
@@ -1364,7 +1355,5 @@ int mod_ssi_plugin_init(plugin *p) {
p->set_defaults = mod_ssi_set_defaults;
p->cleanup = mod_ssi_free;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_ssi.h b/src/mod_ssi.h
index b4722b29..fb5848af 100644
--- a/src/mod_ssi.h
+++ b/src/mod_ssi.h
@@ -8,11 +8,9 @@
#include "plugin.h"
-/* plugin config for all request/connections */
-
typedef struct {
- array *ssi_extension;
- buffer *content_type;
+ const array *ssi_extension;
+ const buffer *content_type;
unsigned short conditional_requests;
unsigned short ssi_exec;
unsigned short ssi_recursion_max;
@@ -20,6 +18,8 @@ typedef struct {
typedef struct {
PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
buffer *timefmt;
@@ -27,10 +27,6 @@ typedef struct {
array *ssi_vars;
array *ssi_cgi_env;
-
- plugin_config **config_storage;
-
- plugin_config conf;
} plugin_data;
typedef struct {
diff --git a/src/mod_staticfile.c b/src/mod_staticfile.c
index 68da1857..cedf43f7 100644
--- a/src/mod_staticfile.c
+++ b/src/mod_staticfile.c
@@ -6,8 +6,6 @@
#include "plugin.h"
-#include "etag.h"
-#include "http_chunk.h"
#include "response.h"
#include <stdlib.h>
@@ -19,147 +17,120 @@
*/
-
-/* plugin config for all request/connections */
-
typedef struct {
- array *exclude_ext;
+ const array *exclude_ext;
unsigned short etags_used;
unsigned short disable_pathinfo;
} plugin_config;
typedef struct {
- PLUGIN_DATA;
-
- plugin_config **config_storage;
-
- plugin_config conf;
+ PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
} plugin_data;
-/* init the plugin data */
INIT_FUNC(mod_staticfile_init) {
- plugin_data *p;
-
- p = calloc(1, sizeof(*p));
-
- return p;
+ return calloc(1, sizeof(plugin_data));
}
-/* detroy the plugin data */
FREE_FUNC(mod_staticfile_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- 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];
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+ UNUSED(srv);
- if (NULL == s) continue;
+ free(p->cvlist);
+ free(p);
- array_free(s->exclude_ext);
-
- free(s);
- }
- free(p->config_storage);
- }
-
- free(p);
-
- return HANDLER_GO_ON;
+ return HANDLER_GO_ON;
}
-/* handle plugin config and check values */
-
-SETDEFAULTS_FUNC(mod_staticfile_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { "static-file.exclude-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { "static-file.etags", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { "static-file.disable-pathinfo", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->exclude_ext = array_init();
- s->etags_used = 1;
- s->disable_pathinfo = 0;
-
- cv[0].destination = s->exclude_ext;
- cv[1].destination = &(s->etags_used);
- cv[2].destination = &(s->disable_pathinfo);
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
-
- if (!array_is_vlist(s->exclude_ext)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected value for static-file.exclude-extensions; expected list of \"ext\"");
- return HANDLER_ERROR;
- }
- }
+static void mod_staticfile_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* static-file.exclude-extensions */
+ pconf->exclude_ext = cpv->v.a;
+ break;
+ case 1: /* static-file.etags */
+ pconf->etags_used = cpv->v.u;
+ break;
+ case 2: /* static-file.disable-pathinfo */
+ pconf->disable_pathinfo = cpv->v.u;
+ break;
+ default:/* should not happen */
+ return;
+ }
+}
- return HANDLER_GO_ON;
+static void mod_staticfile_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_staticfile_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_staticfile_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(exclude_ext);
- PATCH(etags_used);
- PATCH(disable_pathinfo);
-
- /* 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("static-file.exclude-extensions"))) {
- PATCH(exclude_ext);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("static-file.etags"))) {
- PATCH(etags_used);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("static-file.disable-pathinfo"))) {
- PATCH(disable_pathinfo);
- }
- }
- }
+static void mod_staticfile_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_staticfile_merge_config(&p->conf,
+ p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
- return 0;
+SETDEFAULTS_FUNC(mod_staticfile_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("static-file.exclude-extensions"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("static-file.etags"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("static-file.disable-pathinfo"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_staticfile"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* static-file.exclude-extensions */
+ if (!array_is_vlist(cpv->v.a)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s; "
+ "expected list of \"ext\"", cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+ }
+
+ /* initialize p->defaults from global config context */
+ p->defaults.etags_used = 1; /* etags enabled */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_staticfile_merge_config(&p->defaults, cpv);
+ }
+
+ return HANDLER_GO_ON;
}
-#undef PATCH
URIHANDLER_FUNC(mod_staticfile_subrequest) {
plugin_data *p = p_d;
/* someone else has done a decision for us */
if (con->http_status != 0) return HANDLER_GO_ON;
- if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
/* someone else has handled this request */
@@ -175,7 +146,7 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) {
return HANDLER_GO_ON;
}
- mod_staticfile_patch_connection(srv, con, p);
+ mod_staticfile_patch_config(con, p);
if (p->conf.disable_pathinfo && !buffer_string_is_empty(con->request.pathinfo)) {
if (con->conf.log_request_handling) {
@@ -185,7 +156,7 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) {
}
/* ignore certain extensions */
- if (0 != p->conf.exclude_ext->used && array_match_value_suffix(p->conf.exclude_ext, con->physical.path)) {
+ if (p->conf.exclude_ext && array_match_value_suffix(p->conf.exclude_ext, con->physical.path)) {
if (con->conf.log_request_handling) {
log_error_write(srv, __FILE__, __LINE__, "s", "-- NOT handling file as static file, extension forbidden");
}
@@ -203,19 +174,16 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) {
return HANDLER_FINISHED;
}
-/* this function is called at dlopen() time and inits the callbacks */
int mod_staticfile_plugin_init(plugin *p);
int mod_staticfile_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("staticfile");
+ p->name = "staticfile";
p->init = mod_staticfile_init;
p->handle_subrequest_start = mod_staticfile_subrequest;
p->set_defaults = mod_staticfile_set_defaults;
p->cleanup = mod_staticfile_free;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_status.c b/src/mod_status.c
index a89ab3bf..11520918 100644
--- a/src/mod_status.c
+++ b/src/mod_status.c
@@ -18,15 +18,17 @@
#include <stdio.h>
typedef struct {
- buffer *config_url;
- buffer *status_url;
- buffer *statistics_url;
+ const buffer *config_url;
+ const buffer *status_url;
+ const buffer *statistics_url;
- int sort;
+ int sort;
} plugin_config;
typedef struct {
PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
double traffic_out;
double requests;
@@ -42,102 +44,89 @@ typedef struct {
double abs_requests;
double bytes_written;
-
- buffer *module_list;
-
- plugin_config **config_storage;
-
- plugin_config conf;
} plugin_data;
INIT_FUNC(mod_status_init) {
- plugin_data *p;
- size_t i;
-
- p = calloc(1, sizeof(*p));
-
- p->traffic_out = p->requests = 0;
- p->rel_traffic_out = p->rel_requests = 0;
- p->abs_traffic_out = p->abs_requests = 0;
- p->bytes_written = 0;
- p->module_list = buffer_init();
-
- for (i = 0; i < 5; i++) {
- p->mod_5s_traffic_out[i] = p->mod_5s_requests[i] = 0;
- }
-
- return p;
+ return calloc(1, sizeof(plugin_data));
}
FREE_FUNC(mod_status_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- buffer_free(p->module_list);
-
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
- if (NULL == s) continue;
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+ UNUSED(srv);
- buffer_free(s->status_url);
- buffer_free(s->statistics_url);
- buffer_free(s->config_url);
+ free(p->cvlist);
+ free(p);
- free(s);
- }
- free(p->config_storage);
- }
+ return HANDLER_GO_ON;
+}
+static void mod_status_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* status.status-url */
+ pconf->status_url = cpv->v.b;
+ break;
+ case 1: /* status.config-url */
+ pconf->config_url = cpv->v.b;
+ break;
+ case 2: /* status.statistics-url */
+ pconf->statistics_url = cpv->v.b;
+ break;
+ case 3: /* status.enable-sort */
+ pconf->sort = (int)cpv->v.u;
+ break;
+ default:/* should not happen */
+ return;
+ }
+}
- free(p);
+static void mod_status_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_status_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- return HANDLER_GO_ON;
+static void mod_status_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_status_merge_config(&p->conf, p->cvlist + p->cvlist[i].v.u2[0]);
+ }
}
SETDEFAULTS_FUNC(mod_status_set_defaults) {
- plugin_data *p = p_d;
- size_t i;
-
- config_values_t cv[] = {
- { "status.status-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "status.config-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "status.enable-sort", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
- { "status.statistics-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->config_url = buffer_init();
- s->status_url = buffer_init();
- s->sort = 1;
- s->statistics_url = buffer_init();
-
- cv[0].destination = s->status_url;
- cv[1].destination = s->config_url;
- cv[2].destination = &(s->sort);
- cv[3].destination = s->statistics_url;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
- }
-
- return HANDLER_GO_ON;
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("status.status-url"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("status.config-url"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("status.statistics-url"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("status.enable-sort"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_status"))
+ return HANDLER_ERROR;
+
+ p->defaults.sort = 1;
+
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_status_merge_config(&p->defaults, cpv);
+ }
+
+ return HANDLER_GO_ON;
}
@@ -165,8 +154,7 @@ static int mod_status_header_append(buffer *b, const char *key) {
return 0;
}
-static int mod_status_header_append_sort(buffer *b, void *p_d, const char* key) {
- plugin_data *p = p_d;
+static int mod_status_header_append_sort(buffer *b, plugin_data *p, const char* key) {
if (p->conf.sort) {
buffer_append_string_len(b, CONST_STR_LEN("<th class=\"status\"><a href=\"#\" class=\"sortheader\" onclick=\"resort(this);return false;\">"));
@@ -196,8 +184,7 @@ static int mod_status_get_multiplier(double *avg, char *multiplier, int size) {
return 0;
}
-static handler_t mod_status_handle_server_status_html(server *srv, connection *con, void *p_d) {
- plugin_data *p = p_d;
+static handler_t mod_status_handle_server_status_html(server *srv, connection *con, plugin_data *p) {
buffer *b = chunkqueue_append_buffer_open(con->write_queue);
double avg;
uint32_t j;
@@ -498,14 +485,14 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c
buffer_append_string_len(b, CONST_STR_LEN("<table summary=\"status\" class=\"status\">\n"));
buffer_append_string_len(b, CONST_STR_LEN("<tr>"));
- mod_status_header_append_sort(b, p_d, "Client IP");
- mod_status_header_append_sort(b, p_d, "Read");
- mod_status_header_append_sort(b, p_d, "Written");
- mod_status_header_append_sort(b, p_d, "State");
- mod_status_header_append_sort(b, p_d, "Time");
- mod_status_header_append_sort(b, p_d, "Host");
- mod_status_header_append_sort(b, p_d, "URI");
- mod_status_header_append_sort(b, p_d, "File");
+ mod_status_header_append_sort(b, p, "Client IP");
+ mod_status_header_append_sort(b, p, "Read");
+ mod_status_header_append_sort(b, p, "Written");
+ mod_status_header_append_sort(b, p, "State");
+ mod_status_header_append_sort(b, p, "Time");
+ mod_status_header_append_sort(b, p, "Host");
+ mod_status_header_append_sort(b, p, "URI");
+ mod_status_header_append_sort(b, p, "File");
buffer_append_string_len(b, CONST_STR_LEN("</tr>\n"));
for (j = 0; j < srv->conns.used; ++j) {
@@ -593,8 +580,7 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c
}
-static handler_t mod_status_handle_server_status_text(server *srv, connection *con, void *p_d) {
- plugin_data *p = p_d;
+static handler_t mod_status_handle_server_status_text(server *srv, connection *con, plugin_data *p) {
buffer *b = chunkqueue_append_buffer_open(con->write_queue);
double avg;
time_t ts;
@@ -653,8 +639,7 @@ static handler_t mod_status_handle_server_status_text(server *srv, connection *c
}
-static handler_t mod_status_handle_server_status_json(server *srv, connection *con, void *p_d) {
- plugin_data *p = p_d;
+static handler_t mod_status_handle_server_status_json(server *srv, connection *con, plugin_data *p) {
buffer *b = chunkqueue_append_buffer_open(con->write_queue);
double avg;
time_t ts;
@@ -737,11 +722,10 @@ static handler_t mod_status_handle_server_status_json(server *srv, connection *c
}
-static handler_t mod_status_handle_server_statistics(server *srv, connection *con, void *p_d) {
+static handler_t mod_status_handle_server_statistics(server *srv, connection *con) {
buffer *b;
size_t i;
array *st = srv->status;
- UNUSED(p_d);
if (0 == st->used) {
/* we have nothing to send */
@@ -769,15 +753,15 @@ static handler_t mod_status_handle_server_statistics(server *srv, connection *co
}
-static handler_t mod_status_handle_server_status(server *srv, connection *con, void *p_d) {
+static handler_t mod_status_handle_server_status(server *srv, connection *con, plugin_data *p) {
if (buffer_is_equal_string(con->uri.query, CONST_STR_LEN("auto"))) {
- mod_status_handle_server_status_text(srv, con, p_d);
+ mod_status_handle_server_status_text(srv, con, p);
} else if (buffer_string_length(con->uri.query) >= sizeof("json")-1
&& 0 == memcmp(con->uri.query->ptr, CONST_STR_LEN("json"))) {
- mod_status_handle_server_status_json(srv, con, p_d);
+ mod_status_handle_server_status_json(srv, con, p);
} else {
- mod_status_handle_server_status_html(srv, con, p_d);
+ mod_status_handle_server_status_html(srv, con, p);
}
con->http_status = 200;
@@ -787,10 +771,8 @@ static handler_t mod_status_handle_server_status(server *srv, connection *con, v
}
-static handler_t mod_status_handle_server_config(server *srv, connection *con, void *p_d) {
- plugin_data *p = p_d;
+static handler_t mod_status_handle_server_config(server *srv, connection *con) {
buffer *b = chunkqueue_append_buffer_open(con->write_queue);
- buffer *m = p->module_list;
buffer_copy_string_len(b, CONST_STR_LEN(
"<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
@@ -819,19 +801,15 @@ static handler_t mod_status_handle_server_config(server *srv, connection *con, v
mod_status_header_append(b, "Config-File-Settings");
+ buffer *m = srv->tmp_buf;
+ buffer_clear(m);
for (uint32_t i = 0; i < srv->plugins.used; ++i) {
- plugin **ps = srv->plugins.ptr;
-
- plugin *pl = ps[i];
-
- if (i == 0) {
- buffer_copy_buffer(m, pl->name);
- } else {
+ const char *name = ((plugin **)srv->plugins.ptr)[i]->name;
+ if (i != 0) {
buffer_append_string_len(m, CONST_STR_LEN("<br />"));
- buffer_append_string_buffer(m, pl->name);
}
+ buffer_append_string_len(m, name, strlen(name));
}
-
mod_status_row_append(b, "Loaded Modules", m->ptr);
buffer_append_string_len(b, CONST_STR_LEN(" </table>\n"));
@@ -851,60 +829,22 @@ static handler_t mod_status_handle_server_config(server *srv, connection *con, v
return HANDLER_FINISHED;
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_status_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(status_url);
- PATCH(config_url);
- PATCH(sort);
- PATCH(statistics_url);
-
- /* 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("status.status-url"))) {
- PATCH(status_url);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("status.config-url"))) {
- PATCH(config_url);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("status.enable-sort"))) {
- PATCH(sort);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("status.statistics-url"))) {
- PATCH(statistics_url);
- }
- }
- }
-
- return 0;
-}
-
static handler_t mod_status_handler(server *srv, connection *con, void *p_d) {
plugin_data *p = p_d;
if (con->mode != DIRECT) return HANDLER_GO_ON;
- mod_status_patch_connection(srv, con, p);
+ mod_status_patch_config(con, p);
if (!buffer_string_is_empty(p->conf.status_url) &&
buffer_is_equal(p->conf.status_url, con->uri.path)) {
- return mod_status_handle_server_status(srv, con, p_d);
+ return mod_status_handle_server_status(srv, con, p);
} else if (!buffer_string_is_empty(p->conf.config_url) &&
buffer_is_equal(p->conf.config_url, con->uri.path)) {
- return mod_status_handle_server_config(srv, con, p_d);
+ return mod_status_handle_server_config(srv, con);
} else if (!buffer_string_is_empty(p->conf.statistics_url) &&
buffer_is_equal(p->conf.statistics_url, con->uri.path)) {
- return mod_status_handle_server_statistics(srv, con, p_d);
+ return mod_status_handle_server_statistics(srv, con);
}
return HANDLER_GO_ON;
@@ -952,10 +892,11 @@ REQUESTDONE_FUNC(mod_status_account) {
return HANDLER_GO_ON;
}
+
int mod_status_plugin_init(plugin *p);
int mod_status_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("status");
+ p->name = "status";
p->init = mod_status_init;
p->cleanup = mod_status_free;
@@ -965,7 +906,5 @@ int mod_status_plugin_init(plugin *p) {
p->handle_trigger = mod_status_trigger;
p->handle_request_done = mod_status_account;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_trigger_b4_dl.c b/src/mod_trigger_b4_dl.c
index 6dbf4bb7..a919b727 100644
--- a/src/mod_trigger_b4_dl.c
+++ b/src/mod_trigger_b4_dl.c
@@ -1,18 +1,23 @@
#include "first.h"
+#include "plugin.h"
+
+
+#if defined(HAVE_PCRE_H) /* do nothing if PCRE not available */
+#if defined(HAVE_GDBM_H) || defined(USE_MEMCACHED) /* at least one required */
+
+
#include "base.h"
-#include "fdevent.h"
#include "log.h"
#include "buffer.h"
#include "http_header.h"
-#include "plugin.h"
-
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#if defined(HAVE_GDBM_H)
+#include "fdevent.h"
# include <gdbm.h>
#endif
@@ -29,308 +34,341 @@
*
*/
-/* plugin config for all request/connections */
-
typedef struct {
- buffer *db_filename;
-
- buffer *trigger_url;
- buffer *download_url;
- buffer *deny_url;
-
- array *mc_hosts;
- buffer *mc_namespace;
-#if defined(HAVE_PCRE_H)
- pcre *trigger_regex;
- pcre *download_regex;
-#endif
-#if defined(HAVE_GDBM_H)
- GDBM_FILE db;
-#endif
-
-#if defined(USE_MEMCACHED)
- memcached_st *memc;
-#endif
-
- unsigned short trigger_timeout;
- unsigned short debug;
+ const buffer *deny_url;
+ pcre *trigger_regex;
+ pcre *download_regex;
+ #if defined(HAVE_GDBM_H)
+ GDBM_FILE db;
+ #endif
+ #if defined(USE_MEMCACHED)
+ memcached_st *memc;
+ const buffer *mc_namespace;
+ #endif
+ unsigned short trigger_timeout;
+ unsigned short debug;
} plugin_config;
typedef struct {
- PLUGIN_DATA;
-
- buffer *tmp_buf;
-
- plugin_config **config_storage;
-
- plugin_config conf;
+ PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
} plugin_data;
-/* init the plugin data */
INIT_FUNC(mod_trigger_b4_dl_init) {
- plugin_data *p;
-
- p = calloc(1, sizeof(*p));
-
- p->tmp_buf = buffer_init();
-
- return p;
+ return calloc(1, sizeof(plugin_data));
}
-/* detroy the plugin data */
-FREE_FUNC(mod_trigger_b4_dl_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
-
- 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 (NULL == s) continue;
-
- buffer_free(s->db_filename);
- buffer_free(s->download_url);
- buffer_free(s->trigger_url);
- buffer_free(s->deny_url);
-
- buffer_free(s->mc_namespace);
- array_free(s->mc_hosts);
-
-#if defined(HAVE_PCRE_H)
- if (s->trigger_regex) pcre_free(s->trigger_regex);
- if (s->download_regex) pcre_free(s->download_regex);
-#endif
-#if defined(HAVE_GDBM_H)
- if (s->db) gdbm_close(s->db);
-#endif
-#if defined(USE_MEMCACHED)
- if (s->memc) memcached_free(s->memc);
-#endif
-
- free(s);
- }
- free(p->config_storage);
- }
-
- buffer_free(p->tmp_buf);
-
- free(p);
-
- return HANDLER_GO_ON;
+static void mod_trigger_b4_dl_free_config(plugin_data * const p) {
+ if (NULL == p->cvlist) return;
+ /* (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ if (cpv->vtype != T_CONFIG_LOCAL || NULL == cpv->v.v) continue;
+ switch (cpv->k_id) {
+ #if defined(HAVE_GDBM_H)
+ case 0: /* trigger-before-download.gdbm-filename */
+ gdbm_close(cpv->v.v);
+ break;
+ #endif
+ case 1: /* trigger-before-download.trigger-url */
+ pcre_free(cpv->v.v);
+ break;
+ case 2: /* trigger-before-download.download-url */
+ pcre_free(cpv->v.v);
+ break;
+ #if defined(USE_MEMCACHED)
+ case 5: /* trigger-before-download.memcache-hosts */
+ memcached_free(cpv->v.v);
+ break;
+ #endif
+ default:
+ break;
+ }
+ }
+ }
}
-/* handle plugin config and check values */
-
-SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
-
- config_values_t cv[] = {
- { "trigger-before-download.gdbm-filename", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { "trigger-before-download.trigger-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { "trigger-before-download.download-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
- { "trigger-before-download.deny-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
- { "trigger-before-download.trigger-timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
- { "trigger-before-download.memcache-hosts", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
- { "trigger-before-download.memcache-namespace", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
- { "trigger-before-download.debug", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
+static int mod_trigger_b4_dl_init_gdbm(server * const srv, config_plugin_value_t * const cpv) {
+ if (buffer_string_is_empty(cpv->v.b)) {
+ cpv->v.v = NULL;
+ return 1;
+ }
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
-#if defined(HAVE_PCRE_H)
- const char *errptr;
- int erroff;
-#endif
-
- s = calloc(1, sizeof(plugin_config));
- s->db_filename = buffer_init();
- s->download_url = buffer_init();
- s->trigger_url = buffer_init();
- s->deny_url = buffer_init();
- s->mc_hosts = array_init();
- s->mc_namespace = buffer_init();
-
- cv[0].destination = s->db_filename;
- cv[1].destination = s->trigger_url;
- cv[2].destination = s->download_url;
- cv[3].destination = s->deny_url;
- cv[4].destination = &(s->trigger_timeout);
- cv[5].destination = s->mc_hosts;
- cv[6].destination = s->mc_namespace;
- cv[7].destination = &(s->debug);
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
-#if defined(HAVE_GDBM_H)
- if (!buffer_string_is_empty(s->db_filename)) {
- if (NULL == (s->db = gdbm_open(s->db_filename->ptr, 4096, GDBM_WRCREAT | GDBM_NOLOCK, S_IRUSR | S_IWUSR, 0))) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "gdbm-open failed");
- return HANDLER_ERROR;
- }
- fdevent_setfd_cloexec(gdbm_fdesc(s->db));
- }
-#endif
-#if defined(HAVE_PCRE_H)
- if (!buffer_string_is_empty(s->download_url)) {
- if (NULL == (s->download_regex = pcre_compile(s->download_url->ptr,
- 0, &errptr, &erroff, NULL))) {
-
- log_error_write(srv, __FILE__, __LINE__, "sbss",
- "compiling regex for download-url failed:",
- s->download_url, "pos:", erroff);
- return HANDLER_ERROR;
- }
- }
-
- if (!buffer_string_is_empty(s->trigger_url)) {
- if (NULL == (s->trigger_regex = pcre_compile(s->trigger_url->ptr,
- 0, &errptr, &erroff, NULL))) {
+ #if defined(HAVE_GDBM_H)
- log_error_write(srv, __FILE__, __LINE__, "sbss",
- "compiling regex for trigger-url failed:",
- s->trigger_url, "pos:", erroff);
-
- return HANDLER_ERROR;
- }
- }
-#endif
+ GDBM_FILE db = gdbm_open(cpv->v.b->ptr, 4096, GDBM_WRCREAT | GDBM_NOLOCK,
+ S_IRUSR | S_IWUSR, 0);
- if (!array_is_vlist(s->mc_hosts)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected value for trigger-before-download.memcache-hosts; expected list of \"host\"");
- return HANDLER_ERROR;
- }
+ if (db) {
+ cpv->v.v = db;
+ cpv->vtype = T_CONFIG_LOCAL;
+ fdevent_setfd_cloexec(gdbm_fdesc(db));
+ return 1;
+ }
+ else {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "gdbm-open failed %s", cpv->v.b->ptr);
+ return 0;
+ }
- if (s->mc_hosts->used) {
-#if defined(USE_MEMCACHED)
- buffer *option_string = buffer_init();
- size_t k;
+ #else
- {
- data_string *ds = (data_string *)s->mc_hosts->data[0];
+ UNUSED(srv);
+ return 1;
- buffer_append_string_len(option_string, CONST_STR_LEN("--SERVER="));
- buffer_append_string_buffer(option_string, &ds->value);
- }
+ #endif
+}
- for (k = 1; k < s->mc_hosts->used; k++) {
- data_string *ds = (data_string *)s->mc_hosts->data[k];
+static int mod_trigger_b4_dl_init_memcached(server * const srv, config_plugin_value_t * const cpv) {
+ const array * const mc_hosts = cpv->v.a;
+ if (0 == mc_hosts->used) {
+ cpv->v.v = NULL;
+ return 1;
+ }
+
+ #if defined(USE_MEMCACHED)
+
+ buffer * const opts = srv->tmp_buf;
+ buffer_clear(opts);
+ for (uint32_t k = 0; k < mc_hosts->used; ++k) {
+ const data_string * const ds = (const data_string *)mc_hosts->data[k];
+ buffer_append_string_len(opts, CONST_STR_LEN(" --SERVER="));
+ buffer_append_string_buffer(opts, &ds->value);
+ }
+
+ cpv->v.v = memcached(opts->ptr+1, buffer_string_length(opts)-1);
+
+ if (cpv->v.v) {
+ cpv->vtype = T_CONFIG_LOCAL;
+ return 1;
+ }
+ else {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "configuring memcached failed for option string: %s", opts->ptr);
+ return 0;
+ }
+
+ #else
+
+ log_error(srv->errh, __FILE__, __LINE__,
+ "memcache support is not compiled in but "
+ "trigger-before-download.memcache-hosts is set; aborting");
+ return 0;
+
+ #endif
+}
- buffer_append_string_len(option_string, CONST_STR_LEN(" --SERVER="));
- buffer_append_string_buffer(option_string, &ds->value);
- }
+static int mod_trigger_b4_dl_init_regex(server * const srv, config_plugin_value_t * const cpv, const char * const str) {
+ const buffer * const b = cpv->v.b;
+ if (buffer_string_is_empty(b)) {
+ cpv->v.v = NULL;
+ return 1;
+ }
+
+ const char *errptr;
+ int erroff;
+ cpv->v.v = pcre_compile(b->ptr, 0, &errptr, &erroff, NULL);
+
+ if (cpv->v.v) {
+ cpv->vtype = T_CONFIG_LOCAL;
+ return 1;
+ }
+ else {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "compiling regex for %s failed: %s pos: %d",
+ str, b->ptr, erroff);
+ return 0;
+ }
+}
- s->memc = memcached(CONST_BUF_LEN(option_string));
+FREE_FUNC(mod_trigger_b4_dl_free) {
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+ UNUSED(srv);
- if (NULL == s->memc) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "configuring memcached failed for option string:",
- option_string);
- }
- buffer_free(option_string);
+ mod_trigger_b4_dl_free_config(p);
- if (NULL == s->memc) return HANDLER_ERROR;
-#else
- log_error_write(srv, __FILE__, __LINE__, "s",
- "memcache support is not compiled in but trigger-before-download.memcache-hosts is set, aborting");
- return HANDLER_ERROR;
-#endif
- }
- }
+ free(p->cvlist);
+ free(p);
- return HANDLER_GO_ON;
+ return HANDLER_GO_ON;
}
-#if defined(HAVE_PCRE_H)
-
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_trigger_b4_dl_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
-#if defined(HAVE_GDBM)
- PATCH(db);
-#endif
-#if defined(HAVE_PCRE_H)
- PATCH(download_regex);
- PATCH(trigger_regex);
-#endif
- PATCH(trigger_timeout);
- PATCH(deny_url);
- PATCH(mc_namespace);
- PATCH(debug);
-#if defined(USE_MEMCACHED)
- PATCH(memc);
-#endif
+static void mod_trigger_b4_dl_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* trigger-before-download.gdbm-filename */
+ #if defined(HAVE_GDBM_H)
+ if (cpv->vtype != T_CONFIG_LOCAL) break;
+ pconf->db = cpv->v.v;
+ #endif
+ break;
+ case 1: /* trigger-before-download.trigger-url */
+ if (cpv->vtype != T_CONFIG_LOCAL) break;
+ pconf->trigger_regex = cpv->v.v;
+ break;
+ case 2: /* trigger-before-download.download-url */
+ if (cpv->vtype != T_CONFIG_LOCAL) break;
+ pconf->download_regex = cpv->v.v;
+ break;
+ case 3: /* trigger-before-download.deny-url */
+ pconf->deny_url = cpv->v.b;
+ break;
+ case 4: /* trigger-before-download.trigger-timeout */
+ pconf->trigger_timeout = cpv->v.shrt;
+ break;
+ case 5: /* trigger-before-download.memcache-hosts */
+ #if defined(USE_MEMCACHED)
+ if (cpv->vtype != T_CONFIG_LOCAL) break;
+ pconf->memc = cpv->v.v;
+ #endif
+ break;
+ case 6: /* trigger-before-download.memcache-namespace */
+ #if defined(USE_MEMCACHED)
+ pconf->mc_namespace = cpv->v.b;
+ #endif
+ break;
+ case 7: /* trigger-before-download.debug */
+ pconf->debug = cpv->v.u;
+ break;
+ default:/* should not happen */
+ return;
+ }
+}
- /* 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];
+static void mod_trigger_b4_dl_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_trigger_b4_dl_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- /* condition didn't match */
- if (!config_check_cond(srv, con, dc)) continue;
+static void mod_trigger_b4_dl_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_trigger_b4_dl_merge_config(&p->conf,
+ p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
- /* merge config */
- for (j = 0; j < dc->value->used; j++) {
- data_unset *du = dc->value->data[j];
+SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("trigger-before-download.gdbm-filename"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("trigger-before-download.trigger-url"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("trigger-before-download.download-url"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("trigger-before-download.deny-url"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("trigger-before-download.trigger-timeout"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("trigger-before-download.memcache-hosts"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("trigger-before-download.memcache-namespace"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("trigger-before-download.debug"),
+ T_CONFIG_ARRAY,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_trigger_b4_dl"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* trigger-before-download.gdbm-filename */
+ if (!mod_trigger_b4_dl_init_gdbm(srv, cpv))
+ return HANDLER_ERROR;
+ break;
+ case 1: /* trigger-before-download.trigger-url */
+ if (!mod_trigger_b4_dl_init_regex(srv, cpv, "trigger-url"))
+ return HANDLER_ERROR;
+ break;
+ case 2: /* trigger-before-download.download-url */
+ if (!mod_trigger_b4_dl_init_regex(srv, cpv, "download-url"))
+ return HANDLER_ERROR;
+ break;
+ case 3: /* trigger-before-download.deny-url */
+ case 4: /* trigger-before-download.trigger-timeout */
+ break;
+ case 5: /* trigger-before-download.memcache-hosts */
+ if (!array_is_vlist(cpv->v.a)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "unexpected value for %s; "
+ "expected list of \"host\"", cpk[cpv->k_id].k);
+ return HANDLER_ERROR;
+ }
+ if (!mod_trigger_b4_dl_init_memcached(srv, cpv))
+ return HANDLER_ERROR;
+ break;
+ case 6: /* trigger-before-download.memcache-namespace */
+ case 7: /* trigger-before-download.debug */
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+ }
+
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_trigger_b4_dl_merge_config(&p->defaults, cpv);
+ }
+
+ return HANDLER_GO_ON;
+}
- if (buffer_is_equal_string(&du->key, CONST_STR_LEN("trigger-before-download.download-url"))) {
-#if defined(HAVE_PCRE_H)
- PATCH(download_regex);
-#endif
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("trigger-before-download.trigger-url"))) {
-# if defined(HAVE_PCRE_H)
- PATCH(trigger_regex);
-# endif
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("trigger-before-download.gdbm-filename"))) {
-#if defined(HAVE_GDBM_H)
- PATCH(db);
-#endif
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("trigger-before-download.trigger-timeout"))) {
- PATCH(trigger_timeout);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("trigger-before-download.debug"))) {
- PATCH(debug);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("trigger-before-download.deny-url"))) {
- PATCH(deny_url);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("trigger-before-download.memcache-namespace"))) {
- PATCH(mc_namespace);
- } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("trigger-before-download.memcache-hosts"))) {
#if defined(USE_MEMCACHED)
- PATCH(memc);
+static void mod_trigger_b4_dl_memcached_key(buffer * const b, const plugin_data * const p, const buffer * const remote_ip) {
+ buffer_clear(b);
+ if (p->conf.mc_namespace)
+ buffer_copy_buffer(b, p->conf.mc_namespace);
+ buffer_append_string_buffer(b, remote_ip);
+
+ /* memcached can't handle spaces */
+ for (size_t i = 0, len = buffer_string_length(b); i < len; ++i) {
+ if (b->ptr[i] == ' ') b->ptr[i] = '-';
+ }
+}
#endif
- }
- }
- }
- return 0;
+static handler_t mod_trigger_b4_dl_deny(connection * const con, const plugin_data * const p) {
+ if (p->conf.deny_url) {
+ http_header_response_set(con, HTTP_HEADER_LOCATION,
+ CONST_STR_LEN("Location"),
+ CONST_BUF_LEN(p->conf.deny_url));
+ con->http_status = 307;
+ }
+ else {
+ log_error(con->errh, __FILE__, __LINE__,
+ "trigger-before-download.deny-url not configured");
+ con->http_status = 500;
+ }
+ con->file_finished = 1;
+ return HANDLER_FINISHED;
}
-#undef PATCH
-
-#endif
URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
-#if defined(HAVE_PCRE_H)
plugin_data *p = p_d;
- const char *remote_ip;
- const buffer *vb;
int n;
# define N 10
@@ -340,7 +378,7 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
- mod_trigger_b4_dl_patch_connection(srv, con, p);
+ mod_trigger_b4_dl_patch_config(con, p);
if (!p->conf.trigger_regex || !p->conf.download_regex) return HANDLER_GO_ON;
@@ -359,14 +397,12 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
if (!p->conf.memc) return HANDLER_GO_ON;
# endif
- if (NULL != (vb = http_header_request_get(con, HTTP_HEADER_X_FORWARDED_FOR, CONST_STR_LEN("X-Forwarded-For")))) {
- /* X-Forwarded-For contains the ip behind the proxy */
-
- remote_ip = vb->ptr;
-
- /* memcache can't handle spaces */
- } else {
- remote_ip = con->dst_addr_buf->ptr;
+ /* X-Forwarded-For contains the ip behind the proxy */
+ const buffer *remote_ip =
+ http_header_request_get(con, HTTP_HEADER_X_FORWARDED_FOR,
+ CONST_STR_LEN("X-Forwarded-For"));
+ if (NULL == remote_ip) {
+ remote_ip = con->dst_addr_buf;
}
if (p->conf.debug) {
@@ -387,8 +423,8 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
/* the trigger matched */
datum key, val;
- key.dptr = (char *)remote_ip;
- key.dsize = strlen(remote_ip);
+ *(const char **)&key.dptr = remote_ip->ptr;
+ key.dsize = buffer_string_length(remote_ip);
val.dptr = (char *)&(srv->cur_ts);
val.dsize = sizeof(srv->cur_ts);
@@ -401,21 +437,15 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
# endif
# if defined(USE_MEMCACHED)
if (p->conf.memc) {
- size_t i, len;
- buffer_copy_buffer(p->tmp_buf, p->conf.mc_namespace);
- buffer_append_string(p->tmp_buf, remote_ip);
-
- len = buffer_string_length(p->tmp_buf);
- for (i = 0; i < len; i++) {
- if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
- }
+ buffer * const b = srv->tmp_buf;
+ mod_trigger_b4_dl_memcached_key(b, p, remote_ip);
if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) triggered IP:", p->tmp_buf);
+ log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) triggered IP:", b);
}
if (MEMCACHED_SUCCESS != memcached_set(p->conf.memc,
- CONST_BUF_LEN(p->tmp_buf),
+ CONST_BUF_LEN(b),
(const char *)&(srv->cur_ts), sizeof(srv->cur_ts),
p->conf.trigger_timeout, 0)) {
log_error_write(srv, __FILE__, __LINE__, "s",
@@ -439,19 +469,14 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
datum key, val;
time_t last_hit;
- key.dptr = (char *)remote_ip;
- key.dsize = strlen(remote_ip);
+ *(const char **)&key.dptr = remote_ip->ptr;
+ key.dsize = buffer_string_length(remote_ip);
val = gdbm_fetch(p->conf.db, key);
if (val.dptr == NULL) {
/* not found, redirect */
-
- http_header_response_set(con, HTTP_HEADER_LOCATION, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
- con->http_status = 307;
- con->file_finished = 1;
-
- return HANDLER_FINISHED;
+ return mod_trigger_b4_dl_deny(con, p);
}
memcpy(&last_hit, val.dptr, sizeof(time_t));
@@ -461,10 +486,6 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
if (srv->cur_ts - last_hit > p->conf.trigger_timeout) {
/* found, but timeout, redirect */
- http_header_response_set(con, HTTP_HEADER_LOCATION, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
- con->http_status = 307;
- con->file_finished = 1;
-
if (p->conf.db) {
if (0 != gdbm_delete(p->conf.db, key)) {
log_error_write(srv, __FILE__, __LINE__, "s",
@@ -472,7 +493,7 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
}
}
- return HANDLER_FINISHED;
+ return mod_trigger_b4_dl_deny(con, p);
}
val.dptr = (char *)&(srv->cur_ts);
@@ -484,21 +505,13 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
}
}
# endif
-
# if defined(USE_MEMCACHED)
if (p->conf.memc) {
- size_t i, len;
-
- buffer_copy_buffer(p->tmp_buf, p->conf.mc_namespace);
- buffer_append_string(p->tmp_buf, remote_ip);
-
- len = buffer_string_length(p->tmp_buf);
- for (i = 0; i < len; i++) {
- if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
- }
+ buffer * const b = srv->tmp_buf;
+ mod_trigger_b4_dl_memcached_key(b, p, remote_ip);
if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) checking IP:", p->tmp_buf);
+ log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) checking IP:", b);
}
/**
@@ -507,18 +520,13 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
* and the timestamp is updated
*
*/
- if (MEMCACHED_SUCCESS != memcached_exist(p->conf.memc, CONST_BUF_LEN(p->tmp_buf))) {
- http_header_response_set(con, HTTP_HEADER_LOCATION, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
-
- con->http_status = 307;
- con->file_finished = 1;
-
- return HANDLER_FINISHED;
+ if (MEMCACHED_SUCCESS != memcached_exist(p->conf.memc, CONST_BUF_LEN(b))) {
+ return mod_trigger_b4_dl_deny(con, p);
}
/* set a new timeout */
if (MEMCACHED_SUCCESS != memcached_set(p->conf.memc,
- CONST_BUF_LEN(p->tmp_buf),
+ CONST_BUF_LEN(b),
(const char *)&(srv->cur_ts), sizeof(srv->cur_ts),
p->conf.trigger_timeout, 0)) {
log_error_write(srv, __FILE__, __LINE__, "s",
@@ -528,51 +536,33 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
# endif
}
-#else
- UNUSED(srv);
- UNUSED(con);
- UNUSED(p_d);
-#endif
-
return HANDLER_GO_ON;
}
#if defined(HAVE_GDBM_H)
-TRIGGER_FUNC(mod_trigger_b4_dl_handle_trigger) {
- plugin_data *p = p_d;
- size_t i;
-
- /* check DB each minute */
- if (srv->cur_ts % 60 != 0) return HANDLER_GO_ON;
-
- /* cleanup */
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
+static void mod_trigger_b4_dl_trigger_gdbm(GDBM_FILE db, const time_t cur_ts, const int trigger_timeout) {
datum key, val, okey;
-
- if (!s->db) continue;
-
okey.dptr = NULL;
/* according to the manual this loop + delete does delete all entries on its way
*
* we don't care as the next round will remove them. We don't have to perfect here.
*/
- for (key = gdbm_firstkey(s->db); key.dptr; key = gdbm_nextkey(s->db, okey)) {
+ for (key = gdbm_firstkey(db); key.dptr; key = gdbm_nextkey(db, okey)) {
time_t last_hit;
if (okey.dptr) {
free(okey.dptr);
okey.dptr = NULL;
}
- val = gdbm_fetch(s->db, key);
+ val = gdbm_fetch(db, key);
memcpy(&last_hit, val.dptr, sizeof(time_t));
free(val.dptr);
- if (srv->cur_ts - last_hit > s->trigger_timeout) {
- gdbm_delete(s->db, key);
+ if (cur_ts - last_hit > trigger_timeout) {
+ gdbm_delete(db, key);
}
okey = key;
@@ -580,18 +570,54 @@ TRIGGER_FUNC(mod_trigger_b4_dl_handle_trigger) {
if (okey.dptr) free(okey.dptr);
/* reorg once a day */
- if ((srv->cur_ts % (60 * 60 * 24) != 0)) gdbm_reorganize(s->db);
- }
- return HANDLER_GO_ON;
+ if ((cur_ts % (60 * 60 * 24) != 0)) gdbm_reorganize(db);
+}
+
+TRIGGER_FUNC(mod_trigger_b4_dl_handle_trigger) {
+ /* check DB each minute */
+ const time_t cur_ts = srv->cur_ts;
+ if (cur_ts % 60 != 0) return HANDLER_GO_ON;
+
+ plugin_data * const p = p_d;
+
+ /* (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ void *db = NULL;
+ int timeout = (int)p->defaults.trigger_timeout;
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* trigger-before-download.gdbm-filename */
+ if (cpv->vtype == T_CONFIG_LOCAL && NULL != cpv->v.v)
+ db = cpv->v.v;
+ break;
+ case 4: /* trigger-before-download.trigger-timeout */
+ timeout = (int)cpv->v.shrt;
+ break;
+ default:
+ break;
+ }
+ }
+ if (db)
+ mod_trigger_b4_dl_trigger_gdbm(db, cur_ts, timeout);
+ }
+
+ return HANDLER_GO_ON;
}
#endif
-/* this function is called at dlopen() time and inits the callbacks */
+
+#endif /* defined(HAVE_PCRE_H) */
+#endif /* defined(HAVE_GDBM_H) || defined(USE_MEMCACHED) */
+
int mod_trigger_b4_dl_plugin_init(plugin *p);
int mod_trigger_b4_dl_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("trigger_b4_dl");
+ p->name = "trigger_b4_dl";
+
+#if defined(HAVE_PCRE_H) /* do nothing if PCRE not available */
+#if defined(HAVE_GDBM_H) || defined(USE_MEMCACHED) /* at least one required */
p->init = mod_trigger_b4_dl_init;
p->handle_uri_clean = mod_trigger_b4_dl_uri_handler;
@@ -601,7 +627,8 @@ int mod_trigger_b4_dl_plugin_init(plugin *p) {
#endif
p->cleanup = mod_trigger_b4_dl_free;
- p->data = NULL;
+#endif
+#endif
return 0;
}
diff --git a/src/mod_uploadprogress.c b/src/mod_uploadprogress.c
index 418926b2..8ec101bd 100644
--- a/src/mod_uploadprogress.c
+++ b/src/mod_uploadprogress.c
@@ -23,24 +23,20 @@ typedef struct {
typedef struct {
connection_map_entry **ptr;
- size_t used;
- size_t size;
+ uint32_t used;
+ uint32_t size;
} connection_map;
-/* plugin config for all request/connections */
-
typedef struct {
- buffer *progress_url;
+ const buffer *progress_url;
} plugin_config;
typedef struct {
- PLUGIN_DATA;
-
- connection_map *con_map;
+ PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
- plugin_config **config_storage;
-
- plugin_config conf;
+ connection_map con_map;
} plugin_data;
/**
@@ -49,18 +45,8 @@ typedef struct {
*
*/
-/* init the plugin data */
-static connection_map *connection_map_init() {
- connection_map *cm;
-
- cm = calloc(1, sizeof(*cm));
-
- return cm;
-}
-
-static void connection_map_free(connection_map *cm) {
- size_t i;
- for (i = 0; i < cm->size; i++) {
+static void connection_map_free_data(connection_map *cm) {
+ for (uint32_t i = 0; i < cm->size; ++i) {
connection_map_entry *cme = cm->ptr[i];
if (!cme) break;
@@ -70,20 +56,16 @@ static void connection_map_free(connection_map *cm) {
}
free(cme);
}
-
- free(cm);
}
static int connection_map_insert(connection_map *cm, connection *con, const char *con_id, size_t idlen) {
connection_map_entry *cme;
- size_t i;
if (cm->used == cm->size) {
- cm->size += 16;
+ cm->size = cm->size ? (cm->size << 1) : 16;
+ force_assert(cm->size);
cm->ptr = realloc(cm->ptr, cm->size * sizeof(*(cm->ptr)));
- for (i = cm->used; i < cm->size; i++) {
- cm->ptr[i] = NULL;
- }
+ memset(cm->ptr+cm->used, 0, (cm->size - cm->used)*sizeof(*(cm->ptr)));
}
if (cm->ptr[cm->used]) {
@@ -102,9 +84,7 @@ static int connection_map_insert(connection_map *cm, connection *con, const char
}
static connection *connection_map_get_connection(connection_map *cm, const char *con_id, size_t idlen) {
- size_t i;
-
- for (i = 0; i < cm->used; i++) {
+ for (uint32_t i = 0; i < cm->used; ++i) {
connection_map_entry *cme = cm->ptr[i];
if (buffer_is_equal_string(cme->con_id, con_id, idlen)) {
@@ -117,9 +97,7 @@ static connection *connection_map_get_connection(connection_map *cm, const char
}
static int connection_map_remove_connection(connection_map *cm, connection *con) {
- size_t i;
-
- for (i = 0; i < cm->used; i++) {
+ for (uint32_t i = 0; i < cm->used; ++i) {
connection_map_entry *cme = cm->ptr[i];
if (cme->con == con) {
@@ -143,109 +121,71 @@ static int connection_map_remove_connection(connection_map *cm, connection *con)
return 0;
}
-/* init the plugin data */
INIT_FUNC(mod_uploadprogress_init) {
- plugin_data *p;
-
- p = calloc(1, sizeof(*p));
-
- p->con_map = connection_map_init();
-
- return p;
+ return calloc(1, sizeof(plugin_data));
}
-/* detroy the plugin data */
FREE_FUNC(mod_uploadprogress_free) {
- plugin_data *p = p_d;
-
- UNUSED(srv);
+ plugin_data *p = p_d;
+ if (!p) return HANDLER_GO_ON;
+ UNUSED(srv);
- if (!p) return HANDLER_GO_ON;
+ connection_map_free_data(&p->con_map);
- if (p->config_storage) {
- size_t i;
- for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s = p->config_storage[i];
+ free(p->cvlist);
+ free(p);
- if (NULL == s) continue;
-
- buffer_free(s->progress_url);
-
- free(s);
- }
- free(p->config_storage);
- }
-
- connection_map_free(p->con_map);
-
- free(p);
-
- return HANDLER_GO_ON;
+ return HANDLER_GO_ON;
}
-/* handle plugin config and check values */
-
-SETDEFAULTS_FUNC(mod_uploadprogress_set_defaults) {
- plugin_data *p = p_d;
- size_t i = 0;
-
- config_values_t cv[] = {
- { "upload-progress.progress-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
- };
-
- if (!p) return HANDLER_ERROR;
-
- p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *));
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config const* config = (data_config const*)srv->config_context->data[i];
- plugin_config *s;
-
- s = calloc(1, sizeof(plugin_config));
- s->progress_url = buffer_init();
-
- cv[0].destination = s->progress_url;
-
- p->config_storage[i] = s;
-
- if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
- return HANDLER_ERROR;
- }
- }
-
- return HANDLER_GO_ON;
+static void mod_uploadprogress_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* upload-progress.progress-url */
+ pconf->progress_url = cpv->v.b;
+ break;
+ default:/* should not happen */
+ return;
+ }
}
-#define PATCH(x) \
- p->conf.x = s->x;
-static int mod_uploadprogress_patch_connection(server *srv, connection *con, plugin_data *p) {
- size_t i, j;
- plugin_config *s = p->config_storage[0];
-
- PATCH(progress_url);
-
- /* 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];
+static void mod_uploadprogress_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
+ do {
+ mod_uploadprogress_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
- if (buffer_is_equal_string(&du->key, CONST_STR_LEN("upload-progress.progress-url"))) {
- PATCH(progress_url);
- }
- }
- }
+static void mod_uploadprogress_patch_config(connection * const con, plugin_data * const p) {
+ memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id))
+ mod_uploadprogress_merge_config(&p->conf,
+ p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
- return 0;
+SETDEFAULTS_FUNC(mod_uploadprogress_set_defaults) {
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("upload-progress.progress-url"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_uploadprogress"))
+ return HANDLER_ERROR;
+
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_uploadprogress_merge_config(&p->defaults, cpv);
+ }
+
+ return HANDLER_GO_ON;
}
-#undef PATCH
/**
*
@@ -280,7 +220,7 @@ URIHANDLER_FUNC(mod_uploadprogress_uri_handler) {
default: return HANDLER_GO_ON;
}
- mod_uploadprogress_patch_connection(srv, con, p);
+ mod_uploadprogress_patch_config(con, p);
if (buffer_string_is_empty(p->conf.progress_url)) return HANDLER_GO_ON;
if (con->request.http_method == HTTP_METHOD_GET) {
@@ -322,7 +262,7 @@ URIHANDLER_FUNC(mod_uploadprogress_uri_handler) {
switch(con->request.http_method) {
case HTTP_METHOD_POST:
- connection_map_insert(p->con_map, con, id, len);
+ connection_map_insert(&p->con_map, con, id, len);
return HANDLER_GO_ON;
case HTTP_METHOD_GET:
@@ -335,7 +275,7 @@ URIHANDLER_FUNC(mod_uploadprogress_uri_handler) {
con->mode = DIRECT;
/* get the connection */
- if (NULL == (post_con = connection_map_get_connection(p->con_map, id, len))) {
+ if (NULL == (post_con = connection_map_get_connection(&p->con_map, id, len))) {
log_error_write(srv, __FILE__, __LINE__, "ss",
"ID not known:", id);
@@ -382,19 +322,18 @@ REQUESTDONE_FUNC(mod_uploadprogress_request_done) {
if (con->request.http_method != HTTP_METHOD_POST) return HANDLER_GO_ON;
if (buffer_string_is_empty(con->uri.path)) return HANDLER_GO_ON;
- if (connection_map_remove_connection(p->con_map, con)) {
+ if (connection_map_remove_connection(&p->con_map, con)) {
/* removed */
}
return HANDLER_GO_ON;
}
-/* this function is called at dlopen() time and inits the callbacks */
int mod_uploadprogress_plugin_init(plugin *p);
int mod_uploadprogress_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("uploadprogress");
+ p->name = "uploadprogress";
p->init = mod_uploadprogress_init;
p->handle_uri_clean = mod_uploadprogress_uri_handler;
@@ -402,7 +341,5 @@ int mod_uploadprogress_plugin_init(plugin *p) {
p->set_defaults = mod_uploadprogress_set_defaults;
p->cleanup = mod_uploadprogress_free;
- p->data = NULL;
-
return 0;
}
diff --git a/src/mod_userdir.c b/src/mod_userdir.c
index 097d2315..995becc6 100644
--- a/src/mod_userdir.c
+++ b/src/mod_userdir.c
@@ -1,9 +1,9 @@
#include "first.h"
#include "base.h"
-#include "log.h"
+#include "array.h"
#include "buffer.h"
-
+#include "log.h"
#include "response.h"
#include "plugin.h"
@@ -18,332 +18,304 @@
# include <pwd.h>
#endif
-/* plugin config for all request/connections */
typedef struct {
- array *exclude_user;
- array *include_user;