Приложение ISHELLO
В качестве нашего первого расширения ISAPI мы предлагаем приложение ISHELLO, выполняющее простейшие функции.
Вызов расширения ishello.dll выполняется из формы, исходный текст которой приведен в листинге 8.1.
Листинг 8.1. Файл chap8\ishello\ishello.htm
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
<TITLE>ISAPI Script Test</TITLE>
</HEAD>
<BODY BGCOLOR=#FFFFFF>
<H1>Вызов расширения ISAPI</H1>
<FORM METHOD=POST ACTION="http://frolov/scripts/ishello.dll?Param1|Param2|Param3">
<INPUT TYPE=submit VALUE="Send">
</FORM>
</BODY>
</HTML>
Расширение вызывается в параметре ACTION оператора <FORM> аналогично тому, как это делается для программ CGI.
Расширение ishello.dll динамически создает документ HTML, представленный на рис. 8.1.

Рис. 8.1. Документ HTML, созданный динамически расширением ishello.dll
В верхней части этого документа отображается содержимое некоторых полей структуры EXTENSION_CONTROL_BLOCK, а в нижней в качетсве примера отображается содержимое переменной ALL_HTTP, полученное с помощью функции GetServerVariable.
Исходный текст расширения ishello.dll представлен в листинге 8.2.
Листинг 8.2. Файл chap8\ishello\ishello.c
// ===============================================
// Расширение ISAPI ishello.c
// Пример простейшего расширения ISAPI
//
// (C) Фролов А.В., 1997
// E-mail: frolov@glas.apc.org
// WWW: http://www.glasnet.ru/~frolov
// или
// http://www.dials.ccas.ru/frolov
// ===============================================
#include <windows.h>
#include <httpext.h>
// =============================================================
// Функция GetExtensionVersion
// Запись версии интерфейса ISAPI и
// строки описания расширения
// =============================================================
BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer)
{
// Записываем версию интерфейса ISAPI
pVer->dwExtensionVersion =
MAKELONG(HSE_VERSION_MINOR,HSE_VERSION_MAJOR );
// Записываем строку описания расширения
lstrcpyn(pVer->lpszExtensionDesc,
"Simple ISAPI DLL", HSE_MAX_EXT_DLL_NAME_LEN);
return TRUE;
}
// =============================================================
// Функция HttpExtensionProc
// =============================================================
DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *lpECB)
{
CHAR szBuff[4096];
CHAR szTempBuf[4096];
DWORD dwSize;
// Нулевой код состояния - признак успешного выполнения
lpECB->dwHttpStatusCode = 0;
// Записываем в буфер заголовок HTTP и начальный
// фрагмент формируемого динамически документа HTML
wsprintf(szBuff,
"Content-Type: text/html\r\n\r\n"
"<HTML><HEAD><TITLE>Simple ISAPI Extension</TITLE></HEAD>\n"
"<BODY BGCOLOR=#FFFFFF><H1>Hello from ISAPI Extension!</H1>\n");
// Добавляем разделительную линию
strcat(szBuff, "<HR>");
// Добавляем версию интерфейса ISAPI
wsprintf(szTempBuf, "<P>Extension Version: %d.%d",
HIWORD(lpECB->dwVersion), LOWORD(lpECB->dwVersion));
strcat(szBuff, szTempBuf);
// Название метода передачи данных
wsprintf(szTempBuf, "<BR>Method: %s", lpECB->lpszMethod);
strcat(szBuff, szTempBuf);
// Строка параметров запуска расширения ISAPI
wsprintf(szTempBuf, "<BR>QueryString: %s",
lpECB->lpszQueryString);
strcat(szBuff, szTempBuf);
// Физический путь к программному файлу расширения ISAPI
wsprintf(szTempBuf, "<BR>PathTranslated: %s",
lpECB->lpszPathTranslated);
strcat(szBuff, szTempBuf);
// Полный размер данных, которые нужно получить
wsprintf(szTempBuf, "<BR>TotalBytes: %d",
lpECB->cbTotalBytes);
strcat(szBuff, szTempBuf);
// Тип данных
wsprintf(szTempBuf, "<BR>ContentType: %s",
lpECB->lpszContentType);
strcat(szBuff, szTempBuf);
// Отображаем содержимое переменных сервера
strcat(szBuff, "<HR><P><B>Server Variables:</B><BR>");
dwSize = 4096;
lpECB->GetServerVariable(lpECB->ConnID,
(LPSTR)"ALL_HTTP", (LPVOID)szTempBuf, &dwSize);
strcat(szBuff, szTempBuf);
// Конечный фрагмент документа HTML
strcat(szBuff, "</BODY></HTML>");
// Посылаем содержимое буфера удаленному пользователю
if(!lpECB->ServerSupportFunction(lpECB->ConnID,
HSE_REQ_SEND_RESPONSE_HEADER, NULL, NULL,
(LPDWORD)szBuff))
{
// Если послать данные не удалось,
// завершаем работу нашего расширения ISAPI
// с кодом ошибки
return HSE_STATUS_ERROR;
}
// Записываем код успешного завершения
lpECB->dwHttpStatusCode = 200;
// Возвращаем признак успешного завершения
return HSE_STATUS_SUCCESS;
}
Обратите внимание, что наряду с обычным для приложений Windows файлом windows.h мы включили в наш исходный текст файл httpext.h, в котором определены все необходимые константы, структуры данных и прототипы функций. Этот файл поставляется в составе Microsoft Visual C++ версии 4.2, а также в составе Internet SDK, который можно получить на сервере www.microsoft.com.
В приложении определена функция GetExtensionVersion, которая уже была рассмотрена нами ранее. Эта функция с небольшими изменениями будет встречаться во всех наших примерах расширений ISAPI. Она записывает версию интерфейса ISAPI и текстовую строку описания расширения в поля структуры типа HSE_VERSION_INFO с именами dwExtensionVersion и lpszExtensionDesc, сответственно. Адрес структуры HSE_VERSION_INFO передается функции GetExtensionVersion через единственный параметр.
Функция HttpExtensionProc использует буфер szBuff для подготовки динамически создаваемого документа HTML, который будет послан удаленному пользователю в результате работы нашего расширения. В качестве вспомогательного буфера применяется буфер szTempBuf.
Прежде всего в буфер szBuff записывается заголовок HTTP и начальный фрагмент документа HTML, для чего используется функция wsprintf. Далее к буферу szBuff с помощью функции strcat будут добавляться другие строки документа. Например, разделительная линия добавляется так:
strcat(szBuff, "<HR>");
После первой разделительной линии в документ добавляется несколько строк со значениями некоторых полей структуры типа EXTENSION_CONTROL_BLOCK. В следующем фрагменте кода добавляется строка версии интерфейса ISAPI:
wsprintf(szTempBuf, "<P>Extension Version: %d.%d",
HIWORD(lpECB->dwVersion), LOWORD(lpECB->dwVersion));
strcat(szBuff, szTempBuf);
Далее в документ выводятся строка с названием метода передачи данных (поле lpszMethod), строка параметров запуска расширения ISAPI (поле lpszQueryString), физический путь к программному файлу библиотеки DLL расширения (поле lpszPathTranslated), полный размер данных, которые нужно прочитать (поле cbTotalBytes), а также тип данных (поле lpszContentType).
После этого в документ снова выводится разделительная линия и отображается содержимое переменных сервера с префиксом имени HTTP, для чего используется рассмотренная ранее функция GetServerVariable.
В завершении в документ записывается финальная строка:
strcat(szBuff, "</BODY></HTML>");
Документ посылается удаленному пользователю функцией ServerSupportFunction, как это показано ниже:
if(!lpECB->ServerSupportFunction(lpECB->ConnID,
HSE_REQ_SEND_RESPONSE_HEADER, NULL, NULL, (LPDWORD)szBuff))
{
return HSE_STATUS_ERROR;
}
Если при посылке данных произошла ошибка, расширение завершает свою работу с кодом HSE_STATUS_ERROR.
В случае успеха в поле состояния dwHttpStatusCode записывается код 200, вслед за чем расширение завершает свою работу с кодом HSE_STATUS_SUCCESS.
Файл определения модуля для библиотеки DLL расширения ISAPI представлен в листинге 8.3.
Листинг 8.3. Файл chap8\ishello\ishello.def
LIBRARY ishello
DESCRIPTION 'Simple ISAPI DLL'
EXPORTS
GetExtensionVersion
HttpExtensionProc