version 1.1.1.2, 2014/06/15 20:20:06
|
version 1.1.1.3, 2016/11/02 10:35:00
|
Line 1
|
Line 1
|
|
#include "first.h" |
|
|
#include "buffer.h" |
#include "buffer.h" |
#include "server.h" |
#include "server.h" |
#include "keyvalue.h" |
#include "keyvalue.h" |
Line 37
|
Line 39
|
|
|
#include <stdio.h> |
#include <stdio.h> |
|
|
#ifdef HAVE_SYS_FILIO_H |
|
# include <sys/filio.h> |
|
#endif |
|
|
|
#include "sys-socket.h" |
#include "sys-socket.h" |
|
|
#ifdef HAVE_SYS_UIO_H |
#ifdef HAVE_SYS_UIO_H |
Line 50
|
Line 48
|
#include <sys/wait.h> |
#include <sys/wait.h> |
#endif |
#endif |
|
|
#include "version.h" |
|
|
|
#define FCGI_ENV_ADD_CHECK(ret, con) \ |
|
if (ret == -1) { \ |
|
con->http_status = 400; \ |
|
con->file_finished = 1; \ |
|
return -1; \ |
|
}; |
|
|
|
/* |
/* |
* |
* |
* TODO: |
* TODO: |
Line 157 typedef struct {
|
Line 146 typedef struct {
|
*/ |
*/ |
buffer *host; |
buffer *host; |
unsigned short port; |
unsigned short port; |
|
sa_family_t family; |
|
|
/* |
/* |
* Unix Domain Socket |
* Unix Domain Socket |
Line 235 typedef struct {
|
Line 225 typedef struct {
|
unsigned short fix_root_path_name; |
unsigned short fix_root_path_name; |
|
|
/* |
/* |
* If the backend includes X-LIGHTTPD-send-file in the response | * If the backend includes X-Sendfile in the response |
* we use the value as filename and ignore the content. |
* we use the value as filename and ignore the content. |
* |
* |
*/ |
*/ |
unsigned short allow_xsendfile; | unsigned short xsendfile_allow; |
| array *xsendfile_docroot; |
|
|
ssize_t load; /* replace by host->load */ |
ssize_t load; /* replace by host->load */ |
|
|
Line 255 typedef struct {
|
Line 246 typedef struct {
|
applications prefer SIGUSR1 while the |
applications prefer SIGUSR1 while the |
rest of the world would use SIGTERM |
rest of the world would use SIGTERM |
*sigh* */ |
*sigh* */ |
|
|
|
int listen_backlog; |
|
int refcount; |
} fcgi_extension_host; |
} fcgi_extension_host; |
|
|
/* |
/* |
Line 318 typedef struct {
|
Line 312 typedef struct {
|
buffer *fcgi_env; |
buffer *fcgi_env; |
|
|
buffer *path; |
buffer *path; |
buffer *parse_response; |
|
|
|
buffer *statuskey; |
buffer *statuskey; |
|
|
Line 329 typedef struct {
|
Line 322 typedef struct {
|
|
|
/* connection specific data */ |
/* connection specific data */ |
typedef enum { |
typedef enum { |
FCGI_STATE_UNSET, |
|
FCGI_STATE_INIT, |
FCGI_STATE_INIT, |
FCGI_STATE_CONNECT_DELAYED, |
FCGI_STATE_CONNECT_DELAYED, |
FCGI_STATE_PREPARE_WRITE, |
FCGI_STATE_PREPARE_WRITE, |
Line 345 typedef struct {
|
Line 337 typedef struct {
|
fcgi_connection_state_t state; |
fcgi_connection_state_t state; |
time_t state_timestamp; |
time_t state_timestamp; |
|
|
int reconnects; /* number of reconnect attempts */ |
|
|
|
chunkqueue *rb; /* read queue */ |
chunkqueue *rb; /* read queue */ |
chunkqueue *wb; /* write queue */ |
chunkqueue *wb; /* write queue */ |
|
off_t wb_reqlen; |
|
|
buffer *response_header; |
buffer *response_header; |
|
|
size_t request_id; |
|
int fd; /* fd to the fastcgi process */ |
int fd; /* fd to the fastcgi process */ |
int fde_ndx; /* index into the fd-event buffer */ |
int fde_ndx; /* index into the fd-event buffer */ |
|
|
pid_t pid; |
pid_t pid; |
int got_proc; |
int got_proc; |
|
int reconnects; /* number of reconnect attempts */ |
|
|
|
int request_id; |
int send_content_body; |
int send_content_body; |
|
|
plugin_config conf; |
plugin_config conf; |
Line 391 static void fastcgi_status_copy_procname(buffer *b, fc
|
Line 383 static void fastcgi_status_copy_procname(buffer *b, fc
|
buffer_append_string_buffer(b, host->id); |
buffer_append_string_buffer(b, host->id); |
if (proc) { |
if (proc) { |
buffer_append_string_len(b, CONST_STR_LEN(".")); |
buffer_append_string_len(b, CONST_STR_LEN(".")); |
buffer_append_long(b, proc->id); | buffer_append_int(b, proc->id); |
} |
} |
} |
} |
|
|
Line 504 static handler_ctx * handler_ctx_init(void) {
|
Line 496 static handler_ctx * handler_ctx_init(void) {
|
|
|
hctx->rb = chunkqueue_init(); |
hctx->rb = chunkqueue_init(); |
hctx->wb = chunkqueue_init(); |
hctx->wb = chunkqueue_init(); |
|
hctx->wb_reqlen = 0; |
|
|
return hctx; |
return hctx; |
} |
} |
Line 558 static fcgi_extension_host *fastcgi_host_init(void) {
|
Line 551 static fcgi_extension_host *fastcgi_host_init(void) {
|
f->bin_env = array_init(); |
f->bin_env = array_init(); |
f->bin_env_copy = array_init(); |
f->bin_env_copy = array_init(); |
f->strip_request_uri = buffer_init(); |
f->strip_request_uri = buffer_init(); |
|
f->xsendfile_docroot = array_init(); |
|
|
return f; |
return f; |
} |
} |
|
|
static void fastcgi_host_free(fcgi_extension_host *h) { |
static void fastcgi_host_free(fcgi_extension_host *h) { |
if (!h) return; |
if (!h) return; |
|
if (h->refcount) { |
|
--h->refcount; |
|
return; |
|
} |
|
|
buffer_free(h->id); |
buffer_free(h->id); |
buffer_free(h->host); |
buffer_free(h->host); |
Line 573 static void fastcgi_host_free(fcgi_extension_host *h)
|
Line 571 static void fastcgi_host_free(fcgi_extension_host *h)
|
buffer_free(h->strip_request_uri); |
buffer_free(h->strip_request_uri); |
array_free(h->bin_env); |
array_free(h->bin_env); |
array_free(h->bin_env_copy); |
array_free(h->bin_env_copy); |
|
array_free(h->xsendfile_docroot); |
|
|
fastcgi_process_free(h->first); |
fastcgi_process_free(h->first); |
fastcgi_process_free(h->unused_procs); |
fastcgi_process_free(h->unused_procs); |
Line 637 static int fastcgi_extension_insert(fcgi_exts *ext, bu
|
Line 636 static int fastcgi_extension_insert(fcgi_exts *ext, bu
|
force_assert(fe); |
force_assert(fe); |
fe->key = buffer_init(); |
fe->key = buffer_init(); |
fe->last_used_ndx = -1; |
fe->last_used_ndx = -1; |
buffer_copy_string_buffer(fe->key, key); | buffer_copy_buffer(fe->key, key); |
|
|
/* */ |
/* */ |
|
|
Line 679 INIT_FUNC(mod_fastcgi_init) {
|
Line 678 INIT_FUNC(mod_fastcgi_init) {
|
p->fcgi_env = buffer_init(); |
p->fcgi_env = buffer_init(); |
|
|
p->path = buffer_init(); |
p->path = buffer_init(); |
p->parse_response = buffer_init(); |
|
|
|
p->statuskey = buffer_init(); |
p->statuskey = buffer_init(); |
|
|
Line 694 FREE_FUNC(mod_fastcgi_free) {
|
Line 692 FREE_FUNC(mod_fastcgi_free) {
|
|
|
buffer_free(p->fcgi_env); |
buffer_free(p->fcgi_env); |
buffer_free(p->path); |
buffer_free(p->path); |
buffer_free(p->parse_response); |
|
buffer_free(p->statuskey); |
buffer_free(p->statuskey); |
|
|
if (p->config_storage) { |
if (p->config_storage) { |
Line 703 FREE_FUNC(mod_fastcgi_free) {
|
Line 700 FREE_FUNC(mod_fastcgi_free) {
|
plugin_config *s = p->config_storage[i]; |
plugin_config *s = p->config_storage[i]; |
fcgi_exts *exts; |
fcgi_exts *exts; |
|
|
if (!s) continue; | if (NULL == s) continue; |
|
|
exts = s->exts; |
exts = s->exts; |
|
|
Line 724 FREE_FUNC(mod_fastcgi_free) {
|
Line 721 FREE_FUNC(mod_fastcgi_free) {
|
} |
} |
|
|
if (proc->is_local && |
if (proc->is_local && |
!buffer_is_empty(proc->unixsocket)) { | !buffer_string_is_empty(proc->unixsocket)) { |
unlink(proc->unixsocket->ptr); |
unlink(proc->unixsocket->ptr); |
} |
} |
} |
} |
Line 734 FREE_FUNC(mod_fastcgi_free) {
|
Line 731 FREE_FUNC(mod_fastcgi_free) {
|
kill(proc->pid, host->kill_signal); |
kill(proc->pid, host->kill_signal); |
} |
} |
if (proc->is_local && |
if (proc->is_local && |
!buffer_is_empty(proc->unixsocket)) { | !buffer_string_is_empty(proc->unixsocket)) { |
unlink(proc->unixsocket->ptr); |
unlink(proc->unixsocket->ptr); |
} |
} |
} |
} |
Line 794 static int parse_binpath(char_array *env, buffer *b) {
|
Line 791 static int parse_binpath(char_array *env, buffer *b) {
|
/* search for spaces */ |
/* search for spaces */ |
|
|
start = b->ptr; |
start = b->ptr; |
for (i = 0; i < b->used - 1; i++) { | for (i = 0; i < buffer_string_length(b); i++) { |
switch(b->ptr[i]) { |
switch(b->ptr[i]) { |
case ' ': |
case ' ': |
case '\t': |
case '\t': |
Line 844 static int parse_binpath(char_array *env, buffer *b) {
|
Line 841 static int parse_binpath(char_array *env, buffer *b) {
|
return 0; |
return 0; |
} |
} |
|
|
|
#if !defined(HAVE_FORK) |
static int fcgi_spawn_connection(server *srv, |
static int fcgi_spawn_connection(server *srv, |
plugin_data *p, | plugin_data *p, |
fcgi_extension_host *host, | fcgi_extension_host *host, |
fcgi_proc *proc) { | fcgi_proc *proc) { |
| UNUSED(srv); |
| UNUSED(p); |
| UNUSED(host); |
| UNUSED(proc); |
| return -1; |
| } |
| |
| #else /* -> defined(HAVE_FORK) */ |
| |
| static int fcgi_spawn_connection(server *srv, |
| plugin_data *p, |
| fcgi_extension_host *host, |
| fcgi_proc *proc) { |
int fcgi_fd; |
int fcgi_fd; |
int socket_type, status; | int status; |
struct timeval tv = { 0, 100 * 1000 }; |
struct timeval tv = { 0, 100 * 1000 }; |
#ifdef HAVE_SYS_UN_H |
#ifdef HAVE_SYS_UN_H |
struct sockaddr_un fcgi_addr_un; |
struct sockaddr_un fcgi_addr_un; |
#endif |
#endif |
|
#if defined(HAVE_IPV6) && defined(HAVE_INET_PTON) |
|
struct sockaddr_in6 fcgi_addr_in6; |
|
#endif |
struct sockaddr_in fcgi_addr_in; |
struct sockaddr_in fcgi_addr_in; |
struct sockaddr *fcgi_addr; |
struct sockaddr *fcgi_addr; |
|
|
socklen_t servlen; |
socklen_t servlen; |
|
|
#ifndef HAVE_FORK |
|
return -1; |
|
#endif |
|
|
|
if (p->conf.debug) { |
if (p->conf.debug) { |
log_error_write(srv, __FILE__, __LINE__, "sdb", |
log_error_write(srv, __FILE__, __LINE__, "sdb", |
"new proc, socket:", proc->port, proc->unixsocket); |
"new proc, socket:", proc->port, proc->unixsocket); |
} |
} |
|
|
if (!buffer_is_empty(proc->unixsocket)) { | if (!buffer_string_is_empty(proc->unixsocket)) { |
memset(&fcgi_addr, 0, sizeof(fcgi_addr)); | |
| |
#ifdef HAVE_SYS_UN_H |
#ifdef HAVE_SYS_UN_H |
|
memset(&fcgi_addr_un, 0, sizeof(fcgi_addr_un)); |
fcgi_addr_un.sun_family = AF_UNIX; |
fcgi_addr_un.sun_family = AF_UNIX; |
if (proc->unixsocket->used > sizeof(fcgi_addr_un.sun_path)) { | if (buffer_string_length(proc->unixsocket) + 1 > sizeof(fcgi_addr_un.sun_path)) { |
log_error_write(srv, __FILE__, __LINE__, "sB", |
log_error_write(srv, __FILE__, __LINE__, "sB", |
"ERROR: Unix Domain socket filename too long:", |
"ERROR: Unix Domain socket filename too long:", |
proc->unixsocket); |
proc->unixsocket); |
return -1; |
return -1; |
} |
} |
memcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr, proc->unixsocket->used); | memcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr, buffer_string_length(proc->unixsocket) + 1); |
|
|
#ifdef SUN_LEN |
#ifdef SUN_LEN |
servlen = SUN_LEN(&fcgi_addr_un); |
servlen = SUN_LEN(&fcgi_addr_un); |
#else |
#else |
/* stevens says: */ |
/* stevens says: */ |
servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family); | servlen = buffer_string_length(proc->unixsocket) + 1 + sizeof(fcgi_addr_un.sun_family); |
#endif |
#endif |
socket_type = AF_UNIX; |
|
fcgi_addr = (struct sockaddr *) &fcgi_addr_un; |
fcgi_addr = (struct sockaddr *) &fcgi_addr_un; |
|
|
buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("unix:")); |
buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("unix:")); |
Line 898 static int fcgi_spawn_connection(server *srv,
|
Line 906 static int fcgi_spawn_connection(server *srv,
|
"ERROR: Unix Domain sockets are not supported."); |
"ERROR: Unix Domain sockets are not supported."); |
return -1; |
return -1; |
#endif |
#endif |
|
#if defined(HAVE_IPV6) && defined(HAVE_INET_PTON) |
|
} else if (host->family == AF_INET6 && !buffer_string_is_empty(host->host)) { |
|
memset(&fcgi_addr_in6, 0, sizeof(fcgi_addr_in6)); |
|
fcgi_addr_in6.sin6_family = AF_INET6; |
|
inet_pton(AF_INET6, host->host->ptr, (char *) &fcgi_addr_in6.sin6_addr); |
|
fcgi_addr_in6.sin6_port = htons(proc->port); |
|
servlen = sizeof(fcgi_addr_in6); |
|
fcgi_addr = (struct sockaddr *) &fcgi_addr_in6; |
|
#endif |
} else { |
} else { |
|
memset(&fcgi_addr_in, 0, sizeof(fcgi_addr_in)); |
fcgi_addr_in.sin_family = AF_INET; |
fcgi_addr_in.sin_family = AF_INET; |
|
|
if (buffer_is_empty(host->host)) { | if (buffer_string_is_empty(host->host)) { |
fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); |
fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); |
} else { |
} else { |
struct hostent *he; |
struct hostent *he; |
Line 933 static int fcgi_spawn_connection(server *srv,
|
Line 951 static int fcgi_spawn_connection(server *srv,
|
fcgi_addr_in.sin_port = htons(proc->port); |
fcgi_addr_in.sin_port = htons(proc->port); |
servlen = sizeof(fcgi_addr_in); |
servlen = sizeof(fcgi_addr_in); |
|
|
socket_type = AF_INET; |
|
fcgi_addr = (struct sockaddr *) &fcgi_addr_in; |
fcgi_addr = (struct sockaddr *) &fcgi_addr_in; |
|
} |
|
|
|
if (buffer_string_is_empty(proc->unixsocket)) { |
buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("tcp:")); |
buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("tcp:")); |
if (!buffer_is_empty(host->host)) { | if (!buffer_string_is_empty(host->host)) { |
buffer_append_string_buffer(proc->connection_name, host->host); |
buffer_append_string_buffer(proc->connection_name, host->host); |
} else { |
} else { |
buffer_append_string_len(proc->connection_name, CONST_STR_LEN("localhost")); |
buffer_append_string_len(proc->connection_name, CONST_STR_LEN("localhost")); |
} |
} |
buffer_append_string_len(proc->connection_name, CONST_STR_LEN(":")); |
buffer_append_string_len(proc->connection_name, CONST_STR_LEN(":")); |
buffer_append_long(proc->connection_name, proc->port); | buffer_append_int(proc->connection_name, proc->port); |
} |
} |
|
|
if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) { | if (-1 == (fcgi_fd = socket(fcgi_addr->sa_family, SOCK_STREAM, 0))) { |
log_error_write(srv, __FILE__, __LINE__, "ss", |
log_error_write(srv, __FILE__, __LINE__, "ss", |
"failed:", strerror(errno)); |
"failed:", strerror(errno)); |
return -1; |
return -1; |
Line 958 static int fcgi_spawn_connection(server *srv,
|
Line 977 static int fcgi_spawn_connection(server *srv,
|
int val; |
int val; |
|
|
if (errno != ENOENT && |
if (errno != ENOENT && |
!buffer_is_empty(proc->unixsocket)) { | !buffer_string_is_empty(proc->unixsocket)) { |
unlink(proc->unixsocket->ptr); |
unlink(proc->unixsocket->ptr); |
} |
} |
|
|
close(fcgi_fd); |
close(fcgi_fd); |
|
|
/* reopen socket */ |
/* reopen socket */ |
if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) { | if (-1 == (fcgi_fd = socket(fcgi_addr->sa_family, SOCK_STREAM, 0))) { |
log_error_write(srv, __FILE__, __LINE__, "ss", |
log_error_write(srv, __FILE__, __LINE__, "ss", |
"socket failed:", strerror(errno)); |
"socket failed:", strerror(errno)); |
return -1; |
return -1; |
Line 989 static int fcgi_spawn_connection(server *srv,
|
Line 1008 static int fcgi_spawn_connection(server *srv,
|
return -1; |
return -1; |
} |
} |
|
|
if (-1 == listen(fcgi_fd, 1024)) { | if (-1 == listen(fcgi_fd, host->listen_backlog)) { |
log_error_write(srv, __FILE__, __LINE__, "ss", |
log_error_write(srv, __FILE__, __LINE__, "ss", |
"listen failed:", strerror(errno)); |
"listen failed:", strerror(errno)); |
close(fcgi_fd); |
close(fcgi_fd); |
return -1; |
return -1; |
} |
} |
|
|
#ifdef HAVE_FORK |
|
switch ((child = fork())) { |
switch ((child = fork())) { |
case 0: { |
case 0: { |
size_t i = 0; |
size_t i = 0; |
Line 1035 static int fcgi_spawn_connection(server *srv,
|
Line 1053 static int fcgi_spawn_connection(server *srv,
|
} |
} |
} |
} |
} else { |
} else { |
for (i = 0; environ[i]; i++) { | char ** const e = environ; |
| for (i = 0; e[i]; ++i) { |
char *eq; |
char *eq; |
|
|
if (NULL != (eq = strchr(environ[i], '='))) { | if (NULL != (eq = strchr(e[i], '='))) { |
env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1)); | env_add(&env, e[i], eq - e[i], eq+1, strlen(eq+1)); |
} |
} |
} |
} |
} |
} |
Line 1086 static int fcgi_spawn_connection(server *srv,
|
Line 1105 static int fcgi_spawn_connection(server *srv,
|
/* log_error_write(srv, __FILE__, __LINE__, "sbs", |
/* log_error_write(srv, __FILE__, __LINE__, "sbs", |
"execve failed for:", host->bin_path, strerror(errno)); */ |
"execve failed for:", host->bin_path, strerror(errno)); */ |
|
|
exit(errno); | _exit(errno); |
|
|
break; |
break; |
} |
} |
case -1: |
case -1: |
/* error */ |
/* error */ |
|
close(fcgi_fd); |
break; |
break; |
default: |
default: |
/* father */ |
/* father */ |
|
close(fcgi_fd); |
|
|
/* wait */ |
/* wait */ |
select(0, NULL, NULL, NULL, &tv); |
select(0, NULL, NULL, NULL, &tv); |
Line 1144 static int fcgi_spawn_connection(server *srv,
|
Line 1165 static int fcgi_spawn_connection(server *srv,
|
|
|
break; |
break; |
} |
} |
#endif |
|
} else { |
} else { |
|
close(fcgi_fd); |
proc->is_local = 0; |
proc->is_local = 0; |
proc->pid = 0; |
proc->pid = 0; |
|
|
Line 1159 static int fcgi_spawn_connection(server *srv,
|
Line 1180 static int fcgi_spawn_connection(server *srv,
|
proc->state = PROC_STATE_RUNNING; |
proc->state = PROC_STATE_RUNNING; |
host->active_procs++; |
host->active_procs++; |
|
|
close(fcgi_fd); |
|
|
|
return 0; |
return 0; |
} |
} |
|
|
|
#endif /* HAVE_FORK */ |
|
|
|
static fcgi_extension_host * unixsocket_is_dup(plugin_data *p, size_t used, buffer *unixsocket) { |
|
size_t i, j, n; |
|
for (i = 0; i < used; ++i) { |
|
fcgi_exts *exts = p->config_storage[i]->exts; |
|
for (j = 0; j < exts->used; ++j) { |
|
fcgi_extension *ex = exts->exts[j]; |
|
for (n = 0; n < ex->used; ++n) { |
|
fcgi_extension_host *host = ex->hosts[n]; |
|
if (!buffer_string_is_empty(host->unixsocket) |
|
&& buffer_is_equal(host->unixsocket, unixsocket) |
|
&& !buffer_string_is_empty(host->bin_path)) |
|
return host; |
|
} |
|
} |
|
} |
|
|
|
return NULL; |
|
} |
|
|
SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { |
SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { |
plugin_data *p = p_d; |
plugin_data *p = p_d; |
data_unset *du; |
data_unset *du; |
Line 1182 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
Line 1221 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *)); |
p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *)); |
|
|
for (i = 0; i < srv->config_context->used; i++) { |
for (i = 0; i < srv->config_context->used; i++) { |
|
data_config const* config = (data_config const*)srv->config_context->data[i]; |
plugin_config *s; |
plugin_config *s; |
array *ca; |
|
|
|
s = malloc(sizeof(plugin_config)); |
s = malloc(sizeof(plugin_config)); |
s->exts = fastcgi_extensions_init(); |
s->exts = fastcgi_extensions_init(); |
Line 1195 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
Line 1234 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
cv[2].destination = s->ext_mapping; |
cv[2].destination = s->ext_mapping; |
|
|
p->config_storage[i] = s; |
p->config_storage[i] = s; |
ca = ((data_config *)srv->config_context->data[i])->value; |
|
|
|
if (0 != config_insert_values_global(srv, ca, cv)) { | if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) { |
goto error; |
goto error; |
} |
} |
|
|
Line 1205 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
Line 1243 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
* <key> = ( ... ) |
* <key> = ( ... ) |
*/ |
*/ |
|
|
if (NULL != (du = array_get_element(ca, "fastcgi.server"))) { | if (NULL != (du = array_get_element(config->value, "fastcgi.server"))) { |
size_t j; |
size_t j; |
data_array *da = (data_array *)du; |
data_array *da = (data_array *)du; |
|
|
if (du->type != TYPE_ARRAY) { |
if (du->type != TYPE_ARRAY) { |
log_error_write(srv, __FILE__, __LINE__, "sss", |
log_error_write(srv, __FILE__, __LINE__, "sss", |
"unexpected type for key: ", "fastcgi.server", "array of strings"); | "unexpected type for key: ", "fastcgi.server", "expected ( \"ext\" => ( \"backend-label\" => ( \"key\" => \"value\" )))"); |
|
|
goto error; |
goto error; |
} |
} |
Line 1229 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
Line 1267 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
if (da->value->data[j]->type != TYPE_ARRAY) { |
if (da->value->data[j]->type != TYPE_ARRAY) { |
log_error_write(srv, __FILE__, __LINE__, "sssbs", |
log_error_write(srv, __FILE__, __LINE__, "sssbs", |
"unexpected type for key: ", "fastcgi.server", |
"unexpected type for key: ", "fastcgi.server", |
"[", da->value->data[j]->key, "](string)"); | "[", da->value->data[j]->key, "](string); expected ( \"ext\" => ( \"backend-label\" => ( \"key\" => \"value\" )))"); |
|
|
goto error; |
goto error; |
} |
} |
Line 1269 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
Line 1307 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
{ "strip-request-uri", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 13 */ |
{ "strip-request-uri", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 13 */ |
{ "kill-signal", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 14 */ |
{ "kill-signal", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 14 */ |
{ "fix-root-scriptname", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 15 */ |
{ "fix-root-scriptname", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 15 */ |
|
{ "listen-backlog", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION }, /* 16 */ |
|
{ "x-sendfile", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 17 */ |
|
{ "x-sendfile-docroot",NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 18 */ |
|
|
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } |
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } |
}; |
}; |
Line 1277 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
Line 1318 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
log_error_write(srv, __FILE__, __LINE__, "ssSBS", |
log_error_write(srv, __FILE__, __LINE__, "ssSBS", |
"unexpected type for key:", |
"unexpected type for key:", |
"fastcgi.server", |
"fastcgi.server", |
"[", da_host->key, "](string)"); | "[", da_host->key, "](string); expected ( \"ext\" => ( \"backend-label\" => ( \"key\" => \"value\" )))"); |
|
|
goto error; |
goto error; |
} |
} |
Line 1285 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
Line 1326 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
host = fastcgi_host_init(); |
host = fastcgi_host_init(); |
buffer_reset(fcgi_mode); |
buffer_reset(fcgi_mode); |
|
|
buffer_copy_string_buffer(host->id, da_host->key); | buffer_copy_buffer(host->id, da_host->key); |
|
|
host->check_local = 1; |
host->check_local = 1; |
host->max_procs = 4; |
host->max_procs = 4; |
host->mode = FCGI_RESPONDER; |
host->mode = FCGI_RESPONDER; |
host->disable_time = 1; |
host->disable_time = 1; |
host->break_scriptfilename_for_php = 0; |
host->break_scriptfilename_for_php = 0; |
host->allow_xsendfile = 0; /* handle X-LIGHTTPD-send-file */ | host->xsendfile_allow = 0; |
host->kill_signal = SIGTERM; |
host->kill_signal = SIGTERM; |
host->fix_root_path_name = 0; |
host->fix_root_path_name = 0; |
|
host->listen_backlog = 1024; |
|
host->refcount = 0; |
|
|
fcv[0].destination = host->host; |
fcv[0].destination = host->host; |
fcv[1].destination = host->docroot; |
fcv[1].destination = host->docroot; |
Line 1310 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
Line 1353 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
fcv[9].destination = host->bin_env; |
fcv[9].destination = host->bin_env; |
fcv[10].destination = host->bin_env_copy; |
fcv[10].destination = host->bin_env_copy; |
fcv[11].destination = &(host->break_scriptfilename_for_php); |
fcv[11].destination = &(host->break_scriptfilename_for_php); |
fcv[12].destination = &(host->allow_xsendfile); | fcv[12].destination = &(host->xsendfile_allow); |
fcv[13].destination = host->strip_request_uri; |
fcv[13].destination = host->strip_request_uri; |
fcv[14].destination = &(host->kill_signal); |
fcv[14].destination = &(host->kill_signal); |
fcv[15].destination = &(host->fix_root_path_name); |
fcv[15].destination = &(host->fix_root_path_name); |
|
fcv[16].destination = &(host->listen_backlog); |
|
fcv[17].destination = &(host->xsendfile_allow); |
|
fcv[18].destination = host->xsendfile_docroot; |
|
|
if (0 != config_insert_values_internal(srv, da_host->value, fcv)) { | if (0 != config_insert_values_internal(srv, da_host->value, fcv, T_CONFIG_SCOPE_CONNECTION)) { |
goto error; |
goto error; |
} |
} |
|
|
if ((!buffer_is_empty(host->host) || host->port) && | if ((!buffer_string_is_empty(host->host) || host->port) && |
!buffer_is_empty(host->unixsocket)) { | !buffer_string_is_empty(host->unixsocket)) { |
log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", |
log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", |
"either host/port or socket have to be set in:", |
"either host/port or socket have to be set in:", |
da->key, "= (", |
da->key, "= (", |
Line 1330 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
Line 1376 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
goto error; |
goto error; |
} |
} |
|
|
if (!buffer_is_empty(host->unixsocket)) { | if (!buffer_string_is_empty(host->unixsocket)) { |
/* unix domain socket */ |
/* unix domain socket */ |
struct sockaddr_un un; |
struct sockaddr_un un; |
|
|
if (host->unixsocket->used > sizeof(un.sun_path) - 2) { | 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__, "sbsbsbs", |
"unixsocket is too long in:", |
"unixsocket is too long in:", |
da->key, "= (", |
da->key, "= (", |
Line 1343 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
Line 1389 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
|
|
goto error; |
goto error; |
} |
} |
|
|
|
if (!buffer_string_is_empty(host->bin_path)) { |
|
fcgi_extension_host *duplicate = unixsocket_is_dup(p, i+1, host->unixsocket); |
|
if (NULL != duplicate) { |
|
if (!buffer_is_equal(host->bin_path, duplicate->bin_path)) { |
|
log_error_write(srv, __FILE__, __LINE__, "sb", |
|
"duplicate unixsocket path:", |
|
host->unixsocket); |
|
goto error; |
|
} |
|
fastcgi_host_free(host); |
|
host = duplicate; |
|
++host->refcount; |
|
} |
|
} |
|
|
|
host->family = AF_UNIX; |
} else { |
} else { |
/* tcp/ip */ |
/* tcp/ip */ |
|
|
if (buffer_is_empty(host->host) && | if (buffer_string_is_empty(host->host) && |
buffer_is_empty(host->bin_path)) { | buffer_string_is_empty(host->bin_path)) { |
log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", |
log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", |
"host or binpath have to be set in:", |
"host or binpath have to be set in:", |
da->key, "= (", |
da->key, "= (", |
Line 1364 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
Line 1427 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
|
|
goto error; |
goto error; |
} |
} |
|
|
|
host->family = (!buffer_string_is_empty(host->host) && NULL != strchr(host->host->ptr, ':')) ? AF_INET6 : AF_INET; |
} |
} |
|
|
if (!buffer_is_empty(host->bin_path)) { | if (host->refcount) { |
| /* already init'd; skip spawning */ |
| } else if (!buffer_string_is_empty(host->bin_path)) { |
/* a local socket + self spawning */ |
/* a local socket + self spawning */ |
size_t pno; |
size_t pno; |
|
|
Line 1386 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
Line 1453 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
proc->id = host->num_procs++; |
proc->id = host->num_procs++; |
host->max_id++; |
host->max_id++; |
|
|
if (buffer_is_empty(host->unixsocket)) { | if (buffer_string_is_empty(host->unixsocket)) { |
proc->port = host->port + pno; |
proc->port = host->port + pno; |
} else { |
} else { |
buffer_copy_string_buffer(proc->unixsocket, host->unixsocket); | buffer_copy_buffer(proc->unixsocket, host->unixsocket); |
buffer_append_string_len(proc->unixsocket, CONST_STR_LEN("-")); |
buffer_append_string_len(proc->unixsocket, CONST_STR_LEN("-")); |
buffer_append_long(proc->unixsocket, pno); | buffer_append_int(proc->unixsocket, pno); |
} |
} |
|
|
if (s->debug) { |
if (s->debug) { |
Line 1402 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
Line 1469 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
"\n\tcurrent:", pno, "/", host->max_procs); |
"\n\tcurrent:", pno, "/", host->max_procs); |
} |
} |
|
|
if (fcgi_spawn_connection(srv, p, host, proc)) { | if (!srv->srvconf.preflight_check |
| && fcgi_spawn_connection(srv, p, host, proc)) { |
log_error_write(srv, __FILE__, __LINE__, "s", |
log_error_write(srv, __FILE__, __LINE__, "s", |
"[ERROR]: spawning fcgi failed."); |
"[ERROR]: spawning fcgi failed."); |
fastcgi_process_free(proc); |
fastcgi_process_free(proc); |
Line 1425 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
Line 1493 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
host->active_procs++; |
host->active_procs++; |
proc->state = PROC_STATE_RUNNING; |
proc->state = PROC_STATE_RUNNING; |
|
|
if (buffer_is_empty(host->unixsocket)) { | if (buffer_string_is_empty(host->unixsocket)) { |
proc->port = host->port; |
proc->port = host->port; |
} else { |
} else { |
buffer_copy_string_buffer(proc->unixsocket, host->unixsocket); | buffer_copy_buffer(proc->unixsocket, host->unixsocket); |
} |
} |
|
|
fastcgi_status_init(srv, p->statuskey, host, proc); |
fastcgi_status_init(srv, p->statuskey, host, proc); |
Line 1438 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
Line 1506 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
host->max_procs = 1; |
host->max_procs = 1; |
} |
} |
|
|
if (!buffer_is_empty(fcgi_mode)) { | if (!buffer_string_is_empty(fcgi_mode)) { |
if (strcmp(fcgi_mode->ptr, "responder") == 0) { |
if (strcmp(fcgi_mode->ptr, "responder") == 0) { |
host->mode = FCGI_RESPONDER; |
host->mode = FCGI_RESPONDER; |
} else if (strcmp(fcgi_mode->ptr, "authorizer") == 0) { |
} else if (strcmp(fcgi_mode->ptr, "authorizer") == 0) { |
host->mode = FCGI_AUTHORIZER; |
host->mode = FCGI_AUTHORIZER; |
if (buffer_is_empty(host->docroot)) { | if (buffer_string_is_empty(host->docroot)) { |
log_error_write(srv, __FILE__, __LINE__, "s", |
log_error_write(srv, __FILE__, __LINE__, "s", |
"ERROR: docroot is required for authorizer mode."); |
"ERROR: docroot is required for authorizer mode."); |
goto error; |
goto error; |
Line 1455 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
Line 1523 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
|
} |
} |
} |
} |
|
|
|
if (host->xsendfile_docroot->used) { |
|
size_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); |
|
} |
|
} |
|
|
/* if extension already exists, take it */ |
/* if extension already exists, take it */ |
fastcgi_extension_insert(s->exts, da_ext->key, host); |
fastcgi_extension_insert(s->exts, da_ext->key, host); |
host = NULL; |
host = NULL; |
Line 1484 static void fcgi_connection_close(server *srv, handler
|
Line 1571 static void fcgi_connection_close(server *srv, handler
|
plugin_data *p; |
plugin_data *p; |
connection *con; |
connection *con; |
|
|
if (NULL == hctx) return; |
|
|
|
p = hctx->plugin_data; |
p = hctx->plugin_data; |
con = hctx->remote_conn; |
con = hctx->remote_conn; |
|
|
Line 1514 static void fcgi_connection_close(server *srv, handler
|
Line 1599 static void fcgi_connection_close(server *srv, handler
|
|
|
handler_ctx_free(srv, hctx); |
handler_ctx_free(srv, hctx); |
con->plugin_ctx[p->id] = NULL; |
con->plugin_ctx[p->id] = NULL; |
|
|
|
/* finish response (if not already con->file_started, con->file_finished) */ |
|
if (con->mode == p->id) { |
|
http_response_backend_done(srv, con); |
|
} |
} |
} |
|
|
static int fcgi_reconnect(server *srv, handler_ctx *hctx) { |
static int fcgi_reconnect(server *srv, handler_ctx *hctx) { |
Line 1576 static int fcgi_reconnect(server *srv, handler_ctx *hc
|
Line 1666 static int fcgi_reconnect(server *srv, handler_ctx *hc
|
|
|
static handler_t fcgi_connection_reset(server *srv, connection *con, void *p_d) { |
static handler_t fcgi_connection_reset(server *srv, connection *con, void *p_d) { |
plugin_data *p = p_d; |
plugin_data *p = p_d; |
|
handler_ctx *hctx = con->plugin_ctx[p->id]; |
|
if (hctx) fcgi_connection_close(srv, hctx); |
|
|
fcgi_connection_close(srv, con->plugin_ctx[p->id]); |
|
|
|
return HANDLER_GO_ON; |
return HANDLER_GO_ON; |
} |
} |
|
|
|
|
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(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) { |
size_t len; |
size_t len; |
|
char len_enc[8]; |
|
size_t len_enc_len = 0; |
|
|
if (!key || !val) return -1; |
if (!key || !val) return -1; |
|
|
Line 1593 static int fcgi_env_add(buffer *env, const char *key,
|
Line 1685 static int fcgi_env_add(buffer *env, const char *key,
|
len += key_len > 127 ? 4 : 1; |
len += key_len > 127 ? 4 : 1; |
len += val_len > 127 ? 4 : 1; |
len += val_len > 127 ? 4 : 1; |
|
|
if (env->used + len >= FCGI_MAX_LENGTH) { | if (buffer_string_length(env) + len >= FCGI_MAX_LENGTH) { |
/** |
/** |
* we can't append more headers, ignore it |
* we can't append more headers, ignore it |
*/ |
*/ |
Line 1605 static int fcgi_env_add(buffer *env, const char *key,
|
Line 1697 static int fcgi_env_add(buffer *env, const char *key,
|
* |
* |
* HINT: this can't happen as FCGI_MAX_LENGTH is only 16bit |
* HINT: this can't happen as FCGI_MAX_LENGTH is only 16bit |
*/ |
*/ |
if (key_len > 0x7fffffff) key_len = 0x7fffffff; | force_assert(key_len < 0x7fffffffu); |
if (val_len > 0x7fffffff) val_len = 0x7fffffff; | force_assert(val_len < 0x7fffffffu); |
|
|
buffer_prepare_append(env, len); | buffer_string_prepare_append(env, len); |
|
|
if (key_len > 127) { |
if (key_len > 127) { |
env->ptr[env->used++] = ((key_len >> 24) & 0xff) | 0x80; | len_enc[len_enc_len++] = ((key_len >> 24) & 0xff) | 0x80; |
env->ptr[env->used++] = (key_len >> 16) & 0xff; | len_enc[len_enc_len++] = (key_len >> 16) & 0xff; |
env->ptr[env->used++] = (key_len >> 8) & 0xff; | len_enc[len_enc_len++] = (key_len >> 8) & 0xff; |
env->ptr[env->used++] = (key_len >> 0) & 0xff; | len_enc[len_enc_len++] = (key_len >> 0) & 0xff; |
} else { |
} else { |
env->ptr[env->used++] = (key_len >> 0) & 0xff; | len_enc[len_enc_len++] = (key_len >> 0) & 0xff; |
} |
} |
|
|
if (val_len > 127) { |
if (val_len > 127) { |
env->ptr[env->used++] = ((val_len >> 24) & 0xff) | 0x80; | len_enc[len_enc_len++] = ((val_len >> 24) & 0xff) | 0x80; |
env->ptr[env->used++] = (val_len >> 16) & 0xff; | len_enc[len_enc_len++] = (val_len >> 16) & 0xff; |
env->ptr[env->used++] = (val_len >> 8) & 0xff; | len_enc[len_enc_len++] = (val_len >> 8) & 0xff; |
env->ptr[env->used++] = (val_len >> 0) & 0xff; | len_enc[len_enc_len++] = (val_len >> 0) & 0xff; |
} else { |
} else { |
env->ptr[env->used++] = (val_len >> 0) & 0xff; | len_enc[len_enc_len++] = (val_len >> 0) & 0xff; |
} |
} |
|
|
memcpy(env->ptr + env->used, key, key_len); | buffer_append_string_len(env, len_enc, len_enc_len); |
env->used += key_len; | buffer_append_string_len(env, key, key_len); |
memcpy(env->ptr + env->used, val, val_len); | buffer_append_string_len(env, val, val_len); |
env->used += val_len; | |
|
|
return 0; |
return 0; |
} |
} |
|
|
static int fcgi_header(FCGI_Header * header, unsigned char type, size_t request_id, int contentLength, unsigned char paddingLength) { | static int fcgi_header(FCGI_Header * header, unsigned char type, int request_id, int contentLength, unsigned char paddingLength) { |
force_assert(contentLength <= FCGI_MAX_LENGTH); |
force_assert(contentLength <= FCGI_MAX_LENGTH); |
|
|
header->version = FCGI_VERSION_1; |
header->version = FCGI_VERSION_1; |
Line 1661 typedef enum {
|
Line 1752 typedef enum {
|
static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *hctx) { |
static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *hctx) { |
struct sockaddr *fcgi_addr; |
struct sockaddr *fcgi_addr; |
struct sockaddr_in fcgi_addr_in; |
struct sockaddr_in fcgi_addr_in; |
|
#if defined(HAVE_IPV6) && defined(HAVE_INET_PTON) |
|
struct sockaddr_in6 fcgi_addr_in6; |
|
#endif |
#ifdef HAVE_SYS_UN_H |
#ifdef HAVE_SYS_UN_H |
struct sockaddr_un fcgi_addr_un; |
struct sockaddr_un fcgi_addr_un; |
#endif |
#endif |
Line 1670 static connection_result_t fcgi_establish_connection(s
|
Line 1764 static connection_result_t fcgi_establish_connection(s
|
fcgi_proc *proc = hctx->proc; |
fcgi_proc *proc = hctx->proc; |
int fcgi_fd = hctx->fd; |
int fcgi_fd = hctx->fd; |
|
|
memset(&fcgi_addr, 0, sizeof(fcgi_addr)); | if (!buffer_string_is_empty(proc->unixsocket)) { |
| |
if (!buffer_is_empty(proc->unixsocket)) { | |
#ifdef HAVE_SYS_UN_H |
#ifdef HAVE_SYS_UN_H |
/* use the unix domain socket */ |
/* use the unix domain socket */ |
|
memset(&fcgi_addr_un, 0, sizeof(fcgi_addr_un)); |
fcgi_addr_un.sun_family = AF_UNIX; |
fcgi_addr_un.sun_family = AF_UNIX; |
if (proc->unixsocket->used > sizeof(fcgi_addr_un.sun_path)) { | if (buffer_string_length(proc->unixsocket) + 1 > sizeof(fcgi_addr_un.sun_path)) { |
log_error_write(srv, __FILE__, __LINE__, "sB", |
log_error_write(srv, __FILE__, __LINE__, "sB", |
"ERROR: Unix Domain socket filename too long:", |
"ERROR: Unix Domain socket filename too long:", |
proc->unixsocket); |
proc->unixsocket); |
return -1; |
return -1; |
} |
} |
memcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr, proc->unixsocket->used); | memcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr, buffer_string_length(proc->unixsocket) + 1); |
|
|
#ifdef SUN_LEN |
#ifdef SUN_LEN |
servlen = SUN_LEN(&fcgi_addr_un); |
servlen = SUN_LEN(&fcgi_addr_un); |
#else |
#else |
/* stevens says: */ |
/* stevens says: */ |
servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family); | servlen = buffer_string_length(proc->unixsocket) + 1 + sizeof(fcgi_addr_un.sun_family); |
#endif |
#endif |
fcgi_addr = (struct sockaddr *) &fcgi_addr_un; |
fcgi_addr = (struct sockaddr *) &fcgi_addr_un; |
|
|
if (buffer_is_empty(proc->connection_name)) { | if (buffer_string_is_empty(proc->connection_name)) { |
/* on remote spawing we have to set the connection-name now */ |
/* on remote spawing we have to set the connection-name now */ |
buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("unix:")); |
buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("unix:")); |
buffer_append_string_buffer(proc->connection_name, proc->unixsocket); |
buffer_append_string_buffer(proc->connection_name, proc->unixsocket); |
Line 1700 static connection_result_t fcgi_establish_connection(s
|
Line 1793 static connection_result_t fcgi_establish_connection(s
|
#else |
#else |
return CONNECTION_DEAD; |
return CONNECTION_DEAD; |
#endif |
#endif |
|
#if defined(HAVE_IPV6) && defined(HAVE_INET_PTON) |
|
} else if (host->family == AF_INET6 && !buffer_string_is_empty(host->host)) { |
|
memset(&fcgi_addr_in6, 0, sizeof(fcgi_addr_in6)); |
|
fcgi_addr_in6.sin6_family = AF_INET6; |
|
inet_pton(AF_INET6, host->host->ptr, (char *) &fcgi_addr_in6.sin6_addr); |
|
fcgi_addr_in6.sin6_port = htons(proc->port); |
|
servlen = sizeof(fcgi_addr_in6); |
|
fcgi_addr = (struct sockaddr *) &fcgi_addr_in6; |
|
#endif |
} else { |
} else { |
|
memset(&fcgi_addr_in, 0, sizeof(fcgi_addr_in)); |
fcgi_addr_in.sin_family = AF_INET; |
fcgi_addr_in.sin_family = AF_INET; |
if (!buffer_is_empty(host->host)) { | if (!buffer_string_is_empty(host->host)) { |
if (0 == inet_aton(host->host->ptr, &(fcgi_addr_in.sin_addr))) { |
if (0 == inet_aton(host->host->ptr, &(fcgi_addr_in.sin_addr))) { |
log_error_write(srv, __FILE__, __LINE__, "sbs", |
log_error_write(srv, __FILE__, __LINE__, "sbs", |
"converting IP address failed for", host->host, |
"converting IP address failed for", host->host, |
Line 1717 static connection_result_t fcgi_establish_connection(s
|
Line 1820 static connection_result_t fcgi_establish_connection(s
|
servlen = sizeof(fcgi_addr_in); |
servlen = sizeof(fcgi_addr_in); |
|
|
fcgi_addr = (struct sockaddr *) &fcgi_addr_in; |
fcgi_addr = (struct sockaddr *) &fcgi_addr_in; |
|
} |
|
|
if (buffer_is_empty(proc->connection_name)) { | if (buffer_string_is_empty(proc->unixsocket)) { |
| if (buffer_string_is_empty(proc->connection_name)) { |
/* on remote spawing we have to set the connection-name now */ |
/* on remote spawing we have to set the connection-name now */ |
buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("tcp:")); |
buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("tcp:")); |
if (!buffer_is_empty(host->host)) { | if (!buffer_string_is_empty(host->host)) { |
buffer_append_string_buffer(proc->connection_name, host->host); |
buffer_append_string_buffer(proc->connection_name, host->host); |
} else { |
} else { |
buffer_append_string_len(proc->connection_name, CONST_STR_LEN("localhost")); |
buffer_append_string_len(proc->connection_name, CONST_STR_LEN("localhost")); |
} |
} |
buffer_append_string_len(proc->connection_name, CONST_STR_LEN(":")); |
buffer_append_string_len(proc->connection_name, CONST_STR_LEN(":")); |
buffer_append_long(proc->connection_name, proc->port); | buffer_append_int(proc->connection_name, proc->port); |
} |
} |
} |
} |
|
|
Line 1769 static connection_result_t fcgi_establish_connection(s
|
Line 1874 static connection_result_t fcgi_establish_connection(s
|
return CONNECTION_OK; |
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) { |
static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) { |
size_t i; |
size_t i; |
|
|
Line 1777 static int fcgi_env_add_request_headers(server *srv, c
|
Line 1887 static int fcgi_env_add_request_headers(server *srv, c
|
|
|
ds = (data_string *)con->request.headers->data[i]; |
ds = (data_string *)con->request.headers->data[i]; |
|
|
if (ds->value->used && ds->key->used) { | if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) { |
size_t j; | /* Do not emit HTTP_PROXY in environment. |
buffer_reset(srv->tmp_buf); | * Some executables use HTTP_PROXY to configure |
| * outgoing proxy. See also https://httpoxy.org/ */ |
if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) { | if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Proxy"))) { |
buffer_copy_string_len(srv->tmp_buf, CONST_STR_LEN("HTTP_")); | continue; |
srv->tmp_buf->used--; | |
} |
} |
|
|
buffer_prepare_append(srv->tmp_buf, ds->key->used + 2); | buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf, CONST_BUF_LEN(ds->key), 1); |
for (j = 0; j < ds->key->used - 1; j++) { | |
char c = '_'; | |
if (light_isalpha(ds->key->ptr[j])) { | |
/* upper-case */ | |
c = ds->key->ptr[j] & ~32; | |
} else if (light_isdigit(ds->key->ptr[j])) { | |
/* copy */ | |
c = ds->key->ptr[j]; | |
} | |
srv->tmp_buf->ptr[srv->tmp_buf->used++] = c; | |
} | |
srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0'; | |
|
|
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value)),con); |
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value)),con); |
} |
} |
Line 1809 static int fcgi_env_add_request_headers(server *srv, c
|
Line 1906 static int fcgi_env_add_request_headers(server *srv, c
|
|
|
ds = (data_string *)con->environment->data[i]; |
ds = (data_string *)con->environment->data[i]; |
|
|
if (ds->value->used && ds->key->used) { | if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) { |
size_t j; | buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf, CONST_BUF_LEN(ds->key), 0); |
buffer_reset(srv->tmp_buf); | |
|
|
buffer_prepare_append(srv->tmp_buf, ds->key->used + 2); |
|
for (j = 0; j < ds->key->used - 1; j++) { |
|
char c = '_'; |
|
if (light_isalpha(ds->key->ptr[j])) { |
|
/* upper-case */ |
|
c = ds->key->ptr[j] & ~32; |
|
} else if (light_isdigit(ds->key->ptr[j])) { |
|
/* copy */ |
|
c = ds->key->ptr[j]; |
|
} |
|
srv->tmp_buf->ptr[srv->tmp_buf->used++] = c; |
|
} |
|
srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0'; |
|
|
|
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value)), con); |
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value)), con); |
} |
} |
} |
} |
Line 1834 static int fcgi_env_add_request_headers(server *srv, c
|
Line 1916 static int fcgi_env_add_request_headers(server *srv, c
|
return 0; |
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; |
|
plugin_data *p = hctx->plugin_data; |
|
off_t offset, weWant; |
|
const off_t req_cqlen = req_cq->bytes_in - req_cq->bytes_out; |
|
|
static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) { | /* something to send ? */ |
| for (offset = 0; offset != req_cqlen; offset += weWant) { |
| weWant = req_cqlen - offset > FCGI_MAX_LENGTH ? FCGI_MAX_LENGTH : req_cqlen - offset; |
| |
| /* we announce toWrite octets |
| * now take all request_content chunks available |
| * */ |
| |
| fcgi_header(&(header), FCGI_STDIN, request_id, weWant, 0); |
| chunkqueue_append_mem(hctx->wb, (const char *)&header, sizeof(header)); |
| hctx->wb_reqlen += sizeof(header); |
| |
| if (p->conf.debug > 10) { |
| log_error_write(srv, __FILE__, __LINE__, "soso", "tosend:", offset, "/", req_cqlen); |
| } |
| |
| chunkqueue_steal(hctx->wb, req_cq, weWant); |
| /*(hctx->wb_reqlen already includes content_length)*/ |
| } |
| |
| if (hctx->wb->bytes_in == hctx->wb_reqlen) { |
| /* terminate STDIN */ |
| fcgi_header(&(header), FCGI_STDIN, request_id, 0, 0); |
| chunkqueue_append_mem(hctx->wb, (const char *)&header, sizeof(header)); |
| hctx->wb_reqlen += (int)sizeof(header); |
| } |
| } |
| |
| static int fcgi_create_env(server *srv, handler_ctx *hctx, int request_id) { |
FCGI_BeginRequestRecord beginRecord; |
FCGI_BeginRequestRecord beginRecord; |
FCGI_Header header; |
FCGI_Header header; |
buffer *b; |
|
|
|
char buf[32]; | char buf[LI_ITOSTRING_LENGTH]; |
const char *s; |
const char *s; |
#ifdef HAVE_IPV6 |
#ifdef HAVE_IPV6 |
char b2[INET6_ADDRSTRLEN + 1]; |
char b2[INET6_ADDRSTRLEN + 1]; |
Line 1850 static int fcgi_create_env(server *srv, handler_ctx *h
|
Line 1965 static int fcgi_create_env(server *srv, handler_ctx *h
|
fcgi_extension_host *host= hctx->host; |
fcgi_extension_host *host= hctx->host; |
|
|
connection *con = hctx->remote_conn; |
connection *con = hctx->remote_conn; |
|
buffer * const req_uri = con->request.orig_uri; |
server_socket *srv_sock = con->srv_socket; |
server_socket *srv_sock = con->srv_socket; |
|
|
sock_addr our_addr; |
sock_addr our_addr; |
Line 1863 static int fcgi_create_env(server *srv, handler_ctx *h
|
Line 1979 static int fcgi_create_env(server *srv, handler_ctx *h
|
beginRecord.body.flags = 0; |
beginRecord.body.flags = 0; |
memset(beginRecord.body.reserved, 0, sizeof(beginRecord.body.reserved)); |
memset(beginRecord.body.reserved, 0, sizeof(beginRecord.body.reserved)); |
|
|
b = chunkqueue_get_append_buffer(hctx->wb); |
|
|
|
buffer_copy_memory(b, (const char *)&beginRecord, sizeof(beginRecord)); |
|
|
|
/* send FCGI_PARAMS */ |
/* send FCGI_PARAMS */ |
buffer_prepare_copy(p->fcgi_env, 1024); | 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->conf.server_tag)) { | if (!buffer_is_empty(con->server_name)) { |
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_DESC)),con) | size_t len = buffer_string_length(con->server_name); |
} else { | |
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_BUF_LEN(con->conf.server_tag)),con) | |
} | |
|
|
if (con->server_name->used) { |
|
size_t len = con->server_name->used - 1; |
|
|
|
if (con->server_name->ptr[0] == '[') { |
if (con->server_name->ptr[0] == '[') { |
const char *colon = strstr(con->server_name->ptr, "]:"); |
const char *colon = strstr(con->server_name->ptr, "]:"); |
if (colon) len = (colon + 1) - con->server_name->ptr; |
if (colon) len = (colon + 1) - con->server_name->ptr; |
Line 1904 static int fcgi_create_env(server *srv, handler_ctx *h
|
Line 2011 static int fcgi_create_env(server *srv, handler_ctx *h
|
|
|
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1")),con) |
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1")),con) |
|
|
LI_ltostr(buf, | li_utostrn(buf, sizeof(buf), |
#ifdef HAVE_IPV6 |
#ifdef HAVE_IPV6 |
ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port) |
ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port) |
#else |
#else |
Line 1917 static int fcgi_create_env(server *srv, handler_ctx *h
|
Line 2024 static int fcgi_create_env(server *srv, handler_ctx *h
|
/* get the server-side of the connection to the client */ |
/* get the server-side of the connection to the client */ |
our_addr_len = sizeof(our_addr); |
our_addr_len = sizeof(our_addr); |
|
|
if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) { | 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)); |
s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr)); |
} else { |
} else { |
s = inet_ntop_cache_get_ip(srv, &(our_addr)); |
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) |
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s)),con) |
|
|
LI_ltostr(buf, | li_utostrn(buf, sizeof(buf), |
#ifdef HAVE_IPV6 |
#ifdef HAVE_IPV6 |
ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port) |
ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port) |
#else |
#else |
Line 1940 static int fcgi_create_env(server *srv, handler_ctx *h
|
Line 2048 static int fcgi_create_env(server *srv, handler_ctx *h
|
if (con->request.content_length > 0 && host->mode != FCGI_AUTHORIZER) { |
if (con->request.content_length > 0 && host->mode != FCGI_AUTHORIZER) { |
/* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */ |
/* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */ |
|
|
/* request.content_length < SSIZE_MAX, see request.c */ | li_itostrn(buf, sizeof(buf), con->request.content_length); |
LI_ltostr(buf, con->request.content_length); | |
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf)),con) |
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf)),con) |
} |
} |
|
|
Line 1955 static int fcgi_create_env(server *srv, handler_ctx *h
|
Line 2062 static int fcgi_create_env(server *srv, handler_ctx *h
|
|
|
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path)),con) |
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path)),con) |
|
|
if (!buffer_is_empty(con->request.pathinfo)) { | 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) |
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 */ |
/* PATH_TRANSLATED is only defined if PATH_INFO is set */ |
|
|
if (!buffer_is_empty(host->docroot)) { | if (!buffer_string_is_empty(host->docroot)) { |
buffer_copy_string_buffer(p->path, host->docroot); | buffer_copy_buffer(p->path, host->docroot); |
} else { |
} else { |
buffer_copy_string_buffer(p->path, con->physical.basedir); | buffer_copy_buffer(p->path, con->physical.basedir); |
} |
} |
buffer_append_string_buffer(p->path, con->request.pathinfo); |
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) |
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_TRANSLATED"), CONST_BUF_LEN(p->path)),con) |
Line 1980 static int fcgi_create_env(server *srv, handler_ctx *h
|
Line 2087 static int fcgi_create_env(server *srv, handler_ctx *h
|
* parameter. |
* parameter. |
*/ |
*/ |
|
|
if (!buffer_is_empty(host->docroot)) { | if (!buffer_string_is_empty(host->docroot)) { |
/* |
/* |
* rewrite SCRIPT_FILENAME |
* rewrite SCRIPT_FILENAME |
* |
* |
*/ |
*/ |
|
|
buffer_copy_string_buffer(p->path, host->docroot); | buffer_copy_buffer(p->path, host->docroot); |
buffer_append_string_buffer(p->path, con->uri.path); |
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("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) |
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot)),con) |
} else { |
} else { |
buffer_copy_string_buffer(p->path, con->physical.path); | buffer_copy_buffer(p->path, con->physical.path); |
|
|
/* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself |
/* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself |
* |
* |
Line 2006 static int fcgi_create_env(server *srv, handler_ctx *h
|
Line 2113 static int fcgi_create_env(server *srv, handler_ctx *h
|
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.basedir)),con) |
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.basedir)),con) |
} |
} |
|
|
if (host->strip_request_uri->used > 1) { | if (!buffer_string_is_empty(host->strip_request_uri)) { |
/* we need at least one char to strip off */ |
/* we need at least one char to strip off */ |
/** |
/** |
* /app1/index/list |
* /app1/index/list |
Line 2016 static int fcgi_create_env(server *srv, handler_ctx *h
|
Line 2123 static int fcgi_create_env(server *srv, handler_ctx *h
|
* /index/list |
* /index/list |
* |
* |
*/ |
*/ |
if ('/' != host->strip_request_uri->ptr[host->strip_request_uri->used - 2]) { | |
| if ('/' != host->strip_request_uri->ptr[buffer_string_length(host->strip_request_uri) - 1]) { |
/* fix the user-input to have / as last char */ |
/* fix the user-input to have / as last char */ |
buffer_append_string_len(host->strip_request_uri, CONST_STR_LEN("/")); |
buffer_append_string_len(host->strip_request_uri, CONST_STR_LEN("/")); |
} |
} |
|
|
if (con->request.orig_uri->used >= host->strip_request_uri->used && | if (buffer_string_length(req_uri) >= buffer_string_length(host->strip_request_uri) && |
0 == strncmp(con->request.orig_uri->ptr, host->strip_request_uri->ptr, host->strip_request_uri->used - 1)) { | 0 == strncmp(req_uri->ptr, host->strip_request_uri->ptr, buffer_string_length(host->strip_request_uri))) { |
/* the left is the same */ |
/* the left is the same */ |
|
|
fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), | FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), |
con->request.orig_uri->ptr + (host->strip_request_uri->used - 2), | req_uri->ptr + (buffer_string_length(host->strip_request_uri) - 1), |
con->request.orig_uri->used - (host->strip_request_uri->used - 2) - 1); | buffer_string_length(req_uri) - (buffer_string_length(host->strip_request_uri) - 1)), con) |
} else { |
} else { |
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri)),con) | FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(req_uri)),con) |
} |
} |
} else { |
} else { |
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri)),con) | 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)) { |
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) | FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_URI"), CONST_BUF_LEN(con->request.uri)),con); |
} |
} |
if (!buffer_is_empty(con->uri.query)) { | 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) |
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query)),con) |
} else { |
} else { |
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN("")),con) |
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); |
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) |
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s)),con) |
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")),con) /* if php is compiled with --force-redirect */ | /* 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); |
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) |
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"))) { |
if (buffer_is_equal_caseless_string(con->uri.scheme, CONST_STR_LEN("https"))) { |
Line 2055 static int fcgi_create_env(server *srv, handler_ctx *h
|
Line 2169 static int fcgi_create_env(server *srv, handler_ctx *h
|
|
|
FCGI_ENV_ADD_CHECK(fcgi_env_add_request_headers(srv, con, p), con); |
FCGI_ENV_ADD_CHECK(fcgi_env_add_request_headers(srv, con, p), con); |
|
|
fcgi_header(&(header), FCGI_PARAMS, request_id, p->fcgi_env->used, 0); | { |
buffer_append_memory(b, (const char *)&header, sizeof(header)); | buffer *b = buffer_init(); |
buffer_append_memory(b, (const char *)p->fcgi_env->ptr, p->fcgi_env->used); | |
|
|
fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0); | buffer_copy_string_len(b, (const char *)&beginRecord, sizeof(beginRecord)); |
buffer_append_memory(b, (const char *)&header, sizeof(header)); | |
|
|
b->used++; /* add virtual \0 */ | fcgi_header(&(header), FCGI_PARAMS, request_id, buffer_string_length(p->fcgi_env), 0); |
hctx->wb->bytes_in += b->used - 1; | buffer_append_string_len(b, (const char *)&header, sizeof(header)); |
| buffer_append_string_buffer(b, p->fcgi_env); |
|
|
if (con->request.content_length) { | fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0); |
chunkqueue *req_cq = con->request_content_queue; | buffer_append_string_len(b, (const char *)&header, sizeof(header)); |
chunk *req_c; | |
off_t offset; | |
|
|
/* something to send ? */ | hctx->wb_reqlen = buffer_string_length(b); |
for (offset = 0, req_c = req_cq->first; offset != req_cq->bytes_in; ) { | chunkqueue_append_buffer(hctx->wb, b); |
off_t weWant = req_cq->bytes_in - offset > FCGI_MAX_LENGTH ? FCGI_MAX_LENGTH : req_cq->bytes_in - offset; | buffer_free(b); |
off_t written = 0; | |
off_t weHave = 0; | |
| |
/* we announce toWrite octets | |
* now take all the request_content chunks that we need to fill this request | |
* */ | |
| |
b = chunkqueue_get_append_buffer(hctx->wb); | |
fcgi_header(&(header), FCGI_STDIN, request_id, weWant, 0); | |
buffer_copy_memory(b, (const char *)&header, sizeof(header)); | |
hctx->wb->bytes_in += sizeof(header); | |
| |
if (p->conf.debug > 10) { | |
log_error_write(srv, __FILE__, __LINE__, "soso", "tosend:", offset, "/", req_cq->bytes_in); | |
} | |
| |
for (written = 0; written != weWant; ) { | |
if (p->conf.debug > 10) { | |
log_error_write(srv, __FILE__, __LINE__, "soso", "chunk:", written, "/", weWant); | |
} | |
| |
switch (req_c->type) { | |
case FILE_CHUNK: | |
weHave = req_c->file.length - req_c->offset; | |
| |
if (weHave > weWant - written) weHave = weWant - written; | |
| |
if (p->conf.debug > 10) { | |
log_error_write(srv, __FILE__, __LINE__, "soSosOsb", | |
"sending", weHave, "bytes from (", | |
req_c->offset, "/", req_c->file.length, ")", | |
req_c->file.name); | |
} | |
| |
force_assert(weHave != 0); | |
| |
chunkqueue_append_file(hctx->wb, req_c->file.name, req_c->offset, weHave); | |
| |
req_c->offset += weHave; | |
req_cq->bytes_out += weHave; | |
written += weHave; | |
| |
hctx->wb->bytes_in += weHave; | |
| |
/* steal the tempfile | |
* | |
* This is tricky: | |
* - we reference the tempfile from the request-content-queue several times | |
* if the req_c is larger than FCGI_MAX_LENGTH | |
* - we can't simply cleanup the request-content-queue as soon as possible | |
* as it would remove the tempfiles | |
* - the idea is to 'steal' the tempfiles and attach the is_temp flag to the last | |
* referencing chunk of the fastcgi-write-queue | |
* | |
* */ | |
| |
if (req_c->offset == req_c->file.length) { | |
chunk *c; | |
| |
if (p->conf.debug > 10) { | |
log_error_write(srv, __FILE__, __LINE__, "s", "next chunk"); | |
} | |
c = hctx->wb->last; | |
| |
force_assert(c->type == FILE_CHUNK); | |
force_assert(req_c->file.is_temp == 1); | |
| |
c->file.is_temp = 1; | |
req_c->file.is_temp = 0; | |
| |
chunkqueue_remove_finished_chunks(req_cq); | |
| |
req_c = req_cq->first; | |
} | |
| |
break; | |
case MEM_CHUNK: | |
/* append to the buffer */ | |
weHave = req_c->mem->used - 1 - req_c->offset; | |
| |
if (weHave > weWant - written) weHave = weWant - written; | |
| |
buffer_append_memory(b, req_c->mem->ptr + req_c->offset, weHave); | |
| |
req_c->offset += weHave; | |
req_cq->bytes_out += weHave; | |
written += weHave; | |
| |
hctx->wb->bytes_in += weHave; | |
| |
if (req_c->offset == (off_t) req_c->mem->used - 1) { | |
chunkqueue_remove_finished_chunks(req_cq); | |
| |
req_c = req_cq->first; | |
} | |
| |
break; | |
default: | |
break; | |
} | |
} | |
| |
b->used++; /* add virtual \0 */ | |
offset += weWant; | |
} | |
} |
} |
|
|
b = chunkqueue_get_append_buffer(hctx->wb); | hctx->wb_reqlen += con->request.content_length;/* (eventual) (minimal) total request size, not necessarily including all fcgi_headers around content length yet */ |
/* terminate STDIN */ | fcgi_stdin_append(srv, con, hctx, request_id); |
fcgi_header(&(header), FCGI_STDIN, request_id, 0, 0); | |
buffer_copy_memory(b, (const char *)&header, sizeof(header)); | |
b->used++; /* add virtual \0 */ | |
|
|
hctx->wb->bytes_in += sizeof(header); |
|
|
|
return 0; |
return 0; |
} |
} |
|
|
Line 2201 static int fcgi_response_parse(server *srv, connection
|
Line 2202 static int fcgi_response_parse(server *srv, connection
|
|
|
UNUSED(srv); |
UNUSED(srv); |
|
|
buffer_copy_string_buffer(p->parse_response, in); |
|
|
|
/* search for \n */ |
/* search for \n */ |
for (s = p->parse_response->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1) { | for (s = in->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1) { |
char *key, *value; |
char *key, *value; |
int key_len; |
int key_len; |
data_string *ds = NULL; |
|
|
|
/* a good day. Someone has read the specs and is sending a \r\n to us */ |
/* a good day. Someone has read the specs and is sending a \r\n to us */ |
|
|
if (ns > p->parse_response->ptr && | if (ns > in->ptr && |
*(ns-1) == '\r') { |
*(ns-1) == '\r') { |
*(ns-1) = '\0'; |
*(ns-1) = '\0'; |
} |
} |
Line 2237 static int fcgi_response_parse(server *srv, connection
|
Line 2235 static int fcgi_response_parse(server *srv, connection
|
|
|
/* don't forward Status: */ |
/* don't forward Status: */ |
if (0 != strncasecmp(key, "Status", key_len)) { |
if (0 != strncasecmp(key, "Status", key_len)) { |
|
data_string *ds; |
if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) { |
if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) { |
ds = data_response_init(); |
ds = data_response_init(); |
} |
} |
Line 2255 static int fcgi_response_parse(server *srv, connection
|
Line 2254 static int fcgi_response_parse(server *srv, connection
|
break; |
break; |
case 6: |
case 6: |
if (0 == strncasecmp(key, "Status", key_len)) { |
if (0 == strncasecmp(key, "Status", key_len)) { |
con->http_status = strtol(value, NULL, 10); | int status = strtol(value, NULL, 10); |
con->parsed_response |= HTTP_STATUS; | if (status >= 100 && status < 1000) { |
| con->http_status = status; |
| con->parsed_response |= HTTP_STATUS; |
| } else { |
| con->http_status = 502; |
| } |
} |
} |
break; |
break; |
case 8: |
case 8: |
Line 2271 static int fcgi_response_parse(server *srv, connection
|
Line 2275 static int fcgi_response_parse(server *srv, connection
|
} |
} |
break; |
break; |
case 11: |
case 11: |
if (host->allow_xsendfile && 0 == strncasecmp(key, "X-Sendfile2", key_len)&& hctx->send_content_body) { | if (host->xsendfile_allow && 0 == strncasecmp(key, "X-Sendfile2", key_len) && hctx->send_content_body) { |
char *pos = value; |
char *pos = value; |
have_sendfile2 = 1; |
have_sendfile2 = 1; |
|
|
Line 2289 static int fcgi_response_parse(server *srv, connection
|
Line 2293 static int fcgi_response_parse(server *srv, connection
|
if (p->conf.debug) { |
if (p->conf.debug) { |
log_error_write(srv, __FILE__, __LINE__, "ss", "Couldn't find range after filename:", filename); |
log_error_write(srv, __FILE__, __LINE__, "ss", "Couldn't find range after filename:", filename); |
} |
} |
return 1; | return 502; |
} |
} |
buffer_copy_string_len(srv->tmp_buf, filename, range - filename); |
buffer_copy_string_len(srv->tmp_buf, filename, range - filename); |
|
|
Line 2297 static int fcgi_response_parse(server *srv, connection
|
Line 2301 static int fcgi_response_parse(server *srv, connection
|
for (pos = ++range; *pos && *pos != ' ' && *pos != ','; pos++) ; |
for (pos = ++range; *pos && *pos != ' ' && *pos != ','; pos++) ; |
|
|
buffer_urldecode_path(srv->tmp_buf); |
buffer_urldecode_path(srv->tmp_buf); |
|
buffer_path_simplify(srv->tmp_buf, srv->tmp_buf); |
|
if (con->conf.force_lowercase_filenames) { |
|
buffer_to_lower(srv->tmp_buf); |
|
} |
|
if (host->xsendfile_docroot->used) { |
|
size_t i, xlen = buffer_string_length(srv->tmp_buf); |
|
for (i = 0; i < host->xsendfile_docroot->used; ++i) { |
|
data_string *ds = (data_string *)host->xsendfile_docroot->data[i]; |
|
size_t dlen = buffer_string_length(ds->value); |
|
if (dlen <= xlen |
|
&& (!con->conf.force_lowercase_filenames |
|
? 0 == memcmp(srv->tmp_buf->ptr, ds->value->ptr, dlen) |
|
: 0 == strncasecmp(srv->tmp_buf->ptr, ds->value->ptr, dlen))) { |
|
break; |
|
} |
|
} |
|
if (i == host->xsendfile_docroot->used) { |
|
log_error_write(srv, __FILE__, __LINE__, "SBs", |
|
"X-Sendfile2 (", srv->tmp_buf, |
|
") not under configured x-sendfile-docroot(s)"); |
|
return 403; |
|
} |
|
} |
|
|
if (HANDLER_ERROR == stat_cache_get_entry(srv, con, srv->tmp_buf, &sce)) { |
if (HANDLER_ERROR == stat_cache_get_entry(srv, con, srv->tmp_buf, &sce)) { |
if (p->conf.debug) { |
if (p->conf.debug) { |
log_error_write(srv, __FILE__, __LINE__, "sb", |
log_error_write(srv, __FILE__, __LINE__, "sb", |
"send-file error: couldn't get stat_cache entry for X-Sendfile2:", |
"send-file error: couldn't get stat_cache entry for X-Sendfile2:", |
srv->tmp_buf); |
srv->tmp_buf); |
} |
} |
return 1; | return 404; |
} else if (!S_ISREG(sce->st.st_mode)) { |
} else if (!S_ISREG(sce->st.st_mode)) { |
if (p->conf.debug) { |
if (p->conf.debug) { |
log_error_write(srv, __FILE__, __LINE__, "sb", |
log_error_write(srv, __FILE__, __LINE__, "sb", |
"send-file error: wrong filetype for X-Sendfile2:", |
"send-file error: wrong filetype for X-Sendfile2:", |
srv->tmp_buf); |
srv->tmp_buf); |
} |
} |
return 1; | return 502; |
} |
} |
/* found the file */ |
/* found the file */ |
|
|
Line 2335 range_failed:
|
Line 2363 range_failed:
|
if (p->conf.debug) { |
if (p->conf.debug) { |
log_error_write(srv, __FILE__, __LINE__, "ss", "Couldn't decode range after filename:", filename); |
log_error_write(srv, __FILE__, __LINE__, "ss", "Couldn't decode range after filename:", filename); |
} |
} |
return 1; | return 502; |
|
|
range_success: ; |
range_success: ; |
} |
} |
Line 2343 range_success: ;
|
Line 2371 range_success: ;
|
/* no parameters accepted */ |
/* no parameters accepted */ |
|
|
while (*pos == ' ') pos++; |
while (*pos == ' ') pos++; |
if (*pos != '\0' && *pos != ',') return 1; | if (*pos != '\0' && *pos != ',') return 502; |
|
|
range_len = end_range - begin_range + 1; |
range_len = end_range - begin_range + 1; |
if (range_len < 0) return 1; | if (range_len < 0) return 502; |
if (range_len != 0) { |
if (range_len != 0) { |
http_chunk_append_file(srv, con, srv->tmp_buf, begin_range, range_len); | if (0 != http_chunk_append_file_range(srv, con, srv->tmp_buf, begin_range, range_len)) { |
| return 502; |
| } |
} |
} |
sendfile2_content_length += range_len; |
sendfile2_content_length += range_len; |
|
|
Line 2358 range_success: ;
|
Line 2388 range_success: ;
|
break; |
break; |
case 14: |
case 14: |
if (0 == strncasecmp(key, "Content-Length", key_len)) { |
if (0 == strncasecmp(key, "Content-Length", key_len)) { |
con->response.content_length = strtol(value, NULL, 10); | con->response.content_length = strtoul(value, NULL, 10); |
con->parsed_response |= HTTP_CONTENT_LENGTH; |
con->parsed_response |= HTTP_CONTENT_LENGTH; |
|
|
if (con->response.content_length < 0) con->response.content_length = 0; |
if (con->response.content_length < 0) con->response.content_length = 0; |
Line 2372 range_success: ;
|
Line 2402 range_success: ;
|
if (have_sendfile2) { |
if (have_sendfile2) { |
data_string *dcls; |
data_string *dcls; |
|
|
hctx->send_content_body = 0; |
|
joblist_append(srv, con); |
|
|
|
/* fix content-length */ |
/* fix content-length */ |
if (NULL == (dcls = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) { |
if (NULL == (dcls = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) { |
dcls = data_response_init(); |
dcls = data_response_init(); |
} |
} |
|
|
buffer_copy_string_len(dcls->key, "Content-Length", sizeof("Content-Length")-1); |
buffer_copy_string_len(dcls->key, "Content-Length", sizeof("Content-Length")-1); |
buffer_copy_off_t(dcls->value, sendfile2_content_length); | buffer_copy_int(dcls->value, sendfile2_content_length); |
dcls = (data_string*) array_replace(con->response.headers, (data_unset *)dcls); | array_replace(con->response.headers, (data_unset *)dcls); |
if (dcls) dcls->free((data_unset*)dcls); | |
|
|
con->parsed_response |= HTTP_CONTENT_LENGTH; |
con->parsed_response |= HTTP_CONTENT_LENGTH; |
con->response.content_length = sendfile2_content_length; |
con->response.content_length = sendfile2_content_length; |
|
return 200; |
} |
} |
|
|
/* CGI/1.1 rev 03 - 7.2.1.2 */ |
/* CGI/1.1 rev 03 - 7.2.1.2 */ |
Line 2400 range_success: ;
|
Line 2427 range_success: ;
|
|
|
typedef struct { |
typedef struct { |
buffer *b; |
buffer *b; |
size_t len; | unsigned int len; |
int type; |
int type; |
int padding; |
int padding; |
size_t request_id; | int request_id; |
} fastcgi_response_packet; |
} fastcgi_response_packet; |
|
|
static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_packet *packet) { |
static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_packet *packet) { |
chunk * c; | chunk *c; |
size_t offset; |
size_t offset; |
size_t toread; |
size_t toread; |
FCGI_Header *header; |
FCGI_Header *header; |
Line 2423 static int fastcgi_get_packet(server *srv, handler_ctx
|
Line 2450 static int fastcgi_get_packet(server *srv, handler_ctx
|
offset = 0; toread = 8; |
offset = 0; toread = 8; |
/* get at least the FastCGI header */ |
/* get at least the FastCGI header */ |
for (c = hctx->rb->first; c; c = c->next) { |
for (c = hctx->rb->first; c; c = c->next) { |
size_t weHave = c->mem->used - c->offset - 1; | size_t weHave = buffer_string_length(c->mem) - c->offset; |
|
|
if (weHave > toread) weHave = toread; |
if (weHave > toread) weHave = toread; |
|
|
if (packet->b->used == 0) { | buffer_append_string_len(packet->b, c->mem->ptr + c->offset, weHave); |
buffer_copy_string_len(packet->b, c->mem->ptr + c->offset, weHave); | |
} else { | |
buffer_append_string_len(packet->b, c->mem->ptr + c->offset, weHave); | |
} | |
toread -= weHave; |
toread -= weHave; |
offset = weHave; /* skip offset bytes in chunk for "real" data */ |
offset = weHave; /* skip offset bytes in chunk for "real" data */ |
|
|
if (0 == toread) break; |
if (0 == toread) break; |
} |
} |
|
|
if ((packet->b->used == 0) || | if (buffer_string_length(packet->b) < sizeof(FCGI_Header)) { |
(packet->b->used - 1 < sizeof(FCGI_Header))) { | |
/* no header */ |
/* no header */ |
if (hctx->plugin_data->conf.debug) { |
if (hctx->plugin_data->conf.debug) { |
log_error_write(srv, __FILE__, __LINE__, "sdsds", "FastCGI: header too small:", packet->b->used, "bytes <", sizeof(FCGI_Header), "bytes, waiting for more data"); | log_error_write(srv, __FILE__, __LINE__, "sdsds", "FastCGI: header too small:", buffer_string_length(packet->b), "bytes <", sizeof(FCGI_Header), "bytes, waiting for more data"); |
} |
} |
|
|
buffer_free(packet->b); |
buffer_free(packet->b); |
Line 2459 static int fastcgi_get_packet(server *srv, handler_ctx
|
Line 2481 static int fastcgi_get_packet(server *srv, handler_ctx
|
packet->padding = header->paddingLength; |
packet->padding = header->paddingLength; |
|
|
/* ->b should only be the content */ |
/* ->b should only be the content */ |
buffer_copy_string_len(packet->b, CONST_STR_LEN("")); /* used == 1 */ | buffer_string_set_length(packet->b, 0); |
|
|
if (packet->len) { |
if (packet->len) { |
/* copy the content */ |
/* copy the content */ |
for (; c && (packet->b->used < packet->len + 1); c = c->next) { | for (; c && (buffer_string_length(packet->b) < packet->len); c = c->next) { |
size_t weWant = packet->len - (packet->b->used - 1); | size_t weWant = packet->len - buffer_string_length(packet->b); |
size_t weHave = c->mem->used - c->offset - offset - 1; | size_t weHave = buffer_string_length(c->mem) - c->offset - offset; |
|
|
if (weHave > weWant) weHave = weWant; |
if (weHave > weWant) weHave = weWant; |
|
|
Line 2475 static int fastcgi_get_packet(server *srv, handler_ctx
|
Line 2497 static int fastcgi_get_packet(server *srv, handler_ctx
|
offset = 0; |
offset = 0; |
} |
} |
|
|
if (packet->b->used < packet->len + 1) { | if (buffer_string_length(packet->b) < packet->len) { |
/* we didn't get the full packet */ |
/* we didn't get the full packet */ |
|
|
buffer_free(packet->b); |
buffer_free(packet->b); |
return -1; |
return -1; |
} |
} |
|
|
packet->b->used -= packet->padding; | buffer_string_set_length(packet->b, buffer_string_length(packet->b) - packet->padding); |
packet->b->ptr[packet->b->used - 1] = '\0'; | |
} |
} |
|
|
/* tag the chunks as read */ | chunkqueue_mark_written(hctx->rb, packet->len + sizeof(FCGI_Header)); |
toread = packet->len + sizeof(FCGI_Header); | |
for (c = hctx->rb->first; c && toread; c = c->next) { | |
if (c->mem->used - c->offset - 1 <= toread) { | |
/* we read this whole buffer, move it to unused */ | |
toread -= c->mem->used - c->offset - 1; | |
c->offset = c->mem->used - 1; /* everthing has been written */ | |
} else { | |
c->offset += toread; | |
toread = 0; | |
} | |
} | |
|
|
chunkqueue_remove_finished_chunks(hctx->rb); |
|
|
|
return 0; |
return 0; |
} |
} |
|
|
static int fcgi_demux_response(server *srv, handler_ctx *hctx) { |
static int fcgi_demux_response(server *srv, handler_ctx *hctx) { |
int fin = 0; |
int fin = 0; |
int toread; | int toread, ret; |
ssize_t r; | ssize_t r = 0; |
|
|
plugin_data *p = hctx->plugin_data; |
plugin_data *p = hctx->plugin_data; |
connection *con = hctx->remote_conn; |
connection *con = hctx->remote_conn; |
Line 2518 static int fcgi_demux_response(server *srv, handler_ct
|
Line 2526 static int fcgi_demux_response(server *srv, handler_ct
|
/* |
/* |
* check how much we have to read |
* check how much we have to read |
*/ |
*/ |
|
#if !defined(_WIN32) && !defined(__CYGWIN__) |
if (ioctl(hctx->fd, FIONREAD, &toread)) { |
if (ioctl(hctx->fd, FIONREAD, &toread)) { |
if (errno == EAGAIN) return 0; | if (errno == EAGAIN) { |
| fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN); |
| return 0; |
| } |
log_error_write(srv, __FILE__, __LINE__, "sd", |
log_error_write(srv, __FILE__, __LINE__, "sd", |
"unexpected end-of-file (perhaps the fastcgi process died):", |
"unexpected end-of-file (perhaps the fastcgi process died):", |
fcgi_fd); |
fcgi_fd); |
return -1; |
return -1; |
} |
} |
|
#else |
|
toread = 4096; |
|
#endif |
|
|
/* init read-buffer */ |
|
|
|
if (toread > 0) { |
if (toread > 0) { |
buffer *b; | char *mem; |
chunk *cq_first = hctx->rb->first; | size_t mem_len; |
chunk *cq_last = hctx->rb->last; | |
|
|
b = chunkqueue_get_append_buffer(hctx->rb); | if ((con->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN)) { |
buffer_prepare_copy(b, toread + 1); | off_t cqlen = chunkqueue_length(hctx->rb); |
| if (cqlen + toread > 65536 + (int)sizeof(FCGI_Header)) { /*(max size of FastCGI packet + 1)*/ |
| if (cqlen < 65536 + (int)sizeof(FCGI_Header)) { |
| toread = 65536 + (int)sizeof(FCGI_Header) - cqlen; |
| } else { /* should not happen */ |
| toread = toread < 1024 ? toread : 1024; |
| } |
| } |
| } |
|
|
/* append to read-buffer */ | chunkqueue_get_memory(hctx->rb, &mem, &mem_len, 0, toread); |
if (-1 == (r = read(hctx->fd, b->ptr, toread))) { | r = read(hctx->fd, mem, mem_len); |
| chunkqueue_use_memory(hctx->rb, r > 0 ? r : 0); |
| |
| if (-1 == r) { |
if (errno == EAGAIN) { |
if (errno == EAGAIN) { |
/* roll back the last chunk allocation, | fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN); |
and continue on next iteration */ | |
buffer_free(hctx->rb->last->mem); | |
free(hctx->rb->last); | |
hctx->rb->first = cq_first; | |
hctx->rb->last = cq_last; | |
return 0; |
return 0; |
} |
} |
log_error_write(srv, __FILE__, __LINE__, "sds", |
log_error_write(srv, __FILE__, __LINE__, "sds", |
Line 2552 static int fcgi_demux_response(server *srv, handler_ct
|
Line 2570 static int fcgi_demux_response(server *srv, handler_ct
|
fcgi_fd, strerror(errno)); |
fcgi_fd, strerror(errno)); |
return -1; |
return -1; |
} |
} |
| } |
/* this should be catched by the b > 0 above */ | if (0 == r) { |
force_assert(r); | |
| |
b->used = r + 1; /* one extra for the fake \0 */ | |
b->ptr[b->used - 1] = '\0'; | |
} else { | |
log_error_write(srv, __FILE__, __LINE__, "ssdsb", |
log_error_write(srv, __FILE__, __LINE__, "ssdsb", |
"unexpected end-of-file (perhaps the fastcgi process died):", |
"unexpected end-of-file (perhaps the fastcgi process died):", |
"pid:", proc->pid, |
"pid:", proc->pid, |
Line 2587 static int fcgi_demux_response(server *srv, handler_ct
|
Line 2600 static int fcgi_demux_response(server *srv, handler_ct
|
/* is the header already finished */ |
/* is the header already finished */ |
if (0 == con->file_started) { |
if (0 == con->file_started) { |
char *c; |
char *c; |
size_t blen; |
|
data_string *ds; |
data_string *ds; |
|
|
/* search for header terminator |
/* search for header terminator |
Line 2598 static int fcgi_demux_response(server *srv, handler_ct
|
Line 2610 static int fcgi_demux_response(server *srv, handler_ct
|
* search for \n\n |
* search for \n\n |
*/ |
*/ |
|
|
if (hctx->response_header->used == 0) { | buffer_append_string_buffer(hctx->response_header, packet.b); |
buffer_copy_string_buffer(hctx->response_header, packet.b); | |
} else { | |
buffer_append_string_buffer(hctx->response_header, packet.b); | |
} | |
|
|
if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\r\n\r\n")))) { |
if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\r\n\r\n")))) { |
blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 4; | char *hend = c + 4; /* header end == body start */ |
hctx->response_header->used = (c - hctx->response_header->ptr) + 3; | size_t hlen = hend - hctx->response_header->ptr; |
c += 4; /* point the the start of the response */ | buffer_copy_string_len(packet.b, hend, buffer_string_length(hctx->response_header) - hlen); |
| buffer_string_set_length(hctx->response_header, hlen); |
} else if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\n\n")))) { |
} else if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\n\n")))) { |
blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 2; | char *hend = c + 2; /* header end == body start */ |
hctx->response_header->used = c - hctx->response_header->ptr + 2; | size_t hlen = hend - hctx->response_header->ptr; |
c += 2; /* point the the start of the response */ | buffer_copy_string_len(packet.b, hend, buffer_string_length(hctx->response_header) - hlen); |
| buffer_string_set_length(hctx->response_header, hlen); |
} else { |
} else { |
/* no luck, no header found */ |
/* no luck, no header found */ |
|
/*(reuse MAX_HTTP_REQUEST_HEADER as max size for response headers from backends)*/ |
|
if (buffer_string_length(hctx->response_header) > MAX_HTTP_REQUEST_HEADER) { |
|
log_error_write(srv, __FILE__, __LINE__, "sb", "response headers too large for", con->uri.path); |
|
con->http_status = 502; /* Bad Gateway */ |
|
con->mode = DIRECT; |
|
fin = 1; |
|
} |
break; |
break; |
} |
} |
|
|
/* parse the response header */ |
/* parse the response header */ |
if (fcgi_response_parse(srv, con, p, hctx->response_header)) { | if ((ret = fcgi_response_parse(srv, con, p, hctx->response_header))) { |
con->http_status = 502; | if (200 != ret) { /*(200 returned for X-Sendfile2 handled)*/ |
hctx->send_content_body = 0; | con->http_status = ret; |
| con->mode = DIRECT; |
| } |
con->file_started = 1; |
con->file_started = 1; |
|
hctx->send_content_body = 0; |
|
fin = 1; |
break; |
break; |
} |
} |
|
|
Line 2634 static int fcgi_demux_response(server *srv, handler_ct
|
Line 2655 static int fcgi_demux_response(server *srv, handler_ct
|
hctx->send_content_body = 0; |
hctx->send_content_body = 0; |
} |
} |
|
|
if (host->allow_xsendfile && hctx->send_content_body && | if (host->xsendfile_allow && hctx->send_content_body && |
(NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-LIGHTTPD-send-file")) |
(NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-LIGHTTPD-send-file")) |
|| NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-Sendfile")))) { |
|| NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-Sendfile")))) { |
stat_cache_entry *sce; | http_response_xsendfile(srv, con, ds->value, host->xsendfile_docroot); |
| if (con->mode == DIRECT) { |
if (HANDLER_ERROR != stat_cache_get_entry(srv, con, ds->value, &sce)) { | fin = 1; |
data_string *dcls; | |
if (NULL == (dcls = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) { | |
dcls = data_response_init(); | |
} | |
/* found */ | |
http_chunk_append_file(srv, con, ds->value, 0, sce->st.st_size); | |
hctx->send_content_body = 0; /* ignore the content */ | |
joblist_append(srv, con); | |
| |
buffer_copy_string_len(dcls->key, "Content-Length", sizeof("Content-Length")-1); | |
buffer_copy_off_t(dcls->value, sce->st.st_size); | |
dcls = (data_string*) array_replace(con->response.headers, (data_unset *)dcls); | |
if (dcls) dcls->free((data_unset*)dcls); | |
| |
con->parsed_response |= HTTP_CONTENT_LENGTH; | |
con->response.content_length = sce->st.st_size; | |
} else { | |
log_error_write(srv, __FILE__, __LINE__, "sb", | |
"send-file error: couldn't get stat_cache entry for:", | |
ds->value); | |
con->http_status = 502; | |
hctx->send_content_body = 0; | |
con->file_started = 1; | |
break; | |
} |
} |
|
|
|
hctx->send_content_body = 0; /* ignore the content */ |
|
break; |
} |
} |
|
} |
|
|
| if (hctx->send_content_body && !buffer_string_is_empty(packet.b)) { |
if (hctx->send_content_body && blen > 1) { | if (0 != http_chunk_append_buffer(srv, con, packet.b)) { |
/* enable chunked-transfer-encoding */ | /* error writing to tempfile; |
if (con->request.http_version == HTTP_VERSION_1_1 && | * truncate response or send 500 if nothing sent yet */ |
!(con->parsed_response & HTTP_CONTENT_LENGTH)) { | fin = 1; |
con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED; | break; |
| } |
| if ((con->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN) |
| && chunkqueue_length(con->write_queue) > 65536 - 4096) { |
| if (!con->is_writable) { |
| /*(defer removal of FDEVENT_IN interest since |
| * connection_state_machine() might be able to send data |
| * immediately, unless !con->is_writable, where |
| * connection_state_machine() might not loop back to call |
| * mod_fastcgi_handle_subrequest())*/ |
| fdevent_event_clr(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN); |
} |
} |
|
|
http_chunk_append_mem(srv, con, c, blen); |
|
joblist_append(srv, con); |
|
} |
} |
} else if (hctx->send_content_body && packet.b->used > 1) { |
|
if (con->request.http_version == HTTP_VERSION_1_1 && |
|
!(con->parsed_response & HTTP_CONTENT_LENGTH)) { |
|
/* enable chunked-transfer-encoding */ |
|
con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED; |
|
} |
|
|
|
http_chunk_append_mem(srv, con, packet.b->ptr, packet.b->used); |
|
joblist_append(srv, con); |
|
} |
} |
break; |
break; |
case FCGI_STDERR: |
case FCGI_STDERR: |
Line 2697 static int fcgi_demux_response(server *srv, handler_ct
|
Line 2696 static int fcgi_demux_response(server *srv, handler_ct
|
|
|
break; |
break; |
case FCGI_END_REQUEST: |
case FCGI_END_REQUEST: |
con->file_finished = 1; |
|
|
|
if (host->mode != FCGI_AUTHORIZER || |
|
!(con->http_status == 0 || |
|
con->http_status == 200)) { |
|
/* send chunk-end if necessary */ |
|
http_chunk_append_mem(srv, con, NULL, 0); |
|
joblist_append(srv, con); |
|
} |
|
|
|
fin = 1; |
fin = 1; |
break; |
break; |
default: |
default: |
Line 2820 static int fcgi_restart_dead_procs(server *srv, plugin
|
Line 2809 static int fcgi_restart_dead_procs(server *srv, plugin
|
/* local procs get restarted by us, |
/* local procs get restarted by us, |
* remote ones hopefully by the admin */ |
* remote ones hopefully by the admin */ |
|
|
if (!buffer_is_empty(host->bin_path)) { | if (!buffer_string_is_empty(host->bin_path)) { |
/* we still have connections bound to this proc, |
/* we still have connections bound to this proc, |
* let them terminate first */ |
* let them terminate first */ |
if (proc->load != 0) break; |
if (proc->load != 0) break; |
Line 2874 static handler_t fcgi_write_request(server *srv, handl
|
Line 2863 static handler_t fcgi_write_request(server *srv, handl
|
log_error_write(srv, __FILE__, __LINE__, "s", "fatal error: host = NULL"); |
log_error_write(srv, __FILE__, __LINE__, "s", "fatal error: host = NULL"); |
return HANDLER_ERROR; |
return HANDLER_ERROR; |
} |
} |
if ((!host->port && !host->unixsocket->used)) { | if ((!host->port && buffer_string_is_empty(host->unixsocket))) { |
log_error_write(srv, __FILE__, __LINE__, "s", "fatal error: neither host->port nor host->unixsocket is set"); |
log_error_write(srv, __FILE__, __LINE__, "s", "fatal error: neither host->port nor host->unixsocket is set"); |
return HANDLER_ERROR; |
return HANDLER_ERROR; |
} |
} |
Line 2923 static handler_t fcgi_write_request(server *srv, handl
|
Line 2912 static handler_t fcgi_write_request(server *srv, handl
|
switch(hctx->state) { |
switch(hctx->state) { |
case FCGI_STATE_CONNECT_DELAYED: |
case FCGI_STATE_CONNECT_DELAYED: |
/* should never happen */ |
/* should never happen */ |
break; | return HANDLER_WAIT_FOR_EVENT; |
case FCGI_STATE_INIT: |
case FCGI_STATE_INIT: |
/* do we have a running process for this host (max-procs) ? */ |
/* do we have a running process for this host (max-procs) ? */ |
hctx->proc = NULL; |
hctx->proc = NULL; |
Line 2947 static handler_t fcgi_write_request(server *srv, handl
|
Line 2936 static handler_t fcgi_write_request(server *srv, handl
|
if (proc->load < hctx->proc->load) hctx->proc = proc; |
if (proc->load < hctx->proc->load) hctx->proc = proc; |
} |
} |
|
|
ret = host->unixsocket->used ? AF_UNIX : AF_INET; | if (-1 == (hctx->fd = socket(host->family, SOCK_STREAM, 0))) { |
| |
if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) { | |
if (errno == EMFILE || |
if (errno == EMFILE || |
errno == EINTR) { |
errno == EINTR) { |
log_error_write(srv, __FILE__, __LINE__, "sd", |
log_error_write(srv, __FILE__, __LINE__, "sd", |
Line 3066 static handler_t fcgi_write_request(server *srv, handl
|
Line 3053 static handler_t fcgi_write_request(server *srv, handl
|
"fcgi-request is already in use:", hctx->request_id); |
"fcgi-request is already in use:", hctx->request_id); |
} |
} |
|
|
/* fall through */ |
|
if (-1 == fcgi_create_env(srv, hctx, hctx->request_id)) return HANDLER_ERROR; |
if (-1 == fcgi_create_env(srv, hctx, hctx->request_id)) return HANDLER_ERROR; |
|
|
|
fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN); |
fcgi_set_state(srv, hctx, FCGI_STATE_WRITE); |
fcgi_set_state(srv, hctx, FCGI_STATE_WRITE); |
/* fall through */ |
/* fall through */ |
case FCGI_STATE_WRITE: |
case FCGI_STATE_WRITE: |
Line 3098 static handler_t fcgi_write_request(server *srv, handl
|
Line 3086 static handler_t fcgi_write_request(server *srv, handl
|
} |
} |
} |
} |
|
|
if (hctx->wb->bytes_out == hctx->wb->bytes_in) { | if (hctx->wb->bytes_out == hctx->wb_reqlen) { |
/* we don't need the out event anymore */ | fdevent_event_clr(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT); |
fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd); | |
fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN); | |
fcgi_set_state(srv, hctx, FCGI_STATE_READ); |
fcgi_set_state(srv, hctx, FCGI_STATE_READ); |
} else { |
} else { |
fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT); | off_t wblen = hctx->wb->bytes_in - hctx->wb->bytes_out; |
| if (hctx->wb->bytes_in < hctx->wb_reqlen && wblen < 65536 - 16384) { |
return HANDLER_WAIT_FOR_EVENT; | /*(con->conf.stream_request_body & FDEVENT_STREAM_REQUEST)*/ |
| if (!(con->conf.stream_request_body & FDEVENT_STREAM_REQUEST_POLLIN)) { |
| con->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_POLLIN; |
| con->is_readable = 1; /* trigger optimistic read from client */ |
| } |
| } |
| if (0 == wblen) { |
| fdevent_event_clr(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT); |
| } else { |
| fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT); |
| } |
} |
} |
|
|
break; | return HANDLER_WAIT_FOR_EVENT; |
case FCGI_STATE_READ: |
case FCGI_STATE_READ: |
/* waiting for a response */ |
/* waiting for a response */ |
break; | return HANDLER_WAIT_FOR_EVENT; |
default: |
default: |
log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state"); |
log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state"); |
return HANDLER_ERROR; |
return HANDLER_ERROR; |
} |
} |
|
|
return HANDLER_WAIT_FOR_EVENT; |
|
} |
} |
|
|
|
|
/* might be called on fdevent after a connect() is delay too |
/* might be called on fdevent after a connect() is delay too |
* */ |
* */ |
SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) { | static handler_t fcgi_send_request(server *srv, handler_ctx *hctx) { |
plugin_data *p = p_d; | |
| |
handler_ctx *hctx = con->plugin_ctx[p->id]; | |
fcgi_extension_host *host; |
fcgi_extension_host *host; |
|
handler_t rc; |
|
|
if (NULL == hctx) return HANDLER_GO_ON; |
|
|
|
/* not my job */ |
|
if (con->mode != p->id) return HANDLER_GO_ON; |
|
|
|
/* we don't have a host yet, choose one |
/* we don't have a host yet, choose one |
* -> this happens in the first round |
* -> this happens in the first round |
* and when the host died and we have to select a new one */ |
* and when the host died and we have to select a new one */ |
Line 3168 SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
|
Line 3155 SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
|
|
|
fcgi_connection_close(srv, hctx); |
fcgi_connection_close(srv, hctx); |
|
|
con->http_status = 500; |
|
con->mode = DIRECT; |
|
|
|
return HANDLER_FINISHED; |
return HANDLER_FINISHED; |
} |
} |
|
|
Line 3194 SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
|
Line 3178 SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
|
} |
} |
|
|
/* ok, create the request */ |
/* ok, create the request */ |
switch(fcgi_write_request(srv, hctx)) { | rc = fcgi_write_request(srv, hctx); |
case HANDLER_ERROR: | if (HANDLER_ERROR != rc) { |
| return rc; |
| } else { |
| plugin_data *p = hctx->plugin_data; |
| connection *con = hctx->remote_conn; |
| |
if (hctx->state == FCGI_STATE_INIT || |
if (hctx->state == FCGI_STATE_INIT || |
hctx->state == FCGI_STATE_CONNECT_DELAYED) { |
hctx->state == FCGI_STATE_CONNECT_DELAYED) { |
fcgi_restart_dead_procs(srv, p, host); |
fcgi_restart_dead_procs(srv, p, host); |
Line 3203 SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
|
Line 3192 SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
|
/* cleanup this request and let the request handler start this request again */ |
/* cleanup this request and let the request handler start this request again */ |
if (hctx->reconnects < 5) { |
if (hctx->reconnects < 5) { |
fcgi_reconnect(srv, hctx); |
fcgi_reconnect(srv, hctx); |
joblist_append(srv, con); /* in case we come from the event-handler */ |
|
|
|
return HANDLER_WAIT_FOR_FD; | return HANDLER_COMEBACK; |
} else { |
} else { |
fcgi_connection_close(srv, hctx); |
fcgi_connection_close(srv, hctx); |
|
|
buffer_reset(con->physical.path); |
|
con->mode = DIRECT; |
|
con->http_status = 503; |
con->http_status = 503; |
joblist_append(srv, con); /* in case we come from the event-handler */ |
|
|
|
return HANDLER_FINISHED; |
return HANDLER_FINISHED; |
} |
} |
} else { |
} else { |
|
int status = con->http_status; |
fcgi_connection_close(srv, hctx); |
fcgi_connection_close(srv, hctx); |
|
con->http_status = (status == 400) ? 400 : 503; /* see FCGI_ENV_ADD_CHECK() for 400 error */ |
|
|
buffer_reset(con->physical.path); |
|
con->mode = DIRECT; |
|
if (con->http_status != 400) con->http_status = 503; |
|
joblist_append(srv, con); /* really ? */ |
|
|
|
return HANDLER_FINISHED; |
return HANDLER_FINISHED; |
} |
} |
case HANDLER_WAIT_FOR_EVENT: | } |
if (con->file_started == 1) { | } |
return HANDLER_FINISHED; | |
| |
| static handler_t fcgi_recv_response(server *srv, handler_ctx *hctx); |
| |
| |
| SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) { |
| plugin_data *p = p_d; |
| |
| handler_ctx *hctx = con->plugin_ctx[p->id]; |
| |
| if (NULL == hctx) return HANDLER_GO_ON; |
| |
| /* not my job */ |
| if (con->mode != p->id) return HANDLER_GO_ON; |
| |
| if ((con->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN) |
| && con->file_started) { |
| if (chunkqueue_length(con->write_queue) > 65536 - 4096) { |
| fdevent_event_clr(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN); |
| } else if (!(fdevent_event_get_interest(srv->ev, hctx->fd) & FDEVENT_IN)) { |
| /* optimistic read from backend, which might re-enable FDEVENT_IN */ |
| handler_t rc = fcgi_recv_response(srv, hctx); /*(might invalidate hctx)*/ |
| if (rc != HANDLER_GO_ON) return rc; /*(unless HANDLER_GO_ON)*/ |
| } |
| } |
| |
| if (0 == hctx->wb->bytes_in |
| ? con->state == CON_STATE_READ_POST |
| : hctx->wb->bytes_in < hctx->wb_reqlen) { |
| /*(64k - 4k to attempt to avoid temporary files |
| * in conjunction with FDEVENT_STREAM_REQUEST_BUFMIN)*/ |
| if (hctx->wb->bytes_in - hctx->wb->bytes_out > 65536 - 4096 |
| && (con->conf.stream_request_body & FDEVENT_STREAM_REQUEST_BUFMIN)){ |
| con->conf.stream_request_body &= ~FDEVENT_STREAM_REQUEST_POLLIN; |
| if (0 != hctx->wb->bytes_in) return HANDLER_WAIT_FOR_EVENT; |
} else { |
} else { |
return HANDLER_WAIT_FOR_EVENT; | handler_t r = connection_handle_read_post_state(srv, con); |
| chunkqueue *req_cq = con->request_content_queue; |
| if (0 != hctx->wb->bytes_in && !chunkqueue_is_empty(req_cq)) { |
| fcgi_stdin_append(srv, con, hctx, hctx->request_id); |
| if (fdevent_event_get_interest(srv->ev, hctx->fd) & FDEVENT_OUT) { |
| return (r == HANDLER_GO_ON) ? HANDLER_WAIT_FOR_EVENT : r; |
| } |
| } |
| if (r != HANDLER_GO_ON) return r; |
} |
} |
case HANDLER_WAIT_FOR_FD: |
|
return HANDLER_WAIT_FOR_FD; |
|
default: |
|
log_error_write(srv, __FILE__, __LINE__, "s", "subrequest write-req default"); |
|
return HANDLER_ERROR; |
|
} |
} |
|
|
|
return ((0 == hctx->wb->bytes_in || !chunkqueue_is_empty(hctx->wb)) |
|
&& hctx->state != FCGI_STATE_CONNECT_DELAYED) |
|
? fcgi_send_request(srv, hctx) |
|
: HANDLER_WAIT_FOR_EVENT; |
} |
} |
|
|
static handler_t fcgi_handle_fdevent(server *srv, void *ctx, int revents) { | |
handler_ctx *hctx = ctx; | static handler_t fcgi_recv_response(server *srv, handler_ctx *hctx) { |
connection *con = hctx->remote_conn; |
connection *con = hctx->remote_conn; |
plugin_data *p = hctx->plugin_data; |
plugin_data *p = hctx->plugin_data; |
|
|
fcgi_proc *proc = hctx->proc; |
fcgi_proc *proc = hctx->proc; |
fcgi_extension_host *host= hctx->host; |
fcgi_extension_host *host= hctx->host; |
|
|
if ((revents & FDEVENT_IN) && |
|
hctx->state == FCGI_STATE_READ) { |
|
switch (fcgi_demux_response(srv, hctx)) { |
switch (fcgi_demux_response(srv, hctx)) { |
case 0: |
case 0: |
break; |
break; |
Line 3264 static handler_t fcgi_handle_fdevent(server *srv, void
|
Line 3285 static handler_t fcgi_handle_fdevent(server *srv, void
|
* now to handle authorized request. |
* now to handle authorized request. |
*/ |
*/ |
|
|
buffer_copy_string_buffer(con->physical.doc_root, host->docroot); | buffer_copy_buffer(con->physical.doc_root, host->docroot); |
buffer_copy_string_buffer(con->physical.basedir, host->docroot); | buffer_copy_buffer(con->physical.basedir, host->docroot); |
|
|
buffer_copy_string_buffer(con->physical.path, host->docroot); | buffer_copy_buffer(con->physical.path, host->docroot); |
buffer_append_string_buffer(con->physical.path, con->uri.path); |
buffer_append_string_buffer(con->physical.path, con->uri.path); |
fcgi_connection_close(srv, hctx); |
|
|
|
con->mode = DIRECT; | con->mode = DIRECT;/*(avoid changing con->state, con->http_status)*/ |
| fcgi_connection_close(srv, hctx); |
con->http_status = 0; |
con->http_status = 0; |
con->file_started = 1; /* fcgi_extension won't touch the request afterwards */ |
con->file_started = 1; /* fcgi_extension won't touch the request afterwards */ |
} else { |
} else { |
Line 3279 static handler_t fcgi_handle_fdevent(server *srv, void
|
Line 3300 static handler_t fcgi_handle_fdevent(server *srv, void
|
fcgi_connection_close(srv, hctx); |
fcgi_connection_close(srv, hctx); |
} |
} |
|
|
joblist_append(srv, con); |
|
return HANDLER_FINISHED; |
return HANDLER_FINISHED; |
case -1: |
case -1: |
if (proc->pid && proc->state != PROC_STATE_DIED) { |
if (proc->pid && proc->state != PROC_STATE_DIED) { |
Line 3333 static handler_t fcgi_handle_fdevent(server *srv, void
|
Line 3353 static handler_t fcgi_handle_fdevent(server *srv, void
|
|
|
if (hctx->wb->bytes_out == 0 && |
if (hctx->wb->bytes_out == 0 && |
hctx->reconnects < 5) { |
hctx->reconnects < 5) { |
fcgi_reconnect(srv, hctx); |
|
|
|
log_error_write(srv, __FILE__, __LINE__, "ssbsBSBs", |
log_error_write(srv, __FILE__, __LINE__, "ssbsBSBs", |
"response not received, request not sent", |
"response not received, request not sent", |
"on socket:", proc->connection_name, |
"on socket:", proc->connection_name, |
"for", con->uri.path, "?", con->uri.query, ", reconnecting"); |
"for", con->uri.path, "?", con->uri.query, ", reconnecting"); |
|
|
return HANDLER_WAIT_FOR_FD; | fcgi_reconnect(srv, hctx); |
| |
| return HANDLER_COMEBACK; |
} |
} |
|
|
log_error_write(srv, __FILE__, __LINE__, "sosbsBSBs", |
log_error_write(srv, __FILE__, __LINE__, "sosbsBSBs", |
"response not received, request sent:", hctx->wb->bytes_out, |
"response not received, request sent:", hctx->wb->bytes_out, |
"on socket:", proc->connection_name, |
"on socket:", proc->connection_name, |
"for", con->uri.path, "?", con->uri.query, ", closing connection"); |
"for", con->uri.path, "?", con->uri.query, ", closing connection"); |
|
|
fcgi_connection_close(srv, hctx); |
|
|
|
connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); |
|
buffer_reset(con->physical.path); |
|
con->http_status = 500; |
|
con->mode = DIRECT; |
|
} else { |
} else { |
/* response might have been already started, kill the connection */ |
|
fcgi_connection_close(srv, hctx); |
|
|
|
log_error_write(srv, __FILE__, __LINE__, "ssbsBSBs", |
log_error_write(srv, __FILE__, __LINE__, "ssbsBSBs", |
"response already sent out, but backend returned error", |
"response already sent out, but backend returned error", |
"on socket:", proc->connection_name, |
"on socket:", proc->connection_name, |
"for", con->uri.path, "?", con->uri.query, ", terminating connection"); |
"for", con->uri.path, "?", con->uri.query, ", terminating connection"); |
|
|
connection_set_state(srv, con, CON_STATE_ERROR); |
|
} |
} |
|
|
/* */ | http_response_backend_error(srv, con); |
| fcgi_connection_close(srv, hctx); |
| |
joblist_append(srv, con); | |
return HANDLER_FINISHED; |
return HANDLER_FINISHED; |
} |
} |
|
|
|
return HANDLER_GO_ON; |
|
} |
|
|
|
|
|
static handler_t fcgi_handle_fdevent(server *srv, void *ctx, int revents) { |
|
handler_ctx *hctx = ctx; |
|
connection *con = hctx->remote_conn; |
|
|
|
joblist_append(srv, con); |
|
|
|
if (revents & FDEVENT_IN) { |
|
handler_t rc = fcgi_recv_response(srv, hctx);/*(might invalidate hctx)*/ |
|
if (rc != HANDLER_GO_ON) return rc; /*(unless HANDLER_GO_ON)*/ |
} |
} |
|
|
if (revents & FDEVENT_OUT) { |
if (revents & FDEVENT_OUT) { |
if (hctx->state == FCGI_STATE_CONNECT_DELAYED || | return fcgi_send_request(srv, hctx); /*(might invalidate hctx)*/ |
hctx->state == FCGI_STATE_WRITE) { | |
/* we are allowed to send something out | |
* | |
* 1. in an unfinished connect() call | |
* 2. in an unfinished write() call (long POST request) | |
*/ | |
return mod_fastcgi_handle_subrequest(srv, con, p); | |
} else { | |
log_error_write(srv, __FILE__, __LINE__, "sd", | |
"got a FDEVENT_OUT and didn't know why:", | |
hctx->state); | |
} | |
} |
} |
|
|
/* perhaps this issue is already handled */ |
/* perhaps this issue is already handled */ |
Line 3402 static handler_t fcgi_handle_fdevent(server *srv, void
|
Line 3411 static handler_t fcgi_handle_fdevent(server *srv, void
|
* FIXME: as it is a bit ugly. |
* FIXME: as it is a bit ugly. |
* |
* |
*/ |
*/ |
return mod_fastcgi_handle_subrequest(srv, con, p); | fcgi_send_request(srv, hctx); |
} else if (hctx->state == FCGI_STATE_READ && | } else if (con->file_started) { |
hctx->proc->port == 0) { | /* drain any remaining data from kernel pipe buffers |
/* FIXME: | * even if (con->conf.stream_response_body |
* | * & FDEVENT_STREAM_RESPONSE_BUFMIN) |
* ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket | * since event loop will spin on fd FDEVENT_HUP event |
* even if the FCGI_FIN packet is not received yet | * until unregistered. */ |
*/ | handler_t rc; |
| do { |
| rc = fcgi_recv_response(srv,hctx);/*(might invalidate hctx)*/ |
| } while (rc == HANDLER_GO_ON); /*(unless HANDLER_GO_ON)*/ |
| return rc; /* HANDLER_FINISHED or HANDLER_ERROR */ |
} else { |
} else { |
|
fcgi_proc *proc = hctx->proc; |
log_error_write(srv, __FILE__, __LINE__, "sBSbsbsd", |
log_error_write(srv, __FILE__, __LINE__, "sBSbsbsd", |
"error: unexpected close of fastcgi connection for", |
"error: unexpected close of fastcgi connection for", |
con->uri.path, "?", con->uri.query, |
con->uri.path, "?", con->uri.query, |
"(no fastcgi process on socket:", proc->connection_name, "?)", |
"(no fastcgi process on socket:", proc->connection_name, "?)", |
hctx->state); |
hctx->state); |
|
|
connection_set_state(srv, con, CON_STATE_ERROR); |
|
fcgi_connection_close(srv, hctx); |
fcgi_connection_close(srv, hctx); |
joblist_append(srv, con); |
|
} |
} |
} else if (revents & FDEVENT_ERR) { |
} else if (revents & FDEVENT_ERR) { |
log_error_write(srv, __FILE__, __LINE__, "s", |
log_error_write(srv, __FILE__, __LINE__, "s", |
"fcgi: got a FDEVENT_ERR. Don't know why."); |
"fcgi: got a FDEVENT_ERR. Don't know why."); |
/* kill all connections to the fastcgi process */ |
|
|
|
| http_response_backend_error(srv, con); |
connection_set_state(srv, con, CON_STATE_ERROR); | |
fcgi_connection_close(srv, hctx); |
fcgi_connection_close(srv, hctx); |
joblist_append(srv, con); |
|
} |
} |
|
|
return HANDLER_FINISHED; |
return HANDLER_FINISHED; |
} |
} |
|
|
#define PATCH(x) \ |
#define PATCH(x) \ |
p->conf.x = s->x; |
p->conf.x = s->x; |
static int fcgi_patch_connection(server *srv, connection *con, plugin_data *p) { |
static int fcgi_patch_connection(server *srv, connection *con, plugin_data *p) { |
Line 3486 static handler_t fcgi_check_extension(server *srv, con
|
Line 3496 static handler_t fcgi_check_extension(server *srv, con
|
|
|
fn = uri_path_handler ? con->uri.path : con->physical.path; |
fn = uri_path_handler ? con->uri.path : con->physical.path; |
|
|
if (buffer_is_empty(fn)) return HANDLER_GO_ON; | if (buffer_string_is_empty(fn)) return HANDLER_GO_ON; |
|
|
s_len = fn->used - 1; | s_len = buffer_string_length(fn); |
|
|
fcgi_patch_connection(srv, con, p); |
fcgi_patch_connection(srv, con, p); |
|
|
Line 3505 static handler_t fcgi_check_extension(server *srv, con
|
Line 3515 static handler_t fcgi_check_extension(server *srv, con
|
data_string *ds = (data_string *)p->conf.ext_mapping->data[k]; |
data_string *ds = (data_string *)p->conf.ext_mapping->data[k]; |
size_t ct_len; /* length of the config entry */ |
size_t ct_len; /* length of the config entry */ |
|
|
if (ds->key->used == 0) continue; | if (buffer_is_empty(ds->key)) continue; |
|
|
ct_len = ds->key->used - 1; | ct_len = buffer_string_length(ds->key); |
|
|
if (s_len < ct_len) continue; |
if (s_len < ct_len) continue; |
|
|
Line 3533 static handler_t fcgi_check_extension(server *srv, con
|
Line 3543 static handler_t fcgi_check_extension(server *srv, con
|
} |
} |
|
|
if (extension == NULL) { |
if (extension == NULL) { |
|
size_t uri_path_len = buffer_string_length(con->uri.path); |
|
|
/* check if extension matches */ |
/* check if extension matches */ |
for (k = 0; k < p->conf.exts->used; k++) { |
for (k = 0; k < p->conf.exts->used; k++) { |
size_t ct_len; /* length of the config entry */ |
size_t ct_len; /* length of the config entry */ |
fcgi_extension *ext = p->conf.exts->exts[k]; |
fcgi_extension *ext = p->conf.exts->exts[k]; |
|
|
if (ext->key->used == 0) continue; | if (buffer_is_empty(ext->key)) continue; |
|
|
ct_len = ext->key->used - 1; | ct_len = buffer_string_length(ext->key); |
|
|
/* check _url_ in the form "/fcgi_pattern" */ |
/* check _url_ in the form "/fcgi_pattern" */ |
if (ext->key->ptr[0] == '/') { |
if (ext->key->ptr[0] == '/') { |
if ((ct_len <= con->uri.path->used -1) && | if ((ct_len <= uri_path_len) && |
(strncmp(con->uri.path->ptr, ext->key->ptr, ct_len) == 0)) { |
(strncmp(con->uri.path->ptr, ext->key->ptr, ct_len) == 0)) { |
extension = ext; |
extension = ext; |
break; |
break; |
Line 3577 static handler_t fcgi_check_extension(server *srv, con
|
Line 3589 static handler_t fcgi_check_extension(server *srv, con
|
|
|
if (!host) { |
if (!host) { |
/* sorry, we don't have a server alive for this ext */ |
/* sorry, we don't have a server alive for this ext */ |
buffer_reset(con->physical.path); |
|
con->http_status = 500; |
con->http_status = 500; |
|
con->mode = DIRECT; |
|
|
/* only send the 'no handler' once */ |
/* only send the 'no handler' once */ |
if (!extension->note_is_sent) { |
if (!extension->note_is_sent) { |
Line 3659 static handler_t fcgi_check_extension(server *srv, con
|
Line 3671 static handler_t fcgi_check_extension(server *srv, con
|
/* the rewrite is only done for /prefix/? matches */ |
/* the rewrite is only done for /prefix/? matches */ |
if (host->fix_root_path_name && extension->key->ptr[0] == '/' && extension->key->ptr[1] == '\0') { |
if (host->fix_root_path_name && extension->key->ptr[0] == '/' && extension->key->ptr[1] == '\0') { |
buffer_copy_string(con->request.pathinfo, con->uri.path->ptr); |
buffer_copy_string(con->request.pathinfo, con->uri.path->ptr); |
con->uri.path->used = 1; | buffer_string_set_length(con->uri.path, 0); |
con->uri.path->ptr[con->uri.path->used - 1] = '\0'; | |
} else if (extension->key->ptr[0] == '/' && |
} else if (extension->key->ptr[0] == '/' && |
con->uri.path->used > extension->key->used && | buffer_string_length(con->uri.path) > buffer_string_length(extension->key) && |
NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) { | NULL != (pathinfo = strchr(con->uri.path->ptr + buffer_string_length(extension->key), '/'))) { |
/* rewrite uri.path and pathinfo */ |
/* rewrite uri.path and pathinfo */ |
|
|
buffer_copy_string(con->request.pathinfo, pathinfo); |
buffer_copy_string(con->request.pathinfo, pathinfo); |
| buffer_string_set_length(con->uri.path, buffer_string_length(con->uri.path) - buffer_string_length(con->request.pathinfo)); |
con->uri.path->used -= con->request.pathinfo->used - 1; | |
con->uri.path->ptr[con->uri.path->used - 1] = '\0'; | |
} |
} |
} |
} |
} |
} |
Line 3707 static handler_t fcgi_check_extension_2(server *srv, c
|
Line 3716 static handler_t fcgi_check_extension_2(server *srv, c
|
return fcgi_check_extension(srv, con, p_d, 0); |
return fcgi_check_extension(srv, con, p_d, 0); |
} |
} |
|
|
JOBLIST_FUNC(mod_fastcgi_handle_joblist) { |
|
plugin_data *p = p_d; |
|
handler_ctx *hctx = con->plugin_ctx[p->id]; |
|
|
|
if (hctx == NULL) return HANDLER_GO_ON; |
|
|
|
if (hctx->fd != -1) { |
|
switch (hctx->state) { |
|
case FCGI_STATE_READ: |
|
fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN); |
|
|
|
break; |
|
case FCGI_STATE_CONNECT_DELAYED: |
|
case FCGI_STATE_WRITE: |
|
fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT); |
|
|
|
break; |
|
case FCGI_STATE_INIT: |
|
/* at reconnect */ |
|
break; |
|
default: |
|
log_error_write(srv, __FILE__, __LINE__, "sd", "unhandled fcgi.state", hctx->state); |
|
break; |
|
} |
|
} |
|
|
|
return HANDLER_GO_ON; |
|
} |
|
|
|
|
|
static handler_t fcgi_connection_close_callback(server *srv, connection *con, void *p_d) { |
|
plugin_data *p = p_d; |
|
|
|
fcgi_connection_close(srv, con->plugin_ctx[p->id]); |
|
|
|
return HANDLER_GO_ON; |
|
} |
|
|
|
TRIGGER_FUNC(mod_fastcgi_handle_trigger) { |
TRIGGER_FUNC(mod_fastcgi_handle_trigger) { |
plugin_data *p = p_d; |
plugin_data *p = p_d; |
size_t i, j, n; |
size_t i, j, n; |
Line 3849 int mod_fastcgi_plugin_init(plugin *p) {
|
Line 3821 int mod_fastcgi_plugin_init(plugin *p) {
|
p->cleanup = mod_fastcgi_free; |
p->cleanup = mod_fastcgi_free; |
p->set_defaults = mod_fastcgi_set_defaults; |
p->set_defaults = mod_fastcgi_set_defaults; |
p->connection_reset = fcgi_connection_reset; |
p->connection_reset = fcgi_connection_reset; |
p->handle_connection_close = fcgi_connection_close_callback; | p->handle_connection_close = fcgi_connection_reset; |
p->handle_uri_clean = fcgi_check_extension_1; |
p->handle_uri_clean = fcgi_check_extension_1; |
p->handle_subrequest_start = fcgi_check_extension_2; |
p->handle_subrequest_start = fcgi_check_extension_2; |
p->handle_subrequest = mod_fastcgi_handle_subrequest; |
p->handle_subrequest = mod_fastcgi_handle_subrequest; |
p->handle_joblist = mod_fastcgi_handle_joblist; |
|
p->handle_trigger = mod_fastcgi_handle_trigger; |
p->handle_trigger = mod_fastcgi_handle_trigger; |
|
|
p->data = NULL; |
p->data = NULL; |