diff options
| author | George Wang <gwang@php.net> | 2016-08-28 22:23:28 -0400 | 
|---|---|---|
| committer | George Wang <gwang@php.net> | 2016-08-28 22:23:28 -0400 | 
| commit | ca1eb585ee0ef7d2ab5bb4160aa0a36f59d51a48 (patch) | |
| tree | 9247a49e670b787134cccc8e3f36b09a0c483026 /sapi/litespeed/lsapi_main.c | |
| parent | 986d0f87ec873c88dedbac334fa5896c068ed987 (diff) | |
| parent | c73bcbefbd74c650b48caef7e475502c1ef96c90 (diff) | |
| download | php-git-ca1eb585ee0ef7d2ab5bb4160aa0a36f59d51a48.tar.gz | |
Merge branch 'PHP-5.6' into PHP-7.0
Conflicts:
	sapi/litespeed/lsapi_main.c
Diffstat (limited to 'sapi/litespeed/lsapi_main.c')
| -rw-r--r-- | sapi/litespeed/lsapi_main.c | 415 | 
1 files changed, 357 insertions, 58 deletions
| diff --git a/sapi/litespeed/lsapi_main.c b/sapi/litespeed/lsapi_main.c index b0ea105a88..65d2451ab6 100644 --- a/sapi/litespeed/lsapi_main.c +++ b/sapi/litespeed/lsapi_main.c @@ -69,6 +69,19 @@  #define SAPI_LSAPI_MAX_HEADER_LENGTH 2048 +/* Key for each cache entry is dirname(PATH_TRANSLATED). + * + * NOTE: Each cache entry config_hash contains the combination from all user ini files found in + *       the path starting from doc_root throught to dirname(PATH_TRANSLATED).  There is no point + *       storing per-file entries as it would not be possible to detect added / deleted entries + *       between separate files. + */ +typedef struct _user_config_cache_entry { +    time_t expires; +    HashTable user_config; +} user_config_cache_entry; +static HashTable user_config_cache; +  static int  lsapi_mode       = 0;  static char *php_self        = "";  static char *script_filename = ""; @@ -76,6 +89,7 @@ static int  source_highlight = 0;  static int  ignore_php_ini   = 0;  static char * argv0 = NULL;  static int  engine = 1; +static int  parse_user_ini   = 0;  #ifdef ZTS  zend_compiler_globals    *compiler_globals;  zend_executor_globals    *executor_globals; @@ -86,6 +100,14 @@ void ***tsrm_ls;  zend_module_entry litespeed_module_entry; +static void init_sapi_from_env(sapi_module_struct *sapi_module) +{ +    char *p; +    p = getenv("LSPHPRC"); +    if (p) +        sapi_module->php_ini_path_override = p; +} +  /* {{{ php_lsapi_startup   */  static int php_lsapi_startup(sapi_module_struct *sapi_module) @@ -196,46 +218,19 @@ static char *sapi_lsapi_getenv( char * name, size_t name_len )  /* }}} */ - -  static int add_variable( const char * pKey, int keyLen, const char * pValue, int valLen,                           void * arg )  { -#if PHP_MAJOR_VERSION >= 7 -	int filter_arg = (Z_ARR_P((zval *)arg) == Z_ARR(PG(http_globals)[TRACK_VARS_ENV])) +    int filter_arg = (Z_ARR_P((zval *)arg) == Z_ARR(PG(http_globals)[TRACK_VARS_ENV]))          ? PARSE_ENV : PARSE_SERVER; -#else -    int filter_arg = (arg == PG(http_globals)[TRACK_VARS_ENV])?PARSE_ENV:PARSE_SERVER; -#endif      char * new_val = (char *) pValue;      size_t new_val_len;      if (sapi_module.input_filter(filter_arg, (char *)pKey, &new_val, valLen, &new_val_len)) {          php_register_variable_safe((char *)pKey, new_val, new_val_len, (zval *)arg );      } -	return 1; -} - -/* -static int add_variable( const char * pKey, int keyLen, const char * pValue, int valLen, -                         void * arg ) -{ -    zval * gpc_element, **gpc_element_p; -    HashTable * symtable1 = Z_ARRVAL_P((zval * )arg); -    register char * pKey1 = (char *)pKey; - -    MAKE_STD_ZVAL(gpc_element); -    Z_STRLEN_P( gpc_element ) = valLen; -    Z_STRVAL_P( gpc_element ) = estrndup(pValue, valLen); -    Z_TYPE_P( gpc_element ) = IS_STRING; -#if PHP_MAJOR_VERSION > 4 -    zend_symtable_update( symtable1, pKey1, keyLen + 1, &gpc_element, sizeof( zval *), (void **) &gpc_element_p ); -#else -    zend_hash_update( symtable1, pKey1, keyLen + 1, &gpc_element, sizeof( zval *), (void **) &gpc_element_p ); -#endif      return 1;  } -*/  static void litespeed_php_import_environment_variables(zval *array_ptr)  { @@ -244,7 +239,6 @@ static void litespeed_php_import_environment_variables(zval *array_ptr)  	size_t alloc_size = sizeof(buf);  	unsigned long nlen; /* ptrdiff_t is not portable */ -#if PHP_MAJOR_VERSION >= 7      if (Z_TYPE(PG(http_globals)[TRACK_VARS_ENV]) == IS_ARRAY &&          Z_ARR_P(array_ptr) != Z_ARR(PG(http_globals)[TRACK_VARS_ENV]) &&          zend_hash_num_elements(Z_ARRVAL(PG(http_globals)[TRACK_VARS_ENV])) > 0 @@ -260,29 +254,6 @@ static void litespeed_php_import_environment_variables(zval *array_ptr)          ZVAL_DUP(array_ptr, &PG(http_globals)[TRACK_VARS_SERVER]);  		return;  	} -#else -    if (PG(http_globals)[TRACK_VARS_ENV] && -        array_ptr != PG(http_globals)[TRACK_VARS_ENV] && -        Z_TYPE_P(PG(http_globals)[TRACK_VARS_ENV]) == IS_ARRAY && -        zend_hash_num_elements(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_ENV])) > 0 -    ) { -        zval_dtor(array_ptr); -        *array_ptr = *PG(http_globals)[TRACK_VARS_ENV]; -        INIT_PZVAL(array_ptr); -        zval_copy_ctor(array_ptr); -        return; -    } else if (PG(http_globals)[TRACK_VARS_SERVER] && -        array_ptr != PG(http_globals)[TRACK_VARS_SERVER] && -        Z_TYPE_P(PG(http_globals)[TRACK_VARS_SERVER]) == IS_ARRAY && -        zend_hash_num_elements(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER])) > 0 -    ) { -        zval_dtor(array_ptr); -        *array_ptr = *PG(http_globals)[TRACK_VARS_SERVER]; -        INIT_PZVAL(array_ptr); -        zval_copy_ctor(array_ptr); -        return; -    } -#endif  	for (env = environ; env != NULL && *env != NULL; env++) {  		p = strchr(*env, '='); @@ -412,13 +383,33 @@ static void sapi_lsapi_log_message(char *message)  }  /* }}} */ +/* Set to 1 to turn on log messages useful during development: + */ +#if 0 +static void log_message (const char *fmt, ...) +{ +    va_list ap; +    va_start(ap, fmt); +    char buf[0x100]; +    vsnprintf(buf, sizeof(buf), fmt, ap); +    va_end(ap); +    sapi_lsapi_log_message(buf +#if PHP_MAJOR_VERSION > 7 || (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION >= 1) +                               , 0 +#endif +                                  ); +} +#define DEBUG_MESSAGE(fmt, ...) log_message("LS:%d " fmt "\n", __LINE__, ##__VA_ARGS__) +#else +#define DEBUG_MESSAGE(fmt, ...) +#endif  /* {{{ sapi_module_struct cgi_sapi_module   */  static sapi_module_struct lsapi_sapi_module =  {      "litespeed", -    "LiteSpeed V6.9", +    "LiteSpeed V6.10",      php_lsapi_startup,              /* startup */      php_module_shutdown_wrapper,    /* shutdown */ @@ -556,6 +547,7 @@ static int lsapi_execute_script( zend_file_handle * file_handle)  } +static int lsapi_activate_user_ini();  static int lsapi_module_main(int show_source)  { @@ -564,6 +556,11 @@ static int lsapi_module_main(int show_source)      if (php_request_startup() == FAILURE ) {          return -1;      } +     +    if (parse_user_ini && lsapi_activate_user_ini() == FAILURE) { +        return -1; +    } +      if (show_source) {          zend_syntax_highlighter_ini syntax_highlighter_ini; @@ -584,7 +581,7 @@ static int alter_ini( const char * pKey, int keyLen, const char * pValue, int va                  void * arg )  {  #if PHP_MAJOR_VERSION >= 7 -	zend_string * psKey; +    zend_string * psKey;  #endif      int type = ZEND_INI_PERDIR;      if ( '\001' == *pKey ) { @@ -600,7 +597,7 @@ static int alter_ini( const char * pKey, int keyLen, const char * pValue, int va                  engine = 0;          }          else -		{ +        {  #if PHP_MAJOR_VERSION >= 7              --keyLen;              psKey = zend_string_init(pKey, keyLen, 1); @@ -613,11 +610,293 @@ static int alter_ini( const char * pKey, int keyLen, const char * pValue, int va                               (char *)pValue, valLen,                               type, PHP_INI_STAGE_ACTIVATE);  #endif -		} +        }      }      return 1;  } +static void user_config_cache_entry_dtor(zval *el) +{ +    user_config_cache_entry *entry = (user_config_cache_entry *)Z_PTR_P(el); +    zend_hash_destroy(&entry->user_config); +    free(entry); +} + +static void user_config_cache_init() +{ +    zend_hash_init(&user_config_cache, 0, NULL, user_config_cache_entry_dtor, 1); +} + +static int pathlen_without_trailing_slash(char *path) +{ +    int len = (int)strlen(path); +    while (len > 1 && /* mind "/" as root dir */ +           path[len-1] == DEFAULT_SLASH) +    { +        --len; +    } +    return len; +} + +static inline char* skip_slash(char *s) +{ +    while (*s == DEFAULT_SLASH) { +        ++s; +    } +    return s; +} + +/** + * Walk down the path_stop starting at path_start. + * + * If path_start = "/path1" and path_stop = "/path1/path2/path3" + * the callback will be called 3 times with the next args: + * + *   1. "/path1/path2/path3" + *             ^ end + *       ^ start + *   2. "/path1/path2/path3" + *                   ^ end + *       ^ start + *   3. "/path1/path2/path3" + *                         ^ end + *       ^ start + * + * path_stop has to be a subdir of path_start + * or to be path_start itself. + * + * Both path args have to be absolute. + * Trailing slashes are allowed. + * NULL or empty string args are not allowed. + */ +static void walk_down_the_path(char* path_start, +                               char* path_stop, +                               void (*cb)(char* begin, +                                          char* end, +                                          void* data), +                               void* data) +{ +    char *pos = path_stop + pathlen_without_trailing_slash(path_start); +    cb(path_stop, pos, data); + +    while ((pos = skip_slash(pos))[0]) { +        pos = strchr(pos, DEFAULT_SLASH); +        if (!pos) { +            /* The last token without trailing slash +             */ +            cb(path_stop, path_stop + strlen(path_stop), data); +            return; +        } +        cb(path_stop, pos, data); +    } +} + + +typedef struct { +    char *path; +    uint path_len; +    char *doc_root; +    user_config_cache_entry *entry; +} _lsapi_activate_user_ini_ctx; + +typedef int (*fn_activate_user_ini_chain_t) +        (_lsapi_activate_user_ini_ctx *ctx, void* next); + +static int lsapi_activate_user_ini_basic_checks(_lsapi_activate_user_ini_ctx *ctx, +                                                void* next) +{ +    int rc = SUCCESS; +    fn_activate_user_ini_chain_t *fn_next = next; + +    if (!PG(user_ini_filename) || !*PG(user_ini_filename)) { +        return SUCCESS; +    } + +    /* PATH_TRANSLATED should be defined at this stage */ +    ctx->path = SG(request_info).path_translated; +    if (!ctx->path || !*ctx->path) { +        return FAILURE; +    } + +    ctx->doc_root = sapi_lsapi_getenv("DOCUMENT_ROOT", 0); +    DEBUG_MESSAGE("doc_root: %s", ctx->doc_root); + +    if (*fn_next) { +        rc = (*fn_next)(ctx, fn_next + 1); +    } + +    return rc; +} + +static int lsapi_activate_user_ini_mk_path(_lsapi_activate_user_ini_ctx *ctx, +                                           void* next) +{ +    char *path; +    int rc = SUCCESS; +    fn_activate_user_ini_chain_t *fn_next = next; + +    /* Extract dir name from path_translated * and store it in 'path' */ +    ctx->path_len = strlen(ctx->path); +    path = ctx->path = estrndup(SG(request_info).path_translated, ctx->path_len); +    if (!path) +        return FAILURE; +    ctx->path_len = zend_dirname(path, ctx->path_len); +    DEBUG_MESSAGE("dirname: %s", ctx->path); + +    if (*fn_next) { +        rc = (*fn_next)(ctx, fn_next + 1); +    } + +    efree(path); +    return rc; +} + +static int lsapi_activate_user_ini_mk_realpath(_lsapi_activate_user_ini_ctx *ctx, +                                               void* next) +{ +    char *real_path; +    int rc = SUCCESS; +    fn_activate_user_ini_chain_t *fn_next = next; + +    if (!IS_ABSOLUTE_PATH(ctx->path, ctx->path_len)) { +        real_path = tsrm_realpath(ctx->path, NULL); +        if (!real_path) { +            return SUCCESS; +        } +        ctx->path = real_path; +        ctx->path_len = strlen(ctx->path); +        DEBUG_MESSAGE("calculated tsrm realpath: %s", real_path); +    } else { +        DEBUG_MESSAGE("%s is an absolute path", ctx->path); +        real_path = NULL; +    } + +    if (*fn_next) { +        rc = (*fn_next)(ctx, fn_next + 1); +    } + +    if (real_path) +        efree(real_path); +    return rc; +} + +static int lsapi_activate_user_ini_mk_user_config(_lsapi_activate_user_ini_ctx *ctx, +                                                  void* next) +{ +    fn_activate_user_ini_chain_t *fn_next = next; + +    /* Find cached config entry: If not found, create one */ +    ctx->entry = zend_hash_str_find_ptr(&user_config_cache, ctx->path, ctx->path_len); + +    if (ctx->entry) { +        DEBUG_MESSAGE("found entry for %s", ctx->path); +    } else { +        DEBUG_MESSAGE("entry for %s not found, creating new entry", ctx->path); +        ctx->entry = pemalloc(sizeof(user_config_cache_entry), 1); +        ctx->entry->expires = 0; +        zend_hash_init(&ctx->entry->user_config, 0, NULL, +                       config_zval_dtor, 1); +        zend_hash_str_update_ptr(&user_config_cache, ctx->path, +                                            ctx->path_len, ctx->entry); +    } + +    if (*fn_next) { +        return (*fn_next)(ctx, fn_next + 1); +    } else { +        return SUCCESS; +    } +} + +static void walk_down_the_path_callback(char* begin, +                                        char* end, +                                        void* data) +{ +    _lsapi_activate_user_ini_ctx *ctx = data; +    char tmp = end[0]; +    end[0] = 0; +    DEBUG_MESSAGE("parsing %s%c%s", begin, DEFAULT_SLASH, PG(user_ini_filename)); +    php_parse_user_ini_file(begin, PG(user_ini_filename), &ctx->entry->user_config); +    end[0] = tmp; +} + +static int lsapi_activate_user_ini_walk_down_the_path(_lsapi_activate_user_ini_ctx *ctx, +                                                      void* next) +{ +    time_t request_time = sapi_get_request_time(); +    uint path_len, docroot_len; +    int rc = SUCCESS; +    fn_activate_user_ini_chain_t *fn_next = next; + +    if (!ctx->entry->expires || request_time > ctx->entry->expires) +    { +        docroot_len = ctx->doc_root && ctx->doc_root[0] +                    ? pathlen_without_trailing_slash(ctx->doc_root) +                    : 0; + +        int is_outside_of_docroot = !docroot_len || +                ctx->path_len < docroot_len || +                strncmp(ctx->path, ctx->doc_root, docroot_len) != 0; + +        if (is_outside_of_docroot) { +            php_parse_user_ini_file(ctx->path, PG(user_ini_filename),  +                                    &ctx->entry->user_config); +        } else { +            walk_down_the_path(ctx->doc_root, ctx->path, +                               &walk_down_the_path_callback, ctx); +        } + +        ctx->entry->expires = request_time + PG(user_ini_cache_ttl); +    } + +    if (*fn_next) { +        rc = (*fn_next)(ctx, fn_next + 1); +    } + +    return rc; +} + +static int lsapi_activate_user_ini_finally(_lsapi_activate_user_ini_ctx *ctx, +                                           void* next) +{ +    int rc = SUCCESS; +    fn_activate_user_ini_chain_t *fn_next = next; + +    DEBUG_MESSAGE("calling php_ini_activate_config()"); +    php_ini_activate_config(&ctx->entry->user_config, PHP_INI_PERDIR,  +                            PHP_INI_STAGE_HTACCESS); + +    if (*fn_next) { +        rc = (*fn_next)(ctx, fn_next + 1); +    } + +    return rc; +} + +static int lsapi_activate_user_ini(TSRMLS_D) +{ +    _lsapi_activate_user_ini_ctx ctx; +    /** +     * The reason to have this function list stacked +     * is each function now can define a scoped destructor. +     * +     * Passing control via function pointer is a sign of low coupling, +     * which means dependencies between these functions are to be +     * controlled from a single place +     * (here below, by modifying this function list order) +     */ +    static const fn_activate_user_ini_chain_t fn_chain[] = { +        &lsapi_activate_user_ini_basic_checks, +        &lsapi_activate_user_ini_mk_path, +        &lsapi_activate_user_ini_mk_realpath, +        &lsapi_activate_user_ini_mk_user_config, +        &lsapi_activate_user_ini_walk_down_the_path, +        &lsapi_activate_user_ini_finally, +        NULL +    }; +     +    return fn_chain[0](&ctx, (fn_activate_user_ini_chain_t*)(fn_chain + 1)); +} +  static void override_ini()  { @@ -811,9 +1090,9 @@ static int cli_main( int argc, char * argv[] )              case 'v':                  if (php_request_startup() != FAILURE) {  #if ZEND_DEBUG -                    php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2016 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); +                    php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2015 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());  #else -                    php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2016 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); +                    php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2015 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());  #endif  #ifdef PHP_OUTPUT_NEWAPI                      php_output_end_all(); @@ -1039,6 +1318,11 @@ int main( int argc, char * argv[] )      lsapi_sapi_module.executable_location = argv[0]; +    /* Initialize from environment variables before processing command-line +     * options: the latter override the former. +     */ +    init_sapi_from_env(&lsapi_sapi_module); +          if ( ignore_php_ini )          lsapi_sapi_module.php_ini_ignore = 1; @@ -1121,17 +1405,24 @@ int main( int argc, char * argv[] )  /*   LiteSpeed PHP module starts here */ +#if PHP_MAJOR_VERSION > 4 +  /* {{{ arginfo */  ZEND_BEGIN_ARG_INFO(arginfo_litespeed__void, 0)  ZEND_END_ARG_INFO()  /* }}} */ +#else +#define arginfo_litespeed__void NULL +#endif +  PHP_FUNCTION(litespeed_request_headers);  PHP_FUNCTION(litespeed_response_headers);  PHP_FUNCTION(apache_get_modules);  PHP_MINFO_FUNCTION(litespeed); +  zend_function_entry litespeed_functions[] = {      PHP_FE(litespeed_request_headers,   arginfo_litespeed__void)      PHP_FE(litespeed_response_headers,  arginfo_litespeed__void) @@ -1144,6 +1435,12 @@ zend_function_entry litespeed_functions[] = {  static PHP_MINIT_FUNCTION(litespeed)  { +    user_config_cache_init(); + +    const char *p = getenv("LSPHP_ENABLE_USER_INI"); +    if (p && 0 == strcasecmp(p, "on")) +        parse_user_ini = 1; +      /* REGISTER_INI_ENTRIES(); */      return SUCCESS;  } @@ -1151,6 +1448,8 @@ static PHP_MINIT_FUNCTION(litespeed)  static PHP_MSHUTDOWN_FUNCTION(litespeed)  { +    zend_hash_destroy(&user_config_cache); +      /* UNREGISTER_INI_ENTRIES(); */      return SUCCESS;  } | 
