Skip to content

Disallow non-element params to service getters#16328

Merged
dreamofabear merged 10 commits intoampproject:masterfrom
dreamofabear:pwa-services
Jun 29, 2018
Merged

Disallow non-element params to service getters#16328
dreamofabear merged 10 commits intoampproject:masterfrom
dreamofabear:pwa-services

Conversation

@dreamofabear
Copy link
Copy Markdown

Partial for #16322. Goal is to prevent bugs like #16043 in the future.

  • Fix a few instances of window.document being passed to service getters.
  • Change all service getter methods to accept !Element instead of !Node to prevent future bugs.
  • Create getServiceForDocDeprecated(nodeOrDoc, id) to keep a few remaining usages (startup services) for follow-up fix.

/to @jridgewell @danielrozenberg /cc @jpettitt @aghassemi

Copy link
Copy Markdown
Contributor

@jridgewell jridgewell left a comment

Choose a reason for hiding this comment

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

Why can't we just have it accept a Document?

src/service.js Outdated
// If a node is passed, try to resolve via this node.
const win = toWin(/** @type {!Document} */ (
nodeOrDoc.ownerDocument || nodeOrDoc).defaultView);
elementOrAmpDoc.ownerDocument || elementOrAmpDoc).defaultView);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This change is incorrect. Element does not have a defaultView.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Oh man, nice catch. Thanks.

if (elementOrAmpDoc.nodeType) {
const win = toWin(/** @type {!Document} */ (
nodeOrDoc.ownerDocument || nodeOrDoc).defaultView);
elementOrAmpDoc.ownerDocument || elementOrAmpDoc).defaultView);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ditto.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done.

*/
parseUrl_(url) {
return Services.urlForDoc(this.rootNode_).parse(url);
return Services.urlForDoc(this.ampdoc).parse(url);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't think this change is correct. rootNode is in the document scope, while ampdoc is the root scope.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I considered that, but I don't think local scope is important for URL parsing. Line 168 already grabs the URL service from this.ampdoc.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

For FIEs, it's critical. FIE have a <base> element that changes where their relative URLs resolve from.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

TIL, good call. I think I was too aggressive here -- reverted APIs for FIE-scope services.

@dreamofabear
Copy link
Copy Markdown
Author

Why can't we just have it accept a Document?

It would only work for single docs since shadow AMPs don't have a Document, and I want to prevent misuse. Part of the problem is Document vs. AmpDoc conflation e.g. fooForDoc is really misleading.

@dreamofabear
Copy link
Copy Markdown
Author

/cc @dvoytenko FYI

/**
* `nodeOrDoc` must be passed for correct behavior in shadow AMP (PWA) case.
* @param {!Window} win
* @param {!Node|!../../../src/service/ampdoc-impl.AmpDoc} nodeOrDoc
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

!../../../src/service/ampdoc-impl.AmpDoc makes me 😢

*/
parseUrl_(url) {
return Services.urlForDoc(this.rootNode_).parse(url);
return Services.urlForDoc(this.ampdoc).parse(url);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

For FIEs, it's critical. FIE have a <base> element that changes where their relative URLs resolve from.

@dreamofabear
Copy link
Copy Markdown
Author

@jridgewell Friendly ping.

src/service.js Outdated
* Unlike most service getters, passing `Node` is necessary for some FIE-scope
* services since sometimes we only have the FIE Document for context.
*
* @param {!Node|!./service/ampdoc-impl.AmpDoc} nodeOrAmpDoc
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could we change this to !Element|!ShadowRoot|!AmpDoc? That we we fix the core bug here (passing in a Document) but still allow ShadowRoots?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The problem isn't shadow roots, it's FIE.

In PWA context, callers typically can pass in the AmpDoc or elements in the shadow DOM. But in FIE, sometimes we only have access to the iframe's contentWindow. This is because of how FIE services are set up:

function adoptStandardServicesForEmbed(childWin) {
// The order of service adoptations is important.
// TODO(dvoytenko): Refactor service registration if this set becomes
// to pass the "embeddable" flag if this set becomes too unwieldy.
adoptServiceForEmbed(childWin, 'url');
adoptServiceForEmbed(childWin, 'action');
adoptServiceForEmbed(childWin, 'standard-actions');
adoptServiceForEmbed(childWin, 'navigation');
}

Maybe we can refactor this but it'll be a large change. Another idea is to have privileged and non-privileged getters, one that takes !Node and another that takes !Element.

* Unlike most service getters, passing `Node` is necessary for some FIE-scope
* services since sometimes we only have the FIE Document for context.
*
* @param {!Node|!./service/ampdoc-impl.AmpDoc} nodeOrDoc
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could we change this to !Element|!ShadowRoot|!AmpDoc? That we we fix the core bug here (passing in a Document) but still allow ShadowRoots?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants