Closed Bug 881487 Opened 11 years ago Closed 11 years ago

document.write causes updates to location.hash to refresh the entire page

Categories

(Core :: DOM: Navigation, defect)

x86_64
Windows 7
defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla29

People

(Reporter: codefactorial, Assigned: bzbarsky)

References

()

Details

(Keywords: testcase, Whiteboard: [parity-chrome] [parity-opera][parity-ie])

Attachments

(2 files)

Attached file test.html
User Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0 (Beta/Release)
Build ID: 20130511120803

Steps to reproduce:

I have a simple HTML page that generates a string containing a full HTML document. This outer page I will refer to as the "bootstrap", and the HTML document created will be the "target". 

The bootstrap's purpose is to simulate a server side response by generating the same HTML that a JSP or PHP script would by first downloading several resources using AJAX, then generating the HTML, and then using the following code to display the page:

document.open(); document.write(html); document.close();

The example HTML is a stripped down version of the bootstrap application in which the html string is static rather than generated on the fly using AJAX and various parsing techniques. In the example, there are 3 buttons:

1) "Output New Page" : This writes some HTML to the document using document.write. Clicking this button will make buttons #2 and #3 appear.

2) "Add Hash" : The html for this button is inside the static HTML string and when clicked, it will set location.hash = 'test'

3) "What is the hash" : This is similar to button #2 and when clicked it will alert the current value of location.hash (which is initially blank, but should get updated to '#test')

Steps To Reproduce:

1) Go to http://jsfiddle.net/qTjr7/ (or open test.html attached to this bug)
2) Click "Output New Page"
3) Click "Add Hash"


Actual results:

The document is refreshed and the bootstrap page is rendered again. If you are using jsfiddle and you clicked the "run" button then you will see this:

{"error": "Please use POST request"}

If you refresh the page (instead of pressing "run") or open the attached test.html - the result will simply display "Output New Page" button again. And then when you click the "Output New Page" button again it shows an alert "The hash is already set!" in an alert popup.


Expected results:

The "Add Hash" should update the hash to "#test" and then if you click "What is the hash" it should display "#test" in an alert.
Summary: document.write causes updates to location.hash to function imporperly → document.write causes updates to location.hash to refresh the entire page
Component: Untriaged → Document Navigation
Keywords: testcase
Product: Firefox → Core
Whiteboard: [parity-chrome] [parity-opera][parity-ie]
Version: 21 Branch → Trunk
This is because the changes to location end up using the page URI, not the wyciwyg URI, presumably....

And the whole thing is a duplicate of the fact that we don't agree with other browsers on what the URI of document.open-created pages is.  Not least because what some of the other browsers do is nonsensical.  :(
Whiteboard: [parity-chrome] [parity-opera][parity-ie] → DUPEME [parity-chrome] [parity-opera][parity-ie]
@Boris,

Are you saying that there is another bug that is a duplicate of this one? If so, can you please provide a link to the duplicate issue so I can get a feeling if this problem will get resolved any time soon?

Or are you saying this is not a bug at all, and that all of the other modern browsers have it wrong?

I need a way to push a history state on the target page generated by the bootstrap javascript - otherwise there will be no way to parity all the features of a web 2.0 application on the target page in fire fox using this concept of a bootstrap javascript page.

If you have any alternative approaches to solving this with only changes to the bootstrap javascript and achieving similar results that IE/Opera/Chrome/Safari - then I am open to that. 

Changing the target HTML generated by the bootstrap will be the last resort only if the FireFox development team cannot/will not fix the problem with a new release and the bootstrap javascript cannot be changed to fix the problem.

The reason is that the target HTML generated by the bootstrap may reference javascript includes that are not under my control, and the behavior of those javascript files should ideally be the same regardless if they were included on a page that was created using window.open() or not.

Also - is there any way to detect in the target page if the page was created using window.open()? 

That way at the very least the target HTML page could then detect the situation and do some work around (such as not pushing a history state at all).
In my previous comment I meant to say document.open() instead of window.open()
I can confirm this issue exists. Another related issue is that after calling:

