static sa_t client_sa;
+/* hash table */
+
+#define FCGI_HASH_TABLE_SIZE 128
+#define FCGI_HASH_TABLE_MASK (FCGI_HASH_TABLE_SIZE - 1)
+#define FCGI_HASH_SEG_SIZE 4096
+
+typedef struct _fcgi_hash_bucket {
+ unsigned int hash_value;
+ unsigned int var_len;
+ char *var;
+ unsigned int val_len;
+ char *val;
+ struct _fcgi_hash_bucket *next;
+ struct _fcgi_hash_bucket *list_next;
+} fcgi_hash_bucket;
+
+typedef struct _fcgi_hash_buckets {
+ unsigned int idx;
+ struct _fcgi_hash_buckets *next;
+ struct _fcgi_hash_bucket data[FCGI_HASH_TABLE_SIZE];
+} fcgi_hash_buckets;
+
+typedef struct _fcgi_data_seg {
+ char *pos;
+ char *end;
+ struct _fcgi_data_seg *next;
+ char data[1];
+} fcgi_data_seg;
+
+typedef struct _fcgi_hash {
+ fcgi_hash_bucket *hash_table[FCGI_HASH_TABLE_SIZE];
+ fcgi_hash_bucket *list;
+ fcgi_hash_buckets *buckets;
+ fcgi_data_seg *data;
+} fcgi_hash;
+
+static void fcgi_hash_init(fcgi_hash *h)
+{
+ memset(h->hash_table, 0, sizeof(h->hash_table));
+ h->list = NULL;
+ h->buckets = (fcgi_hash_buckets*)malloc(sizeof(fcgi_hash_buckets));
+ h->buckets->idx = 0;
+ h->buckets->next = NULL;
+ h->data = (fcgi_data_seg*)malloc(sizeof(fcgi_data_seg) - 1 + FCGI_HASH_SEG_SIZE);
+ h->data->pos = h->data->data;
+ h->data->end = h->data->pos + FCGI_HASH_SEG_SIZE;
+ h->data->next = NULL;
+}
+
+static void fcgi_hash_destroy(fcgi_hash *h)
+{
+ fcgi_hash_buckets *b;
+ fcgi_data_seg *p;
+
+ b = h->buckets;
+ while (b) {
+ fcgi_hash_buckets *q = b;
+ b = b->next;
+ free(q);
+ }
+ p = h->data;
+ while (p) {
+ fcgi_data_seg *q = p;
+ p = p->next;
+ free(q);
+ }
+}
+
+static void fcgi_hash_clean(fcgi_hash *h)
+{
+ memset(h->hash_table, 0, sizeof(h->hash_table));
+ h->list = NULL;
+ /* delete all bucket blocks except the first one */
+ while (h->buckets->next) {
+ fcgi_hash_buckets *q = h->buckets;
+
+ h->buckets = h->buckets->next;
+ free(q);
+ }
+ h->buckets->idx = 0;
+ /* delete all data segments except the first one */
+ while (h->data->next) {
+ fcgi_data_seg *q = h->data;
+
+ h->data = h->data->next;
+ free(q);
+ }
+ h->data->pos = h->data->data;
+}
+
+static inline char* fcgi_hash_strndup(fcgi_hash *h, char *str, unsigned int str_len)
+{
+ char *ret;
+
+ if (UNEXPECTED(h->data->pos + str_len + 1 >= h->data->end)) {
+ unsigned int seg_size = (str_len + 1 > FCGI_HASH_SEG_SIZE) ? str_len + 1 : FCGI_HASH_SEG_SIZE;
+ fcgi_data_seg *p = (fcgi_data_seg*)malloc(sizeof(fcgi_data_seg) - 1 + seg_size);
+
+ p->pos = p->data;
+ p->end = p->pos + seg_size;
+ p->next = h->data;
+ h->data = p;
+ }
+ ret = h->data->pos;
+ memcpy(ret, str, str_len);
+ ret[str_len] = 0;
+ h->data->pos += str_len + 1;
+ return ret;
+}
+
+static char* fcgi_hash_set(fcgi_hash *h, unsigned int hash_value, char *var, unsigned int var_len, char *val, unsigned int val_len)
+{
+ unsigned int idx = hash_value & FCGI_HASH_TABLE_MASK;
+ fcgi_hash_bucket *p = h->hash_table[idx];
+
+ while (UNEXPECTED(p != NULL)) {
+ if (UNEXPECTED(p->hash_value == hash_value) &&
+ p->var_len == var_len &&
+ memcmp(p->var, var, var_len) == 0) {
+
+ p->val_len = val_len;
+ p->val = fcgi_hash_strndup(h, val, val_len);
+ return p->val;
+ }
+ p = p->next;
+ }
+
+ if (UNEXPECTED(h->buckets->idx >= FCGI_HASH_TABLE_SIZE)) {
+ fcgi_hash_buckets *b = (fcgi_hash_buckets*)malloc(sizeof(fcgi_hash_buckets));
+ b->idx = 0;
+ b->next = h->buckets;
+ h->buckets = b;
+ }
+ p = h->buckets->data + h->buckets->idx;
+ h->buckets->idx++;
+ p->next = h->hash_table[idx];
+ h->hash_table[idx] = p;
+ p->list_next = h->list;
+ h->list = p;
+ p->hash_value = hash_value;
+ p->var_len = var_len;
+ p->var = fcgi_hash_strndup(h, var, var_len);
+ p->val_len = val_len;
+ p->val = fcgi_hash_strndup(h, val, val_len);
+ return p->val;
+}
+
+static void fcgi_hash_del(fcgi_hash *h, unsigned int hash_value, char *var, unsigned int var_len)
+{
+ unsigned int idx = hash_value & FCGI_HASH_TABLE_MASK;
+ fcgi_hash_bucket **p = &h->hash_table[idx];
+
+ while (*p != NULL) {
+ if ((*p)->hash_value == hash_value &&
+ (*p)->var_len == var_len &&
+ memcmp((*p)->var, var, var_len) == 0) {
+
+ (*p)->val = NULL; /* NULL value means deleted */
+ (*p)->val_len = 0;
+ *p = (*p)->next;
+ return;
+ }
+ p = &(*p)->next;
+ }
+}
+
+static char *fcgi_hash_get(fcgi_hash *h, unsigned int hash_value, char *var, unsigned int var_len, unsigned int *val_len)
+{
+ unsigned int idx = hash_value & FCGI_HASH_TABLE_MASK;
+ fcgi_hash_bucket *p = h->hash_table[idx];
+
+ while (p != NULL) {
+ if (p->hash_value == hash_value &&
+ p->var_len == var_len &&
+ memcmp(p->var, var, var_len) == 0) {
+ *val_len = p->val_len;
+ return p->val;
+ }
+ p = p->next;
+ }
+ return NULL;
+}
+
+static void fcgi_hash_apply(fcgi_hash *h, fcgi_apply_func func, void *arg)
+{
+ fcgi_hash_bucket *p = h->list;
+
+ while (p) {
+ if (EXPECTED(p->val != NULL)) {
+ func(p->var, p->var_len, p->val, p->val_len, arg);
+ }
+ p = p->list_next;
+ }
+}
+
+struct _fcgi_request {
+ int listen_socket;
+#ifdef _WIN32
+ int tcp;
+#endif
+ int fd;
+ int id;
+ int keep;
+#ifdef TCP_NODELAY
+ int nodelay;
+#endif
+ int closed;
+
+ int in_len;
+ int in_pad;
+
+ fcgi_header *out_hdr;
+ unsigned char *out_pos;
+ unsigned char out_buf[1024*8];
+ unsigned char reserved[sizeof(fcgi_end_request_rec)];
+
+ int has_env;
+ fcgi_hash env;
+};
+
#ifdef _WIN32
static DWORD WINAPI fcgi_shutdown_thread(LPVOID arg)
}
#endif
+int fcgi_in_shutdown(void)
+{
+ return in_shutdown;
+}
+
+void fcgi_terminate(void)
+{
+ in_shutdown = 1;
+}
+
int fcgi_init(void)
{
if (!is_initialized) {
- zend_hash_init(&fcgi_mgmt_vars, 0, NULL, fcgi_free_mgmt_var_cb, 1);
+ zend_hash_init(&fcgi_mgmt_vars, 8, NULL, fcgi_free_mgmt_var_cb, 1);
fcgi_set_mgmt_var("FCGI_MPXS_CONNS", sizeof("FCGI_MPXS_CONNS") - 1, "0", sizeof("0")-1);
is_initialized = 1;
}
}
-void fcgi_init_request(fcgi_request *req, int listen_socket)
+fcgi_request *fcgi_init_request(int listen_socket)
{
- memset(req, 0, sizeof(fcgi_request));
+ fcgi_request *req = (fcgi_request*)calloc(1, sizeof(fcgi_request));
req->listen_socket = listen_socket;
req->fd = -1;
req->id = -1;
#ifdef _WIN32
req->tcp = !GetNamedPipeInfo((HANDLE)_get_osfhandle(req->listen_socket), NULL, NULL, NULL, NULL);
#endif
+
+#ifdef TCP_NODELAY
+ req->nodelay = 0;
+#endif
+
+ fcgi_hash_init(&req->env);
+
+ return req;
+}
+
+void fcgi_destroy_request(fcgi_request *req)
+{
+ fcgi_hash_destroy(&req->env);
+ free(req);
}
static inline ssize_t safe_write(fcgi_request *req, const void *buf, size_t count)
return pad;
}
-static inline size_t fcgi_get_params_len( int *result, unsigned char *p, unsigned char *end)
-{
- size_t ret = 0;
-
- if (p < end) {
- *result = p[0];
- if (*result < 128) {
- ret = 1;
- }
- else if (p + 3 < end) {
- *result = ((*result & 0x7f) << 24);
- *result |= (p[1] << 16);
- *result |= (p[2] << 8);
- *result |= p[3];
- ret = 4;
- }
- }
- if (*result < 0) {
- ret = 0;
- }
- return ret;
-}
-
-static inline int fcgi_param_get_eff_len( unsigned char *p, unsigned char *end, uint *eff_len)
-{
- int ret = 1;
- int zero_found = 0;
- *eff_len = 0;
- for (; p != end; ++p) {
- if (*p == '\0') {
- zero_found = 1;
- }
- else {
- if (zero_found) {
- ret = 0;
- break;
- }
- if (*eff_len < ((uint)-1)) {
- ++*eff_len;
- }
- else {
- ret = 0;
- break;
- }
- }
- }
- return ret;
-}
-
static int fcgi_get_params(fcgi_request *req, unsigned char *p, unsigned char *end)
{
- char buf[128];
- char *tmp = buf;
- size_t buf_size = sizeof(buf);
int name_len = 0;
int val_len = 0;
- uint eff_name_len = 0;
- char *s;
- int ret = 1;
- size_t bytes_consumed;
while (p < end) {
- bytes_consumed = fcgi_get_params_len(&name_len, p, end);
- if (!bytes_consumed) {
- /* Malformated request */
- ret = 0;
- break;
+ name_len = *p++;
+ if (UNEXPECTED(name_len >= 128)) {
+ if (UNEXPECTED(p + 3 >= end)) return 0;
+ name_len = ((name_len & 0x7f) << 24);
+ name_len |= (*p++ << 16);
+ name_len |= (*p++ << 8);
+ name_len |= *p++;
}
- p += bytes_consumed;
- bytes_consumed = fcgi_get_params_len(&val_len, p, end);
- if (!bytes_consumed) {
- /* Malformated request */
- ret = 0;
- break;
+ if (UNEXPECTED(p >= end)) return 0;
+ val_len = *p++;
+ if (UNEXPECTED(val_len >= 128)) {
+ if (UNEXPECTED(p + 3 >= end)) return 0;
+ val_len = ((val_len & 0x7f) << 24);
+ val_len |= (*p++ << 16);
+ val_len |= (*p++ << 8);
+ val_len |= *p++;
}
- p += bytes_consumed;
- if (name_len > (INT_MAX - val_len) || /* would the addition overflow? */
- name_len + val_len > end - p) { /* would we exceed the buffer? */
+ if (UNEXPECTED(name_len > (INT_MAX - val_len)) || /* would the addition overflow? */
+ UNEXPECTED(name_len + val_len > end - p)) { /* would we exceed the buffer? */
/* Malformated request */
- ret = 0;
- break;
+ return 0;
}
/*
* get the effective length of the name in case it's not a valid string
* don't do this on the value because it can be binary data
*/
- if (!fcgi_param_get_eff_len(p, p+name_len, &eff_name_len)){
+ if (UNEXPECTED(memchr(p, 0, name_len) != NULL)) {
/* Malicious request */
- ret = 0;
- break;
- }
- if (eff_name_len >= buf_size-1) {
- if (eff_name_len > ((uint)-1)-64) {
- ret = 0;
- break;
- }
- buf_size = eff_name_len + 64;
- tmp = (tmp == buf ? emalloc(buf_size): erealloc(tmp, buf_size));
- if (tmp == NULL) {
- ret = 0;
- break;
- }
+ return 0;
}
- memcpy(tmp, p, eff_name_len);
- tmp[eff_name_len] = 0;
- s = estrndup((char*)p + name_len, val_len);
- zend_hash_str_update_ptr(req->env, tmp, eff_name_len, s);
+ fcgi_hash_set(&req->env, FCGI_HASH_FUNC(p, name_len), (char*)p, name_len, (char*)p + name_len, val_len);
p += name_len + val_len;
}
- if (tmp != buf && tmp != NULL) {
- efree(tmp);
- }
- return ret;
+ return 1;
}
static void fcgi_free_var(zval *zv)
req->in_len = 0;
req->out_hdr = NULL;
req->out_pos = req->out_buf;
- ALLOC_HASHTABLE(req->env);
- zend_hash_init(req->env, 0, NULL, fcgi_free_var, 0);
+ req->has_env = 1;
if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
hdr.version < FCGI_VERSION_1) {
req->id = (hdr.requestIdB1 << 8) + hdr.requestIdB0;
if (hdr.type == FCGI_BEGIN_REQUEST && len == sizeof(fcgi_begin_request)) {
- char *val;
-
if (safe_read(req, buf, len+padding) != len+padding) {
return 0;
}
req->keep = (((fcgi_begin_request*)buf)->flags & FCGI_KEEP_CONN);
+#ifdef TCP_NODELAY
+ if (req->keep && req->tcp && !req->nodelay) {
+# ifdef _WIN32
+ BOOL on = 1;
+# else
+ int on = 1;
+# endif
+
+ setsockopt(req->fd, IPPROTO_TCP, TCP_NODELAY, (char*)&on, sizeof(on));
+ req->nodelay = 1;
+ }
+#endif
switch ((((fcgi_begin_request*)buf)->roleB1 << 8) + ((fcgi_begin_request*)buf)->roleB0) {
case FCGI_RESPONDER:
- val = estrdup("RESPONDER");
- zend_hash_str_update_ptr(req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), val);
+ fcgi_hash_set(&req->env, FCGI_HASH_FUNC("FCGI_ROLE", sizeof("FCGI_ROLE")-1), "FCGI_ROLE", sizeof("FCGI_ROLE")-1, "RESPONDER", sizeof("RESPONDER")-1);
break;
case FCGI_AUTHORIZER:
- val = estrdup("AUTHORIZER");
- zend_hash_str_update_ptr(req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), val);
+ fcgi_hash_set(&req->env, FCGI_HASH_FUNC("FCGI_ROLE", sizeof("FCGI_ROLE")-1), "FCGI_ROLE", sizeof("FCGI_ROLE")-1, "AUTHORIZER", sizeof("AUTHORIZER")-1);
break;
case FCGI_FILTER:
- val = estrdup("FILTER");
- zend_hash_str_update_ptr(req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), val);
+ fcgi_hash_set(&req->env, FCGI_HASH_FUNC("FCGI_ROLE", sizeof("FCGI_ROLE")-1), "FCGI_ROLE", sizeof("FCGI_ROLE")-1, "FILTER", sizeof("FILTER")-1);
break;
default:
return 0;
}
} else if (hdr.type == FCGI_GET_VALUES) {
unsigned char *p = buf + sizeof(fcgi_header);
- zend_string *key;
zval *value;
+ unsigned int zlen;
+ fcgi_hash_bucket *q;
if (safe_read(req, buf, len+padding) != len+padding) {
req->keep = 0;
return 0;
}
- ZEND_HASH_FOREACH_STR_KEY(req->env, key) {
- int zlen;
- if (!key) {
- continue;
- }
- value = zend_hash_find(&fcgi_mgmt_vars, key);
- if (!value) {
+ q = req->env.list;
+ while (q != NULL) {
+ if ((value = zend_hash_str_find(&fcgi_mgmt_vars, q->var, q->var_len)) == NULL) {
+ q = q->list_next;
continue;
}
- zlen = Z_STRLEN_P(value);
- if ((p + 4 + 4 + key->len + zlen) >= (buf + sizeof(buf))) {
+ zlen = (unsigned int)Z_STRLEN_P(value);
+ if ((p + 4 + 4 + q->var_len + zlen) >= (buf + sizeof(buf))) {
break;
}
- if (key->len < 0x80) {
- *p++ = key->len;
+ if (q->var_len < 0x80) {
+ *p++ = q->var_len;
} else {
- *p++ = ((key->len >> 24) & 0xff) | 0x80;
- *p++ = (key->len >> 16) & 0xff;
- *p++ = (key->len >> 8) & 0xff;
- *p++ = key->len & 0xff;
+ *p++ = ((q->var_len >> 24) & 0xff) | 0x80;
+ *p++ = (q->var_len >> 16) & 0xff;
+ *p++ = (q->var_len >> 8) & 0xff;
+ *p++ = q->var_len & 0xff;
}
if (zlen < 0x80) {
*p++ = zlen;
*p++ = (zlen >> 8) & 0xff;
*p++ = zlen & 0xff;
}
- memcpy(p, key->val, key->len);
- p += key->len;
+ memcpy(p, q->var, q->var_len);
+ p += q->var_len;
memcpy(p, Z_STRVAL_P(value), zlen);
p += zlen;
- } ZEND_HASH_FOREACH_END();
+ q = q->list_next;
+ }
len = p - buf - sizeof(fcgi_header);
len += fcgi_make_header((fcgi_header*)buf, FCGI_GET_VALUES_RESULT, 0, len);
if (safe_write(req, buf, sizeof(fcgi_header)+len) != (int)sizeof(fcgi_header)+len) {
void fcgi_close(fcgi_request *req, int force, int destroy)
{
- if (destroy && req->env) {
- zend_hash_destroy(req->env);
- FREE_HASHTABLE(req->env);
- req->env = NULL;
+ if (destroy && req->has_env) {
+ fcgi_hash_clean(&req->env);
+ req->has_env = 0;
}
#ifdef _WIN32
while (recv(req->fd, buf, sizeof(buf), 0) > 0) {}
}
close(req->fd);
+#endif
+#ifdef TCP_NODELAY
+ req->nodelay = 0;
#endif
req->fd = -1;
fpm_request_finished();
}
}
+int fcgi_is_closed(fcgi_request *req)
+{
+ return (req->fd < 0);
+}
+
static int fcgi_is_allowed() {
int i;
char* fcgi_getenv(fcgi_request *req, const char* var, int var_len)
{
- if (!req) {
- return NULL;
- }
+ unsigned int val_len;
+
+ if (!req) return NULL;
+
+ return fcgi_hash_get(&req->env, FCGI_HASH_FUNC(var, var_len), (char*)var, var_len, &val_len);
+}
+
+char* fcgi_quick_getenv(fcgi_request *req, const char* var, int var_len, unsigned int hash_value)
+{
+ unsigned int val_len;
- return zend_hash_str_find_ptr(req->env, var, var_len);
+ return fcgi_hash_get(&req->env, hash_value, (char*)var, var_len, &val_len);
}
char* fcgi_putenv(fcgi_request *req, char* var, int var_len, char* val)
{
- if (var && req) {
- if (val == NULL) {
- zend_hash_str_del(req->env, var, var_len);
- } else {
- val = estrdup(val);
- zend_hash_str_update_ptr(req->env, var, var_len, val);
- return val;
- }
+ if (!req) return NULL;
+ if (val == NULL) {
+ fcgi_hash_del(&req->env, FCGI_HASH_FUNC(var, var_len), var, var_len);
+ return NULL;
+ } else {
+ return fcgi_hash_set(&req->env, FCGI_HASH_FUNC(var, var_len), var, var_len, val, (unsigned int)strlen(val));
}
- return NULL;
+}
+
+char* fcgi_quick_putenv(fcgi_request *req, char* var, int var_len, unsigned int hash_value, char* val)
+{
+ if (val == NULL) {
+ fcgi_hash_del(&req->env, hash_value, var, var_len);
+ return NULL;
+ } else {
+ return fcgi_hash_set(&req->env, hash_value, var, var_len, val, (unsigned int)strlen(val));
+ }
+}
+
+void fcgi_loadenv(fcgi_request *req, fcgi_apply_func func, zval *array)
+{
+ fcgi_hash_apply(&req->env, func, array);
}
void fcgi_set_mgmt_var(const char * name, size_t name_len, const char * value, size_t value_len)
#define FCGI_KEEP_CONN 1
+/* this is near the perfect hash function for most useful FastCGI variables
+ * which combines efficiency and minimal hash collisions
+ */
+
+#define FCGI_HASH_FUNC(var, var_len) \
+ (UNEXPECTED(var_len < 3) ? var_len : \
+ (((unsigned int)var[3]) << 2) + \
+ (((unsigned int)var[var_len-2]) << 4) + \
+ (((unsigned int)var[var_len-1]) << 2) + \
+ var_len)
+
+#define FCGI_GETENV(request, name) \
+ fcgi_quick_getenv(request, name, sizeof(name)-1, FCGI_HASH_FUNC(name, sizeof(name)-1))
+
+#define FCGI_PUTENV(request, name, value) \
+ fcgi_quick_putenv(request, name, sizeof(name)-1, FCGI_HASH_FUNC(name, sizeof(name)-1), value)
+
typedef enum _fcgi_role {
FCGI_RESPONDER = 1,
FCGI_AUTHORIZER = 2,
/* FastCGI client API */
-typedef struct _fcgi_request {
- int listen_socket;
-#ifdef _WIN32
- int tcp;
-#endif
- int fd;
- int id;
- int keep;
- int closed;
-
- int in_len;
- int in_pad;
-
- fcgi_header *out_hdr;
- unsigned char *out_pos;
- unsigned char out_buf[1024*8];
- unsigned char reserved[sizeof(fcgi_end_request_rec)];
+typedef void (*fcgi_apply_func)(char *var, unsigned int var_len, char *val, unsigned int val_len, void *arg);
- HashTable *env;
-} fcgi_request;
+typedef struct _fcgi_request fcgi_request;
int fcgi_init(void);
void fcgi_shutdown(void);
-void fcgi_init_request(fcgi_request *req, int listen_socket);
+int fcgi_in_shutdown(void);
+void fcgi_terminate(void);
+fcgi_request* fcgi_init_request(int listen_socket);
+void fcgi_destroy_request(fcgi_request *req);
int fcgi_accept_request(fcgi_request *req);
int fcgi_finish_request(fcgi_request *req, int force_close);
-void fcgi_set_in_shutdown(int);
void fcgi_set_allowed_clients(char *);
void fcgi_close(fcgi_request *req, int force, int destroy);
+int fcgi_is_closed(fcgi_request *req);
char* fcgi_getenv(fcgi_request *req, const char* var, int var_len);
char* fcgi_putenv(fcgi_request *req, char* var, int var_len, char* val);
+char* fcgi_quick_getenv(fcgi_request *req, const char* var, int var_len, unsigned int hash_value);
+char* fcgi_quick_putenv(fcgi_request *req, char* var, int var_len, unsigned int hash_value, char* val);
+void fcgi_loadenv(fcgi_request *req, fcgi_apply_func load_func, zval *array);
int fcgi_read(fcgi_request *req, char *str, int len);
while (read_bytes < count_bytes) {
fcgi_request *request = (fcgi_request*) SG(server_context);
if (request_body_fd == -1) {
- char *request_body_filename = sapi_cgibin_getenv((char *) "REQUEST_BODY_FILE",
- sizeof("REQUEST_BODY_FILE") - 1);
+ char *request_body_filename = FCGI_GETENV(request, "REQUEST_BODY_FILE");
if (request_body_filename && *request_body_filename) {
request_body_fd = open(request_body_filename, O_RDONLY);
static char *sapi_cgi_read_cookies(void)
{
- return sapi_cgibin_getenv((char *) "HTTP_COOKIE", sizeof("HTTP_COOKIE") - 1);
+ fcgi_request *request = (fcgi_request*) SG(server_context);
+
+ return FCGI_GETENV(request, "HTTP_COOKIE");
+}
+
+static void cgi_php_load_env_var(char *var, unsigned int var_len, char *val, unsigned int val_len, void *arg)
+{
+ zval *array_ptr = (zval*)arg;
+ int filter_arg = (Z_ARR_P(array_ptr) == Z_ARR(PG(http_globals)[TRACK_VARS_ENV]))?PARSE_ENV:PARSE_SERVER;
+ size_t new_val_len;
+
+ if (sapi_module.input_filter(filter_arg, var, &val, strlen(val), &new_val_len)) {
+ php_register_variable_safe(var, val, new_val_len, array_ptr);
+ }
}
void cgi_php_import_environment_variables(zval *array_ptr)
php_php_import_environment_variables(array_ptr);
request = (fcgi_request*) SG(server_context);
- filter_arg = Z_ARR_P(array_ptr) == Z_ARR(PG(http_globals)[TRACK_VARS_ENV])
- ? PARSE_ENV : PARSE_SERVER;
-
- ZEND_HASH_FOREACH_STR_KEY_PTR(request->env, var, val) {
- size_t new_val_len;
-
- if (var && sapi_module.input_filter(filter_arg, var->val, &val, strlen(val), &new_val_len)) {
- php_register_variable_safe(var->val, val, new_val_len, array_ptr);
- }
- } ZEND_HASH_FOREACH_END();
+ fcgi_loadenv(request, cgi_php_load_env_var, array_ptr);
}
static void sapi_cgi_register_variables(zval *track_vars_array)
{
+ fcgi_request *request = (fcgi_request*) SG(server_context);
size_t php_self_len;
char *php_self;
if (CGIG(fix_pathinfo)) {
char *script_name = SG(request_info).request_uri;
unsigned int script_name_len = script_name ? strlen(script_name) : 0;
- char *path_info = sapi_cgibin_getenv("PATH_INFO", sizeof("PATH_INFO") - 1);
+ char *path_info = FCGI_GETENV(request, "PATH_INFO");
unsigned int path_info_len = path_info ? strlen(path_info) : 0;
php_self_len = script_name_len + path_info_len;
static int sapi_cgi_activate(void)
{
+ fcgi_request *request = (fcgi_request*) SG(server_context);
char *path, *doc_root, *server_name;
uint path_len, doc_root_len, server_name_len;
if (php_ini_has_per_host_config()) {
/* Activate per-host-system-configuration defined in php.ini and stored into configuration_hash during startup */
- server_name = sapi_cgibin_getenv("SERVER_NAME", sizeof("SERVER_NAME") - 1);
+ server_name = FCGI_GETENV(request, "SERVER_NAME");
/* SERVER_NAME should also be defined at this stage..but better check it anyway */
if (server_name) {
server_name_len = strlen(server_name);
/* Load and activate user ini files in path starting from DOCUMENT_ROOT */
if (PG(user_ini_filename) && *PG(user_ini_filename)) {
- doc_root = sapi_cgibin_getenv("DOCUMENT_ROOT", sizeof("DOCUMENT_ROOT") - 1);
+ doc_root = FCGI_GETENV(request, "DOCUMENT_ROOT");
/* DOCUMENT_ROOT should also be defined at this stage..but better check it anyway */
if (doc_root) {
doc_root_len = strlen(doc_root);
*/
static void init_request_info(void)
{
- char *env_script_filename = sapi_cgibin_getenv("SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME") - 1);
- char *env_path_translated = sapi_cgibin_getenv("PATH_TRANSLATED", sizeof("PATH_TRANSLATED") - 1);
+ fcgi_request *request = (fcgi_request*) SG(server_context);
+ char *env_script_filename = FCGI_GETENV(request, "SCRIPT_FILENAME");
+ char *env_path_translated = FCGI_GETENV(request, "PATH_TRANSLATED");
char *script_path_translated = env_script_filename;
char *ini;
int apache_was_here = 0;
* of the script will be retreived later via argc/argv */
if (script_path_translated) {
const char *auth;
- char *content_length = sapi_cgibin_getenv("CONTENT_LENGTH", sizeof("CONTENT_LENGTH") - 1);
- char *content_type = sapi_cgibin_getenv("CONTENT_TYPE", sizeof("CONTENT_TYPE") - 1);
- char *env_path_info = sapi_cgibin_getenv("PATH_INFO", sizeof("PATH_INFO") - 1);
- char *env_script_name = sapi_cgibin_getenv("SCRIPT_NAME", sizeof("SCRIPT_NAME") - 1);
+ char *content_length = FCGI_GETENV(request, "CONTENT_LENGTH");
+ char *content_type = FCGI_GETENV(request, "CONTENT_TYPE");
+ char *env_path_info = FCGI_GETENV(request, "PATH_INFO");
+ char *env_script_name = FCGI_GETENV(request, "SCRIPT_NAME");
/* Hack for buggy IIS that sets incorrect PATH_INFO */
- char *env_server_software = sapi_cgibin_getenv("SERVER_SOFTWARE", sizeof("SERVER_SOFTWARE") - 1);
+ char *env_server_software = FCGI_GETENV(request, "SERVER_SOFTWARE");
if (env_server_software &&
env_script_name &&
env_path_info &&
strncmp(env_server_software, "Microsoft-IIS", sizeof("Microsoft-IIS") - 1) == 0 &&
strncmp(env_path_info, env_script_name, strlen(env_script_name)) == 0
) {
- env_path_info = _sapi_cgibin_putenv("ORIG_PATH_INFO", env_path_info);
+ env_path_info = FCGI_PUTENV(request, "ORIG_PATH_INFO", env_path_info);
env_path_info += strlen(env_script_name);
if (*env_path_info == 0) {
env_path_info = NULL;
}
- env_path_info = _sapi_cgibin_putenv("PATH_INFO", env_path_info);
+ env_path_info = FCGI_PUTENV(request, "PATH_INFO", env_path_info);
}
#define APACHE_PROXY_FCGI_PREFIX "proxy:fcgi://"
if (CGIG(fix_pathinfo)) {
struct stat st;
char *real_path = NULL;
- char *env_redirect_url = sapi_cgibin_getenv("REDIRECT_URL", sizeof("REDIRECT_URL") - 1);
- char *env_document_root = sapi_cgibin_getenv("DOCUMENT_ROOT", sizeof("DOCUMENT_ROOT") - 1);
+ char *env_redirect_url = FCGI_GETENV(request, "REDIRECT_URL");
+ char *env_document_root = FCGI_GETENV(request, "DOCUMENT_ROOT");
char *orig_path_translated = env_path_translated;
char *orig_path_info = env_path_info;
char *orig_script_name = env_script_name;
int script_path_translated_len;
if (!env_document_root && PG(doc_root)) {
- env_document_root = _sapi_cgibin_putenv("DOCUMENT_ROOT", PG(doc_root));
+ env_document_root = FCGI_PUTENV(request, "DOCUMENT_ROOT", PG(doc_root));
/* fix docroot */
TRANSLATE_SLASHES(env_document_root);
}
if (orig_path_info) {
char old;
- _sapi_cgibin_putenv("ORIG_PATH_INFO", orig_path_info);
+ FCGI_PUTENV(request, "ORIG_PATH_INFO", orig_path_info);
old = path_info[0];
path_info[0] = 0;
if (!orig_script_name ||
strcmp(orig_script_name, env_path_info) != 0) {
if (orig_script_name) {
- _sapi_cgibin_putenv("ORIG_SCRIPT_NAME", orig_script_name);
+ FCGI_PUTENV(request, "ORIG_SCRIPT_NAME", orig_script_name);
}
- SG(request_info).request_uri = _sapi_cgibin_putenv("SCRIPT_NAME", env_path_info);
+ SG(request_info).request_uri = FCGI_PUTENV(request, "SCRIPT_NAME", env_path_info);
} else {
SG(request_info).request_uri = orig_script_name;
}
*/
int snlen = strlen(env_script_name);
if (snlen>slen && !strcmp(env_script_name+snlen-slen, path_info)) {
- _sapi_cgibin_putenv("ORIG_SCRIPT_NAME", orig_script_name);
+ FCGI_PUTENV(request, "ORIG_SCRIPT_NAME", orig_script_name);
env_script_name[snlen-slen] = 0;
- SG(request_info).request_uri = _sapi_cgibin_putenv("SCRIPT_NAME", env_script_name);
+ SG(request_info).request_uri = FCGI_PUTENV(request, "SCRIPT_NAME", env_script_name);
}
}
- env_path_info = _sapi_cgibin_putenv("PATH_INFO", path_info);
+ env_path_info = FCGI_PUTENV(request, "PATH_INFO", path_info);
}
if (!orig_script_filename ||
strcmp(orig_script_filename, pt) != 0) {
if (orig_script_filename) {
- _sapi_cgibin_putenv("ORIG_SCRIPT_FILENAME", orig_script_filename);
+ FCGI_PUTENV(request, "ORIG_SCRIPT_FILENAME", orig_script_filename);
}
- script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", pt);
+ script_path_translated = FCGI_PUTENV(request, "SCRIPT_FILENAME", pt);
}
TRANSLATE_SLASHES(pt);
}
path_translated[path_translated_len] = '\0';
if (orig_path_translated) {
- _sapi_cgibin_putenv("ORIG_PATH_TRANSLATED", orig_path_translated);
+ FCGI_PUTENV(request, "ORIG_PATH_TRANSLATED", orig_path_translated);
}
- env_path_translated = _sapi_cgibin_putenv("PATH_TRANSLATED", path_translated);
+ env_path_translated = FCGI_PUTENV(request, "PATH_TRANSLATED", path_translated);
efree(path_translated);
} else if ( env_script_name &&
strstr(pt, env_script_name)
}
path_translated[path_translated_len] = '\0';
if (orig_path_translated) {
- _sapi_cgibin_putenv("ORIG_PATH_TRANSLATED", orig_path_translated);
+ FCGI_PUTENV(request, "ORIG_PATH_TRANSLATED", orig_path_translated);
}
- env_path_translated = _sapi_cgibin_putenv("PATH_TRANSLATED", path_translated);
+ env_path_translated = FCGI_PUTENV(request, "PATH_TRANSLATED", path_translated);
efree(path_translated);
}
break;
* have failed anyway... we output 'no input file' now.
*/
if (orig_script_filename) {
- _sapi_cgibin_putenv("ORIG_SCRIPT_FILENAME", orig_script_filename);
+ FCGI_PUTENV(request, "ORIG_SCRIPT_FILENAME", orig_script_filename);
}
- script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", NULL);
+ script_path_translated = FCGI_PUTENV(request, "SCRIPT_FILENAME", NULL);
SG(sapi_headers).http_response_code = 404;
}
if (!SG(request_info).request_uri) {
if (!orig_script_name ||
strcmp(orig_script_name, env_script_name) != 0) {
if (orig_script_name) {
- _sapi_cgibin_putenv("ORIG_SCRIPT_NAME", orig_script_name);
+ FCGI_PUTENV(request, "ORIG_SCRIPT_NAME", orig_script_name);
}
- SG(request_info).request_uri = _sapi_cgibin_putenv("SCRIPT_NAME", env_script_name);
+ SG(request_info).request_uri = FCGI_PUTENV(request, "SCRIPT_NAME", env_script_name);
} else {
SG(request_info).request_uri = orig_script_name;
}
(script_path_translated != orig_script_filename &&
strcmp(script_path_translated, orig_script_filename) != 0)) {
if (orig_script_filename) {
- _sapi_cgibin_putenv("ORIG_SCRIPT_FILENAME", orig_script_filename);
+ FCGI_PUTENV(request, "ORIG_SCRIPT_FILENAME", orig_script_filename);
}
- script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", script_path_translated);
+ script_path_translated = FCGI_PUTENV(request, "SCRIPT_FILENAME", script_path_translated);
}
if (!apache_was_here && env_redirect_url) {
/* if we used PATH_TRANSLATED to work around Apache mod_fastcgi (but not mod_proxy_fcgi,
* hence !apache_was_here) weirdness, strip info accordingly */
if (orig_path_info) {
- _sapi_cgibin_putenv("ORIG_PATH_INFO", orig_path_info);
- _sapi_cgibin_putenv("PATH_INFO", NULL);
+ FCGI_PUTENV(request, "ORIG_PATH_INFO", orig_path_info);
+ FCGI_PUTENV(request, "PATH_INFO", NULL);
}
if (orig_path_translated) {
- _sapi_cgibin_putenv("ORIG_PATH_TRANSLATED", orig_path_translated);
- _sapi_cgibin_putenv("PATH_TRANSLATED", NULL);
+ FCGI_PUTENV(request, "ORIG_PATH_TRANSLATED", orig_path_translated);
+ FCGI_PUTENV(request, "PATH_TRANSLATED", NULL);
}
}
if (env_script_name != orig_script_name) {
if (orig_script_name) {
- _sapi_cgibin_putenv("ORIG_SCRIPT_NAME", orig_script_name);
+ FCGI_PUTENV(request, "ORIG_SCRIPT_NAME", orig_script_name);
}
- SG(request_info).request_uri = _sapi_cgibin_putenv("SCRIPT_NAME", env_script_name);
+ SG(request_info).request_uri = FCGI_PUTENV(request, "SCRIPT_NAME", env_script_name);
} else {
SG(request_info).request_uri = env_script_name;
}
SG(request_info).path_translated = estrdup(script_path_translated);
}
- SG(request_info).request_method = sapi_cgibin_getenv("REQUEST_METHOD", sizeof("REQUEST_METHOD") - 1);
+ SG(request_info).request_method = FCGI_GETENV(request, "REQUEST_METHOD");
/* FIXME - Work out proto_num here */
- SG(request_info).query_string = sapi_cgibin_getenv("QUERY_STRING", sizeof("QUERY_STRING") - 1);
+ SG(request_info).query_string = FCGI_GETENV(request, "QUERY_STRING");
SG(request_info).content_type = (content_type ? content_type : "" );
SG(request_info).content_length = (content_length ? atol(content_length) : 0);
/* The CGI RFC allows servers to pass on unvalidated Authorization data */
- auth = sapi_cgibin_getenv("HTTP_AUTHORIZATION", sizeof("HTTP_AUTHORIZATION") - 1);
+ auth = FCGI_GETENV(request, "HTTP_AUTHORIZATION");
php_handle_auth_data(auth);
}
/* INI stuff */
- ini = sapi_cgibin_getenv("PHP_VALUE", sizeof("PHP_VALUE") - 1);
+ ini = FCGI_GETENV(request, "PHP_VALUE");
if (ini) {
int mode = ZEND_INI_USER;
char *tmp;
efree(tmp);
}
- ini = sapi_cgibin_getenv("PHP_ADMIN_VALUE", sizeof("PHP_ADMIN_VALUE") - 1);
+ ini = FCGI_GETENV(request, "PHP_ADMIN_VALUE");
if (ini) {
int mode = ZEND_INI_SYSTEM;
char *tmp;
{
fcgi_request *request = (fcgi_request*) SG(server_context);
- if (request->fd >= 0) {
+ if (!fcgi_is_closed(request)) {
php_output_end_all();
php_header();
int max_requests = 500;
int requests = 0;
int fcgi_fd = 0;
- fcgi_request request;
+ fcgi_request *request;
char *fpm_config = NULL;
char *fpm_prefix = NULL;
char *fpm_pid = NULL;
php_import_environment_variables = cgi_php_import_environment_variables;
/* library is already initialized, now init our request */
- fcgi_init_request(&request, fcgi_fd);
+ request = fcgi_init_request(fcgi_fd);
zend_first_try {
- while (fcgi_accept_request(&request) >= 0) {
+ while (fcgi_accept_request(request) >= 0) {
request_body_fd = -1;
- SG(server_context) = (void *) &request;
+ SG(server_context) = (void *) request;
init_request_info();
char *primary_script = NULL;
/* request startup only after we've done all we can to
* get path_translated */
if (php_request_startup() == FAILURE) {
- fcgi_finish_request(&request, 1);
+ fcgi_finish_request(request, 1);
SG(server_context) = NULL;
php_module_shutdown();
return FPM_EXIT_SOFTWARE;
requests++;
if (max_requests && (requests == max_requests)) {
- fcgi_finish_request(&request, 1);
+ fcgi_finish_request(request, 1);
break;
}
/* end of fastcgi loop */
}
+ fcgi_destroy_request(request);
fcgi_shutdown();
if (cgi_sapi_module.php_ini_path_override) {
void fpm_php_soft_quit() /* {{{ */
{
- fcgi_set_in_shutdown(1);
+ fcgi_terminate();
}
/* }}} */