Bug 16952 - Add a Blob.close()
Add a Blob.close()
Status: RESOLVED FIXED
Product: WebAppsWG
Classification: Unclassified
Component: File API
unspecified
PC All
: P2 normal
: ---
Assigned To: Arun
public-webapps-bugzilla
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2012-05-07 15:30 UTC by Arun
Modified: 2012-08-17 18:41 UTC (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Arun 2012-05-07 15:30:59 UTC
Currently, there's no way to "neuter" a Blob object.  Add a Blob.close() method (with method name TBD) that does the right things in terms of neutering a Blob object.
Comment 1 Eric Uhrhane 2012-05-07 16:55:40 UTC
Do we need to be able to neuter blobs?  It's most useful for transferring expensive objects between the document and worker contexts without copies, but blobs are designed to be [potentially] cheap anyway.
Comment 2 Jonas Sicking 2012-05-07 17:23:53 UTC
Blobs represent a potentially large amount of data, which in best case is on disk, worst case in memory, in both cases expensive on mobile.

It's generally a bad idea to rely on GC for managing expensive resources. (I believe that is a quote from Darin Fisher, but don't quote me on that :) ).

Hence it makes sense to me to have an explicit function to neuter a Blob. However, I think it's important that when you do neuter it, any already started reading operations will not be affected, and any other Blob instances, including slices, are not affected.
Comment 3 Arun 2012-06-26 20:27:40 UTC
There's a close() now:

