diff --git a/src/mod_scgi.c b/src/mod_scgi.c index 5c2fcfe5..e1adc947 100644 --- a/src/mod_scgi.c +++ b/src/mod_scgi.c @@ -212,6 +212,15 @@ typedef struct { */ unsigned short fix_root_path_name; + + /* + * If the backend includes X-Sendfile in the response + * we use the value as filename and ignore the content. + * + */ + unsigned short xsendfile_allow; + array *xsendfile_docroot; + ssize_t load; /* replace by host->load */ size_t max_id; /* corresponds most of the time to @@ -416,6 +425,7 @@ static scgi_extension_host *scgi_host_init(void) { f->bin_path = buffer_init(); f->bin_env = array_init(); f->bin_env_copy = array_init(); + f->xsendfile_docroot = array_init(); return f; } @@ -429,6 +439,7 @@ static void scgi_host_free(scgi_extension_host *h) { buffer_free(h->bin_path); array_free(h->bin_env); array_free(h->bin_env_copy); + array_free(h->xsendfile_docroot); scgi_process_free(h->first); scgi_process_free(h->unused_procs); @@ -1053,6 +1064,8 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) { { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 12 */ { "fix-root-scriptname", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 13 */ { "listen-backlog", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION }, /* 14 */ + { "x-sendfile", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 15 */ + { "x-sendfile-docroot",NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 16 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } @@ -1077,6 +1090,7 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) { df->disable_time = 60; df->fix_root_path_name = 0; df->listen_backlog = 1024; + df->xsendfile_allow = 0; fcv[0].destination = df->host; fcv[1].destination = df->docroot; @@ -1095,6 +1109,8 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) { fcv[12].destination = df->bin_env_copy; fcv[13].destination = &(df->fix_root_path_name); fcv[14].destination = &(df->listen_backlog); + fcv[15].destination = &(df->xsendfile_allow); + fcv[16].destination = df->xsendfile_docroot; if (0 != config_insert_values_internal(srv, da_host->value, fcv, T_CONFIG_SCOPE_CONNECTION)) { @@ -1227,6 +1243,25 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) { df->max_procs = 1; } + if (df->xsendfile_docroot->used) { + size_t k; + for (k = 0; k < df->xsendfile_docroot->used; ++k) { + data_string *ds = (data_string *)df->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); + } + } + /* if extension already exists, take it */ scgi_extension_insert(s->exts, da_ext->key, df); df = NULL; @@ -1916,6 +1951,14 @@ static int scgi_demux_response(server *srv, handler_ctx *hctx) { /* parse the response header */ scgi_response_parse(srv, con, p, hctx->response_header, eol); + if (hctx->host->xsendfile_allow) { + data_string *ds; + if (NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-Sendfile"))) { + http_response_xsendfile(srv, con, ds->value, hctx->host->xsendfile_docroot); + return 1; + } + } + /* enable chunked-transfer-encoding */ if (con->request.http_version == HTTP_VERSION_1_1 && !(con->parsed_response & HTTP_CONTENT_LENGTH)) {