Return to php5isapi.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / sapi / isapi |
1.1 ! misho 1: /* ! 2: +----------------------------------------------------------------------+ ! 3: | PHP Version 5 | ! 4: +----------------------------------------------------------------------+ ! 5: | Copyright (c) 1997-2012 The PHP Group | ! 6: +----------------------------------------------------------------------+ ! 7: | This source file is subject to version 3.01 of the PHP license, | ! 8: | that is bundled with this package in the file LICENSE, and is | ! 9: | available through the world-wide-web at the following url: | ! 10: | http://www.php.net/license/3_01.txt | ! 11: | If you did not receive a copy of the PHP license and are unable to | ! 12: | obtain it through the world-wide-web, please send a note to | ! 13: | license@php.net so we can mail you a copy immediately. | ! 14: +----------------------------------------------------------------------+ ! 15: | Authors: Zeev Suraski <zeev@zend.com> | ! 16: | Ben Mansell <ben@zeus.com> (Zeus Support) | ! 17: +----------------------------------------------------------------------+ ! 18: */ ! 19: /* $Id: php5isapi.c 321634 2012-01-01 13:15:04Z felipe $ */ ! 20: ! 21: #include "php.h" ! 22: #include <httpext.h> ! 23: #include <httpfilt.h> ! 24: #include <httpext.h> ! 25: #include "php_main.h" ! 26: #include "SAPI.h" ! 27: #include "php_globals.h" ! 28: #include "ext/standard/info.h" ! 29: #include "php_variables.h" ! 30: #include "php_ini.h" ! 31: ! 32: #ifdef PHP_WIN32 ! 33: # include <process.h> ! 34: #else ! 35: # define __try ! 36: # define __except(val) ! 37: # define __declspec(foo) ! 38: #endif ! 39: ! 40: ! 41: #ifdef WITH_ZEUS ! 42: # include "httpext.h" ! 43: # include <errno.h> ! 44: # define GetLastError() errno ! 45: #endif ! 46: ! 47: #ifdef PHP_WIN32 ! 48: #define PHP_ENABLE_SEH ! 49: #endif ! 50: ! 51: /* ! 52: uncomment the following lines to turn off ! 53: exception trapping when running under a debugger ! 54: ! 55: #ifdef _DEBUG ! 56: #undef PHP_ENABLE_SEH ! 57: #endif ! 58: */ ! 59: ! 60: #define MAX_STATUS_LENGTH sizeof("xxxx LONGEST POSSIBLE STATUS DESCRIPTION") ! 61: #define ISAPI_SERVER_VAR_BUF_SIZE 1024 ! 62: #define ISAPI_POST_DATA_BUF 1024 ! 63: ! 64: static zend_bool bFilterLoaded=0; ! 65: static zend_bool bTerminateThreadsOnError=0; ! 66: ! 67: static char *isapi_special_server_variable_names[] = { ! 68: "ALL_HTTP", ! 69: "HTTPS", ! 70: #ifndef WITH_ZEUS ! 71: "SCRIPT_NAME", ! 72: #endif ! 73: NULL ! 74: }; ! 75: ! 76: #define NUM_SPECIAL_VARS (sizeof(isapi_special_server_variable_names)/sizeof(char *)) ! 77: #define SPECIAL_VAR_ALL_HTTP 0 ! 78: #define SPECIAL_VAR_HTTPS 1 ! 79: #define SPECIAL_VAR_PHP_SELF 2 ! 80: ! 81: static char *isapi_server_variable_names[] = { ! 82: "AUTH_PASSWORD", ! 83: "AUTH_TYPE", ! 84: "AUTH_USER", ! 85: "CONTENT_LENGTH", ! 86: "CONTENT_TYPE", ! 87: "PATH_TRANSLATED", ! 88: "QUERY_STRING", ! 89: "REMOTE_ADDR", ! 90: "REMOTE_HOST", ! 91: "REMOTE_USER", ! 92: "REQUEST_METHOD", ! 93: "SERVER_NAME", ! 94: "SERVER_PORT", ! 95: "SERVER_PROTOCOL", ! 96: "SERVER_SOFTWARE", ! 97: #ifndef WITH_ZEUS ! 98: "APPL_MD_PATH", ! 99: "APPL_PHYSICAL_PATH", ! 100: "INSTANCE_ID", ! 101: "INSTANCE_META_PATH", ! 102: "LOGON_USER", ! 103: "REQUEST_URI", ! 104: "URL", ! 105: #else ! 106: "DOCUMENT_ROOT", ! 107: #endif ! 108: NULL ! 109: }; ! 110: ! 111: ! 112: static char *isapi_secure_server_variable_names[] = { ! 113: "CERT_COOKIE", ! 114: "CERT_FLAGS", ! 115: "CERT_ISSUER", ! 116: "CERT_KEYSIZE", ! 117: "CERT_SECRETKEYSIZE", ! 118: "CERT_SERIALNUMBER", ! 119: "CERT_SERVER_ISSUER", ! 120: "CERT_SERVER_SUBJECT", ! 121: "CERT_SUBJECT", ! 122: "HTTPS_KEYSIZE", ! 123: "HTTPS_SECRETKEYSIZE", ! 124: "HTTPS_SERVER_ISSUER", ! 125: "HTTPS_SERVER_SUBJECT", ! 126: "SERVER_PORT_SECURE", ! 127: #ifdef WITH_ZEUS ! 128: "SSL_CLIENT_CN", ! 129: "SSL_CLIENT_EMAIL", ! 130: "SSL_CLIENT_OU", ! 131: "SSL_CLIENT_O", ! 132: "SSL_CLIENT_L", ! 133: "SSL_CLIENT_ST", ! 134: "SSL_CLIENT_C", ! 135: "SSL_CLIENT_I_CN", ! 136: "SSL_CLIENT_I_EMAIL", ! 137: "SSL_CLIENT_I_OU", ! 138: "SSL_CLIENT_I_O", ! 139: "SSL_CLIENT_I_L", ! 140: "SSL_CLIENT_I_ST", ! 141: "SSL_CLIENT_I_C", ! 142: #endif ! 143: NULL ! 144: }; ! 145: ! 146: ! 147: static void php_info_isapi(ZEND_MODULE_INFO_FUNC_ARGS) ! 148: { ! 149: char **p; ! 150: char variable_buf[ISAPI_SERVER_VAR_BUF_SIZE]; ! 151: DWORD variable_len; ! 152: char **all_variables[] = { ! 153: isapi_server_variable_names, ! 154: isapi_special_server_variable_names, ! 155: isapi_secure_server_variable_names, ! 156: NULL ! 157: }; ! 158: char ***server_variable_names; ! 159: LPEXTENSION_CONTROL_BLOCK lpECB; ! 160: ! 161: lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context); ! 162: ! 163: php_info_print_table_start(); ! 164: php_info_print_table_header(2, "Server Variable", "Value"); ! 165: server_variable_names = all_variables; ! 166: while (*server_variable_names) { ! 167: p = *server_variable_names; ! 168: while (*p) { ! 169: variable_len = ISAPI_SERVER_VAR_BUF_SIZE; ! 170: if (lpECB->GetServerVariable(lpECB->ConnID, *p, variable_buf, &variable_len) ! 171: && variable_buf[0]) { ! 172: php_info_print_table_row(2, *p, variable_buf); ! 173: } else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { ! 174: char *tmp_variable_buf; ! 175: ! 176: tmp_variable_buf = (char *) emalloc(variable_len); ! 177: if (lpECB->GetServerVariable(lpECB->ConnID, *p, tmp_variable_buf, &variable_len) ! 178: && variable_buf[0]) { ! 179: php_info_print_table_row(2, *p, tmp_variable_buf); ! 180: } ! 181: efree(tmp_variable_buf); ! 182: } ! 183: p++; ! 184: } ! 185: server_variable_names++; ! 186: } ! 187: php_info_print_table_end(); ! 188: } ! 189: ! 190: ! 191: static zend_module_entry php_isapi_module = { ! 192: STANDARD_MODULE_HEADER, ! 193: "ISAPI", ! 194: NULL, ! 195: NULL, ! 196: NULL, ! 197: NULL, ! 198: NULL, ! 199: php_info_isapi, ! 200: NULL, ! 201: STANDARD_MODULE_PROPERTIES ! 202: }; ! 203: ! 204: ! 205: static int sapi_isapi_ub_write(const char *str, uint str_length TSRMLS_DC) ! 206: { ! 207: DWORD num_bytes = str_length; ! 208: LPEXTENSION_CONTROL_BLOCK ecb; ! 209: ! 210: ecb = (LPEXTENSION_CONTROL_BLOCK) SG(server_context); ! 211: if (ecb->WriteClient(ecb->ConnID, (char *) str, &num_bytes, HSE_IO_SYNC) == FALSE) { ! 212: php_handle_aborted_connection(); ! 213: } ! 214: return num_bytes; ! 215: } ! 216: ! 217: ! 218: static int sapi_isapi_header_handler(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC) ! 219: { ! 220: return SAPI_HEADER_ADD; ! 221: } ! 222: ! 223: ! 224: ! 225: static void accumulate_header_length(sapi_header_struct *sapi_header, uint *total_length TSRMLS_DC) ! 226: { ! 227: *total_length += sapi_header->header_len+2; ! 228: } ! 229: ! 230: ! 231: static void concat_header(sapi_header_struct *sapi_header, char **combined_headers_ptr TSRMLS_DC) ! 232: { ! 233: memcpy(*combined_headers_ptr, sapi_header->header, sapi_header->header_len); ! 234: *combined_headers_ptr += sapi_header->header_len; ! 235: **combined_headers_ptr = '\r'; ! 236: (*combined_headers_ptr)++; ! 237: **combined_headers_ptr = '\n'; ! 238: (*combined_headers_ptr)++; ! 239: } ! 240: ! 241: ! 242: static int sapi_isapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) ! 243: { ! 244: uint total_length = 2; /* account for the trailing \r\n */ ! 245: char *combined_headers, *combined_headers_ptr; ! 246: LPEXTENSION_CONTROL_BLOCK lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context); ! 247: HSE_SEND_HEADER_EX_INFO header_info; ! 248: sapi_header_struct default_content_type; ! 249: char *status_buf = NULL; ! 250: ! 251: /* Obtain headers length */ ! 252: if (SG(sapi_headers).send_default_content_type) { ! 253: sapi_get_default_content_type_header(&default_content_type TSRMLS_CC); ! 254: accumulate_header_length(&default_content_type, (void *) &total_length TSRMLS_CC); ! 255: } ! 256: zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t) accumulate_header_length, (void *) &total_length TSRMLS_CC); ! 257: ! 258: /* Generate headers */ ! 259: combined_headers = (char *) emalloc(total_length+1); ! 260: combined_headers_ptr = combined_headers; ! 261: if (SG(sapi_headers).send_default_content_type) { ! 262: concat_header(&default_content_type, (void *) &combined_headers_ptr TSRMLS_CC); ! 263: sapi_free_header(&default_content_type); /* we no longer need it */ ! 264: } ! 265: zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t) concat_header, (void *) &combined_headers_ptr TSRMLS_CC); ! 266: *combined_headers_ptr++ = '\r'; ! 267: *combined_headers_ptr++ = '\n'; ! 268: *combined_headers_ptr = 0; ! 269: ! 270: switch (SG(sapi_headers).http_response_code) { ! 271: case 200: ! 272: header_info.pszStatus = "200 OK"; ! 273: break; ! 274: case 302: ! 275: header_info.pszStatus = "302 Moved Temporarily"; ! 276: break; ! 277: case 401: ! 278: header_info.pszStatus = "401 Authorization Required"; ! 279: break; ! 280: default: { ! 281: const char *sline = SG(sapi_headers).http_status_line; ! 282: int sline_len; ! 283: ! 284: /* httpd requires that r->status_line is set to the first digit of ! 285: * the status-code: */ ! 286: if (sline && ((sline_len = strlen(sline)) > 12) && strncmp(sline, "HTTP/1.", 7) == 0 && sline[8] == ' ') { ! 287: if ((sline_len - 9) > MAX_STATUS_LENGTH) { ! 288: status_buf = estrndup(sline + 9, MAX_STATUS_LENGTH); ! 289: } else { ! 290: status_buf = estrndup(sline + 9, sline_len - 9); ! 291: } ! 292: } else { ! 293: status_buf = emalloc(MAX_STATUS_LENGTH + 1); ! 294: snprintf(status_buf, MAX_STATUS_LENGTH, "%d Undescribed", SG(sapi_headers).http_response_code); ! 295: } ! 296: header_info.pszStatus = status_buf; ! 297: break; ! 298: } ! 299: } ! 300: header_info.cchStatus = strlen(header_info.pszStatus); ! 301: header_info.pszHeader = combined_headers; ! 302: header_info.cchHeader = total_length; ! 303: header_info.fKeepConn = FALSE; ! 304: lpECB->dwHttpStatusCode = SG(sapi_headers).http_response_code; ! 305: ! 306: lpECB->ServerSupportFunction(lpECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER_EX, &header_info, NULL, NULL); ! 307: ! 308: efree(combined_headers); ! 309: if (status_buf) { ! 310: efree(status_buf); ! 311: } ! 312: return SAPI_HEADER_SENT_SUCCESSFULLY; ! 313: } ! 314: ! 315: ! 316: static int php_isapi_startup(sapi_module_struct *sapi_module) ! 317: { ! 318: if (php_module_startup(sapi_module, &php_isapi_module, 1)==FAILURE) { ! 319: return FAILURE; ! 320: } else { ! 321: bTerminateThreadsOnError = (zend_bool) INI_INT("isapi.terminate_threads_on_error"); ! 322: return SUCCESS; ! 323: } ! 324: } ! 325: ! 326: ! 327: static int sapi_isapi_read_post(char *buffer, uint count_bytes TSRMLS_DC) ! 328: { ! 329: LPEXTENSION_CONTROL_BLOCK lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context); ! 330: DWORD read_from_buf=0; ! 331: DWORD read_from_input=0; ! 332: DWORD total_read=0; ! 333: ! 334: if ((DWORD) SG(read_post_bytes) < lpECB->cbAvailable) { ! 335: read_from_buf = MIN(lpECB->cbAvailable-SG(read_post_bytes), count_bytes); ! 336: memcpy(buffer, lpECB->lpbData+SG(read_post_bytes), read_from_buf); ! 337: total_read += read_from_buf; ! 338: } ! 339: if (read_from_buf<count_bytes ! 340: && (SG(read_post_bytes)+read_from_buf) < lpECB->cbTotalBytes) { ! 341: DWORD cbRead=0, cbSize; ! 342: ! 343: read_from_input = MIN(count_bytes-read_from_buf, lpECB->cbTotalBytes-SG(read_post_bytes)-read_from_buf); ! 344: while (cbRead < read_from_input) { ! 345: cbSize = read_from_input - cbRead; ! 346: if (!lpECB->ReadClient(lpECB->ConnID, buffer+read_from_buf+cbRead, &cbSize) || cbSize==0) { ! 347: break; ! 348: } ! 349: cbRead += cbSize; ! 350: } ! 351: total_read += cbRead; ! 352: } ! 353: return total_read; ! 354: } ! 355: ! 356: ! 357: static char *sapi_isapi_read_cookies(TSRMLS_D) ! 358: { ! 359: LPEXTENSION_CONTROL_BLOCK lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context); ! 360: char variable_buf[ISAPI_SERVER_VAR_BUF_SIZE]; ! 361: DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE; ! 362: ! 363: if (lpECB->GetServerVariable(lpECB->ConnID, "HTTP_COOKIE", variable_buf, &variable_len)) { ! 364: return estrndup(variable_buf, variable_len); ! 365: } else if (GetLastError()==ERROR_INSUFFICIENT_BUFFER) { ! 366: char *tmp_variable_buf = (char *) emalloc(variable_len+1); ! 367: ! 368: if (lpECB->GetServerVariable(lpECB->ConnID, "HTTP_COOKIE", tmp_variable_buf, &variable_len)) { ! 369: tmp_variable_buf[variable_len] = 0; ! 370: return tmp_variable_buf; ! 371: } else { ! 372: efree(tmp_variable_buf); ! 373: } ! 374: } ! 375: return STR_EMPTY_ALLOC(); ! 376: } ! 377: ! 378: ! 379: #ifdef WITH_ZEUS ! 380: ! 381: static void sapi_isapi_register_zeus_ssl_variables(LPEXTENSION_CONTROL_BLOCK lpECB, zval *track_vars_array TSRMLS_DC) ! 382: { ! 383: char static_variable_buf[ISAPI_SERVER_VAR_BUF_SIZE]; ! 384: DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE; ! 385: char static_cons_buf[ISAPI_SERVER_VAR_BUF_SIZE]; ! 386: /* ! 387: * We need to construct the /C=.../ST=... ! 388: * DN's for SSL_CLIENT_DN and SSL_CLIENT_I_DN ! 389: */ ! 390: strcpy( static_cons_buf, "/C=" ); ! 391: if( lpECB->GetServerVariable( lpECB->ConnID, "SSL_CLIENT_C", static_variable_buf, &variable_len ) && static_variable_buf[0] ) { ! 392: strlcat( static_cons_buf, static_variable_buf, ISAPI_SERVER_VAR_BUF_SIZE); ! 393: } ! 394: strlcat( static_cons_buf, "/ST=", ISAPI_SERVER_VAR_BUF_SIZE); ! 395: variable_len = ISAPI_SERVER_VAR_BUF_SIZE; ! 396: if( lpECB->GetServerVariable( lpECB->ConnID, "SSL_CLIENT_ST", static_variable_buf, &variable_len ) && static_variable_buf[0] ) { ! 397: strlcat( static_cons_buf, static_variable_buf, ISAPI_SERVER_VAR_BUF_SIZE ); ! 398: } ! 399: php_register_variable( "SSL_CLIENT_DN", static_cons_buf, track_vars_array TSRMLS_CC ); ! 400: ! 401: strcpy( static_cons_buf, "/C=" ); ! 402: variable_len = ISAPI_SERVER_VAR_BUF_SIZE; ! 403: if( lpECB->GetServerVariable( lpECB->ConnID, "SSL_CLIENT_I_C", static_variable_buf, &variable_len ) && static_variable_buf[0] ) { ! 404: strlcat( static_cons_buf, static_variable_buf, ISAPI_SERVER_VAR_BUF_SIZE ); ! 405: } ! 406: strlcat( static_cons_buf, "/ST=", ISAPI_SERVER_VAR_BUF_SIZE); ! 407: variable_len = ISAPI_SERVER_VAR_BUF_SIZE; ! 408: if( lpECB->GetServerVariable( lpECB->ConnID, "SSL_CLIENT_I_ST", static_variable_buf, &variable_len ) && static_variable_buf[0] ) { ! 409: strlcat( static_cons_buf, static_variable_buf, ISAPI_SERVER_VAR_BUF_SIZE ); ! 410: } ! 411: php_register_variable( "SSL_CLIENT_I_DN", static_cons_buf, track_vars_array TSRMLS_CC ); ! 412: } ! 413: ! 414: static void sapi_isapi_register_zeus_variables(LPEXTENSION_CONTROL_BLOCK lpECB, zval *track_vars_array TSRMLS_DC) ! 415: { ! 416: char static_variable_buf[ISAPI_SERVER_VAR_BUF_SIZE]; ! 417: DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE; ! 418: DWORD scriptname_len = ISAPI_SERVER_VAR_BUF_SIZE; ! 419: DWORD pathinfo_len = 0; ! 420: char *strtok_buf = NULL; ! 421: ! 422: /* Get SCRIPT_NAME, we use this to work out which bit of the URL ! 423: * belongs in PHP's version of PATH_INFO ! 424: */ ! 425: lpECB->GetServerVariable(lpECB->ConnID, "SCRIPT_NAME", static_variable_buf, &scriptname_len); ! 426: ! 427: /* Adjust Zeus' version of PATH_INFO, set PHP_SELF, ! 428: * and generate REQUEST_URI ! 429: */ ! 430: if ( lpECB->GetServerVariable(lpECB->ConnID, "PATH_INFO", static_variable_buf, &variable_len) && static_variable_buf[0] ) { ! 431: ! 432: /* PHP_SELF is just PATH_INFO */ ! 433: php_register_variable( "PHP_SELF", static_variable_buf, track_vars_array TSRMLS_CC ); ! 434: ! 435: /* Chop off filename to get just the 'real' PATH_INFO' */ ! 436: pathinfo_len = variable_len - scriptname_len; ! 437: php_register_variable( "PATH_INFO", static_variable_buf + scriptname_len - 1, track_vars_array TSRMLS_CC ); ! 438: /* append query string to give url... extra byte for '?' */ ! 439: if ( strlen(lpECB->lpszQueryString) + variable_len + 1 < ISAPI_SERVER_VAR_BUF_SIZE ) { ! 440: /* append query string only if it is present... */ ! 441: if ( strlen(lpECB->lpszQueryString) ) { ! 442: static_variable_buf[ variable_len - 1 ] = '?'; ! 443: strcpy( static_variable_buf + variable_len, lpECB->lpszQueryString ); ! 444: } ! 445: php_register_variable( "URL", static_variable_buf, track_vars_array TSRMLS_CC ); ! 446: php_register_variable( "REQUEST_URI", static_variable_buf, track_vars_array TSRMLS_CC ); ! 447: } ! 448: } ! 449: ! 450: /* Get and adjust PATH_TRANSLATED to what PHP wants */ ! 451: variable_len = ISAPI_SERVER_VAR_BUF_SIZE; ! 452: if ( lpECB->GetServerVariable(lpECB->ConnID, "PATH_TRANSLATED", static_variable_buf, &variable_len) && static_variable_buf[0] ) { ! 453: static_variable_buf[ variable_len - pathinfo_len - 1 ] = '\0'; ! 454: php_register_variable( "PATH_TRANSLATED", static_variable_buf, track_vars_array TSRMLS_CC ); ! 455: } ! 456: ! 457: /* Bring in the AUTHENTICATION stuff as needed */ ! 458: variable_len = ISAPI_SERVER_VAR_BUF_SIZE; ! 459: if ( lpECB->GetServerVariable(lpECB->ConnID, "AUTH_USER", static_variable_buf, &variable_len) && static_variable_buf[0] ) { ! 460: php_register_variable( "PHP_AUTH_USER", static_variable_buf, track_vars_array TSRMLS_CC ); ! 461: } ! 462: variable_len = ISAPI_SERVER_VAR_BUF_SIZE; ! 463: if ( lpECB->GetServerVariable(lpECB->ConnID, "AUTH_PASSWORD", static_variable_buf, &variable_len) && static_variable_buf[0] ) { ! 464: php_register_variable( "PHP_AUTH_PW", static_variable_buf, track_vars_array TSRMLS_CC ); ! 465: } ! 466: variable_len = ISAPI_SERVER_VAR_BUF_SIZE; ! 467: if ( lpECB->GetServerVariable(lpECB->ConnID, "AUTH_TYPE", static_variable_buf, &variable_len) && static_variable_buf[0] ) { ! 468: php_register_variable( "AUTH_TYPE", static_variable_buf, track_vars_array TSRMLS_CC ); ! 469: } ! 470: ! 471: /* And now, for the SSL variables (if applicable) */ ! 472: variable_len = ISAPI_SERVER_VAR_BUF_SIZE; ! 473: if ( lpECB->GetServerVariable(lpECB->ConnID, "CERT_COOKIE", static_variable_buf, &variable_len) && static_variable_buf[0] ) { ! 474: sapi_isapi_register_zeus_ssl_variables( lpECB, track_vars_array TSRMLS_CC ); ! 475: } ! 476: /* Copy some of the variables we need to meet Apache specs */ ! 477: variable_len = ISAPI_SERVER_VAR_BUF_SIZE; ! 478: if ( lpECB->GetServerVariable(lpECB->ConnID, "SERVER_SOFTWARE", static_variable_buf, &variable_len) && static_variable_buf[0] ) { ! 479: php_register_variable( "SERVER_SIGNATURE", static_variable_buf, track_vars_array TSRMLS_CC ); ! 480: } ! 481: } ! 482: #else ! 483: ! 484: static void sapi_isapi_register_iis_variables(LPEXTENSION_CONTROL_BLOCK lpECB, zval *track_vars_array TSRMLS_DC) ! 485: { ! 486: char static_variable_buf[ISAPI_SERVER_VAR_BUF_SIZE]; ! 487: char path_info_buf[ISAPI_SERVER_VAR_BUF_SIZE]; ! 488: DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE; ! 489: DWORD scriptname_len = ISAPI_SERVER_VAR_BUF_SIZE; ! 490: DWORD pathinfo_len = 0; ! 491: HSE_URL_MAPEX_INFO humi; ! 492: ! 493: /* Get SCRIPT_NAME, we use this to work out which bit of the URL ! 494: * belongs in PHP's version of PATH_INFO. SCRIPT_NAME also becomes PHP_SELF. ! 495: */ ! 496: lpECB->GetServerVariable(lpECB->ConnID, "SCRIPT_NAME", static_variable_buf, &scriptname_len); ! 497: php_register_variable("SCRIPT_FILENAME", SG(request_info).path_translated, track_vars_array TSRMLS_CC); ! 498: ! 499: /* Adjust IIS' version of PATH_INFO, set PHP_SELF, ! 500: * and generate REQUEST_URI ! 501: * Get and adjust PATH_TRANSLATED to what PHP wants ! 502: */ ! 503: if ( lpECB->GetServerVariable(lpECB->ConnID, "PATH_INFO", static_variable_buf, &variable_len) && static_variable_buf[0] ) { ! 504: ! 505: /* Chop off filename to get just the 'real' PATH_INFO' */ ! 506: php_register_variable( "ORIG_PATH_INFO", static_variable_buf, track_vars_array TSRMLS_CC ); ! 507: pathinfo_len = variable_len - scriptname_len; ! 508: strncpy(path_info_buf, static_variable_buf + scriptname_len - 1, sizeof(path_info_buf)-1); ! 509: php_register_variable( "PATH_INFO", path_info_buf, track_vars_array TSRMLS_CC ); ! 510: /* append query string to give url... extra byte for '?' */ ! 511: if ( strlen(lpECB->lpszQueryString) + variable_len + 1 < ISAPI_SERVER_VAR_BUF_SIZE ) { ! 512: /* append query string only if it is present... */ ! 513: if ( strlen(lpECB->lpszQueryString) ) { ! 514: static_variable_buf[ variable_len - 1 ] = '?'; ! 515: strcpy( static_variable_buf + variable_len, lpECB->lpszQueryString ); ! 516: } ! 517: php_register_variable( "URL", static_variable_buf, track_vars_array TSRMLS_CC ); ! 518: php_register_variable( "REQUEST_URI", static_variable_buf, track_vars_array TSRMLS_CC ); ! 519: } ! 520: variable_len = ISAPI_SERVER_VAR_BUF_SIZE; ! 521: if ( lpECB->GetServerVariable(lpECB->ConnID, "PATH_TRANSLATED", static_variable_buf, &variable_len) && static_variable_buf[0] ) { ! 522: php_register_variable( "ORIG_PATH_TRANSLATED", static_variable_buf, track_vars_array TSRMLS_CC ); ! 523: } ! 524: if (lpECB->ServerSupportFunction(lpECB->ConnID, HSE_REQ_MAP_URL_TO_PATH_EX, path_info_buf, &pathinfo_len, (LPDWORD) &humi)) { ! 525: /* Remove trailing \ */ ! 526: if (humi.lpszPath[variable_len-2] == '\\') { ! 527: humi.lpszPath[variable_len-2] = 0; ! 528: } ! 529: php_register_variable("PATH_TRANSLATED", humi.lpszPath, track_vars_array TSRMLS_CC); ! 530: } ! 531: } ! 532: ! 533: static_variable_buf[0] = '/'; ! 534: static_variable_buf[1] = 0; ! 535: variable_len = 2; ! 536: if (lpECB->ServerSupportFunction(lpECB->ConnID, HSE_REQ_MAP_URL_TO_PATH_EX, static_variable_buf, &variable_len, (LPDWORD) &humi)) { ! 537: /* Remove trailing \ */ ! 538: if (humi.lpszPath[variable_len-2] == '\\') { ! 539: humi.lpszPath[variable_len-2] = 0; ! 540: } ! 541: php_register_variable("DOCUMENT_ROOT", humi.lpszPath, track_vars_array TSRMLS_CC); ! 542: } ! 543: ! 544: if (!SG(request_info).auth_user || !SG(request_info).auth_password || ! 545: !SG(request_info).auth_user[0] || !SG(request_info).auth_password[0]) { ! 546: variable_len = ISAPI_SERVER_VAR_BUF_SIZE; ! 547: if (lpECB->GetServerVariable(lpECB->ConnID, "HTTP_AUTHORIZATION", static_variable_buf, &variable_len) ! 548: && static_variable_buf[0]) { ! 549: php_handle_auth_data(static_variable_buf TSRMLS_CC); ! 550: } ! 551: } ! 552: ! 553: if (SG(request_info).auth_user) { ! 554: php_register_variable("PHP_AUTH_USER", SG(request_info).auth_user, track_vars_array TSRMLS_CC ); ! 555: } ! 556: if (SG(request_info).auth_password) { ! 557: php_register_variable("PHP_AUTH_PW", SG(request_info).auth_password, track_vars_array TSRMLS_CC ); ! 558: } ! 559: } ! 560: #endif ! 561: ! 562: static void sapi_isapi_register_server_variables2(char **server_variables, LPEXTENSION_CONTROL_BLOCK lpECB, zval *track_vars_array, char **recorded_values TSRMLS_DC) ! 563: { ! 564: char **p=server_variables; ! 565: DWORD variable_len; ! 566: char static_variable_buf[ISAPI_SERVER_VAR_BUF_SIZE]; ! 567: char *variable_buf; ! 568: ! 569: while (*p) { ! 570: variable_len = ISAPI_SERVER_VAR_BUF_SIZE; ! 571: if (lpECB->GetServerVariable(lpECB->ConnID, *p, static_variable_buf, &variable_len) ! 572: && static_variable_buf[0]) { ! 573: php_register_variable(*p, static_variable_buf, track_vars_array TSRMLS_CC); ! 574: if (recorded_values) { ! 575: recorded_values[p-server_variables] = estrndup(static_variable_buf, variable_len); ! 576: } ! 577: } else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { ! 578: variable_buf = (char *) emalloc(variable_len+1); ! 579: if (lpECB->GetServerVariable(lpECB->ConnID, *p, variable_buf, &variable_len) ! 580: && variable_buf[0]) { ! 581: php_register_variable(*p, variable_buf, track_vars_array TSRMLS_CC); ! 582: } ! 583: if (recorded_values) { ! 584: recorded_values[p-server_variables] = variable_buf; ! 585: } else { ! 586: efree(variable_buf); ! 587: } ! 588: } else { /* for compatibility with Apache SAPIs */ ! 589: php_register_variable(*p, "", track_vars_array TSRMLS_CC); ! 590: } ! 591: p++; ! 592: } ! 593: } ! 594: ! 595: ! 596: static void sapi_isapi_register_server_variables(zval *track_vars_array TSRMLS_DC) ! 597: { ! 598: DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE; ! 599: char *variable; ! 600: char *strtok_buf = NULL; ! 601: char *isapi_special_server_variables[NUM_SPECIAL_VARS]; ! 602: LPEXTENSION_CONTROL_BLOCK lpECB; ! 603: ! 604: lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context); ! 605: ! 606: /* Register the special ISAPI variables */ ! 607: memset(isapi_special_server_variables, 0, sizeof(isapi_special_server_variables)); ! 608: sapi_isapi_register_server_variables2(isapi_special_server_variable_names, lpECB, track_vars_array, isapi_special_server_variables TSRMLS_CC); ! 609: if (SG(request_info).cookie_data) { ! 610: php_register_variable("HTTP_COOKIE", SG(request_info).cookie_data, track_vars_array TSRMLS_CC); ! 611: } ! 612: ! 613: /* Register the standard ISAPI variables */ ! 614: sapi_isapi_register_server_variables2(isapi_server_variable_names, lpECB, track_vars_array, NULL TSRMLS_CC); ! 615: ! 616: if (isapi_special_server_variables[SPECIAL_VAR_HTTPS] ! 617: && (atoi(isapi_special_server_variables[SPECIAL_VAR_HTTPS]) ! 618: || !strcasecmp(isapi_special_server_variables[SPECIAL_VAR_HTTPS], "on")) ! 619: ) { ! 620: /* Register SSL ISAPI variables */ ! 621: sapi_isapi_register_server_variables2(isapi_secure_server_variable_names, lpECB, track_vars_array, NULL TSRMLS_CC); ! 622: } ! 623: ! 624: if (isapi_special_server_variables[SPECIAL_VAR_HTTPS]) { ! 625: efree(isapi_special_server_variables[SPECIAL_VAR_HTTPS]); ! 626: } ! 627: ! 628: ! 629: #ifdef WITH_ZEUS ! 630: sapi_isapi_register_zeus_variables(lpECB, track_vars_array TSRMLS_CC); ! 631: #else ! 632: sapi_isapi_register_iis_variables(lpECB, track_vars_array TSRMLS_CC); ! 633: #endif ! 634: ! 635: /* PHP_SELF support */ ! 636: if (isapi_special_server_variables[SPECIAL_VAR_PHP_SELF]) { ! 637: php_register_variable("PHP_SELF", isapi_special_server_variables[SPECIAL_VAR_PHP_SELF], track_vars_array TSRMLS_CC); ! 638: efree(isapi_special_server_variables[SPECIAL_VAR_PHP_SELF]); ! 639: } ! 640: ! 641: if (isapi_special_server_variables[SPECIAL_VAR_ALL_HTTP]) { ! 642: /* Register the internal bits of ALL_HTTP */ ! 643: variable = php_strtok_r(isapi_special_server_variables[SPECIAL_VAR_ALL_HTTP], "\r\n", &strtok_buf); ! 644: while (variable) { ! 645: char *colon = strchr(variable, ':'); ! 646: ! 647: if (colon) { ! 648: char *value = colon+1; ! 649: ! 650: while (*value==' ') { ! 651: value++; ! 652: } ! 653: *colon = 0; ! 654: php_register_variable(variable, value, track_vars_array TSRMLS_CC); ! 655: *colon = ':'; ! 656: } ! 657: variable = php_strtok_r(NULL, "\r\n", &strtok_buf); ! 658: } ! 659: efree(isapi_special_server_variables[SPECIAL_VAR_ALL_HTTP]); ! 660: } ! 661: } ! 662: ! 663: ! 664: static sapi_module_struct isapi_sapi_module = { ! 665: "isapi", /* name */ ! 666: "ISAPI", /* pretty name */ ! 667: ! 668: php_isapi_startup, /* startup */ ! 669: php_module_shutdown_wrapper, /* shutdown */ ! 670: ! 671: NULL, /* activate */ ! 672: NULL, /* deactivate */ ! 673: ! 674: sapi_isapi_ub_write, /* unbuffered write */ ! 675: NULL, /* flush */ ! 676: NULL, /* get uid */ ! 677: NULL, /* getenv */ ! 678: ! 679: php_error, /* error handler */ ! 680: ! 681: sapi_isapi_header_handler, /* header handler */ ! 682: sapi_isapi_send_headers, /* send headers handler */ ! 683: NULL, /* send header handler */ ! 684: ! 685: sapi_isapi_read_post, /* read POST data */ ! 686: sapi_isapi_read_cookies, /* read Cookies */ ! 687: ! 688: sapi_isapi_register_server_variables, /* register server variables */ ! 689: NULL, /* Log message */ ! 690: NULL, /* Get request time */ ! 691: NULL, /* Child terminate */ ! 692: ! 693: STANDARD_SAPI_MODULE_PROPERTIES ! 694: }; ! 695: ! 696: ! 697: BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pFilterVersion) ! 698: { ! 699: bFilterLoaded = 1; ! 700: pFilterVersion->dwFilterVersion = HTTP_FILTER_REVISION; ! 701: strcpy(pFilterVersion->lpszFilterDesc, isapi_sapi_module.pretty_name); ! 702: pFilterVersion->dwFlags= (SF_NOTIFY_AUTHENTICATION | SF_NOTIFY_PREPROC_HEADERS); ! 703: return TRUE; ! 704: } ! 705: ! 706: ! 707: DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificationType, LPVOID pvNotification) ! 708: { ! 709: TSRMLS_FETCH(); ! 710: ! 711: switch (notificationType) { ! 712: case SF_NOTIFY_PREPROC_HEADERS: ! 713: SG(request_info).auth_user = NULL; ! 714: SG(request_info).auth_password = NULL; ! 715: SG(request_info).auth_digest = NULL; ! 716: break; ! 717: case SF_NOTIFY_AUTHENTICATION: { ! 718: char *auth_user = ((HTTP_FILTER_AUTHENT *) pvNotification)->pszUser; ! 719: char *auth_password = ((HTTP_FILTER_AUTHENT *) pvNotification)->pszPassword; ! 720: ! 721: if (auth_user && auth_user[0]) { ! 722: SG(request_info).auth_user = estrdup(auth_user); ! 723: } ! 724: if (auth_password && auth_password[0]) { ! 725: SG(request_info).auth_password = estrdup(auth_password); ! 726: } ! 727: return SF_STATUS_REQ_HANDLED_NOTIFICATION; ! 728: } ! 729: break; ! 730: } ! 731: return SF_STATUS_REQ_NEXT_NOTIFICATION; ! 732: } ! 733: ! 734: ! 735: static void init_request_info(LPEXTENSION_CONTROL_BLOCK lpECB TSRMLS_DC) ! 736: { ! 737: DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE; ! 738: char static_variable_buf[ISAPI_SERVER_VAR_BUF_SIZE]; ! 739: #ifndef WITH_ZEUS ! 740: HSE_URL_MAPEX_INFO humi; ! 741: #endif ! 742: ! 743: SG(request_info).request_method = lpECB->lpszMethod; ! 744: SG(request_info).query_string = lpECB->lpszQueryString; ! 745: SG(request_info).request_uri = lpECB->lpszPathInfo; ! 746: SG(request_info).content_type = lpECB->lpszContentType; ! 747: SG(request_info).content_length = lpECB->cbTotalBytes; ! 748: SG(sapi_headers).http_response_code = 200; /* I think dwHttpStatusCode is invalid at this stage -RL */ ! 749: if (!bFilterLoaded) { /* we don't have valid ISAPI Filter information */ ! 750: SG(request_info).auth_user = SG(request_info).auth_password = SG(request_info).auth_digest = NULL; ! 751: } ! 752: ! 753: #ifdef WITH_ZEUS ! 754: /* PATH_TRANSLATED can contain extra PATH_INFO stuff after the ! 755: * file being loaded, so we must use SCRIPT_FILENAME instead ! 756: */ ! 757: if(lpECB->GetServerVariable(lpECB->ConnID, "SCRIPT_FILENAME", static_variable_buf, &variable_len)) { ! 758: SG(request_info).path_translated = estrdup(static_variable_buf); ! 759: } else ! 760: #else ! 761: /* happily, IIS gives us SCRIPT_NAME which is correct (without PATH_INFO stuff) ! 762: so we can just map that to the physical path and we have our filename */ ! 763: ! 764: lpECB->GetServerVariable(lpECB->ConnID, "SCRIPT_NAME", static_variable_buf, &variable_len); ! 765: if (lpECB->ServerSupportFunction(lpECB->ConnID, HSE_REQ_MAP_URL_TO_PATH_EX, static_variable_buf, &variable_len, (LPDWORD) &humi)) { ! 766: SG(request_info).path_translated = estrdup(humi.lpszPath); ! 767: } else ! 768: #endif ! 769: /* if mapping fails, default to what the server tells us */ ! 770: SG(request_info).path_translated = estrdup(lpECB->lpszPathTranslated); ! 771: ! 772: /* some server configurations allow '..' to slip through in the ! 773: translated path. We'll just refuse to handle such a path. */ ! 774: if (strstr(SG(request_info).path_translated,"..")) { ! 775: SG(sapi_headers).http_response_code = 404; ! 776: efree(SG(request_info).path_translated); ! 777: SG(request_info).path_translated = NULL; ! 778: } ! 779: } ! 780: ! 781: ! 782: static void php_isapi_report_exception(char *message, int message_len TSRMLS_DC) ! 783: { ! 784: if (!SG(headers_sent)) { ! 785: HSE_SEND_HEADER_EX_INFO header_info; ! 786: LPEXTENSION_CONTROL_BLOCK lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context); ! 787: ! 788: header_info.pszStatus = "500 Internal Server Error"; ! 789: header_info.cchStatus = strlen(header_info.pszStatus); ! 790: header_info.pszHeader = "Content-Type: text/html\r\n\r\n"; ! 791: header_info.cchHeader = strlen(header_info.pszHeader); ! 792: ! 793: lpECB->dwHttpStatusCode = 500; ! 794: lpECB->ServerSupportFunction(lpECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER_EX, &header_info, NULL, NULL); ! 795: SG(headers_sent)=1; ! 796: } ! 797: sapi_isapi_ub_write(message, message_len TSRMLS_CC); ! 798: } ! 799: ! 800: ! 801: BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer) ! 802: { ! 803: pVer->dwExtensionVersion = HSE_VERSION; ! 804: #ifdef WITH_ZEUS ! 805: strncpy( pVer->lpszExtensionDesc, isapi_sapi_module.name, HSE_MAX_EXT_DLL_NAME_LEN); ! 806: #else ! 807: lstrcpyn(pVer->lpszExtensionDesc, isapi_sapi_module.name, HSE_MAX_EXT_DLL_NAME_LEN); ! 808: #endif ! 809: return TRUE; ! 810: } ! 811: ! 812: ! 813: static void my_endthread() ! 814: { ! 815: #ifdef PHP_WIN32 ! 816: if (bTerminateThreadsOnError) { ! 817: _endthread(); ! 818: } ! 819: #endif ! 820: } ! 821: ! 822: #ifdef PHP_WIN32 ! 823: /* ep is accessible only in the context of the __except expression, ! 824: * so we have to call this function to obtain it. ! 825: */ ! 826: BOOL exceptionhandler(LPEXCEPTION_POINTERS *e, LPEXCEPTION_POINTERS ep) ! 827: { ! 828: *e=ep; ! 829: return TRUE; ! 830: } ! 831: #endif ! 832: ! 833: DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB) ! 834: { ! 835: zend_file_handle file_handle; ! 836: zend_bool stack_overflown=0; ! 837: int retval = FAILURE; ! 838: #ifdef PHP_ENABLE_SEH ! 839: LPEXCEPTION_POINTERS e; ! 840: #endif ! 841: TSRMLS_FETCH(); ! 842: ! 843: zend_first_try { ! 844: #ifdef PHP_ENABLE_SEH ! 845: __try { ! 846: #endif ! 847: init_request_info(lpECB TSRMLS_CC); ! 848: SG(server_context) = lpECB; ! 849: ! 850: php_request_startup(TSRMLS_C); ! 851: ! 852: file_handle.filename = SG(request_info).path_translated; ! 853: file_handle.free_filename = 0; ! 854: file_handle.type = ZEND_HANDLE_FILENAME; ! 855: file_handle.opened_path = NULL; ! 856: ! 857: /* open the script here so we can 404 if it fails */ ! 858: if (file_handle.filename) ! 859: retval = php_fopen_primary_script(&file_handle TSRMLS_CC); ! 860: ! 861: if (!file_handle.filename || retval == FAILURE) { ! 862: SG(sapi_headers).http_response_code = 404; ! 863: PUTS("No input file specified.\n"); ! 864: } else { ! 865: php_execute_script(&file_handle TSRMLS_CC); ! 866: } ! 867: ! 868: if (SG(request_info).cookie_data) { ! 869: efree(SG(request_info).cookie_data); ! 870: } ! 871: if (SG(request_info).path_translated) ! 872: efree(SG(request_info).path_translated); ! 873: #ifdef PHP_ENABLE_SEH ! 874: } __except(exceptionhandler(&e, GetExceptionInformation())) { ! 875: char buf[1024]; ! 876: if (_exception_code()==EXCEPTION_STACK_OVERFLOW) { ! 877: LPBYTE lpPage; ! 878: static SYSTEM_INFO si; ! 879: static MEMORY_BASIC_INFORMATION mi; ! 880: static DWORD dwOldProtect; ! 881: ! 882: GetSystemInfo(&si); ! 883: ! 884: /* Get page ESP is pointing to */ ! 885: _asm mov lpPage, esp; ! 886: ! 887: /* Get stack allocation base */ ! 888: VirtualQuery(lpPage, &mi, sizeof(mi)); ! 889: ! 890: /* Go to the page below the current page */ ! 891: lpPage = (LPBYTE) (mi.BaseAddress) - si.dwPageSize; ! 892: ! 893: /* Free pages below current page */ ! 894: if (!VirtualFree(mi.AllocationBase, (LPBYTE)lpPage - (LPBYTE) mi.AllocationBase, MEM_DECOMMIT)) { ! 895: _endthread(); ! 896: } ! 897: ! 898: /* Restore the guard page */ ! 899: if (!VirtualProtect(lpPage, si.dwPageSize, PAGE_GUARD | PAGE_READWRITE, &dwOldProtect)) { ! 900: _endthread(); ! 901: } ! 902: ! 903: CG(unclean_shutdown)=1; ! 904: _snprintf(buf, sizeof(buf)-1,"PHP has encountered a Stack overflow"); ! 905: php_isapi_report_exception(buf, strlen(buf) TSRMLS_CC); ! 906: } else if (_exception_code()==EXCEPTION_ACCESS_VIOLATION) { ! 907: _snprintf(buf, sizeof(buf)-1,"PHP has encountered an Access Violation at %p", e->ExceptionRecord->ExceptionAddress); ! 908: php_isapi_report_exception(buf, strlen(buf) TSRMLS_CC); ! 909: my_endthread(); ! 910: } else { ! 911: _snprintf(buf, sizeof(buf)-1,"PHP has encountered an Unhandled Exception Code %d at %p", e->ExceptionRecord->ExceptionCode , e->ExceptionRecord->ExceptionAddress); ! 912: php_isapi_report_exception(buf, strlen(buf) TSRMLS_CC); ! 913: my_endthread(); ! 914: } ! 915: } ! 916: #endif ! 917: #ifdef PHP_ENABLE_SEH ! 918: __try { ! 919: php_request_shutdown(NULL); ! 920: } __except(EXCEPTION_EXECUTE_HANDLER) { ! 921: my_endthread(); ! 922: } ! 923: #else ! 924: php_request_shutdown(NULL); ! 925: #endif ! 926: } zend_catch { ! 927: zend_try { ! 928: php_request_shutdown(NULL); ! 929: } zend_end_try(); ! 930: return HSE_STATUS_ERROR; ! 931: } zend_end_try(); ! 932: ! 933: return HSE_STATUS_SUCCESS; ! 934: } ! 935: ! 936: ! 937: ! 938: __declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) ! 939: { ! 940: switch (fdwReason) { ! 941: case DLL_PROCESS_ATTACH: ! 942: #ifdef WITH_ZEUS ! 943: tsrm_startup(128, 1, TSRM_ERROR_LEVEL_CORE, "TSRM.log"); ! 944: #else ! 945: tsrm_startup(128, 1, TSRM_ERROR_LEVEL_CORE, "C:\\TSRM.log"); ! 946: #endif ! 947: sapi_startup(&isapi_sapi_module); ! 948: if (isapi_sapi_module.startup) { ! 949: isapi_sapi_module.startup(&sapi_module); ! 950: } ! 951: break; ! 952: case DLL_THREAD_ATTACH: ! 953: break; ! 954: case DLL_THREAD_DETACH: ! 955: ts_free_thread(); ! 956: break; ! 957: case DLL_PROCESS_DETACH: ! 958: if (isapi_sapi_module.shutdown) { ! 959: isapi_sapi_module.shutdown(&sapi_module); ! 960: } ! 961: sapi_shutdown(); ! 962: tsrm_shutdown(); ! 963: break; ! 964: } ! 965: return TRUE; ! 966: } ! 967: ! 968: /* ! 969: * Local variables: ! 970: * tab-width: 4 ! 971: * c-basic-offset: 4 ! 972: * End: ! 973: */