Help needed to extend CefRequestHandler

2,181 views
Skip to first unread message

Ram

unread,
Dec 25, 2012, 2:29:18 AM12/25/12
to cef...@googlegroups.com
Hi,
 I am working on a application which requires handling files securely. Its an offline app. So the app will ship the assets in an encrypted format. So i would like to intercept the incoming request for the certain parts of the app and decode them and send it to CEF. After digging through the code i found CefRequestHandler got a method OnBeforeResourceLoad , i believe i can  use this for my custom request handler. I wanted to make sure this is the right way Or if there is any other better way.

Anybody got an idea how to implement this.?

Cheers
Ramesh


Ram

unread,
Dec 25, 2012, 2:57:41 AM12/25/12
to cef...@googlegroups.com
Or is it the other handler CefResourceHandler?

Dmitry Azaraev

unread,
Dec 25, 2012, 4:29:04 AM12/25/12
to cef...@googlegroups.com
Hi.
You can implement own scheme with CefResourceHandler.
Register scheme handler with CefRuntime.RegisterSchemeHandlerFactory .
If you need handle POST's request bodies - better register scheme handler on http scheme + domain.
I.e. RegisterSchemeHandlerFactory("http", "app.mydomain.com", new MySchemeHandler()); In this case all requests to http://app.mydomain.com will be handled by this scheme handler.
--
Best regards,
   Dmitry

Ram

unread,
Dec 25, 2012, 7:53:32 AM12/25/12
to cef...@googlegroups.com, dmitry....@gmail.com
Thanks Dimitry, Thats exactly what i want. I have implemented my own resourcehandler and registered with the RegisterSchemeHandlerFactory. Below the code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;  
using Xilium.CefGlue;
using System.Windows.Forms;
using System.IO; 

namespace Reader
{
    class ReaderResourceHandler : CefResourceHandler
    {
        
        private bool _completed;
        private string _url;
        private string _resourceFolder = "res";
        private Utils _objUtils  = new Utils();
        private long _pos,_resLength;
        private byte[] _content; 

        protected override bool ProcessRequest(CefRequest request, CefCallback callback)
        {
            _url = request.Url;
            callback.Continue();
            return true;

        }

        protected override void GetResponseHeaders(CefResponse response, out long responseLength, out string redirectUrl)
        {
            //response.SetHeaderMap();
            response.Status = 200;
            response.MimeType = getMimeType();
            response.StatusText = "OK";
            responseLength = -1; // unknown content-length
            redirectUrl = null;  // no-redirect
        }

        protected override bool ReadResponse(System.IO.Stream response, int bytesToRead, out int bytesRead, CefCallback callback)
        {
            if (_completed)
            {
                bytesRead = 0;
                return false;
            }
            else
            {
                var content = ReadFromFile();            
                response.Write(content, 0, content.Length);
                bytesRead = content.Length;
                _completed = true;
                return true;
            }

        }

        protected override bool CanGetCookie(CefCookie cookie)
        {
            return true;
        }

        protected override bool CanSetCookie(CefCookie cookie)
        {
            return true;
        }

        protected override void Cancel()
        {

        }

        private Byte[] ReadFromFile()
        {
            var _fileName = getFileName();
            if (!String.IsNullOrEmpty(_fileName))
            {
                var _filePath = Application.StartupPath + "\\" + _resourceFolder + "\\" + getFileName();
                return File.ReadAllBytes(_filePath);
             
            }
            else
            {
                return null;
            }
            
        }

        private string getFileName()
        {
            var _url_splitted = _url.Split(new String[] { "http://test-local.com/" }, StringSplitOptions.None);
            return (_url_splitted.Length > 0) ? _url_splitted[1] : null;
           

        }

        private string getMimeType()
        {
            var _url_splitted = _url.Split('.');
            return _objUtils.GetMimeType(_url_splitted[_url_splitted.Length-1]);
        }
    }
}

All assets are started serving fine. Except one big js file. I got the exception NotSupportedException{"Unable to expand length of this stream beyond its capacity."} at

    response.Write(content, 0, content.Length);

