使用TEmbeddedWB或TWebBrowser检测外部内容

4
我正在尝试阻止由TEmbeddedWB或TWebBrowser(或TCppWebBrowser)加载的任何外部内容。我想要阻止从互联网加载的任何内容,包括图像、javascript、外部CSS、外部[embed]或[object]或[applet]或[frame]或[iframe],执行可以加载外部内容的JavaScript等。
这个问题包含两个部分:
1. 将Web浏览器置于“限制所有”模式(除了基本的HTML没有图像),并检测是否存在此类内容。 2. 如果不存在外部内容,则正常显示;如果存在,则显示一个“下载栏”,点击后将Web浏览器置于“下载所有”模式并获取所有内容。
第一项存在问题。在TEmbeddedWB中,您可以使用DownloadOptions开关阻止几乎所有内容,其中最重要的是ForceOffline开关,但即使关闭所有开关,它仍会通过一些内容,如[object]或[iframe]标记。我知道这是这种情况,因为我实现了OnBeforeNavigate2事件,并且它会触发这些标记中包含的URL,并在本地服务器日志中进行记录。在TEmbeddedWB中设置OfflineMode和ForceOfflineMode对于这些项目无效。
那么我该如何真正阻止所有内容?因此,它需要作为基本HTML开始,其中包括被阻止的外部元素,包括脚本和CSS。有没有一种方法可以在每次下载任何内容时触发事件,以便可以阻止它或通过阻止所有外部下载来避免首先触发此类事件?我需要调整Internet Explorer区域和安全性吗?任何指向正确方向的指针都将有所帮助。
第二项也很棘手,因为我需要检测是否存在问题标记(例如“applet”、“script”、“link”等)。这种检测不需要完美,但必须足够好以涵盖大多数此类标记。我是这样做的:
//----------------------------------------------------------------------
// Check for external content (images, scripts, ActiveX, frames...)
//----------------------------------------------------------------------
try
    {    
    bool                                HasExternalContent = false;
    DelphiInterface<IHTMLDocument2>     diDoc;                              // Smart pointer wrapper - should automatically call release() and do reference counting
    diDoc = TEmbeddedWB->Document;

    DelphiInterface<IHTMLElementCollection>     diColApplets;           DelphiInterface<IDispatch>          diDispApplets;      DelphiInterface<IHTMLObjectElement> diObj;
    DelphiInterface<IHTMLElementCollection>     diColEmbeds;            DelphiInterface<IDispatch>          diDispEmbeds;
    DelphiInterface<IHTMLFramesCollection2>     diColFrames;            DelphiInterface<IDispatch>          diDispFrames;
    DelphiInterface<IHTMLElementCollection>     diColImages;            DelphiInterface<IDispatch>          diDispImages;       DelphiInterface<IHTMLImgElement>    diImg;
    DelphiInterface<IHTMLElementCollection>     diColLinks;             DelphiInterface<IDispatch>          diDispLinks;
    DelphiInterface<IHTMLElementCollection>     diColPlugins;           DelphiInterface<IDispatch>          diDispPlugins;
    DelphiInterface<IHTMLElementCollection>     diColScripts;           DelphiInterface<IDispatch>          diDispScripts;
    DelphiInterface<IHTMLStyleSheetsCollection> diColStyleSheets;       DelphiInterface<IDispatch>          diDispStyleSheets;

    OleCheck(diDoc->Get_applets     (diColApplets));
    OleCheck(diDoc->Get_embeds      (diColEmbeds));
    OleCheck(diDoc->Get_frames      (diColFrames));
    OleCheck(diDoc->Get_images      (diColImages));
    OleCheck(diDoc->Get_links       (diColLinks));
    OleCheck(diDoc->Get_plugins     (diColPlugins));
    OleCheck(diDoc->Get_scripts     (diColScripts));
    OleCheck(diDoc->Get_styleSheets (diColStyleSheets));

    // Scan for applets external links
    for (int i = 0; i < diColApplets->length; i++)
        {
        OleCheck(diColApplets->item(i,i,diDispApplets));
        if (diDispApplets != NULL)
            {
            diDispApplets->QueryInterface(IID_IHTMLObjectElement, (void**)&diObj);
            if (diObj != NULL)
                {
                UnicodeString s1 = Sysutils::Trim(diObj->data),
                              s2 = Sysutils::Trim(diObj->codeBase),
                              s3 = Sysutils::Trim(diObj->classid);

                if (StartsText("http", s1) || StartsText("http", s2) || StartsText("http", s3))
                    {
                    HasExternalContent = true;
                    break;                                                  // At least 1 found, bar will be shown, no further search needed
                    }
                }
            }
        }

    // Scan for images external links
    for (int i = 0; i < diColImages->length; i++)
        {
        OleCheck(diColImages->item(i,i,diDispImages));
        if (diDispImages != NULL)                                           // Unnecessary? OleCheck throws exception if this applies?
            {
            diDispImages->QueryInterface(IID_IHTMLImgElement, (void**)&diImg);
            if (diImg != NULL)
                {
                UnicodeString s1 = Sysutils::Trim(diImg->src);

                // Case insensitive check
                if (StartsText("http", s1))
                    {
                    HasExternalContent = true;
                    break;                                                  // At least 1 found, bar will be shown, no further search needed
                    }
                }
            }
        }
    }
