Построение остальных элементов XML
После обработки функции HttpExtensionProc значения заголовка ALL_HTTP остальные серверные переменные обрабатываются с помощью функции GetECBElement (см. листинг 5.7). Каждая серверная переменная, передаваемая в GetECBElement, извлекается с помощью функции GetServerVariable и записывается в элемент XML, присоединяемый к строке, на которую указывает psElement. Указатель psElement указывает на документ XML, конструируемый в HttpExtensionProc.
Листинг 5.7. Function GetECBElement (html, txt)
Функция ValidateValue проверяет, что специальные символы указаны с помощью альтернативных комбинаций символов. Функция применяется к строке, перед тем как строке присваивается статус значения элемента. Для подтверждения значения атрибута можно применять ValidateValue. XML не разрешает использование определенных специальных символов в позиции значения, если они не представлены в альтернативном виде. Как видно из листинга 5.8, символы, используемые для реализации XML-структуры: "=", "?" и "?" – заменяются альтернативными эквивалентами.
Листинг 5.8. Function ValidateValue (html, txt)
Функция FindAndReplace представляет собой утилиту для замещения всех вхождений строки. В расширении ISAPI SEUX она является идеальным механизмом для замещения одной фразы внутри строки другой фразой. Аргументы представляют собой указатели на строки:
- изменяемая строка (контейнер);
- строка, которую нужно заменить внутри контейнера (цель);
- строка, заменяющая цель в контейнере (замещение).
Строка STL содержит функции find и replace, используемые функцией FindAndReplace для поиска контейнера всех вхождений цели (см. листинг 5.9). Каждый раз при обнаружении цели в контейнере происходит ее замена, и начинается новый поиск. По завершении работы функции FindAndReplace контейнер обновляется замещениями, если таковые имеются.
Листинг 5.9.
(html, txt)
Функция GetElement работает аналогично функции GetECBElement; она вызывается из функции HttpExtensionProc для конкатенации элементов из свойств ECB.
Свойства извлекаются из ECB, после чего передаются вместе со своими именами и документом XML в функцию GetElement. GetElement размещает свойство ECB и соответствующее значение в XML документе и конкатенирует его с указателем документа XML, переданным функции GetElement. Осуществляется запрос следующих свойств:
- lpszLogData. Буфер размера HSE_LOG_BUFFER_LEN, используемый для размещения информации, добавляемой в файл журнала для данной транзакции HTTP-запроса.
- lpszMethod. Строковое значение используемого метода HTTP, например, GET, PUT или HEAD.
- lpszQueryString. Строковое значение символов в секции дополнительной информации адреса URL, исключая символ "?". Аналогично значению переменной сервера QUERY_STRING.
- lpszPathInfo. Строковое значение секции URL, находящейся между библиотекой DLL расширения ISAPI и началом секции дополнительной информации URL. Обычно не содержит данных, если запрашивающее ПО не разместило в этом месте определенное значение.
- lpszContentType. Строковое значение типа содержимого отправленных по HTTP данных. Аналогично значению серверной переменной CONTENT_TYPE.
Когда функция HttpExtensionProc завершает получение содержимого всех возможных серверных переменных и свойств ECB, в документе XML указываются закрывающие тегов XML, и он передается функции SendResponse. SendResponse направляет запрашивающей программе строковое значение, переданное в функцию. Заголовок типа содержимого передается запрашивающему клиенту с помощью функции ECB ServerSupportFunction (см. листинг 5.10). Передаваемый заголовок представляется константой BASIC_HEADER, эквивалентной следующей строке: Content-type: text/html\r\n\r\n. За заголовками HTTP следуют два символа возврата каретки и новой строки, поскольку возвращаемые данные представляют собой текст. Можно указать и XML, однако если в запрашивающем браузере в XML зарегистрированы типы Multipurpose Internet Mail Extensions (MIME), то для отображения XML откроется зарегистрированная программа.
Листинг 5.10. Function SendResponse (html, txt)
После отправки заголовка возврата отправляется содержимое с помощью функции WriteClient. Как показано в следующем примере, при передаче данных клиенту отправляется идентификатор соединения ConnID. Имеющееся значение, полученное из текущего экземпляра указателя, использовано в листинге 5.10. Содержимое передается функцией WriteClient с помощью пустого указателя в параметре Buffer. Содержимое, на которое ссылается указатель Buffer, должно равняться количеству байт, передаваемому клиенту, и указываться в параметре lpdwBytes. По завершении вызова lpdwBytes содержит количество переданных байт, если запись не осуществлялась асинхронно. Значение параметра dwSync определяет способ передачи данных клиенту. В листинге 5.10 с помощью макроса HSE_IO_SYNC указывается значение 0х00000001, т.е. запись выполняется синхронно, и пространство памяти, на которое ссылается указатель lpdwBytes, обновится по завершении WriteClient количеством байт, переданным клиенту. Если в макросе HSE_IO_ASYNC представлено значение 0х00000002, то данные, отправляемые клиенту, и функция обратной связи зафиксируют события передачи информации клиенту. Асинхронное использование функции WriteClient требует объявления функции обратной связи, а также отправки функцией ServerSupportFunction значения HSE_REQ_IO_COMPLETION для установки с клиентом транзакции асинхронной записи.
Функция WriteClient является членом ECB. Может показаться странным, что используемое описание ECB передается функции. Поскольку приложение IIS включает несколько нитей, в любой момент времени может потребоваться несколько экземпляров ECB, и вероятно выполнение записи в экземпляре ECB в другой экземпляр ECB. Ниже приведен пример WriteClient:
BOOL WriteClient( HCONN ConnID, LPVOID Buffer, LPDWORD lpdwBytes, DWORD dwSync );
Аналогично значению переменной сервера QUERY_STRING.
Когда функция HttpExtensionProc завершает получение содержимого всех возможных серверных переменных и свойств ECB, в документе XML указываются закрывающие тегов XML, и он передается функции SendResponse. SendResponse направляет запрашивающей программе строковое значение, переданное в функцию. Заголовок типа содержимого передается запрашивающему клиенту с помощью функции ECB ServerSupportFunction (см. листинг 5.10). Передаваемый заголовок представляется константой BASIC_HEADER, эквивалентной следующей строке: Content-type: text/html\r\n\r\n. За заголовками HTTP следуют два символа возврата каретки и новой строки, поскольку возвращаемые данные представляют собой текст. Можно указать и XML, однако если в запрашивающем браузере в XML зарегистрированы типы Multipurpose Internet Mail Extensions (MIME), то для отображения XML откроется зарегистрированная программа.
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Name: SendResponse
In: pECB - pointer to the extension control block sValue - string reference to the value to be written to the HTTP response
Out: nothing
Purpose: writes the intended value to the HTTP response /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ void SendResponse(EXTENSION_CONTROL_BLOCK *pECB, string &sValue) { TCHAR szTempBuffer[BUFFER_LENGTH]; DWORD dwBufferSize = BUFFER_LENGTH;
// set content-type header strcpy(szTempBuffer, BASIC_HEADER); DWORD dwHeaderSize = strlen(szTempBuffer); pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, NULL, &dwHeaderSize, (LPDWORD) szTempBuffer);
// write value to http response DWORD dwLength=sValue.length(); pECB->WriteClient( pECB->ConnID, (PVOID)sValue.c_str(), &dwLength, HSE_IO_SYNC); }
Листинг 5.10. Function SendResponse
После отправки заголовка возврата отправляется содержимое с помощью функции WriteClient. Как показано в следующем примере, при передаче данных клиенту отправляется идентификатор соединения ConnID. Имеющееся значение, полученное из текущего экземпляра указателя, использовано в листинге 5.10. Содержимое передается функцией WriteClient с помощью пустого указателя в параметре Buffer. Содержимое, на которое ссылается указатель Buffer, должно равняться количеству байт, передаваемому клиенту, и указываться в параметре lpdwBytes. По завершении вызова lpdwBytes содержит количество переданных байт, если запись не осуществлялась асинхронно. Значение параметра dwSync определяет способ передачи данных клиенту. В листинге 5.10 с помощью макроса HSE_IO_SYNC указывается значение 0х00000001, т.е. запись выполняется синхронно, и пространство памяти, на которое ссылается указатель lpdwBytes, обновится по завершении WriteClient количеством байт, переданным клиенту. Если в макросе HSE_IO_ASYNC представлено значение 0х00000002, то данные, отправляемые клиенту, и функция обратной связи зафиксируют события передачи информации клиенту. Асинхронное использование функции WriteClient требует объявления функции обратной связи, а также отправки функцией ServerSupportFunction значения HSE_REQ_IO_COMPLETION для установки с клиентом транзакции асинхронной записи.
Функция WriteClient является членом ECB. Может показаться странным, что используемое описание ECB передается функции. Поскольку приложение IIS включает несколько нитей, в любой момент времени может потребоваться несколько экземпляров ECB, и вероятно выполнение записи в экземпляре ECB в другой экземпляр ECB. Ниже приведен пример WriteClient:
BOOL WriteClient( HCONN ConnID, LPVOID Buffer, LPDWORD lpdwBytes, DWORD dwSync );