Intercepting redirects and canceling navigation

3,878 views
Skip to first unread message

Munjal Doshi

unread,
Jul 25, 2012, 7:35:21 PM7/25/12
to Chromium-dev, Mihai Parparita
TL;DR - what is the best way to listen to navigation in a browser popup and cancel navigation *before* they happen (if some condition is met) and close the popup?

Long version:

I have spent a fair amount of time trying out various options to do the following:

- Given a URL, load the URL using web contents
- If the URL redirects to a specific URL, I am done; I don't need to create any popups / windows.
- If the URL returns content (200), then create a browser popup and load the WebContents.
- Observe the navigation happening in the popup web contents and *before* navigation happens to a specific URL, cancel the navigation and close the popup.

I am able to do everything except the last step.

For the last step I tried numerous things:
1. WebContentsObserver: tried listening to events like DidStartProvisionalLoadForFrame and ProvisionalChangeToMainFrameUrl. There are two problems with this approach:
    - I am not getting a callback for some redirects
    - I am not sure if "Obserers" are designed to be able to stop navigation in such callbacks
2. Listening to content::NOTIFICATION_LOAD_START. Again, the same two problems as above - did not get notification for some redirects and not sure if this is designed to cancel navigation.
3. Looked at what extension WebRequest API does: this seems to be hooking up at a very low level than what I need.
4. Looked at this patch for Clank (thanks to creis@ for the pointer). But again this is hooking up at a very low level, and probably also does things in the renderer while I need to do this in the browser.
5. Tried being a WebContentsDelegate, but cannot be a delegate once I tell the browser to navigate to open existing web contents (since Browser will be the delegate after that point).

Note that I have a working implementation of this already, but the current implementation uses platform specific window implementations. It works but the problem is that I need to show the URL bar and SSL certificate UI in the window. So I was hoping to use Browser::Navigate method to just open a browser popup. And that is when I ran into the above issues.

Any help or pointers will be greatly appreciated.

-Munjal

Darin Fisher

unread,
Jul 26, 2012, 3:38:33 AM7/26/12
to mun...@chromium.org, Chromium-dev, Mihai Parparita
You just want to make navigation in a popup window impossible?  Presumably you want to allow the initial navigation, or do you want to prohibit even that?

Since this feels like a static setting, you could just make it a setting for the RenderView.  RenderViewImpl could easily block navigations in decidePolicyForNavigation.  If you want to allow the first navigation, but block all subsequent navigations, then there could be some trickiness with setting the flag at the right time to prevent race conditions.

-Darin




-Munjal

--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev

Munjal Doshi

unread,
Jul 26, 2012, 12:51:15 PM7/26/12
to Darin Fisher, Chromium-dev, Mihai Parparita
On Thu, Jul 26, 2012 at 12:38 AM, Darin Fisher <da...@chromium.org> wrote:
You just want to make navigation in a popup window impossible?  Presumably you want to allow the initial navigation, or do you want to prohibit even that?

I want to allow navigation until navigation happens to a specific URL, mostly via a redirect but I don't care.

For example, load www.facebook.com/dialog/oauth/... and let all navigation happen normally until navigation happens to a URL of the format myapp.com/facebook_reply/...

*Before* navigation happens to myapp.com/facebook_reply/... I want to stop it, and close the popup.


 
Since this feels like a static setting, you could just make it a setting for the RenderView.  RenderViewImpl could easily block navigations in decidePolicyForNavigation.  If you want to allow the first navigation, but block all subsequent navigations, then there could be some trickiness with setting the flag at the right time to prevent race conditions.


Does that work from the browser? I need to do this from the browser. Is there a counterpart in RenderViewHost I can use?

Joshua Woodward

unread,
Jul 26, 2012, 1:04:41 PM7/26/12
to mun...@chromium.org, Darin Fisher, Chromium-dev, Mihai Parparita
On Thu, Jul 26, 2012 at 9:51 AM, Munjal Doshi <mun...@chromium.org> wrote:
I want to allow navigation until navigation happens to a specific URL, mostly via a redirect but I don't care.

For example, load www.facebook.com/dialog/oauth/... and let all navigation happen normally until navigation happens to a URL of the format myapp.com/facebook_reply/...

*Before* navigation happens to myapp.com/facebook_reply/... I want to stop it, and close the popup.


Can you explain a little why you want to do this?
Are you trying to prevent something (event) from happening, or want something else to happen?

What is your end goal? There might be another way to accomplish that.

--



Twitter - @howtohtml5

Munjal Doshi