document.open(); document.write(html); document.close();

the reload button (including CTRL-R / Command-R) is broken.
Attachment #760601 - Attachment mime type: text/plain → text/html
I also can confirm this bug (Firefox 23.0.1). But for me it only happens after using XMLHttpRequest.

Syptoms are the same - you can't reload the page and changing just hash leads to full page reload. 

Here is the html that can be used to reproduce the issue.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html manifest="cache.manifest">
	<script type="text/javascript">
		(function() {
			var request = new XMLHttpRequest(),
				check_auth = function (e) {
					document.open();
					document.write('1');
					document.close();
				};
			request.addEventListener("load", check_auth);
			request.open('GET','/');

			request.send();
		})();
	</script>
</html>
I must also say, that above flow works fine in IE9, IE10 and Chrome 29
This bug breaks galleries on wired.com because it uses Mobify.js (which makes extensive use of doc.write) and jQuery gallery (which sets #hash to make each gallery image linkable - and sets #hash when showing the very first image on load - causing an annoying reload loop).
(In reply to Boris Zbarsky [:bz] from comment #1)
> we don't agree with
> other browsers on what the URI of document.open-created pages is.  Not least
> because what some of the other browsers do is nonsensical.  :(

Hi Boris,
I don't quite see the issue here - the trivial test case
<script>window.onload=function(){ document.write('<script>document.write(location.href)<\/script>') }</script>
works the same (and sensible) way in Gecko, PrestOpera and Chromium here. Any internal wyciwyg URL is an implementation detail which should have no observable consequences for scripts.

As we're now breaking a pretty high profile website with this bug I'd like to suggest prioritising it.
Status: UNCONFIRMED → NEW
Ever confirmed: true
Mobify.js tries to work around this: 
https://github.com/mobify/mobifyjs/commit/9a8e6ee72a67b19eb9a502bea9a1ca0573fe7bb3

The workaround might hurt later though, would be a lot nicer to have it fixed on our side :-/
I wonder why this bug I still not in work? Shame to set aside bugs like this.
If you have some reasons to not fixing it, you better write here about it.
(In reply to zozulyakviktor from comment #11)
> I wonder why this bug I still not in work? Shame to set aside bugs like this.

Everybody agrees that it is a problem and should get fixed - the likely problem is that the code is a bit complicated here and nobody with sufficient coding skills managed to look at this issue yet. Simple as that -
So at this point I think our handling of the document URI and location.href actually matches the spec, because the spec has changed.

The remaining reason for this bug is that Location operates on the result of CreateExposableURI, while the history scrolling code in nsDocShell::InternalLoad operates on mCurrentURI.  In this case the latter is the wyciwyg URI, so we get the failure mode described here.

The most obvious option for fixing this bug is to change InternalLoad to CreateExposableURI() from mCurrentURI before checking for anchor scroll.  Or if we want to be really safe, doing anchor scrolls if either mCurrentURI or its exposable version matches the incoming URI with hashes ignored.

Olli, thoughts?
Flags: needinfo?(bugs)
Whiteboard: DUPEME [parity-chrome] [parity-opera][parity-ie] → [parity-chrome] [parity-opera][parity-ie]
Or to use the document URI instead of mCurrentURI, except we may have no guarantee at that point that there's a document...
Assignee: nobody → bzbarsky
Status: NEW → ASSIGNED
Thanks a lot for tackling this Boris!
Flags: needinfo?(bugs)
Attachment #8358574 - Flags: review?(bugs) → review+
https://hg.mozilla.org/integration/mozilla-inbound/rev/4142d03082e1
Flags: in-testsuite+
Target Milestone: --- → mozilla29
https://hg.mozilla.org/mozilla-central/rev/4142d03082e1
Status: ASSIGNED → RESOLVED
Closed: 11 years ago
Resolution: --- → FIXED
Depends on: 974857
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: