基于Vc++開(kāi)發(fā)IIS7以及IIS6的萬(wàn)能篩選器
一、iis6篇
1)新建工程:準(zhǔn)備好vs6以后,新建新工程,選擇"ISAPI Filter Wizard" 工程類(lèi)型,一路下一步之后,工程目錄就出來(lái)了(暫時(shí)將我們初始化的filter類(lèi)命令為CTestFilter)。
2)打開(kāi)vs初始化的工程,打開(kāi)CTestFilter.cpp文件,我們可以看到有一個(gè)自動(dòng)生成的函數(shù):
BOOL CTestFilter::GetFilterVersion(PHTTP_FILTER_VERSION pVer)
{
// Call default implementation for initialization
CTestFilter::GetFilterVersion(pVer);
// Clear the flags set by base class
pVer->dwFlags &= ~SF_NOTIFY_ORDER_MASK;
// Set the flags we are interested in
pVer->dwFlags |= SF_NOTIFY_ORDER_HIGH| SF_NOTIFY_PREPROC_HEADERS | SF_NOTIFY_SEND_RAW_DATA;
// Load description string
TCHAR sz[SF_MAX_FILTER_DESC_LEN+1];
ISAPIVERIFY(::LoadString(AfxGetResourceHandle(),
IDS_FILTER, sz, SF_MAX_FILTER_DESC_LEN));
_tcscpy(pVer->lpszFilterDesc, sz);
return TRUE;
}
不要關(guān)注其他代碼,只需要關(guān)注紅色字體部分,這幾個(gè)系統(tǒng)常量是用來(lái)指定篩選器需要攔截哪些http內(nèi)容的,我簡(jiǎn)單攔截類(lèi)型有好幾種,詳細(xì)信息可以查詢(xún)msdn的文檔,我只簡(jiǎn)單介紹下其中的SF_NOTIFY_PREPROC_HEADERS和 SF_NOTIFY_SEND_RAW_DATA,SF_NOTIFY_PREPROC_HEADERS代表在iis處理http的header請(qǐng)求時(shí)觸發(fā)一次攔截,而SF_NOTIFY_SEND_RAW_DATA代表在iis向客戶(hù)端回寫(xiě)http的response內(nèi)容前觸發(fā)攔截,在這個(gè)攔截當(dāng)中,你可以接收到response的指針,修改response的內(nèi)容。
3)還是用wizard,去實(shí)現(xiàn)CHttpFilter基類(lèi)的各個(gè)攔截方法(需要與前面的GetFilterVersion方法中指定的攔截事件對(duì)應(yīng),否則iis不會(huì)觸發(fā)這些方法的),這里我還是介紹下與上一步向?qū)?yīng)的OnSendRawData(CHttpFilterContext* pfc, PHTTP_FILTER_RAW_DATA pRawData)和OnPreprocHeaders(CHttpFilterContext* pfc,PHTTP_FILTER_PREPROC_HEADERS pHeaders)兩個(gè)函數(shù),大家可以很容易地看出這兩個(gè)函數(shù)與前面兩個(gè)攔截類(lèi)型的對(duì)應(yīng)關(guān)系。OnPreprocHeaders是專(zhuān)門(mén)用來(lái)在iis處理http請(qǐng)求前,對(duì)客戶(hù)端的http header進(jìn)行處理,其中入?yún)Headers是個(gè)結(jié)構(gòu)型數(shù)據(jù),其中包含了一個(gè)指向header對(duì)象的指針,我們可以拿到這個(gè)指針進(jìn)行預(yù)處理,并可以修改headers的內(nèi)容。
OnSendRawData可以說(shuō)是這些方法中最強(qiáng)悍的了,它可以拿到iis的response內(nèi)容,并可以修改response的內(nèi)容,其中pRawData這個(gè)結(jié)構(gòu)型的入?yún)⒕桶藃esponse內(nèi)容的指針,還是上代碼給大家講講這個(gè)函數(shù)是如何去修改一切的吧:
DWORD CTestFilter::OnSendRawData(CHttpFilterContext* pfc, PHTTP_FILTER_RAW_DATA pRawData)
{
// TODO: Add your specialized code here and/or call the base class
CString resp="Hello isapi??!";
void* mem=(void*)pfc->AllocMem(resp.GetLength());//必須使用isapi提供的申請(qǐng)內(nèi)存方法,才能正常返回http內(nèi)容,用isapi的方法申請(qǐng)的內(nèi)存,iis會(huì)自動(dòng)幫你回收
memset(mem,0,resp.GetLength());
memcpy(mem,resp.GetBuffer(0),resp.GetLength());
pRawData->cbInBuffer=resp.GetLength();
pRawData->cbInData=resp.GetLength();
pRawData->pvInData=mem;
return SF_STATUS_REQ_NEXT_NOTIFICATION;
}
這樣修改過(guò)后,所有客戶(hù)端的請(qǐng)求都變成了”Hello isqpi??!“了,而且連正常的http頭都被去掉了。
4)部署:編譯完成剛才的工程后,我們可以得到一個(gè)TestFilter.dll的文件,打開(kāi)iis6的管理頁(yè)面,進(jìn)入web站點(diǎn)的屬性對(duì)話(huà)框,到isapi的選項(xiàng)卡中,添加我們剛才生成的dll文件,并重啟iis服務(wù)器,ok,iis就只會(huì)返回”Hello isapi!!“了。
二、iis7篇
伴隨著windows server2008的出現(xiàn),iis7也一起推出,iis7雖然也可以通過(guò)很曲折的方式,實(shí)現(xiàn)isapi接口功能,但根據(jù)實(shí)踐的情況來(lái)開(kāi),iis7在使用isapi擴(kuò)展來(lái)實(shí)現(xiàn)攔截功能時(shí),經(jīng)常會(huì)出現(xiàn)攔截不了的煩人問(wèn)題,這時(shí)我們?cè)诓殚喠舜罅抠Y料后發(fā)現(xiàn),iis7對(duì)isapi的支持本來(lái)就不好,因?yàn)槲④浻衷趇is7這個(gè)平臺(tái)上推出了一個(gè)更強(qiáng)大的攔截實(shí)現(xiàn),那就是iis擴(kuò)展模塊,iis7的所有功能都是通過(guò)加載不同的模塊來(lái)實(shí)現(xiàn)的,而且為我們實(shí)現(xiàn)攔截器特別提供了一個(gè)httpmodule的模塊,這個(gè)模塊是凌駕于所有http請(qǐng)求的,不管你使用的asp還是asp.net甚至是借用iis做服務(wù)器的php服務(wù)器,所有的請(qǐng)求都會(huì)先經(jīng)過(guò)這個(gè)模塊來(lái)處理,難怪微軟不會(huì)去關(guān)注iis7對(duì)isapi的兼容問(wèn)題,它要推新東西了嘛~
下面我們就介紹下如何通過(guò)iis的模塊來(lái)實(shí)現(xiàn)攔截并修改http請(qǐng)求的功能:
1)環(huán)境準(zhǔn)備:visual studio2008/2005+iis7+windows server2008。
2)新建c++工程:在vs中新建一個(gè)空的動(dòng)態(tài)鏈接庫(kù)的工程。
3)新建一個(gè)CHttpModule的子類(lèi)CMyHttpModule(需要基于對(duì)頭文件httpserv.h的引用),并實(shí)現(xiàn)一個(gè)虛方法OnBeginRequest:
#define _WINSOCKAPI_
#include <windows.h>
#include <sal.h>
#include <httpserv.h>
class CMyHttpModule: public CHttpModule
{
public:
REQUEST_NOTIFICATION_STATUS
OnBeginRequest(
IN IHttpContext * pHttpContext,
IN IHttpEventProvider * pProvider
)
{
UNREFERENCED_PARAMETER( pProvider );
// 創(chuàng)建一個(gè) HRESULT 來(lái)接收方法返回值.
HRESULT hr;
// 獲取一個(gè)指向response對(duì)象的指針.
IHttpResponse * pHttpResponse = pHttpContext->GetResponse();
if (pHttpResponse != NULL)
{
// 直接清理掉原來(lái)的response內(nèi)容.
pHttpResponse->Clear();
// 設(shè)置response的格式.
pHttpResponse->SetHeader(
HttpHeaderContentType,"text/plain",
(USHORT)strlen("text/plain"),TRUE);
PCSTR pszBuffer = "Hello HttpModule?。?!";
// 創(chuàng)建一個(gè)數(shù)據(jù)塊.
HTTP_DATA_CHUNK dataChunk;
// 把數(shù)據(jù)塊類(lèi)型設(shè)置成http類(lèi)型的(后續(xù)的內(nèi)存清理工作就會(huì)由iis容器自己完成).
dataChunk.DataChunkType = HttpDataChunkFromMemory;
DWORD cbSent;
// 給數(shù)據(jù)塊賦值.
dataChunk.FromMemory.pBuffer =
(PVOID) pszBuffer;
dataChunk.FromMemory.BufferLength =
(USHORT) strlen(pszBuffer);
// 將數(shù)據(jù)塊插入到response內(nèi)容中.
hr = pHttpResponse->WriteEntityChunks(
&dataChunk,1,FALSE,TRUE,&cbSent);
if (FAILED(hr))
{
pHttpResponse->SetStatus(500,"Server Error",0,hr);
}
return RQ_NOTIFICATION_FINISH_REQUEST;
}
return RQ_NOTIFICATION_CONTINUE;
}
}
4)新建一個(gè)實(shí)現(xiàn)了IHttpModuleFactory接口的工廠類(lèi),用來(lái)注冊(cè)攔截模塊和攔截的方式
class CMyHttpModuleFactory : public IHttpModuleFactory
{
public:
HRESULT
GetHttpModule(
OUT CHttpModule ** ppModule,
IN IModuleAllocator * pAllocator
)
{
UNREFERENCED_PARAMETER( pAllocator );
// 實(shí)例化一個(gè)模塊的指針.
CMyHttpModule * pModule = new CMyHttpModule;
if (!pModule)
{
return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
}
else
{
*ppModule = pModule;
pModule = NULL;
return S_OK;
}
}
void
Terminate()
{
// 清理自己的內(nèi)存.
delete this;
}
};
// 用來(lái)注冊(cè)模塊工廠的方法.
HRESULT
__stdcall
RegisterModule(
DWORD dwServerVersion,
IHttpModuleRegistrationInfo * pModuleInfo,
IHttpServer * pGlobalInfo
)
{
UNREFERENCED_PARAMETER( dwServerVersion );
UNREFERENCED_PARAMETER( pGlobalInfo );
// 設(shè)置需要攔截的方式,這里設(shè)置的是給客戶(hù)端返回response內(nèi)容前,和我們之前iis6的示例類(lèi)似,可以設(shè)置多個(gè),但必須和你的httpmodule中對(duì)應(yīng).
return pModuleInfo->SetRequestNotifications(
new CMyHttpModuleFactory,
RQ_BEGIN_REQUEST,
0
);
}
5)編譯并生成一個(gè)MyHttpModule.dll的動(dòng)態(tài)鏈接庫(kù),將保存MyHttpModule.dll的全路徑添加到%windir%\system32\inetsrv\config\applicationHost.config文件的globalModules節(jié)點(diǎn)下,重啟iis,ok,這下訪(fǎng)問(wèn)你iis中的任何一個(gè)文件,返回的內(nèi)容都會(huì)是:“Hello HttpModule?。?!”。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線(xiàn),公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性?xún)r(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專(zhuān)為企業(yè)上云打造定制,能夠滿(mǎn)足用戶(hù)豐富、多元化的應(yīng)用場(chǎng)景需求。
當(dāng)前標(biāo)題:IIS篩選器編程-創(chuàng)新互聯(lián)
網(wǎng)站路徑:http://aaarwkj.com/article34/jdpse.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供電子商務(wù)、網(wǎng)站策劃、建站公司、品牌網(wǎng)站建設(shè)、企業(yè)網(wǎng)站制作、用戶(hù)體驗(yàn)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容