unread,
Jul 26, 2012, 1:07:51 PM7/26/12
to Joshua Woodward, Darin Fisher, Chromium-dev, Mihai Parparita
Basically this is for an extension API that can start auth flows to providers like Facebook, Twitter, Google, etc. But at the end of the auth flow, we need to route back the response from the provider to the application / extension that called the API to start the flow. The way the providers respond back is via a redirect back to a known app URL.

That is why I need to monitor navigations happening in the popup that I create in response to the app calling the API. And *before* navigation happens to a specific known URL, I respond back to the app instead of loading that URL.

Charlie Reis

unread,
Jul 26, 2012, 1:25:24 PM7/26/12
to mun...@chromium.org, Joshua Woodward, Darin Fisher, Chromium-dev, Mihai Parparita
I'm not aware of any way to block a navigation in the browser process, unless you use something like a ResourceThrottle (or look at how the WebRequest extension API is implemented).

In general, the renderer process is free to start and even complete a navigation at any time, without involving the browser process (e.g., data URLs).  That's why Darin suggested RenderViewImpl::decidePolicyForNavigation, which has a chance to intercept all navigations in the renderer process.

It's worth noting that decidePolicyForNavigation already has some extension-specific checks, by calling out to the ChromeContentRendererClient.  The renderer process does know which extensions are installed.  Are you sure the check can't be done there?

If that won't work, I'd still recommend ResourceThrottles or figuring out the WebRequest API's approach.

Charlie


Darin Fisher

unread,
Jul 27, 2012, 2:37:33 AM7/27/12
to Munjal Doshi, Joshua Woodward, Chromium-dev, Mihai Parparita
That sounds a little too specific for an extension API.  Why do we want to bake knowledge of such auth flows into Chrome?

Can't extensions just use the WebRequest API to implement this functionality?  Maybe the WebRequest API is missing a feature?

-Darin

Munjal Doshi

unread,
Jul 27, 2012, 1:32:10 PM7/27/12
to Darin Fisher, Joshua Woodward, Chromium-dev, Mihai Parparita
Update on this. I was able to make this work by listening to NOTIFICATION_RESOURCE_RECEIVED_REDIRECT and then calling WebContents::Close when I get that notification for the right URL from the right WebContents. (Thanks to mihaip@ for the pointer).

See inline too.

Thanks for all the replies.

-Munjal

Yeah, I thought about that at some point. Admittedly I didn't follow through with my thought enough to see if this would work well.

Darin Fisher

unread,
Jul 27, 2012, 1:36:24 PM7/27/12
to Munjal Doshi, Joshua Woodward, Chromium-dev, Mihai Parparita
Are you sure that does what you want?  The redirect may still be followed before you close the WebContents.  There is a race condition.  Do you care if the HTTP request for the redirected location is sent?

I still don't quite understand what you are proposing to add to Chrome that would require this functionality.  Can you describe that further or point me at some design doc?
 
-Darin

Munjal Doshi

unread,
Jul 27, 2012, 1:51:26 PM7/27/12
to Darin Fisher, Joshua Woodward, Chromium-dev, Mihai Parparita
On Fri, Jul 27, 2012 at 10:36 AM, Darin Fisher <da...@chromium.org> wrote:
Are you sure that does what you want?  The redirect may still be followed before you close the WebContents.  There is a race condition.  Do you care if the HTTP request for the redirected location is sent?


It seems to work. It is okay if the navigation to that redirect URL happens alghouth it will be nice to avoid that. The URL that we are intercepting is not reachable , so the navigation will fail. But even then it will be nice to not even do that navigation if possible.

I am not too familiar with all this code (as is very evident from the email), but would the navigation happen even after WebContents::Close is called? May be because it is on a separate thread?
 
I still don't quite understand what you are proposing to add to Chrome that would require this functionality.  Can you describe that further or point me at some design doc?
 

You mean the auth flow that I described earlier?

Darin Fisher

unread,
Jul 27, 2012, 1:52:21 PM7/27/12
to Munjal Doshi, Joshua Woodward, Chromium-dev, Mihai Parparita
On Fri, Jul 27, 2012 at 10:51 AM, Munjal Doshi <mun...@chromium.org> wrote:


On Fri, Jul 27, 2012 at 10:36 AM, Darin Fisher <da...@chromium.org> wrote:
Are you sure that does what you want?  The redirect may still be followed before you close the WebContents.  There is a race condition.  Do you care if the HTTP request for the redirected location is sent?


It seems to work. It is okay if the navigation to that redirect URL happens alghouth it will be nice to avoid that. The URL that we are intercepting is not reachable , so the navigation will fail. But even then it will be nice to not even do that navigation if possible.

I am not too familiar with all this code (as is very evident from the email), but would the navigation happen even after WebContents::Close is called? May be because it is on a separate thread?
 
