Skip to content Skip to sidebar Skip to footer

Cefsharp Inject Javascript Prior To Any Document Load/processing

For a project I am working on I need to inject javascript prior to any of the webpage document processing begins. This can easily be achieved via the WebBrowser component, but I a

Solution 1:

Finally got back to this. Heavily based on example found in: CefSharp.Example/Filters/FindReplaceResponseFilter.cs

implementing the IRequestHandler and IResponseFilter interfaces:

==MainWindow.xaml==

<Windowx:Class="ExampleCefSharp001.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:cefSharp="clr-namespace:CefSharp.Wpf;assembly=CefSharp.Wpf"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:ExampleCefSharp001"mc:Ignorable="d"Title="MainWindow"Height="1000"Width="1100"><Grid><cefSharp:ChromiumWebBrowserx:Name="uiWebView"></cefSharp:ChromiumWebBrowser></Grid></Window>

==MainWindow.xaml.cs==

publicpartialclassMainWindow : Window
{
  JavascriptManager jsmanager;

  publicMainWindow()
  {
    InitializeComponent();

    jsmanager = new JavascriptManager(uiWebView);
  }
}

publicclassJavascriptManager : IRequestHandler
{
  string injection = "window.InjectedObject = {};";

  publicJavascriptManager(ChromiumWebBrowser browser)
  {
    browser.RequestHandler = this;

    //  Lets just pretend this is a real url with the example html above.
    browser.Address = "https://www.example.com/timingtest.htm"
  }

  public IResponseFilter GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
    {
        if (frame.IsMain && request.ResourceType == ResourceType.MainFrame) 
        {
            returnnew JavascriptInjectionFilter(injection);
        }
        returnnull;
    }
}

publicclassJavascriptInjectionFilter : IResponseFilter
{
    ///<summary>/// Location to insert the javascript///</summary>publicenum Locations
    {
        ///<summary>/// Insert Javascript at the top of the header element///</summary>
        head,
        ///<summary>/// Insert Javascript at the top of the body element///</summary>
        body
    }

    string injection;
    string location;
    int offset = 0;
    List<byte> overflow = new List<byte>();

    ///<summary>/// Constructor///</summary>///<param name="injection"></param>///<param name="location"></param>publicJavascriptInjectionFilter(string injection, Locations location = Locations.head)
    {
        this.injection = "<script>" + injection + "</script>";
        switch (location)
        {
            case Locations.head:
                this.location = "<head>";
                break;

            case Locations.body:
                this.location = "<body>";
                break;

            default:
                this.location = "<head>";
                break;
        }
    }

    ///<summary>/// Disposal///</summary>publicvoidDispose()
    {
        //
    }

    ///<summary>/// Filter Processing...  handles the injection///</summary>///<param name="dataIn"></param>///<param name="dataInRead"></param>///<param name="dataOut"></param>///<param name="dataOutWritten"></param>///<returns></returns>public FilterStatus Filter(Stream dataIn, outlong dataInRead, Stream dataOut, outlong dataOutWritten)
    {
        dataInRead = dataIn == null ? 0 : dataIn.Length;
        dataOutWritten = 0;

        if (overflow.Count > 0)
        {
            var buffersize = Math.Min(overflow.Count, (int)dataOut.Length);
            dataOut.Write(overflow.ToArray(), 0, buffersize);
            dataOutWritten += buffersize;

            if (buffersize < overflow.Count)
            {
                overflow.RemoveRange(0, buffersize - 1);
            }
            else
            {
                overflow.Clear();
            }
        }


        for (var i = 0; i < dataInRead; ++i)
        {
            var readbyte = (byte)dataIn.ReadByte();
            var readchar = Convert.ToChar(readbyte);
            var buffersize = dataOut.Length - dataOutWritten;

            if (buffersize > 0)
            {
                dataOut.WriteByte(readbyte);
                dataOutWritten++;
            }
            else
            {
                overflow.Add(readbyte);
            }

            if (char.ToLower(readchar) == location[offset])
            {
                offset++;
                if (offset >= location.Length)
                {
                    offset = 0;
                    buffersize = Math.Min(injection.Length, dataOut.Length - dataOutWritten);

                    if (buffersize > 0)
                    {
                        var data = Encoding.UTF8.GetBytes(injection);
                        dataOut.Write(data, 0, (int)buffersize);
                        dataOutWritten += buffersize;
                    }

                    if (buffersize < injection.Length)
                    {
                        var remaining = injection.Substring((int)buffersize, (int)(injection.Length - buffersize));
                        overflow.AddRange(Encoding.UTF8.GetBytes(remaining));
                    }

                }
            }
            else
            {
                offset = 0;
            }

        }

        if (overflow.Count > 0 || offset > 0)
        {
            return FilterStatus.NeedMoreData;
        }

        return FilterStatus.Done;
    }

    ///<summary>/// Initialization///</summary>///<returns></returns>publicboolInitFilter()
    {
        returntrue;
    }

}

Thanks to amaitland for pointing me in the right direction, and for the sample program that the vast majority of the above code was based on. End result:

<html><head></head><body><script>window.InjectedObject = {}</script><script>
    isObjectPresent = typeofInjectedObject == "object";
  </script><p>isObjectPresent?</p><divid="result"></div><script>document.getElementById("result").innerHTML = isObjectPresent;
  </script></body></html>

Which meets my needs of pre-processing the document with some text at the top of the header ensuring no timing issues where existing code might be run before the injected code.

edit couple small fixes. added control logic to only insert when a mainframe is loaded.

Solution 2:

Well your answer is correct that you should override the implementation of GetResourceResponseFilter but in case you didn't implement the interface in a correct way you will end up with browser not rendering content, you can instead inherit the DefaultRequestHandler and override the GetResourceResponseFilter() and provide the custom filter as mentioned in the accepted answer, this will be easier in case you need only to ovveride this specific functionality :

publicclassCustomRequestHandler : DefaultRequestHandler
{
    string script = "alert('hello');";

    publicoverride IResponseFilter GetResourceResponseFilter(CefSharp.IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
    {
        if (frame.IsMain && request.ResourceType == ResourceType.MainFrame)
        {
            returnnew JavascriptInjectionFilter(script);
        }
        returnnull;
    }
}

Then assign it to the chromium browser:

CustomRequestHandlercustomRequestHandler=newCustomRequestHandler();
chromeBrowser.RequestHandler = customRequestHandler ;

Post a Comment for "Cefsharp Inject Javascript Prior To Any Document Load/processing"