Closed Bug 114461 Opened 20 years ago Closed 16 years ago

document.open/document.write clobbers js scope/context

Categories

(Core :: DOM: Core & HTML, defect)

defect
Not set
major

Tracking

()

RESOLVED FIXED
mozilla1.3final

People

(Reporter: basic, Unassigned)

References

(Depends on 1 open bug, )

Details

(Keywords: testcase, topembed-, Whiteboard: [ADT3] need info)

Attachments

(3 files, 10 obsolete files)

after calling document.open() previously defined javascript functions seems to
disappear...

This works in NN4.78 ( via http only, for some reason doesn't work when loaded
locally)

This works in IE5.01 SP2 (everywhere)

This doesn't seem to work in win32 Opera5

related to bug 57107 maybe?
Attached file testcase js file (obsolete) —
Attached file testcase (obsolete) —
Comment on attachment 61136 [details]
testcase

after clicking the link in this testcase, it should doc.write the link again
with a thick border div below it.
Attached file testcase js file (obsolete) —
ooops last one didn't work
Attachment #61134 - Attachment is obsolete: true
Attached file testcase (obsolete) —
ok this one should work
Attachment #61136 - Attachment is obsolete: true
Attached file testcase js file (obsolete) —
sorry about the spam (I'm sure it works this time)
Attachment #61141 - Attachment is obsolete: true
Attached file testcase (obsolete) —
finally!
Attachment #61142 - Attachment is obsolete: true
document's scope needs to be cleared after document.open() is called (directly
or indirectly by document.write[ln]()) for security reasons, if nothing else,
IIRC IE does this too, but IE seems to clear the scope *after* the script that
executed document.open() is completely executed (does properties defined in the
document.write()'n data also get cleared, I don't think so). Maybe we should
only clear the context if the calling context is *different* than document's
context?

Could someone investigate closer what IE and 4x does in this situation?
Status: NEW → ASSIGNED
Target Milestone: --- → mozilla0.9.8
I don't believe that document.open preserved old window scope contents in 4.x,
based on my memory and surfing http://lxr.mozilla.org/classic/search?doc_open.
Cc'ing chouck.

/be
It would seem to me that whatever JavaScript was running when document.open() is
called should continue to run until it completes its operation.  At least until
the document.close() call (albeit I have heard that there is some disagreement
as to the behavior of document.close())

I pointed out this problem because it jused seemed rather strange that a
JavaScript based page could not rewrite the JavaScript.  However, after checking
in Netscape 4.x and 3.x and IE 4.x and IE 5.x and Opera (4.x I believe - not my
system) and having this work, I thought it worth while to bring up to others who
deal with Mozilla a bit more than I do.

Given the timeframe when document.open() and document.open(...,"replace") were
added to the JavaScript -- back in version 1.1 -- this would seem to be the
reasonable behavior.  However, I can understand the difficulty of making it work
given the behavior of the document context.

I do think, however, that it is rather strange that the document context gets
ripped out from under the JavaScript as harshly as it is.

I had a variant of my page where I did not do document.open() or
document.write() but just built the whole HTML into one big string and then did,
all at once, a document.open();document.write(bigString);document.close();

This also failed as the bigString variable ended up being undefined by the time
the document.write() happened (only in NetScape 6.2 - all other systems seemed
to deal with it just fine)

This means that nasty things happen to the JavaScript context while it is still
running even.  The fact that the document.write(bigString) call happened after
having completely removed the document context is a bug - one way or the other.

Either (not my prefered answer) the JavaScript needs to be stopped if its
document context is removed/trashed

Or (my prefered answer) the JavaScript keeps a "shadow context" until it
completes running  (Which is what seems to be happening in the NS 4.x and IE
cases - however it was accomplished)

The current case is bad in both respects.

