Prevent OnQueryCanceled on file download

Having problems with building or using CEF's C/C++ APIs? This forum is here to help. Please do not post bug reports or feature requests here.

Prevent OnQueryCanceled on file download

Postby MartinM » Thu Aug 20, 2015 2:51 am

Hi,

for my app I implemented CefMessageRouterBrowserSide::Handler and the following functions for the render process.
  • OnContextCreated
  • OnContextReleased
  • OnProcessMessageReceived
The handler is used to inform my app, when the browser window has been maximized or restored. Therefore I'm using a persistent handler:
Code: Select all
// Create and send a new query.
if (window.cefQuery) {
  requestId = window.cefQuery({
    request: 'maximizedListener',
    persistent: true,
    onSuccess: function (response) {
      var value = true;
      if (response === 'maximized') {
        value = true;
      } else {
        value = false;
      }
      $scope.$apply(function () {
        $scope.maximized = value;
      });
    },
    onFailure: function () {
      $scope.$apply(function () {
        requestId = null;
      });
    }
  });
}

It is used to either show a maximize button or a restore button (like the typical Windows controls in the upper right corner of a window).

It works quite well, until I start a file download. For example a pdf download: <a href="pdf/file.pdf">file download</a>. In OnBeforeDownload I open a file save dialog via callback->Continue.

After that, I'm returning to my app, but the query in my MaximizeHandler has been canceled and the callback is now invalid. :( Does someone have a clue, how to reinstantiate the query or to make it outlive the pdf download in the first place? Because the JavaScript context is not really released here ...

This calling order might be helpful:
  • OnBeforeBrowse
  • --> OnQueryCanceled
  • OnBeforeResourceLoad
  • GetResourceHandler
  • OnBeforeDownload

This is the code for my handler.
Code: Select all
const char kMaximizedListener[] = "maximizedListener";

// Handle messages in the browser process.
class MaximizeHandler : public CefMessageRouterBrowserSide::Handler {
public:
  MaximizeHandler() : callback_(NULL) {}

  CefRefPtr<Callback> GetCallback() {
    return callback_;
  }

  virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
    CefRefPtr<CefFrame> frame,
    int64 query_id,
    const CefString& request,
    bool persistent,
    CefRefPtr<Callback> callback) OVERRIDE{

    const std::string& message_name = request;
    if (message_name.compare(kMaximizedListener) == 0) {
      callback_ = callback;
      return true;
    }

    return false;
  }

  virtual void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
    CefRefPtr<CefFrame> frame,
    int64 query_id) OVERRIDE{
    callback_ = NULL;
  }

private:
  CefRefPtr<Callback> callback_;
};


P.S. I have an idea for a workaround. It is to start the download inside of a hidden iframe. Is this really necessary?
MartinM
Techie
 
Posts: 25
Joined: Wed Nov 07, 2012 5:21 am

Re: Prevent OnQueryCanceled on file download

Postby amaitland » Thu Aug 20, 2015 3:26 am

Would be helpful if you could include, version, operating system, x86/x64, basic background info.
Maintainer of the CefSharp project.
amaitland
Virtuoso
 
Posts: 1292
Joined: Wed Jan 14, 2015 2:35 am

Re: Prevent OnQueryCanceled on file download

Postby MartinM » Thu Aug 20, 2015 5:47 am

Sure.

Win 8.1, 32-Bit Build 2357.

Flags: --no-proxy-server --disable-d3d11
MartinM
Techie
 
Posts: 25
Joined: Wed Nov 07, 2012 5:21 am

Re: Prevent OnQueryCanceled on file download

Postby magreenblatt » Thu Aug 20, 2015 8:39 am

Probably the JavaScript is being executed again when the PDF file loads, and since you're not checking the |query_id| in MaximizeHandler it's removing the callback reference added the first time the JavaScript was executed.
magreenblatt
Site Admin
 
Posts: 12409
Joined: Fri May 29, 2009 6:57 pm

Re: Prevent OnQueryCanceled on file download

Postby MartinM » Thu Aug 20, 2015 9:17 am

Hi Marshall, sorry I don't understand what you mean.

The handler is persistent and actually fires multiple times. Actually everytime I'm maximizing (SIZE_MAXIMIZED) or restoring (SIZE_RESTORED) my window. In the OnQuery function I'm saving the callback object for later. Then I retrieve it in my Windows message loop via my custom GetCallback() member function. I don't need the query_id here I think.

The problem (I think) is that CEF thinks I'm browsing away to another page and calls OnQueryCanceled, when all I do is start a file download.
MartinM
Techie
 
Posts: 25
Joined: Wed Nov 07, 2012 5:21 am

Re: Prevent OnQueryCanceled on file download

Postby magreenblatt » Thu Aug 20, 2015 10:02 am

MartinM wrote:The problem (I think) is that CEF thinks I'm browsing away to another page and calls OnQueryCanceled, when all I do is start a file download.

You're probably correct because <a href="pdf/file.pdf"> will trigger OnBeforeBrowse. I'm not sure how to fix this in a generic way, but you could likely fix it in your application by not calling CefMessageRouterBrowserSide::OnBeforeBrowse if you know the file will be downloaded (by looking at the file extension, for example).
magreenblatt
Site Admin
 
Posts: 12409
Joined: Fri May 29, 2009 6:57 pm

Re: Prevent OnQueryCanceled on file download

Postby MartinM » Fri Aug 28, 2015 3:14 am

Thanks a lot!

This works:

Code: Select all
bool SimpleHandler::OnBeforeBrowse(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, bool is_redirect)
{
  CEF_REQUIRE_UI_THREAD();
  std::string url = request->GetURL();

  if (url.length() < 4 ||
    url.compare(url.length() - 4, 4, ".pdf") != 0) {
    message_router_->OnBeforeBrowse(browser, frame);
  }

  // Allow the navigation to proceed.
  return false;
}
MartinM
Techie
 
Posts: 25
Joined: Wed Nov 07, 2012 5:21 am


Return to Support Forum

Who is online

Users browsing this forum: No registered users and 56 guests