http://dev.w3.org/2006/webapi/FileAPI/#dfn-close
Comment 4 Arun 2012-06-27 20:35:14 UTC
Marking this resolved | fixed.
Comment 5 Simon Pieters 2012-07-02 06:16:29 UTC
The spec should say that size must return 0 if the Blob is neutered (is consistent with ArrayBuffer). (Please specify this at #dfn-size.)

I'm not happy with async reads being successful for neutered Blobs. If Blobs are made Transferable, and gets transfered mid-read, it would mean you have to make a copy anyway. I would prefer if async reads fail if the Blob gets neutered.

The requirement about sync read methods should be removed since it can't happen to begin with.

"dereferencing a Blob URI bound to a Blob object on which close has been called results in a 500 Error." this part should be made a requirement (preferably in the part of the spec where dereferencing a Blob URI is defined).
Comment 6 Arun 2012-07-03 14:47:18 UTC
(In reply to comment #5)
> The spec should say that size must return 0 if the Blob is neutered (is
> consistent with ArrayBuffer). (Please specify this at #dfn-size.)
> 

OK.

> I'm not happy with async reads being successful for neutered Blobs. If Blobs
> are made Transferable, and gets transfered mid-read, it would mean you have to
> make a copy anyway. I would prefer if async reads fail if the Blob gets
> neutered.

But what if a read has already been initiated?  I think this requirement is for reads that are underway.  Are you ok with *that*?  If so, that should be made more clear.  

I wonder now if we should keep a flag that indicates neutered on a Blob.
 
> The requirement about sync read methods should be removed since it can't happen
> to begin with.
> 

OK.

> "dereferencing a Blob URI bound to a Blob object on which close has been called
> results in a 500 Error." this part should be made a requirement (preferably in
> the part of the spec where dereferencing a Blob URI is defined).

OK.
Comment 7 Arun 2012-07-03 14:55:38 UTC
Another important thing to note is that Blob is not Transferable -- we're merely cribbing from HTML5's concept of neutered objects, without taking the notion of Transferable interfaces over.
Comment 8 Simon Pieters 2012-07-03 15:59:20 UTC
(In reply to comment #6)
> But what if a read has already been initiated?  I think this requirement is for
> reads that are underway.  Are you ok with *that*?

No. I think it should fail in that case. Similarly as if the user removes a file from disk while the browser is reading it. It seems the async read algorithm doesn't actually step through the fail steps after the read has started, currently, but it should, right?

> I wonder now if we should keep a flag that indicates neutered on a Blob.

That works. The ArrayBuffer spec seems to just reference "neutered" and use it as a flag.

(In reply to comment #7)
> Another important thing to note is that Blob is not Transferable -- we're
> merely cribbing from HTML5's concept of neutered objects, without taking the
> notion of Transferable interfaces over.

But we should make sure that it can be made Transferable in the future and ideally let it have the same semantics as close() wrt neutered, IMHO.
Comment 9 Jonas Sicking 2012-07-03 22:05:13 UTC
Once a read has started, we should definitely not allow other in-browser APIs to cause it to fail more or less stochastically. I.e. if someone writes a page like:

var reader = new FileReader();
reader.readAsArrayBuffer(myblob);
setTimeout(function() {
  myblob.close();
}, 500);

Then this shouldn't fail in some browsers and work in others. Or work for users with a fast filesystem but fail for users with a slow filesystem.

Exactly the same thing goes for

var xhr = new XMLHttpRequest();
xhr.open("GET", someurl);
xhr.send(myblob);
setTimeout(function() {
  myblob.close();
}, 500);


Likewise

var myurl = URL.createObjectURL(myblob);
imgElement.src = myurl;
setTimeout(function() {
  URL.revokeObjectURL(myurl);
}, 500);

should not fail or work depending on timing.

So any reads that have already started should not fail when Blob.close() or URL.revokeObjectURL is invoked.


I disagree with the argument that this is just like if the user deletes the file through the filesystem. First of all that means that the user has to take explicit action, which is unlikely these days given that few users mess around in the filesystem. It also is something that the user can prevent if he/she realizes that things fail if they go and delete a file too quickly after doing something with them in a webpage.

Second, the OS filesystem can be made to prevent the user from deleting the file. I.e. if the browser keeps the file open in read mode while reading from the file, then the user is either prevented from deleting the file (Windows), or the file won't be truly deleted until the browser closes the file (Linux, OSX).
Comment 10 Simon Pieters 2012-07-04 07:32:49 UTC
OK, that seems fair enough. But if we want to make Blobs Transferable, what do you want to happen here?

var reader = new FileReader();
reader.readAsArrayBuffer(myblob);
setTimeout(function() {
  worker.postMessage(myblob, [myblob]);
}, 500);

var xhr = new XMLHttpRequest();
xhr.open("GET", someurl);
xhr.send(myblob);
setTimeout(function() {
  worker.postMessage(myblob, [myblob]);
}, 500);

? Should the message be delayed until the read has completed?
Comment 11 Jonas Sicking 2012-07-10 09:20:39 UTC
Given that blobs are read-only, there's no point in making them "transferrable". I.e. there's no point in ever invalidating them on the sending side. It's possible for the implementation to share the data between the two threads anyway.
Comment 12 Simon Pieters 2012-07-10 10:51:03 UTC
OK.
Comment 13 Arun 2012-07-11 19:15:47 UTC
I fixed the specification based on Comment 5. 

http://www.w3.org/TR/2012/WD-FileAPI-20120712/#close-method

(In reply to comment #5)
> The spec should say that size must return 0 if the Blob is neutered (is
> consistent with ArrayBuffer). (Please specify this at #dfn-size.)

Done.

http://www.w3.org/TR/2012/WD-FileAPI-20120712/#dfn-size

> 
> I'm not happy with async reads being successful for neutered Blobs. If Blobs
> are made Transferable, and gets transfered mid-read, it would mean you have to
> make a copy anyway. I would prefer if async reads fail if the Blob gets
> neutered.

As discussed:

1. A read that is underway continues.  But this is stipulated in a Note.  I wonder what else, if anything, has to be done to bolster this condition.

2. A read commencing on a neutered Blob throws; see for example: http://www.w3.org/TR/2012/WD-FileAPI-20120712/#dfn-readAsText

While a neutered Blob has size 0, resulting in an empty result, I think that throwing when reading a neutral Blob object is still useful for developers.

> 
> "dereferencing a Blob URI bound to a Blob object on which close has been called
> results in a 500 Error." this part should be made a requirement (preferably in
> the part of the spec where dereferencing a Blob URI is defined).

Done.  It's in http://www.w3.org/TR/2012/WD-FileAPI-20120712/#lifeTime

Feedback welcome before this is closed.
Comment 14 Jonas Sicking 2012-07-12 02:14:45 UTC
Hmm.. I wonder if it would make using Blobs easier if we didn't throw when trying to read from a neutered Blob. That way the page can be sure that reading will never throw, and can simply watch for error events.

I agree that reading from a neutered Blob is generally a bug, and throwing in cases of bugs is generally a good thing. But I wonder if this might be a case where not throwing and instead firing an error event asynchronously would simplify the model for developers.
Comment 15 Simon Pieters 2012-07-12 05:04:53 UTC
TypedArray allows reading after being neutered, AFAICT, but maybe it should be changed?
Comment 16 Arun 2012-07-12 16:05:05 UTC
(In reply to comment #14)
> Hmm.. I wonder if it would make using Blobs easier if we didn't throw when
> trying to read from a neutered Blob. That way the page can be sure that reading
> will never throw, and can simply watch for error events.
> 
> I agree that reading from a neutered Blob is generally a bug, and throwing in
> cases of bugs is generally a good thing. But I wonder if this might be a case
> where not throwing and instead firing an error event asynchronously would
> simplify the model for developers.

I don't think so.

Note that neutering a Blob and then explicitly reading on that Blob is such a bad pattern that throwing seems better than yet another error event.  It is probably the result of a mistake, or else something that the developer should catch (e.g. a Blob that's neutered owing to a set of conditions, etc.).
Comment 17 Jonas Sicking 2012-07-12 19:39:40 UTC
The thing is that a Blob can generally be passed around through a lot of parts of a code-base due to it's mostly-readonly nature.

This could mean that just because part of the code closes a Blob, doesn't always mean that another part of the code which has a reference to the same Blob, is always aware.
Comment 18 Arun 2012-07-12 19:52:30 UTC
(In reply to comment #17)
> The thing is that a Blob can generally be passed around through a lot of parts
> of a code-base due to it's mostly-readonly nature.
> 
> This could mean that just because part of the code closes a Blob, doesn't
> always mean that another part of the code which has a reference to the same
> Blob, is always aware.

Which I think is fine, and independent of our discussion about whether or not to throw, no?

This is similar to reads which are already underway: technically, such reads are "unaware" that a Blob has had close() called on it and is thus neutered, which is why we allow them to go through.  Operations which begin anew on a neutered Blob (and thus, operations which are "aware" of the fact that the Blob is neutered) throw.  

Or have I missed something?
Comment 19 Arun 2012-08-17 18:41:44 UTC
I think this is fixed now.  Please file a different bug for specifics.