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

Need a way to specify base url of pure fragment urls #1781

Open
duanyao opened this issue Sep 14, 2016 · 18 comments
Open

Need a way to specify base url of pure fragment urls #1781

duanyao opened this issue Sep 14, 2016 · 18 comments
Labels
needs tests Moving the issue forward requires someone to write tests

Comments

@duanyao
Copy link

duanyao commented Sep 14, 2016

Currently pure fragment urls ("#foo") are resolved in the same way as normal relative urls, i.e. against base url. However sometimes we want to resolve pure fragment urls against current document regardless of the base url. For example:

  • links (<a>) to a location inside document.
  • css clip-path referencing a svg clipPath inside the document.

Currently, if the base url is not identical to the document url, those pure fragment urls are broken.

Someone suggested changing links to absolute ones via JS to workaround this issue. However this doesn't work for css clip-path, because the absolute url is pointing to a html document, not a svg. Additionally, if the document url is a special one (e.g. about:blank), it is not even possible to figure out the absolute form of a pure fragment url.

The following test case demonstrates the "fragment in about:blank" problem:

<!DOCTYPE html>
<iframe style="width:400px; height:400px"></iframe>
<script>
var frame = document.querySelector('iframe');
if (frame.contentDocument.readyState == 'complete') {
  renderFrame();
} else frame.onload = renderFrame;

function renderFrame() {
  var content = '';
  for (var i = 0; i < 50; i++) {
    content += '<p id="' + i + '">' + i + '</p>';
  }
  content += '<p><a href="#25">go to the 25th</a></p>';
  // content += '<p><a href="' + document.baseURI + '#25">go to the 25th, absolute url</a></p>';
  frame.contentDocument.body.innerHTML = content;
}
console.log('load time:' + Date.now());
</script>

What should a browser do when the link "go to the 25th" is clicked? Chrome 53 creates a nested iframe, while Firefox 51 and Edge 13 scroll to the the 25th line. I think Chrome's behavior is "technically correct" but is not what we want, while Firefox and Edge are the opposite.

So I suggest reusing <base> tag to specify base url of pure fragment urls, E.g.:

<base fragment-resolution="self|base" href="...">

Value "self" and "base" of fragment-resolution means pure fragment urls are resolved against the document itself, and the base url, respectively.

@zcorpan
Copy link
Member

zcorpan commented Sep 14, 2016

I don't think we need to add something to base, it seems to me it should be possible to just fix this (i.e. specify the Firefox/Edge behavior).

For navigate I think the relevant step is

If this is not a reload-triggered navigation, resource is a request, resource's url equals browsingContext's active document's URL with exclude fragments flag set, and resource's url's fragment is non-null, then navigate to that fragment and abort these steps.

https://html.spec.whatwg.org/multipage/browsers.html#navigate

CSS/SVG needs to be handled in CSS and SVG specs, but I think there has been some work already to try to deal with this problem... cc @AmeliaBR @tabatkins

@duanyao
Copy link
Author

duanyao commented Sep 14, 2016

But what to do if there is a valid <base> in a about:blank doc, and we still want to resolve pure fragment urls against the doc? It seems about:blank#foo works in Firefox and Chrome, but not in Edge.
Even if about:blank#foo works, it is still very nasty to change every pure fragment urls.

Test case:

<!DOCTYPE html>
<iframe style="width:400px; height:400px"></iframe>
<script>
var frame = document.querySelector('iframe');
if (frame.contentDocument.readyState == 'complete') {
  renderFrame();
} else frame.onload = renderFrame;

function renderFrame() {
  if (!frame.contentDocument || frame.contentDocument.URL !== 'about:blank') {
    return;
  }
  frame.contentDocument.head.innerHTML = '<base href="http://example.com" >';
  var content = '';
  for (var i = 0; i < 50; i++) {
    content += '<p id="' + i + '">' + i + '</p>';
  }
  // go to http://example.com/#25 in all browsers
  content += '<p><a href="#25">go to #25</a></p>';
  // go to #25 in Chrome & Firefox, fail in Edge
  content += '<p><a href="about:blank#25">go to about:blank#25</a></p>';
  frame.contentDocument.body.innerHTML = content;
}
</script>

