[multiple] gw_backends config_plugin_values_init()
parent
0ad4911d39
commit
4a6fe83837
261
src/gw_backend.c
261
src/gw_backend.c
|
@ -158,7 +158,7 @@ static void gw_host_free(gw_host *h) {
|
|||
gw_proc_free(h->first);
|
||||
gw_proc_free(h->unused_procs);
|
||||
|
||||
for (size_t i = 0; i < h->args.used; ++i) free(h->args.ptr[i]);
|
||||
for (uint32_t i = 0; i < h->args.used; ++i) free(h->args.ptr[i]);
|
||||
free(h->args.ptr);
|
||||
free(h);
|
||||
}
|
||||
|
@ -171,9 +171,9 @@ static gw_exts *gw_extensions_init(void) {
|
|||
|
||||
static void gw_extensions_free(gw_exts *f) {
|
||||
if (!f) return;
|
||||
for (size_t i = 0; i < f->used; ++i) {
|
||||
for (uint32_t i = 0; i < f->used; ++i) {
|
||||
gw_extension *fe = f->exts[i];
|
||||
for (size_t j = 0; j < fe->used; ++j) {
|
||||
for (uint32_t j = 0; j < fe->used; ++j) {
|
||||
gw_host_free(fe->hosts[j]);
|
||||
}
|
||||
buffer_free(fe->key);
|
||||
|
@ -186,7 +186,7 @@ static void gw_extensions_free(gw_exts *f) {
|
|||
|
||||
static int gw_extension_insert(gw_exts *ext, buffer *key, gw_host *fh) {
|
||||
gw_extension *fe = NULL;
|
||||
for (size_t i = 0; i < ext->used; ++i) {
|
||||
for (uint32_t i = 0; i < ext->used; ++i) {
|
||||
if (buffer_is_equal(key, ext->exts[i]->key)) {
|
||||
fe = ext->exts[i];
|
||||
break;
|
||||
|
@ -423,7 +423,7 @@ static int env_add(char_array *env, const char *key, size_t key_len, const char
|
|||
dst[key_len] = '=';
|
||||
memcpy(dst + key_len + 1, val, val_len + 1); /* add the \0 from the value */
|
||||
|
||||
for (size_t i = 0; i < env->used; ++i) {
|
||||
for (uint32_t i = 0; i < env->used; ++i) {
|
||||
if (0 == strncmp(dst, env->ptr[i], key_len + 1)) {
|
||||
free(env->ptr[i]);
|
||||
env->ptr[i] = dst;
|
||||
|
@ -476,7 +476,7 @@ static int gw_spawn_connection(server *srv, gw_host *host, gw_proc *proc, int de
|
|||
if (-1 == status) {
|
||||
/* server is not up, spawn it */
|
||||
char_array env;
|
||||
size_t i;
|
||||
uint32_t i;
|
||||
int dfd = -1;
|
||||
|
||||
/* reopen socket */
|
||||
|
@ -701,13 +701,28 @@ static void gw_proc_kill(server *srv, gw_host *host, gw_proc *proc) {
|
|||
--host->num_procs;
|
||||
}
|
||||
|
||||
static gw_host * unixsocket_is_dup(gw_plugin_data *p, size_t used, buffer *unixsocket) {
|
||||
for (size_t i = 0; i < used; ++i) {
|
||||
gw_exts *exts = p->config_storage[i]->exts;
|
||||
if (NULL == exts) continue;
|
||||
for (size_t j = 0; j < exts->used; ++j) {
|
||||
static gw_host * unixsocket_is_dup(gw_plugin_data *p, buffer *unixsocket) {
|
||||
if (NULL == p->cvlist) return NULL;
|
||||
/* (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];
|
||||
gw_plugin_config *conf = NULL;
|
||||
for (; -1 != cpv->k_id; ++cpv) {
|
||||
switch (cpv->k_id) {
|
||||
case 0: /* xxxxx.server */
|
||||
if (cpv->vtype == T_CONFIG_LOCAL) conf = cpv->v.v;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL == conf || NULL == conf->exts) continue;
|
||||
|
||||
gw_exts *exts = conf->exts;
|
||||
for (uint32_t j = 0; j < exts->used; ++j) {
|
||||
gw_extension *ex = exts->exts[j];
|
||||
for (size_t n = 0; n < ex->used; ++n) {
|
||||
for (uint32_t n = 0; n < ex->used; ++n) {
|
||||
gw_host *host = ex->hosts[n];
|
||||
if (!buffer_string_is_empty(host->unixsocket)
|
||||
&& buffer_is_equal(host->unixsocket, unixsocket)
|
||||
|
@ -778,7 +793,7 @@ static gw_host * gw_host_get(server *srv, connection *con, gw_extension *extensi
|
|||
unsigned long last_max = ULONG_MAX;
|
||||
int max_usage = INT_MAX;
|
||||
int ndx = -1;
|
||||
size_t k;
|
||||
uint32_t k;
|
||||
|
||||
if (extension->used <= 1) {
|
||||
if (1 == extension->used && extension->hosts[0]->active_procs > 0) {
|
||||
|
@ -1122,9 +1137,9 @@ void * gw_init(void) {
|
|||
void gw_plugin_config_free(gw_plugin_config *s) {
|
||||
gw_exts *exts = s->exts;
|
||||
if (exts) {
|
||||
for (size_t j = 0; j < exts->used; ++j) {
|
||||
for (uint32_t j = 0; j < exts->used; ++j) {
|
||||
gw_extension *ex = exts->exts[j];
|
||||
for (size_t n = 0; n < ex->used; ++n) {
|
||||
for (uint32_t n = 0; n < ex->used; ++n) {
|
||||
gw_proc *proc;
|
||||
gw_host *host = ex->hosts[n];
|
||||
|
||||
|
@ -1155,40 +1170,46 @@ void gw_plugin_config_free(gw_plugin_config *s) {
|
|||
gw_extensions_free(s->exts_auth);
|
||||
gw_extensions_free(s->exts_resp);
|
||||
}
|
||||
array_free(s->ext_mapping);
|
||||
free(s);
|
||||
}
|
||||
|
||||
handler_t gw_free(server *srv, void *p_d) {
|
||||
gw_plugin_data *p = p_d;
|
||||
if (p->config_storage) {
|
||||
for (size_t i = 0; i < srv->config_context->used; ++i) {
|
||||
gw_plugin_config *s = p->config_storage[i];
|
||||
if (NULL == s) continue;
|
||||
gw_plugin_config_free(s);
|
||||
gw_plugin_data * const p = p_d;
|
||||
if (!p) return HANDLER_GO_ON;
|
||||
UNUSED(srv);
|
||||
if (NULL == p->cvlist) { free(p); return HANDLER_GO_ON; }
|
||||
/* (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: /* xxxxx.server */
|
||||
if (cpv->vtype == T_CONFIG_LOCAL)
|
||||
gw_plugin_config_free(cpv->v.v);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(p->config_storage);
|
||||
}
|
||||
free(p->cvlist);
|
||||
free(p);
|
||||
return HANDLER_GO_ON;
|
||||
}
|
||||
|
||||
int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const data_unset *du, size_t i, int sh_exec) {
|
||||
int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const array *a, gw_plugin_config *s, int sh_exec, const char *cpkkey) {
|
||||
/* per-module plugin_config MUST have common "base class" gw_plugin_config*/
|
||||
/* per-module plugin_data MUST have pointer-compatible common "base class"
|
||||
* with gw_plugin_data (stemming from gw_plugin_config compatibility) */
|
||||
|
||||
const data_array *da = (const data_array *)du;
|
||||
gw_plugin_config *s = p->config_storage[i];
|
||||
buffer *gw_mode;
|
||||
gw_host *host = NULL;
|
||||
|
||||
if (NULL == da) return 1;
|
||||
|
||||
if (da->type != TYPE_ARRAY || !array_is_kvarray(&da->value)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"unexpected value for xxxxx.server; expected "
|
||||
"( \"ext\" => ( \"backend-label\" => ( \"key\" => \"value\" )))");
|
||||
if (!array_is_kvarray(a)) {
|
||||
log_error(srv->errh, __FILE__, __LINE__,
|
||||
"unexpected value for %s; expected "
|
||||
"( \"ext\" => ( \"backend-label\" => ( \"key\" => \"value\" )))",
|
||||
cpkkey);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1206,8 +1227,8 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const data_unset *du
|
|||
* "<ext>" => ( ... ) )
|
||||
*/
|
||||
|
||||
for (size_t j = 0; j < da->value.used; ++j) {
|
||||
data_array *da_ext = (data_array *)da->value.data[j];
|
||||
for (uint32_t j = 0; j < a->used; ++j) {
|
||||
data_array *da_ext = (data_array *)a->data[j];
|
||||
|
||||
/*
|
||||
* da_ext->key == name of the extension
|
||||
|
@ -1221,7 +1242,7 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const data_unset *du
|
|||
* "<ext>" => ... )
|
||||
*/
|
||||
|
||||
for (size_t n = 0; n < da_ext->value.used; ++n) {
|
||||
for (uint32_t n = 0; n < da_ext->value.used; ++n) {
|
||||
data_array *da_host = (data_array *)da_ext->value.data[n];
|
||||
|
||||
config_values_t fcv[] = {
|
||||
|
@ -1231,7 +1252,7 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const data_unset *du
|
|||
{ "socket", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
|
||||
{ "bin-path", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
|
||||
|
||||
{ "check-local", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
|
||||
{ "check-local", NULL, T_CONFIG_BOOL, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
|
||||
{ "port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
|
||||
{ "min-procs", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
|
||||
{ "max-procs", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
|
||||
|
@ -1242,15 +1263,15 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const data_unset *du
|
|||
{ "bin-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
|
||||
{ "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 13 */
|
||||
|
||||
{ "broken-scriptfilename", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 14 */
|
||||
{ "allow-x-send-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 15 */
|
||||
{ "broken-scriptfilename", NULL, T_CONFIG_BOOL, T_CONFIG_SCOPE_CONNECTION }, /* 14 */
|
||||
{ "allow-x-send-file", NULL, T_CONFIG_BOOL, T_CONFIG_SCOPE_CONNECTION }, /* 15 */
|
||||
{ "strip-request-uri", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 16 */
|
||||
{ "kill-signal", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 17 */
|
||||
{ "fix-root-scriptname", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 18 */
|
||||
{ "fix-root-scriptname", NULL, T_CONFIG_BOOL, T_CONFIG_SCOPE_CONNECTION }, /* 18 */
|
||||
{ "listen-backlog", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION }, /* 19 */
|
||||
{ "x-sendfile", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 20 */
|
||||
{ "x-sendfile", NULL, T_CONFIG_BOOL, T_CONFIG_SCOPE_CONNECTION }, /* 20 */
|
||||
{ "x-sendfile-docroot",NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 21 */
|
||||
{ "tcp-fin-propagate", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 22 */
|
||||
{ "tcp-fin-propagate", NULL, T_CONFIG_BOOL, T_CONFIG_SCOPE_CONNECTION }, /* 22 */
|
||||
|
||||
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
|
||||
};
|
||||
|
@ -1312,7 +1333,7 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const data_unset *du
|
|||
goto error;
|
||||
}
|
||||
|
||||
for (size_t m = 0; m < da_host->value.used; ++m) {
|
||||
for (uint32_t m = 0; m < da_host->value.used; ++m) {
|
||||
if (NULL != strchr(da_host->value.data[m]->key.ptr, '_')) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "sb",
|
||||
"incorrect directive contains underscore ('_') instead of dash ('-'):",
|
||||
|
@ -1322,9 +1343,9 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const data_unset *du
|
|||
|
||||
if ((!buffer_string_is_empty(host->host) || host->port)
|
||||
&& !buffer_string_is_empty(host->unixsocket)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
|
||||
log_error_write(srv, __FILE__, __LINE__, "sssbsbs",
|
||||
"either host/port or socket have to be set in:",
|
||||
&da->key, "= (",
|
||||
cpkkey, "= (",
|
||||
&da_ext->key, " => (",
|
||||
&da_host->key, " ( ...");
|
||||
|
||||
|
@ -1341,9 +1362,9 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const data_unset *du
|
|||
struct sockaddr_un un;
|
||||
|
||||
if (buffer_string_length(host->unixsocket) + 1 > sizeof(un.sun_path) - 2) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
|
||||
log_error_write(srv, __FILE__, __LINE__, "sssbsbs",
|
||||
"unixsocket is too long in:",
|
||||
&da->key, "= (",
|
||||
cpkkey, "= (",
|
||||
&da_ext->key, " => (",
|
||||
&da_host->key, " ( ...");
|
||||
|
||||
|
@ -1351,7 +1372,7 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const data_unset *du
|
|||
}
|
||||
|
||||
if (!buffer_string_is_empty(host->bin_path)) {
|
||||
gw_host *duplicate = unixsocket_is_dup(p, i+1, host->unixsocket);
|
||||
gw_host *duplicate = unixsocket_is_dup(p, host->unixsocket);
|
||||
if (NULL != duplicate) {
|
||||
if (!buffer_is_equal(host->bin_path, duplicate->bin_path)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "sb",
|
||||
|
@ -1371,9 +1392,9 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const data_unset *du
|
|||
|
||||
if (buffer_string_is_empty(host->host) &&
|
||||
buffer_string_is_empty(host->bin_path)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
|
||||
log_error_write(srv, __FILE__, __LINE__, "sssbsbs",
|
||||
"host or bin-path have to be set in:",
|
||||
&da->key, "= (",
|
||||
cpkkey, "= (",
|
||||
&da_ext->key, " => (",
|
||||
&da_host->key, " ( ...");
|
||||
|
||||
|
@ -1410,7 +1431,7 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const data_unset *du
|
|||
/*(preserve prior behavior for SCGI exec of command)*/
|
||||
/*(admin should really prefer to put
|
||||
* any complex command into a script)*/
|
||||
for (size_t m = 0; m < host->args.used; ++m)
|
||||
for (uint32_t m = 0; m < host->args.used; ++m)
|
||||
free(host->args.ptr[m]);
|
||||
free(host->args.ptr);
|
||||
|
||||
|
@ -1457,7 +1478,7 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const data_unset *du
|
|||
"\n\tmax-procs:", host->max_procs);
|
||||
}
|
||||
|
||||
for (size_t pno = 0; pno < host->min_procs; ++pno) {
|
||||
for (uint32_t pno = 0; pno < host->min_procs; ++pno) {
|
||||
gw_proc *proc = gw_proc_init();
|
||||
proc->id = host->num_procs++;
|
||||
host->max_id++;
|
||||
|
@ -1536,7 +1557,7 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const data_unset *du
|
|||
}
|
||||
|
||||
if (host->xsendfile_docroot->used) {
|
||||
size_t k;
|
||||
uint32_t k;
|
||||
for (k = 0; k < host->xsendfile_docroot->used; ++k) {
|
||||
data_string *ds = (data_string *)host->xsendfile_docroot->data[k];
|
||||
if (ds->type != TYPE_STRING) {
|
||||
|
@ -1590,39 +1611,28 @@ error:
|
|||
return 0;
|
||||
}
|
||||
|
||||
int gw_set_defaults_balance(server *srv, gw_plugin_config *s, const data_unset *du) {
|
||||
const buffer *b;
|
||||
if (NULL == du) {
|
||||
b = NULL;
|
||||
} else if (du->type == TYPE_STRING) {
|
||||
b = &((const data_string *)du)->value;
|
||||
} else {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"unexpected type for xxxxx.balance; expected string");
|
||||
return 0;
|
||||
}
|
||||
if (buffer_string_is_empty(b)) {
|
||||
s->balance = GW_BALANCE_LEAST_CONNECTION;
|
||||
} else if (buffer_is_equal_string(b, CONST_STR_LEN("fair"))) {
|
||||
s->balance = GW_BALANCE_LEAST_CONNECTION;
|
||||
} else if (buffer_is_equal_string(b, CONST_STR_LEN("least-connection"))) {
|
||||
s->balance = GW_BALANCE_LEAST_CONNECTION;
|
||||
} else if (buffer_is_equal_string(b, CONST_STR_LEN("round-robin"))) {
|
||||
s->balance = GW_BALANCE_RR;
|
||||
} else if (buffer_is_equal_string(b, CONST_STR_LEN("hash"))) {
|
||||
s->balance = GW_BALANCE_HASH;
|
||||
} else if (buffer_is_equal_string(b, CONST_STR_LEN("sticky"))) {
|
||||
s->balance = GW_BALANCE_STICKY;
|
||||
} else {
|
||||
log_error_write(srv, __FILE__, __LINE__, "sb",
|
||||
"xxxxx.balance has to be one of: "
|
||||
"least-connection, round-robin, hash, sticky, but not:",
|
||||
b);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
int gw_get_defaults_balance(server *srv, const buffer *b) {
|
||||
if (buffer_string_is_empty(b))
|
||||
return GW_BALANCE_LEAST_CONNECTION;
|
||||
if (buffer_eq_slen(b, CONST_STR_LEN("fair")))
|
||||
return GW_BALANCE_LEAST_CONNECTION;
|
||||
if (buffer_eq_slen(b, CONST_STR_LEN("least-connection")))
|
||||
return GW_BALANCE_LEAST_CONNECTION;
|
||||
if (buffer_eq_slen(b, CONST_STR_LEN("round-robin")))
|
||||
return GW_BALANCE_RR;
|
||||
if (buffer_eq_slen(b, CONST_STR_LEN("hash")))
|
||||
return GW_BALANCE_HASH;
|
||||
if (buffer_eq_slen(b, CONST_STR_LEN("sticky")))
|
||||
return GW_BALANCE_STICKY;
|
||||
|
||||
log_error_write(srv, __FILE__, __LINE__, "sb",
|
||||
"xxxxx.balance has to be one of: "
|
||||
"least-connection, round-robin, hash, sticky, but not:",
|
||||
b);
|
||||
return GW_BALANCE_LEAST_CONNECTION;
|
||||
}
|
||||
|
||||
|
||||
static void gw_set_state(server *srv, gw_handler_ctx *hctx, gw_connection_state_t state) {
|
||||
hctx->state = state;
|
||||
hctx->state_timestamp = srv->cur_ts;
|
||||
|
@ -2258,7 +2268,7 @@ handler_t gw_check_extension(server *srv, connection *con, gw_plugin_data *p, in
|
|||
if (NULL != ds) {
|
||||
/* found a mapping */
|
||||
/* check if we know the extension */
|
||||
size_t k;
|
||||
uint32_t k;
|
||||
for (k = 0; k < exts->used; ++k) {
|
||||
extension = exts->exts[k];
|
||||
|
||||
|
@ -2278,7 +2288,7 @@ handler_t gw_check_extension(server *srv, connection *con, gw_plugin_data *p, in
|
|||
size_t uri_path_len = buffer_string_length(con->uri.path);
|
||||
|
||||
/* check if extension matches */
|
||||
for (size_t k = 0; k < exts->used; ++k) {
|
||||
for (uint32_t k = 0; k < exts->used; ++k) {
|
||||
gw_extension *ext = exts->exts[k];
|
||||
size_t ct_len = buffer_string_length(ext->key);
|
||||
|
||||
|
@ -2489,18 +2499,18 @@ static void gw_handle_trigger_host(server *srv, gw_host *host, int debug) {
|
|||
}
|
||||
|
||||
static void gw_handle_trigger_exts(server *srv, gw_exts *exts, int debug) {
|
||||
for (size_t j = 0; j < exts->used; ++j) {
|
||||
for (uint32_t j = 0; j < exts->used; ++j) {
|
||||
gw_extension *ex = exts->exts[j];
|
||||
for (size_t n = 0; n < ex->used; ++n) {
|
||||
for (uint32_t n = 0; n < ex->used; ++n) {
|
||||
gw_handle_trigger_host(srv, ex->hosts[n], debug);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gw_handle_trigger_exts_wkr(server *srv, gw_exts *exts) {
|
||||
for (size_t j = 0; j < exts->used; ++j) {
|
||||
for (uint32_t j = 0; j < exts->used; ++j) {
|
||||
gw_extension * const ex = exts->exts[j];
|
||||
for (size_t n = 0; n < ex->used; ++n) {
|
||||
for (uint32_t n = 0; n < ex->used; ++n) {
|
||||
gw_host * const host = ex->hosts[n];
|
||||
for (gw_proc *proc = host->first; proc; proc = proc->next) {
|
||||
if (proc->state == PROC_STATE_OVERLOADED)
|
||||
|
@ -2511,35 +2521,78 @@ static void gw_handle_trigger_exts_wkr(server *srv, gw_exts *exts) {
|
|||
}
|
||||
|
||||
handler_t gw_handle_trigger(server *srv, void *p_d) {
|
||||
gw_plugin_data *p = p_d;
|
||||
gw_plugin_data * const p = p_d;
|
||||
int wkr = (0 != srv->srvconf.max_worker && p->srv_pid != srv->pid);
|
||||
int global_debug = 0;
|
||||
|
||||
for (size_t i = 0; i < srv->config_context->used; i++) {
|
||||
gw_plugin_config *conf = p->config_storage[i];
|
||||
gw_exts *exts = conf->exts;
|
||||
int debug = conf->debug ? conf->debug : p->config_storage[0]->debug;
|
||||
if (NULL == exts) continue;
|
||||
if (NULL == p->cvlist) return HANDLER_GO_ON;
|
||||
/* (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];
|
||||
gw_plugin_config *conf = NULL;
|
||||
int debug = global_debug;
|
||||
for (; -1 != cpv->k_id; ++cpv) {
|
||||
switch (cpv->k_id) {
|
||||
case 0: /* xxxxx.server */
|
||||
if (cpv->vtype == T_CONFIG_LOCAL) conf = cpv->v.v;
|
||||
break;
|
||||
case 2: /* xxxxx.debug */
|
||||
debug = (int)cpv->v.u;
|
||||
if (0 == i) global_debug = (int)cpv->v.u;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL == conf || NULL == conf->exts) continue;
|
||||
|
||||
/* (debug flag is only active if set in same scope as xxxxx.server
|
||||
* or global scope (for convenience))
|
||||
* (unable to use p->defaults.debug since gw_plugin_config
|
||||
* might be part of a larger plugin_config) */
|
||||
wkr
|
||||
? gw_handle_trigger_exts_wkr(srv, exts)
|
||||
: gw_handle_trigger_exts(srv, exts, debug);
|
||||
? gw_handle_trigger_exts_wkr(srv, conf->exts)
|
||||
: gw_handle_trigger_exts(srv, conf->exts, debug);
|
||||
}
|
||||
|
||||
return HANDLER_GO_ON;
|
||||
}
|
||||
|
||||
handler_t gw_handle_waitpid_cb(server *srv, void *p_d, pid_t pid, int status) {
|
||||
gw_plugin_data *p = p_d;
|
||||
gw_plugin_data * const p = p_d;
|
||||
if (0 != srv->srvconf.max_worker && p->srv_pid != srv->pid)
|
||||
return HANDLER_GO_ON;
|
||||
int global_debug = 0;
|
||||
|
||||
for (size_t i = 0; i < srv->config_context->used; ++i) {
|
||||
gw_plugin_config *conf = p->config_storage[i];
|
||||
if (NULL == p->cvlist) return HANDLER_GO_ON;
|
||||
/* (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];
|
||||
gw_plugin_config *conf = NULL;
|
||||
int debug = global_debug;
|
||||
for (; -1 != cpv->k_id; ++cpv) {
|
||||
switch (cpv->k_id) {
|
||||
case 0: /* xxxxx.server */
|
||||
if (cpv->vtype == T_CONFIG_LOCAL) conf = cpv->v.v;
|
||||
break;
|
||||
case 2: /* xxxxx.debug */
|
||||
debug = (int)cpv->v.u;
|
||||
if (0 == i) global_debug = (int)cpv->v.u;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL == conf || NULL == conf->exts) continue;
|
||||
|
||||
/* (debug flag is only active if set in same scope as xxxxx.server
|
||||
* or global scope (for convenience))
|
||||
* (unable to use p->defaults.debug since gw_plugin_config
|
||||
* might be part of a larger plugin_config) */
|
||||
gw_exts *exts = conf->exts;
|
||||
int debug = conf->debug ? conf->debug : p->config_storage[0]->debug;
|
||||
if (NULL == exts) continue;
|
||||
for (size_t j = 0; j < exts->used; ++j) {
|
||||
for (uint32_t j = 0; j < exts->used; ++j) {
|
||||
gw_extension *ex = exts->exts[j];
|
||||
for (size_t n = 0; n < ex->used; ++n) {
|
||||
for (uint32_t n = 0; n < ex->used; ++n) {
|
||||
gw_host *host = ex->hosts[n];
|
||||
gw_proc *proc;
|
||||
for (proc = host->first; proc; proc = proc->next) {
|
||||
|
|
|
@ -12,14 +12,14 @@
|
|||
typedef struct {
|
||||
char **ptr;
|
||||
|
||||
size_t size;
|
||||
size_t used;
|
||||
uint32_t size;
|
||||
uint32_t used;
|
||||
} char_array;
|
||||
|
||||
typedef struct gw_proc {
|
||||
size_t id; /* id will be between 1 and max_procs */
|
||||
uint32_t id; /* id will be between 1 and max_procs */
|
||||
unsigned short port; /* config.port + pno */
|
||||
buffer *unixsocket; /* config.socket + "-" + id */
|
||||
unsigned port; /* config.port + pno */
|
||||
socklen_t saddrlen;
|
||||
struct sockaddr *saddr;
|
||||
|
||||
|
@ -28,13 +28,11 @@ typedef struct gw_proc {
|
|||
|
||||
pid_t pid; /* PID of the spawned process (0 if not spawned locally) */
|
||||
|
||||
uint32_t load; /* number of requests waiting on this process */
|
||||
|
||||
size_t load; /* number of requests waiting on this process */
|
||||
|
||||
time_t last_used; /* see idle_timeout */
|
||||
size_t requests; /* see max_requests */
|
||||
struct gw_proc *prev, *next; /* see first */
|
||||
|
||||
time_t last_used; /* see idle_timeout */
|
||||
time_t disabled_until; /* proc disabled until given time */
|
||||
|
||||
int is_local;
|
||||
|
@ -74,8 +72,8 @@ typedef struct {
|
|||
|
||||
unsigned short min_procs;
|
||||
unsigned short max_procs;
|
||||
size_t num_procs; /* how many procs are started */
|
||||
size_t active_procs; /* how many procs in state PROC_STATE_RUNNING */
|
||||
uint32_t num_procs; /* how many procs are started */
|
||||
uint32_t active_procs; /* how many procs in state PROC_STATE_RUNNING */
|
||||
|
||||
unsigned short max_load_per_proc;
|
||||
|
||||
|
@ -103,7 +101,7 @@ typedef struct {
|
|||
* process after a number of handled requests.
|
||||
*
|
||||
*/
|
||||
size_t max_requests_per_proc;
|
||||
uint32_t max_requests_per_proc;
|
||||
|
||||
|
||||
/* config */
|
||||
|
@ -197,9 +195,9 @@ typedef struct {
|
|||
unsigned short xsendfile_allow;
|
||||
array *xsendfile_docroot;
|
||||
|
||||
ssize_t load;
|
||||
int32_t load;
|
||||
|
||||
size_t max_id; /* corresponds most of the time to num_procs */
|
||||
uint32_t max_id; /* corresponds most of the time to num_procs */
|
||||
|
||||
buffer *strip_request_uri;
|
||||
|
||||
|
@ -242,15 +240,15 @@ typedef struct {
|
|||
|
||||
gw_host **hosts;
|
||||
|
||||
size_t used;
|
||||
size_t size;
|
||||
uint32_t used;
|
||||
uint32_t size;
|
||||
} gw_extension;
|
||||
|
||||
typedef struct {
|
||||
gw_extension **exts;
|
||||
|
||||
size_t used;
|
||||
size_t size;
|
||||
uint32_t used;
|
||||
uint32_t size;
|
||||
} gw_exts;
|
||||
|
||||
|
||||
|
@ -265,9 +263,7 @@ typedef struct gw_plugin_config {
|
|||
gw_exts *exts;
|
||||
gw_exts *exts_auth;
|
||||
gw_exts *exts_resp;
|
||||
|
||||
array *ext_mapping;
|
||||
|
||||
const array *ext_mapping;
|
||||
int balance;
|
||||
int proto;
|
||||
int debug;
|
||||
|
@ -276,10 +272,9 @@ typedef struct gw_plugin_config {
|
|||
/* generic plugin data, shared between all connections */
|
||||
typedef struct gw_plugin_data {
|
||||
PLUGIN_DATA;
|
||||
gw_plugin_config **config_storage;
|
||||
|
||||
pid_t srv_pid; /* must precede gw_plugin_config for mods w/ larger struct */
|
||||
gw_plugin_config conf; /* used only as long as no gw_handler_ctx is setup */
|
||||
pid_t srv_pid;
|
||||
gw_plugin_config defaults;/*(must not be used by gw_backend.c: lg struct) */
|
||||
} gw_plugin_data;
|
||||
|
||||
/* connection specific data */
|
||||
|
@ -335,8 +330,8 @@ typedef struct gw_handler_ctx {
|
|||
void * gw_init(void);
|
||||
void gw_plugin_config_free(gw_plugin_config *s);
|
||||
handler_t gw_free(server *srv, void *p_d);
|
||||
int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const data_unset *du, size_t i, int sh_exec);
|
||||
int gw_set_defaults_balance(server *srv, gw_plugin_config *s, const data_unset *du);
|
||||
int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const array *a, gw_plugin_config *s, int sh_exec, const char *cpkkey);
|
||||
int gw_get_defaults_balance(server *srv, const buffer *b);
|
||||
handler_t gw_check_extension(server *srv, connection *con, gw_plugin_data *p, int uri_path_handler, size_t hctx_sz);
|
||||
handler_t gw_connection_reset(server *srv, connection *con, void *p_d);
|
||||
handler_t gw_handle_subrequest(server *srv, connection *con, void *p_d);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#include "first.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
@ -37,59 +36,120 @@ typedef gw_handler_ctx handler_ctx;
|
|||
#error "mismatched defines: (GW_FILTER != FCGI_FILTER)"
|
||||
#endif
|
||||
|
||||
SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
||||
plugin_data *p = p_d;
|
||||
const data_unset *du;
|
||||
size_t i = 0;
|
||||
|
||||
config_values_t cv[] = {
|
||||
{ "fastcgi.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
|
||||
{ "fastcgi.debug", NULL, T_CONFIG_INT , T_CONFIG_SCOPE_CONNECTION }, /* 1 */
|
||||
{ "fastcgi.map-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
|
||||
{ "fastcgi.balance", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
|
||||
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
|
||||
};
|
||||
|
||||
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->exts = NULL;
|
||||
s->exts_auth = NULL;
|
||||
s->exts_resp = NULL;
|
||||
s->debug = 0;
|
||||
s->ext_mapping = array_init();
|
||||
|
||||
cv[0].destination = s->exts; /* not used; T_CONFIG_LOCAL */
|
||||
cv[1].destination = &(s->debug);
|
||||
cv[2].destination = s->ext_mapping;
|
||||
cv[3].destination = NULL; /* not used; T_CONFIG_LOCAL */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
du = array_get_element_klen(config->value, CONST_STR_LEN("fastcgi.server"));
|
||||
if (!gw_set_defaults_backend(srv, p, du, i, 0)) {
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
|
||||
du = array_get_element_klen(config->value, CONST_STR_LEN("fastcgi.balance"));
|
||||
if (!gw_set_defaults_balance(srv, s, du)) {
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return HANDLER_GO_ON;
|
||||
static void mod_fastcgi_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: /* fastcgi.server */
|
||||
if (cpv->vtype == T_CONFIG_LOCAL) {
|
||||
gw_plugin_config * const gw = cpv->v.v;
|
||||
pconf->exts = gw->exts;
|
||||
pconf->exts_auth = gw->exts_auth;
|
||||
pconf->exts_resp = gw->exts_resp;
|
||||
}
|
||||
break;
|
||||
case 1: /* fastcgi.balance */
|
||||
/*if (cpv->vtype == T_CONFIG_LOCAL)*//*always true here for this param*/
|
||||
pconf->balance = (int)cpv->v.u;
|
||||
break;
|
||||
case 2: /* fastcgi.debug */
|
||||
pconf->debug = (int)cpv->v.u;
|
||||
break;
|
||||
case 3: /* fastcgi.map-extensions */
|
||||
pconf->ext_mapping = cpv->v.a;
|
||||
break;
|
||||
default:/* should not happen */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void mod_fastcgi_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
|
||||
do {
|
||||
mod_fastcgi_merge_config_cpv(pconf, cpv);
|
||||
} while ((++cpv)->k_id != -1);
|
||||
}
|
||||
|
||||
static void mod_fastcgi_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_fastcgi_merge_config(&p->conf,p->cvlist + p->cvlist[i].v.u2[0]);
|
||||
}
|
||||
}
|
||||
|
||||
SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
||||
static const config_plugin_keys_t cpk[] = {
|
||||
{ CONST_STR_LEN("fastcgi.server"),
|
||||
T_CONFIG_ARRAY,
|
||||
T_CONFIG_SCOPE_CONNECTION }
|
||||
,{ CONST_STR_LEN("fastcgi.balance"),
|
||||
T_CONFIG_STRING,
|
||||
T_CONFIG_SCOPE_CONNECTION }
|
||||
,{ CONST_STR_LEN("fastcgi.debug"),
|
||||
T_CONFIG_INT,
|
||||
T_CONFIG_SCOPE_CONNECTION }
|
||||
,{ CONST_STR_LEN("fastcgi.map-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_fastcgi"))
|
||||
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:{/* fastcgi.server */
|
||||
gw_plugin_config *gw = calloc(1, sizeof(gw_plugin_config));
|
||||
force_assert(gw);
|
||||
if (!gw_set_defaults_backend(srv, p, cpv->v.a, gw, 0,
|
||||
cpk[cpv->k_id].k)) {
|
||||
gw_plugin_config_free(gw);
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
cpv->v.v = gw;
|
||||
cpv->vtype = T_CONFIG_LOCAL;
|
||||
break;
|
||||
}
|
||||
case 1: /* fastcgi.balance */
|
||||
cpv->v.u = (unsigned int)gw_get_defaults_balance(srv, cpv->v.b);
|
||||
break;
|
||||
case 2: /* fastcgi.debug */
|
||||
break;
|
||||
case 3: /* fastcgi.map-extensions */
|
||||
if (!array_is_kvstring(cpv->v.a)) {
|
||||
log_error(srv->errh, __FILE__, __LINE__,
|
||||
"unexpected value for %s; "
|
||||
"expected list of \"suffix\" => \"subst\"",
|
||||
cpk[cpv->k_id].k);
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
break;
|
||||
default:/* should not happen */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* default is 0 */
|
||||
/*p->defaults.balance = (unsigned int)gw_get_defaults_balance(srv, NULL);*/
|
||||
|
||||
/* 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_fastcgi_merge_config(&p->defaults, cpv);
|
||||
}
|
||||
|
||||
return HANDLER_GO_ON;
|
||||
}
|
||||
|
||||
|
||||
static int fcgi_env_add(void *venv, const char *key, size_t key_len, const char *val, size_t val_len) {
|
||||
buffer *env = venv;
|
||||
size_t len;
|
||||
|
@ -437,55 +497,13 @@ static handler_t fcgi_recv_parse(server *srv, connection *con, struct http_respo
|
|||
return 0 == fin ? HANDLER_GO_ON : HANDLER_FINISHED;
|
||||
}
|
||||
|
||||
#define PATCH(x) \
|
||||
p->conf.x = s->x;
|
||||
static int fcgi_patch_connection(server *srv, connection *con, plugin_data *p) {
|
||||
size_t i, j;
|
||||
plugin_config *s = p->config_storage[0];
|
||||
|
||||
PATCH(exts);
|
||||
PATCH(exts_auth);
|
||||
PATCH(exts_resp);
|
||||
PATCH(debug);
|
||||
PATCH(balance);
|
||||
PATCH(ext_mapping);
|
||||
|
||||
/* 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];
|
||||
|
||||
/* 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("fastcgi.server"))) {
|
||||
PATCH(exts);
|
||||
PATCH(exts_auth);
|
||||
PATCH(exts_resp);
|
||||
} else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("fastcgi.debug"))) {
|
||||
PATCH(debug);
|
||||
} else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("fastcgi.balance"))) {
|
||||
PATCH(balance);
|
||||
} else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("fastcgi.map-extensions"))) {
|
||||
PATCH(ext_mapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#undef PATCH
|
||||
|
||||
static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
|
||||
plugin_data *p = p_d;
|
||||
handler_t rc;
|
||||
|
||||
if (con->mode != DIRECT) return HANDLER_GO_ON;
|
||||
|
||||
fcgi_patch_connection(srv, con, p);
|
||||
mod_fastcgi_patch_config(con, p);
|
||||
if (NULL == p->conf.exts) return HANDLER_GO_ON;
|
||||
|
||||
rc = gw_check_extension(srv, con, p, uri_path_handler, 0);
|
||||
|
|
589
src/mod_proxy.c
589
src/mod_proxy.c
|
@ -45,20 +45,17 @@ typedef enum {
|
|||
} proxy_forwarded_t;
|
||||
|
||||
typedef struct {
|
||||
gw_plugin_config gw;
|
||||
array *forwarded_params;
|
||||
array *header_params;
|
||||
unsigned short replace_http_host;
|
||||
unsigned int forwarded;
|
||||
|
||||
http_header_remap_opts header;
|
||||
gw_plugin_config gw; /* start must match layout of gw_plugin_config */
|
||||
unsigned int replace_http_host;
|
||||
unsigned int forwarded;
|
||||
http_header_remap_opts header;
|
||||
} plugin_config;
|
||||
|
||||
typedef struct {
|
||||
PLUGIN_DATA;
|
||||
plugin_config **config_storage;
|
||||
|
||||
plugin_config conf;
|
||||
PLUGIN_DATA;
|
||||
pid_t srv_pid; /* must match layout of gw_plugin_data through conf member */
|
||||
plugin_config conf;
|
||||
plugin_config defaults;
|
||||
} plugin_data;
|
||||
|
||||
static int proxy_check_extforward;
|
||||
|
@ -71,218 +68,356 @@ typedef struct {
|
|||
|
||||
|
||||
INIT_FUNC(mod_proxy_init) {
|
||||
plugin_data *p;
|
||||
return calloc(1, sizeof(plugin_data));
|
||||
}
|
||||
|
||||
p = calloc(1, sizeof(*p));
|
||||
|
||||
return p;
|
||||
static void mod_proxy_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 5: /* proxy.header */
|
||||
if (cpv->vtype == T_CONFIG_LOCAL) free(cpv->v.v);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FREE_FUNC(mod_proxy_free) {
|
||||
plugin_data *p = p_d;
|
||||
plugin_data *p = p_d;
|
||||
if (!p) return HANDLER_GO_ON;
|
||||
|
||||
UNUSED(srv);
|
||||
mod_proxy_free_config(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;
|
||||
|
||||
array_free(s->forwarded_params);
|
||||
array_free(s->header_params);
|
||||
|
||||
/*assert(0 == offsetof(s->gw));*/
|
||||
gw_plugin_config_free(&s->gw);
|
||||
/*free(s);*//*free'd by gw_plugin_config_free()*/
|
||||
}
|
||||
free(p->config_storage);
|
||||
}
|
||||
|
||||
free(p);
|
||||
|
||||
return HANDLER_GO_ON;
|
||||
return gw_free(srv, p);
|
||||
}
|
||||
|
||||
SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
|
||||
plugin_data *p = p_d;
|
||||
const data_unset *du;
|
||||
size_t i = 0;
|
||||
static void mod_proxy_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: /* proxy.server */
|
||||
if (cpv->vtype == T_CONFIG_LOCAL) {
|
||||
gw_plugin_config * const gw = cpv->v.v;
|
||||
pconf->gw.exts = gw->exts;
|
||||
pconf->gw.exts_auth = gw->exts_auth;
|
||||
pconf->gw.exts_resp = gw->exts_resp;
|
||||
}
|
||||
break;
|
||||
case 1: /* proxy.balance */
|
||||
/*if (cpv->vtype == T_CONFIG_LOCAL)*//*always true here for this param*/
|
||||
pconf->gw.balance = (int)cpv->v.u;
|
||||
break;
|
||||
case 2: /* proxy.debug */
|
||||
pconf->gw.debug = (int)cpv->v.u;
|
||||
break;
|
||||
case 3: /* proxy.map-extensions */
|
||||
pconf->gw.ext_mapping = cpv->v.a;
|
||||
break;
|
||||
case 4: /* proxy.forwarded */
|
||||
/*if (cpv->vtype == T_CONFIG_LOCAL)*//*always true here for this param*/
|
||||
pconf->forwarded = cpv->v.u;
|
||||
break;
|
||||
case 5: /* proxy.header */
|
||||
/*if (cpv->vtype == T_CONFIG_LOCAL)*//*always true here for this param*/
|
||||
pconf->header = *(http_header_remap_opts *)cpv->v.v; /*(copies struct)*/
|
||||
break;
|
||||
case 6: /* proxy.replace-http-host */
|
||||
pconf->replace_http_host = cpv->v.u;
|
||||
break;
|
||||
default:/* should not happen */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
config_values_t cv[] = {
|
||||
{ "proxy.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
|
||||
{ "proxy.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
|
||||
{ "proxy.balance", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
|
||||
{ "proxy.replace-http-host", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
|
||||
{ "proxy.forwarded", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
|
||||
{ "proxy.header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
|
||||
{ "proxy.map-extensions", NULL, T_CONFIG_ARRAY, 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 *));
|
||||
static void mod_proxy_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv)
|
||||
{
|
||||
do {
|
||||
mod_proxy_merge_config_cpv(pconf, cpv);
|
||||
} while ((++cpv)->k_id != -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;
|
||||
|
||||
s = calloc(1, sizeof(plugin_config));
|
||||
s->gw.debug = 0;
|
||||
s->replace_http_host = 0;
|
||||
s->forwarded_params = array_init();
|
||||
s->forwarded = PROXY_FORWARDED_NONE;
|
||||
s->header_params = array_init();
|
||||
s->gw.ext_mapping = array_init();
|
||||
static void mod_proxy_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_proxy_merge_config(&p->conf, p->cvlist+p->cvlist[i].v.u2[0]);
|
||||
}
|
||||
}
|
||||
|
||||
cv[0].destination = NULL; /* T_CONFIG_LOCAL */
|
||||
cv[1].destination = &(s->gw.debug);
|
||||
cv[2].destination = NULL; /* T_CONFIG_LOCAL */
|
||||
cv[3].destination = &(s->replace_http_host);
|
||||
cv[4].destination = s->forwarded_params;
|
||||
cv[5].destination = s->header_params;
|
||||
cv[6].destination = s->gw.ext_mapping;
|
||||
|
||||
p->config_storage[i] = s;
|
||||
static unsigned int mod_proxy_parse_forwarded(server *srv, const array *a)
|
||||
{
|
||||
unsigned int forwarded = 0;
|
||||
for (uint32_t j = 0, used = a->used; j < used; ++j) {
|
||||
proxy_forwarded_t param;
|
||||
data_unset *du = a->data[j];
|
||||
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 if (buffer_eq_slen(&du->key, CONST_STR_LEN("host")))
|
||||
param = PROXY_FORWARDED_HOST;
|
||||
else if (buffer_eq_slen(&du->key, CONST_STR_LEN("proto")))
|
||||
param = PROXY_FORWARDED_PROTO;
|
||||
else if (buffer_eq_slen(&du->key, CONST_STR_LEN("remote_user")))
|
||||
param = PROXY_FORWARDED_REMOTE_USER;
|
||||
else {
|
||||
log_error(srv->errh, __FILE__, __LINE__,
|
||||
"proxy.forwarded keys must be one of: "
|
||||
"by, for, host, proto, remote_user, but not: %s", du->key.ptr);
|
||||
return UINT_MAX;
|
||||
}
|
||||
if (du->type == TYPE_STRING) {
|
||||
data_string *ds = (data_string *)du;
|
||||
if (buffer_eq_slen(&ds->value, CONST_STR_LEN("enable")))
|
||||
forwarded |= param;
|
||||
else if (!buffer_eq_slen(&ds->value, CONST_STR_LEN("disable"))) {
|
||||
log_error(srv->errh, __FILE__, __LINE__,
|
||||
"proxy.forwarded 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) forwarded |= param;
|
||||
}
|
||||
else {
|
||||
log_error(srv->errh, __FILE__, __LINE__,
|
||||
"proxy.forwarded values must be one of: "
|
||||
"0, 1, enable, disable; error for key: %s", du->key.ptr);
|
||||
return UINT_MAX;
|
||||
}
|
||||
}
|
||||
return forwarded;
|
||||
}
|
||||
|
||||
if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
|
||||
du = array_get_element_klen(config->value, CONST_STR_LEN("proxy.server"));
|
||||
if (!gw_set_defaults_backend(srv, (gw_plugin_data *)p, du, i, 0)) {
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
static http_header_remap_opts * mod_proxy_parse_header_opts(server *srv, const array *a)
|
||||
{
|
||||
http_header_remap_opts header;
|
||||
memset(&header, 0, sizeof(header));
|
||||
for (uint32_t j = 0, used = a->used; j < used; ++j) {
|
||||
data_array *da = (data_array *)a->data[j];
|
||||
if (buffer_eq_slen(&da->key, CONST_STR_LEN("https-remap"))) {
|
||||
data_string *ds = (data_string *)da;
|
||||
if (ds->type != TYPE_STRING) {
|
||||
log_error(srv->errh, __FILE__, __LINE__,
|
||||
"unexpected value for proxy.header; "
|
||||
"expected \"enable\" or \"disable\" for https-remap");
|
||||
return NULL;
|
||||
}
|
||||
header.https_remap =
|
||||
!buffer_eq_slen(&ds->value, CONST_STR_LEN("disable"))
|
||||
&& !buffer_eq_slen(&ds->value, CONST_STR_LEN("0"));
|
||||
continue;
|
||||
}
|
||||
else if (buffer_eq_slen(&da->key, CONST_STR_LEN("upgrade"))) {
|
||||
data_string *ds = (data_string *)da;
|
||||
if (ds->type != TYPE_STRING) {
|
||||
log_error(srv->errh, __FILE__, __LINE__,
|
||||
"unexpected value for proxy.header; "
|
||||
"expected \"upgrade\" => \"enable\" or \"disable\"");
|
||||
return NULL;
|
||||
}
|
||||
header.upgrade =
|
||||
!buffer_eq_slen(&ds->value, CONST_STR_LEN("disable"))
|
||||
&& !buffer_eq_slen(&ds->value, CONST_STR_LEN("0"));
|
||||
continue;
|
||||
}
|
||||
else if (buffer_eq_slen(&da->key, CONST_STR_LEN("connect"))) {
|
||||
data_string *ds = (data_string *)da;
|
||||
if (ds->type != TYPE_STRING) {
|
||||
log_error(srv->errh, __FILE__, __LINE__,
|
||||
"unexpected value for proxy.header; "
|
||||
"expected \"connect\" => \"enable\" or \"disable\"");
|
||||
return NULL;
|
||||
}
|
||||
header.connect_method =
|
||||
!buffer_eq_slen(&ds->value, CONST_STR_LEN("disable"))
|
||||
&& !buffer_eq_slen(&ds->value, CONST_STR_LEN("0"));
|
||||
continue;
|
||||
}
|
||||
if (da->type != TYPE_ARRAY || !array_is_kvstring(&da->value)) {
|
||||
log_error(srv->errh, __FILE__, __LINE__,
|
||||
"unexpected value for proxy.header; "
|
||||
"expected ( \"param\" => ( \"key\" => \"value\" ) ) near key %s",
|
||||
da->key.ptr);
|
||||
return NULL;
|
||||
}
|
||||
if (buffer_eq_slen(&da->key, CONST_STR_LEN("map-urlpath"))) {
|
||||
header.urlpaths = &da->value;
|
||||
}
|
||||
else if (buffer_eq_slen(&da->key, CONST_STR_LEN("map-host-request"))) {
|
||||
header.hosts_request = &da->value;
|
||||
}
|
||||
else if (buffer_eq_slen(&da->key, CONST_STR_LEN("map-host-response"))) {
|
||||
header.hosts_response = &da->value;
|
||||
}
|
||||
else {
|
||||
log_error(srv->errh, __FILE__, __LINE__,
|
||||
"unexpected key for proxy.header; "
|
||||
"expected ( \"param\" => ( \"key\" => \"value\" ) ) near key %s",
|
||||
da->key.ptr);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
du = array_get_element_klen(config->value, CONST_STR_LEN("proxy.balance"));
|
||||
if (!gw_set_defaults_balance(srv, &s->gw, du)) {
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
http_header_remap_opts *opts = malloc(sizeof(header));
|
||||
force_assert(opts);
|
||||
memcpy(opts, &header, sizeof(header));
|
||||
return opts;
|
||||
}
|
||||
|
||||
/* disable check-local for all exts (default enabled) */
|
||||
if (s->gw.exts) { /*(check after gw_set_defaults_backend())*/
|
||||
for (size_t j = 0; j < s->gw.exts->used; ++j) {
|
||||
gw_extension *ex = s->gw.exts->exts[j];
|
||||
for (size_t n = 0; n < ex->used; ++n) {
|
||||
ex->hosts[n]->check_local = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!array_is_kvany(s->forwarded_params)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"unexpected value for proxy.forwarded; expected ( \"param\" => \"value\" )");
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
for (size_t j = 0, used = s->forwarded_params->used; j < used; ++j) {
|
||||
proxy_forwarded_t param;
|
||||
du = s->forwarded_params->data[j];
|
||||
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 if (buffer_is_equal_string(&du->key, CONST_STR_LEN("host"))) {
|
||||
param = PROXY_FORWARDED_HOST;
|
||||
} else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("proto"))) {
|
||||
param = PROXY_FORWARDED_PROTO;
|
||||
} 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",
|
||||
"proxy.forwarded keys must be one of: by, for, host, proto, 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->forwarded |= param;
|
||||
} else if (!buffer_is_equal_string(&ds->value, CONST_STR_LEN("disable"))) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "sb",
|
||||
"proxy.forwarded 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->forwarded |= param;
|
||||
} else {
|
||||
log_error_write(srv, __FILE__, __LINE__, "sb",
|
||||
"proxy.forwarded values must be one of: 0, 1, enable, disable; error for key:", &du->key);
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
}
|
||||
SETDEFAULTS_FUNC(mod_proxy_set_defaults)
|
||||
{
|
||||
static const config_plugin_keys_t cpk[] = {
|
||||
{ CONST_STR_LEN("proxy.server"),
|
||||
T_CONFIG_ARRAY,
|
||||
T_CONFIG_SCOPE_CONNECTION }
|
||||
,{ CONST_STR_LEN("proxy.balance"),
|
||||
T_CONFIG_STRING,
|
||||
T_CONFIG_SCOPE_CONNECTION }
|
||||
,{ CONST_STR_LEN("proxy.debug"),
|
||||
T_CONFIG_INT,
|
||||
T_CONFIG_SCOPE_CONNECTION }
|
||||
,{ CONST_STR_LEN("proxy.map-extensions"),
|
||||
T_CONFIG_ARRAY,
|
||||
T_CONFIG_SCOPE_CONNECTION }
|
||||
,{ CONST_STR_LEN("proxy.forwarded"),
|
||||
T_CONFIG_ARRAY,
|
||||
T_CONFIG_SCOPE_CONNECTION }
|
||||
,{ CONST_STR_LEN("proxy.header"),
|
||||
T_CONFIG_ARRAY,
|
||||
T_CONFIG_SCOPE_CONNECTION }
|
||||
,{ CONST_STR_LEN("proxy.replace-http-host"),
|
||||
T_CONFIG_BOOL,
|
||||
T_CONFIG_SCOPE_CONNECTION }
|
||||
,{ NULL, 0,
|
||||
T_CONFIG_UNSET,
|
||||
T_CONFIG_SCOPE_UNSET }
|
||||
};
|
||||
|
||||
if (!array_is_kvany(s->header_params)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"unexpected value for proxy.header; expected ( \"param\" => ( \"key\" => \"value\" ) )");
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
for (size_t j = 0, used = s->header_params->used; j < used; ++j) {
|
||||
data_array *da = (data_array *)s->header_params->data[j];
|
||||
if (buffer_is_equal_string(&da->key, CONST_STR_LEN("https-remap"))) {
|
||||
data_string *ds = (data_string *)da;
|
||||
if (ds->type != TYPE_STRING) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"unexpected value for proxy.header; expected \"enable\" or \"disable\" for https-remap");
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
s->header.https_remap = !buffer_is_equal_string(&ds->value, CONST_STR_LEN("disable"))
|
||||
&& !buffer_is_equal_string(&ds->value, CONST_STR_LEN("0"));
|
||||
continue;
|
||||
}
|
||||
else if (buffer_is_equal_string(&da->key, CONST_STR_LEN("upgrade"))) {
|
||||
data_string *ds = (data_string *)da;
|
||||
if (ds->type != TYPE_STRING) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"unexpected value for proxy.header; expected \"upgrade\" => \"enable\" or \"disable\"");
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
s->header.upgrade = !buffer_is_equal_string(&ds->value, CONST_STR_LEN("disable"))
|
||||
&& !buffer_is_equal_string(&ds->value, CONST_STR_LEN("0"));
|
||||
continue;
|
||||
}
|
||||
else if (buffer_is_equal_string(&da->key, CONST_STR_LEN("connect"))) {
|
||||
data_string *ds = (data_string *)da;
|
||||
if (ds->type != TYPE_STRING) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"unexpected value for proxy.header; expected \"connect\" => \"enable\" or \"disable\"");
|
||||
return HANDLER_ERROR;
|
||||