mozilla

Compare Revisions

Uploading and Downloading Files

Change Revisions

Revision 69483:

Revision 69483 by andpol on

Revision 308547:

Revision 308547 by Wladimir_Palant on

Title:
Uploading and Downloading Files
Uploading and Downloading Files
Slug:
FileGuide/FileUpDown
FileGuide/FileUpDown
Content:

Revision 69483
Revision 308547
n17      Some web sites allow one to upload a file. This is done by n17      Some web sites allow one to upload a file. This is done by 
>using an HTML &lt;input&gt; element using the <code>file</code> t>using an HTML &lt;input&gt; element using the <code>file</code> t
>ype from within a form. When the user selects a file, it can be u>ype from within a form. When the user selects a file, it can be u
>ploaded to a server. This operation can also be performed via a s>ploaded to a server. This operation can also be performed via a s
>cript using the XMLHttpRequest object. This is a common technique>cript using the XMLHttpRequest object. This is a common technique
> for uploading files as it is compatible with existing servers. H> for uploading files as it is compatible with existing servers an
>owever, this is a fairly complicated method.>d <a href="/en-US/docs/DOM/XMLHttpRequest/FormData" title="/en-US
 >/docs/DOM/XMLHttpRequest/FormData">FormData</a> interface makes t
 >hat task fairly simple.