@duanyao
Copy link
Author

duanyao commented Sep 14, 2016

Just found that CSS has special behavior for fragment-only urls: always treat as same-document (rather than cross-document): https://drafts.csswg.org/css-values-3/#local-urls

Should HTML spec do the same thing?

@AmeliaBR
Copy link

I handled this in SVG 2 by requiring that, for SVG cross-references

  • URLs are only made absolute when needed
  • After generating an absolute URL, it must be compared against the current document base URL (not against the actual document URL); if they match, treat this as a same-document cross reference rather than a fetch.

For links, I reference the HTML rules (or W3C snapshot thereof), so I don't explicitly require the same comparison against document base URL before navigation. But if HTML makes it explicit, SVG will be expected to get the matching behavior.

In CSS it's a little more complicated, because they also wanted to enable same-document cross references (for properties like clip-path) with CSS set in a .css file. So CSS Values and Units 4 adds a special rule that target-only URLs are always to be treated as same-document URLs, relative to whatever document contains the styled element.

PS, These are both recent spec changes; implementations have not been universally updated to match.

@duanyao
Copy link
Author

duanyao commented Sep 15, 2016

Thanks for the detailed explanation!

Maybe it's better to just fix the navigation rule of HTML: treat #foo and document.baseURI + '#foo' as same-document navigation. But I doubt whether this is web compatible.

@annevk
Copy link
Member

annevk commented Sep 15, 2016

URLs are only made absolute when needed

How does this work? Making a URL absolute is not something https://url.spec.whatwg.org/ supports. But assuming you mean parsing a URL string into a URL record, how can you only do that sometimes? And if do not do it at a deterministic point in time, you break blob URLs.

@annevk annevk closed this as completed May 3, 2017
@tabatkins
Copy link
Contributor

CSS, in particular, explicitly calls out hash-only urls (that is, values of the url() function that start with a hash) as always being local. They still resolve to absolute URLs as normal, but they have an internal "local url" flag set, forcing them to serialize as hash-only, and making them always be interpreted as references to the current document only.

@duanyao
Copy link
Author

duanyao commented May 4, 2017

Now that this issue was closed, what was the resolution?

@annevk
Copy link
Member

annevk commented May 4, 2017

No change, basically. We're not going to add new features for this and changing the way fragment identifiers work seems extremely risky.

@duanyao
Copy link
Author

duanyao commented May 4, 2017

How about the different behaviors between Chrome and Firefox/Edge when navigating to #foo or about:blank#foo mentioned in this issue?

@annevk
Copy link
Member

annevk commented May 4, 2017

I'll reopen it for that since it does seem worth to add tests if we don't have any yet. I don't really understand how you get a new nested frame by following a link.

@annevk annevk reopened this May 4, 2017
@duanyao
Copy link
Author

duanyao commented May 4, 2017

Which browser are you testing? Chrome 53 should load a nested iframe, not sure newer versions.
Update: Chrome 60 still loads a nested iframe when click "go to the 25th" for the first time, but does nothing for following clicks.

@annevk
Copy link
Member

annevk commented May 4, 2017

It doesn't load a nested iframe here. It just navigates the iframe the link is in.

@duanyao
Copy link
Author

duanyao commented May 4, 2017

So you mean Chrome and Firefox have same behavior? Strange.

@duanyao
Copy link
Author

duanyao commented May 4, 2017

Can you try html this in Chrome? fragment-url-base-link-dynamic.htm.zip

The screenshot after clicking "go to the 25th" looks like
20170504201351

@annevk
Copy link
Member

annevk commented May 4, 2017

I think this is a duplicate of #421. I don't think I get different results from you, I'm just describing it differently.

@duanyao
Copy link
Author

duanyao commented May 4, 2017

I see. Is about:blank#25 case mentioned in #1781 (comment) also covered by #421 ?

@annevk
Copy link
Member

annevk commented May 4, 2017

Yeah, it's basically that bug. But we can leave this open and close them together.

@zcorpan zcorpan added the needs tests Moving the issue forward requires someone to write tests label Sep 1, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs tests Moving the issue forward requires someone to write tests
Development

No branches or pull requests

5 participants