diff options
author | foobar <sniper@php.net> | 2004-01-17 13:00:38 +0000 |
---|---|---|
committer | foobar <sniper@php.net> | 2004-01-17 13:00:38 +0000 |
commit | f4983c0d3f56c2074458e4840db36643b2fec59b (patch) | |
tree | 2dcf521f07114e3bb2952439fe28cdfa40d30677 /sapi/isapi/php5isapi.c | |
parent | b851f3712388de9f6c4addf2063dbc3c663a0b3b (diff) | |
download | php-git-f4983c0d3f56c2074458e4840db36643b2fec59b.tar.gz |
- Renamed all *php4* files to *php5*, changed all php4/PHP4 to php5/PHP5
Diffstat (limited to 'sapi/isapi/php5isapi.c')
-rw-r--r-- | sapi/isapi/php5isapi.c | 949 |
1 files changed, 949 insertions, 0 deletions
diff --git a/sapi/isapi/php5isapi.c b/sapi/isapi/php5isapi.c new file mode 100644 index 0000000000..b0d1366299 --- /dev/null +++ b/sapi/isapi/php5isapi.c @@ -0,0 +1,949 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2004 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.0 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Zeev Suraski <zeev@zend.com> | + | Ben Mansell <ben@zeus.com> (Zeus Support) | + +----------------------------------------------------------------------+ + */ + +#include "php.h" +#include <httpext.h> +#include <httpfilt.h> +#include <httpext.h> +#include "php_main.h" +#include "SAPI.h" +#include "php_globals.h" +#include "ext/standard/info.h" +#include "php_variables.h" +#include "php_ini.h" + +#ifdef PHP_WIN32 +# include <process.h> +#else +# define __try +# define __except(val) +# define __declspec(foo) +#endif + + +#ifdef WITH_ZEUS +# include "httpext.h" +# include <errno.h> +# define GetLastError() errno +#endif + +#ifdef PHP_WIN32 +#define PHP_ENABLE_SEH +#endif + +/* +uncomment the following lines to turn off +exception trapping when running under a debugger + +#ifdef _DEBUG +#undef PHP_ENABLE_SEH +#endif +*/ + +#define MAX_STATUS_LENGTH sizeof("xxxx LONGEST STATUS DESCRIPTION") +#define ISAPI_SERVER_VAR_BUF_SIZE 1024 +#define ISAPI_POST_DATA_BUF 1024 + +static zend_bool bFilterLoaded=0; +static zend_bool bTerminateThreadsOnError=0; + +static char *isapi_special_server_variable_names[] = { + "ALL_HTTP", + "HTTPS", +#ifndef WITH_ZEUS + "SCRIPT_NAME", +#endif + NULL +}; + +#define NUM_SPECIAL_VARS (sizeof(isapi_special_server_variable_names)/sizeof(char *)) +#define SPECIAL_VAR_ALL_HTTP 0 +#define SPECIAL_VAR_HTTPS 1 +#define SPECIAL_VAR_PHP_SELF 2 + +static char *isapi_server_variable_names[] = { + "AUTH_PASSWORD", + "AUTH_TYPE", + "AUTH_USER", + "CONTENT_LENGTH", + "CONTENT_TYPE", + "PATH_TRANSLATED", + "QUERY_STRING", + "REMOTE_ADDR", + "REMOTE_HOST", + "REMOTE_USER", + "REQUEST_METHOD", + "SERVER_NAME", + "SERVER_PORT", + "SERVER_PROTOCOL", + "SERVER_SOFTWARE", +#ifndef WITH_ZEUS + "APPL_MD_PATH", + "APPL_PHYSICAL_PATH", + "INSTANCE_ID", + "INSTANCE_META_PATH", + "LOGON_USER", + "REQUEST_URI", + "URL", +#else + "DOCUMENT_ROOT", +#endif + NULL +}; + + +static char *isapi_secure_server_variable_names[] = { + "CERT_COOKIE", + "CERT_FLAGS", + "CERT_ISSUER", + "CERT_KEYSIZE", + "CERT_SECRETKEYSIZE", + "CERT_SERIALNUMBER", + "CERT_SERVER_ISSUER", + "CERT_SERVER_SUBJECT", + "CERT_SUBJECT", + "HTTPS_KEYSIZE", + "HTTPS_SECRETKEYSIZE", + "HTTPS_SERVER_ISSUER", + "HTTPS_SERVER_SUBJECT", + "SERVER_PORT_SECURE", +#ifdef WITH_ZEUS + "SSL_CLIENT_CN", + "SSL_CLIENT_EMAIL", + "SSL_CLIENT_OU", + "SSL_CLIENT_O", + "SSL_CLIENT_L", + "SSL_CLIENT_ST", + "SSL_CLIENT_C", + "SSL_CLIENT_I_CN", + "SSL_CLIENT_I_EMAIL", + "SSL_CLIENT_I_OU", + "SSL_CLIENT_I_O", + "SSL_CLIENT_I_L", + "SSL_CLIENT_I_ST", + "SSL_CLIENT_I_C", +#endif + NULL +}; + + +static void php_info_isapi(ZEND_MODULE_INFO_FUNC_ARGS) +{ + char **p; + char variable_buf[ISAPI_SERVER_VAR_BUF_SIZE]; + DWORD variable_len; + char **all_variables[] = { + isapi_server_variable_names, + isapi_special_server_variable_names, + isapi_secure_server_variable_names, + NULL + }; + char ***server_variable_names; + LPEXTENSION_CONTROL_BLOCK lpECB; + + lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context); + + php_info_print_table_start(); + php_info_print_table_header(2, "Server Variable", "Value"); + server_variable_names = all_variables; + while (*server_variable_names) { + p = *server_variable_names; + while (*p) { + variable_len = ISAPI_SERVER_VAR_BUF_SIZE; + if (lpECB->GetServerVariable(lpECB->ConnID, *p, variable_buf, &variable_len) + && variable_buf[0]) { + php_info_print_table_row(2, *p, variable_buf); + } else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + char *tmp_variable_buf; + + tmp_variable_buf = (char *) emalloc(variable_len); + if (lpECB->GetServerVariable(lpECB->ConnID, *p, tmp_variable_buf, &variable_len) + && variable_buf[0]) { + php_info_print_table_row(2, *p, tmp_variable_buf); + } + efree(tmp_variable_buf); + } + p++; + } + server_variable_names++; + } + php_info_print_table_end(); +} + + +static zend_module_entry php_isapi_module = { + STANDARD_MODULE_HEADER, + "ISAPI", + NULL, + NULL, + NULL, + NULL, + NULL, + php_info_isapi, + NULL, + STANDARD_MODULE_PROPERTIES +}; + + +static int sapi_isapi_ub_write(const char *str, uint str_length TSRMLS_DC) +{ + DWORD num_bytes = str_length; + LPEXTENSION_CONTROL_BLOCK ecb; + + ecb = (LPEXTENSION_CONTROL_BLOCK) SG(server_context); + if (ecb->WriteClient(ecb->ConnID, (char *) str, &num_bytes, HSE_IO_SYNC) == FALSE) { + php_handle_aborted_connection(); + } + return num_bytes; +} + + +static int sapi_isapi_header_handler(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers TSRMLS_DC) +{ + return SAPI_HEADER_ADD; +} + + + +static void accumulate_header_length(sapi_header_struct *sapi_header, uint *total_length TSRMLS_DC) +{ + *total_length += sapi_header->header_len+2; +} + + +static void concat_header(sapi_header_struct *sapi_header, char **combined_headers_ptr TSRMLS_DC) +{ + memcpy(*combined_headers_ptr, sapi_header->header, sapi_header->header_len); + *combined_headers_ptr += sapi_header->header_len; + **combined_headers_ptr = '\r'; + (*combined_headers_ptr)++; + **combined_headers_ptr = '\n'; + (*combined_headers_ptr)++; +} + + +static int sapi_isapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) +{ + uint total_length = 2; /* account for the trailing \r\n */ + char *combined_headers, *combined_headers_ptr; + LPEXTENSION_CONTROL_BLOCK lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context); + HSE_SEND_HEADER_EX_INFO header_info; + char status_buf[MAX_STATUS_LENGTH]; + sapi_header_struct default_content_type; + + /* Obtain headers length */ + if (SG(sapi_headers).send_default_content_type) { + sapi_get_default_content_type_header(&default_content_type TSRMLS_CC); + accumulate_header_length(&default_content_type, (void *) &total_length TSRMLS_CC); + } + zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t) accumulate_header_length, (void *) &total_length TSRMLS_CC); + + /* Generate headers */ + combined_headers = (char *) emalloc(total_length+1); + combined_headers_ptr = combined_headers; + if (SG(sapi_headers).send_default_content_type) { + concat_header(&default_content_type, (void *) &combined_headers_ptr TSRMLS_CC); + sapi_free_header(&default_content_type); /* we no longer need it */ + } + zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t) concat_header, (void *) &combined_headers_ptr TSRMLS_CC); + *combined_headers_ptr++ = '\r'; + *combined_headers_ptr++ = '\n'; + *combined_headers_ptr = 0; + + switch (SG(sapi_headers).http_response_code) { + case 200: + header_info.pszStatus = "200 OK"; + break; + case 302: + header_info.pszStatus = "302 Moved Temporarily"; + break; + case 401: + header_info.pszStatus = "401 Authorization Required"; + break; + default: + snprintf(status_buf, MAX_STATUS_LENGTH, "%d Undescribed", SG(sapi_headers).http_response_code); + header_info.pszStatus = status_buf; + break; + } + header_info.cchStatus = strlen(header_info.pszStatus); + header_info.pszHeader = combined_headers; + header_info.cchHeader = total_length; + header_info.fKeepConn = FALSE; + lpECB->dwHttpStatusCode = SG(sapi_headers).http_response_code; + + lpECB->ServerSupportFunction(lpECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER_EX, &header_info, NULL, NULL); + + efree(combined_headers); + return SAPI_HEADER_SENT_SUCCESSFULLY; +} + + +static int php_isapi_startup(sapi_module_struct *sapi_module) +{ + if (php_module_startup(sapi_module, &php_isapi_module, 1)==FAILURE) { + return FAILURE; + } else { + bTerminateThreadsOnError = (zend_bool) INI_INT("isapi.terminate_threads_on_error"); + return SUCCESS; + } +} + + + +static int sapi_isapi_read_post(char *buffer, uint count_bytes TSRMLS_DC) +{ + LPEXTENSION_CONTROL_BLOCK lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context); + DWORD read_from_buf=0; + DWORD read_from_input=0; + DWORD total_read=0; + + if ((DWORD) SG(read_post_bytes) < lpECB->cbAvailable) { + read_from_buf = MIN(lpECB->cbAvailable-SG(read_post_bytes), count_bytes); + memcpy(buffer, lpECB->lpbData+SG(read_post_bytes), read_from_buf); + total_read += read_from_buf; + } + if (read_from_buf<count_bytes + && (SG(read_post_bytes)+read_from_buf) < lpECB->cbTotalBytes) { + DWORD cbRead=0, cbSize; + + read_from_input = MIN(count_bytes-read_from_buf, lpECB->cbTotalBytes-SG(read_post_bytes)-read_from_buf); + while (cbRead < read_from_input) { + cbSize = read_from_input - cbRead; + if (!lpECB->ReadClient(lpECB->ConnID, buffer+read_from_buf+cbRead, &cbSize) || cbSize==0) { + break; + } + cbRead += cbSize; + } + total_read += cbRead; + } + return total_read; +} + + +static char *sapi_isapi_read_cookies(TSRMLS_D) +{ + LPEXTENSION_CONTROL_BLOCK lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context); + char variable_buf[ISAPI_SERVER_VAR_BUF_SIZE]; + DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE; + + if (lpECB->GetServerVariable(lpECB->ConnID, "HTTP_COOKIE", variable_buf, &variable_len)) { + return estrndup(variable_buf, variable_len); + } else if (GetLastError()==ERROR_INSUFFICIENT_BUFFER) { + char *tmp_variable_buf = (char *) emalloc(variable_len+1); + + if (lpECB->GetServerVariable(lpECB->ConnID, "HTTP_COOKIE", tmp_variable_buf, &variable_len)) { + tmp_variable_buf[variable_len] = 0; + return tmp_variable_buf; + } else { + efree(tmp_variable_buf); + } + } + return NULL; +} + + +#ifdef WITH_ZEUS + +static void sapi_isapi_register_zeus_ssl_variables(LPEXTENSION_CONTROL_BLOCK lpECB, zval *track_vars_array TSRMLS_DC) +{ + char static_variable_buf[ISAPI_SERVER_VAR_BUF_SIZE]; + DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE; + char static_cons_buf[ISAPI_SERVER_VAR_BUF_SIZE]; + /* + * We need to construct the /C=.../ST=... + * DN's for SSL_CLIENT_DN and SSL_CLIENT_I_DN + */ + strcpy( static_cons_buf, "/C=" ); + if( lpECB->GetServerVariable( lpECB->ConnID, "SSL_CLIENT_C", static_variable_buf, &variable_len ) && static_variable_buf[0] ) { + strcat( static_cons_buf, static_variable_buf ); + } + strcat( static_cons_buf, "/ST=" ); + variable_len = ISAPI_SERVER_VAR_BUF_SIZE; + if( lpECB->GetServerVariable( lpECB->ConnID, "SSL_CLIENT_ST", static_variable_buf, &variable_len ) && static_variable_buf[0] ) { + strcat( static_cons_buf, static_variable_buf ); + } + php_register_variable( "SSL_CLIENT_DN", static_cons_buf, track_vars_array TSRMLS_CC ); + + strcpy( static_cons_buf, "/C=" ); + variable_len = ISAPI_SERVER_VAR_BUF_SIZE; + if( lpECB->GetServerVariable( lpECB->ConnID, "SSL_CLIENT_I_C", static_variable_buf, &variable_len ) && static_variable_buf[0] ) { + strcat( static_cons_buf, static_variable_buf ); + } + strcat( static_cons_buf, "/ST=" ); + variable_len = ISAPI_SERVER_VAR_BUF_SIZE; + if( lpECB->GetServerVariable( lpECB->ConnID, "SSL_CLIENT_I_ST", static_variable_buf, &variable_len ) && static_variable_buf[0] ) { + strcat( static_cons_buf, static_variable_buf ); + } + php_register_variable( "SSL_CLIENT_I_DN", static_cons_buf, track_vars_array TSRMLS_CC ); +} + +static void sapi_isapi_register_zeus_variables(LPEXTENSION_CONTROL_BLOCK lpECB, zval *track_vars_array TSRMLS_DC) +{ + char static_variable_buf[ISAPI_SERVER_VAR_BUF_SIZE]; + DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE; + DWORD scriptname_len = ISAPI_SERVER_VAR_BUF_SIZE; + DWORD pathinfo_len = 0; + char *strtok_buf = NULL; + + /* Get SCRIPT_NAME, we use this to work out which bit of the URL + * belongs in PHP's version of PATH_INFO + */ + lpECB->GetServerVariable(lpECB->ConnID, "SCRIPT_NAME", static_variable_buf, &scriptname_len); + + /* Adjust Zeus' version of PATH_INFO, set PHP_SELF, + * and generate REQUEST_URI + */ + if ( lpECB->GetServerVariable(lpECB->ConnID, "PATH_INFO", static_variable_buf, &variable_len) && static_variable_buf[0] ) { + + /* PHP_SELF is just PATH_INFO */ + php_register_variable( "PHP_SELF", static_variable_buf, track_vars_array TSRMLS_CC ); + + /* Chop off filename to get just the 'real' PATH_INFO' */ + pathinfo_len = variable_len - scriptname_len; + php_register_variable( "PATH_INFO", static_variable_buf + scriptname_len - 1, track_vars_array TSRMLS_CC ); + /* append query string to give url... extra byte for '?' */ + if ( strlen(lpECB->lpszQueryString) + variable_len + 1 < ISAPI_SERVER_VAR_BUF_SIZE ) { + /* append query string only if it is present... */ + if ( strlen(lpECB->lpszQueryString) ) { + static_variable_buf[ variable_len - 1 ] = '?'; + strcpy( static_variable_buf + variable_len, lpECB->lpszQueryString ); + } + php_register_variable( "URL", static_variable_buf, track_vars_array TSRMLS_CC ); + php_register_variable( "REQUEST_URI", static_variable_buf, track_vars_array TSRMLS_CC ); + } + } + + /* Get and adjust PATH_TRANSLATED to what PHP wants */ + variable_len = ISAPI_SERVER_VAR_BUF_SIZE; + if ( lpECB->GetServerVariable(lpECB->ConnID, "PATH_TRANSLATED", static_variable_buf, &variable_len) && static_variable_buf[0] ) { + static_variable_buf[ variable_len - pathinfo_len - 1 ] = '\0'; + php_register_variable( "PATH_TRANSLATED", static_variable_buf, track_vars_array TSRMLS_CC ); + } + + /* Bring in the AUTHENTICATION stuff as needed */ + variable_len = ISAPI_SERVER_VAR_BUF_SIZE; + if ( lpECB->GetServerVariable(lpECB->ConnID, "AUTH_USER", static_variable_buf, &variable_len) && static_variable_buf[0] ) { + php_register_variable( "PHP_AUTH_USER", static_variable_buf, track_vars_array TSRMLS_CC ); + } + variable_len = ISAPI_SERVER_VAR_BUF_SIZE; + if ( lpECB->GetServerVariable(lpECB->ConnID, "AUTH_PASSWORD", static_variable_buf, &variable_len) && static_variable_buf[0] ) { + php_register_variable( "PHP_AUTH_PW", static_variable_buf, track_vars_array TSRMLS_CC ); + } + variable_len = ISAPI_SERVER_VAR_BUF_SIZE; + if ( lpECB->GetServerVariable(lpECB->ConnID, "AUTH_TYPE", static_variable_buf, &variable_len) && static_variable_buf[0] ) { + php_register_variable( "AUTH_TYPE", static_variable_buf, track_vars_array TSRMLS_CC ); + } + + /* And now, for the SSL variables (if applicable) */ + variable_len = ISAPI_SERVER_VAR_BUF_SIZE; + if ( lpECB->GetServerVariable(lpECB->ConnID, "CERT_COOKIE", static_variable_buf, &variable_len) && static_variable_buf[0] ) { + sapi_isapi_register_zeus_ssl_variables( lpECB, track_vars_array TSRMLS_CC ); + } + /* Copy some of the variables we need to meet Apache specs */ + variable_len = ISAPI_SERVER_VAR_BUF_SIZE; + if ( lpECB->GetServerVariable(lpECB->ConnID, "SERVER_SOFTWARE", static_variable_buf, &variable_len) && static_variable_buf[0] ) { + php_register_variable( "SERVER_SIGNATURE", static_variable_buf, track_vars_array TSRMLS_CC ); + } +} +#else + +static void sapi_isapi_register_iis_variables(LPEXTENSION_CONTROL_BLOCK lpECB, zval *track_vars_array TSRMLS_DC) +{ + char static_variable_buf[ISAPI_SERVER_VAR_BUF_SIZE]; + char path_info_buf[ISAPI_SERVER_VAR_BUF_SIZE]; + DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE; + DWORD scriptname_len = ISAPI_SERVER_VAR_BUF_SIZE; + DWORD pathinfo_len = 0; + HSE_URL_MAPEX_INFO humi; + + /* Get SCRIPT_NAME, we use this to work out which bit of the URL + * belongs in PHP's version of PATH_INFO. SCRIPT_NAME also becomes PHP_SELF. + */ + lpECB->GetServerVariable(lpECB->ConnID, "SCRIPT_NAME", static_variable_buf, &scriptname_len); + php_register_variable("SCRIPT_FILENAME", SG(request_info).path_translated, track_vars_array TSRMLS_CC); + + /* Adjust IIS' version of PATH_INFO, set PHP_SELF, + * and generate REQUEST_URI + * Get and adjust PATH_TRANSLATED to what PHP wants + */ + if ( lpECB->GetServerVariable(lpECB->ConnID, "PATH_INFO", static_variable_buf, &variable_len) && static_variable_buf[0] ) { + + /* Chop off filename to get just the 'real' PATH_INFO' */ + php_register_variable( "ORIG_PATH_INFO", static_variable_buf, track_vars_array TSRMLS_CC ); + pathinfo_len = variable_len - scriptname_len; + strncpy(path_info_buf, static_variable_buf + scriptname_len - 1, sizeof(path_info_buf)-1); + php_register_variable( "PATH_INFO", path_info_buf, track_vars_array TSRMLS_CC ); + /* append query string to give url... extra byte for '?' */ + if ( strlen(lpECB->lpszQueryString) + variable_len + 1 < ISAPI_SERVER_VAR_BUF_SIZE ) { + /* append query string only if it is present... */ + if ( strlen(lpECB->lpszQueryString) ) { + static_variable_buf[ variable_len - 1 ] = '?'; + strcpy( static_variable_buf + variable_len, lpECB->lpszQueryString ); + } + php_register_variable( "URL", static_variable_buf, track_vars_array TSRMLS_CC ); + php_register_variable( "REQUEST_URI", static_variable_buf, track_vars_array TSRMLS_CC ); + } + variable_len = ISAPI_SERVER_VAR_BUF_SIZE; + if ( lpECB->GetServerVariable(lpECB->ConnID, "PATH_TRANSLATED", static_variable_buf, &variable_len) && static_variable_buf[0] ) { + php_register_variable( "ORIG_PATH_TRANSLATED", static_variable_buf, track_vars_array TSRMLS_CC ); + } + if (lpECB->ServerSupportFunction(lpECB->ConnID, HSE_REQ_MAP_URL_TO_PATH_EX, path_info_buf, &pathinfo_len, (LPDWORD) &humi)) { + /* Remove trailing \ */ + if (humi.lpszPath[variable_len-2] == '\\') { + humi.lpszPath[variable_len-2] = 0; + } + php_register_variable("PATH_TRANSLATED", humi.lpszPath, track_vars_array TSRMLS_CC); + } + } + + static_variable_buf[0] = '/'; + static_variable_buf[1] = 0; + variable_len = 2; + if (lpECB->ServerSupportFunction(lpECB->ConnID, HSE_REQ_MAP_URL_TO_PATH_EX, static_variable_buf, &variable_len, (LPDWORD) &humi)) { + /* Remove trailing \ */ + if (humi.lpszPath[variable_len-2] == '\\') { + humi.lpszPath[variable_len-2] = 0; + } + php_register_variable("DOCUMENT_ROOT", humi.lpszPath, track_vars_array TSRMLS_CC); + } + + if (!SG(request_info).auth_user || !SG(request_info).auth_password || + !SG(request_info).auth_user[0] || !SG(request_info).auth_password[0]) { + variable_len = ISAPI_SERVER_VAR_BUF_SIZE; + if (lpECB->GetServerVariable(lpECB->ConnID, "HTTP_AUTHORIZATION", static_variable_buf, &variable_len) + && static_variable_buf[0]) { + php_handle_auth_data(static_variable_buf TSRMLS_CC); + } + } + + if (SG(request_info).auth_user) { + php_register_variable("PHP_AUTH_USER", SG(request_info).auth_user, track_vars_array TSRMLS_CC ); + } + if (SG(request_info).auth_password) { + php_register_variable("PHP_AUTH_PW", SG(request_info).auth_password, track_vars_array TSRMLS_CC ); + } +} +#endif + +static void sapi_isapi_register_server_variables2(char **server_variables, LPEXTENSION_CONTROL_BLOCK lpECB, zval *track_vars_array, char **recorded_values TSRMLS_DC) +{ + char **p=server_variables; + DWORD variable_len; + char static_variable_buf[ISAPI_SERVER_VAR_BUF_SIZE]; + char *variable_buf; + + while (*p) { + variable_len = ISAPI_SERVER_VAR_BUF_SIZE; + if (lpECB->GetServerVariable(lpECB->ConnID, *p, static_variable_buf, &variable_len) + && static_variable_buf[0]) { + php_register_variable(*p, static_variable_buf, track_vars_array TSRMLS_CC); + if (recorded_values) { + recorded_values[p-server_variables] = estrndup(static_variable_buf, variable_len); + } + } else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + variable_buf = (char *) emalloc(variable_len+1); + if (lpECB->GetServerVariable(lpECB->ConnID, *p, variable_buf, &variable_len) + && variable_buf[0]) { + php_register_variable(*p, variable_buf, track_vars_array TSRMLS_CC); + } + if (recorded_values) { + recorded_values[p-server_variables] = variable_buf; + } else { + efree(variable_buf); + } + } + p++; + } +} + + +static void sapi_isapi_register_server_variables(zval *track_vars_array TSRMLS_DC) +{ + DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE; + char *variable; + char *strtok_buf = NULL; + char *isapi_special_server_variables[NUM_SPECIAL_VARS]; + LPEXTENSION_CONTROL_BLOCK lpECB; + + lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context); + + /* Register the special ISAPI variables */ + memset(isapi_special_server_variables, 0, sizeof(isapi_special_server_variables)); + sapi_isapi_register_server_variables2(isapi_special_server_variable_names, lpECB, track_vars_array, isapi_special_server_variables TSRMLS_CC); + if (SG(request_info).cookie_data) { + php_register_variable("HTTP_COOKIE", SG(request_info).cookie_data, track_vars_array TSRMLS_CC); + } + + /* Register the standard ISAPI variables */ + sapi_isapi_register_server_variables2(isapi_server_variable_names, lpECB, track_vars_array, NULL TSRMLS_CC); + + if (isapi_special_server_variables[SPECIAL_VAR_HTTPS] + && (atoi(isapi_special_server_variables[SPECIAL_VAR_HTTPS]) + || !strcasecmp(isapi_special_server_variables[SPECIAL_VAR_HTTPS], "on")) + ) { + /* Register SSL ISAPI variables */ + sapi_isapi_register_server_variables2(isapi_secure_server_variable_names, lpECB, track_vars_array, NULL TSRMLS_CC); + } + + if (isapi_special_server_variables[SPECIAL_VAR_HTTPS]) { + efree(isapi_special_server_variables[SPECIAL_VAR_HTTPS]); + } + + +#ifdef WITH_ZEUS + sapi_isapi_register_zeus_variables(lpECB, track_vars_array TSRMLS_CC); +#else + sapi_isapi_register_iis_variables(lpECB, track_vars_array TSRMLS_CC); +#endif + + /* PHP_SELF support */ + if (isapi_special_server_variables[SPECIAL_VAR_PHP_SELF]) { + php_register_variable("PHP_SELF", isapi_special_server_variables[SPECIAL_VAR_PHP_SELF], track_vars_array TSRMLS_CC); + efree(isapi_special_server_variables[SPECIAL_VAR_PHP_SELF]); + } + + if (isapi_special_server_variables[SPECIAL_VAR_ALL_HTTP]) { + /* Register the internal bits of ALL_HTTP */ + variable = php_strtok_r(isapi_special_server_variables[SPECIAL_VAR_ALL_HTTP], "\r\n", &strtok_buf); + while (variable) { + char *colon = strchr(variable, ':'); + + if (colon) { + char *value = colon+1; + + while (*value==' ') { + value++; + } + *colon = 0; + php_register_variable(variable, value, track_vars_array TSRMLS_CC); + *colon = ':'; + } + variable = php_strtok_r(NULL, "\r\n", &strtok_buf); + } + efree(isapi_special_server_variables[SPECIAL_VAR_ALL_HTTP]); + } +} + + +static sapi_module_struct isapi_sapi_module = { + "isapi", /* name */ + "ISAPI", /* pretty name */ + + php_isapi_startup, /* startup */ + php_module_shutdown_wrapper, /* shutdown */ + + NULL, /* activate */ + NULL, /* deactivate */ + + sapi_isapi_ub_write, /* unbuffered write */ + NULL, /* flush */ + NULL, /* get uid */ + NULL, /* getenv */ + + php_error, /* error handler */ + + sapi_isapi_header_handler, /* header handler */ + sapi_isapi_send_headers, /* send headers handler */ + NULL, /* send header handler */ + + sapi_isapi_read_post, /* read POST data */ + sapi_isapi_read_cookies, /* read Cookies */ + + sapi_isapi_register_server_variables, /* register server variables */ + NULL, /* Log message */ + + STANDARD_SAPI_MODULE_PROPERTIES +}; + + +BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pFilterVersion) +{ + bFilterLoaded = 1; + pFilterVersion->dwFilterVersion = HTTP_FILTER_REVISION; + strcpy(pFilterVersion->lpszFilterDesc, isapi_sapi_module.pretty_name); + pFilterVersion->dwFlags= (SF_NOTIFY_AUTHENTICATION | SF_NOTIFY_PREPROC_HEADERS); + return TRUE; +} + + +DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificationType, LPVOID pvNotification) +{ + TSRMLS_FETCH(); + + switch (notificationType) { + case SF_NOTIFY_PREPROC_HEADERS: + SG(request_info).auth_user = NULL; + SG(request_info).auth_password = NULL; + break; + case SF_NOTIFY_AUTHENTICATION: { + char *auth_user = ((HTTP_FILTER_AUTHENT *) pvNotification)->pszUser; + char *auth_password = ((HTTP_FILTER_AUTHENT *) pvNotification)->pszPassword; + + if (auth_user && auth_user[0]) { + SG(request_info).auth_user = estrdup(auth_user); + } + if (auth_password && auth_password[0]) { + SG(request_info).auth_password = estrdup(auth_password); + } + return SF_STATUS_REQ_HANDLED_NOTIFICATION; + } + break; + } + return SF_STATUS_REQ_NEXT_NOTIFICATION; +} + + +static void init_request_info(LPEXTENSION_CONTROL_BLOCK lpECB TSRMLS_DC) +{ + DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE; + char static_variable_buf[ISAPI_SERVER_VAR_BUF_SIZE]; +#ifndef WITH_ZEUS + HSE_URL_MAPEX_INFO humi; +#endif + + SG(request_info).request_method = lpECB->lpszMethod; + SG(request_info).query_string = lpECB->lpszQueryString; + SG(request_info).request_uri = lpECB->lpszPathInfo; + SG(request_info).content_type = lpECB->lpszContentType; + SG(request_info).content_length = lpECB->cbTotalBytes; + SG(sapi_headers).http_response_code = 200; /* I think dwHttpStatusCode is invalid at this stage -RL */ + if (!bFilterLoaded) { /* we don't have valid ISAPI Filter information */ + SG(request_info).auth_user = SG(request_info).auth_password = NULL; + } + +#ifdef WITH_ZEUS + /* PATH_TRANSLATED can contain extra PATH_INFO stuff after the + * file being loaded, so we must use SCRIPT_FILENAME instead + */ + if(lpECB->GetServerVariable(lpECB->ConnID, "SCRIPT_FILENAME", static_variable_buf, &variable_len)) { + SG(request_info).path_translated = estrdup(static_variable_buf); + } else +#else + /* happily, IIS gives us SCRIPT_NAME which is correct (without PATH_INFO stuff) + so we can just map that to the physical path and we have our filename */ + + lpECB->GetServerVariable(lpECB->ConnID, "SCRIPT_NAME", static_variable_buf, &variable_len); + if (lpECB->ServerSupportFunction(lpECB->ConnID, HSE_REQ_MAP_URL_TO_PATH_EX, static_variable_buf, &variable_len, (LPDWORD) &humi)) { + SG(request_info).path_translated = estrdup(humi.lpszPath); + } else +#endif + /* if mapping fails, default to what the server tells us */ + SG(request_info).path_translated = estrdup(lpECB->lpszPathTranslated); + + /* some server configurations allow '..' to slip through in the + translated path. We'll just refuse to handle such a path. */ + if (strstr(SG(request_info).path_translated,"..")) { + SG(sapi_headers).http_response_code = 404; + efree(SG(request_info).path_translated); + SG(request_info).path_translated = NULL; + } +} + + +static void php_isapi_report_exception(char *message, int message_len TSRMLS_DC) +{ + if (!SG(headers_sent)) { + HSE_SEND_HEADER_EX_INFO header_info; + LPEXTENSION_CONTROL_BLOCK lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context); + + header_info.pszStatus = "500 Internal Server Error"; + header_info.cchStatus = strlen(header_info.pszStatus); + header_info.pszHeader = "Content-Type: text/html\r\n\r\n"; + header_info.cchHeader = strlen(header_info.pszHeader); + + lpECB->dwHttpStatusCode = 500; + lpECB->ServerSupportFunction(lpECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER_EX, &header_info, NULL, NULL); + SG(headers_sent)=1; + } + sapi_isapi_ub_write(message, message_len TSRMLS_CC); +} + + +BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer) +{ + pVer->dwExtensionVersion = HSE_VERSION; +#ifdef WITH_ZEUS + strncpy( pVer->lpszExtensionDesc, isapi_sapi_module.name, HSE_MAX_EXT_DLL_NAME_LEN); +#else + lstrcpyn(pVer->lpszExtensionDesc, isapi_sapi_module.name, HSE_MAX_EXT_DLL_NAME_LEN); +#endif + return TRUE; +} + + +static void my_endthread() +{ +#ifdef PHP_WIN32 + if (bTerminateThreadsOnError) { + _endthread(); + } +#endif +} + +#ifdef PHP_WIN32 +/* ep is accessible only in the context of the __except expression, + * so we have to call this function to obtain it. + */ +BOOL exceptionhandler(LPEXCEPTION_POINTERS *e, LPEXCEPTION_POINTERS ep) +{ + *e=ep; + return TRUE; +} +#endif + +DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB) +{ + zend_file_handle file_handle; + zend_bool stack_overflown=0; + int retval = FAILURE; +#ifdef PHP_ENABLE_SEH + LPEXCEPTION_POINTERS e; +#endif + TSRMLS_FETCH(); + + zend_first_try { +#ifdef PHP_ENABLE_SEH + __try { +#endif + init_request_info(lpECB TSRMLS_CC); + SG(server_context) = lpECB; + + php_request_startup(TSRMLS_C); + + file_handle.filename = SG(request_info).path_translated; + file_handle.free_filename = 0; + file_handle.type = ZEND_HANDLE_FILENAME; + file_handle.opened_path = NULL; + + /* open the script here so we can 404 if it fails */ + if (file_handle.filename) + retval = php_fopen_primary_script(&file_handle TSRMLS_CC); + + if (!file_handle.filename || retval == FAILURE) { + SG(sapi_headers).http_response_code = 404; + PUTS("No input file specified.\n"); + } else { + php_execute_script(&file_handle TSRMLS_CC); + } + + if (SG(request_info).cookie_data) { + efree(SG(request_info).cookie_data); + } + if (SG(request_info).path_translated) + efree(SG(request_info).path_translated); +#ifdef PHP_ENABLE_SEH + } __except(exceptionhandler(&e, GetExceptionInformation())) { + char buf[1024]; + if (_exception_code()==EXCEPTION_STACK_OVERFLOW) { + LPBYTE lpPage; + static SYSTEM_INFO si; + static MEMORY_BASIC_INFORMATION mi; + static DWORD dwOldProtect; + + GetSystemInfo(&si); + + /* Get page ESP is pointing to */ + _asm mov lpPage, esp; + + /* Get stack allocation base */ + VirtualQuery(lpPage, &mi, sizeof(mi)); + + /* Go to the page below the current page */ + lpPage = (LPBYTE) (mi.BaseAddress) - si.dwPageSize; + + /* Free pages below current page */ + if (!VirtualFree(mi.AllocationBase, (LPBYTE)lpPage - (LPBYTE) mi.AllocationBase, MEM_DECOMMIT)) { + _endthread(); + } + + /* Restore the guard page */ + if (!VirtualProtect(lpPage, si.dwPageSize, PAGE_GUARD | PAGE_READWRITE, &dwOldProtect)) { + _endthread(); + } + + CG(unclean_shutdown)=1; + _snprintf(buf, sizeof(buf)-1,"PHP has encountered a Stack overflow"); + php_isapi_report_exception(buf, strlen(buf) TSRMLS_CC); + } else if (_exception_code()==EXCEPTION_ACCESS_VIOLATION) { + _snprintf(buf, sizeof(buf)-1,"PHP has encountered an Access Violation at %p", e->ExceptionRecord->ExceptionAddress); + php_isapi_report_exception(buf, strlen(buf) TSRMLS_CC); + my_endthread(); + } else { + _snprintf(buf, sizeof(buf)-1,"PHP has encountered an Unhandled Exception Code %d at %p", e->ExceptionRecord->ExceptionCode , e->ExceptionRecord->ExceptionAddress); + php_isapi_report_exception(buf, strlen(buf) TSRMLS_CC); + my_endthread(); + } + } +#endif +#ifdef PHP_ENABLE_SEH + __try { + php_request_shutdown(NULL); + } __except(EXCEPTION_EXECUTE_HANDLER) { + my_endthread(); + } +#else + php_request_shutdown(NULL); +#endif + } zend_catch { + zend_try { + php_request_shutdown(NULL); + } zend_end_try(); + return HSE_STATUS_ERROR; + } zend_end_try(); + + return HSE_STATUS_SUCCESS; +} + + + +__declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + switch (fdwReason) { + case DLL_PROCESS_ATTACH: +#ifdef WITH_ZEUS + tsrm_startup(128, 1, TSRM_ERROR_LEVEL_CORE, "TSRM.log"); +#else + tsrm_startup(128, 1, TSRM_ERROR_LEVEL_CORE, "C:\\TSRM.log"); +#endif + sapi_startup(&isapi_sapi_module); + if (isapi_sapi_module.startup) { + isapi_sapi_module.startup(&sapi_module); + } + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + ts_free_thread(); + break; + case DLL_PROCESS_DETACH: + if (isapi_sapi_module.shutdown) { + isapi_sapi_module.shutdown(&sapi_module); + } + tsrm_shutdown(); + break; + } + return TRUE; +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ |