1.Introduction
This section is informative.
Web applications should have the ability to manipulate as wide as possible a range of user input, including files that a user may wish to upload to a remote server or manipulate inside a rich web application. This specification defines the basic representations for files, lists of files, errors raised by access to files, and programmatic ways to read files. Additionally, this specification also defines an interface that represents "raw data" which can be asynchronously processed on the main thread of conforming user agents. The interfaces and API defined in this specification can be used with other interfaces and APIs exposed to the web platform.
TheFile
interface represents file data typically obtained from the underlying file system,
and theBlob
interface
( "Binary Large Object" - a name originally introduced to web APIs inGoogle Gears)
represents immutable raw data.File
orBlob
reads should happen asynchronously on the main thread,
with an optional synchronous API used within threaded web applications.
An asynchronous API for reading files prevents blocking and UI "freezing" on a user agent’s main thread.
This specification defines an asynchronous API based on anevent modelto read and access aFile
orBlob
’s data.
AFileReader
object provides asynchronous read methods to access that file’s data
through event handler content attributes and the firing of events.
The use of events and event handlers allows separate code blocks the ability
to monitor theprogress of the read(which is particularly useful for remote drives or mounted drives,
where file access performance may vary from local drives)
and error conditions that may arise during reading of a file.
An example will be illustrative.
function startRead() { // obtain input element through DOM var file= document. getElementById( 'file' ). files[ 0 ]; if ( file){ getAsText( file); } } function getAsText( readFile) { var reader= new FileReader(); // Read file into memory as UTF-16 reader. readAsText( readFile, "UTF-16" ); // Handle progress, success, and errors reader. onprogress= updateProgress; reader. onload= loaded; reader. onerror= errorHandler; } function updateProgress( evt) { if ( evt. lengthComputable) { // evt.loaded and evt.total are ProgressEvent properties var loaded= ( evt. loaded/ evt. total); if ( loaded< 1 ) { // Increase the prog bar length // style.width = (loaded * 200) + "px"; } } } function loaded( evt) { // Obtain the read file data var fileString= evt. target. result; // Handle UTF-16 file dump if ( utils. regexp. isChinese( fileString)) { //Chinese Characters + Name validation } else { // run other charset test } // xhr.send(fileString) } function errorHandler( evt) { if ( evt. target. error. name== "NotReadableError" ) { // The file could not be read } }
2.Terminology and Algorithms
When this specification says toterminate an algorithmthe user agent must terminate the algorithm after finishing the step it is on.
Asynchronousread methodsdefined in this specification may return before the algorithm in question is terminated,
and can be terminated by anabort()
call.
The algorithms and steps in this specification use the following mathematical operations:
-
max(a,b) returns the maximum of a and b, and is always performed on integers as they are defined in WebIDL[WebIDL]; in the case of max(6,4) the result is 6. This operation is also defined in ECMAScript[ECMA-262].
-
min(a,b) returns the minimum of a and b, and is always performed on integers as they are defined in WebIDL[WebIDL]; in the case of min(6,4) the result is 4. This operation is also defined in ECMAScript[ECMA-262].
-
Mathematical comparisons such as < (less than), ≤ (less than or equal to), and > (greater than) are as in ECMAScript[ECMA-262].
The termUnix Epochis used in this specification to refer to the time 00:00:00 UTC on January 1 1970
(or 1970-01-01T00:00:00Z ISO 8601);
this is the same time that is conceptually "0
"in ECMA-262[ECMA-262].
Blob
blob,start,end,andcontentTypeis used to refer to the following
steps and returns a newBlob
containing the bytes ranging from thestartparameter
up to but not including theendparameter. It must act as follows:
-
LetoriginalSizebeblob’s
size
. -
Thestartparameter, if non-null, is a value for the start point of aslice blobcall, and must be treated as a byte-order position, with the zeroth position representing the first byte. User agents must normalizestartaccording to the following:
- Ifstartis null, letrelativeStartbe 0.
- Ifstartis negative, letrelativeStartbe
max((originalSize+start), 0)
. - Otherwise, letrelativeStartbe
min(start,originalSize)
.
-
Theendparameter, if non-null. is a value for the end point of aslice blobcall. User agents must normalizeendaccording to the following:
- Ifendis null, letrelativeEndbeoriginalSize.
- Ifendis negative, letrelativeEndbe
max((originalSize+end), 0)
. - Otherwise, letrelativeEndbe
min(end,originalSize)
.
-
ThecontentTypeparameter, if non-null, is used to set the ASCII-encoded string in lower case representing the media type of the
Blob
.User agents must normalizecontentTypeaccording to the following:- IfcontentTypeis null, letrelativeContentTypebe set to the empty string.
-
Otherwise, letrelativeContentTypebe set tocontentTypeand run the
substeps below:
-
IfrelativeContentTypecontains any characters outside the range of U+0020 to U+007E, then setrelativeContentTypeto the empty string and return from these substeps.
-
Convert every character inrelativeContentTypetoASCII lowercase.
-
-
Letspanbe
max((relativeEnd-relativeStart), 0)
. -
Return a new
Blob
objectSwith the following characteristics:
3.The Blob Interface and Binary Data
ABlob
object refers to abytesequence,
and has asize
attribute which is the total number of bytes in the byte sequence,
and atype
attribute,
which is an ASCII-encoded string in lower case representing the media type of thebytesequence.
EachBlob
must have an internalsnapshot state,
which must be initially set to the state of the underlying storage,
if any such underlying storage exists.
Further normative definition ofsnapshot statecan be found forFile
s.
[Exposed =(Window ,Worker ),Serializable ]interface {
Blob (
constructor optional sequence <BlobPart >blobParts ,optional BlobPropertyBag = {});
options readonly attribute unsigned long long size ;readonly attribute DOMString type ; // slice Blob into byte-ranged chunksBlob slice (optional [Clamp ]long long ,
start optional [Clamp ]long long ,
end optional DOMString ); // read from the Blob. [
contentType NewObject ]ReadableStream stream (); [NewObject ]Promise <USVString >text (); [NewObject ]Promise <ArrayBuffer >arrayBuffer (); [NewObject ]Promise <Uint8Array >bytes (); };enum {
EndingType ,
"transparent" };
"native" dictionary {
BlobPropertyBag DOMString type = "";EndingType endings = "transparent"; };typedef (BufferSource or Blob or USVString );
BlobPart
Blob
objects areserializable objects.Theirserialization steps,
givenvalueandserialized,are:
-
Setserialized.[[SnapshotState]] tovalue’ssnapshot state.
-
Setserialized.[[ByteSequence]] tovalue’s underlying byte sequence.
Theirdeserialization step,givenserializedandvalue,are:
-
Setvalue’ssnapshot statetoserialized.[[SnapshotState]].
-
Setvalue’s underlying byte sequence toserialized.[[ByteSequence]].
Blob
blobhas an associatedget streamalgorithm,
which runs these steps:
-
Letstreambe anew
ReadableStream
created inblob’srelevant Realm. -
Set upstreamwith byte reading support.
-
Run the following stepsin parallel:
-
While not all bytes ofblobhave been read:
-
Letbytesbe thebyte sequencethat results from reading achunkfromblob,or failure if a chunk cannot be read.
-
Queue a global taskon thefile reading task sourcegivenblob’srelevant global objectto perform the following steps:
-
Ifbytesis failure, thenerrorstreamwith afailure reasonand abort these steps.
-
Letchunkbe a new
Uint8Array
wrapping anArrayBuffer
containingbytes.If creating theArrayBuffer
throws an exception, thenerrorstreamwith that exception and abort these steps. -
Enqueuechunkinstream.
-
We need to specify more concretely what reading from a Blob actually does, what possible errors can happen, perhaps something about chunk sizes, etc.
-
-
-
Returnstream.
3.1.Constructors
Blob()
constructor can be invoked with zero or more parameters.
When theBlob()
constructor is invoked,
user agents must run the following steps:
-
If invoked with zero parameters, return a new
Blob
object consisting of 0 bytes, withsize
set to 0, and withtype
set to the empty string. -
Letbytesbe the result ofprocessing blob partsgiven
blobParts
andoptions
. -
If the
type
member of theoptions
argument is not the empty string, run the following sub-steps:-
Lettbe the
type
dictionary member. Iftcontains any characters outside the range U+0020 to U+007E, then settto the empty string and return from these substeps. -
Convert every character inttoASCII lowercase.
-
-
Return a
Blob
object referring tobytesas its associatedbytesequence, with itssize
set to the length ofbytes, and itstype
set to the value oftfrom the substeps above.
3.1.1.Constructor Parameters
TheBlob()
constructor can be invoked with the parameters below:
- A
blobParts
sequence
-
which takes any number of the following types of elements, and in any order:
-
BufferSource
elements. -
Blob
elements. -
USVString
elements.
-
- Anoptional
BlobPropertyBag
-
which takes these optional members:
-
type
, the ASCII-encoded string in lower case representing the media type of theBlob
. Normative conditions for this member are provided in the§ 3.1 Constructors. -
endings
, an enum which can take the values"transparent"
or"native"
. By default this is set to"transparent"
.If set to"native"
,line endings will be converted to nativein anyUSVString
elements inblobParts
.
-
BlobPart
'spartsandBlobPropertyBag
options,
run the following steps:
-
Letbytesbe an empty sequence of bytes.
-
For eachelementinparts:
-
Ifelementis a
USVString
,run the following substeps:-
Letsbeelement.
-
If the
endings
member ofoptionsis"native"
, setsto the result ofconverting line endings to nativeofelement. -
Append the result ofUTF-8 encodingstobytes.
Note:The algorithm from WebIDL[WebIDL]replaces unmatched surrogates in an invalid utf-16 string with U+FFFD replacement characters. Scenarios exist when the
Blob
constructor may result in some data loss due to lost or scrambled character sequences.
-
-
Ifelementis a
BufferSource
,get a copy of the bytes held by the buffer source,and append those bytes tobytes. -
Ifelementis a
Blob
, append the bytes it represents tobytes.Note:The
type
of theBlob
array element is ignored and will not affecttype
of returnedBlob
object.
-
-
Returnbytes.
-
Letnative line endingbe be thecode pointU+000A LF.
-
If the underlying platform’s conventions are to represent newlines as a carriage return and line feed sequence, setnative line endingto thecode pointU+000D CR followed by thecode pointU+000A LF.
-
Setresultto the emptystring.
-
Letpositionbe aposition variablefors, initially pointing at the start ofs.
-
Lettokenbe the result ofcollecting a sequence of code pointsthat are not equal to U+000A LF or U+000D CR fromsgivenposition.
-
Appendtokentoresult.
-
Whilepositionis not past the end ofs:
-
If thecode pointatpositionwithinsequals U+000D CR:
-
Appendnative line endingtoresult.
-
Advancepositionby 1.
-
Ifpositionis not past the end ofsand thecode pointatpositionwithinsequals U+000A LF advancepositionby 1.
-
-
Otherwise if thecode pointatpositionwithinsequals U+000A LF, advancepositionby 1 and appendnative line endingtoresult.
-
Lettokenbe the result ofcollecting a sequence of code pointsthat are not equal to U+000A LF or U+000D CR fromsgivenposition.
-
Appendtokentoresult.
-
-
Returnresult.
// Create a new Blob object var a= new Blob(); // Create a 1024-byte ArrayBuffer // buffer could also come from reading a File var buffer= new ArrayBuffer( 1024 ); // Create ArrayBufferView objects based on buffer var shorts= new Uint16Array( buffer, 512 , 128 ); var bytes= new Uint8Array( buffer, shorts. byteOffset+ shorts. byteLength); var b= new Blob([ "foobarbazetcetc" + "birdiebirdieboo" ], { type: "text/plain;charset=utf-8" }); var c= new Blob([ b, shorts]); var a= new Blob([ b, c, bytes]); var d= new Blob([ buffer, b, c, bytes]);
3.2.Attributes
size
,of typeunsigned long long,readonly- Returns the size of thebytesequence in number of bytes.
On getting, conforming user agents must return the total number of bytes that can be read by a
FileReader
orFileReaderSync
object, or 0 if theBlob
has no bytes to be read. type
,of typeDOMString,readonly-
The ASCII-encoded string in lower case representing the media type of the
Blob
. On getting, user agents must return the type of aBlob
as an ASCII-encoded string in lower case, such that when it is converted to abytesequence, it is aparsable MIME type, or the empty string – 0 bytes – if the type cannot be determined.The
type
attribute can be set by the web application itself through constructor invocation and through theslice()
call; in these cases, further normative conditions for this attribute are in§ 3.1 Constructors,§ 4.1 Constructor, and§ 3.3.1 The slice() methodrespectively. User agents can also determine thetype
of aBlob
, especially if thebytesequence is from an on-disk file; in this case, further normative conditions are in thefile type guidelines.Note:The typetof a
Blob
is considered aparsable MIME type, if performing theparse a MIME typealgorithm to a byte sequence converted from the ASCII-encoded string representing the Blob object’s type does not return failure.Note:Use of the
type
attribute informs thepackage dataalgorithm and determines theContent-Type
header whenfetchingblob URLs.
3.3.Methods and Parameters
3.3.1.Theslice()
method
slice()
method
returns a newBlob
object with bytes ranging from the optionalstartparameter
up to but not including the optionalendparameter, and with atype
attribute
that is the value of the optionalcontentTypeparameter. It must act as follows:
-
LetsliceStart,sliceEnd,andsliceContentTypebe null.
-
Ifstartis given, setsliceStarttostart.
-
Ifendis given, setsliceEndtoend.
-
IfcontentTypeis given, setsliceContentTypetocontentType.
-
Return the result ofslice blobgiventhis,sliceStart,sliceEnd,andsliceContentType.
slice()
calls possible. Since theFile
interface inherits from theBlob
interface, examples are based on the use of theFile
interface.
// obtain input element through DOM var file= document. getElementById( 'file' ). files[ 0 ]; if ( file) { // create an identical copy of file // the two calls below are equivalent var fileClone= file. slice(); var fileClone2= file. slice( 0 , file. size); // slice file into 1/2 chunk starting at middle of file // Note the use of negative number var fileChunkFromEnd= file. slice( - ( Math. round( file. size/ 2 ))); // slice file into 1/2 chunk starting at beginning of file var fileChunkFromStart= file. slice( 0 , Math. round( file. size/ 2 )); // slice file from beginning till 150 bytes before end var fileNoMetadata= file. slice( 0 , - 150 , "application/experimental" ); }
3.3.2.Thestream()
method
Thestream()
method, when invoked, must return
the result of callingget streamonthis.
3.3.3.Thetext()
method
Thetext()
method, when invoked, must run these steps:
-
Letstreambe the result of callingget streamonthis.
-
Letreaderbe the result ofgetting a readerfromstream. If that threw an exception, return a new promise rejected with that exception.
-
Letpromisebe the result ofreading all bytesfromstreamwithreader.
-
Return the result of transformingpromiseby a fulfillment handler that returns the result of runningUTF-8 decodeon its first argument.
Note:This is different from the behavior ofreadAsText()
to align better
with the behavior ofFetch’s text()
.Specifically this method will always
use UTF-8 as encoding, whileFileReader
can use a different encoding depending on
the blob’s type and passed in encoding name.
3.3.4.ThearrayBuffer()
method
ThearrayBuffer()
method, when invoked, must run these steps:
-
Letstreambe the result of callingget streamonthis.
-
Letreaderbe the result ofgetting a readerfromstream. If that threw an exception, return a new promise rejected with that exception.
-
Letpromisebe the result ofreading all bytesfromstreamwithreader.
-
Return the result of transformingpromiseby a fulfillment handler that returns a new
ArrayBuffer
whose contents are its first argument.
3.3.5.Thebytes()
method
Thebytes()
method, when invoked, must run these steps:
-
Letstreambe the result of callingget streamonthis.
-
Letreaderbe the result ofgetting a readerfromstream. If that threw an exception, return a new promise rejected with that exception.
-
Letpromisebe the result ofreading all bytesfromstreamwithreader.
-
Return the result of transformingpromiseby a fulfillment handler that returns a new
Uint8Array
wrapping anArrayBuffer
containing its first argument.
4.The File Interface
AFile
object is aBlob
object with aname
attribute, which is a string;
it can be created within the web application via a constructor,
or is a reference to abytesequence from a file from the underlying (OS) file system.
If aFile
object is a reference to abytesequence originating from a file on disk,
then itssnapshot stateshould be set to the state of the file on disk at the time theFile
object is created.
Note:This is a non-trivial requirement to implement for user agents,
and is thus not amustbut ashould[RFC2119].
User agents should endeavor to have aFile
object’ssnapshot stateset to the state of the underlying storage on disk at the time the reference is taken.
If the file is modified on disk following the time a reference has been taken,
theFile
'ssnapshot statewill differ from the state of the underlying storage.
User agents may use modification time stamps and other mechanisms to maintainsnapshot state,
but this is left as an implementation detail.
When aFile
object refers to a file on disk,
user agents must return thetype
of that file,
and must follow thefile type guidelinesbelow:
-
User agents must return the
type
as an ASCII-encoded string in lower case, such that when it is converted to a corresponding byte sequence, it is aparsable MIME type, or the empty string – 0 bytes – if the type cannot be determined. -
When the file is of type
text/plain
user agents must NOT append a charset parameter to thedictionary of parametersportion of the media type[MIMESNIFF]. -
User agents must not attempt heuristic determination of encoding, including statistical methods.
[Exposed =(Window ,Worker ),Serializable ]interface :
File Blob {(
constructor sequence <BlobPart >fileBits ,USVString fileName ,optional FilePropertyBag = {});
options readonly attribute DOMString name ;readonly attribute long long lastModified ; };dictionary :
FilePropertyBag BlobPropertyBag {long long lastModified ; };
File
objects areserializable objects.Theirserialization steps,
givenvalueandserialized,are:
-
Setserialized.[[SnapshotState]] tovalue’ssnapshot state.
-
Setserialized.[[ByteSequence]] tovalue’s underlying byte sequence.
-
Setserialized.[[Name]] to the value ofvalue’s
name
attribute. -
Setserialized.[[LastModified]] to the value ofvalue’s
lastModified
attribute.
Theirdeserialization steps,givenvalueandserialized,are:
-
Setvalue’ssnapshot statetoserialized.[[SnapshotState]].
-
Setvalue’s underlying byte sequence toserialized.[[ByteSequence]].
-
Initialize the value ofvalue’s
name
attribute toserialized.[[Name]]. -
Initialize the value ofvalue’s
lastModified
attribute toserialized.[[LastModified]].
4.1.Constructor
File
constructor is invoked with two or three parameters,
depending on whether the optional dictionary parameter is used.
When theFile()
constructor is invoked,
user agents must run the following steps:
-
Letbytesbe the result ofprocessing blob partsgiven
fileBits
andoptions
. -
Letnbe the
fileName
argument to the constructor.Note:Underlying OS filesystems use differing conventions for file name; with constructed files, mandating UTF-16 lessens ambiquity when file names are converted tobytesequences.
-
Process
FilePropertyBag
dictionary argument by running the following substeps:-
If the
type
member is provided and is not the empty string, lettbe set to thetype
dictionary member. Iftcontains any characters outside the range U+0020 to U+007E, then settto the empty string and return from these substeps. -
Convert every character inttoASCII lowercase.
-
If the
lastModified
member is provided, letdbe set to thelastModified
dictionary member. If it is not provided, setdto the current date and time represented as the number of milliseconds since theUnix Epoch(which is the equivalent ofDate.now()
[ECMA-262]).Note:Since ECMA-262
Date
objects convert tolong long
values representing the number of milliseconds since theUnix Epoch, thelastModified
member could be aDate
object[ECMA-262].
-
-
Return a new
File
objectFsuch that:-
Frefers to thebytesbytesequence.
-
F.
size
is set to the number of total bytes inbytes. -
F.
name
is set ton. -
F.
type
is set tot. -
F.
lastModified
is set tod.
-
4.1.1.Constructor Parameters
TheFile()
constructor can be invoked with the parameters below:
- A
fileBits
sequence
-
which takes any number of the following elements, and in any order:
-
BufferSource
elements. -
USVString
elements.
-
- A
fileName
parameter - A
USVString
parameter representing the name of the file; normative conditions for this constructor parameter can be found in§ 4.1 Constructor. - An optional
FilePropertyBag
dictionary -
which in addition to themembersof
BlobPropertyBag
takes one member:-
An optional
lastModified
member, which must be along long
; normative conditions for this member are provided in§ 4.1 Constructor.
-
4.2.Attributes
name
,of typeDOMString,readonly- The name of the file.
On getting, this must return the name of the file as a string.
There are numerous file name variations and conventions used by different underlying OS file systems;
this is merely the name of the file, without path information.
On getting, if user agents cannot make this information available,
they must return the empty string.
If a
File
object is created using a constructor, further normative conditions for this attribute are found in§ 4.1 Constructor. lastModified
,of typelong long,readonly- The last modified date of the file.
On getting, if user agents can make this information available,
this must return a
long long
set to the time the file was last modified as the number of milliseconds since theUnix Epoch. If the last modification date and time are not known, the attribute must return the current date and time as along long
representing the number of milliseconds since theUnix Epoch; this is equivalent toDate
[ECMA-262]. If a. now() File
object is created using a constructor, further normative conditions for this attribute are found in§ 4.1 Constructor.
TheFile
interface is available on objects that expose an attribute of typeFileList
;
these objects are defined in HTML[HTML].
TheFile
interface, which inherits fromBlob
,is immutable,
and thus represents file data that can be read into memory at the time aread operationis initiated.
User agents must process reads on files that no longer exist at the time of read aserrors,
throwing aNotFoundError
exception
if using aFileReaderSync
on a Web Worker[Workers]or firing anerror
event
with theerror
attribute returning aNotFoundError
.
var file= document. getElementById( "filePicker" ). files[ 0 ]; var date= new Date( file. lastModified); println( "You selected the file" + file. name+ "which was modified on" + date. toDateString() + "." ); ... // Generate a file with a specific last modified date var d= new Date( 2013 , 12 , 5 , 16 , 23 , 45 , 600 ); var generatedFile= new File([ "Rough Draft...." ], "Draft1.txt" , { type: "text/plain" , lastModified: d}) ...
5.The FileList Interface
Note:TheFileList
interface should be considered "at risk"
since the general trend on the Web Platform is to replace such interfaces
with theArray
platform object in ECMAScript[ECMA-262].
In particular, this means syntax of the sortfilelist
is at risk;
most other programmatic use ofFileList
is unlikely to be affected by the eventual migration to anArray
type.
This interface is a list ofFile
objects.
[Exposed =(Window ,Worker ),Serializable ]interface {
FileList getter File ?item (unsigned long index );readonly attribute unsigned long length ; };
FileList
objects areserializable objects.Theirserialization steps,
givenvalueandserialized,are:
-
Setserialized.[[Files]] to an emptylist.
-
For eachfileinvalue,append thesub-serializationoffiletoserialized.[[Files]].
Theirdeserialization step,givenserializedandvalue,are:
-
For eachfileofserialized.[[Files]], add thesub-deserializationoffiletovalue.
<input type= "file" >
element within a form,
and then accessing selected files.
// uploadData is a form element // fileChooser is input element of type 'file' var file= document. forms[ 'uploadData' ][ 'fileChooser' ]. files[ 0 ]; // alternative syntax can be // var file = document.forms['uploadData']['fileChooser'].files.item(0); if ( file) { // Perform file ops }
5.1.Attributes
length
,of typeunsigned long,readonly- must return the number of files in the
FileList
object. If there are no files, this attribute must return 0.
5.2.Methods and Parameters
item(index)
-
must return theindexth
File
object in theFileList
. If there is noindexthFile
object in theFileList
, then this method must returnnull
.index
must be treated by user agents as value for the position of aFile
object in theFileList
, with 0 representing the first file.Supported property indicesare the numbers in the range zero to one less than the number ofFile
objects represented by theFileList
object. If there are no suchFile
objects, then there are no supported property indices.
Note:TheHTMLInputElement
interface has a readonly attribute of typeFileList
,
which is what is being accessed in the above example.
Other interfaces with a readonly attribute of typeFileList
include theDataTransfer
interface.
6.Reading Data
6.1.The File Reading Task Source
This specification defines a new generictask sourcecalled thefile reading task source,
which is used for alltasks that are queuedin this specification
to read byte sequences associated withBlob
andFile
objects.
It is to be used for features that trigger in response to asynchronously reading binary data.
6.2.TheFileReader
API
[Exposed =(Window ,Worker )]interface :
FileReader EventTarget {constructor (); // async read methodsundefined readAsArrayBuffer (Blob );
blob undefined readAsBinaryString (Blob );
blob undefined readAsText (Blob ,
blob optional DOMString );
encoding undefined readAsDataURL (Blob );
blob undefined abort (); // statesconst unsigned short = 0;
EMPTY const unsigned short = 1;
LOADING const unsigned short = 2;
DONE readonly attribute unsigned short readyState ; // File or Blob datareadonly attribute (DOMString or ArrayBuffer )?result ;readonly attribute DOMException ?error ; // event handler content attributesattribute EventHandler onloadstart ;attribute EventHandler onprogress ;attribute EventHandler onload ;attribute EventHandler onabort ;attribute EventHandler onerror ;attribute EventHandler onloadend ; };
AFileReader
has an associatedstate,
that is"empty"
,"loading"
,or"done"
.It is initially"empty"
.
AFileReader
has an associatedresult(null
,aDOMString
or anArrayBuffer
). It is initiallynull
.
AFileReader
has an associatederror(null
or aDOMException
). It is initiallynull
.
TheFileReader()
constructor,
when invoked, must return a newFileReader
object.
ThereadyState
attribute’s getter,
when invoked, switches onthis'sstateand runs the associated step:
Theresult
attribute’s getter,
when invoked, must returnthis'sresult.
Theerror
attribute’s getter,
when invoked, must returnthis'serror.
FileReader
frhas an associatedread operationalgorithm,
which givenblob,atypeand an optionalencodingName,
runs the following steps:
-
Iffr’sstateis
"loading"
, throw anInvalidStateError
DOMException
. -
Setfr’sstateto
"loading"
. -
Setfr’sresultto
null
. -
Setfr’serrorto
null
. -
Letstreambe the result of callingget streamonblob.
-
Letreaderbe the result ofgetting a readerfromstream.
-
Letbytesbe an emptybyte sequence.
-
LetchunkPromisebe the result ofreading a chunkfromstreamwithreader.
-
LetisFirstChunkbe true.
-
In parallel,while true:
-
Wait forchunkPromiseto be fulfilled or rejected.
-
IfchunkPromiseis fulfilled, andisFirstChunkis true,queue a tasktofire a progress eventcalled
loadstart
atfr.We might change
loadstart
to be dispatched synchronously, to align with XMLHttpRequest behavior.[Issue #119] -
SetisFirstChunkto false.
-
IfchunkPromiseis fulfilled with an object whose
done
property is false and whosevalue
property is aUint8Array
object, run these steps:-
Letbsbe thebyte sequencerepresented by the
Uint8Array
object. -
Appendbstobytes.
-
If roughly 50ms have passed since these steps were last invoked,queue a tasktofire a progress eventcalled
progress
atfr. -
SetchunkPromiseto the result ofreading a chunkfromstreamwithreader.
-
-
Otherwise, ifchunkPromiseis fulfilled with an object whose
done
property is true,queue a taskto run the following steps and abort this algorithm:-
Setfr’sstateto
"done"
. -
Letresultbe the result ofpackage datagivenbytes,type,blob’s
type
,andencodingName. -
Ifpackage datathrew an exceptionerror:
-
Setfr’serrortoerror.
-
Fire a progress eventcalled
error
atfr.
-
-
Else:
-
Setfr’sresulttoresult.
-
Fire a progress eventcalled
load
at thefr.
-
-
Iffr’sstateis not
"loading"
,fire a progress eventcalledloadend
at thefr.Note:Event handler for the
load
orerror
events could have started another load, if that happens theloadend
event for this load is not fired.
-
-
Otherwise, ifchunkPromiseis rejected with an errorerror,queue a taskto run the following steps and abort this algorithm:
-
Setfr’sstateto
"done"
. -
Setfr’serrortoerror.
-
Fire a progress eventcalled
error
atfr. -
Iffr’sstateis not
"loading"
,fire a progress eventcalledloadend
atfr.Note:Event handler for the
error
event could have started another load, if that happens theloadend
event for this load is not fired.
-
-
Use thefile reading task sourcefor all these tasks.
6.2.1.Event Handler Content Attributes
The following are theevent handler content attributes(and their correspondingevent handler event types)
that user agents must support onFileReader
as DOM attributes:
event handler content attribute | event handler event type |
---|---|
onloadstart
| loadstart
|
onprogress
| progress
|
onabort
| abort
|
onerror
| error
|
onload
| load
|
onloadend
| loadend
|
6.2.2.FileReader States
FileReader
object can be in one of 3 states.
ThereadyState
attribute tells you in which state the object is:
EMPTY
(numeric value 0)-
The
FileReader
object has been constructed, and there are no pending reads. None of theread methodshave been called. This is the default state of a newly mintedFileReader
object, until one of theread methodshave been called on it. LOADING
(numeric value 1)-
A
File
orBlob
is being read. One of theread methodsis being processed, and no error has occurred during the read. DONE
(numeric value 2)-
The entire
File
orBlob
has been read into memory, OR afile read erroroccurred, OR the read was aborted usingabort()
. TheFileReader
is no longer reading aFile
orBlob
. IfreadyState
is set toDONE
it means at least one of theread methodshave been called on thisFileReader
.
6.2.3.Reading a File or Blob
TheFileReader
interface makes available severalasynchronous read methods—readAsArrayBuffer()
,readAsBinaryString()
,readAsText()
andreadAsDataURL()
,
which read files into memory.
Note:If multiple concurrent read methods are called on the sameFileReader
object,
user agents throw anInvalidStateError
on any of the read methods that occur
whenreadyState
=LOADING
.
(FileReaderSync
makes available severalsynchronous read methods.
Collectively, the sync and async read methods ofFileReader
andFileReaderSync
are referred to as justread methods.)
6.2.3.1.ThereadAsDataURL()
method
ThereadAsDataURL(blob)
method,
when invoked, must initiate aread operationforblobwithDataURL.
6.2.3.2.ThereadAsText()
method
ThereadAsText(blob,encoding)
method,
when invoked, must initiate aread operationforblobwithTextandencoding.
6.2.3.3.ThereadAsArrayBuffer()
ThereadAsArrayBuffer(blob)
method,
when invoked, must initiate aread operationforblobwithArrayBuffer.
6.2.3.4.ThereadAsBinaryString()
method
ThereadAsBinaryString(blob)
method,
when invoked, must initiate aread operationforblobwithBinaryString.
Note:The use ofreadAsArrayBuffer()
is preferred overreadAsBinaryString()
,which is provided for backwards
compatibility.
6.2.3.5.Theabort()
method
When theabort()
method is called,
the user agent must run the steps below:
-
Ifthis'sstateis
"empty"
or ifthis'sstateis"done"
setthis'sresulttonull
andterminate this algorithm. -
Ifthis'sstateis
"loading"
setthis'sstateto"done"
and setthis'sresulttonull
. -
If there are anytasksfromthison thefile reading task sourcein an affiliatedtask queue, then remove thosetasksfrom that task queue.
-
Terminate the algorithmfor theread methodbeing processed.
-
Fire a progress eventcalled
abort
atthis. -
Ifthis'sstateis not
"loading"
,fire a progress eventcalledloadend
atthis.
6.3.Packaging data
Blob
has an associatedpackage dataalgorithm,
givenbytes,atype,a optionalmimeType,and a optionalencodingName,
which switches ontypeand runs the associated steps:
- DataURL
-
Returnbytesas a DataURL[RFC2397]subject to the considerations below:
-
UsemimeTypeas part of the Data URL if it is available in keeping with the Data URL specification[RFC2397].
-
IfmimeTypeis not available return a Data URL without a media-type.[RFC2397].
Better specify how the DataURL is generated.[Issue #104]
-
- Text
-
-
Letencodingbe failure.
-
If theencodingNameis present, setencodingto the result ofgetting an encodingfromencodingName.
-
Ifencodingis failure, andmimeTypeis present:
-
Lettypebe the result ofparse a MIME typegivenmimeType.
-
Iftypeis not failure, setencodingto the result ofgetting an encodingfromtype’sparameters[
"charset"
].Ifblob
has atype
attribute oftext/plain;charset=utf-8
thengetting an encodingis run using"utf-8"
as the label. Note that user agents must parse and extract the portion of the Charset Parameter that constitutes alabelof an encoding.
-
-
Ifencodingis failure, then setencodingtoUTF-8.
-
Decodebytesusing fallback encodingencoding,and return the result.
-
- ArrayBuffer
-
Return a new
ArrayBuffer
whose contents arebytes. - BinaryString
-
Returnbytesas a binary string, in which every byte is represented by a code unit of equal value [0..255].
6.4.Events
TheFileReader
object must be the event target for all events in this specification.
When this specification says tofire a progress eventcalled e(for someProgressEvent
e
at a givenFileReader
reader
),
the following are normative:
-
The progress event
e
does not bubble.e.bubbles
must be false[DOM] -
The progress event
e
is NOT cancelable.e.cancelable
must be false[DOM]
6.4.1.Event Summary
The following are the events that arefiredatFileReader
objects.
Event name | Interface | Fired when… |
---|---|---|
loadstart
| ProgressEvent
| When the read starts. |
progress
| ProgressEvent
| While reading (and decoding)blob
|
abort
| ProgressEvent
| When the read has been aborted.
For instance, by invoking theabort() method.
|
error
| ProgressEvent
| When the read has failed (seefile read errors). |
load
| ProgressEvent
| When the read has successfully completed. |
loadend
| ProgressEvent
| When the request has completed (either in success or failure). |
6.4.2.Summary of Event Invariants
This section is informative.
The following are invariants applicable toevent firingfor a given asynchronousread methodin this specification:
-
Once a
loadstart
has been fired, a correspondingloadend
fires at completion of the read, UNLESS any of the following are true:-
theread methodhas been cancelled using
abort()
and a newread methodhas been invoked -
the event handler function for a
load
event initiates a new read -
the event handler function for a
error
event initiates a new read.
Note:The events
loadstart
andloadend
are not coupled in a one-to-one manner.This example showcases "read-chaining": initiating another read from within an event handler while the "first" read continues processing.// In code of the sort... reader. readAsText( file); reader. onload= function (){ reader. readAsText( alternateFile);} ..... //... the loadend event must not fire for the first read reader. readAsText( file); reader. abort(); reader. onabort= function (){ reader. readAsText( updatedFile);} //... the loadend event must not fire for the first read -
-
One
progress
event will fire whenblob
has been completely read into memory. -
No
progress
event fires after any one ofabort
,load
,anderror
have fired. At most one ofabort
,load
,anderror
fire for a given read.
6.5.Reading on Threads
Web Workers allow for the use of synchronousFile
orBlob
read APIs,
since such reads on threads do not block the main thread.
This section defines a synchronous API, which can be used within Workers [[Web Workers]].
Workers can avail of both the asynchronous API (theFileReader
object)andthe synchronous API (theFileReaderSync
object).
6.5.1.TheFileReaderSync
API
This interface provides methods tosynchronously readFile
orBlob
objects into memory.
[Exposed =(DedicatedWorker ,SharedWorker )]interface {
FileReaderSync (); // Synchronously return strings
constructor ArrayBuffer readAsArrayBuffer (Blob );
blob DOMString readAsBinaryString (Blob );
blob DOMString readAsText (Blob ,
blob optional DOMString );
encoding DOMString readAsDataURL (Blob ); };
blob
6.5.1.1.Constructors
When theFileReaderSync()
constructor is invoked,
the user agent must return a newFileReaderSync
object.
6.5.1.2.ThereadAsText()
ThereadAsText(blob,encoding)
method,
when invoked, must run these steps:
-
Letstreambe the result of callingget streamonblob.
-
Letreaderbe the result ofgetting a readerfromstream.
-
Letpromisebe the result ofreading all bytesfromstreamwithreader.
-
Wait forpromiseto be fulfilled or rejected.
-
Ifpromisefulfilled with abyte sequencebytes:
-
Return the result ofpackage datagivenbytes,Text,blob’s
type
,andencoding.
-
-
Throwpromise’s rejection reason.
6.5.1.3.ThereadAsDataURL()
method
ThereadAsDataURL(blob)
method,
when invoked, must run these steps:
-
Letstreambe the result of callingget streamonblob.
-
Letreaderbe the result ofgetting a readerfromstream.
-
Letpromisebe the result ofreading all bytesfromstreamwithreader.
-
Wait forpromiseto be fulfilled or rejected.
-
Ifpromisefulfilled with abyte sequencebytes:
-
Return the result ofpackage datagivenbytes,DataURL,andblob’s
type
.
-
-
Throwpromise’s rejection reason.
6.5.1.4.ThereadAsArrayBuffer()
method
ThereadAsArrayBuffer(blob)
method,
when invoked, must run these steps:
-
Letstreambe the result of callingget streamonblob.
-
Letreaderbe the result ofgetting a readerfromstream.
-
Letpromisebe the result ofreading all bytesfromstreamwithreader.
-
Wait forpromiseto be fulfilled or rejected.
-
Ifpromisefulfilled with abyte sequencebytes:
-
Return the result ofpackage datagivenbytes,ArrayBuffer,andblob’s
type
.
-
-
Throwpromise’s rejection reason.
6.5.1.5.ThereadAsBinaryString()
method
ThereadAsBinaryString(blob)
method,
when invoked, must run these steps:
-
Letstreambe the result of callingget streamonblob.
-
Letreaderbe the result ofgetting a readerfromstream.
-
Letpromisebe the result ofreading all bytesfromstreamwithreader.
-
Wait forpromiseto be fulfilled or rejected.
-
Ifpromisefulfilled with abyte sequencebytes:
-
Return the result ofpackage datagivenbytes,BinaryString,andblob’s
type
.
-
-
Throwpromise’s rejection reason.
Note:The use ofreadAsArrayBuffer()
is preferred overreadAsBinaryString()
,which is provided for
backwards compatibility.
7.Errors and Exceptions
File read errorscan occur when reading files from the underlying filesystem. The list below of potential error conditions isinformative.
-
The
File
orBlob
being accessed may not exist at the time one of theasynchronous read methodsorsynchronous read methodsare called. This may be due to it having been moved or deleted after a reference to it was acquired (e.g. concurrent modification with another application). SeeNotFoundError
. -
A
File
orBlob
may be unreadable. This may be due to permission problems that occur after a reference to aFile
orBlob
has been acquired (e.g. concurrent lock with another application). Additionally, thesnapshot statemay have changed. SeeNotReadableError
. -
User agents MAY determine that some files are unsafe for use within Web applications. A file may change on disk since the original file selection, thus resulting in an invalid read. Additionally, some file and directory structures may be considered restricted by the underlying filesystem; attempts to read from them may be considered a security violation. See§ 9 Security and Privacy Considerationsand
SecurityError
.
7.1.Throwing an Exception or Returning an Error
This section is normative.
Error conditions can arise when reading aFile
or aBlob
.
Theread operationcan terminate due to error conditions when reading aFile
or aBlob
;
the particular error condition that causes theget streamalgorithm to fail
is called afailure reason.Afailure reasonis one ofNotFound,UnsafeFile,TooManyReads,SnapshotState,orFileLock.
Synchronous read methodsthrowexceptions of the type in the table below if there has been an error owing to a particularfailure reason.
Asynchronous read methods use theerror
attribute of theFileReader
object,
which must return aDOMException
object of the most appropriate type from the table below
if there has been an error owing to a particularfailure reason,
or otherwise return null.
Type | Description and Failure Reason |
---|---|
NotFoundError
|
If theFile orBlob resource could not be found at the time the read was processed,
this is theNotFoundfailure reason.
For asynchronous read methods the |
SecurityError
|
If:
For asynchronous read methods the This is a security error to be used in situations not covered by any otherfailure reason. |
NotReadableError
|
If:
For asynchronous read methods the |
8.A URL for Blob and MediaSource reference
This section defines aschemefor aURLused to refer toBlob
andMediaSource
objects.
8.1.Introduction
This section is informative.
Blob (or object) URLsare URLs likeblob:http://example.com/550e8400-e29b-41d4-a716-446655440000
.
This enables integration ofBlob
s andMediaSource
s with other
APIs that are only designed to be used with URLs, such as theimg
element.Blob URLscan also be used to navigate to as well as to trigger downloads
of locally generated data.
For this purpose two static methods are exposed on theURL
interface,createObjectURL(obj)
andrevokeObjectURL(url)
.
The first method creates a mapping from aURLto aBlob
,
and the second method revokes said mapping.
As long as the mapping exist theBlob
can’t be garbage collected,
so some care must be taken to revoke the URL as soon as the reference is no longer needed.
All URLs are revoked when the global that created the URL itself goes away.
8.2.Model
Each user agent must maintain ablob URL store. Ablob URL storeis amapwherekeysarevalid URL stringsandvaluesareblob URL Entries.
Ablob URL entryconsists of
anobject(of typeBlob
orMediaSource
),
and anenvironment(anenvironment settings object).
Keysin theblob URL store(also known asblob URLs)
arevalid URL stringsthat whenparsedresult in aURLwith aschemeequal to "blob
",
anempty host,and apathconsisting of one element itself also avalid URL string.
-
Letresultbe the empty string.
-
Append the string "
blob:
"toresult. -
Letsettingsbe thecurrent settings object
-
Letoriginbesettings’sorigin.
-
Letserializedbe theASCII serializationoforigin.
-
Ifserializedis "
null
",set it to an implementation-defined value. -
Appendserializedtoresult.
-
Append U+0024 SOLIDUS (
/
) toresult. -
Generate a UUID[RFC4122]as a string and append it toresult.
-
Returnresult.
blob:https://example.org/40a5fb5a-d56d-4a33-b4e2-0acf6a8e5f64
.-
Letstorebe the user agent’sblob URL store.
-
Leturlbe the result ofgenerating a new blob URL.
-
Letentrybe a newblob URL entryconsisting ofobjectand thecurrent settings object.
-
Setstore[url] toentry.
-
Returnurl.
-
Letstorebe the user agent’sblob URL store;
-
Leturl stringbe the result ofserializingurl.
-
Removestore[url string].
8.3.Dereferencing Model for blob URLs
-
Letstorebe the user agent’sblob URL store.
-
Leturl stringbe the result ofserializingurlwith theexclude fragment flagset.
-
Ifstore[url string]exists,returnstore[url string]; otherwise return failure.
Futher requirements for the parsing and fetching model forblob URLsare defined in the[URL]and[Fetch]specifications.
8.3.1.Origin of blob URLs
This section is informative.
The origin of a blob URL is always the same as that of the environment that created the URL, as long as the URL hasn’t been revoked yet. This is achieved by the[URL]spec looking up the URL in theblob URL storewhen parsing a URL, and using that entry to return the correct origin.
If the URL was revoked the serialization of the origin will still remain the same as the serialization of the origin of the environment that created the blob URL, but for opaque origins the origin itself might be distinct. This difference isn’t observable though, since a revoked blob URL can’t be resolved/fetched anymore anyway.
8.3.2.Lifetime of blob URLs
This specification extends theunloading document cleanup stepswith the following steps:
-
Letenvironmentbe the
Document
'srelevant settings object. -
Letstorebe the user agent’sblob URL store;
-
Remove fromstoreany entries for which thevalue'senvironmentis equal toenvironment.
This needs a similar hook when a worker is unloaded.
8.4.Creating and Revoking a blob URL
Blob URLsare created and revoked using static methods exposed on theURL
object.
Revocation of ablob URLdecouples theblob URLfrom the resource it refers to,
and if it is dereferenced after it is revoked,
user agents must act as if anetwork errorhas occurred.
This section describes a supplemental interface to the URL specification[URL]and presents methods forblob URLcreation and revocation.
[Exposed =(Window ,DedicatedWorker ,SharedWorker )]partial interface URL {static DOMString createObjectURL ((Blob or MediaSource ));
obj static undefined revokeObjectURL (DOMString ); };
url
createObjectURL(obj)
static method must
return the result ofadding an entry to the blob URL storeforobj.revokeObjectURL(url)
static method must run these steps:
-
Leturl recordbe the result ofparsingurl.
-
Ifurl record’sschemeis not "
blob
",return. -
Letoriginbe theoriginofurl record.
-
Letsettingsbe thecurrent settings object.
-
Iforiginis notsame originwithsettings’sorigin,return.
Note:This means that rather than throwing some kind of error, attempting to revoke a URL that isn’t registered will silently fail. User agents might display a message on the error console if this happens.
Note:Attempts to dereferenceurlafter it has been revoked will result in anetwork error. Requests that were started before theurlwas revoked should still succeed.
window1
andwindow2
are separate,
but in thesame origin;window2
could be aniframe
insidewindow1
.
myurl= window1. URL. createObjectURL( myblob); window2. URL. revokeObjectURL( myurl);
Since a user agent has one globalblob URL store,
it is possible to revoke an object URL from a different window than from which it was created.
TheURL.
call
ensures that subsequent dereferencing ofrevokeObjectURL()
myurl
results in a the user agent acting as if anetwork errorhas occurred.
8.4.1.Examples of blob URL Creation and Revocation
Blob URLs are strings that are used tofetchBlob
objects,
and can persist for as long as thedocument
from which they were minted
usingURL.
—createObjectURL()
This section gives sample usage of creation and revocation ofblob URLs with explanations.
img
elements[HTML]refer to the sameblob URL:
url= URL. createObjectURL( blob); img1. src= url; img2. src= url;
URL.revokeObjectURL()
is explicitly called.
var blobURLref= URL. createObjectURL( file); img1= new Image(); img2= new Image(); // Both assignments below work as expected img1. src= blobURLref; img2. src= blobURLref; //... Following body load // Check if both images have loaded if ( img1. complete&& img2. complete) { // Ensure that subsequent refs throw an exception URL. revokeObjectURL( blobURLref); } else { msg( "Images cannot be previewed!" ); // revoke the string-based reference URL. revokeObjectURL( blobURLref); }
The example above allows multiple references to a singleblob URL,
and the web developer then revokes theblob URLstring after both image objects have been loaded.
While not restricting number of uses of theblob URLoffers more flexibility,
it increases the likelihood of leaks;
developers should pair it with a corresponding call toURL.
.revokeObjectURL()
9.Security and Privacy Considerations
This section is informative.
This specification allows web content to read files from the underlying file system,
as well as provides a means for files to be accessed by unique identifiers,
and as such is subject to some security considerations.
This specification also assumes that the primary user interaction is with the<input type= "file" />
element of HTML forms[HTML],
and that all files that are being read byFileReader
objects have first been selected by the user.
Important security considerations include preventing malicious file selection attacks (selection looping),
preventing access to system-sensitive files,
and guarding against modifications of files on disk after a selection has taken place.
- Preventing selection looping
-
During file selection, a user may be bombarded with the file picker associated with
<input type= "file" />
(in a "must choose" loop that forces selection before the file picker is dismissed) and a user agent may prevent file access to any selections by making theFileList
object returned be of size 0. - System-sensitive files
-
(e.g. files in /usr/bin, password files, and other native operating system executables) typically should not be exposed to web content, and should not be accessed viablob URLs. User agents maythrowa
SecurityError
exception for synchronous read methods, or return aSecurityError
exception for asynchronous reads.
This section is provisional; more security data may supplement this in subsequent drafts.
10.Requirements and Use Cases
This section covers what the requirements are for this API, as well as illustrates some use cases. This version of the API does not satisfy all use cases; subsequent versions may elect to address these.
-
Once a user has given permission, user agents should provide the ability to read and parse data directly from a local file programmatically.
-
Data should be able to be stored locally so that it is available for later use, which is useful for offline data access for web applications.
A Calendar App. User’s company has a calendar. User wants to sync local events to company calendar, marked as "busy" slots (without leaking personal info). User browses for file and selects it. Thetext/calendar
file is parsed in the browser, allowing the user to merge the files to one calendar view. The user wants to then save the file back to his local calendar file (using "Save As"?). The user can also send the integrated calendar file back to the server calendar store asynchronously. -
User agents should provide the ability to save a local file programmatically given an amount of data and a file name.
Note:While this specification doesn’t provide an explicit API call to trigger downloads, the HTML5 specification has addressed this. The
download
attribute of thea
element initiates a download, saving aFile
with the name specified. The combination of this API and thedownload
attribute ona
elements allows for the creation of files within web applications, and the ability to save them locally.A Spreadsheet App. User interacts with a form, and generates some input. The form then generates a CSV (Comma Separated Variables) output for the user to import into a spreadsheet, and uses "Save...". The generated output can also be directly integrated into a web-based spreadsheet, and uploaded asynchronously. -
User agents should provide a streamlined programmatic ability to send data from a file to a remote server that works more efficiently than form-based uploads today.
-
User agents should provide an API exposed to script that exposes the features above. The user is notified by UI anytime interaction with the file system takes place, giving the user full ability to cancel or abort the transaction. The user is notified of any file selections, and can cancel these. No invocations to these APIs occur silently without user intervention.
Acknowledgements
This specification was originally developed by the SVG Working Group. Many thanks to Mark Baker and Anne van Kesteren for their feedback.
Thanks to Robin Berjon, Jonas Sicking and Vsevolod Shmyroff for editing the original specification.
Special thanks to Olli Pettay, Nikunj Mehta, Garrett Smith, Aaron Boodman, Michael Nordman, Jian Li, Dmitry Titov, Ian Hickson, Darin Fisher, Sam Weinig, Adrian Bateman and Julian Reschke.
Thanks to the W3C WebApps WG, and to participants on the [email protected] listserv