Note that a document.open() of a separate frame is not a problem since the
JavaScript is not running within that context.  However, this does not really
address the, what I see as a reasonable feature, of having a page update itself
via JavaScript generated HTML without the need for frames (I don't see any)
This is a real bug, but it has nothing to do with document.open causing
(synchronously) the window scope to be cleared.  It appears that generated
script tags don't work in Mozilla, at least not in 0.9.6.  Attaching testcase in
a minute.

/be
Attached file trivial .js file for test (obsolete) —
Target Milestone: mozilla0.9.8 → mozilla0.9.9
Brendan's testcase is strange because Vidur implemented dynamic addition of
<script> tags a while ago. Did something break or is this case blocked for some
reason?
Someone please debug a little -- I have no time.  I'd like to see this fixed in
0.9.9 though, so I'm happy it's targeted there.

/be
Keywords: mozilla0.9.9
We might be able to hook up a ``termination function''
(http://lxr.mozilla.org/seamonkey/source/dom/src/base/nsJSEnvironment.cpp#1448)
and delay the ::JS_ClearScope() call when document.open() is called so that the
scope would be cleared when the JS that executed document.open() is done. I
think this would match what IE does very closely.
Never mind IE, what did 4.x do?  That (actually 2.0-4.0) is the DOM level 0
progenitor.

/be
Netscape Navigator 2.02 and 3.04 works the same as moz, I get a foo is not
defined error.

Netscape Communicator 4.78 works with no js errors.
forgot to mention that I tested the win32 versions
Keywords: nsbeta1
Pushing to mozilla1.0
Target Milestone: mozilla0.9.9 → mozilla1.0
ADT3 per ADT triage.
Whiteboard: [ADT3]
Attachment #61328 - Attachment is obsolete: true
Attached file Correct testcase.
All the above testcases were invalid, this one shows the real problem here.
Attachment #61144 - Attachment is obsolete: true
Attachment #61145 - Attachment is obsolete: true
Attachment #61327 - Attachment is obsolete: true
Looks good to me, but I don't feel comfortable enough with JS internals to r=.

Let's get r= and sr= and get this in.
Keywords: mozilla0.9.9mozilla1.0
*** Bug 138939 has been marked as a duplicate of this bug. ***
Can we get r= and sr= on this one and get it into trunk?  jst, brendan?  It is
nsbeta1+, though it's adt3.
Changing nsbeta1+ [adt3] bugs to nsbeta1- on behalf of the adt.  If you have any
questions about this, please email adt@netscape.com.  You can search for
"changing adt3 bugs" to quickly find and delete these bug mails.
Keywords: nsbeta1-
Changing nsbeta1+ [adt3] bugs to nsbeta1- on behalf of the adt.  If you have any
questions about this, please email adt@netscape.com.  You can search for
"changing adt3 bugs" to quickly find and delete these bug mails.
Keywords: nsbeta1+
Attached patch Complete fix... (obsolete) — Splinter Review
The attached patch does two things. It makes us clear the scope when the script
that executes document.open() is done executing, and it makes us support
multiple termination functions on nsIScriptContext's, that's now needed since
document.write(), document.open() and window.close() can now all cause
termination functions to be added, IOW there can now (well, this is not really
new, but it's easier to trigger now than ever) be more than one termination
function per context...
http://bugscape.mcom.com/show_bug.cgi?id=14778 is tracking this due to some
european topsites breaking because of this
Bad news. I did some more testing with this patch (or a newer version there of)
and also with IE, and I'm afraid that this fix is not quite good enough, and I
don't know that we can fully emulate what IE does :-(

In a case like this, IE ends up clearing the scope where the
document.open/write/close is done once that script is done executing, but it
does not however clear methods in the scope used in the document from this point
on, starting with the document.open(). At the point of the document.write()
happening the script that's executing document.write() is running in scope A, if
a script tag is written out, that script executes in a different scope B. From
that point on, all scripts that run in the document that's being written out
will run in scope B, so properties defined in scripts that are written out will
remain defined in that scope, and properties from scope A are never reachable
from scope B, i.e. the following will work:

  var foo = "bar";
  document.open();
  document.write(foo);
  document.close();

but this won't work:

  var foo = "bar <script>alert(foo);</script>"
  document.open();
  document.write(foo);
  document.close();
  alert(foo);

here the document.write(foo) successfully writes out |foo|, and alert(foo); will
slow you the value of |foo|, but when the script tag is written out and
executed, it can't access |foo|. Furthermore, if there's an external reference
to the window where this is executed, the external references will point to the
global object in scope B. Or at least that's what it appears like, in reality,
say window X sets 'w' to point to window Y, in Y, window == opener.w, but window
!== opener.w. According to Brendan this is non-ECMA, so IE uses some kind of
delegation scheme when dealing with these scopes n' all...

Back to the drawing board...
Hardware: PC → All
To clarify my last comment, in the latter case, the alert(foo); that's
immediately after the document.close() successfully shows the value of |foo|,
but the alert(foo); in the script that's written out will not be able to reach
the |foo| property defined in scope A.
This won't make it for mozilla1.0, pushing forward.
Target Milestone: mozilla1.0 → mozilla1.2alpha
Johnny, where are we at with this?
Keywords: nsbeta1-nsbeta1
Fixing this will be really really hard, there's no way to get this in for
mozilla1.0, or mozilla1.0.1 :-(
Attached file a bunch of testcases (obsolete) —
*** Bug 158113 has been marked as a duplicate of this bug. ***
*** Bug 170719 has been marked as a duplicate of this bug. ***
retargeting to 1.3a since 1.2a is long gone.

We REALLY should try to fix this; I had an ops guy here ask me why his scripts
(used for monitoring clusters) no longer worked under mozilla.  Interestingly,
he said it worked in 1.0 but not in 1.1 (but I think he may have been lucky
and/or mistaken).  In any case, it was the classic "code in the Foo frame doing
Foo.document.clear()/etc" problem this bug is about.

Looks like there's been no work since May.
Severity: normal → major
Target Milestone: mozilla1.2alpha → mozilla1.3alpha
Keywords: mozilla1.0patch, testcase
FYI, the ops guy said it was broken but in a slightly different way in 1.0
Keywords: topembed
Attachment #82280 - Attachment is obsolete: true
Marking Topembed- as part of topembed triage. If anyone thinks this will
occur/does occur in the real world, please renominate.
Keywords: topembedtopembed-
renominating

I can guarantee this happens a lot in the real world.  As I said, someone here
wrote CGI's that generate HTML to monitor headend systems.  Those CGI's hit this
bug (and this bug forced them to rewrite their CGI's once I explained to them
why they didn't work).  Another person here has a personal webpage that was
being bitten by this bug (msinz).  There are plenty of sites in the real world
that hit this bug.

Apparently some european topsites are affected by this (I can't read it, but
that's what the comment here says):
http://bugscape.mcom.com/show_bug.cgi?id=14778

Feel free to topembed- it if you like, but not for the reason that it doesn't
happen "in the field".
Keywords: topembed-topembed
*** Bug 182614 has been marked as a duplicate of this bug. ***
jst, what is your take on this?  How hard and how important do you think this is?
Comment #c33 pretty much says how hard it would be to fix this, and as for the
importance of this bug, my feeling is that it's not all that important, but
other people, like Randell Jesup, seems to disagree. I don't know who's "right"
here.

If we decide that this is a must-fix for some release, we better know that
months before the release, otherwise I doubt we can come up with a reliable fix.
Note two other issues:

1)  The longer it is before this is fixed, the less likely it will matter.

2)  Not fixing this will cause one of two things to happen at any given site:

    a)  Changing of all pages this affects - which is sometimes easily done and
        sometimes not

    b)  Dropping support for Mozilla at the site.

In my personal case I had to change the site since I wanted to use Mozilla and a
number of the other users of the site wanted to switch from IE to Mozilla (Mac
OSX users in this case).  The really sad part was that it works in Netscape and
IE.  (At least my site did)

To fix my site to once again use the JavaScript mechanism (which significantly
reduces the number of HTTP transations) without having Mozilla fixed would
require that I use frames such that I could write into the other frame.  That
would end up breaking some other browsers that people use.  (My universe of
users happens to include many Mac users and they use a number of different browsers)

Anyway, my site is no longer affected (other than the increased HTTP
transactions and server load) and the longer Mozilla (and mozilla based
browsers) are broken the more likely I will never spend the time to return to
the JS form.

Generally, this is annoying.  And I can easily see some web sites going the
other way (don't worry about the broken browsers), which I would have done had
it not affected a large number of users, especially me :-)
Randall, can you be more specific about the top european sites affected? Given
that jst says this is a lot of work and brendan sez it is non-standard we'll
need a solid list of afflicted sites to make this topembed+

Thanks
Whiteboard: [ADT3] → [ADT3] need info
See bug 76495 comment 132.  I claim the same fix for the problem described by
that bug can and should suffice to fix this bug.  I'll think about taking both
bugs and doing the fix, and say more in a bit.

jst, stop me if you think I'm crazy.

/be
Depends on: zombie
Nope, Brendan, I think you're on the right track...
EDT is still awaiting a list of sites.
brendan, any headway here?
minusing for topembed at this point. if we can get a larger set of impacted
URLs, please re-nominate.
Keywords: topembedtopembed-
Target Milestone: mozilla1.3alpha → mozilla1.3final
Mass-reassigning bugs to dom_bugs@netscape.com
Assignee: jst → dom_bugs
Status: ASSIGNED → NEW
*** Bug 202096 has been marked as a duplicate of this bug. ***
adt: nsbeta1-
Keywords: nsbeta1nsbeta1-
*** Bug 206173 has been marked as a duplicate of this bug. ***
Summary: document.open clobbers js context??? → document.open/document.write clobbers js scope/context
*** Bug 212817 has been marked as a duplicate of this bug. ***
*** Bug 213989 has been marked as a duplicate of this bug. ***
I keep running into this annoying little problem with the JS context going away
when you try to rewrite the page in Mozilla.  I first reported this when I did a
photo album site and ended up having to do more of the work on the server side.

However, I have been tripped up by this a number of times since.  Each time I
bang my head and say "darn!  you can't do that in Mozilla even if it seems to
make sense" because it just seems natural to be able to run a script and have
that specific execution thread continue until the script exits.  Loosing all of
your variables and functions is just not expected.

I have, however, worked around this by using foo.innerHTML= but that requires
building the complete string all at once (you can not do foo.innerHTML+= - not
sure why yet)  However, this cuts off Netscape 4.x completely.  (Netscape 4.x
did work the document.write way, but Mozilla/Netscape 6+ do not...)

So, the only reasonable workaround I have found is to use the innerHTML= mechanism.

(Oh, and it is not really the same as the innerHTML= form is not like a
document.write() in that in-line JS does not get evaluated during the load/write
process.  However, since I can now fix the document how I want, this no longer
is an issue for me as I let the generating JS do what is needed at each point.)

So, I would say that if this can not be fixed, at least document the work-around
of using the innerHTML property.  It works reasonably well in all of the current
browsers (Safari, IE, Opera, and Mozilla/Netscape-based) with only minor
limitations.
I use a cookie to pass any REQUIRED data into a new document.
but that may be awkward for mucho data.....
Use it for database and search engine where only a dozen
or so vars need to be passed.
but that is only a workaround till it is fixed ;-] ;-]
 john in niagara