n20      File upload via a form involves the use of data in a multipn20      A FormData object will automatically generate request data 
>art stream. One part will contain the file data and the other par>with MIME type <code>multipart/form-data</code> that existing ser
>t will contain any other form parameters. However, each part is o>vers can process. To add a file field to the data you use a <a hr
>ptional. Each part is separated with a boundary string which can >ef="/en-US/docs/DOM/File" title="/en-US/docs/DOM/File">File</a> o
>be any string, but should not occur within the file or elsewhere >bject that an extension can construct from file path. The FormDat
>in the data being sent. This allows the host to distinguish where>a object can then simply be passed to XMLHttpRequest:
> each part ends and the next one begins. 
n22    <p>n22    <pre class="brush:js;">
23      For example, the raw data for a typical upload might look l23function upload(postUrl, fieldName, filePath)
>ike the following: 
24    </p>
25    <pre class="eval">
26Content-type: multipart/form-data; boundary=abcd
27Content-length: 20
28--abcd
29Content-Disposition: form-data; name="fieldname"; filename="sampl
>e.txt" 
30Content-type: text/plain
31 
32This is sample text
33 
34--abcd
35</pre>
36    <p>
37      As can be seen, the boundary is specified in the first line
> as 'abcd'. When used on subsequent lines, it is always preceded  
>by two hyphens. The first part after the initial header indicates 
> a file that is being uploaded. The desired filename is specified 
> as 'sample.txt'. The name specified as 'fieldname' corresponds t 
>o the name specified on an HTML input form control if this had be 
>en uploaded from an HTML form. 
38    </p>
39    <p>
40      The content of the file to upload is specified as the body 
>of the part, in this case with the type <code>text/plain</code>.  
>Other content types could be used to upload content of other type 
>s. 
41    </p>
42    <p>
43      You could perform the upload by just writing content like t
>hat above. However, it may be convenient in some cases to use the 
> stream interfaces instead. The following is a sample function wh 
>ich uploads a file given by the first argument, to a url given by 
> the second argument. The name argument is the field name. 
44    </p>
45    <pre class="eval">
46function upload(file, posturl, name)
n48  var boundary = "--------XX" + Math.random();n25  var formData = new FormData();
26  formData.append(fieldName, new File(filePath));
n52  req.setRequestHeader("Content-type", "multipart/form-data; bounn
>dary=" + boundary); 
53  req.setRequestHeader("Content-length", file.fileSize);
54  req.onload = function(event) { alert(event.target.responseText)30  req.onload = function(event) { alert(event.target.responseText)
>; }>; };
55 
56  var prefix = "--" + boundary + "\n" +
57               "Content-Disposition: form-data; name=\"" + name +
> "\"; filename=\"" + 
58               file.leafName + "\"\n" +
59               "Content-type: text/plain\n\n";
60  var stream = IO.newInputStream(prefix, "multi");
61  stream.appendStream(IO.newInputStream(file, ""));
62  stream.appendStream(IO.newInputStream("\n--" + boundary + "\n",
> "")); 
63 
64  req.send(stream);31  req.send(formData);
n66</pre>n
67    <p>
68      When the content is uploaded, the 'onload' handler will dis
>play the response. You would want to alter this portion to perfor 
>m whatever operations are necessary with the response data. 
69    </p>
70    <p>
71      The boundary string is generated from a random number. You 
>can see here that this string is used twice to mark the beginning 
> and end of the file data. Note that in this example, no check is 
> performed to ensure that the boundary string doesn't exist withi 
>n the file. Although unlikely, an error could occur if the bounda 
>ry happened to appear within the file data, so you may wish to re 
>ad the file first. 
72    </p>
73    <p>
74      The interesting aspect of this example is that it uses a mu
>lti stream, to indicate multiple parts of a stream. Here is this  
>portion of the function above. 
75    </p>
76    <pre class="eval">
77var stream = IO.newInputStream(prefix, "multi");
78stream.appendStream(IO.newInputStream(file, ""));
79stream.appendStream(IO.newInputStream("\n--" + boundary + "\n", "
>")); 
80 
81req.send(stream);
82</pre>
83    <p>
84      Three streams are created, one for the data that comes befo
>re the file data, one for the file itself, and the third for the  
>final boundary string. A multi stream is created using the <code> 
>multi</code> flag. A multi stream indicates a stream where additi 
>onal pieces may be appended to it. Each piece will be merged toge 
>ther in sequence, as if all of the pieces were one larger stream. 
> The first stream is read from the 'prefix' string. Each addition 
>al stream is added to the multi stream using {{ ifmethod("nsIMult 
>iplexInputStream","appendStream") }}. The second stream is create 
>d from a file, which was supplied as an argument to the <code>upl 
>oad</code> function. Finally, the third stream is created from a  
>string. The result is sent to the remote host and the streams wil 
>l be read from in sequence as needed. 
85    </p>
86    <p>
87      A multi stream works even though two of the parts are read 
>from a string and one part is read from a file. To the XMLHttpReq 
>uest object, it is as if all of the data was in one stream all al 
>ong. 
88    </p>
89    <p>
90      <br>
91      <strong>Example HTTP POST for multipart/form-data (Using XP
>COM syntax)</strong> 
92    </p>
93    <pre class="eval">
94//Buffer the upload file
95var inStream = Cc["@mozilla.org/network/file-input-stream;1"].cre
>ateInstance(Ci.nsIFileInputStream); 
96inStream.init(nsIFile, 1, 1, inStream.CLOSE_ON_EOF);
97var bufInStream = Cc["@mozilla.org/network/buffered-input-stream;
>1"].createInstance(Ci.nsIBufferedInputStream); 
98bufInStream.init(inStream, 4096);
99 
100//Setup the start Boundery stream
101var boundary = "X-------------X" + Math.random();
102var startBoundaryStream = Cc["@mozilla.org/io/string-input-stream
>;1"].createInstance(Ci.nsIStringInputStream); 
103startBoundaryStream.setData("\r\n--"+boundary+"\r\n", -1);
104 
105//Setup the middle Boundary stream
106var boundaryStream = Cc["@mozilla.org/io/string-input-stream;1"].
>createInstance(Ci.nsIStringInputStream); 
107boundaryStream.setData("\r\n--"+boundary+"\r\n", -1);
108 
109//Setup the end Boundery stream
110var endBoundaryStream = Cc["@mozilla.org/io/string-input-stream;1
>"].createInstance(Ci.nsIStringInputStream); 
111endBoundaryStream.setData("\r\n--"+boundary+"--", -1);
112 
113//Setup the binary data (file upload) mime-stream
114var file_mimeStream = Cc["@mozilla.org/network/mime-input-stream;
>1"].createInstance(Ci.nsIMIMEInputStream); 
115file_mimeStream.addContentLength = false;
116file_mimeStream.addHeader("Content-disposition","form-data; name=
>\"aValue\"; filename=\""+nsIFile.leafName+"\""); 
117file_mimeStream.addHeader("Content-type","application/octet-strea
>m;"); 
118file_mimeStream.setData(bufInStream);
119 
120//Setup the "user" mime-stream
121var user_mimeStream = Cc["@mozilla.org/network/mime-input-stream;
>1"].createInstance(Ci.nsIMIMEInputStream); 
122user_mimeStream.addContentLength = false;
123user_mimeStream.addHeader("Content-disposition", "form-data; name
>=\"user\""); 
124var strStream = Cc["@mozilla.org/io/string-input-stream;1"].creat
>eInstance(Ci.nsIStringInputStream); 
125strStream.setData("SteveJobs", -1);
126user_mimeStream.setData(strStream);
127 
128//Setup the multiplex stream to combine the necessary streams
129var multiStream = Cc["@mozilla.org/io/multiplex-input-stream;1"].
>createInstance(Ci.nsIMultiplexInputStream); 
130multiStream.appendStream(startBoundaryStream);
131multiStream.appendStream(file_mimeStream);
132multiStream.appendStream(boundaryStream);
133multiStream.appendStream(user_mimeStream);
134multiStream.appendStream(endBoundaryStream);
135 
136//Setup the POST request
137var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createIns
>tance(Ci.nsIXMLHttpRequest); 
138req.open("POST", URL_VALUE, false);  //false makes this an asyncr
>onous request 
139req.setRequestHeader("Content-type", "multipart/form-data; bounda
>ry="+boundary); 
140req.setRequestHeader("Content-length", multiStream.available());
141 
142//Send the request (finally!)
143req.send(multiStream); 
144 
t152    <pre class="eval">t40    <pre class="brush:js;">

Back to History