mirror of
https://github.com/php/php-src.git
synced 2024-11-29 04:46:07 +08:00
2a854ca8b9
implementation now has its own directory under sapi/, just like extensions have theirs under ext/. To make the final targets appear in the main dir, the top-level Makefile includes sapi/NN/Makefile.inc from the selected sapi backend. This is a plan Makefile stub without any autoconf substitutions. Each SAPI backend also has its own config.m4 like extensions (read at the end of diversion 2) and config.h.stub files. Each SAPI backend has to contain: config.m4: just like for extensions, this file contains autoconf/automake directives that end up in the configure script. The only difference is that the sapi config.m4 files are read in diversion (output block) 2 instead of 3. The sapi config.m4 files should set two variables: PHP_SAPI (which sapi backend to choose) and SAPI_TARGET (the name of the resulting library or program, previously BINNAME). If they are not specified, they will default to "cgi" and "php", respectively. Makefile.inc: has to exist, has to define "INSTALL_IT" to the command used to install the final target (or ":" for no operation). It also has to define a plain Makefile rule (without autoconf substitutions) to build $(SAPI_TARGET) Makefile.am: just what you think. Make sure your target is called "libphpsapi_NNN.a", where NNN is the value of PHP_SAPI. Some testing and fixing probably remains. To make everything hang together, I've done some ugly tricks that I can imagine causing some problems. I've built and run the CGI version and built the Apache DSO.
464 lines
12 KiB
C
464 lines
12 KiB
C
#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;
|
|
} |