Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add will-redirect #13866

Merged
merged 8 commits into from Sep 15, 2018
Merged

feat: add will-redirect #13866

merged 8 commits into from Sep 15, 2018

Conversation

MarshallOfSound
Copy link
Member

@MarshallOfSound MarshallOfSound commented Jul 30, 2018

Example usage:

mainWindow.webContents.on('will-redirect', (e, url) => {
  if (!testIsValidUrl(url))
    e.preventDefault()
})

TODO:

  • Tests

Notes: added a will-redirect event on webContents to capture, handle and prevent redirects during navigations

@MarshallOfSound MarshallOfSound requested review from a team and felixrieseberg July 30, 2018 04:39
@MarshallOfSound MarshallOfSound requested a review from a team July 30, 2018 04:39
@MarshallOfSound MarshallOfSound changed the title feat: add will-redirect [wip] feat: add will-redirect Jul 30, 2018
@MarshallOfSound MarshallOfSound changed the title [wip] feat: add will-redirect feat: add will-redirect Jul 30, 2018
@MarshallOfSound
Copy link
Member Author

Please do not merge until after the meeting on Monday 30th

@felixrieseberg
Copy link
Member

Well that was easy - I had no idea Chrome already has an event, but of course it does. 👏 for sprinting into action, this seems like a very clean solution.

@ckerr ckerr added the semver/minor backwards-compatible functionality label Jul 30, 2018
if (EmitNavigationEvent("will-redirect", navigation_handle)) {
scoped_refptr<base::SingleThreadTaskRunner> task_runner(
base::ThreadTaskRunnerHandle::Get());
task_runner->PostTask(FROM_HERE, base::BindOnce(&OnStopSoon, this));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the asynchronous nature of this leave a window of opportunity for the redirect to start happening? It'd be awesome if there was a way to guarantee that not a single byte of network traffic leaves to the domain of the redirect's target.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be awesome if there was a way to guarantee that not a single byte of network traffic leaves to the domain of the redirect's target.

Its possible by registering navigation throttlers https://cs.chromium.org/chromium/src/content/public/browser/navigation_throttle.h

@MarshallOfSound
Copy link
Member Author

@nornagon @deepak1556 I re-implemented this event and the prevention logic using NavigationThrottle. Should be no chance for race conditions now 👍

Copy link
Member

@deepak1556 deepak1556 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, with some minor changes. Thanks!

AtomBrowserClient::CreateThrottlesForNavigation(
content::NavigationHandle* handle) {
std::vector<std::unique_ptr<content::NavigationThrottle>> throttles;
throttles.push_back(base::WrapUnique(new AtomNavigationThrottle(handle)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer std::make_unique

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call me crazy, but std::make_unique didn't compile ❓ and the equivalent CreateThrottlesForNavigation inside chromium uses the base helper 🤔 I can look into changing it tomorrow if it's a big thing

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call me crazy, but std::make_unique didn't compile

Hmm it should work.

and the equivalent CreateThrottlesForNavigation inside chromium uses the base helper

yeah in this case its fine using either, but prefer make_unique for creation of unique_ptr, More context from chromium style guide https://www.chromium.org/developers/coding-style/cpp-dos-and-donts#TOC-Prefer-std::make_unique-to-base::WrapUnique

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would still like to see this resolved

auto* handle = navigation_handle();
auto* contents = handle->GetWebContents();
if (!contents)
return PROCEED;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we let the navigation proceed if there are no web contents ? This case should definitely not happen, but in the rarest chance it occurs we should terminate the navigation otherwise potential for use-after-free bugs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this is more like a NOREACHED() but I thought I'd handle it for safety. Current behavior where we have no throttles would be for the navigation to proceed so I'd like to maintain that behavior. Might be worth adding a DCHECK or something there so that it would cause failures in debug mode though?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current behavior where we have no throttles would be for the navigation to proceed so I'd like to maintain that behavior

👍

auto api_contents =
atom::api::WebContents::CreateFrom(v8::Isolate::GetCurrent(), contents);
if (api_contents.IsEmpty())
return PROCEED;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Navigation should be terminated for the same reason mentioned above.


#include "content/public/browser/navigation_throttle.h"

class URLPattern;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Unused declaration.


AtomNavigationThrottle::ThrottleCheckResult WillRedirectRequest() override;

const char* GetNameForLogging() { return "AtomNavigationThrottle"; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const char* GetNameForLogging() override { }

@@ -27,6 +27,7 @@
#include "atom/browser/child_web_contents_tracker.h"
#include "atom/browser/lib/bluetooth_chooser.h"
#include "atom/browser/native_window.h"
#include "atom/browser/net/atom_navigation_throttle.h"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you move the atom_navigation_throttle under atom/browser, the throttler is entirely used on the UI thread and it doesn't directly handle any component from //net of chromium.

Copy link
Member

@nornagon nornagon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the DCHECKs should be CHECKs. It's scary to me that those supposedly-never-reached conditions result in allowing the navigation to occur. Safer to CHECK, if they're truly never reached.

AtomBrowserClient::CreateThrottlesForNavigation(
content::NavigationHandle* handle) {
std::vector<std::unique_ptr<content::NavigationThrottle>> throttles;
throttles.push_back(base::WrapUnique(new AtomNavigationThrottle(handle)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would still like to see this resolved

auto* handle = navigation_handle();
auto* contents = handle->GetWebContents();
if (!contents) {
DCHECK(false); // This should be unreachable
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CHECK(false) then?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason they are DCHECK is to maintain existing behavior in release builds (see the comment chain above). Although this should be unreachable, in it's current state Electron would PROCEED with the navigation.

Copy link
Member

@nornagon nornagon Aug 10, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok. BTW NOTREACHED() exists and should be used here (it just DCHECK(false)es, but it documents itself and is greppable)

auto api_contents =
atom::api::WebContents::CreateFrom(v8::Isolate::GetCurrent(), contents);
if (api_contents.IsEmpty()) {
DCHECK(false); // This should be unreachable
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here too

@MarshallOfSound
Copy link
Member Author

@nornagon This has been updated and I even made std::make_unique work, idk why it wasn't before but it does now 😆

Assuming CI is green I'm gonna merge this in 👍

@MarshallOfSound MarshallOfSound merged commit 7065093 into master Sep 15, 2018
@release-clerk
Copy link

release-clerk bot commented Sep 15, 2018

Release Notes Persisted

added a will-redirect event on webContents to capture, handle and prevent redirects during navigations

@MarshallOfSound MarshallOfSound deleted the feat/will-redirect branch September 15, 2018 15:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
semver/minor backwards-compatible functionality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants