From abb616ae2042e5769cf4fc5e9ab12bc4d6938a58 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Wed, 13 May 2015 18:54:41 +0300 Subject: [PATCH] Merged fastcgi.* reated changes from sapi/cgi --- sapi/fpm/fpm/fastcgi.c | 490 ++++++++++++++++++++++++++++------------ sapi/fpm/fpm/fastcgi.h | 48 ++-- sapi/fpm/fpm/fpm_main.c | 135 +++++------ sapi/fpm/fpm/fpm_php.c | 2 +- 4 files changed, 445 insertions(+), 230 deletions(-) diff --git a/sapi/fpm/fpm/fastcgi.c b/sapi/fpm/fpm/fastcgi.c index 0e3ec18023..71eaa78cd4 100644 --- a/sapi/fpm/fpm/fastcgi.c +++ b/sapi/fpm/fpm/fastcgi.c @@ -146,6 +146,226 @@ static sa_t *allowed_clients = NULL; 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) @@ -181,10 +401,20 @@ static void fcgi_setup_signals(void) } #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; @@ -285,9 +515,9 @@ void fcgi_set_allowed_clients(char *ip) } } -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; @@ -301,6 +531,20 @@ void fcgi_init_request(fcgi_request *req, int listen_socket) #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) @@ -379,120 +623,47 @@ static inline int fcgi_make_header(fcgi_header *hdr, fcgi_request_type type, int 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) @@ -511,8 +682,7 @@ static int fcgi_read_request(fcgi_request *req) 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) { @@ -539,25 +709,32 @@ static int fcgi_read_request(fcgi_request *req) 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; @@ -596,8 +773,9 @@ static int fcgi_read_request(fcgi_request *req) } } 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; @@ -609,26 +787,23 @@ static int fcgi_read_request(fcgi_request *req) 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; @@ -638,11 +813,12 @@ static int fcgi_read_request(fcgi_request *req) *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) { @@ -712,10 +888,9 @@ int fcgi_read(fcgi_request *req, char *str, int 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 @@ -750,12 +925,20 @@ void fcgi_close(fcgi_request *req, int force, int destroy) 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; @@ -1072,25 +1255,44 @@ int fcgi_finish_request(fcgi_request *req, int force_close) 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) diff --git a/sapi/fpm/fpm/fastcgi.h b/sapi/fpm/fpm/fastcgi.h index fb7385afcc..31419dfdd0 100644 --- a/sapi/fpm/fpm/fastcgi.h +++ b/sapi/fpm/fpm/fastcgi.h @@ -26,6 +26,23 @@ #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, @@ -91,39 +108,28 @@ typedef struct _fcgi_end_request_rec { /* 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); diff --git a/sapi/fpm/fpm/fpm_main.c b/sapi/fpm/fpm/fpm_main.c index ecfc9be024..efd1f7155a 100644 --- a/sapi/fpm/fpm/fpm_main.c +++ b/sapi/fpm/fpm/fpm_main.c @@ -460,8 +460,7 @@ static size_t sapi_cgi_read_post(char *buffer, size_t count_bytes) 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); @@ -515,7 +514,20 @@ static char *_sapi_cgibin_putenv(char *name, char *value) 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) @@ -545,20 +557,12 @@ 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; @@ -570,7 +574,7 @@ static void sapi_cgi_register_variables(zval *track_vars_array) 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; @@ -711,6 +715,7 @@ static void php_cgi_ini_activate_user_config(char *path, int path_len, const cha 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; @@ -721,7 +726,7 @@ static int sapi_cgi_activate(void) 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); @@ -755,7 +760,7 @@ static int sapi_cgi_activate(void) /* 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); @@ -984,8 +989,9 @@ static int is_valid_path(const char *path) */ 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; @@ -1013,25 +1019,25 @@ static void init_request_info(void) * 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://" @@ -1066,8 +1072,8 @@ static void init_request_info(void) 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; @@ -1075,7 +1081,7 @@ static void init_request_info(void) 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); } @@ -1156,15 +1162,15 @@ static void init_request_info(void) 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; } @@ -1176,19 +1182,19 @@ static void init_request_info(void) */ 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); @@ -1218,9 +1224,9 @@ static void init_request_info(void) } 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) @@ -1237,9 +1243,9 @@ static void init_request_info(void) } 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; @@ -1255,18 +1261,18 @@ static void init_request_info(void) * 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; } @@ -1280,27 +1286,27 @@ static void init_request_info(void) (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; } @@ -1322,19 +1328,19 @@ static void init_request_info(void) 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; @@ -1343,7 +1349,7 @@ static void init_request_info(void) 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; @@ -1463,7 +1469,7 @@ PHP_FUNCTION(fastcgi_finish_request) /* {{{ */ { fcgi_request *request = (fcgi_request*) SG(server_context); - if (request->fd >= 0) { + if (!fcgi_is_closed(request)) { php_output_end_all(); php_header(); @@ -1517,7 +1523,7 @@ int main(int argc, char *argv[]) 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; @@ -1813,12 +1819,12 @@ consult the installation file that came with this distribution, or visit \n\ 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; @@ -1827,7 +1833,7 @@ consult the installation file that came with this distribution, or visit \n\ /* 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; @@ -1920,11 +1926,12 @@ fastcgi_request_done: 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) { diff --git a/sapi/fpm/fpm/fpm_php.c b/sapi/fpm/fpm/fpm_php.c index 7e703889b2..9ddc45e5b9 100644 --- a/sapi/fpm/fpm/fpm_php.c +++ b/sapi/fpm/fpm/fpm_php.c @@ -201,7 +201,7 @@ static void fpm_php_cleanup(int which, void *arg) /* {{{ */ void fpm_php_soft_quit() /* {{{ */ { - fcgi_set_in_shutdown(1); + fcgi_terminate(); } /* }}} */ -- 2.40.0