Friday, August 28, 2009

Securing the web with continuations!

The payoff from the previous posts:

Say Alice is an iframe inside Bob and wants to start a shared library with Bob.

alice.html:


library = {y: {x: "call me Ishmael"}};


bob.html:

var library = makePostMembrane(document.getElementById('alice').contentWindow).getRoot("library");
alert(library.y().x())


Technical aside: unfortunately, Strands etc. do not support continuations captured in redefined field accessors (setters/getters), so I didn't quite achieve the transparency goal of "library.y.x", but close :) Maybe try hacking in support if I have time.

The architecture is somewhat interesting:
  1. One cross-frame 'networking' library for using the string-passing abilities of postMessage to make sharing closures and objects between frames no different from passing to them to functions/actors in the same context: no more JSON and strange asynchronous protocols.
  2. Optionally, our membrane library
  3. More optionally, one of our view/policy libraries

Digging deeper..

To build 1), transparent sharing, we load libraries to CPS the page and construct proxy objects that proxy shared-object interactions between frames viz. the asynchronous postMessage primitive for passing strings between frames. Pretty quickly, it's clear there are distributed object usage concerns like deadlock. Our library helps a bit (e.g., handshaking for initialization and caching), but the push for process-per-origin/process-per-frame has created serious usability problems. The pickling support doesn't help you with the concurrency, and my tactic of using continuations hides the ugliness in the typical case, but, in reality (and, arguably, in the normal code without the library), there are yields in the middle of event handling! Invariants might not be held when control is resumed if folks aren't careful. Perhaps flapjax to the rescue? :) A transactional approach might make sense... but then again... I suspect it'd be horrendous in this domain: transparency is the goal.

Now 2) If, instead of exporting say "window" to be shared, we exported a fresh "membrane(window)" for every iframe, we can, at any time, turn on/off or even modify access to shared objects and even be selective about for which principal. Again, for free. Sort of like flying with Python, but safer. Complete mediation ftw! Also happens to be the first true aspect system for JavaScript and introduces a new notion of secure advice.

Writing behavior for 2) from scratch and per-field/object/method/etc. is cool at first, but quickly, you hit repetitive abstractions. Enter 3): a binary yes/no policy language (the 'who' is whoever has the object reference; the action is 'invoke', so all that is left is the yes/no choice on the resource). That's not quite true: introducing exceptions on DOM access might break programs, so we might want to semantically hide elements. Generalizing, we see we just want to create a secure bidirectional view , which we do for a useful case. Would be fun to create more combinators :)


... and now... benchmarking and updating the writeup :(

Wednesday, August 19, 2009

JavaScript Continuation Support? 2: Strands

Strands did what I expected (though still need to write my actual app using it :)):


function sleep(millis) {
var future = new Future();
setTimeout(future.fulfill, millis);
future.result();
}


function go () {
document.getElementById("txtr").innerHTML += "1" ;
sleep(2000);
document.getElementById("txtr").innerHTML += "2" ;

}

function go2 () {
go();
document.getElementById("txtr").innerHTML += "3" ;
}


new Future(go2);


Yields "123". Requiring "new Future(go2)" isn't that wonky to work with in terms of my transparency goals: just wrap the entire program in a thunk and call it as a future.

Setting up the library took a bit of editing: line 344 of strand.js had a strange eval statement that wasn't parsing so I removed it (Firefox 3.5.2). Depending on how you invoke it, you might need to change some hardcoded default paths. I couldn't get the compiler mode working, unfortunately. We'll see if it can handle big APIs :)

JavaScript Continuation Support? 1: NarrativeJS

Narrative JS enables you to define a sleep function in JavaScript:


function sleep (ms) {
var n = new EventReceiver();
setTimeout(n, ms);
n.wait->(); //block until n called
}


Now, we can sleep between printing without manual CPSing:


function writer() {
document.write("1");
sleep->(1000);
document.write("2");
}
writer();


This is close to what I wanted.. but not enough. Consider the following:


writer();
document.write("3");


I expected to see "1", and then, a second later, "123". Unfortunately, I saw "132"! The magic incantation would have been:


writer->();
document.write("3");


Essentially, the extension broke function encapsulation with respect to control. I can see merit to it -- rewriting becomes a local process. I want to truly and transparently write my asynchronous code in a synchronous manner (for a reason to be disclosed later): NarrativeJS helps clean up callback code while maintaining basic callback-style code structure (so you don't worry differently about a UI event handling mucking with state between callbacks), but it doesn't restore the synchronous semantics.

This is great... but I want the transformation to be global: sleep(), not sleep->(). Hopefully Strands fares better.

JavaScript Continuation Support?

Any recommendations for a JavaScript extension to support continuations?

I want to straighten some callbacks for Google Maps (and, yeah, I know Flapjax is another way to do that!). The important part is that I'll be wrapping their API: user code should look like "x = map.getZip(...)" and my wrapper will add in the continuations behind the scenes.

NarrativeJS was early on continuation support, but I don't think it supports dynamic code loading (and I have to trust it wraps gmaps correctly!). More recent approaches (jwacs, strands) seem to build upon it and somehow use JS 1.7 generators for more native support and dynamic code loading, but they seem to add wrapping obligations to callsites that I'm explicitly trying to avoid.

The pay off will be insanely cool :)

Tuesday, August 18, 2009

Back on the mainland

Crazy vacation #2: Hawaii! AKA, Leo learns how to surf.

Other news..

  • MSR work is going well.
  • Flapjax paper for OOPSLA won a best paper award -- and it actually left out a lot of the good stuff. E.g., talking about how to interface FRP code with imperative APIs without destroying performance, experiences at Berkeley getting undergrads to use and implement an FRP system, and, as Mike noted, his integration of a more relational (lense) layer was relegated to a couple of paragraphs that probably don't make any sense for newcomers.
  • I think I want to take our web application paper out of the dustbin, extend it a bit, and try for ICSE in a few weeks. I love that there was an FSE position paper suggesting someone should do work like ours yet the conference rejected ours that actually did it ;-) This paper has been a frustrating process, yet I think it's as exciting as our parallel browser work.
  • For this week, I want to add a cool postmessage layer to our membrane work (our main usage was for Caja, but it helps even in MashupOS style isolation approaches). Reviewers for the paper would be appreciated -- not sure if we're going for NDSS or WWW.
  • Talk @ Adobe on the parallel web browser soon, finishing font benchmarks, and cleaning up prose for the parallel CSS paper (IPDPS? PLDI? already several pages over..)
August/September will be nuts with paper polishing. But, luckily, back to research after that.

Finally... there's talk of a half-marathon in Napa for Halloween. I did ~5 miles on somewhat hilly terrain a few times last week in Hawaii (going around diamond head), but never have tried longer. Have started working on my 5k (~26min or 8.5min miles), which seems to have led to my bumping up normal pace mileage. Might need to be more methodical about this if I want to enjoy Napa after the marathon :)