Intercepting link clicks

61 views
Skip to first unread message

Ewen Cheslack-Postava

unread,
Jun 29, 2011, 2:16:19 AM6/29/11
to berk...@googlegroups.com
So I'm trying to address a problem where we want to intercept
navigation requests so that we can do something different with them
(e.g. preserve UI and open in a new window instead). At first I
thought the WindowDelegate::onNavigationRequested() method would be
invoked for these (which also allows cancelling them), but it turns
out it isn't. I'm still not clear *when* that's invoked (it's also
triggered by a call to RenderViewHostDelegate, but I haven't figured
out when/why it is invoked).

Then, I tracked down the place that Berkelium finds out about
navigation due to clicking links to WindowImpl::DidNavigate. However,
it looks like this is purely for notification so that history can be
maintained. I can't see any way to provide feedback that it should be
cancelled (and obviously its important that it be cancelled *before*
it starts).

Does anyone know if cancelling this navigation is possible? Perhaps it
just isn't functionality Chromium needed?

-Ewen

Patrick Horn

unread,
Jun 30, 2011, 3:01:01 AM6/30/11
to berk...@googlegroups.com
Hi Ewen,

Unfortunately onNavigationRequested is broken, and does not work in some versions. There are some fundamental problems with onNavigationRequested, even if implemented correctly--this is why I haven't spent the time to fix it. The purpose of this function in Chromium is to transfer control to a new renderer process when opening a new tab. Navigations that do not result in a new tab are often done directly in WebKit, and only reported back to the browser process after the fact--so without adding a new callback, there's no clean way to prevent the next page from loading (I think this changed recently because Chrome supports blacklisting URLs from extensions).

This function is only called for top-level frames, and not for iframes or subresources (images, scripts), which is what you want. However, it only applies to links loaded from the parent page, not all types of javascript redirects. In other words, you can't rely on untrusted source pages to do the right type of navigation (or trusted pages containing untrusted iframes which can "break out of a frame"). Now--there probably is a way to block navigations by hooking into resource loads, as in the future extension api from crbug.com/60101 -- so this method might be useful.

In your case, this might be good enough, since you know you are only going to navigate using links. Unfortunately, it was not implemented correctly in Berkelium and wasn't called for most types of links. I decided to try changing it to be called onStartLoading if you still have a chance to cancel, but unfortunately that doesn't give you the URL.

You can make more reliable solutions by modifying the HTML itself. The standard practice for this is to add a target="_blank" attribute to your links. If that's not good enough, you can add an onclick for all elements that looks at e.target.href and cancels the event.

Finally, if you do want to support any type of navigation (even untrusted pages), the best way to do this is addEventListener("beforeunload", func); Then, have func open a new window (window.open or whatever) and return false. The big problem here is this callback doesn't offer a way to get the destination URL. I suggest having links set this into a variable, which is then used by this function (or ignored if the variable is unset, preventing an accidental window close)

-Patrick
Reply all
Reply to author
Forward
0 new messages