On Wed, Aug 1, 2012 at 7:59 AM, Robin Berjon <ro...@berjon.com> wrote: > Hi all, > > with the likes of postMessage and Web Intents that we are getting access to > now, it is increasingly common that data may flow from a server to an > in-browser page, that may then pass that data on to another in-browser page > (typically running at a different origin). In a many cases, such data will be > captured as Blobs. There can be several reasons why one may wish to toss a > Blob over postMessage rather than a URL: > > • Origin restrictions and lack of CORS support (not necessarily fixable > by the hacker working on the site); > • CSP on the receiving end; > • Cookies or authorisation issues; > • Hotlinking prevention; > • Secrecy of the actual URL to the data (possibly for privacy reasons); > • Probably a bunch of others I haven't thought of. > > The problem is that the way that things currently work, the sending end needs > to load the data in full before transmitting it. That's okay when it's small > and there are only few resources, or if you know that the receiving end will > read it all right away anyway. But there are cases in which there is a lot of > data (e.g. an image gallery) or where the receiving end might filter the > data, only load it item per item, etc. > > This is something that we noted while working on implementing some Web > Intents based services but that applies more broadly. The most acute example > was Jungkee Song's Pick Image Intent that could easily find itself in a > position to load several hundreds of megabytes that might then just be thrown > away by the receiving end. > > The proposals below were hashed out with Jungkee Song and Richard Tibbett, > based on the above use case as well as several people in the Intents and DAP > groups stating that they bumped into situations where they would have needed > this (feel free to send additional use cases folks). > > > POTENTIAL SOLUTIONS > =================== > > The overall idea is simple irrespective of which approach is chosen: create a > Blob that can lazily fetch the content of a URL. Blobs are designed to be > transparently lazy if they need to, so nothing needs to change at the Blob > level, or for that matter at the level of anything that may end up reading > from one. In fact, a good implementation that reads file-based Blobs is > probably already lazy. A Lazy Blob is just a Blob. > > Things start to get messier (unless we've missed an option) when you plug > that into URLs (don't they always). That's where the multiple approaches > outlined below kick in. > > In all approaches it is assumed that if there is information to be inferred > from context (e.g. access to cookies) then the relevant context is the one in > which the Blob is created. Reading of the Blob performed in another context > changes nothing to that. > > User agents are always allowed to access the actual data at any arbitrary > moment, between immediately and when code requests it. Of course, quality of > implementation may dictate a strategy that doesn't make it just as bad as > loading everything immediately. > > Also, none of the options below are detailed anywhere near where they should > be — but if we agree on the need and on a general direction I'll be happy to > take care of that. If there's agreement on this, I volunteer as editor > (Jungkee and perhaps Richard may be interested as well). > > > === The Simple Approach > > partial interface BlobBuilder { > Blob getBlobFromURL (DOMString url); > }; > > Usage: > var bb = new BlobBuilder() > , blob = bb.getBlobFromURL("http://specifiction.com/kitten.png"); > > This is the simplest possible approach. When called, essentially the > equivalent of this happens: > > var xhr = new XMLHttpRequest(); > xhr.open("GET", url, true); > xhr.responseType = "blob"; > > And upon reading the blob, send() is triggered and everything else happens as > if the XHR blob from xhr.response were accessed directly. > > Pro: Extremely simple. > Con: Does not allow much control over the request that gets made, notably > some uses will likely require setting headers. > > > > === The Somewhat Less Simple Approach > > partial interface BlobBuilder { > Blob getBlobFromURL (DOMString url, optional DOMString method, optional > Object headers); > }; > > Usage: > var bb = new BlobBuilder() > , blob = bb.getBlobFromURL("http://specifiction.com/kitten.png", "GET", { > Authorization: "Basic DEADBEEF" }); > > Everything is the same as the previous version but the method and some > headers can be set by enumerating the Object. I *think* that those are all > that would ever be needed. > > This is currently my preferred approach. If you like it too, you may consider > the following ones as merely curiosities. > > > === Using XHR For Options > > partial interface BlobBuilder { > Blob getBlobFromURL (XMLHttpRequest xhr); > }; > > Usage: > var bb = new BlobBuilder() > , xhr = new XMLHttpRequest(); > xhr.open("GET", "/kitten.png", true); > xhr.setRequestHeader("Authorization", "Basic DEADBEEF"); > var blob = bb.getBlobFromURL(xhr); > > This avails the developer the full flexibility and power of XHR, and uses the > configured XHR object to make the request (which is forced to responseType = > "blob" behind the scenes). It's more powerful and might be more future-proof, > but it's more verbose and carries some extra complexity. Once the XHR object > has been given to the BlobBuilder it needs to be impossible to change it, > events should fire on it, etc. > > > === Another XHR Approach > > partial interface XMLHttpRequest { > Blob makeLazyBlob (); > }; > > Usage: > var xhr = new XMLHttpRequest(); > xhr.open("GET", "/kitten.png", true); > xhr.setRequestHeader("Authorization", "Basic DEADBEEF"); > var blob =xhr.makeLazyBlob(xhr); > > This is very similar to the previous one in its power and complexity, but the > difference is that everything happens on XHR. > > > === The Inheritance Approach > > interface LazyBlob : XMLHttpRequest { > void send (); // noop > }; > > Usage: > var lb = new LazyBlob(); > lb.open("GET", "/kitten.png", true); > lb.setRequestHeader("Authorization", "Basic DEADBEEF"); > > More of the same, turns send() into a no-op. > > > === Cloneable XHR > > Just toss the XHR itself over postMessage(). > > > Speaking personally, I prefer option B but I'm certainly open to other > options. My primary concern at this time is to get a sense for whether > there's agreement on the issue to start with or not.
Since it appears my original email went unnoticed, here's another try. I think what you are looking for is Streams. The resulting code would be something like: var xhr = new XMLHttpRequest(); xhr.responseType = "stream"; xhr.open(...); xhr.send(); var stream = xhr.result; otherGuy.postMessage(stream); / Jonas