13

I am trying to upload big files with drag and drop. I have this piece of Javascript code:

xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.setRequestHeader('X-File-Name', file.name);
xhr.setRequestHeader('X-File-Size', file.size);
xhr.setRequestHeader('Content-Type', file.type);
xhr.send(file);

where url is a string of the target url and file is a Blob (according to http://www.w3.org/TR/XMLHttpRequest2/#the-send-method) which I have retrieved after a file drag-drop. This code works in Chrome 12, Safari 5 and Firefox 4 and sends the raw contents of the file in the body of the HTTP request.

However, if the file is big enough the request is never sent. Instead, the XMLHttpRequest object fires and error event (without any useful message). This limit is 86Mb in my environment, but it varies from machine to machine.

The javascript console of Chrome shows the message:

POST http://localhost/xfiles/xfiles.php undefined (undefined)

which has nothing to do with my code (which works perfectly with smaller files).

It seems that the browser reads the entire file in memory and before sending it. Probably there is an out of memory exception or something like that that stops the process. In any case, there no HTTP request is sent, so it is certain that the server's limits have nothing to do with this problem.

Anyway, reading the entire file is a waste of resources.

Is there any method to send the file in a streaming fashion, byte by byte, without having to store it in the memory first?

linepogl
  • 9,147
  • 4
  • 34
  • 45

2 Answers2

10

Try using the Blob.slice method to split the Blob up into multiple chunks, and send each one as a separate request.

Na7coldwater
  • 1,404
  • 12
  • 24
  • I have just finished implementing the solution with Blob.slice and works perfectly even with files of 4GB! Thanks a lot. – linepogl Jun 24 '11 at 15:16
  • 5
    Could you show me an example, how to slice and send blob multiple chunk. Thanks :) – TaeV Jul 03 '12 at 05:40
  • How to send wach one as a separate request? Is it possible with just the same XMLHttpRequest object? Or a new one should be created for every chunk of data? – Green Aug 08 '12 at 22:18
  • I think you have to create a new XMLHttpRequest object for each. Basically, you split the file, send each piece in a separate http request, and piece them back together on the server. – Na7coldwater Aug 14 '12 at 18:39
  • @Na7coldwater How would you identify the communication on the server? A large random string? – user877329 Oct 09 '17 at 07:05
8

Today, with chrome 31 (windows), xhr.send(file) will not read the whole file into memory. The fact is, I try to xhr.send 100mb file and look at task manager for chrome memory usage - it grows only slightly during 100mb file upload.

As a side note, xhr.send(file) fits better for PUT upload, for POST more appropriate would be FormData:

  var formData = new FormData();
  formData.append("thefile", file);
  xhr.send(formData);

Using FormData however, increases upload time by some 50% - probably because of the base64 encoding.

Sandman4
  • 2,673
  • 2
  • 22
  • 18