Uploading and Downloading Files

  • Revision slug: FileGuide/FileUpDown
  • Revision title: Uploading and Downloading Files
  • Revision id: 69477
  • Created:
  • Creator: Enn
  • Is current revision? No
  • Comment New page: ==Uploading and Downloading Files== The IO object and stream objects can be used to upload files to servers in various ways. The exact method depends on the type of upload that you wish t...

Revision Content

Uploading and Downloading Files

The IO object and stream objects can be used to upload files to servers in various ways. The exact method depends on the type of upload that you wish to perform.

HTTP File Upload

Some web sites allow one to upload a file. This is done by using an HTML <input> element using the file type from within a form. When the user selects a file, it can be uploaded to a server. This operation can also be performed via a script using the XMLHttpRequest object. This is a common technique for uploading files as it is compatible with existing servers. However, this is a fairly complicated method.

File upload via a form invloves the use of data in a multipart stream. One part will contain the file data and the other part will contain any other form parameters. However, each part is optional. Each part is separated with a boundary string which can be any string, but should not occur within the file or elsewhere in the data being sent. This allows the host to distinguish where each part ends and the next one begins.

For example, the raw data for a typical upload might look like the following:

Content-type: multipart/form-data; boundary=abcd
Content-length: 20
--abcd
Content-Disposition: form-data; name="fieldname"; filename="sample.txt"
Content-type: text/plain

This is sample text

--abcd

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 to the name specified on an HTML input form control if this had been uploaded from an HTML form.

The content of the file to upload is specified as the body of the part, in this case with the type text/plain. Other content types could be used to upload content of other types.

You could perform the upload by just writing content like that above. However, it may be convenient in some cases to use the stream interfaces instead. The following is a sample function which uploads a file given by the first argument, to a url given by the second argument. The name argument is the field name.

function upload(file, posturl, name)
{
  var boundary = "--------XX" + Math.random();

  var req = new XMLHttpRequest();
  req.open("POST", posturl);
  req.setRequestHeader("Content-type", "multipart/form-data; boundary=" + boundary);
  req.setRequestHeader("Content-length", file.fileSize);
  req.onload = function(event) { alert(event.target.responseText); }

  var prefix = "--" + boundary + "\n" +
               "Content-Disposition: form-data; name=\"" + name + "\"; filename=\"" +
               file.leafName + "\"\n" +
               "Content-type: text/plain\n\n";
  var stream = IO.newInputStream(prefix, "multi");
  stream.appendStream(IO.newInputStream(file, ""));
  stream.appendStream(IO.newInputStream("\n--" + boundary + "\n", ""));

  req.send(stream);
}

When the content is uploaded, the 'onload' handler will display the response. You would want to alter this portion to perform whatever operations are necessary with the response data.

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 within the file. Although unlikely, an error could occur if the boundary happened to appear within the file data, so you may wish to read the file first.

The interesting aspect of this example is that it uses a multi stream, to indicate multiple parts of a stream. Here is this portion of the function above.

var stream = IO.newInputStream(prefix, "multi");
stream.appendStream(IO.newInputStream(file, ""));
stream.appendStream(IO.newInputStream("\n--" + boundary + "\n", ""));

req.send(stream);

Three streams are created, one for the data that comes before the file data, one for the file itself, and the third for the final boundary string. A multi stream is created using the multi flag. A multi stream indicates a stream where additional pieces may be appended to it. Each piece will be merged together in sequence, as if all of the pieces were one larger stream. The first stream is read from the 'prefix' string. Each additional stream is added to the multi stream using the appendStream method. The second stream is created from a file, which was supplied as an argument to the upload function. Finally, the third stream is created from a string. The result is sent to the remote host and the streams will be read from in sequence as needed.

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 XMLHttpRequest object, it is as if all of the data was in one stream all along.

HTTP PUT

You can also upload a file using an HTTP PUT operation. This doesn't require the multipart content as above and is much simpler, however web servers usually need special configuration to support PUT operations.

function uploadPut(file, posturl)
{
  var req = new XMLHttpRequest();
  req.open("PUT", posturl);
  req.setRequestHeader("Content-type", "text/plain");
  req.setRequestHeader("Content-length", file.fileSize);
  req.onload = function(event) { alert(event.target.responseText); }

  var stream = IO.newInputStream(file, "");
  req.send(stream);
}

In this example, a new input stream is created for a file, and is passed to the XMLHttpRequest's send method.

Downloading Files

