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

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

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

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

Приложение ISFORM

Приложение ISFORM демонстрирует способ получения и обработки данных, полученных от формы, расширением ISAPI. Аналогичные действия выполняла программа CGI с именем CONTROLS, описанная нами в предыдущей главе.

Исходный текст документа HTML, содержащий форму, представлен в листинге 8.4. Эта форма уже использовалась нами ранее в предыдущей главе (рис. 7.2), поэтому мы не будем показывать ее внешний вид снова для экономии места.

Листинг 8.4. Файл chap8\isform\isform.htm


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
 <TITLE>Органы управления в формах</TITLE>
</HEAD>
<BODY BGCOLOR=#FFFFFF>
<FORM METHOD=POST ACTION="http://frolov/scripts/isform.dll?Param1|Param2|Param3">
  <TABLE>
    <TR>
      <TD VALIGN=TOP>Текстовое поле TEXT</TD>
      <TD><INPUT TYPE=text NAME="text1" VALUE="Sample of text1" SIZE=30></TD>
    </TR>
    <TR>
      <TD VALIGN=TOP>Текстовое поле PASSWORD</TD>
      <TD><INPUT TYPE=password NAME="pwd" VALUE="Sample of password"></TD>
    </TR>
    <TR>
      <TD VALIGN=TOP>Текстовое поле TEXTAREA</TD>
      <TD><TEXTAREA NAME="text2" ROWS=4 COLS=30>Sample of text</TEXTAREA></TD>
    </TR>
    <TR>
      <TD VALIGN=TOP>Переключатели CHECKBOX</TD>
      <TD>
        <INPUT TYPE=CHECKBOX NAME="chk1" VALUE="on" CHECKED>Первый<BR>
        <INPUT TYPE=CHECKBOX NAME="chk2" VALUE="on">Второй<BR>
        <INPUT TYPE=CHECKBOX NAME="chk3" VALUE="on" CHECKED>Третий<BR>
      </TD>
    </TR>
    <TR>
      <TD VALIGN=TOP>Переключатели RADIO</TD>
      <TD>
        <INPUT TYPE=RADIO NAME="rad" VALUE="on1" CHECKED>Первый<BR>
        <INPUT TYPE=RADIO NAME="rad" VALUE="on2">Второй<BR>
        <INPUT TYPE=RADIO NAME="rad" VALUE="on3">Третий<BR>
      </TD>
    </TR>
    <TR>
      <TD VALIGN=TOP>Список</TD>
      <TD>
        <SELECT NAME="sel" SIZE="1">
          <OPTION Value="First Option">First Option</OPTION>
          <OPTION Value="Second Option">Second Option</OPTION>
          <OPTION Value="None">None Selected</OPTION>
        </SELECT>
      </TD>
    </TR>
    <TR>
      <TD VALIGN=TOP>Скрытый орган управления</TD>
      <TD><INPUT TYPE=HIDDEN NAME="hid" VALUE="Hidden"></TD>
    </TR>
  </TABLE>
<BR><INPUT TYPE=submit VALUE="Send">&nbsp;
<INPUT TYPE=reset VALUE="Reset">
<P><INPUT TYPE=IMAGE SRC="send.gif" BORDER=0>
</FORM>
</BODY>
</HTML>

Вызов расширения ISAPI выполняется в форме с помощью параметра ACTION оператора <FORM>, как это показано ниже:


ACTION="http://frolov/scripts/isform.dll?Param1|Param2|Param3">

После разделительного символа “?” расширению передается строка параметров Param1|Param2|Param3.

Результат обработки формы показан на рис. 8.2.

Рис. 8.2. Результат обработки формы расширением ISAPI с именем isform.dll

Обратите внимание, что поля TotalBytes и Available содержат одинаковые значения. Следовательно, все принятые данные поместились в буфере предварительной загрузки. И это не удивительно - форма передала всего 127 байт данных.

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

Листинг 8.5. Файл chap8\isform\isform.c


// ===============================================
// Расширение ISAPI isform.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>

// Прототипы функций перекодировки
void DecodeStr(char *szString);
char DecodeHex(char *str);

// =============================================================
// Функция GetExtensionVersion
// Запись версии интерфейса ISAPI и
// строки описания расширения
// =============================================================
BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer)
{
  // Записываем версию интерфейса ISAPI
  pVer->dwExtensionVersion = 
    MAKELONG(HSE_VERSION_MINOR,HSE_VERSION_MAJOR );

  // Записываем строку описания расширения
  lstrcpyn(pVer->lpszExtensionDesc,
    "Form Parser ISAPI DLL", HSE_MAX_EXT_DLL_NAME_LEN);

  return TRUE;
}

