Eric Seidel wrote:
1. JS content authors will want an async API.
Sometimes, for the large applications; small apps won't care. As you note, the
workaround of immediately packaging up a setTimeout continuation isn't
difficult. I tend to think worrying about the N-1 case is designing a bit too
much for the special cases, personally. Special cases aren't special enough to
break the rules.[0] Further, nothing says browser implementations must or will
continue to enforce hard limits on recursion.
function messageHandler(messageEvent) {
// We assume calling into our complex functions might run out of stack
space, so we just handle this in a timeout:
setTimeout(0, function() { realMessageHandler(messageEvent) } );
}
function realMessageHandler(messageEvent) {
// handle the message...
// and, reply to the message
messageEvent.source.postMessage("response message");
}
Furthermore, note that the above behavior is actually *insecure* if the handler
authenticates the sender and discloses some secret in his response, because
|messageEvent.source| may have been navigated to a different origin. Making
the API async basically requires the optional origin argument always be
provided to postMessage, adding API complexity. If a piece of information
doesn't have to be [present] for the system to [usually] work, sooner or later
it won't be [and the system won't work].[1]
I forsee JS authors implementing their own asynchronous behavior, as
shown above.
I do, too, in some cases; I just don't think it's worth sacrificing simplicity
or security in the common case for the special, rare case.
2. JS engine implementors will want an async API.
I would rather we didn't prevent FireFox or Safari
"Firefox", the second "f" isn't capitalized. :-)
(Only possible for frames which are not of the same origin. Same-origin
frames already assume they can grab at each others innards in a
synchronous manner.) postMessage imposes a NEW requirement that all
connected frames to be run from the same thread (or somehow synchronize
the threads after the first postMessage() call is made).
Wrong; if a window can get a reference to another window, same-origin or not,
run-to-completion already requires synchronous behavior. If some piece of JS
is in flight, every client-side change it can detect *must* be one it has
caused.
This requirement would seem even worse for Microsoft, since IE8 looks like
it's multi-process. A synchronous postMessage would require IE8 to keep
all frames which have references to each other in the same process.
postMessage imposes no new requirement for the appearance of synchrony, no
matter how the implementation chooses to achieve it.
Asynchrony was brought up in a separate thread ("[whatwg] reply() extension to
postMessage()") two months ago, before the source-navigation discussion made this
secret-exposure danger more easily noticeable. I made basically the same arguments then
as I make now; I also noted that sync can replicate async (again ignoring the uncommon
case of being right at the recursion limit), whereas the reverse is not true:
I think I favor sync postMessage over async because async capabilities
are a strict subset of sync capabilities. You can always use setTimeout
with the sync model to get async behavior; if the model is async you
can't replicate sync behavior.
Note also that nothing prevents an implementation with a recursion limit from
requiring that postMessage always guarantee enough available frames to dispatch
the setTimeout continuation, although nobody I know has actually done this.
In sum, I think worrying about recursion limits is the wrong thing to do, sync
behavior is more flexible, and we shouldn't sacrifice security for the uncommon
recursion-limit case.
Jeff
0. Python, thy name is AWESOME. <http://www.python.org/dev/peps/pep-0020/>
1. Astonishingly PEP 20 doesn't have any dicta related to security, but
<http://www.wiretip.com/?about> comes to the rescue, with a few tweaks.