To come...

Revision Source

<h3 name="Uploading_and_Downloading_Files">Uploading and Downloading Files</h3>
<p>The IO object and stream objects can be used to upload files to servers in various ways. The exact method depends on the type of upload that you wish to perform.
</p>
<h4 name="HTTP_File_Upload">HTTP File Upload</h4>
<p>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> type from within a form. When the user selects a file, it can be uploaded to a server. This operation can also be performed via a script using the XMLHttpRequest object. This is a common technique for uploading files as it is compatible with existing servers. However, this is a fairly complicated method.
</p><p>File upload via a form invloves the use of data in a multipart stream. One part will contain the file data and the other part will contain any other form parameters. However, each part is optional. Each part is separated with a boundary string which can be any string, but should not occur within the file or elsewhere in the data being sent. This allows the host to distinguish where each part ends and the next one begins.
</p><p>For example, the raw data for a typical upload might look like the following:
</p>
<pre>Content-type: multipart/form-data; boundary=abcd
Content-length: 20
--abcd
Content-Disposition: form-data; name="fieldname"; filename="sample.txt"
Content-type: text/plain

This is sample text

--abcd
</pre>
<p>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 to the name specified on an HTML input form control if this had been uploaded from an HTML form.
</p><p>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 types.
</p><p>You could perform the upload by just writing content like that above. However, it may be convenient in some cases to use the stream interfaces instead. The following is a sample function which uploads a file given by the first argument, to a url given by the second argument. The name argument is the field name. 
</p>
<pre>function upload(file, posturl, name)
{
  var boundary = "--------XX" + Math.random();

  var req = new XMLHttpRequest();
  req.open("POST", posturl);
  req.setRequestHeader("Content-type", "multipart/form-data; boundary=" + boundary);
  req.setRequestHeader("Content-length", file.fileSize);
  req.onload = function(event) { alert(event.target.responseText); }

  var prefix = "--" + boundary + "\n" +
               "Content-Disposition: form-data; name=\"" + name + "\"; filename=\"" +
               file.leafName + "\"\n" +
               "Content-type: text/plain\n\n";
  var stream = IO.newInputStream(prefix, "multi");
  stream.appendStream(IO.newInputStream(file, ""));
  stream.appendStream(IO.newInputStream("\n--" + boundary + "\n", ""));

  req.send(stream);
}
</pre>
<p>When the content is uploaded, the 'onload' handler will display the response. You would want to alter this portion to perform whatever operations are necessary with the response data.
</p><p>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 within the file. Although unlikely, an error could occur if the boundary happened to appear within the file data, so you may wish to read the file first.
</p><p>The interesting aspect of this example is that it uses a multi stream, to indicate multiple parts of a stream. Here is this portion of the function above.
</p>
<pre>var stream = IO.newInputStream(prefix, "multi");
stream.appendStream(IO.newInputStream(file, ""));
stream.appendStream(IO.newInputStream("\n--" + boundary + "\n", ""));

req.send(stream);
</pre>
<p>Three streams are created, one for the data that comes before 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 additional pieces may be appended to it. Each piece will be merged together in sequence, as if all of the pieces were one larger stream. The first stream is read from the 'prefix' string. Each additional stream is added to the multi stream using the <a href="en/NsIMultiplexInputStream.appendStream">appendStream</a> method. The second stream is created from a file, which was supplied as an argument to the <code>upload</code> function. Finally, the third stream is created from a string. The result is sent to the remote host and the streams will be read from in sequence as needed.
</p><p>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 XMLHttpRequest object, it is as if all of the data was in one stream all along.
</p>
<h4 name="HTTP_PUT">HTTP PUT</h4>
<p>You can also upload a file using an HTTP PUT operation. This doesn't require the multipart content as above and is much simpler, however web servers usually need special configuration to support PUT operations.
</p>
<pre>function uploadPut(file, posturl)
{
  var req = new XMLHttpRequest();
  req.open("PUT", posturl);
  req.setRequestHeader("Content-type", "text/plain");
  req.setRequestHeader("Content-length", file.fileSize);
  req.onload = function(event) { alert(event.target.responseText); }

  var stream = IO.newInputStream(file, "");
  req.send(stream);
}
</pre>
<p>In this example, a new input stream is created for a file, and is passed to the XMLHttpRequest's <code>send</code> method.
</p>
<h4 name="Downloading_Files">Downloading Files</h4>
<p>To come...
</p>
Revert to this revision