I still don't quite understand what you are proposing to add to Chrome that would require this functionality.  Can you describe that further or point me at some design doc?
 

You mean the auth flow that I described earlier?

Yes.
-Darin

Darin Fisher

unread,
Jul 27, 2012, 1:52:40 PM7/27/12
to Munjal Doshi, Joshua Woodward, Chromium-dev, Mihai Parparita
On Fri, Jul 27, 2012 at 10:52 AM, Darin Fisher <da...@chromium.org> wrote:


On Fri, Jul 27, 2012 at 10:51 AM, Munjal Doshi <mun...@chromium.org> wrote:


On Fri, Jul 27, 2012 at 10:36 AM, Darin Fisher <da...@chromium.org> wrote:
Are you sure that does what you want?  The redirect may still be followed before you close the WebContents.  There is a race condition.  Do you care if the HTTP request for the redirected location is sent?


It seems to work. It is okay if the navigation to that redirect URL happens alghouth it will be nice to avoid that. The URL that we are intercepting is not reachable , so the navigation will fail. But even then it will be nice to not even do that navigation if possible.

I am not too familiar with all this code (as is very evident from the email), but would the navigation happen even after WebContents::Close is called? May be because it is on a separate thread?

Yes, it is on a separate thread.
-Darin

Tim Steele

unread,
Jul 27, 2012, 6:00:28 PM7/27/12
to da...@google.com, Munjal Doshi, Joshua Woodward, Chromium-dev, Mihai Parparita
We looked at a similar problem trying to get browser signin working, and e.g, redirect to the 'Configure Data Types' screen after logging in successfully.

Do you / the app developer control what the "dummy" URL is? Would it suffice to use a special scheme and wire up a DataSource to handle the request? Or is it a worry that some endpoints could try to validate the URL and break that approach...

I'm also not sure how or what the WebNavigation API is intended for, but WebNavigationTabObserver is wired up to receive things like DidStartProvisionalLoad, which happens pretty early on when a new URL is requested (IIRC it happens before client or server redirects from that URL can happen).

Mihai Parparita

unread,
Jul 29, 2012, 2:08:17 PM7/29/12
to Tim Steele, da...@google.com, Munjal Doshi, Joshua Woodward, Chromium-dev
On Fri, Jul 27, 2012 at 3:00 PM, Tim Steele <t...@chromium.org> wrote:
We looked at a similar problem trying to get browser signin working, and e.g, redirect to the 'Configure Data Types' screen after logging in successfully.

Do you / the app developer control what the "dummy" URL is? Would it suffice to use a special scheme and wire up a DataSource to handle the request? Or is it a worry that some endpoints could try to validate the URL and break that approach...

We started out with using a chrome-extension://<id> URL, but some OAuth implementations validate the URL and expect it to HTTP(S), so a special https://<id>.chromeapps.org scheme is also supported. Either way, the final URL (after the which the WebContents should be closed) is something that doesn't strictly need to be loaded, but there's no harm if it is (the pages have no content). If it's preferable, the Browser could be hidden immediately, but the WebContents not be closed until the page finishes loading.

Darin: This API is meant to be used in apps (to handle OAuth-like signing flows that benefit from having access to the regular profile cookies), so the WebNavigation API wouldn't be appropriate (it would expose too much detail to apps, when they shouldn't really be able to get at any state from the regular profile cookie jar, etc.).
 
I'm also not sure how or what the WebNavigation API is intended for, but WebNavigationTabObserver is wired up to receive things like DidStartProvisionalLoad, which happens pretty early on when a new URL is requested (IIRC it happens before client or server redirects from that URL can happen).

I'm not seeing WebNavigationTabObserver in the codebase. Did you mean WebContentsObserver? Munjal tried that and it didn't signal all requests.

Mihai 

Martin Kosiba

unread,
Jul 30, 2012, 6:38:05 AM7/30/12
to chromi...@chromium.org, Mihai Parparita
Sorry for the late reply but only just noticed that the InterceptNavigationResourceThrottle was mentioned here. As you've noted in point 4, it's a bit low-level, but I don't think there exists a higher-level alternative unless (as it's already been mentioned) you're OK with having a race condition.
The one thing I wanted to add to the discussion is that ResourceThrottles work browser-side, not renderer-side, so this might still be an option worth considering.

Cheers!
    Martin

Darin Fisher

unread,
Jul 30, 2012, 12:48:27 PM7/30/12
to Mihai Parparita, Tim Steele, Munjal Doshi, Joshua Woodward, Chromium-dev
Sorry, I should have posted a follow-up summary of the conversation Munjal and I had offline.  I understand the use case now, and I pointed him toward using a ResourceThrottle.

-Darin
Reply all
Reply to author
Forward
0 new messages