Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using CefSharp to capture Resource Response Data (body)

Tags:

cefsharp

I am trying to use CefSharp to visit a URL and capture specific resources retrieved during the loading of a given page. Presumably as a Stream or byte array per resource.

CefSharp provides the interface IRequestHandler. You can create a class which implements this interface to respond to Request/Response events, but it does not contain the response body in any way.

like image 764
Frits Donkerbroek Avatar asked Jan 30 '23 18:01

Frits Donkerbroek


1 Answers

Take a look at GetResourceResponseFilter in your implementation of IRequestHandler. GetResourceResponseFilter returns an IResponseFilter, which provides you with an opportunity to capture all responses. You'll need to implement your own IResponseFilter, thankfully there are ample examples.

Example IResponseFilter implementation taken from the CefSharp GitHub project.

public class MemoryStreamResponseFilter : IResponseFilter
{
        private MemoryStream memoryStream;

        bool IResponseFilter.InitFilter()
        {
            //NOTE: We could initialize this earlier, just one possible use of InitFilter
            memoryStream = new MemoryStream();
             
            return true;
        }

        FilterStatus IResponseFilter.Filter(Stream dataIn, out long dataInRead, Stream dataOut, out long dataOutWritten)
        {
            if (dataIn == null)
            {
                dataInRead = 0;
                dataOutWritten = 0;

                return FilterStatus.Done;
            }

            dataInRead = dataIn.Length;
            dataOutWritten = Math.Min(dataInRead, dataOut.Length);

            //Important we copy dataIn to dataOut
            dataIn.CopyTo(dataOut);

            //Copy data to stream
            dataIn.Position = 0;
            dataIn.CopyTo(memoryStream);

            return FilterStatus.Done;
        }

        void IDisposable.Dispose()
        {
            memoryStream.Dispose();
            memoryStream = null;
        }

        public byte[] Data
        {
            get { return memoryStream.ToArray(); }
        }
    }

Now in your GetResourceResponseFilter method:

 private Dictionary<ulong, MemoryStreamResponseFilter> responseDictionary = new Dictionary<ulong, MemoryStreamResponseFilter>();
 public IResponseFilter GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
 {
       var dataFilter = new MemoryStreamResponseFilter();
       responseDictionary.Add(request.Identifier, dataFilter);
       return dataFilter;
 }

Then in OnResourceLoadComplete:

public void OnResourceLoadComplete(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response, UrlRequestStatus status, long receivedContentLength)
{      
    MemoryStreamResponseFilter filter;
    if (responseDictionary.TryGetValue(request.Identifier, out filter))
    {
        var data = filter.Data; //This returns a byte[]
        //File.WriteAllBytes("c:/save/path", data);
    }
}

You can use the properties within the IRequest and IResponse parameters to decide what you want to filter.

like image 64
TEK Avatar answered Feb 14 '23 13:02

TEK