Электронная библиотека книг Александра Фролова и Григория Фролова.
 
Библиотека
Братьев
Фроловых
Электронная библиотека книг Александра Фролова и Григория Фролова.
Библиотека системного программиста
Программирование на JAVA
ПК. Шаг за шагом
Другие книги
Восстановление данных
Антивирусная защита
Статьи для
программистов
Пользователю компьютера

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


Создание интернет-магазинов: http://www.shop2you.ru/ © Александр Фролов, Григорий Фролов, 1991-2016