Back to index

php5  5.3.10
php5isapi.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Zeev Suraski <zeev@zend.com>                                |
00016    |          Ben Mansell <ben@zeus.com> (Zeus Support)                   |
00017    +----------------------------------------------------------------------+
00018  */
00019 /* $Id: php5isapi.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 #include "php.h"
00022 #include <httpext.h>
00023 #include <httpfilt.h>
00024 #include <httpext.h>
00025 #include "php_main.h"
00026 #include "SAPI.h"
00027 #include "php_globals.h"
00028 #include "ext/standard/info.h"
00029 #include "php_variables.h"
00030 #include "php_ini.h"
00031 
00032 #ifdef PHP_WIN32
00033 # include <process.h>
00034 #else
00035 # define __try
00036 # define __except(val)
00037 # define __declspec(foo)
00038 #endif
00039 
00040 
00041 #ifdef WITH_ZEUS
00042 # include "httpext.h"
00043 # include <errno.h>
00044 # define GetLastError() errno
00045 #endif
00046 
00047 #ifdef PHP_WIN32
00048 #define PHP_ENABLE_SEH
00049 #endif
00050 
00051 /* 
00052 uncomment the following lines to turn off 
00053 exception trapping when running under a debugger 
00054 
00055 #ifdef _DEBUG
00056 #undef PHP_ENABLE_SEH
00057 #endif
00058 */
00059 
00060 #define MAX_STATUS_LENGTH sizeof("xxxx LONGEST POSSIBLE STATUS DESCRIPTION")
00061 #define ISAPI_SERVER_VAR_BUF_SIZE 1024
00062 #define ISAPI_POST_DATA_BUF 1024
00063 
00064 static zend_bool bFilterLoaded=0;
00065 static zend_bool bTerminateThreadsOnError=0;
00066 
00067 static char *isapi_special_server_variable_names[] = {
00068        "ALL_HTTP",
00069        "HTTPS",
00070 #ifndef WITH_ZEUS
00071        "SCRIPT_NAME",
00072 #endif
00073        NULL
00074 };
00075 
00076 #define NUM_SPECIAL_VARS           (sizeof(isapi_special_server_variable_names)/sizeof(char *))
00077 #define SPECIAL_VAR_ALL_HTTP       0
00078 #define SPECIAL_VAR_HTTPS          1
00079 #define SPECIAL_VAR_PHP_SELF       2
00080 
00081 static char *isapi_server_variable_names[] = {
00082        "AUTH_PASSWORD",
00083        "AUTH_TYPE",
00084        "AUTH_USER",
00085        "CONTENT_LENGTH",
00086        "CONTENT_TYPE",
00087        "PATH_TRANSLATED",
00088        "QUERY_STRING",
00089        "REMOTE_ADDR",
00090        "REMOTE_HOST",
00091        "REMOTE_USER",
00092        "REQUEST_METHOD",
00093        "SERVER_NAME",
00094        "SERVER_PORT",
00095        "SERVER_PROTOCOL",
00096        "SERVER_SOFTWARE",
00097 #ifndef WITH_ZEUS
00098        "APPL_MD_PATH",
00099        "APPL_PHYSICAL_PATH",
00100        "INSTANCE_ID",
00101        "INSTANCE_META_PATH",
00102        "LOGON_USER",
00103        "REQUEST_URI",
00104        "URL",
00105 #else
00106        "DOCUMENT_ROOT",
00107 #endif
00108        NULL
00109 };
00110 
00111 
00112 static char *isapi_secure_server_variable_names[] = {
00113        "CERT_COOKIE",
00114        "CERT_FLAGS",
00115        "CERT_ISSUER",
00116        "CERT_KEYSIZE",
00117        "CERT_SECRETKEYSIZE",
00118        "CERT_SERIALNUMBER",
00119        "CERT_SERVER_ISSUER",
00120        "CERT_SERVER_SUBJECT",
00121        "CERT_SUBJECT",
00122        "HTTPS_KEYSIZE",
00123        "HTTPS_SECRETKEYSIZE",
00124        "HTTPS_SERVER_ISSUER",
00125        "HTTPS_SERVER_SUBJECT",
00126        "SERVER_PORT_SECURE",
00127 #ifdef WITH_ZEUS
00128        "SSL_CLIENT_CN",
00129        "SSL_CLIENT_EMAIL",
00130        "SSL_CLIENT_OU",
00131        "SSL_CLIENT_O",
00132        "SSL_CLIENT_L",
00133        "SSL_CLIENT_ST",
00134        "SSL_CLIENT_C",
00135        "SSL_CLIENT_I_CN",
00136        "SSL_CLIENT_I_EMAIL",
00137        "SSL_CLIENT_I_OU",
00138        "SSL_CLIENT_I_O",
00139        "SSL_CLIENT_I_L",
00140        "SSL_CLIENT_I_ST",
00141        "SSL_CLIENT_I_C",    
00142 #endif
00143        NULL
00144 };
00145 
00146 
00147 static void php_info_isapi(ZEND_MODULE_INFO_FUNC_ARGS)
00148 {
00149        char **p;
00150        char variable_buf[ISAPI_SERVER_VAR_BUF_SIZE];
00151        DWORD variable_len;
00152        char **all_variables[] = {
00153               isapi_server_variable_names,
00154               isapi_special_server_variable_names,
00155               isapi_secure_server_variable_names,
00156               NULL
00157        };
00158        char ***server_variable_names;
00159        LPEXTENSION_CONTROL_BLOCK lpECB;
00160 
00161        lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context);
00162 
00163        php_info_print_table_start();
00164        php_info_print_table_header(2, "Server Variable", "Value");
00165        server_variable_names = all_variables;
00166        while (*server_variable_names) {
00167               p = *server_variable_names;
00168               while (*p) {
00169                      variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
00170                      if (lpECB->GetServerVariable(lpECB->ConnID, *p, variable_buf, &variable_len)
00171                             && variable_buf[0]) {
00172                             php_info_print_table_row(2, *p, variable_buf);
00173                      } else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
00174                             char *tmp_variable_buf;
00175 
00176                             tmp_variable_buf = (char *) emalloc(variable_len);
00177                             if (lpECB->GetServerVariable(lpECB->ConnID, *p, tmp_variable_buf, &variable_len)
00178                                    && variable_buf[0]) {
00179                                    php_info_print_table_row(2, *p, tmp_variable_buf);
00180                             }
00181                             efree(tmp_variable_buf);
00182                      }
00183                      p++;
00184               }
00185               server_variable_names++;
00186        }
00187        php_info_print_table_end();
00188 }
00189 
00190 
00191 static zend_module_entry php_isapi_module = {
00192     STANDARD_MODULE_HEADER,
00193        "ISAPI",
00194        NULL,
00195        NULL,
00196        NULL,
00197        NULL,
00198        NULL,
00199        php_info_isapi,
00200     NULL,
00201        STANDARD_MODULE_PROPERTIES
00202 };
00203 
00204 
00205 static int sapi_isapi_ub_write(const char *str, uint str_length TSRMLS_DC)
00206 {
00207        DWORD num_bytes = str_length;
00208        LPEXTENSION_CONTROL_BLOCK ecb;
00209        
00210        ecb = (LPEXTENSION_CONTROL_BLOCK) SG(server_context);
00211        if (ecb->WriteClient(ecb->ConnID, (char *) str, &num_bytes, HSE_IO_SYNC) == FALSE) {
00212               php_handle_aborted_connection();
00213        }
00214        return num_bytes;
00215 }
00216 
00217 
00218 static int sapi_isapi_header_handler(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC)
00219 {
00220        return SAPI_HEADER_ADD;
00221 }
00222 
00223 
00224 
00225 static void accumulate_header_length(sapi_header_struct *sapi_header, uint *total_length TSRMLS_DC)
00226 {
00227        *total_length += sapi_header->header_len+2;
00228 }
00229 
00230 
00231 static void concat_header(sapi_header_struct *sapi_header, char **combined_headers_ptr TSRMLS_DC)
00232 {
00233        memcpy(*combined_headers_ptr, sapi_header->header, sapi_header->header_len);
00234        *combined_headers_ptr += sapi_header->header_len;
00235        **combined_headers_ptr = '\r';
00236        (*combined_headers_ptr)++;
00237        **combined_headers_ptr = '\n';
00238        (*combined_headers_ptr)++;
00239 }
00240 
00241 
00242 static int sapi_isapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
00243 {
00244        uint total_length = 2;             /* account for the trailing \r\n */
00245        char *combined_headers, *combined_headers_ptr;
00246        LPEXTENSION_CONTROL_BLOCK lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context);
00247        HSE_SEND_HEADER_EX_INFO header_info;
00248        sapi_header_struct default_content_type;
00249        char *status_buf = NULL;
00250 
00251        /* Obtain headers length */
00252        if (SG(sapi_headers).send_default_content_type) {
00253               sapi_get_default_content_type_header(&default_content_type TSRMLS_CC);
00254               accumulate_header_length(&default_content_type, (void *) &total_length TSRMLS_CC);
00255        }
00256        zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t) accumulate_header_length, (void *) &total_length TSRMLS_CC);
00257 
00258        /* Generate headers */
00259        combined_headers = (char *) emalloc(total_length+1);
00260        combined_headers_ptr = combined_headers;
00261        if (SG(sapi_headers).send_default_content_type) {
00262               concat_header(&default_content_type, (void *) &combined_headers_ptr TSRMLS_CC);
00263               sapi_free_header(&default_content_type); /* we no longer need it */
00264        }
00265        zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t) concat_header, (void *) &combined_headers_ptr TSRMLS_CC);
00266        *combined_headers_ptr++ = '\r';
00267        *combined_headers_ptr++ = '\n';
00268        *combined_headers_ptr = 0;
00269 
00270        switch (SG(sapi_headers).http_response_code) {
00271               case 200:
00272                      header_info.pszStatus = "200 OK";
00273                      break;
00274               case 302:
00275                      header_info.pszStatus = "302 Moved Temporarily";
00276                      break;
00277               case 401:
00278                      header_info.pszStatus = "401 Authorization Required";
00279                      break;
00280               default: {
00281                      const char *sline = SG(sapi_headers).http_status_line;
00282                      int sline_len;
00283                      
00284                      /* httpd requires that r->status_line is set to the first digit of
00285                       * the status-code: */
00286                      if (sline && ((sline_len = strlen(sline)) > 12) && strncmp(sline, "HTTP/1.", 7) == 0 && sline[8] == ' ') {
00287                             if ((sline_len - 9) > MAX_STATUS_LENGTH) {
00288                                    status_buf = estrndup(sline + 9, MAX_STATUS_LENGTH);
00289                             } else {
00290                                    status_buf = estrndup(sline + 9, sline_len - 9);
00291                             }
00292                      } else {
00293                             status_buf = emalloc(MAX_STATUS_LENGTH + 1);
00294                             snprintf(status_buf, MAX_STATUS_LENGTH, "%d Undescribed", SG(sapi_headers).http_response_code);
00295                      }
00296                      header_info.pszStatus = status_buf;
00297                      break;
00298               }
00299        }
00300        header_info.cchStatus = strlen(header_info.pszStatus);
00301        header_info.pszHeader = combined_headers;
00302        header_info.cchHeader = total_length;
00303        header_info.fKeepConn = FALSE;
00304        lpECB->dwHttpStatusCode = SG(sapi_headers).http_response_code;
00305 
00306        lpECB->ServerSupportFunction(lpECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER_EX, &header_info, NULL, NULL);
00307 
00308        efree(combined_headers);
00309        if (status_buf) {
00310               efree(status_buf);
00311        }
00312        return SAPI_HEADER_SENT_SUCCESSFULLY;
00313 }
00314 
00315 
00316 static int php_isapi_startup(sapi_module_struct *sapi_module)
00317 {
00318        if (php_module_startup(sapi_module, &php_isapi_module, 1)==FAILURE) {
00319               return FAILURE;
00320        } else {
00321               bTerminateThreadsOnError = (zend_bool) INI_INT("isapi.terminate_threads_on_error");
00322               return SUCCESS;
00323        }
00324 }
00325 
00326 
00327 static int sapi_isapi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
00328 {
00329        LPEXTENSION_CONTROL_BLOCK lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context);
00330        DWORD read_from_buf=0;
00331        DWORD read_from_input=0;
00332        DWORD total_read=0;
00333 
00334        if ((DWORD) SG(read_post_bytes) < lpECB->cbAvailable) {
00335               read_from_buf = MIN(lpECB->cbAvailable-SG(read_post_bytes), count_bytes);
00336               memcpy(buffer, lpECB->lpbData+SG(read_post_bytes), read_from_buf);
00337               total_read += read_from_buf;
00338        }
00339        if (read_from_buf<count_bytes
00340               && (SG(read_post_bytes)+read_from_buf) < lpECB->cbTotalBytes) {
00341               DWORD cbRead=0, cbSize;
00342 
00343               read_from_input = MIN(count_bytes-read_from_buf, lpECB->cbTotalBytes-SG(read_post_bytes)-read_from_buf);
00344               while (cbRead < read_from_input) {
00345                      cbSize = read_from_input - cbRead;
00346                      if (!lpECB->ReadClient(lpECB->ConnID, buffer+read_from_buf+cbRead, &cbSize) || cbSize==0) {
00347                             break;
00348                      }
00349                      cbRead += cbSize;
00350               }
00351               total_read += cbRead;
00352        }
00353        return total_read;
00354 }
00355 
00356 
00357 static char *sapi_isapi_read_cookies(TSRMLS_D)
00358 {
00359        LPEXTENSION_CONTROL_BLOCK lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context);
00360        char variable_buf[ISAPI_SERVER_VAR_BUF_SIZE];
00361        DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
00362 
00363        if (lpECB->GetServerVariable(lpECB->ConnID, "HTTP_COOKIE", variable_buf, &variable_len)) {
00364               return estrndup(variable_buf, variable_len);
00365        } else if (GetLastError()==ERROR_INSUFFICIENT_BUFFER) {
00366               char *tmp_variable_buf = (char *) emalloc(variable_len+1);
00367 
00368               if (lpECB->GetServerVariable(lpECB->ConnID, "HTTP_COOKIE", tmp_variable_buf, &variable_len)) {
00369                      tmp_variable_buf[variable_len] = 0;
00370                      return tmp_variable_buf;
00371               } else {
00372                      efree(tmp_variable_buf);
00373               }
00374        }
00375        return STR_EMPTY_ALLOC();
00376 }
00377 
00378 
00379 #ifdef WITH_ZEUS
00380 
00381 static void sapi_isapi_register_zeus_ssl_variables(LPEXTENSION_CONTROL_BLOCK lpECB, zval *track_vars_array TSRMLS_DC)
00382 {
00383        char static_variable_buf[ISAPI_SERVER_VAR_BUF_SIZE];
00384        DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
00385        char static_cons_buf[ISAPI_SERVER_VAR_BUF_SIZE];
00386        /*
00387         * We need to construct the /C=.../ST=...
00388         * DN's for SSL_CLIENT_DN and SSL_CLIENT_I_DN
00389         */
00390        strcpy( static_cons_buf, "/C=" );
00391        if( lpECB->GetServerVariable( lpECB->ConnID, "SSL_CLIENT_C", static_variable_buf, &variable_len ) && static_variable_buf[0] ) {
00392               strlcat( static_cons_buf, static_variable_buf,  ISAPI_SERVER_VAR_BUF_SIZE);
00393        }
00394        strlcat( static_cons_buf, "/ST=",  ISAPI_SERVER_VAR_BUF_SIZE);
00395        variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
00396        if( lpECB->GetServerVariable( lpECB->ConnID, "SSL_CLIENT_ST", static_variable_buf, &variable_len ) && static_variable_buf[0] ) {
00397               strlcat( static_cons_buf, static_variable_buf, ISAPI_SERVER_VAR_BUF_SIZE );
00398        }
00399        php_register_variable( "SSL_CLIENT_DN", static_cons_buf, track_vars_array TSRMLS_CC );
00400        
00401        strcpy( static_cons_buf, "/C=" );
00402        variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
00403        if( lpECB->GetServerVariable( lpECB->ConnID, "SSL_CLIENT_I_C", static_variable_buf, &variable_len ) && static_variable_buf[0] ) {
00404               strlcat( static_cons_buf, static_variable_buf, ISAPI_SERVER_VAR_BUF_SIZE );
00405        }
00406        strlcat( static_cons_buf, "/ST=", ISAPI_SERVER_VAR_BUF_SIZE);
00407        variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
00408        if( lpECB->GetServerVariable( lpECB->ConnID, "SSL_CLIENT_I_ST", static_variable_buf, &variable_len ) && static_variable_buf[0] ) {
00409               strlcat( static_cons_buf, static_variable_buf, ISAPI_SERVER_VAR_BUF_SIZE );
00410        }
00411        php_register_variable( "SSL_CLIENT_I_DN", static_cons_buf, track_vars_array TSRMLS_CC );   
00412 }
00413 
00414 static void sapi_isapi_register_zeus_variables(LPEXTENSION_CONTROL_BLOCK lpECB, zval *track_vars_array TSRMLS_DC)
00415 {
00416        char static_variable_buf[ISAPI_SERVER_VAR_BUF_SIZE];
00417        DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
00418        DWORD scriptname_len = ISAPI_SERVER_VAR_BUF_SIZE;
00419        DWORD pathinfo_len = 0;
00420        char *strtok_buf = NULL;
00421 
00422        /* Get SCRIPT_NAME, we use this to work out which bit of the URL
00423         * belongs in PHP's version of PATH_INFO
00424         */
00425        lpECB->GetServerVariable(lpECB->ConnID, "SCRIPT_NAME", static_variable_buf, &scriptname_len);
00426 
00427        /* Adjust Zeus' version of PATH_INFO, set PHP_SELF,
00428         * and generate REQUEST_URI
00429         */
00430        if ( lpECB->GetServerVariable(lpECB->ConnID, "PATH_INFO", static_variable_buf, &variable_len) && static_variable_buf[0] ) {
00431 
00432               /* PHP_SELF is just PATH_INFO */
00433               php_register_variable( "PHP_SELF", static_variable_buf, track_vars_array TSRMLS_CC );
00434 
00435               /* Chop off filename to get just the 'real' PATH_INFO' */
00436               pathinfo_len = variable_len - scriptname_len;
00437               php_register_variable( "PATH_INFO", static_variable_buf + scriptname_len - 1, track_vars_array TSRMLS_CC );
00438               /* append query string to give url... extra byte for '?' */
00439               if ( strlen(lpECB->lpszQueryString) + variable_len + 1 < ISAPI_SERVER_VAR_BUF_SIZE ) {
00440                      /* append query string only if it is present... */
00441                      if ( strlen(lpECB->lpszQueryString) ) {
00442                             static_variable_buf[ variable_len - 1 ] = '?';
00443                             strcpy( static_variable_buf + variable_len, lpECB->lpszQueryString );
00444                      }
00445                      php_register_variable( "URL", static_variable_buf, track_vars_array TSRMLS_CC );
00446                      php_register_variable( "REQUEST_URI", static_variable_buf, track_vars_array TSRMLS_CC );
00447               }
00448        }
00449 
00450        /* Get and adjust PATH_TRANSLATED to what PHP wants */
00451        variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
00452        if ( lpECB->GetServerVariable(lpECB->ConnID, "PATH_TRANSLATED", static_variable_buf, &variable_len) && static_variable_buf[0] ) {
00453               static_variable_buf[ variable_len - pathinfo_len - 1 ] = '\0';
00454               php_register_variable( "PATH_TRANSLATED", static_variable_buf, track_vars_array TSRMLS_CC );
00455        }
00456 
00457        /* Bring in the AUTHENTICATION stuff as needed */
00458        variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
00459        if ( lpECB->GetServerVariable(lpECB->ConnID, "AUTH_USER", static_variable_buf, &variable_len) && static_variable_buf[0] )  {
00460               php_register_variable( "PHP_AUTH_USER", static_variable_buf, track_vars_array TSRMLS_CC );
00461        }
00462        variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
00463        if ( lpECB->GetServerVariable(lpECB->ConnID, "AUTH_PASSWORD", static_variable_buf, &variable_len) && static_variable_buf[0] )  {
00464               php_register_variable( "PHP_AUTH_PW", static_variable_buf, track_vars_array TSRMLS_CC );
00465        }
00466        variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
00467        if ( lpECB->GetServerVariable(lpECB->ConnID, "AUTH_TYPE", static_variable_buf, &variable_len) && static_variable_buf[0] )  {
00468               php_register_variable( "AUTH_TYPE", static_variable_buf, track_vars_array TSRMLS_CC );
00469        }
00470        
00471        /* And now, for the SSL variables (if applicable) */
00472        variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
00473        if ( lpECB->GetServerVariable(lpECB->ConnID, "CERT_COOKIE", static_variable_buf, &variable_len) && static_variable_buf[0] ) {
00474               sapi_isapi_register_zeus_ssl_variables( lpECB, track_vars_array TSRMLS_CC );
00475        }
00476        /* Copy some of the variables we need to meet Apache specs */
00477        variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
00478        if ( lpECB->GetServerVariable(lpECB->ConnID, "SERVER_SOFTWARE", static_variable_buf, &variable_len) && static_variable_buf[0] )  {
00479               php_register_variable( "SERVER_SIGNATURE", static_variable_buf, track_vars_array TSRMLS_CC );
00480        }
00481 }
00482 #else
00483 
00484 static void sapi_isapi_register_iis_variables(LPEXTENSION_CONTROL_BLOCK lpECB, zval *track_vars_array TSRMLS_DC)
00485 {
00486        char static_variable_buf[ISAPI_SERVER_VAR_BUF_SIZE];
00487        char path_info_buf[ISAPI_SERVER_VAR_BUF_SIZE];
00488        DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
00489        DWORD scriptname_len = ISAPI_SERVER_VAR_BUF_SIZE;
00490        DWORD pathinfo_len = 0;
00491        HSE_URL_MAPEX_INFO humi;
00492 
00493        /* Get SCRIPT_NAME, we use this to work out which bit of the URL
00494         * belongs in PHP's version of PATH_INFO.  SCRIPT_NAME also becomes PHP_SELF.
00495         */
00496        lpECB->GetServerVariable(lpECB->ConnID, "SCRIPT_NAME", static_variable_buf, &scriptname_len);
00497        php_register_variable("SCRIPT_FILENAME", SG(request_info).path_translated, track_vars_array TSRMLS_CC);
00498 
00499        /* Adjust IIS' version of PATH_INFO, set PHP_SELF,
00500         * and generate REQUEST_URI
00501         * Get and adjust PATH_TRANSLATED to what PHP wants
00502         */
00503        if ( lpECB->GetServerVariable(lpECB->ConnID, "PATH_INFO", static_variable_buf, &variable_len) && static_variable_buf[0] ) {
00504 
00505               /* Chop off filename to get just the 'real' PATH_INFO' */
00506               php_register_variable( "ORIG_PATH_INFO", static_variable_buf, track_vars_array TSRMLS_CC );
00507               pathinfo_len = variable_len - scriptname_len;
00508               strncpy(path_info_buf, static_variable_buf + scriptname_len - 1, sizeof(path_info_buf)-1);
00509               php_register_variable( "PATH_INFO", path_info_buf, track_vars_array TSRMLS_CC );
00510               /* append query string to give url... extra byte for '?' */
00511               if ( strlen(lpECB->lpszQueryString) + variable_len + 1 < ISAPI_SERVER_VAR_BUF_SIZE ) {
00512                      /* append query string only if it is present... */
00513                      if ( strlen(lpECB->lpszQueryString) ) {
00514                             static_variable_buf[ variable_len - 1 ] = '?';
00515                             strcpy( static_variable_buf + variable_len, lpECB->lpszQueryString );
00516                      }
00517                      php_register_variable( "URL", static_variable_buf, track_vars_array TSRMLS_CC );
00518                      php_register_variable( "REQUEST_URI", static_variable_buf, track_vars_array TSRMLS_CC );
00519               }
00520               variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
00521               if ( lpECB->GetServerVariable(lpECB->ConnID, "PATH_TRANSLATED", static_variable_buf, &variable_len) && static_variable_buf[0] ) {
00522                      php_register_variable( "ORIG_PATH_TRANSLATED", static_variable_buf, track_vars_array TSRMLS_CC );
00523               }
00524               if (lpECB->ServerSupportFunction(lpECB->ConnID, HSE_REQ_MAP_URL_TO_PATH_EX, path_info_buf, &pathinfo_len, (LPDWORD) &humi)) {
00525                      /* Remove trailing \  */
00526                      if (humi.lpszPath[variable_len-2] == '\\') {
00527                             humi.lpszPath[variable_len-2] = 0;
00528                      }
00529                      php_register_variable("PATH_TRANSLATED", humi.lpszPath, track_vars_array TSRMLS_CC);
00530               }
00531        }
00532 
00533        static_variable_buf[0] = '/';
00534        static_variable_buf[1] = 0;
00535        variable_len = 2;
00536        if (lpECB->ServerSupportFunction(lpECB->ConnID, HSE_REQ_MAP_URL_TO_PATH_EX, static_variable_buf, &variable_len, (LPDWORD) &humi)) {
00537               /* Remove trailing \  */
00538               if (humi.lpszPath[variable_len-2] == '\\') {
00539                      humi.lpszPath[variable_len-2] = 0;
00540               }
00541               php_register_variable("DOCUMENT_ROOT", humi.lpszPath, track_vars_array TSRMLS_CC);
00542        }
00543 
00544        if (!SG(request_info).auth_user || !SG(request_info).auth_password || 
00545               !SG(request_info).auth_user[0] || !SG(request_info).auth_password[0]) {
00546               variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
00547               if (lpECB->GetServerVariable(lpECB->ConnID, "HTTP_AUTHORIZATION", static_variable_buf, &variable_len)
00548                      && static_variable_buf[0]) {
00549                      php_handle_auth_data(static_variable_buf TSRMLS_CC);
00550               }
00551        }
00552 
00553        if (SG(request_info).auth_user)  {
00554               php_register_variable("PHP_AUTH_USER", SG(request_info).auth_user, track_vars_array TSRMLS_CC );
00555        }
00556        if (SG(request_info).auth_password) {
00557               php_register_variable("PHP_AUTH_PW", SG(request_info).auth_password, track_vars_array TSRMLS_CC );
00558        }
00559 }
00560 #endif
00561 
00562 static void sapi_isapi_register_server_variables2(char **server_variables, LPEXTENSION_CONTROL_BLOCK lpECB, zval *track_vars_array, char **recorded_values TSRMLS_DC)
00563 {
00564        char **p=server_variables;
00565        DWORD variable_len;
00566        char static_variable_buf[ISAPI_SERVER_VAR_BUF_SIZE];
00567        char *variable_buf;
00568 
00569        while (*p) {
00570               variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
00571               if (lpECB->GetServerVariable(lpECB->ConnID, *p, static_variable_buf, &variable_len)
00572                      && static_variable_buf[0]) {
00573                      php_register_variable(*p, static_variable_buf, track_vars_array TSRMLS_CC);
00574                      if (recorded_values) {
00575                             recorded_values[p-server_variables] = estrndup(static_variable_buf, variable_len);
00576                      }
00577               } else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
00578                      variable_buf = (char *) emalloc(variable_len+1);
00579                      if (lpECB->GetServerVariable(lpECB->ConnID, *p, variable_buf, &variable_len)
00580                             && variable_buf[0]) {
00581                             php_register_variable(*p, variable_buf, track_vars_array TSRMLS_CC);
00582                      }
00583                      if (recorded_values) {
00584                             recorded_values[p-server_variables] = variable_buf;
00585                      } else {
00586                             efree(variable_buf);
00587                      }
00588               } else { /* for compatibility with Apache SAPIs */
00589                      php_register_variable(*p, "", track_vars_array TSRMLS_CC);
00590               }
00591               p++;
00592        }
00593 }
00594 
00595 
00596 static void sapi_isapi_register_server_variables(zval *track_vars_array TSRMLS_DC)
00597 {
00598        DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
00599        char *variable;
00600        char *strtok_buf = NULL;
00601        char *isapi_special_server_variables[NUM_SPECIAL_VARS];
00602        LPEXTENSION_CONTROL_BLOCK lpECB;
00603 
00604        lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context);
00605 
00606        /* Register the special ISAPI variables */
00607        memset(isapi_special_server_variables, 0, sizeof(isapi_special_server_variables));
00608        sapi_isapi_register_server_variables2(isapi_special_server_variable_names, lpECB, track_vars_array, isapi_special_server_variables TSRMLS_CC);
00609        if (SG(request_info).cookie_data) {
00610               php_register_variable("HTTP_COOKIE", SG(request_info).cookie_data, track_vars_array TSRMLS_CC);
00611        }
00612 
00613        /* Register the standard ISAPI variables */
00614        sapi_isapi_register_server_variables2(isapi_server_variable_names, lpECB, track_vars_array, NULL TSRMLS_CC);
00615 
00616        if (isapi_special_server_variables[SPECIAL_VAR_HTTPS]
00617               && (atoi(isapi_special_server_variables[SPECIAL_VAR_HTTPS])
00618               || !strcasecmp(isapi_special_server_variables[SPECIAL_VAR_HTTPS], "on"))
00619        ) {
00620               /* Register SSL ISAPI variables */
00621               sapi_isapi_register_server_variables2(isapi_secure_server_variable_names, lpECB, track_vars_array, NULL TSRMLS_CC);
00622        }
00623 
00624        if (isapi_special_server_variables[SPECIAL_VAR_HTTPS]) {
00625               efree(isapi_special_server_variables[SPECIAL_VAR_HTTPS]);
00626        }
00627 
00628 
00629 #ifdef WITH_ZEUS
00630        sapi_isapi_register_zeus_variables(lpECB, track_vars_array TSRMLS_CC);
00631 #else
00632        sapi_isapi_register_iis_variables(lpECB, track_vars_array TSRMLS_CC);
00633 #endif
00634 
00635        /* PHP_SELF support */
00636        if (isapi_special_server_variables[SPECIAL_VAR_PHP_SELF]) {
00637               php_register_variable("PHP_SELF", isapi_special_server_variables[SPECIAL_VAR_PHP_SELF], track_vars_array TSRMLS_CC);
00638               efree(isapi_special_server_variables[SPECIAL_VAR_PHP_SELF]);
00639        }
00640 
00641        if (isapi_special_server_variables[SPECIAL_VAR_ALL_HTTP]) {
00642               /* Register the internal bits of ALL_HTTP */
00643               variable = php_strtok_r(isapi_special_server_variables[SPECIAL_VAR_ALL_HTTP], "\r\n", &strtok_buf);
00644               while (variable) {
00645                      char *colon = strchr(variable, ':');
00646 
00647                      if (colon) {
00648                             char *value = colon+1;
00649 
00650                             while (*value==' ') {
00651                                    value++;
00652                             }
00653                             *colon = 0;
00654                             php_register_variable(variable, value, track_vars_array TSRMLS_CC);
00655                             *colon = ':';
00656                      }
00657                      variable = php_strtok_r(NULL, "\r\n", &strtok_buf);
00658               }
00659               efree(isapi_special_server_variables[SPECIAL_VAR_ALL_HTTP]);
00660        }
00661 }
00662 
00663 
00664 static sapi_module_struct isapi_sapi_module = {
00665        "isapi",                                         /* name */
00666        "ISAPI",                                         /* pretty name */
00667                                                                
00668        php_isapi_startup,                        /* startup */
00669        php_module_shutdown_wrapper,       /* shutdown */
00670 
00671        NULL,                                            /* activate */
00672        NULL,                                            /* deactivate */
00673 
00674        sapi_isapi_ub_write,               /* unbuffered write */
00675        NULL,                                            /* flush */
00676        NULL,                                            /* get uid */
00677        NULL,                                            /* getenv */
00678 
00679        php_error,                                       /* error handler */
00680 
00681        sapi_isapi_header_handler,         /* header handler */
00682        sapi_isapi_send_headers,           /* send headers handler */
00683        NULL,                                            /* send header handler */
00684 
00685        sapi_isapi_read_post,                     /* read POST data */
00686        sapi_isapi_read_cookies,           /* read Cookies */
00687 
00688        sapi_isapi_register_server_variables,     /* register server variables */
00689        NULL,                                            /* Log message */
00690        NULL,                                            /* Get request time */
00691        NULL,                                            /* Child terminate */
00692 
00693        STANDARD_SAPI_MODULE_PROPERTIES
00694 };
00695 
00696 
00697 BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pFilterVersion)
00698 {
00699        bFilterLoaded = 1;
00700        pFilterVersion->dwFilterVersion = HTTP_FILTER_REVISION;
00701        strcpy(pFilterVersion->lpszFilterDesc, isapi_sapi_module.pretty_name);
00702        pFilterVersion->dwFlags= (SF_NOTIFY_AUTHENTICATION | SF_NOTIFY_PREPROC_HEADERS);
00703        return TRUE;
00704 }
00705 
00706 
00707 DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificationType, LPVOID pvNotification)
00708 {
00709        TSRMLS_FETCH();
00710 
00711        switch (notificationType) {
00712               case SF_NOTIFY_PREPROC_HEADERS:
00713                      SG(request_info).auth_user = NULL;
00714                      SG(request_info).auth_password = NULL;
00715                      SG(request_info).auth_digest = NULL;
00716                      break;
00717               case SF_NOTIFY_AUTHENTICATION: {
00718                             char *auth_user = ((HTTP_FILTER_AUTHENT *) pvNotification)->pszUser;
00719                             char *auth_password = ((HTTP_FILTER_AUTHENT *) pvNotification)->pszPassword;
00720 
00721                             if (auth_user && auth_user[0]) {
00722                                    SG(request_info).auth_user = estrdup(auth_user);
00723                             }      
00724                             if (auth_password && auth_password[0]) {
00725                                    SG(request_info).auth_password = estrdup(auth_password);
00726                             }
00727                             return SF_STATUS_REQ_HANDLED_NOTIFICATION;
00728                      }
00729                      break;
00730        }
00731        return SF_STATUS_REQ_NEXT_NOTIFICATION;
00732 }
00733 
00734 
00735 static void init_request_info(LPEXTENSION_CONTROL_BLOCK lpECB TSRMLS_DC)
00736 {
00737        DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
00738        char static_variable_buf[ISAPI_SERVER_VAR_BUF_SIZE];
00739 #ifndef WITH_ZEUS
00740        HSE_URL_MAPEX_INFO humi;
00741 #endif
00742 
00743        SG(request_info).request_method = lpECB->lpszMethod;
00744        SG(request_info).query_string = lpECB->lpszQueryString;
00745        SG(request_info).request_uri = lpECB->lpszPathInfo;
00746        SG(request_info).content_type = lpECB->lpszContentType;
00747        SG(request_info).content_length = lpECB->cbTotalBytes;
00748        SG(sapi_headers).http_response_code = 200;  /* I think dwHttpStatusCode is invalid at this stage -RL */
00749        if (!bFilterLoaded) { /* we don't have valid ISAPI Filter information */
00750               SG(request_info).auth_user = SG(request_info).auth_password = SG(request_info).auth_digest = NULL;
00751        }
00752 
00753 #ifdef WITH_ZEUS
00754        /* PATH_TRANSLATED can contain extra PATH_INFO stuff after the
00755         * file being loaded, so we must use SCRIPT_FILENAME instead
00756         */
00757        if(lpECB->GetServerVariable(lpECB->ConnID, "SCRIPT_FILENAME", static_variable_buf, &variable_len)) {
00758               SG(request_info).path_translated = estrdup(static_variable_buf);
00759        } else 
00760 #else
00761        /* happily, IIS gives us SCRIPT_NAME which is correct (without PATH_INFO stuff)
00762           so we can just map that to the physical path and we have our filename */
00763 
00764        lpECB->GetServerVariable(lpECB->ConnID, "SCRIPT_NAME", static_variable_buf, &variable_len);
00765        if (lpECB->ServerSupportFunction(lpECB->ConnID, HSE_REQ_MAP_URL_TO_PATH_EX, static_variable_buf, &variable_len, (LPDWORD) &humi)) {
00766               SG(request_info).path_translated = estrdup(humi.lpszPath);
00767        } else 
00768 #endif
00769               /* if mapping fails, default to what the server tells us */
00770               SG(request_info).path_translated = estrdup(lpECB->lpszPathTranslated);
00771 
00772        /* some server configurations allow '..' to slip through in the
00773           translated path.   We'll just refuse to handle such a path. */
00774        if (strstr(SG(request_info).path_translated,"..")) {
00775               SG(sapi_headers).http_response_code = 404;
00776               efree(SG(request_info).path_translated);
00777               SG(request_info).path_translated = NULL;
00778        }
00779 }
00780 
00781 
00782 static void php_isapi_report_exception(char *message, int message_len TSRMLS_DC)
00783 {
00784        if (!SG(headers_sent)) {
00785               HSE_SEND_HEADER_EX_INFO header_info;
00786               LPEXTENSION_CONTROL_BLOCK lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context);
00787 
00788               header_info.pszStatus = "500 Internal Server Error";
00789               header_info.cchStatus = strlen(header_info.pszStatus);
00790               header_info.pszHeader = "Content-Type: text/html\r\n\r\n";
00791               header_info.cchHeader = strlen(header_info.pszHeader);
00792 
00793               lpECB->dwHttpStatusCode = 500;
00794               lpECB->ServerSupportFunction(lpECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER_EX, &header_info, NULL, NULL);
00795               SG(headers_sent)=1;
00796        }
00797        sapi_isapi_ub_write(message, message_len TSRMLS_CC);
00798 }
00799 
00800 
00801 BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer)
00802 {
00803        pVer->dwExtensionVersion = HSE_VERSION;
00804 #ifdef WITH_ZEUS
00805        strncpy( pVer->lpszExtensionDesc, isapi_sapi_module.name, HSE_MAX_EXT_DLL_NAME_LEN);
00806 #else
00807        lstrcpyn(pVer->lpszExtensionDesc, isapi_sapi_module.name, HSE_MAX_EXT_DLL_NAME_LEN);
00808 #endif
00809        return TRUE;
00810 }
00811 
00812 
00813 static void my_endthread()
00814 {
00815 #ifdef PHP_WIN32
00816        if (bTerminateThreadsOnError) {
00817               _endthread();
00818        }
00819 #endif
00820 }
00821 
00822 #ifdef PHP_WIN32
00823 /* ep is accessible only in the context of the __except expression,
00824  * so we have to call this function to obtain it.
00825  */
00826 BOOL exceptionhandler(LPEXCEPTION_POINTERS *e, LPEXCEPTION_POINTERS ep)
00827 {
00828        *e=ep;
00829        return TRUE;
00830 }
00831 #endif
00832 
00833 DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB)
00834 {
00835        zend_file_handle file_handle;
00836        zend_bool stack_overflown=0;
00837        int retval = FAILURE;
00838 #ifdef PHP_ENABLE_SEH
00839        LPEXCEPTION_POINTERS e;
00840 #endif
00841        TSRMLS_FETCH();
00842 
00843        zend_first_try {
00844 #ifdef PHP_ENABLE_SEH
00845               __try {
00846 #endif
00847                      init_request_info(lpECB TSRMLS_CC);
00848                      SG(server_context) = lpECB;
00849 
00850                      php_request_startup(TSRMLS_C);
00851 
00852                      file_handle.filename = SG(request_info).path_translated;
00853                      file_handle.free_filename = 0;
00854                      file_handle.type = ZEND_HANDLE_FILENAME;
00855                      file_handle.opened_path = NULL;
00856 
00857                      /* open the script here so we can 404 if it fails */
00858                      if (file_handle.filename)
00859                             retval = php_fopen_primary_script(&file_handle TSRMLS_CC);
00860 
00861                      if (!file_handle.filename || retval == FAILURE) {
00862                             SG(sapi_headers).http_response_code = 404;
00863                             PUTS("No input file specified.\n");
00864                      } else {
00865                             php_execute_script(&file_handle TSRMLS_CC);
00866                      }
00867 
00868                      if (SG(request_info).cookie_data) {
00869                             efree(SG(request_info).cookie_data);
00870                      }
00871                      if (SG(request_info).path_translated)
00872                             efree(SG(request_info).path_translated);
00873 #ifdef PHP_ENABLE_SEH
00874               } __except(exceptionhandler(&e, GetExceptionInformation())) {
00875                      char buf[1024];
00876                      if (_exception_code()==EXCEPTION_STACK_OVERFLOW) {
00877                             LPBYTE lpPage;
00878                             static SYSTEM_INFO si;
00879                             static MEMORY_BASIC_INFORMATION mi;
00880                             static DWORD dwOldProtect;
00881 
00882                             GetSystemInfo(&si);
00883 
00884                             /* Get page ESP is pointing to */
00885                             _asm mov lpPage, esp;
00886 
00887                             /* Get stack allocation base */
00888                             VirtualQuery(lpPage, &mi, sizeof(mi));
00889 
00890                             /* Go to the page below the current page */
00891                             lpPage = (LPBYTE) (mi.BaseAddress) - si.dwPageSize;
00892 
00893                             /* Free pages below current page */
00894                             if (!VirtualFree(mi.AllocationBase, (LPBYTE)lpPage - (LPBYTE) mi.AllocationBase, MEM_DECOMMIT)) {
00895                                    _endthread();
00896                             }
00897 
00898                             /* Restore the guard page */
00899                             if (!VirtualProtect(lpPage, si.dwPageSize, PAGE_GUARD | PAGE_READWRITE, &dwOldProtect)) {
00900                                    _endthread();
00901                             }
00902 
00903                             CG(unclean_shutdown)=1;
00904                             _snprintf(buf, sizeof(buf)-1,"PHP has encountered a Stack overflow");
00905                             php_isapi_report_exception(buf, strlen(buf) TSRMLS_CC);
00906                      } else if (_exception_code()==EXCEPTION_ACCESS_VIOLATION) {
00907                             _snprintf(buf, sizeof(buf)-1,"PHP has encountered an Access Violation at %p", e->ExceptionRecord->ExceptionAddress);
00908                             php_isapi_report_exception(buf, strlen(buf) TSRMLS_CC);
00909                             my_endthread();
00910                      } else {
00911                             _snprintf(buf, sizeof(buf)-1,"PHP has encountered an Unhandled Exception Code %d at %p", e->ExceptionRecord->ExceptionCode , e->ExceptionRecord->ExceptionAddress);
00912                             php_isapi_report_exception(buf, strlen(buf) TSRMLS_CC);
00913                             my_endthread();
00914                      }
00915               }
00916 #endif
00917 #ifdef PHP_ENABLE_SEH
00918               __try {
00919                      php_request_shutdown(NULL);
00920               } __except(EXCEPTION_EXECUTE_HANDLER) {
00921                      my_endthread();
00922               }
00923 #else
00924               php_request_shutdown(NULL);
00925 #endif
00926        } zend_catch {
00927               zend_try {
00928                      php_request_shutdown(NULL);
00929               } zend_end_try();
00930               return HSE_STATUS_ERROR;
00931        } zend_end_try();
00932 
00933        return HSE_STATUS_SUCCESS;
00934 }
00935 
00936 
00937 
00938 __declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
00939 {
00940        switch (fdwReason) {
00941               case DLL_PROCESS_ATTACH:
00942 #ifdef WITH_ZEUS
00943                      tsrm_startup(128, 1, TSRM_ERROR_LEVEL_CORE, "TSRM.log");
00944 #else
00945                      tsrm_startup(128, 1, TSRM_ERROR_LEVEL_CORE, "C:\\TSRM.log");
00946 #endif
00947                      sapi_startup(&isapi_sapi_module);
00948                      if (isapi_sapi_module.startup) {
00949                             isapi_sapi_module.startup(&sapi_module);
00950                      }
00951                      break;
00952               case DLL_THREAD_ATTACH:
00953                      break;
00954               case DLL_THREAD_DETACH:
00955                      ts_free_thread();
00956                      break;
00957               case DLL_PROCESS_DETACH:
00958                      if (isapi_sapi_module.shutdown) {
00959                             isapi_sapi_module.shutdown(&sapi_module);
00960                      }
00961                      sapi_shutdown();
00962                      tsrm_shutdown();
00963                      break;
00964        }
00965        return TRUE;
00966 }
00967 
00968 /*
00969  * Local variables:
00970  * tab-width: 4
00971  * c-basic-offset: 4
00972  * End:
00973  */