Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Сервер Web своими руками. Язык HTML, приложения CGI и ISAPI, установка серверов Web для Windows

© Александр Фролов, Григорий Фролов
Том 29, М.: Диалог-МИФИ, 1997, 288 стр.

[Назад] [Содеожание] [Дальше]

Приложение 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 XE "EXTENSION_CONTROL_BLOCK" , а в нижней в качетсве примера отображается содержимое переменной ALL_HTTP, полученное с помощью функции GetServerVariable.

Исходный текст расширения ishello.dll представлен в листинге 8.2.


// ===============================================
// Расширение 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
[Назад] [Содеожание] [Дальше]