Россия, Брянск |
Расширения ISAPI
Извлечение информации из IIS
ECB обычно используется для извлечения информации о запросе HTTP и экземпляре сервера IIS, посредством чего расширение ISAPI выполняет определенные программные действия на основе события запроса. В коде листинга 5.3, взятого из расширения ISAPI SEUX (Простое расширение с использованием XML), функция HttpExtensionProc выполняет следующие задачи.
- Построение документа XML со множеством общих серверных переменных, получаемых из функции GetServerVariable.
- Добавление свойств ECB в документ XML.
- Возврат документа XML запрашивающей стороне.
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Name:HttpExtensionProc In: pECB - pointer to the Extension control block structure Out: DWORD - HSE status code Purpose: main entry point for HTTP request the possible return codes are: HSE_STATUS_SUCCESS - everything worked great HSE_STATUS_SUCCESS_AND_KEEP_CONN - same as HSE_STATUS_SUCCESS since IIS 4 HSE_STATUS_PENDING - wait until effort completed HSE_STATUS_ERROR - sends a 500 error code /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB) { string sDoc; //start our XML document sDoc = string(HEAD) + string(NEW_LINE) + string(XML_L) + string(MAIN_ELEMENT_NAME) + string(XML_R) + string(NEW_LINE); //START THE ECBServerVariable VARIABLES sDoc += string(XML_L) + string("ECBServerVariable") + string(XML_R) + string(NEW_LINE); //GET the ALL_HTTP sDoc += string(XML_L) + string("ALL_HTTP"); GetALLHTTPHeader(pECB, &sDoc); sDoc += string(XML_R_END) + string(NEW_LINE);//end the first main element GetECBElement(pECB, string("AUTH_TYPE"), &sDoc); GetECBElement(pECB, string("APPL_MD_PATH"), &sDoc); GetECBElement(pECB, string("APPL_PHYSICAL_PATH"), &sDoc); GetECBElement(pECB, string("CONTENT_LENGTH"), &sDoc); GetECBElement(pECB, string("CONTENT_TYPE"), &sDoc); GetECBElement(pECB, string("GATEWAY_INTERFACE"), &sDoc); GetECBElement(pECB, string("HTTP_ACCEPT"), &sDoc); GetECBElement(pECB, string("HTTPS"), &sDoc); GetECBElement(pECB, string("HTTP_AUTHORIZATION"), &sDoc); GetECBElement(pECB, string("LOGON_USER"), &sDoc); GetECBElement(pECB, string("AUTH_PASSWORD"), &sDoc); GetECBElement(pECB, string("AUTH_TYPE"), &sDoc); GetECBElement(pECB, string("AUTH_USER"), &sDoc); GetECBElement(pECB, string("APPL_PHYSICAL_PATH"), &sDoc); GetECBElement(pECB, string("INSTANCE_ID"), &sDoc); GetECBElement(pECB, string("INSTANCE_META_PATH"), &sDoc); GetECBElement(pECB, string("PATH_INFO"), &sDoc); GetECBElement(pECB, string("PATH_TRANSLATED"), &sDoc); GetECBElement(pECB, string("QUERY_STRING"), &sDoc); GetECBElement(pECB, string("REMOTE_ADDR"), &sDoc); GetECBElement(pECB, string("REMOTE_HOST"), &sDoc); GetECBElement(pECB, string("REMOTE_USER"), &sDoc); GetECBElement(pECB, string("REQUEST_METHOD"), &sDoc); GetECBElement(pECB, string("SCRIPT_NAME"), &sDoc); GetECBElement(pECB, string("SERVER_NAME"), &sDoc); GetECBElement(pECB, string("SERVER_PORT"), &sDoc); GetECBElement(pECB, string("SERVER_PORT_SECURE"), &sDoc); GetECBElement(pECB, string("SERVER_PROTOCOL"), &sDoc); GetECBElement(pECB, string("SERVER_SOFTWARE"), &sDoc); GetECBElement(pECB, string("URL"), &sDoc); //End THE ECBServerVariable VARIABLES sDoc += string(XML_L_END) + string("ECBServerVariable") + string(XML_R) + string(NEW_LINE); //START THE ECBProperties sDoc += string(XML_L) + string("ECBProperties") + string(XML_R) + string(NEW_LINE); GetElement(string("lpszLogData"), string(pECB->lpszLogData),&sDoc); GetElement(string("lpszMethod"), string(pECB->lpszMethod),&sDoc); GetElement(string("lpszQueryString"), string(pECB->lpszQueryString),&sDoc); GetElement(string("lpszPathInfo"), string(pECB->lpszPathInfo),&sDoc); GetElement(string("lpszContentType"), string(pECB->lpszContentType),&sDoc); //end THE ECBProperties sDoc += string(XML_L_END) + string("ECBProperties") + string(XML_R) + string(NEW_LINE); //end our XML document sDoc += string(XML_L_END) + string(MAIN_ELEMENT_NAME) + string(XML_R) + string(NEW_LINE); //write it! SendResponse(pECB,sDoc); return HSE_STATUS_SUCCESS; }Листинг 5.3. HttpExtensionProc Function Building XML Document in SEUX ISAPI Extension
Примечание. Исходный код SEUX доступен на веб-сайте автора книги (см. введение).
Построение XML для представления значений серверных переменных
Первой задачей (см. листинг 5.3) является открытие документа XML посредством присоединения некоторых констант, представляющих собой части документа XML. Построение XML происходит вручную, и константы объявляются для общих частей документа XML, так как они используются во многих местах. Документ XML размещается в строковой переменной с именем sDoc. Ниже приведены константы XML:
//xml parts const char* MAIN_ELEMENT_NAME = "HTTPRequestRaw"; const char* QUOTE ="\""; const char* XML_L ="<"; const char* XML_R =">"; const char* XML_L_END ="</"; const char* XML_R_END ="/>"; const char* NEW_LINE ="\n"; const char* HEAD = "<?xml version=\"1.0\"?>";
Рассматриваемый документ XML достаточно прост, поэтому его построение вручную не вызывает никаких трудностей. Для более сложного документа рекомендуется использовать аналитическую библиотеку XML, такую как MSXML.
После инициализации документа XML начинается работа по размещению в элементах XML всех серверных переменных. Создаваемый документ XML имеет родительский элемент HTTPRequestRaw. Внутри HTTPRequestRaw содержатся два дочерних элемента с ECBServerVariable и ECBProperties. Для каждого значения серверной переменной, запрашиваемого из ECB, будет создаваться дочерний элемент для элемента ECBServerVariable, независимо от получения значения соответствующей серверной переменной. Для каждого запрошенного свойства ECB создается дочерний элемент под элементом ECBProperties, которое содержит значение независимо от получения значения свойства. При вызове расширения ISAPI SEUX с помощью IE 6.0 отобразится документ XML (см. рис. 5.12). В других версиях браузера XML может отобразится по-другому или не отобразиться вовсе.
увеличить изображение
Рис. 5.12. IE 6.0, отображающий документ XML серверных переменных из расширения SEUX ISAPI
Специальный случай серверной переменной ALL_HTTP
Первой серверной переменной, для которой получается значение, является переменная ALL_HTTP, представляющая собой все заголовки HTTP, переданные в запросе HTTP. Результатом остальных запрошенных серверных переменных является число или строка, легко согласуемая с XML, однако ALL_HTTP возвращает все заголовки в одну и ту же серверную переменную.
Заголовки в значении, возвращаемом из ALL_HTTP, ограничены символами новой строки, поэтому требуется дополнительный анализ для размещения каждого заголовка в элементе XML в качестве атрибута. Функция GetALLHTTPHeader выполняет данную задачу с помощью функции ECB GetServerVariable (см. листинг 5.4).
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Name:GetALLHTTPHeader In: pECB - pointer to the Extension control block structure psElement - string pointer to XML document being built that will be updated with the element for the ALL_HTTP server variable value. Out: nothing returned but the string psElement points to will be updated. Purpose: Updates the XML document string by adding an element for the ALL_HTTP server variable. This variable contains all of the http headers so some additional parsing must take place on the headers to format them into XML. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ void GetALLHTTPHeader(EXTENSION_CONTROL_BLOCK *pECB, string *psElement) { TCHAR szTempBuffer[BUFFER_LENGTH]; DWORD dwBufferSize = BUFFER_LENGTH; const string EQUAL("="); const string SPACE(" "); string sAllHeaders; //used to cut up 'all headers' returned int nNewLinePos = 0; int nEndLinePos = 0; string sName; string sValue; //pull the whole HTTP header if (pECB->GetServerVariable( pECB->ConnID, "ALL_HTTP", szTempBuffer, &dwBufferSize)) { //if the whole http header was pulled then parse it sAllHeaders.assign(szTempBuffer); //get the name / value pairs while (GetHeaderValuePair( sAllHeaders, nNewLinePos, &sName, &sValue, &nEndLinePos)) { //add the attribute to the element psElement->append( SPACE + sName + EQUAL + QUOTE + ValidateValue(sValue) + QUOTE); //reset the newline to the last endline nNewLinePos = nEndLinePos; //dump the values sName.erase(); sValue.erase(); } } }Листинг 5.4. GetALLHTTPHeader Function Building XML Element in SEUX ISAPI Extension
Функция GetServerVariable
Функция GetServerVariable возвращает значение "истина" при успешном выполнении и значение "ложь" при возникновении ошибки, как показано в следующем примере:
BOOL WINAPI GetServerVariable( HCONN hConn, LPSTR lpszVariableName, LPVOID lpvBuffer, LPDWORD lpdwSizeofBuffer );
Прототип GetServerVariable в данном случае требует передачи четырех параметров.
- hConn. Поддержка соединения, полученная от ECB.
- lpszVariableName. Строка с символом конца строки запрашиваемой серверной переменной.
- lpvBuffer. Пустой указатель на буфер, который заполняется результирующим значением имени переменной и байтом конца строки.
- lpdwSizeofBuffer. Указатель на значение DWORD, отражающее размер буфера.
При успешном выполнении функция GetServerVariable возвращает значение "истина". Указатель lpvBuffer указывает значение запрашиваемой серверной переменной, а lpdwSizeofBuffer – на новое значение DWORD, отражающее текущий размер значения, включая байт конца строки. При неудачном завершении работы функция GetServerValue возвращает значение "ложь". В этом случае вызывается функция GetLastError, которая возвращает значение DWORD, представляющее собой код ошибки. В таблице 5.2 показаны возможные ошибки функции GetServerVariable ; это константы, определяемыми во вспомогательном файле заголовка расширения ISAPI.