diff options
-rw-r--r-- | src/gw_backend.c | 351 | ||||
-rw-r--r-- | src/gw_backend.h | 28 | ||||
-rw-r--r-- | src/response.h | 4 |
3 files changed, 234 insertions, 149 deletions
diff --git a/src/gw_backend.c b/src/gw_backend.c index cc288478..a79288ed 100644 --- a/src/gw_backend.c +++ b/src/gw_backend.c @@ -124,17 +124,6 @@ static void gw_proc_free(gw_proc *f) { static gw_host *gw_host_init(void) { gw_host *f = calloc(1, sizeof(*f)); force_assert(f); - - f->id = buffer_init(); - f->host = buffer_init(); - f->unixsocket = buffer_init(); - f->docroot = buffer_init(); - f->bin_path = buffer_init(); - f->bin_env = array_init(); - f->bin_env_copy = array_init(); - f->strip_request_uri = buffer_init(); - f->xsendfile_docroot = array_init(); - return f; } @@ -145,16 +134,6 @@ static void gw_host_free(gw_host *h) { return; } - buffer_free(h->id); - buffer_free(h->host); - buffer_free(h->unixsocket); - buffer_free(h->docroot); - buffer_free(h->bin_path); - buffer_free(h->strip_request_uri); - array_free(h->bin_env); - array_free(h->bin_env_copy); - array_free(h->xsendfile_docroot); - gw_proc_free(h->first); gw_proc_free(h->unused_procs); @@ -390,7 +369,9 @@ static int gw_proc_sockaddr_init(server *srv, gw_host *host, gw_proc *proc) { else { /* overwrite host->host buffer with IP addr string so that * any further use of gw_host does not block on DNS lookup */ - sock_addr_inet_ntop_copy_buffer(host->host, &addr); + buffer *h; + *(const buffer **)&h = host->host; + sock_addr_inet_ntop_copy_buffer(h, &addr); host->family = sock_addr_get_family(&addr); } buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("tcp:")); @@ -518,7 +499,7 @@ static int gw_spawn_connection(server *srv, gw_host *host, gw_proc *proc, int de env.used = 0; /* build clean environment */ - if (host->bin_env_copy->used) { + if (host->bin_env_copy && host->bin_env_copy->used) { for (i = 0; i < host->bin_env_copy->used; ++i) { data_string *ds=(data_string *)host->bin_env_copy->data[i]; char *ge; @@ -539,10 +520,12 @@ static int gw_spawn_connection(server *srv, gw_host *host, gw_proc *proc, int de } /* create environment */ - for (i = 0; i < host->bin_env->used; ++i) { - data_string *ds = (data_string *)host->bin_env->data[i]; - - env_add(&env,CONST_BUF_LEN(&ds->key),CONST_BUF_LEN(&ds->value)); + if (host->bin_env) { + for (i = 0; i < host->bin_env->used; ++i) { + data_string *ds = (data_string *)host->bin_env->data[i]; + env_add(&env, CONST_BUF_LEN(&ds->key), + CONST_BUF_LEN(&ds->value)); + } } for (i = 0; i < env.used; ++i) { @@ -701,7 +684,7 @@ 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, buffer *unixsocket) { +static gw_host * unixsocket_is_dup(gw_plugin_data *p, const 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) { @@ -735,7 +718,7 @@ static gw_host * unixsocket_is_dup(gw_plugin_data *p, buffer *unixsocket) { return NULL; } -static int parse_binpath(char_array *env, buffer *b) { +static int parse_binpath(char_array *env, const buffer *b) { char *start = b->ptr; char c; /* search for spaces */ @@ -1202,7 +1185,81 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const array *a, gw_p /* per-module plugin_data MUST have pointer-compatible common "base class" * with gw_plugin_data (stemming from gw_plugin_config compatibility) */ - buffer *gw_mode; + static const config_plugin_keys_t cpk[] = { + { CONST_STR_LEN("host"), + T_CONFIG_STRING, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("port"), + T_CONFIG_SHORT, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("socket"), + T_CONFIG_STRING, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("listen-backlog"), + T_CONFIG_INT, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("bin-path"), + T_CONFIG_STRING, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("kill-signal"), + T_CONFIG_SHORT, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("check-local"), + T_CONFIG_BOOL, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("mode"), + T_CONFIG_STRING, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("docroot"), + T_CONFIG_STRING, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("min-procs"), + T_CONFIG_SHORT, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("max-procs"), + T_CONFIG_SHORT, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("max-load-per-proc"), + T_CONFIG_SHORT, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("idle-timeout"), + T_CONFIG_SHORT, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("disable-time"), + T_CONFIG_SHORT, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("bin-environment"), + T_CONFIG_ARRAY, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("bin-copy-environment"), + T_CONFIG_ARRAY, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("broken-scriptfilename"), + T_CONFIG_BOOL, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("strip-request-uri"), + T_CONFIG_STRING, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("fix-root-scriptname"), + T_CONFIG_BOOL, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("allow-x-send-file"), + T_CONFIG_BOOL, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("x-sendfile"), + T_CONFIG_BOOL, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("x-sendfile-docroot"), + T_CONFIG_ARRAY, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("tcp-fin-propagate"), + T_CONFIG_BOOL, + T_CONFIG_SCOPE_CONNECTION } + ,{ NULL, 0, + T_CONFIG_UNSET, + T_CONFIG_SCOPE_UNSET } + }; + gw_host *host = NULL; if (!array_is_kvarray(a)) { @@ -1215,8 +1272,6 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const array *a, gw_p p->srv_pid = srv->pid; - gw_mode = buffer_init(); - s->exts = gw_extensions_init(); s->exts_auth = gw_extensions_init(); s->exts_resp = gw_extensions_init(); @@ -1243,53 +1298,29 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const array *a, gw_p */ 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[] = { - { "host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ - { "docroot", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ - { "mode", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */ - { "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_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 */ - { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 9 */ - { "idle-timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 10 */ - { "disable-time", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 11 */ - - { "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_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_BOOL, T_CONFIG_SCOPE_CONNECTION }, /* 18 */ - { "listen-backlog", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION }, /* 19 */ - { "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_BOOL, T_CONFIG_SCOPE_CONNECTION }, /* 22 */ - - { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } - }; - unsigned short host_mode = GW_RESPONDER; - - if (da_host->type != TYPE_ARRAY || !array_is_kvany(&da_host->value)){ - log_error_write(srv, __FILE__, __LINE__, "SBS", - "unexpected value for gw.server near [", - &da_host->key, "](string); expected ( \"ext\" => ( \"backend-label\" => ( \"key\" => \"value\" )))"); - + data_array * const da_host = (data_array *)da_ext->value.data[n]; + + if (da_host->type != TYPE_ARRAY + || !array_is_kvany(&da_host->value)){ + log_error(srv->errh, __FILE__, __LINE__, + "unexpected value for gw.server near [%s](string); " + "expected ( \"ext\" => " + "( \"backend-label\" => ( \"key\" => \"value\" )))", + da_host->key.ptr ? da_host->key.ptr : ""); goto error; } - host = gw_host_init(); - buffer_clear(gw_mode); + config_plugin_value_t cvlist[sizeof(cpk)/sizeof(cpk[0])+1]; + memset(cvlist, 0, sizeof(cvlist)); - buffer_copy_buffer(host->id, &da_host->key); + array *ca = &da_host->value; + if (!config_plugin_values_init_block(srv, ca, cpk, cpkkey, cvlist)) + goto error; + + unsigned short host_mode = GW_RESPONDER; + host = gw_host_init(); + host->id = &da_host->key; host->check_local = 1; host->min_procs = 4; host->max_procs = 4; @@ -1303,34 +1334,111 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const array *a, gw_p host->xsendfile_allow = 0; host->refcount = 0; - fcv[0].destination = host->host; - fcv[1].destination = host->docroot; - fcv[2].destination = gw_mode; - fcv[3].destination = host->unixsocket; - fcv[4].destination = host->bin_path; - - fcv[5].destination = &(host->check_local); - fcv[6].destination = &(host->port); - fcv[7].destination = &(host->min_procs); - fcv[8].destination = &(host->max_procs); - fcv[9].destination = &(host->max_load_per_proc); - fcv[10].destination = &(host->idle_timeout); - fcv[11].destination = &(host->disable_time); - - fcv[12].destination = host->bin_env; - fcv[13].destination = host->bin_env_copy; - fcv[14].destination = &(host->break_scriptfilename_for_php); - fcv[15].destination = &(host->xsendfile_allow); - fcv[16].destination = host->strip_request_uri; - fcv[17].destination = &(host->kill_signal); - fcv[18].destination = &(host->fix_root_path_name); - fcv[19].destination = &(host->listen_backlog); - fcv[20].destination = &(host->xsendfile_allow); - fcv[21].destination = host->xsendfile_docroot; - fcv[22].destination = &(host->tcp_fin_propagate); - - if (0 != config_insert_values_internal(srv, &da_host->value, fcv, T_CONFIG_SCOPE_CONNECTION)) { - goto error; + config_plugin_value_t *cpv = cvlist; + for (; -1 != cpv->k_id; ++cpv) { + switch (cpv->k_id) { + case 0: /* host */ + host->host = cpv->v.b; + break; + case 1: /* port */ + host->port = cpv->v.shrt; + break; + case 2: /* socket */ + host->unixsocket = cpv->v.b; + break; + case 3: /* listen-backlog */ + host->listen_backlog = cpv->v.u; + break; + case 4: /* bin-path */ + host->bin_path = cpv->v.b; + break; + case 5: /* kill-signal */ + host->kill_signal = cpv->v.shrt; + break; + case 6: /* check-local */ + host->check_local = (0 != cpv->v.u); + break; + case 7: /* mode */ + if (!buffer_string_is_empty(cpv->v.b)) { + const buffer *b = cpv->v.b; + if (buffer_eq_slen(b, CONST_STR_LEN("responder"))) + host_mode = GW_RESPONDER; + else if (buffer_eq_slen(b, CONST_STR_LEN("authorizer"))) + host_mode = GW_AUTHORIZER; + else + log_error(srv->errh, __FILE__, __LINE__, + "WARNING: unknown gw mode: %s " + "(ignored, mode set to responder)", b->ptr); + } + break; + case 8: /* docroot */ + host->docroot = cpv->v.b; + break; + case 9: /* min-procs */ + host->min_procs = cpv->v.shrt; + break; + case 10:/* max-procs */ + host->max_procs = cpv->v.shrt; + break; + case 11:/* max-load-per-proc */ + host->max_load_per_proc = cpv->v.shrt; + break; + case 12:/* idle-timeout */ + host->idle_timeout = cpv->v.shrt; + break; + case 13:/* disable-time */ + host->disable_time = cpv->v.shrt; + break; + case 14:/* bin-environment */ + host->bin_env = cpv->v.a; + break; + case 15:/* bin-copy-environment */ + host->bin_env_copy = cpv->v.a; + break; + case 16:/* broken-scriptfilename */ + host->break_scriptfilename_for_php = (0 != cpv->v.u); + break; + case 17:/* strip-request-uri */ + host->strip_request_uri = cpv->v.b; + break; + case 18:/* fix-root-scriptname */ + host->fix_root_path_name = (0 != cpv->v.u); + break; + case 19:/* allow-x-send-file */ + host->xsendfile_allow = (0 != cpv->v.u); + break; + case 20:/* x-sendfile */ + host->xsendfile_allow = (0 != cpv->v.u); + break; + case 21:/* x-sendfile-docroot */ + host->xsendfile_docroot = cpv->v.a; + if (cpv->v.a->used) { + for (uint32_t k = 0; k < cpv->v.a->used; ++k) { + data_string *ds = (data_string *)cpv->v.a->data[k]; + if (ds->type != TYPE_STRING) { + log_error(srv->errh, __FILE__, __LINE__, + "unexpected type for x-sendfile-docroot; " + "expected: \"x-sendfile-docroot\" => " + "( \"/allowed/path\", ... )"); + goto error; + } + if (ds->value.ptr[0] != '/') { + log_error(srv->errh, __FILE__, __LINE__, + "x-sendfile-docroot paths must begin with " + "'/'; invalid: \"%s\"", ds->value.ptr); + goto error; + } + buffer_path_simplify(&ds->value, &ds->value); + buffer_append_slash(&ds->value); + } + } + break; + case 22:/* tcp-fin-propagate */ + host->tcp_fin_propagate = (0 != cpv->v.u); + break; + default: + break; + } } for (uint32_t m = 0; m < da_host->value.used; ++m) { @@ -1354,7 +1462,7 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const array *a, gw_p if (!buffer_string_is_empty(host->host) && *host->host->ptr == '/' && buffer_string_is_empty(host->unixsocket)) { - buffer_copy_buffer(host->unixsocket, host->host); + host->unixsocket = host->host; } if (!buffer_string_is_empty(host->unixsocket)) { @@ -1404,8 +1512,8 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const array *a, gw_p } if (buffer_string_is_empty(host->host)) { - buffer_copy_string_len(host->host, - CONST_STR_LEN("127.0.0.1")); + static const buffer lhost = {CONST_STR_LEN("127.0.0.1"), 0}; + host->host = &lhost; } host->family = (NULL != strchr(host->host->ptr, ':')) @@ -1544,37 +1652,6 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const array *a, gw_p if (0 != gw_proc_sockaddr_init(srv, host, proc)) goto error; } - if (!buffer_string_is_empty(gw_mode)) { - if (strcmp(gw_mode->ptr, "responder") == 0) { - host_mode = GW_RESPONDER; - } else if (strcmp(gw_mode->ptr, "authorizer") == 0) { - host_mode = GW_AUTHORIZER; - } else { - log_error_write(srv, __FILE__, __LINE__, "sbs", - "WARNING: unknown gw mode:", - gw_mode,"(ignored, mode set to responder)"); - } - } - - if (host->xsendfile_docroot->used) { - 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) { - log_error_write(srv, __FILE__, __LINE__, "s", - "unexpected type for x-sendfile-docroot; expected: \"x-sendfile-docroot\" => ( \"/allowed/path\", ... )"); - goto error; - } - if (ds->value.ptr[0] != '/') { - log_error_write(srv, __FILE__, __LINE__, "SBs", - "x-sendfile-docroot paths must begin with '/'; invalid: \"", &ds->value, "\""); - goto error; - } - buffer_path_simplify(&ds->value, &ds->value); - buffer_append_slash(&ds->value); - } - } - /* s->exts is list of exts -> hosts * s->exts now used as combined list * of authorizer and responder hosts (for backend maintenance) @@ -1602,12 +1679,10 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const array *a, gw_p } } - buffer_free(gw_mode); return 1; error: if (NULL != host) gw_host_free(host); - buffer_free(gw_mode); return 0; } diff --git a/src/gw_backend.h b/src/gw_backend.h index d5909c86..cb17b236 100644 --- a/src/gw_backend.h +++ b/src/gw_backend.h @@ -48,7 +48,7 @@ typedef struct gw_proc { typedef struct { /* the key that is used to reference this value */ - buffer *id; + const buffer *id; /* list of processes handling this extension * sorted by lowest load @@ -116,7 +116,7 @@ typedef struct { * "localhost" (INADDR_LOOPBACK) is assumed. * */ - buffer *host; + const buffer *host; unsigned short port; unsigned short family; /* sa_family_t */ @@ -128,7 +128,7 @@ typedef struct { * - more control (on locally) * - more speed (no extra overhead) */ - buffer *unixsocket; + const buffer *unixsocket; /* if socket is local we can start the gw process ourself * @@ -137,16 +137,16 @@ typedef struct { * check min_procs and max_procs for the number * of process to start up */ - buffer *bin_path; + const buffer *bin_path; /* bin-path is set bin-environment is taken to * create the environement before starting the * FastCGI process * */ - array *bin_env; + const array *bin_env; - array *bin_env_copy; + const array *bin_env_copy; /* * docroot-translation between URL->phys and the @@ -157,7 +157,7 @@ typedef struct { * - chroot if local * */ - buffer *docroot; + const buffer *docroot; /* * check_local tells you if the phys file is stat()ed @@ -193,13 +193,13 @@ typedef struct { * */ unsigned short xsendfile_allow; - array *xsendfile_docroot; + const array *xsendfile_docroot; int32_t load; uint32_t max_id; /* corresponds most of the time to num_procs */ - buffer *strip_request_uri; + const buffer *strip_request_uri; unsigned short tcp_fin_propagate; unsigned short kill_signal; /* we need a setting for this as libfcgi @@ -327,11 +327,21 @@ typedef struct gw_handler_ctx { } gw_handler_ctx; +__attribute_cold__ void * gw_init(void); + +__attribute_cold__ void gw_plugin_config_free(gw_plugin_config *s); + +__attribute_cold__ handler_t gw_free(server *srv, void *p_d); + +__attribute_cold__ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const array *a, gw_plugin_config *s, int sh_exec, const char *cpkkey); + +__attribute_cold__ 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); diff --git a/src/response.h b/src/response.h index 3e3fa369..6f4938a8 100644 --- a/src/response.h +++ b/src/response.h @@ -14,8 +14,8 @@ int http_response_write_header(server *srv, connection *con); typedef struct http_cgi_opts_t { int authorizer; int break_scriptfilename_for_php; - buffer *docroot; - buffer *strip_request_uri; + const buffer *docroot; + const buffer *strip_request_uri; } http_cgi_opts; enum { |