diff options
Diffstat (limited to 'sapi/isapi/php4isapi.c')
-rw-r--r-- | sapi/isapi/php4isapi.c | 464 |
1 files changed, 464 insertions, 0 deletions
diff --git a/sapi/isapi/php4isapi.c b/sapi/isapi/php4isapi.c new file mode 100644 index 0000000000..ee3f1f2179 --- /dev/null +++ b/sapi/isapi/php4isapi.c @@ -0,0 +1,464 @@ +#include <windows.h> +#include <httpext.h> +#include <httpfilt.h> +#include <httpext.h> +#include "php.h" +#include "main.h" +#include "SAPI.h" +#include "php_globals.h" +#include "ext/standard/info.h" + +#define MAX_STATUS_LENGTH sizeof("xxxx LONGEST STATUS DESCRIPTION") +#define ISAPI_SERVER_VAR_BUF_SIZE 1024 +#define ISAPI_POST_DATA_BUF 1024 + +int IWasLoaded=0; + +static char *isapi_server_variables[] = { + "ALL_HTTP", + "APPL_MD_PATH", + "APPL_PHYSICAL_PATH", + "AUTH_PASSWORD", + "AUTH_TYPE", + "AUTH_USER", + "CERT_COOKIE", + "CERT_FLAGS", + "CERT_ISSUER", + "CERT_KEYSIZE", + "CERT_SECRETKEYSIZE", + "CERT_SERIALNUMBER", + "CERT_SERVER_ISSUER", + "CERT_SERVER_SUBJECT", + "CERT_SUBJECT", + "CONTENT_LENGTH", + "CONTENT_TYPE", + "LOGON_USER", + "HTTP_COOKIE", + "HTTPS", + "HTTPS_KEYSIZE", + "HTTPS_SECRETKEYSIZE", + "HTTPS_SERVER_ISSUER", + "HTTPS_SERVER_SUBJECT", + "INSTANCE_ID", + "INSTANCE_META_PATH", + "PATH_INFO", + "PATH_TRANSLATED", + "QUERY_STRING", + "REMOTE_ADDR", + "REMOTE_HOST", + "REMOTE_USER", + "REQUEST_METHOD", + "SCRIPT_NAME", + "SERVER_NAME", + "SERVER_PORT", + "SERVER_PORT_SECURE", + "SERVER_PROTOCOL", + "SERVER_SOFTWARE", + "URL", + NULL +}; + + +static void php_info_isapi(ZEND_MODULE_INFO_FUNC_ARGS) +{ + char **p = isapi_server_variables; + char variable_buf[ISAPI_SERVER_VAR_BUF_SIZE]; + DWORD variable_len; + LPEXTENSION_CONTROL_BLOCK lpECB; + SLS_FETCH(); + + lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context); + + PUTS("<table border=5 width=\"600\">\n"); + php_info_print_table_header(2, "Server Variable", "Value"); + 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++; + } + + PUTS("</table>"); +} + + +static zend_module_entry php_isapi_module = { + "ISAPI", + NULL, + NULL, + NULL, + NULL, + NULL, + php_info_isapi, + STANDARD_MODULE_PROPERTIES +}; + + +static int zend_isapi_ub_write(const char *str, uint str_length) +{ + DWORD num_bytes = str_length; + LPEXTENSION_CONTROL_BLOCK ecb; + SLS_FETCH(); + + ecb = (LPEXTENSION_CONTROL_BLOCK) SG(server_context); + ecb->WriteClient(ecb->ConnID, (char *) str, &num_bytes, HSE_IO_SYNC ); + return num_bytes; +} + + +static int sapi_isapi_header_handler(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers SLS_DC) +{ + return SAPI_HEADER_ADD; +} + + + +static void accumulate_header_length(sapi_header_struct *sapi_header, uint *total_length) +{ + *total_length += sapi_header->header_len+2; +} + + +static void concat_header(sapi_header_struct *sapi_header, char **combined_headers_ptr) +{ + 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 SLS_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 = { SAPI_DEFAULT_CONTENT_TYPE, sizeof(SAPI_DEFAULT_CONTENT_TYPE)-1 }; + sapi_header_struct php_version_header = { SAPI_PHP_VERSION_HEADER, sizeof(SAPI_PHP_VERSION_HEADER)-1 }; + PLS_FETCH(); + + /* Obtain headers length */ + if (SG(sapi_headers).send_default_content_type) { + accumulate_header_length(&default_content_type, (void *) &total_length); + } + if (PG(expose_php)) { + accumulate_header_length(&php_version_header, (void *) &total_length); + } + zend_llist_apply_with_argument(&SG(sapi_headers).headers, (void (*)(void *, void *)) accumulate_header_length, (void *) &total_length); + + /* 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); + } + if (PG(expose_php)) { + concat_header(&php_version_header, (void *) &combined_headers_ptr); + } + zend_llist_apply_with_argument(&SG(sapi_headers).headers, (void (*)(void *, void *)) concat_header, (void *) &combined_headers_ptr); + *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; + 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); + if (SG(sapi_headers).http_status_line) { + efree(SG(sapi_headers).http_status_line); + } + return SAPI_HEADER_SENT_SUCCESSFULLY; +} + + +static int php_isapi_startup(sapi_module_struct *sapi_module) +{ + if (php_module_startup(sapi_module)==FAILURE + || zend_register_module(&php_isapi_module)==FAILURE) { + return FAILURE; + } else { + return SUCCESS; + } +} + + + +static int sapi_isapi_read_post(char *buffer, uint count_bytes SLS_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 (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; + } + SG(read_post_bytes) += total_read; + return total_read; +} + + +static char *sapi_isapi_read_cookies(SLS_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; +} + + +static sapi_module_struct sapi_module = { + "PHP Language", /* name */ + + php_isapi_startup, /* startup */ + php_module_shutdown_wrapper, /* shutdown */ + + zend_isapi_ub_write, /* unbuffered write */ + + 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 */ + + STANDARD_SAPI_MODULE_PROPERTIES +}; + + +BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pFilterVersion) +{ + pFilterVersion->dwFilterVersion = HTTP_FILTER_REVISION; + strcpy(pFilterVersion->lpszFilterDesc, sapi_module.name); + pFilterVersion->dwFlags= (SF_NOTIFY_AUTHENTICATION | SF_NOTIFY_PREPROC_HEADERS); + return TRUE; +} + + +DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificationType, LPVOID pvNotification) +{ + SLS_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); + } + auth_user[0] = 0; + auth_password[0] = 0; + return SF_STATUS_REQ_HANDLED_NOTIFICATION; + } + break; + } + return SF_STATUS_REQ_NEXT_NOTIFICATION; +} + + +static void init_request_info(sapi_globals_struct *sapi_globals, LPEXTENSION_CONTROL_BLOCK lpECB) +{ + SG(request_info).request_method = lpECB->lpszMethod; + SG(request_info).query_string = lpECB->lpszQueryString; + SG(request_info).path_translated = lpECB->lpszPathTranslated; + SG(request_info).request_uri = lpECB->lpszPathInfo; + SG(request_info).content_type = lpECB->lpszContentType; + SG(request_info).content_length = lpECB->cbTotalBytes; + { + char *path_end = strrchr(SG(request_info).path_translated, '\\'); + + if (path_end) { + *path_end = 0; + chdir(SG(request_info).path_translated); + *path_end = '\\'; + } + } +} + + +BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer) +{ + pVer->dwExtensionVersion = HSE_VERSION; + lstrcpyn(pVer->lpszExtensionDesc, sapi_module.name, HSE_MAX_EXT_DLL_NAME_LEN); + return TRUE; +} + + +static void hash_isapi_variables(ELS_D SLS_DC) +{ + char static_variable_buf[ISAPI_SERVER_VAR_BUF_SIZE]; + char *variable_buf; + DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE; + char *variable; + LPEXTENSION_CONTROL_BLOCK lpECB; + + lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context); + + if (lpECB->GetServerVariable(lpECB->ConnID, "ALL_HTTP", static_variable_buf, &variable_len)) { + variable_buf = static_variable_buf; + } else { + if (GetLastError()==ERROR_INSUFFICIENT_BUFFER) { + variable_buf = (char *) emalloc(variable_len); + if (!lpECB->GetServerVariable(lpECB->ConnID, "ALL_HTTP", variable_buf, &variable_len)) { + efree(variable_buf); + return; + } + } else { + return; + } + } + variable = strtok(variable_buf, "\r\n"); + while (variable) { + char *colon = strchr(variable, ':'); + + if (colon) { + char *value = colon+1; + zval *entry = (zval *) emalloc(sizeof(zval)); + + while (*value==' ') { + value++; + } + *colon = 0; + INIT_PZVAL(entry); + entry->value.str.len = strlen(value); + entry->value.str.val = estrndup(value, entry->value.str.len); + entry->type = IS_STRING; + zend_hash_add(&EG(symbol_table), variable, strlen(variable)+1, &entry, sizeof(zval *), NULL); + *colon = ':'; + } + variable = strtok(NULL, "\r\n"); + } + if (variable_buf!=static_variable_buf) { + efree(variable_buf); + } +} + + +DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB) +{ + zend_file_handle file_handle; + SLS_FETCH(); + CLS_FETCH(); + ELS_FETCH(); + PLS_FETCH(); + + if (setjmp(EG(bailout))!=0) { + return HSE_STATUS_ERROR; + } + + init_request_info(sapi_globals, lpECB); + SG(server_context) = lpECB; + + file_handle.filename = sapi_globals->request_info.path_translated; + file_handle.type = ZEND_HANDLE_FILENAME; + + php_request_startup(CLS_C ELS_CC PLS_CC SLS_CC); + hash_isapi_variables(ELS_C SLS_CC); + php_execute_script(&file_handle CLS_CC ELS_CC PLS_CC); + if (SG(request_info).cookie_data) { + efree(SG(request_info).cookie_data); + } + php_request_shutdown(NULL); + return HSE_STATUS_SUCCESS; +} + + + +__declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + tsrm_startup(1, 1, 0); + sapi_startup(&sapi_module); + if (sapi_module.startup) { + sapi_module.startup(&sapi_module); + } + IWasLoaded = 1; + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + ts_free_thread(); + break; + case DLL_PROCESS_DETACH: + if (sapi_module.shutdown) { + sapi_module.shutdown(&sapi_module); + } + tsrm_shutdown(); + break; + } + return TRUE; +}
\ No newline at end of file |