Patch bug60891-v1.patch for FPM related Bug #60891
Patch version 2012-05-28 23:08 UTC
Return to Bug #60891 |
Download this patch
Patch Revisions:
Developer: fat@php.net
diff --git a/sapi/fpm/fpm/fpm.c b/sapi/fpm/fpm/fpm.c
index dab415d..34e8f78 100644
--- a/sapi/fpm/fpm/fpm.c
+++ b/sapi/fpm/fpm/fpm.c
@@ -19,6 +19,7 @@
#include "fpm_conf.h"
#include "fpm_worker_pool.h"
#include "fpm_scoreboard.h"
+#include "fpm_status.h"
#include "fpm_stdio.h"
#include "fpm_log.h"
#include "zlog.h"
@@ -40,6 +41,7 @@ struct fpm_globals_s fpm_globals = {
.heartbeat = 0,
.run_as_root = 0,
.send_config_signal = 0,
+ .scoreboards = NULL,
};
int fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int test_conf, int run_as_root) /* {{{ */
@@ -57,6 +59,7 @@ int fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int t
0 > fpm_stdio_init_main() ||
0 > fpm_conf_init_main(test_conf) ||
0 > fpm_unix_init_main() ||
+ 0 > fpm_status_init_main() ||
0 > fpm_scoreboard_init_main() ||
0 > fpm_pctl_init_main() ||
0 > fpm_env_init_main() ||
diff --git a/sapi/fpm/fpm/fpm.h b/sapi/fpm/fpm/fpm.h
index 7a2903d..e735254 100644
--- a/sapi/fpm/fpm/fpm.h
+++ b/sapi/fpm/fpm/fpm.h
@@ -56,6 +56,7 @@ struct fpm_globals_s {
int heartbeat;
int run_as_root;
int send_config_signal;
+ struct fpm_scoreboard_list_s *scoreboards;
};
extern struct fpm_globals_s fpm_globals;
diff --git a/sapi/fpm/fpm/fpm_children.c b/sapi/fpm/fpm/fpm_children.c
index 84a9474..67ba6b8 100644
--- a/sapi/fpm/fpm/fpm_children.c
+++ b/sapi/fpm/fpm/fpm_children.c
@@ -338,13 +338,14 @@ static void fpm_resources_discard(struct fpm_child_s *child) /* {{{ */
static void fpm_child_resources_use(struct fpm_child_s *child) /* {{{ */
{
struct fpm_worker_pool_s *wp;
+/*
for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
if (wp == child->wp) {
continue;
}
fpm_scoreboard_free(wp->scoreboard);
}
-
+*/
fpm_scoreboard_child_use(child->wp->scoreboard, child->scoreboard_i, getpid());
fpm_stdio_child_use_pipes(child);
fpm_child_free(child);
diff --git a/sapi/fpm/fpm/fpm_conf.c b/sapi/fpm/fpm/fpm_conf.c
index 1f3258f..def6aca 100644
--- a/sapi/fpm/fpm/fpm_conf.c
+++ b/sapi/fpm/fpm/fpm_conf.c
@@ -123,6 +123,7 @@ static struct ini_value_parser_s ini_fpm_pool_options[] = {
{ "pm.process_idle_timeout", &fpm_conf_set_time, WPO(pm_process_idle_timeout) },
{ "pm.max_requests", &fpm_conf_set_integer, WPO(pm_max_requests) },
{ "pm.status_path", &fpm_conf_set_string, WPO(pm_status_path) },
+ { "pm.status_allow", &fpm_conf_set_string, WPO(pm_status_allow) },
{ "ping.path", &fpm_conf_set_string, WPO(ping_path) },
{ "ping.response", &fpm_conf_set_string, WPO(ping_response) },
{ "access.log", &fpm_conf_set_string, WPO(access_log) },
@@ -614,6 +615,7 @@ int fpm_worker_pool_config_free(struct fpm_worker_pool_config_s *wpc) /* {{{ */
free(wpc->listen_mode);
free(wpc->listen_allowed_clients);
free(wpc->pm_status_path);
+ free(wpc->pm_status_allow);
free(wpc->ping_path);
free(wpc->ping_response);
free(wpc->access_log);
@@ -840,6 +842,10 @@ static int fpm_conf_process_all_pools() /* {{{ */
return -1;
}
}
+
+ /* status allow */
+ if (wp->config->pm_status_allow && *wp->config->pm_status_allow) {
+ }
}
/* ping */
@@ -1550,6 +1556,7 @@ static void fpm_conf_dump() /* {{{ */
zlog(ZLOG_NOTICE, "\tpm.process_idle_timeout = %d", wp->config->pm_process_idle_timeout);
zlog(ZLOG_NOTICE, "\tpm.max_requests = %d", wp->config->pm_max_requests);
zlog(ZLOG_NOTICE, "\tpm.status_path = %s", STR2STR(wp->config->pm_status_path));
+ zlog(ZLOG_NOTICE, "\tpm.status_allow = %s", STR2STR(wp->config->pm_status_allow));
zlog(ZLOG_NOTICE, "\tping.path = %s", STR2STR(wp->config->ping_path));
zlog(ZLOG_NOTICE, "\tping.response = %s", STR2STR(wp->config->ping_response));
zlog(ZLOG_NOTICE, "\taccess.log = %s", STR2STR(wp->config->access_log));
diff --git a/sapi/fpm/fpm/fpm_conf.h b/sapi/fpm/fpm/fpm_conf.h
index f780f03..9423c5e 100644
--- a/sapi/fpm/fpm/fpm_conf.h
+++ b/sapi/fpm/fpm/fpm_conf.h
@@ -67,6 +67,7 @@ struct fpm_worker_pool_config_s {
int pm_process_idle_timeout;
int pm_max_requests;
char *pm_status_path;
+ char *pm_status_allow;
char *ping_path;
char *ping_response;
char *access_log;
diff --git a/sapi/fpm/fpm/fpm_log.c b/sapi/fpm/fpm/fpm_log.c
index 69bd31b..93d0762 100644
--- a/sapi/fpm/fpm/fpm_log.c
+++ b/sapi/fpm/fpm/fpm_log.c
@@ -122,7 +122,7 @@ int fpm_log_write(char *log_format TSRMLS_DC) /* {{{ */
now_epoch = time(NULL);
if (!test) {
- scoreboard = fpm_scoreboard_get();
+ scoreboard = fpm_scoreboard_get(NULL);
if (!scoreboard) {
zlog(ZLOG_WARNING, "unable to get scoreboard while preparing the access log");
return -1;
diff --git a/sapi/fpm/fpm/fpm_php.c b/sapi/fpm/fpm/fpm_php.c
index 840eec7..a886aa4 100644
--- a/sapi/fpm/fpm/fpm_php.c
+++ b/sapi/fpm/fpm/fpm_php.c
@@ -257,3 +257,40 @@ int fpm_php_limit_extensions(char *path) /* {{{ */
return 1; /* extension not found: not allowed */
}
/* }}} */
+
+char* fpm_php_get_string_from_table(char *table, char *key TSRMLS_DC) /* {{{ */
+{
+ zval **data, **tmp;
+ char *string_key;
+ uint string_len;
+ ulong num_key;
+ if (!table || !key) {
+ return NULL;
+ }
+
+ /* inspired from ext/standard/info.c */
+
+ zend_is_auto_global(table, strlen(table) TSRMLS_CC);
+
+ /* find the table and ensure it's an array */
+ if (zend_hash_find(&EG(symbol_table), table, strlen(table) + 1, (void **) &data) == SUCCESS && Z_TYPE_PP(data) == IS_ARRAY) {
+
+ /* reset the internal pointer */
+ zend_hash_internal_pointer_reset(Z_ARRVAL_PP(data));
+
+ /* parse the array to look for our key */
+ while (zend_hash_get_current_data(Z_ARRVAL_PP(data), (void **) &tmp) == SUCCESS) {
+ /* ensure the key is a string */
+ if (zend_hash_get_current_key_ex(Z_ARRVAL_PP(data), &string_key, &string_len, &num_key, 0, NULL) == HASH_KEY_IS_STRING) {
+ /* compare to our key */
+ if (!strncmp(string_key, key, string_len)) {
+ return Z_STRVAL_PP(tmp);
+ }
+ }
+ zend_hash_move_forward(Z_ARRVAL_PP(data));
+ }
+ }
+
+ return NULL;
+}
+/* }}} */
diff --git a/sapi/fpm/fpm/fpm_php.h b/sapi/fpm/fpm/fpm_php.h
index a2c7ed3..d605473 100644
--- a/sapi/fpm/fpm/fpm_php.h
+++ b/sapi/fpm/fpm/fpm_php.h
@@ -44,6 +44,7 @@ void fpm_php_soft_quit();
int fpm_php_init_main();
int fpm_php_apply_defines_ex(struct key_value_s *kv, int mode);
int fpm_php_limit_extensions(char *path);
+char* fpm_php_get_string_from_table(char *table, char *key TSRMLS_DC);
#endif
diff --git a/sapi/fpm/fpm/fpm_scoreboard.c b/sapi/fpm/fpm/fpm_scoreboard.c
index 4222f60..d44dc9b 100644
--- a/sapi/fpm/fpm/fpm_scoreboard.c
+++ b/sapi/fpm/fpm/fpm_scoreboard.c
@@ -7,6 +7,7 @@
#include <stdio.h>
#include <time.h>
+#include "fpm.h"
#include "fpm_config.h"
#include "fpm_scoreboard.h"
#include "fpm_shm.h"
@@ -26,6 +27,7 @@ int fpm_scoreboard_init_main() /* {{{ */
{
struct fpm_worker_pool_s *wp;
int i;
+ struct fpm_scoreboard_list_s *sb1, *sb2;
#ifdef HAVE_TIMES
#if (defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK))
@@ -68,6 +70,29 @@ int fpm_scoreboard_init_main() /* {{{ */
wp->scoreboard->pm = wp->config->pm;
wp->scoreboard->start_epoch = time(NULL);
strlcpy(wp->scoreboard->pool, wp->config->name, sizeof(wp->scoreboard->pool));
+
+ /* add the scoreboard to the global SHM list */
+ sb1 = malloc(sizeof(struct fpm_scoreboard_list_s));
+ if (!sb1) {
+ zlog(ZLOG_SYSERROR, "[pool %s] Unable to malloc scoreboard list", wp->config->name);
+ return -1;
+ }
+ /* save the SHM addr */
+ sb1->scoreboard = wp->scoreboard;
+ /* mark the end of the list */
+ sb1->next = NULL;
+
+ /* find the last element, and add this scoreboard at the end */
+ if (!fpm_globals.scoreboards) {
+ fpm_globals.scoreboards = sb1;
+ } else {
+ sb2 = fpm_globals.scoreboards;
+ while (sb2->next) {
+ sb2 = sb2->next;
+ }
+ sb2->next = sb1;
+ }
+ zlog(ZLOG_DEBUG, "Adding pool %s to scoreboards", sb1->scoreboard->pool);
}
return 0;
}
@@ -144,9 +169,25 @@ void fpm_scoreboard_update(int idle, int active, int lq, int lq_len, int request
}
/* }}} */
-struct fpm_scoreboard_s *fpm_scoreboard_get() /* {{{*/
+struct fpm_scoreboard_s *fpm_scoreboard_get(char *pool TSRMLS_DC) /* {{{*/
{
- return fpm_scoreboard;
+ struct fpm_scoreboard_list_s *sb;
+ if (!pool) {
+ return fpm_scoreboard;
+ }
+
+ for (sb=fpm_globals.scoreboards; sb; sb=sb->next) {
+ if (!sb || !sb->scoreboard || !sb->scoreboard->pool) {
+ continue;
+ }
+
+ if (strcmp(pool, sb->scoreboard->pool) == 0) {
+ return sb->scoreboard;
+ }
+ }
+
+ zlog(ZLOG_WARNING, "Unable to find scoreboard for pool %s", pool);
+ return NULL;
}
/* }}} */
diff --git a/sapi/fpm/fpm/fpm_scoreboard.h b/sapi/fpm/fpm/fpm_scoreboard.h
index 136ea48..9b9cab7 100644
--- a/sapi/fpm/fpm/fpm_scoreboard.h
+++ b/sapi/fpm/fpm/fpm_scoreboard.h
@@ -67,11 +67,16 @@ struct fpm_scoreboard_s {
struct fpm_scoreboard_proc_s *procs[];
};
+struct fpm_scoreboard_list_s {
+ struct fpm_scoreboard_s *scoreboard;
+ struct fpm_scoreboard_list_s *next;
+};
+
int fpm_scoreboard_init_main();
int fpm_scoreboard_init_child(struct fpm_worker_pool_s *wp);
void fpm_scoreboard_update(int idle, int active, int lq, int lq_len, int requests, int max_children_reached, int action, struct fpm_scoreboard_s *scoreboard);
-struct fpm_scoreboard_s *fpm_scoreboard_get();
+struct fpm_scoreboard_s *fpm_scoreboard_get(char *pool);
struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get(struct fpm_scoreboard_s *scoreboard, int child_index);
struct fpm_scoreboard_s *fpm_scoreboard_acquire(struct fpm_scoreboard_s *scoreboard, int nohang);
diff --git a/sapi/fpm/fpm/fpm_status.c b/sapi/fpm/fpm/fpm_status.c
index e64a645..c8d8e88 100644
--- a/sapi/fpm/fpm/fpm_status.c
+++ b/sapi/fpm/fpm/fpm_status.c
@@ -14,22 +14,137 @@
#include "zlog.h"
#include "fpm_atomic.h"
#include "fpm_conf.h"
+#include "fpm_php.h"
#include <ext/standard/html.h>
static char *fpm_status_uri = NULL;
static char *fpm_status_ping_uri = NULL;
static char *fpm_status_ping_response = NULL;
+static int fpm_status_allow_nb = 0;
+static char **fpm_status_allow_pools;
+static char *fpm_status_pool_name = NULL;
+int fpm_status_init_main() /* {{{*/
+{
+ struct fpm_worker_pool_s *wp, *wp2;
+
+ /* loop on each pool configuration */
+ for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
+
+ /* if the status path is not set, skip */
+ if (!wp->config->pm_status_path || !*wp->config->pm_status_path) {
+ continue;
+ }
+
+ if (wp->config->pm_status_allow && *wp->config->pm_status_allow) {
+ char *orig, *orig2, *s;
+ int i;
+ char *saveptr = NULL;
+
+ wp->pm_status_allow_nb = 0;
+
+ /* dup the original string as strtok alterates it */
+ if (!(orig = strdup(wp->config->pm_status_allow))) {
+ return -1;
+ }
+ orig2 = orig;
+
+ while ((s = strtok_r(orig2, ",", &saveptr))) {
+ /* reset strtok ptr to avoid loop */
+ orig2 = NULL;
+
+ /* if '*', then all are allowed */
+ if (strncmp(s, "*", 1) == 0) {
+ wp->pm_status_allow_nb = -1; /* -1 means all */
+ break;
+ }
+
+ if (strlen(s) <= 0) {
+ zlog(ZLOG_ERROR, "[pool %s] pm.status_allow can't have empty elements", wp->config->name);
+ free(orig);
+ return -1;
+ }
+ /* s is not empty */
+
+ /* search if the pool exists */
+ i = 0;
+ for (wp2 = fpm_worker_all_pools; wp2; wp2 = wp2->next) {
+ if (wp2->config->name && strcmp(wp2->config->name, s) == 0) {
+ i = 1;
+ break;
+ }
+ }
+
+ if (!i) {
+ zlog(ZLOG_ERROR, "[pool %s] pm.status_allow specifies an unknown pool: %s", wp->config->name, s);
+ return -1;
+ }
+
+ /* we have one more winner */
+ wp->pm_status_allow_nb++;
+ }
+
+ /* alloc allowed pools strings */
+ if (wp->pm_status_allow_nb > 0) {
+ if (!(wp->pm_status_allow_pools = malloc(sizeof(char *) * wp->pm_status_allow_nb))) {
+ return -1;
+ }
+
+ /* dup the original string as strtok alterates it */
+ if (!(orig = strdup(wp->config->pm_status_allow))) {
+ return -1;
+ }
+ orig2 = orig;
+
+ i = 0;
+ while ((s = strtok_r(orig2, ",", &saveptr))) {
+ orig2 = NULL;
+ if (strlen(s) > 0) {
+ if (!(wp->pm_status_allow_pools[i] = strdup(s))) {
+ free(orig);
+ return -1;
+ }
+ i++;
+ }
+ }
+
+ free(orig);
+ }
+ }
+ }
+ return 0;
+}
+/* }}} */
int fpm_status_init_child(struct fpm_worker_pool_s *wp) /* {{{ */
{
- if (!wp || !wp->config) {
+ if (!wp || !wp->config || !wp->config->name) {
zlog(ZLOG_ERROR, "unable to init fpm_status because conf structure is NULL");
return -1;
}
+ /* save our own pool name */
+ if (!(fpm_status_pool_name = strdup(wp->config->name))) {
+ return -1;
+ }
+
if (wp->config->pm_status_path) {
fpm_status_uri = strdup(wp->config->pm_status_path);
+
+ fpm_status_allow_nb = wp->pm_status_allow_nb;
+ /* duplicate allowed pools as the origin will be freed right after child init */
+ if (fpm_status_allow_nb > 0) {
+ int i;
+ if (!(fpm_status_allow_pools = malloc(sizeof(char *) * fpm_status_allow_nb))) {
+ return -1;
+ }
+
+ for (i=0; i<fpm_status_allow_nb; i++) {
+ if (!(fpm_status_allow_pools[i] = strdup(wp->pm_status_allow_pools[i]))) {
+ return -1;
+ }
+ }
+ }
}
if (wp->config->ping_path) {
@@ -78,9 +193,36 @@ int fpm_status_handle_request(TSRMLS_D) /* {{{ */
/* STATUS */
if (fpm_status_uri && !strcmp(fpm_status_uri, SG(request_info).request_uri)) {
+ char *pool;
+
fpm_request_executing();
- scoreboard_p = fpm_scoreboard_get();
+ pool = fpm_php_get_string_from_table("_GET", "pool" TSRMLS_CC);
+
+ /* we're asked for a different pool than us, check if allowed */
+ if (pool && strlen(pool) > 0 && strcmp(fpm_status_pool_name, pool) != 0 && fpm_status_allow_nb >= 0) {
+ int ok = 0;
+ int i;
+ for (i=0; i<fpm_status_allow_nb; i++) {
+ if (!strcmp(fpm_status_allow_pools[i], pool)) {
+ ok = 1;
+ break;
+ }
+ }
+
+ /* nothing has been found, permission is not allowed to show this pool status */
+ if (!ok) {
+ zlog(ZLOG_ERROR, "status: trying to access pool %s status, but it's not been allowed in pm.status_allow", pool);
+ SG(sapi_headers).http_response_code = 403;
+ sapi_add_header_ex(ZEND_STRL("Content-Type: text/plain"), 1, 1 TSRMLS_CC);
+ sapi_add_header_ex(ZEND_STRL("Expires: Thu, 01 Jan 1970 00:00:00 GMT"), 1, 1 TSRMLS_CC);
+ sapi_add_header_ex(ZEND_STRL("Cache-Control: no-cache, no-store, must-revalidate, max-age=0"), 1, 1 TSRMLS_CC);
+ PUTS("Access denied");
+ return 1;
+ }
+ }
+
+ scoreboard_p = fpm_scoreboard_get(pool TSRMLS_CC);
if (!scoreboard_p) {
zlog(ZLOG_ERROR, "status: unable to find or access status shared memory");
SG(sapi_headers).http_response_code = 500;
@@ -125,13 +267,13 @@ int fpm_status_handle_request(TSRMLS_D) /* {{{ */
}
/* full status ? */
- full = SG(request_info).request_uri && strstr(SG(request_info).query_string, "full");
+ full = (fpm_php_get_string_from_table("_GET", "full" TSRMLS_CC) != NULL);
short_syntax = short_post = NULL;
full_separator = full_pre = full_syntax = full_post = NULL;
encode = 0;
/* HTML */
- if (SG(request_info).query_string && strstr(SG(request_info).query_string, "html")) {
+ if (fpm_php_get_string_from_table("_GET", "html")) {
sapi_add_header_ex(ZEND_STRL("Content-Type: text/html"), 1, 1 TSRMLS_CC);
time_format = "%d/%b/%Y:%H:%M:%S %z";
encode = 1;
@@ -205,7 +347,7 @@ int fpm_status_handle_request(TSRMLS_D) /* {{{ */
}
/* XML */
- } else if (SG(request_info).request_uri && strstr(SG(request_info).query_string, "xml")) {
+ } else if (fpm_php_get_string_from_table("_GET", "xml")) {
sapi_add_header_ex(ZEND_STRL("Content-Type: text/xml"), 1, 1 TSRMLS_CC);
time_format = "%s";
encode = 1;
@@ -256,7 +398,7 @@ int fpm_status_handle_request(TSRMLS_D) /* {{{ */
}
/* JSON */
- } else if (SG(request_info).request_uri && strstr(SG(request_info).query_string, "json")) {
+ } else if (fpm_php_get_string_from_table("_GET", "json")) {
sapi_add_header_ex(ZEND_STRL("Content-Type: application/json"), 1, 1 TSRMLS_CC);
time_format = "%s";
diff --git a/sapi/fpm/fpm/fpm_status.h b/sapi/fpm/fpm/fpm_status.h
index 8f3daf9..56ee819 100644
--- a/sapi/fpm/fpm/fpm_status.h
+++ b/sapi/fpm/fpm/fpm_status.h
@@ -21,6 +21,7 @@ struct fpm_status_s {
struct timeval last_update;
};
+int fpm_status_init_main();
int fpm_status_init_child(struct fpm_worker_pool_s *wp);
void fpm_status_update_activity(struct fpm_shm_s *shm, int idle, int active, int total, unsigned cur_lq, int max_lq, int clear_last_update);
void fpm_status_update_accepted_conn(struct fpm_shm_s *shm, unsigned long int accepted_conn);
diff --git a/sapi/fpm/fpm/fpm_worker_pool.h b/sapi/fpm/fpm/fpm_worker_pool.h
index 6688e6d..8279948 100644
--- a/sapi/fpm/fpm/fpm_worker_pool.h
+++ b/sapi/fpm/fpm/fpm_worker_pool.h
@@ -42,6 +42,10 @@ struct fpm_worker_pool_s {
/* for ondemand PM */
struct fpm_event_s *ondemand_event;
int socket_event_set;
+
+ /* status */
+ int pm_status_allow_nb;
+ char **pm_status_allow_pools;
};
struct fpm_worker_pool_s *fpm_worker_pool_alloc();
diff --git a/sapi/fpm/php-fpm.conf.in b/sapi/fpm/php-fpm.conf.in
index 44e4dba..8892113 100644
--- a/sapi/fpm/php-fpm.conf.in
+++ b/sapi/fpm/php-fpm.conf.in
@@ -340,6 +340,13 @@ pm.max_spare_servers = 3
; may conflict with a real PHP file.
; Default Value: not set
;pm.status_path = /status
+
+; Allow this pool to access other status pools
+; Specify the pool when calling the status page: /status?pool=xxxxx
+; Note: - Different pool names can be specified using the comma ',' character
+; - Allow to access all status pools by setting pm.status_allow to '*'
+; Default Value: not set (means only the current pool)
+;pm.status_allow = pool1,pool2,pool3
; The ping URI to call the monitoring page of FPM. If this value is not set, no
; URI will be recognized as a ping page. This could be used to test from outside
|