catch (Exception &e)
    {
    // triggered by OleCheck
    ShowMessage(e.Message);
    }

有没有更简单的方法来扫描这个问题,或者唯一的方法是使用其他接口函数运行几个循环,例如Get_appletsGet_embedsGet_stylesheets等类似于上面的代码?到目前为止,我发现我必须调用以下函数来覆盖所有内容:

    OleCheck(diDoc->Get_applets     (diColApplets));
    OleCheck(diDoc->Get_embeds      (diColEmbeds));
    OleCheck(diDoc->Get_frames      (diColFrames));
    OleCheck(diDoc->Get_images      (diColImages));
    OleCheck(diDoc->Get_links       (diColLinks));
    OleCheck(diDoc->Get_plugins     (diColPlugins));
    OleCheck(diDoc->Get_scripts     (diColScripts));
    OleCheck(diDoc->Get_styleSheets (diColStyleSheets));

但如果有更简单的处理方式,我不想实现那么多循环。有吗?


“我想要阻止从互联网加载的任何内容”这句话的意思是您想要离线模式吗?如果是这样,只需将 TWebBrowser.Offline 设置为 True 即可;-) - TLama
如果真的那么容易就好了。我设置了离线和强制离线标志,但仍然会加载一些外部内容,例如[object]标签或某些框架。 - Coder12345
你的HTML有多复杂?你需要使用Internet Explorer吗? - Pol
是的,我需要IE - HTML并不是微不足道的。我已经考虑过使用RegEx和类似的解决方案来过滤HTML。问题也在于这方面的文档非常糟糕,而且示例很少(除非我想进入完整的C++模式 - 然后我有相对详细的MSDN文档)。上面的代码是从各种来源进行大量搜索的结果,我甚至不确定它是否正确,涉及内存泄漏等等,尽管它可以工作 :) - Coder12345
其他想法/选项...你说的IE...IE是指IE浏览器还是Internet Explorer?你试过TChromium了吗? - Whiler
让我们把这当作最后的解决方案。IE控件对于这些目的工作得很好,而且它还有一些我不确定Chromium是否具备的功能——编辑模式。更不用说市场份额等等了。而且我相信肯定有解决方案或者至少是解决方法来阻止所有下载,所以我还没有到那个地步。 - Coder12345
1个回答

2
我建议您尝试这个解决方案:
#include "html.h"
THTMLDocument doc;
void __fastcall TForm1::CppWebBrowser1DocumentComplete(TObject *Sender, LPDISPATCH pDisp,
          Variant *URL)
{
    doc.documentFromVariant(CppWebBrowser1->Document);

    bool HasExternalContent = false;
    for (int i=0; i<doc.images.length; i++) {
        if(doc.images[i].src.SubString(1, 4) == "http")
        {
            HasExternalContent = true;
            break;
        }
    }
    for (int i=0; i<doc.applets.length; i++) {
        THTMLObjectElement obj = doc.applets[i];
        if(obj.data.SubString(1, 4) == "http")
            HasExternalContent = true;
        if(obj.codeBase.SubString(1, 4) == "http")
            HasExternalContent = true;
        if(obj.classid.SubString(1, 4) == "http")
            HasExternalContent = true;
    }
}

这个强大的封装类可以从 这里下载。

这看起来真的很有用。这个包装器是用来做什么的?那个网站上或者课堂上都没有太多的信息。 - Coder12345
这个包装器是我自己编写的,适用于具有HTML UI或任何与HTML相关的目的的应用程序。使用此包装器,您还可以在C++ Builder中处理HTML事件,例如“onmouseclick”;有关更多信息,请参见此处 - mh taqia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接