HTML代碼過濾技術

來源:互聯網
上載者:User

 

參考資料:MSDN的《Pluggable Protocols Overview》

參考樣本:MSDN提供的

       http://support.microsoft.com/default.aspx?scid=kb;EN-US;q260840#appliesto

       另一樣本是用Delphi寫的:http://www.guicode.com/scr/mimefilter.zip

要實現HTML代碼過濾必需註冊一個或多個MIME過濾器(Pluggable MIME Filter)。

MIME過濾器是一個COM對象,必需實現IInternetProtocolSink和IInternetProtocol介面。MIME過濾器可以註冊成臨時或者永久的,如果同時註冊多個臨時的MIME過濾器,那麼後註冊的對象先被調用!

       要如何註冊一個MIME過濾器?要註冊一個永久的MIME過濾器,你必需在註冊表

的HKEY_CLASSES_ROOT"PROTOCOLS"Filter鍵下添加一個子鍵,子鍵的名稱是你要

註冊的MIME類型

,在添加的子鍵下必需有一個名為CLSID的字串值,值的內容就是你

提供的COM對象的CLSID。該鍵的預設值可以是關於你的對象的簡單描述。如果你用ATL

了開發,你可以在對象的RGS檔案中添加如下內容:

HKCR

{

         NoRemove PROTOCOLS

         {

                   NoRemove Filter

                  {

                           ForceRemove 'text/html' = s 'XMLMimeFilter MIME Filter Sample'

                            {

                                     val CLSID = s '{53B95211-7D77-11D2-9F80-00104B107C96}'

                            }

                   }

         }

}

上面的代碼來自文章開頭提到的樣本。’XMLMimeFilter MIME Filter Sample’和

{53B95211-7D77-11D2-9F80-00104B107C96}'都要換成你自已的!

    如果要註冊臨時的MIME過濾器,就要通過IInternetSession介面(取消註冊也

用該介面),下面提供的註冊一個臨時過濾器的代碼:

CComPtr<IInternetSession> m_spSession ;

CComPtr<IClassFactory>    m_spClassFactoryMime ;

hr = ::CoGetClassObject( CLSID_MimeFilter, CLSCTX_SERVER,

                                               NULL, IID_IClassFactory,

                             (void**)&m_spClassFactoryMime );

if( hr == S_OK )

{

         if( ::CoInternetGetSession( 0, &m_spSession, 0) ==S_OK )

         {

                   m_spSession->RegisterMimeFilter(m_spClassFactoryMime,

      CLSID_MimeFilter,                                                                                                                                      L"text/html" );

          }

 }

 這裡的CLSID_MimeFilter就是你的對象的CLSID。

 MIME的類型有許多種,要瞭解這些資訊可以查看MSDN的附錄

《MIME Type Detection in Internet Explorer 4.0》,但實際的類型要比這裡列的多得多。

