consistent, shared code to create CGI env

consolidated from CGI, FastCGI, SCGI, SSI

Note: due to prior inconsistencies between the code in mod_cgi,
mod_fastcgi, mod_scgi, and mod_ssi, there are some minor behavior
changes.

CONTENT_LENGTH is now always set, even if 0
  (though CONTENT_LENGTH is never set for FASTCGI_AUTHORIZER)
PATH_INFO is created only if present, not if empty.
  (mod_fastcgi and mod_ssi previously set PATH_INFO="" (blank value))
PATH_TRANSLATED is now set if PATH_INFO is present
  (previously missing from mod_cgi and mod_ssi)

mod_ssi now sets DOCUMENT_ROOT to con->physical.basedir, like others
  (previously, mod_ssi set DOCUMENT_ROOT to con->physical.doc_root,
   which matched con->physical.basedir unless mod_alias changed basedir)
mod_ssi now sets REQUEST_URI to con->request.orig_uri, like others
  (previously, mod_ssi set REQUEST_URI to con->request.uri, which
   matched con->request.orig_uri except after redirects, error docs)
personal/stbuehler/mod-csrf
Glenn Strauss 7 years ago
parent 81ce160d83
commit 7fa5bfc938

@ -760,3 +760,261 @@ void http_response_backend_done (server *srv, connection *con) {
break;
}
}
int http_cgi_headers (server *srv, connection *con, http_cgi_opts *opts, http_cgi_header_append_cb cb, void *vdata) {
/* CGI-SPEC 6.1.2, FastCGI spec 6.3 and SCGI spec */
int rc = 0;
unsigned short port;
server_socket *srv_sock = con->srv_socket;
const char *s;
size_t n;
char buf[LI_ITOSTRING_LENGTH];
#ifdef HAVE_IPV6
char b2[INET6_ADDRSTRLEN + 1];
#endif
sock_addr *addr;
sock_addr addrbuf;
/* (CONTENT_LENGTH must be first for SCGI) */
if (!opts->authorizer) {
li_itostrn(buf, sizeof(buf), con->request.content_length);
rc |= cb(vdata, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
}
if (!buffer_string_is_empty(con->uri.query)) {
rc |= cb(vdata, CONST_STR_LEN("QUERY_STRING"),
CONST_BUF_LEN(con->uri.query));
} else {
rc |= cb(vdata, CONST_STR_LEN("QUERY_STRING"),
CONST_STR_LEN(""));
}
if (!buffer_string_is_empty(opts->strip_request_uri)) {
/**
* /app1/index/list
*
* stripping /app1 or /app1/ should lead to
*
* /index/list
*
*/
size_t len = buffer_string_length(opts->strip_request_uri);
if ('/' == opts->strip_request_uri->ptr[len-1]) {
--len;
}
if (buffer_string_length(con->request.orig_uri) >= len
&& 0 == memcmp(con->request.orig_uri->ptr,
opts->strip_request_uri->ptr, len)
&& con->request.orig_uri->ptr[len] == '/') {
rc |= cb(vdata, CONST_STR_LEN("REQUEST_URI"),
con->request.orig_uri->ptr+len,
buffer_string_length(con->request.orig_uri) - len);
} else {
rc |= cb(vdata, CONST_STR_LEN("REQUEST_URI"),
CONST_BUF_LEN(con->request.orig_uri));
}
} else {
rc |= cb(vdata, CONST_STR_LEN("REQUEST_URI"),
CONST_BUF_LEN(con->request.orig_uri));
}
if (!buffer_is_equal(con->request.uri, con->request.orig_uri)) {
rc |= cb(vdata, CONST_STR_LEN("REDIRECT_URI"),
CONST_BUF_LEN(con->request.uri));
}
/* set REDIRECT_STATUS for php compiled with --force-redirect
* (if REDIRECT_STATUS has not already been set by error handler) */
if (0 == con->error_handler_saved_status) {
rc |= cb(vdata, CONST_STR_LEN("REDIRECT_STATUS"),
CONST_STR_LEN("200"));
}
/*
* SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to
* http://cgi-spec.golux.com/draft-coar-cgi-v11-03-clean.html
* (6.1.14, 6.1.6, 6.1.7)
*/
if (!opts->authorizer) {
rc |= cb(vdata, CONST_STR_LEN("SCRIPT_NAME"),
CONST_BUF_LEN(con->uri.path));
if (!buffer_string_is_empty(con->request.pathinfo)) {
rc |= cb(vdata, CONST_STR_LEN("PATH_INFO"),
CONST_BUF_LEN(con->request.pathinfo));
/* PATH_TRANSLATED is only defined if PATH_INFO is set */
if (!buffer_string_is_empty(opts->docroot)) {
buffer_copy_buffer(srv->tmp_buf, opts->docroot);
} else {
buffer_copy_buffer(srv->tmp_buf, con->physical.basedir);
}
buffer_append_string_buffer(srv->tmp_buf, con->request.pathinfo);
rc |= cb(vdata, CONST_STR_LEN("PATH_TRANSLATED"),
CONST_BUF_LEN(srv->tmp_buf));
}
}
/*
* SCRIPT_FILENAME and DOCUMENT_ROOT for php
* The PHP manual http://www.php.net/manual/en/reserved.variables.php
* treatment of PATH_TRANSLATED is different from the one of CGI specs.
* (see php.ini cgi.fix_pathinfo = 1 config parameter)
*/
if (!buffer_string_is_empty(opts->docroot)) {
/* alternate docroot, e.g. for remote FastCGI or SCGI server */
buffer_copy_buffer(srv->tmp_buf, opts->docroot);
buffer_append_string_buffer(srv->tmp_buf, con->uri.path);
rc |= cb(vdata, CONST_STR_LEN("SCRIPT_FILENAME"),
CONST_BUF_LEN(srv->tmp_buf));
rc |= cb(vdata, CONST_STR_LEN("DOCUMENT_ROOT"),
CONST_BUF_LEN(opts->docroot));
} else {
if (opts->break_scriptfilename_for_php) {
/* php.ini config cgi.fix_pathinfo = 1 need a broken SCRIPT_FILENAME
* to find out what PATH_INFO is itself
*
* see src/sapi/cgi_main.c, init_request_info()
*/
buffer_copy_buffer(srv->tmp_buf, con->physical.path);
buffer_append_string_buffer(srv->tmp_buf, con->request.pathinfo);
rc |= cb(vdata, CONST_STR_LEN("SCRIPT_FILENAME"),
CONST_BUF_LEN(srv->tmp_buf));
} else {
rc |= cb(vdata, CONST_STR_LEN("SCRIPT_FILENAME"),
CONST_BUF_LEN(con->physical.path));
}
rc |= cb(vdata, CONST_STR_LEN("DOCUMENT_ROOT"),
CONST_BUF_LEN(con->physical.basedir));
}
s = get_http_method_name(con->request.http_method);
force_assert(s);
rc |= cb(vdata, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
s = get_http_version_name(con->request.http_version);
force_assert(s);
rc |= cb(vdata, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
rc |= cb(vdata, CONST_STR_LEN("SERVER_SOFTWARE"),
CONST_BUF_LEN(con->conf.server_tag));
rc |= cb(vdata, CONST_STR_LEN("GATEWAY_INTERFACE"),
CONST_STR_LEN("CGI/1.1"));
if (buffer_is_equal_caseless_string(con->uri.scheme,
CONST_STR_LEN("https"))) {
rc |= cb(vdata, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
}
addr = &srv_sock->addr;
#ifdef HAVE_IPV6
port = addr->plain.sa_family == AF_INET6
? addr->ipv6.sin6_port
: addr->ipv4.sin_port;
#else
port = addr->ipv4.sin_port;
#endif
li_utostrn(buf, sizeof(buf), ntohs(port));
rc |= cb(vdata, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
switch (addr->plain.sa_family) {
#ifdef HAVE_IPV6
case AF_INET6:
if (0 ==memcmp(&addr->ipv6.sin6_addr,&in6addr_any,sizeof(in6addr_any))){
socklen_t addrlen = sizeof(addrbuf);
if (0 == getsockname(con->fd,(struct sockaddr *)&addrbuf,&addrlen)){
addr = &addrbuf;
} else {
s = "";
break;
}
}
s = inet_ntop(AF_INET6, (const void *) &(addr->ipv6.sin6_addr),
b2, sizeof(b2)-1);
break;
#endif
case AF_INET:
if (srv_sock->addr.ipv4.sin_addr.s_addr == INADDR_ANY) {
socklen_t addrlen = sizeof(addrbuf);
if (0 == getsockname(con->fd,(struct sockaddr *)&addrbuf,&addrlen)){
addr = &addrbuf;
} else {
s = "";
break;
}
}
#ifdef HAVE_IPV6
s = inet_ntop(AF_INET, (const void *) &(addr->ipv4.sin_addr),
b2, sizeof(b2)-1);
#else
s = inet_ntoa(addr->ipv4.sin_addr);
#endif
break;
default:
s = "";
break;
}
force_assert(s);
rc |= cb(vdata, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
if (!buffer_string_is_empty(con->server_name)) {
size_t len = buffer_string_length(con->server_name);
if (con->server_name->ptr[0] == '[') {
const char *colon = strstr(con->server_name->ptr, "]:");
if (colon) len = (colon + 1) - con->server_name->ptr;
} else {
const char *colon = strchr(con->server_name->ptr, ':');
if (colon) len = colon - con->server_name->ptr;
}
rc |= cb(vdata, CONST_STR_LEN("SERVER_NAME"),
con->server_name->ptr, len);
} else {
/* set to be same as SERVER_ADDR (above) */
rc |= cb(vdata, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
}
rc |= cb(vdata, CONST_STR_LEN("REMOTE_ADDR"),
CONST_BUF_LEN(con->dst_addr_buf));
#ifdef HAVE_IPV6
port = con->dst_addr.plain.sa_family == AF_INET6
? con->dst_addr.ipv6.sin6_port
: con->dst_addr.ipv4.sin_port;
#else
port = con->dst_addr.ipv4.sin_port;
#endif
li_utostrn(buf, sizeof(buf), ntohs(port));
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];
if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
/* Security: Do not emit HTTP_PROXY in environment.
* Some executables use HTTP_PROXY to configure
* outgoing proxy. See also https://httpoxy.org/ */
if (buffer_is_equal_caseless_string(ds->key,
CONST_STR_LEN("Proxy"))) {
continue;
}
buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf,
CONST_BUF_LEN(ds->key), 1);
rc |= cb(vdata, CONST_BUF_LEN(srv->tmp_buf),
CONST_BUF_LEN(ds->value));
}
}
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);
rc |= cb(vdata, CONST_BUF_LEN(srv->tmp_buf),
CONST_BUF_LEN(ds->value));
}
}
return rc;
}