mks@sinz.org: a simpler workaround is to document.write() the entire document at
once.
Well, document.write of the whole document almost works - except if you want the
behavior of document.open('text/html','replace'); (see bug 164821 for a problem
with Mozilla in this case)

Anyway, if you are going to write the whole document at once you may as well use
the innerHTML trick and get the replace feature (no new history entry) and also
be able to only replace the HTML parts and not the JavaScript parts (if you wish).

Please excuse the tone of the last post I did as I was rather annoyed after
having a site once again not work in Mozilla and having tracked it down to this
problem.  It would be nice to fix but if not possible, at least having people
switch to the innerHTML trick will save a lot of headaches.
One alternative workaround that *may* work in some cases is to do the
document.write() in a local scope (i.e. in a function) and make sure you hold
local references to the data you're writing, that way your code will work as
long as your code doesn't depend on the global scope not being cleared. And if
your code does depend on some key functions being in the global scope, you can
always set the global functions back to what they were supposed to be after
you've called document.open().

It ain't pretty, but it may be a more workable alternative to using innerHTML.
*** Bug 224176 has been marked as a duplicate of this bug. ***
*** Bug 245830 has been marked as a duplicate of this bug. ***
*** Bug 251878 has been marked as a duplicate of this bug. ***
*** Bug 254678 has been marked as a duplicate of this bug. ***
*** Bug 259209 has been marked as a duplicate of this bug. ***
*** Bug 269408 has been marked as a duplicate of this bug. ***
   " (you can not do foo.innerHTML+= - not sure why yet)"