// =============================================================
// Функция HttpExtensionProc
// =============================================================
DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *lpECB)
{
  CHAR  szBuff[4096];
  CHAR  szTempBuf[4096];
  char * szPtr;
  char * szParam;
  
  // Нулевой код состояния - признак успешного выполнения
  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><H2>Information from ECB</H2>\n");

  // Добавляем версию интерфейса 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>Available: %d", 
    lpECB->cbAvailable);
  strcat(szBuff, szTempBuf);

  // Тип данных
  wsprintf(szTempBuf, "<BR>ContentType: %s", 
    lpECB->lpszContentType);
  strcat(szBuff, szTempBuf);

  lstrcpyn(szTempBuf, lpECB->lpbData, lpECB->cbAvailable + 1);
  szTempBuf[lpECB->cbAvailable + 1] = '\0';
  
  strcat(szBuff, "<H2>Принятые данные</H2>");
  strcat(szBuff, szTempBuf);

  // Перекодируем данные и отображаем результат
  // перекодировки
  DecodeStr(szTempBuf);

  strcat(szBuff, "<H2>Данные после перекодировки</H2>");
  strcat(szBuff, szTempBuf);

  // Выводим в документ список значений полей формы
  strcat(szBuff, "<H2>Список значений полей</H2>");

  szTempBuf[lpECB->cbAvailable] = '&';
  szTempBuf[lpECB->cbAvailable + 1] = '\0';
  
  for(szParam = szTempBuf;;)
  {
      szPtr = strchr(szParam, '&');
      if(szPtr != NULL)
      {
        *szPtr = '\0';
        DecodeStr(szParam);
        strcat(szBuff, szParam);
        strcat(szBuff, "<BR>");

        szParam = szPtr + 1;
        if(szParam >= (szTempBuf + lpECB->cbAvailable))
          break;
      }
      else
        break;
  }


  // Конечный фрагмент документа 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;
}

// ------------------------------------------------
// Функция DecodeStr
// Раскодирование строки из кодировки URL
// ------------------------------------------------
void DecodeStr(char *szString)
{
  int src;
  int dst;
  char ch;

  // Цикл по строке
  for(src=0, dst=0; szString[src]; src++, dst++)
  {
    // Получаем очередной символ перекодируемой строки
    ch = szString[src];

    // Заменяем символ "+" на пробел
    ch = (ch == '+') ? ' ' : ch;
    
    // Сохраняем результат
    szString[dst] = ch;
    
    // Обработка шестнадцатеричных кодов вида "%xx"
    if(ch == '%')
    {
      // Выполняем преобразование строки "%xx"
      // в код символа
      szString[dst] = DecodeHex(&szString[src + 1]);
      src += 2;
    }
  }
  
  // Закрываем строку двоичным нулем
  szString[dst] = '\0';
}

// ------------------------------------------------
// Функция DecodeHex
// Раскодирование строки "%xx"
// ------------------------------------------------
char DecodeHex(char *str)
{
  char ch;

  // Обрабатываем старший разряд
  if(str[0] >= 'A')
    ch = ((str[0] & 0xdf) - 'A') + 10;
  else
    ch = str[0] - '0';

  // Сдвигаем его влево на 4 бита
  ch <<= 4;

  // Обрабатываем младший разряд и складываем
  // его со старшим
  if(str[1] >= 'A')
    ch += ((str[1] & 0xdf) - 'A') + 10;
  else
    ch += str[1] - '0';

  // Возвращаем результат перекодировки
  return ch;
}

Для перекодирования принятых данных из кодировки URL мы использовали здесь функции DecodeStr и DecodeHex, описанные нами в разделе “Программа CONTROLS” предыдущей главы.

Перед тем как выполнить перекодировку принятых данных, расширение копирует эти данные во временный буфер szTempBuf, и закрывает его двоичным нулем, превращая в строку. Такая операция допустима, если передаются только текстовые данные (а это как раз наш случай). После копирования адрес буфера передается функции DecodeStr:


lstrcpyn(szTempBuf, lpECB->lpbData, lpECB->cbAvailable + 1);
szTempBuf[lpECB->cbAvailable + 1] = '\0';
DecodeStr(szTempBuf);

Сканирование и вывод значений отдельных полей формы выполняется аналогично тому, как это делалось в программе CGI с именем CONTROLS. Однако в отличие от указанной программы, значения отдельных полей не выводятся в стандартный поток STDOUT, а дописываются в конец буфера szBuff функцией strcat.

Файл определения модуля библиотеки DLL приложения приведен в листинге 8.6.

Листинг 8.6. Файл chap8\isform\isform.def


LIBRARY	     isform
DESCRIPTION  'Form Parser ISAPI DLL'
EXPORTS
    GetExtensionVersion
    HttpExtensionProc
[Назад] [Содеожание] [Дальше]