@ -70,7 +70,6 @@ typedef struct {
PLUGIN_DATA;
buffer_pid_t cgi_pid;
buffer *tmp_buf;
buffer *parse_response;
plugin_config **config_storage;
@ -121,7 +120,6 @@ INIT_FUNC(mod_cgi_init) {
force_assert(p);
p->tmp_buf = buffer_init();
p->parse_response = buffer_init();
return p;
@ -152,7 +150,6 @@ FREE_FUNC(mod_cgi_free) {
if (r->ptr) free(r->ptr);
buffer_free(p->tmp_buf);
buffer_free(p->parse_response);
free(p);
@ -836,7 +833,8 @@ static handler_t cgi_handle_fdevent(server *srv, void *ctx, int revents) {
}
static int cgi_env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
static int cgi_env_add(void *venv, const char *key, size_t key_len, const char *val, size_t val_len) {
char_array *env = venv;
char *dst;
if (!key || !val) return -1;
@ -1060,13 +1058,10 @@ static int cgi_write_request(server *srv, handler_ctx *hctx, int fd) {
static int cgi_create_env(server *srv, connection *con, plugin_data *p, handler_ctx *hctx, buffer *cgi_handler) {
pid_t pid;
#ifdef HAVE_IPV6
char b2[INET6_ADDRSTRLEN + 1];
#endif
int to_cgi_fds[2];
int from_cgi_fds[2];
struct stat st;
UNUSED(p);
#ifndef __WIN32
@ -1099,12 +1094,10 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, handler_
char **args;
int argc;
int i = 0;
char buf[LI_ITOSTRING_LENGTH];
size_t n;
char_array env;
char *c;
const char *s;
server_socket *srv_sock = con->srv_socket;
http_cgi_opts opts = { 0, 0, NULL, NULL };
/* move stdout to from_cgi_fd[1] */
dup2(from_cgi_fds[1], STDOUT_FILENO);
@ -1127,142 +1120,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, handler_
env.size = 0;
env.used = 0;
cgi_env_add(&env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_BUF_LEN(con->conf.server_tag));
if (!buffer_string_is_empty(con->server_name)) {
size_t len = buffer_string_length(con->server_name);
if (con->server_name->ptr[0] == '[') {
const char *colon = strstr(con->server_name->ptr, "]:");
if (colon) len = (colon + 1) - con->server_name->ptr;
} else {
const char *colon = strchr(con->server_name->ptr, ':');
if (colon) len = colon - con->server_name->ptr;
}
cgi_env_add(&env, CONST_STR_LEN("SERVER_NAME"), con->server_name->ptr, len);
} else {
#ifdef HAVE_IPV6
s = inet_ntop(
srv_sock->addr.plain.sa_family,
srv_sock->addr.plain.sa_family == AF_INET6 ?
(const void *) &(srv_sock->addr.ipv6.sin6_addr) :
(const void *) &(srv_sock->addr.ipv4.sin_addr),
b2, sizeof(b2)-1);
#else
s = inet_ntoa(srv_sock->addr.ipv4.sin_addr);
#endif
force_assert(s);
cgi_env_add(&env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
}
cgi_env_add(&env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
s = get_http_version_name(con->request.http_version);
force_assert(s);
cgi_env_add(&env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
li_utostrn(buf, sizeof(buf),
#ifdef HAVE_IPV6
ntohs(srv_sock->addr.plain.sa_family == AF_INET6 ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
#else
ntohs(srv_sock->addr.ipv4.sin_port)
#endif
);
cgi_env_add(&env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
switch (srv_sock->addr.plain.sa_family) {
#ifdef HAVE_IPV6
case AF_INET6:
s = inet_ntop(
srv_sock->addr.plain.sa_family,
(const void *) &(srv_sock->addr.ipv6.sin6_addr),
b2, sizeof(b2)-1);
break;
case AF_INET:
s = inet_ntop(
srv_sock->addr.plain.sa_family,
(const void *) &(srv_sock->addr.ipv4.sin_addr),
b2, sizeof(b2)-1);
break;
#else
case AF_INET:
s = inet_ntoa(srv_sock->addr.ipv4.sin_addr);
break;
#endif
default:
s = "";
break;
}
force_assert(s);
cgi_env_add(&env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
s = get_http_method_name(con->request.http_method);
force_assert(s);
cgi_env_add(&env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
if (!buffer_string_is_empty(con->request.pathinfo)) {
cgi_env_add(&env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
}
if (!buffer_string_is_empty(con->uri.query)) {
cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
} else {
cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
}
cgi_env_add(&env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
if (!buffer_is_equal(con->request.uri, con->request.orig_uri)) {
cgi_env_add(&env, CONST_STR_LEN("REDIRECT_URI"), CONST_BUF_LEN(con->request.uri));
}
/* set REDIRECT_STATUS for php compiled with --force-redirect
* (if REDIRECT_STATUS has not already been set by error handler) */
if (0 == con->error_handler_saved_status) {
cgi_env_add(&env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200"));
}
switch (con->dst_addr.plain.sa_family) {
#ifdef HAVE_IPV6
case AF_INET6:
s = inet_ntop(
con->dst_addr.plain.sa_family,
(const void *) &(con->dst_addr.ipv6.sin6_addr),
b2, sizeof(b2)-1);
break;
case AF_INET:
s = inet_ntop(
con->dst_addr.plain.sa_family,
(const void *) &(con->dst_addr.ipv4.sin_addr),
b2, sizeof(b2)-1);
break;
#else
case AF_INET:
s = inet_ntoa(con->dst_addr.ipv4.sin_addr);
break;
#endif
default:
s = "";
break;
}
force_assert(s);
cgi_env_add(&env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
li_utostrn(buf, sizeof(buf),
#ifdef HAVE_IPV6
ntohs(con->dst_addr.plain.sa_family == AF_INET6 ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
#else
ntohs(con->dst_addr.ipv4.sin_port)
#endif
);
cgi_env_add(&env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
if (buffer_is_equal_caseless_string(con->uri.scheme, CONST_STR_LEN("https"))) {
cgi_env_add(&env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
}
li_itostrn(buf, sizeof(buf), con->request.content_length);
cgi_env_add(&env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
cgi_env_add(&env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
cgi_env_add(&env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
cgi_env_add(&env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.basedir));
http_cgi_headers(srv, con, &opts, cgi_env_add, &env);
/* for valgrind */
if (NULL != (s = getenv("LD_PRELOAD"))) {
@ -1279,37 +1137,6 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, handler_
}
#endif
for (n = 0; n < con->request.headers->used; n++) {
data_string *ds;
ds = (data_string *)con->request.headers->data[n];
if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
/* Do not emit HTTP_PROXY in environment.
* Some executables use HTTP_PROXY to configure
* outgoing proxy. See also https://httpoxy.org/ */
if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Proxy"))) {
continue;
}
buffer_copy_string_encoded_cgi_varnames(p->tmp_buf, CONST_BUF_LEN(ds->key), 1);
cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
}
}
for (n = 0; n < con->environment->used; n++) {
data_string *ds;
ds = (data_string *)con->environment->data[n];
if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
buffer_copy_string_encoded_cgi_varnames(p->tmp_buf, CONST_BUF_LEN(ds->key), 0);
cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
}
}
if (env.size == env.used) {
env.size += 16;
env.ptr = realloc(env.ptr, env.size * sizeof(*env.ptr));

@ -1724,7 +1724,8 @@ static handler_t fcgi_connection_reset(server *srv, connection *con, void *p_d)
}
static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
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;
char len_enc[8];
size_t len_enc_len = 0;
@ -1925,48 +1926,6 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h
return CONNECTION_OK;
}
#define FCGI_ENV_ADD_CHECK(ret, con) \
if (ret == -1) { \
con->http_status = 400; \
return -1; \
};
static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
size_t i;
for (i = 0; i < con->request.headers->used; i++) {
data_string *ds;
ds = (data_string *)con->request.headers->data[i];
if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
/* Do not emit HTTP_PROXY in environment.
* Some executables use HTTP_PROXY to configure
* outgoing proxy. See also https://httpoxy.org/ */
if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Proxy"))) {
continue;
}
buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf, CONST_BUF_LEN(ds->key), 1);
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value)),con);
}
}
for (i = 0; i < con->environment->used; i++) {
data_string *ds;
ds = (data_string *)con->environment->data[i];
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);
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value)), con);
}
}
return 0;
}
static void fcgi_stdin_append(server *srv, connection *con, handler_ctx *hctx, int request_id) {
FCGI_Header header;
chunkqueue *req_cq = con->request_content_queue;
@ -2005,21 +1964,17 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, int request_id) {
FCGI_BeginRequestRecord beginRecord;
FCGI_Header header;
char buf[LI_ITOSTRING_LENGTH];
const char *s;
#ifdef HAVE_IPV6
char b2[INET6_ADDRSTRLEN + 1];
#endif
plugin_data *p = hctx->plugin_data;
fcgi_extension_host *host= hctx->host;
connection *con = hctx->remote_conn;
buffer * const req_uri = con->request.orig_uri;
server_socket *srv_sock = con->srv_socket;
sock_addr our_addr;
socklen_t our_addr_len;
http_cgi_opts opts = {
(hctx->fcgi_mode == FCGI_AUTHORIZER),
host->break_scriptfilename_for_php,
host->docroot,
host->strip_request_uri
};
/* send FCGI_BEGIN_REQUEST */
@ -2032,194 +1987,10 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, int request_id) {
/* send FCGI_PARAMS */
buffer_string_prepare_copy(p->fcgi_env, 1023);
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_BUF_LEN(con->conf.server_tag)),con)
if (!buffer_is_empty(con->server_name)) {
size_t len = buffer_string_length(con->server_name);
if (con->server_name->ptr[0] == '[') {
const char *colon = strstr(con->server_name->ptr, "]:");
if (colon) len = (colon + 1) - con->server_name->ptr;
} else {
const char *colon = strchr(con->server_name->ptr, ':');
if (colon) len = colon - con->server_name->ptr;
}
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), con->server_name->ptr, len),con)
} else {
#ifdef HAVE_IPV6
s = inet_ntop(srv_sock->addr.plain.sa_family,
srv_sock->addr.plain.sa_family == AF_INET6 ?
(const void *) &(srv_sock->addr.ipv6.sin6_addr) :
(const void *) &(srv_sock->addr.ipv4.sin_addr),
b2, sizeof(b2)-1);
#else
s = inet_ntoa(srv_sock->addr.ipv4.sin_addr);
#endif
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s)),con)
}
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1")),con)
li_utostrn(buf, sizeof(buf),
#ifdef HAVE_IPV6
ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
#else
ntohs(srv_sock->addr.ipv4.sin_port)
#endif
);
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf)),con)
/* get the server-side of the connection to the client */
our_addr_len = sizeof(our_addr);
if (-1 == getsockname(con->fd, (struct sockaddr *)&our_addr, &our_addr_len)
|| our_addr_len > (socklen_t)sizeof(our_addr)) {
s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
} else {
s = inet_ntop_cache_get_ip(srv, &(our_addr));
}
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s)),con)
li_utostrn(buf, sizeof(buf),
#ifdef HAVE_IPV6
ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
#else
ntohs(con->dst_addr.ipv4.sin_port)
#endif
);
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf)),con)
s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s)),con)
if (con->request.content_length > 0 && hctx->fcgi_mode != FCGI_AUTHORIZER) {
/* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
li_itostrn(buf, sizeof(buf), con->request.content_length);
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf)),con)
}
if (hctx->fcgi_mode != FCGI_AUTHORIZER) {
/*
* SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to
* http://cgi-spec.golux.com/draft-coar-cgi-v11-03-clean.html
* (6.1.14, 6.1.6, 6.1.7)
* For AUTHORIZER mode these headers should be omitted.
*/
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path)),con)
if (!buffer_string_is_empty(con->request.pathinfo)) {
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo)),con)
/* PATH_TRANSLATED is only defined if PATH_INFO is set */
if (!buffer_string_is_empty(host->docroot)) {
buffer_copy_buffer(p->path, host->docroot);
} else {
buffer_copy_buffer(p->path, con->physical.basedir);
}
buffer_append_string_buffer(p->path, con->request.pathinfo);
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_TRANSLATED"), CONST_BUF_LEN(p->path)),con)
} else {
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_INFO"), CONST_STR_LEN("")),con)
}
}
/*
* SCRIPT_FILENAME and DOCUMENT_ROOT for php. The PHP manual
* http://www.php.net/manual/en/reserved.variables.php
* treatment of PATH_TRANSLATED is different from the one of CGI specs.
* TODO: this code should be checked against cgi.fix_pathinfo php
* parameter.
*/
if (!buffer_string_is_empty(host->docroot)) {
/*
* rewrite SCRIPT_FILENAME
*
*/
buffer_copy_buffer(p->path, host->docroot);
buffer_append_string_buffer(p->path, con->uri.path);
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path)),con)
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot)),con)
} else {
buffer_copy_buffer(p->path, con->physical.path);
/* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself
*
* see src/sapi/cgi_main.c, init_request_info()
*/
if (host->break_scriptfilename_for_php) {
buffer_append_string_buffer(p->path, con->request.pathinfo);
}
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path)),con)
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.basedir)),con)
}
if (!buffer_string_is_empty(host->strip_request_uri)) {
/* we need at least one char to strip off */
/**
* /app1/index/list
*
* stripping /app1 or /app1/ should lead to
*
* /index/list
*
*/
if ('/' != host->strip_request_uri->ptr[buffer_string_length(host->strip_request_uri) - 1]) {
/* fix the user-input to have / as last char */
buffer_append_string_len(host->strip_request_uri, CONST_STR_LEN("/"));
}
if (buffer_string_length(req_uri) >= buffer_string_length(host->strip_request_uri) &&
0 == strncmp(req_uri->ptr, host->strip_request_uri->ptr, buffer_string_length(host->strip_request_uri))) {
/* the left is the same */
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"),
req_uri->ptr + (buffer_string_length(host->strip_request_uri) - 1),
buffer_string_length(req_uri) - (buffer_string_length(host->strip_request_uri) - 1)), con)
} else {
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(req_uri)),con)
}
} else {
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(req_uri)),con)
}
if (!buffer_is_equal(con->request.uri, con->request.orig_uri)) {
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_URI"), CONST_BUF_LEN(con->request.uri)),con);
}
if (!buffer_string_is_empty(con->uri.query)) {
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query)),con)
if (0 != http_cgi_headers(srv, con, &opts, fcgi_env_add, p->fcgi_env)) {
con->http_status = 400;
return -1;
} else {
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN("")),con)
}
s = get_http_method_name(con->request.http_method);
force_assert(s);
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s)),con)
/* set REDIRECT_STATUS for php compiled with --force-redirect
* (if REDIRECT_STATUS has not already been set by error handler) */
if (0 == con->error_handler_saved_status) {
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")), con);
}
s = get_http_version_name(con->request.http_version);
force_assert(s);
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s)),con)
if (buffer_is_equal_caseless_string(con->uri.scheme, CONST_STR_LEN("https"))) {
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on")),con)
}
FCGI_ENV_ADD_CHECK(fcgi_env_add_request_headers(srv, con, p), con);
{
buffer *b = buffer_init();
buffer_copy_string_len(b, (const char *)&beginRecord, sizeof(beginRecord));
@ -3266,7 +3037,7 @@ static handler_t fcgi_send_request(server *srv, handler_ctx *hctx) {
} else {
int status = con->http_status;
fcgi_connection_close(srv, hctx);
con->http_status = (status == 400) ? 400 : 503; /* see FCGI_ENV_ADD_CHECK() for 400 error */
con->http_status = (status == 400) ? 400 : 503;
return HANDLER_FINISHED;
}

@ -1423,10 +1423,8 @@ static handler_t scgi_connection_reset(server *srv, connection *con, void *p_d)
}
typedef int (*scgi_env_add_t)(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len);
static int scgi_env_add_scgi(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
static int scgi_env_add_scgi(void *venv, const char *key, size_t key_len, const char *val, size_t val_len) {
buffer *env = venv;
size_t len;
if (!key || !val) return -1;
@ -1451,7 +1449,8 @@ static int scgi_env_add_scgi(buffer *env, const char *key, size_t key_len, const
#endif
static int scgi_env_add_uwsgi(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
static int scgi_env_add_uwsgi(void *venv, const char *key, size_t key_len, const char *val, size_t val_len) {
buffer *env = venv;
size_t len;
uint16_t uwlen;
@ -1581,222 +1580,30 @@ static int scgi_establish_connection(server *srv, handler_ctx *hctx) {
return 0;
}
static int scgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
size_t i;
scgi_env_add_t scgi_env_add = p->conf.proto == LI_PROTOCOL_SCGI
? scgi_env_add_scgi
: scgi_env_add_uwsgi;
for (i = 0; i < con->request.headers->used; i++) {
data_string *ds;
ds = (data_string *)con->request.headers->data[i];
if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
/* Do not emit HTTP_PROXY in environment.
* Some executables use HTTP_PROXY to configure
* outgoing proxy. See also https://httpoxy.org/ */
if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Proxy"))) {
continue;
}
buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf, CONST_BUF_LEN(ds->key), 1);
scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
}
}
for (i = 0; i < con->environment->used; i++) {
data_string *ds;
ds = (data_string *)con->environment->data[i];
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);
scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
}
}
return 0;
}
static int scgi_create_env(server *srv, handler_ctx *hctx) {
char buf[LI_ITOSTRING_LENGTH];
const char *s;
#ifdef HAVE_IPV6
char b2[INET6_ADDRSTRLEN + 1];
#endif
buffer *b;
plugin_data *p = hctx->plugin_data;
scgi_extension_host *host= hctx->host;
connection *con = hctx->remote_conn;
server_socket *srv_sock = con->srv_socket;
sock_addr our_addr;
socklen_t our_addr_len;
http_cgi_opts opts = { 0, 0, host->docroot, NULL };
scgi_env_add_t scgi_env_add = p->conf.proto == LI_PROTOCOL_SCGI
http_cgi_header_append_cb scgi_env_add = p->conf.proto == LI_PROTOCOL_SCGI
? scgi_env_add_scgi
: scgi_env_add_uwsgi;
buffer_string_prepare_copy(p->scgi_env, 1023);
/* CGI-SPEC 6.1.2, FastCGI spec 6.3 and SCGI spec */
li_itostrn(buf, sizeof(buf), con->request.content_length);
scgi_env_add(p->scgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
if (p->conf.proto == LI_PROTOCOL_SCGI)
scgi_env_add(p->scgi_env, CONST_STR_LEN("SCGI"), CONST_STR_LEN("1"));
scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_BUF_LEN(con->conf.server_tag));
if (!buffer_is_empty(con->server_name)) {
size_t len = buffer_string_length(con->server_name);
if (con->server_name->ptr[0] == '[') {
const char *colon = strstr(con->server_name->ptr, "]:");
if (colon) len = (colon + 1) - con->server_name->ptr;
} else {
const char *colon = strchr(con->server_name->ptr, ':');
if (colon) len = colon - con->server_name->ptr;
}
scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), con->server_name->ptr, len);
} else {
#ifdef HAVE_IPV6
s = inet_ntop(srv_sock->addr.plain.sa_family,
srv_sock->addr.plain.sa_family == AF_INET6 ?
(const void *) &(srv_sock->addr.ipv6.sin6_addr) :
(const void *) &(srv_sock->addr.ipv4.sin_addr),
b2, sizeof(b2)-1);
#else
s = inet_ntoa(srv_sock->addr.ipv4.sin_addr);
#endif
force_assert(s);
scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
}
scgi_env_add(p->scgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
li_utostrn(buf, sizeof(buf),
#ifdef HAVE_IPV6
ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
#else
ntohs(srv_sock->addr.ipv4.sin_port)
#endif
);
scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
/* get the server-side of the connection to the client */
our_addr_len = sizeof(our_addr);
if (-1 == getsockname(con->fd, (struct sockaddr *)&our_addr, &our_addr_len)
|| our_addr_len > (socklen_t)sizeof(our_addr)) {
s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
} else {
s = inet_ntop_cache_get_ip(srv, &(our_addr));
}
scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
li_utostrn(buf, sizeof(buf),
#ifdef HAVE_IPV6
ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
#else
ntohs(con->dst_addr.ipv4.sin_port)
#endif
);
scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
force_assert(s);
scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
/*
* SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to
* http://cgi-spec.golux.com/draft-coar-cgi-v11-03-clean.html
* (6.1.14, 6.1.6, 6.1.7)
*/
scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
if (!buffer_string_is_empty(con->request.pathinfo)) {
scgi_env_add(p->scgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
/* PATH_TRANSLATED is only defined if PATH_INFO is set */
if (!buffer_string_is_empty(host->docroot)) {
buffer_copy_buffer(p->path, host->docroot);
} else {
buffer_copy_buffer(p->path, con->physical.basedir);
}
buffer_append_string_buffer(p->path, con->request.pathinfo);
scgi_env_add(p->scgi_env, CONST_STR_LEN("PATH_TRANSLATED"), CONST_BUF_LEN(p->path));
} else {
scgi_env_add(p->scgi_env, CONST_STR_LEN("PATH_INFO"), CONST_STR_LEN(""));
}
/*
* SCRIPT_FILENAME and DOCUMENT_ROOT for php. The PHP manual
* http://www.php.net/manual/en/reserved.variables.php
* treatment of PATH_TRANSLATED is different from the one of CGI specs.
* TODO: this code should be checked against cgi.fix_pathinfo php
* parameter.
*/
if (!buffer_string_is_empty(host->docroot)) {
/*
* rewrite SCRIPT_FILENAME
*
*/
buffer_copy_buffer(p->path, host->docroot);
buffer_append_string_buffer(p->path, con->uri.path);
scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot));
} else {
buffer_copy_buffer(p->path, con->physical.path);
scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.basedir));
}
scgi_env_add(p->scgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
if (!buffer_is_equal(con->request.uri, con->request.orig_uri)) {
scgi_env_add(p->scgi_env, CONST_STR_LEN("REDIRECT_URI"), CONST_BUF_LEN(con->request.uri));
}
if (!buffer_string_is_empty(con->uri.query)) {
scgi_env_add(p->scgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
} else {
scgi_env_add(p->scgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
}
s = get_http_method_name(con->request.http_method);
force_assert(s);
scgi_env_add(p->scgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
/* set REDIRECT_STATUS for php compiled with --force-redirect
* (if REDIRECT_STATUS has not already been set by error handler) */
if (0 == con->error_handler_saved_status) {
scgi_env_add(p->scgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200"));
}
s = get_http_version_name(con->request.http_version);
force_assert(s);
scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
#ifdef USE_OPENSSL
if (buffer_is_equal_caseless_string(con->uri.scheme, CONST_STR_LEN("https"))) {
scgi_env_add(p->scgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
if (0 != http_cgi_headers(srv, con, &opts, scgi_env_add, p->scgi_env)) {
con->http_status = 400;
return -1;
}
#endif
scgi_env_add_request_headers(srv, con, p);
if (p->conf.proto == LI_PROTOCOL_SCGI) {
scgi_env_add(p->scgi_env, CONST_STR_LEN("SCGI"), CONST_STR_LEN("1"));
b = buffer_init();
buffer_append_int(b, buffer_string_length(p->scgi_env));
buffer_append_string_len(b, CONST_STR_LEN(":"));

@ -135,157 +135,44 @@ SETDEFAULTS_FUNC(mod_ssi_set_defaults) {
}
static int ssi_env_add(array *env, const char *key, const char *val) {
static int ssi_env_add(void *venv, const char *key, size_t klen, const char *val, size_t vlen) {
array *env = venv;
data_string *ds;
/* array_set_key_value() w/o extra lookup to see if key already exists */
if (NULL == (ds = (data_string *)array_get_unused_element(env, TYPE_STRING))) {
ds = data_string_init();
}
buffer_copy_string(ds->key, key);
buffer_copy_string(ds->value, val);
buffer_copy_string_len(ds->key, key, klen);
buffer_copy_string_len(ds->value, val, vlen);
array_insert_unique(env, (data_unset *)ds);
return 0;
}
/**
*
* the next two functions are take from fcgi.c
*
*/
static int ssi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
size_t i;
for (i = 0; i < con->request.headers->used; i++) {
data_string *ds;
ds = (data_string *)con->request.headers->data[i];
if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
/* don't forward the Authorization: Header */
if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Authorization"))) {
continue;
}
/* Do not emit HTTP_PROXY in environment.
* Some executables use HTTP_PROXY to configure
* outgoing proxy. See also https://httpoxy.org/ */
if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Proxy"))) {
continue;
}
buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf, CONST_BUF_LEN(ds->key), 1);
ssi_env_add(p->ssi_cgi_env, srv->tmp_buf->ptr, ds->value->ptr);
}
}
for (i = 0; i < con->environment->used; i++) {
data_string *ds;
ds = (data_string *)con->environment->data[i];
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);
ssi_env_add(p->ssi_cgi_env, srv->tmp_buf->ptr, ds->value->ptr);
}
}
return 0;
}
static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) {
char buf[LI_ITOSTRING_LENGTH];
server_socket *srv_sock = con->srv_socket;
#ifdef HAVE_IPV6
char b2[INET6_ADDRSTRLEN + 1];
#endif
#define CONST_STRING(x) \
x
array_reset(p->ssi_cgi_env);
ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_SOFTWARE"), con->conf.server_tag->ptr);
ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_NAME"),
#ifdef HAVE_IPV6
inet_ntop(srv_sock->addr.plain.sa_family,
srv_sock->addr.plain.sa_family == AF_INET6 ?
(const void *) &(srv_sock->addr.ipv6.sin6_addr) :
(const void *) &(srv_sock->addr.ipv4.sin_addr),
b2, sizeof(b2)-1)
#else
inet_ntoa(srv_sock->addr.ipv4.sin_addr)
#endif
);
ssi_env_add(p->ssi_cgi_env, CONST_STRING("GATEWAY_INTERFACE"), "CGI/1.1");
li_utostrn(buf, sizeof(buf),
#ifdef HAVE_IPV6
ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
#else
ntohs(srv_sock->addr.ipv4.sin_port)
#endif
);
ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PORT"), buf);
ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_ADDR"),
inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
if (con->request.content_length > 0) {
/* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
li_itostrn(buf, sizeof(buf), con->request.content_length);
ssi_env_add(p->ssi_cgi_env, CONST_STRING("CONTENT_LENGTH"), buf);
}
/*
* SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to
* http://cgi-spec.golux.com/draft-coar-cgi-v11-03-clean.html
* (6.1.14, 6.1.6, 6.1.7)
*/
ssi_env_add(p->ssi_cgi_env, CONST_STRING("SCRIPT_NAME"), con->uri.path->ptr);
ssi_env_add(p->ssi_cgi_env, CONST_STRING("PATH_INFO"), "");
/*
* SCRIPT_FILENAME and DOCUMENT_ROOT for php. The PHP manual
* http://www.php.net/manual/en/reserved.variables.php
* treatment of PATH_TRANSLATED is different from the one of CGI specs.
* TODO: this code should be checked against cgi.fix_pathinfo php
* parameter.
*/
if (!buffer_string_is_empty(con->request.pathinfo)) {
ssi_env_add(p->ssi_cgi_env, CONST_STRING("PATH_INFO"), con->request.pathinfo->ptr);
http_cgi_opts opts = { 0, 0, NULL, NULL };
/* temporarily remove Authorization from request headers
* so that Authorization does not end up in SSI environment */
data_string *ds_auth = (data_string *)array_get_element(con->request.headers, "Authorization");
buffer *b_auth = NULL;
if (ds_auth) {
b_auth = ds_auth->value;
ds_auth->value = NULL;
}
ssi_env_add(p->ssi_cgi_env, CONST_STRING("SCRIPT_FILENAME"), con->physical.path->ptr);
ssi_env_add(p->ssi_cgi_env, CONST_STRING("DOCUMENT_ROOT"), con->physical.basedir->ptr);
ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_URI"), con->request.uri->ptr);
array_reset(p->ssi_cgi_env);
if (!buffer_string_is_empty(con->uri.scheme)) {
ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_SCHEME"), con->uri.scheme->ptr);
if (0 != http_cgi_headers(srv, con, &opts, ssi_env_add, p->ssi_cgi_env)) {
con->http_status = 400;
return -1;
}
ssi_env_add(p->ssi_cgi_env, CONST_STRING("QUERY_STRING"), buffer_is_empty(con->uri.query) ? "" : con->uri.query->ptr);
ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_METHOD"), get_http_method_name(con->request.http_method));
ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PROTOCOL"), get_http_version_name(con->request.http_version));
/* set REDIRECT_STATUS for php compiled with --force-redirect
* (if REDIRECT_STATUS has not already been set by error handler) */
if (0 == con->error_handler_saved_status) {
ssi_env_add(p->ssi_cgi_env, CONST_STRING("REDIRECT_STATUS"), "200");
if (ds_auth) {
ds_auth->value = b_auth;
}
ssi_env_add_request_headers(srv, con, p);
return 0;
}

@ -13,6 +13,16 @@ int response_header_insert(server *srv, connection *con, const char *key, size_t
int response_header_overwrite(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen);
int response_header_append(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen);
typedef struct http_cgi_opts_t {
int authorizer;
int break_scriptfilename_for_php;
buffer *docroot;
buffer *strip_request_uri;
} http_cgi_opts;
typedef int (*http_cgi_header_append_cb)(void *vdata, const char *k, size_t klen, const char *v, size_t vlen);
int http_cgi_headers(server *srv, connection *con, http_cgi_opts *opts, http_cgi_header_append_cb cb, void *vdata);
handler_t http_response_prepare(server *srv, connection *con);
int http_response_redirect_to_directory(server *srv, connection *con);
int http_response_handle_cachable(server *srv, connection *con, buffer * mtime);

Loading…
Cancel
Save