Because Gecko DOM closes the elements, thus
   document.write("<div>\r\n");
actually writes
   "<div>\r\n</div>".
*** Bug 274085 has been marked as a duplicate of this bug. ***
*** Bug 282201 has been marked as a duplicate of this bug. ***
*** Bug 283818 has been marked as a duplicate of this bug. ***
(In reply to comment #33)

I say accept the patch to let the first case work.
I would truly not expect the second case to even work as it is in a whole other
context/scope.  However I expect the first case to work since I'm still in the
document that is creating the new document.

> from scope B, i.e. the following will work:
> 
>   var foo = "bar";
>   document.open();
>   document.write(foo);
>   document.close();
> 
> but this won't work:
> 
>   var foo = "bar <script>alert(foo);</script>"
>   document.open();
>   document.write(foo);
>   document.close();
>   alert(foo);
> 

I became aware of this bug while trying to help someone out in the mozillazine
forums here:
http://forums.mozillazine.org/viewtopic.php?p=1276761
(In reply to comment #50)

I think the real bug is that creating a document destroys the current context
and takes with it your window and document references.  In other words
document.open should have returned the new document object like window.open.
But it isn't like that can be fixed now, you'd have to introduce a new method of
the document or window object for that.

There also is no way to save the reference to the current window so you can
access the 'globals'.  I think that if you save a window reference it should not
get silently replaced like that.  In code:
var winRef = window;
document.open();
// at this point winRef should be the original window not the new window object

I think this is what you are proposing in bug 76495.  If that is the case then
great.  But I still think you should take the patch as is now and implement the
proxy if time permits.  Coders are probably used to their window objects getting
clobbered as even IE does it.

> See bug 76495 comment 132.  I claim the same fix for the problem described by
> that bug can and should suffice to fix this bug.  I'll think about taking both
> bugs and doing the fix, and say more in a bit.
> 
> jst, stop me if you think I'm crazy.
> 
> /be
*** Bug 84634 has been marked as a duplicate of this bug. ***
*** Bug 290791 has been marked as a duplicate of this bug. ***
*** Bug 292330 has been marked as a duplicate of this bug. ***
I have a "killer favelet" that doesn't work in Firefox - but I can't tell
whether it's due to this bug, or should be filed as a separate bug.  What
confuses me is it works the first time I use it, but on subsequent times it
fails erratically by never writing the HTML to the document.

Here it is - I have a keyword "find" associated with this.  So I can type
find the capital of Zanzibar
in the address bar and I will get a frameset showing the search results on the
four most popular search engines.

javascript:var s = '%s'; if (s == '%' + 's') { s = prompt(%22Search for:%22,
%22%22); } if (s != null) { s = escape(s).replace(/\+/g, %22%%22 + %222b%22);
document.open(); document.write(%22<frameset rows='50%,50%'
cols='50%,50%'><frame src='http://www.google.com/search?q=%22 + s + %22'><frame
src='http://search.yahoo.com/search?p=%22 + s + %22'><frame
src='http://search.msn.com/results.aspx?q=%22 + s + %22'><frame
src='http://web.ask.com/web?q=%22 + s + %22'></frameset>%22); } void(0);

What makes me think it might be this bug is that I declare s before the
document.open() but use it after the document.write()
Depends on: splitwindows
1. This bug has been around since 2001
2. I admit that I'm not enough of an expert to argue the security issue but it
is hard to accept the argument given that the end result (a preserved js context
and a cleared body/new html) can be achieved in other--albeit more complex-- ways.  
3. In my view, it is a bug and quite a serious one. (a) There is no language or
environment that I have ever seen where the context is ripped out from under the
code in mid execution. (b) It doesn't happen in IE--or at least the versions
that I have worked in (c) It severely constrains or more realistically, all but
eliminates, the usefulness of document.write, and in a manner clearly not
expected in any documentation.
4. Surely the proper and intended design is for any javascript referenced in the
head section to remain in a separate environment from anything in the body/html;
since it is the latter that document.write should clear, the js context defined
in the head should remain untouched.
5. Document.write is useful for any number of purposes, including debugging. At
present, it's benefits are not available to many Firefox users.
6. Without wishing to appear unappreciative for all the hard work being done by
open source contributors, isn't it time for this bug to get a definite date for
a fix?
(In reply to comment #82)
> 1. This bug has been around since 2001
> [other complaints deleted]

Look, we're getting very close to being able to fix this bug thanks to the work
in bug 296639, so I'm confident it will be fixed in 1.9 -- I will make sure that
it is fixed in that milestone.  But your comment here is worse than useless. 
All you do is add noise and drive developers away with this sort of list.  What
you just did is clearly against bugzilla etiquette.  Please stop.

/be
Attached file updated testcases
Here's the current state of the testcases posted back in 2002.

This list was compiled after the checkin of split windows patch (bug 296639).

Current versions of Firefox 1.5, IE6, and Opera8 tested.
Attachment #90090 - Attachment is obsolete: true
The root problem here is, believe it or not, fixed now. The splitwindow landing
took care of this problem. Not sure what all the last testcase here is trying to
show, but the "Correct testcase." (attachment 77354 [details]) now works as expected.
Closing bug as FIXED, please open new bugs on any remaining related issues.
Status: NEW → RESOLVED
Closed: 16 years ago
Resolution: --- → FIXED
*** Bug 296544 has been marked as a duplicate of this bug. ***
Its fixed. 
*** Bug 317764 has been marked as a duplicate of this bug. ***
You need to log in before you can comment on or make changes to this bug.