Any idea how to fix this?

Cheers
Ramesh

Dmitry Azaraev

unread,
Dec 25, 2012, 8:07:31 AM12/25/12
to cef...@googlegroups.com
Read comments for method

        protected override bool ReadResponse(System.IO.Stream response, int bytesToRead, out int bytesRead, CefCallback callback)

CEF reads stream by small portions (about 4KB) - and indicate how much data  you must write into the stream in bytesToRead argument. In bytesRead you must place how much data you written. Yes, it can be simplified, but now it is just raw interface.


On Tue, Dec 25, 2012 at 2:53 PM, Ram <rame...@gmail.com> wrote:
        protected override bool ReadResponse(System.IO.Stream response, int bytesToRead, out int bytesRead, CefCallback callback)



--
Best regards,
   Dmitry

Ram

unread,
Dec 25, 2012, 8:23:39 AM12/25/12
to cef...@googlegroups.com, dmitry....@gmail.com
yippy, got it working.  posted the question before looking at the comment. Now just sending chunks instead the whole array. this is the modified code

        private bool _completed;
        private string _url;
        private string _resourceFolder = "res";
        private Utils _objUtils  = new Utils();        
        private byte[] _content;
        private int _bytesDone = 0;

        protected override bool ProcessRequest(CefRequest request, CefCallback callback)
        {
            _url = request.Url;
            callback.Continue();
            return true;

        }

        protected override void GetResponseHeaders(CefResponse response, out long responseLength, out string redirectUrl)
        {
            //response.SetHeaderMap();
            response.Status = 200;
            response.MimeType = getMimeType();
            response.StatusText = "OK";
            _content = ReadFromFile();
            responseLength = _content.Length; // unknown content-length
            redirectUrl = null;  // no-redirect
        }

        protected override bool ReadResponse(System.IO.Stream response, int bytesToRead, out int bytesRead, CefCallback callback)
        {
            if (_completed)
            {
                bytesRead = 0;
                _bytesDone = 0;
                _content=null;
                return false;
            }
            else
            {

                if (_content != null)
                {
                    if (_bytesDone == 0)
                    {
                        response.Write(_content.Skip(0).Take(bytesToRead).ToArray(), 0, bytesToRead);
                        bytesRead = bytesToRead;
                        _bytesDone = bytesToRead;
                        if (_content.Length < bytesToRead)
                            _completed = true;
                    }
                    else
                    {
                        response.Write(_content.Skip(_bytesDone).Take(bytesToRead).ToArray(), 0, bytesToRead);
                        bytesRead = bytesToRead;
                        _bytesDone += bytesToRead;
                        if (_bytesDone >= _content.Length)
                        {
                            _completed = true;
                        }
                    }

                   
                   
                }
                else
                {
                    bytesRead = 0;
                }
               

                return true;

Dmitry Azaraev

unread,
Dec 25, 2012, 9:16:03 AM12/25/12
to cef...@googlegroups.com
                        response.Write(_content.Skip(0).Take(bytesToRead).ToArray(), 0, bytesToRead);
It is recreating array everytime. Istead of this you can use something similar to:
                        response.Write(_content, _bytesDone, bytesToRead);
And it have sense make some guards around incorrect values.


On Tue, Dec 25, 2012 at 3:23 PM, Ram <rame...@gmail.com> wrote:
                        response.Write(_content.Skip(0).Take(bytesToRead).ToArray(), 0, bytesToRead);



--
Best regards,
   Dmitry

Dmitry Azaraev

unread,
Dec 25, 2012, 9:18:24 AM12/25/12
to cef...@googlegroups.com
Also check yourself that you doesn't miss last file's chunk. May be i'm something forget, but 'last' completed call doesn't actually returns data to cef, or may be it was be before. Not sure just now.
--
Best regards,
   Dmitry

Ram

unread,
Dec 25, 2012, 9:54:22 AM12/25/12
to cef...@googlegroups.com, dmitry....@gmail.com
Yeah, that looks great. Thanks
Reply all
Reply to author
Forward
0 new messages