要瞭解你的電腦註冊的MIME類型,可以查看註冊表的[HKEY_CLASSES_ROOT"MIME"

Database"Content Type]鍵。也可以通過調用FindMimeFromData函數來得到檔案的對應MIME

類型,下面的程式碼範例了得到JS檔案的MIME類型:

LPWSTR pwzMimeOut ;

FindMimeFromData( NULL , L"time.js" , 0 , 0 , 0 , 0 , &pwzMimeOut , 0 );

得到的MIME類型是:application/x-javascript。

       一般情況下,要過濾HMTL頁面,可以註冊text/html類型。你也可以根據實際情況

通過調用RegisterMimeFilter註冊多個不同的MIME過濾器。

        註冊一個臨時或永久的MIME過濾器後,接下來的工作就是實現MIME過濾器對象。

在實現之前,先看一下《Pluggable Protocols Overview》一文中關於MIME過濾器與WEB

處理器(transaction handler,即urlmon.dll)之間介面的調用的描述(註:urlmon.dll內部實現了IInternetProtocol和IInternetProtocolSink介面):

 1、 WEB處理器調用MIME過濾器的IInternetProtocolRoot::Start方法(IInternetProtocol

從IInternetProtocolRoot派生);

2、 WEB處理器先後調用MIME過濾器的IInternetProtocolSink::ReportProgress 和

IInternetProtocolSink::ReportData方法;

3、 MIME過濾器調用WEB處理器的IInternetProtocol::Read方法;

4、 MIME過濾器調用WEB處理器的IInternetProtocolSink::ReportData方法;

5、 WEB處理器調用MIME過濾器的IInternetProtoco::Read方法;

 因此,要實現MIME過濾器,有幾個重要的方法:

1、IInternetProtocolRoot::Start方法:

HRESULT Start(

    [in] LPCWSTR szUrl,

    [in] IInternetProtocolSink *pOIProtSink,

    [in] IInternetBindInfo *pOIBindInfo,

    [in] DWORD grfPI,

    [in] DWORD dwReserved

);

作為MIME過濾對象,szUrl傳入的是MIME的類型(如果是name space handlers對象,

則該參數為一個即將下載或解析的URL)。若是你想得到URL,可以通過pOIBindInfo 接

口得到,下面是樣本:

       LPOLESTR pwzUrl ;           

       ULONG uElFetched ;

       pIBindInfo->GetBindString( BINDSTRING_URL , &pwzUrl , 1 , &uElFetched ) ;

 pOIProtSink是由urlmon.dll提供的IInternetProtocolSink介面,因為在後面的處理過程中,需要調用到該介面,所以要將它儲存;

grfPI是一個枚舉變數,必需包含PI_FILTER_MODE標誌,表示該對象運行在filter模式中。

dwReserved是一個指向PROTOCOLFILTERDATA結構的指標,該結構的pProtocol成員是由urlmon.dll提供的IInternetProtocol介面,因為在後面的處理過程中需要調用到該介面,所以要將它儲存。實際上該介面也可以通過pOIProtSink參數調用QueryInterface得到,同樣PROTOCOLFILTERDATA結構的pProtocolSink與pOIProtSink都是指向同一個介面。

        在Start方法中,我們必需做的實際上只是儲存urlmon.dll提供的IInternetProtocolSink

和IInternetProtocol介面。

 2、IInternetProtocolSink::ReportProgress方法:

HRESULT ReportProgress(

    [in] ULONG ulStatusCode,

 

    [in] LPCWSTR szStatusText )

 作為MIME過濾器,ulStatusCode一般都是BINDSTATUS_CACHEFILENAMEAVAILABLE , 當

 ulStatusCode為BINDSTATUS_CACHEFILENAMEAVAILABLE時,szStatusText為臨時快取檔案

 的路徑名稱,但有一些網頁並不寫到緩衝裡,所以szStatusText可能為空白字串。

 3、IInternetProtocolSink::ReportData方法:

 HRESULT ReportData(

    [in] DWORD grfBSCF,
    [in] ULONG ulProgress,
    [in] ULONG ulProgressMax
);

IE下載檔案過程中或下載完畢時會調用MIME過濾器的ReportData方法,ulProgressMax

 

為檔案總是資料量,ulProgress為下載進度,理論上當檔案全部下載完後,ulProgress應

 等於ulProgressMax(實際上,當網頁檔案不是很大時,即使ulProgress不等於ulProgressMax時,檔案也可能全部下載下來),還有一個反應檔案下載情況的參數是grfBSCF。有時,ReportData方法會被Web處理器調用多次。

     ReportData是過濾網頁內容或修改網頁內容比較合適的地方。在此地,可以將網頁內容通過調用Read儲存到自已的緩衝或流中並做適當的處理(注意檢查字元的編碼)。

 最後,別忘了調用Web處理器的IInternetProtocolSink::ReportData方法,向它彙報資料下載的情況。Web處理器得到此通知後,就會調用MIME過濾器的IInternetProtocol::Read,此時,你就可以將修改後的資料交給WEB處理器。

    下面的程式碼範例了如何在ReportData中調用Web處理器的Read預先儲存資料:

 

// m_spIncomingProt是在Start中儲存的Web處理器的IInternetProtocol介面

// m_spStm 是IStream 指標,用來快取資料

 

BYTE buffer[ SIZE_BUFFER ] ;

 DWORD cbRead ;

 do

 {              

     cbRead = 0 ;       

     hr = m_spIncomingProt->Read( buffer , SIZE_BUFFER , &cbRead ) ;

     if( cbRead > 0 ) **A 處

    {

        if( m_spStm->Write( buffer , cbRead , NULL ) == S_OK )

         {

             m_cbTotal += cbRead ;

         }

 }

 }while ( hr == S_OK );

 Read成功取得資料一般只返回S_OK或S_FALSE ,返回S_OK表示還有資料,而S_FALSE

 表示資料已讀取完畢,因此迴圈的條件設為 hr==S_OK。那A處的條件判斷為什麼不是

 if( hr == S_OK || hr == S_FALSE ) 呢, 因為我發現某些情況下,Read可能返回其

 它值,但仍然有成功讀取一部分資料出來,資料的大小就是cbRead指定的值。如果將

 那部分資料遺落,網頁將無法正常解析!那這樣會不會導致因讀取失敗而將一些無用的

 資料儲存到緩衝中?至少目前還沒碰到過。

 4、IInternetProtocol::Read方法

     該方法由WEB處理器調用來取得瀏覽器要解析的資料。在上一方法ReportData中

 我們已經將所有資料緩衝到流中,因此,這裡只需將流中的資料返回給WEB處理器。

 下面的程式碼範例了Read中的簡單處理:

    if( m_spStm->Read( pv , cb , pcbRead ) == S_OK )

     {

          if( *pcbRead == cb )

          {

              return S_OK ;

          }

          else

              return S_FALSE ;

      }

       千萬注意,在資料已讀取完畢時要返回S_FALSE , 不然可能導致Read被無窮迴圈調用。

 處理完這幾個方法後,基本是大功造成,其它一些方法處理十分簡單,可以參考上面

 提到的例子。 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.