1

I would like to upload an image to a site from a Firefox Addon.

I know I can createElement('canvas'), convert Image data to base64 and XHR POST the data, but I would like to see if it is possible to let Firefox handle it.

Normally, a user will click BROWSE on the site, Firefox will then Open File Upload dialogue, select file, and click OPEN.

I would like to automate that from the context menu so that a local file opened by the browser (ie an image) can be uploaded to the destination directly.

Is that possible and how?

Clarification:

In file selection for upload via Firefox, these are the required data:
- target form
- local file location
- The action attached to the OPEN button in FILE UPLOAD dialogue box

In a context menu situation that I would like to create:
- target form: will be hard-coded in the script
- local file location: the file that is right-clicked (ie gContextMenu.target.src)
- The action: here is what I would like to do and attach 'command' to the function of the above button (the existing Firefox function)

That means, not manually creating new XMLHttpRequest() and POSTing the data, and instead using the existing function of Firefox.

In other words, manually feed the 'target form' & 'local file location' to the OPEN button function of FILE UPLOAD as if that was the process that was executed.

File Upload Dialogue Box

erosman
  • 7,094
  • 7
  • 27
  • 46
  • possible it's possible – Madhawa Priyashantha Jul 14 '14 at 18:22
  • There are multiple ways. Here's one way: (warning this guy's real sloppy) - [upload image binary - using imageshack api ](http://stackoverflow.com/questions/22036442/upload-image-binary-using-imageshack-api) – Blagoh Jul 14 '14 at 19:09
  • Thank you but that guy is using JavaScript, canvs, XHR, which as I mentioned, was not what I was after ;) – erosman Jul 14 '14 at 19:14
  • I think you're going to have to use XHR. The difference is that you want to use FormData. You send FormData as the first agument of XHR `.send()` or `.open()` no need to base64, just use `mozGetAsFile` from canvas. – Blagoh Jul 14 '14 at 19:40
  • Great question man. The solution posted below learned me a lot. – Noitidart Jul 15 '14 at 00:01

1 Answers1

3

Using a DOM File

The DOM File constructor actually accepts plain paths (from privileged code)

var xhr = new XMLHttpRequest();
xhr.open("POST", "http://example.org/");
xhr.setRequestHeader("Content-Type",
                     "application/octet-stream");
xhr.send(new File("/tmp/test.upload"));

This can be combined with form data.

Using an input stream

You can send nsIInputStream. So it is just a matter of knowing the path to a file, then initializing a nsIFileInputStream, a "super-interface" of nsIInputStream and send()ing stuff off with a proper Content-Type.

var {classes: Cc, interfaces: Ci, utils: Cu} = Components;

Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");

var stream = Cc["@mozilla.org/network/file-input-stream;1"].
  createInstance(Ci.nsIFileInputStream);
stream.init(FileUtils.File("/tmp/test.upload"),
            -1, -1,
            Ci.nsIFileInputStream.DEFER_OPEN);
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://example.org/");
xhr.setRequestHeader("Content-Type",
                     "application/octet-stream");
xhr.send(stream);

This can be combined (IIRC) with nsIMultiplexInputStream to construct more complex payloads.

nmaier
  • 32,336
  • 5
  • 63
  • 78
  • Wow very interesting for the DOM `File`, this is available to JSM. But from JSM shouldn't we use `new FileUtils.File`? Will content-type always be `application/octet-stream` for images? Also you IIRC a lot, where are you recalling this from, I would like to go there. – Noitidart Jul 14 '14 at 23:56
  • Ah I think `octet-stream` is set always when using input stream, and with that way we can set `FileUtils.File('/tmp/test.upload')` (how come you didn't do `new FileUtils`?) to any file we want huh? If true this is so awesome man thanks you! – Noitidart Jul 15 '14 at 00:03
  • `var xhr = new XMLHttpRequest();` is not available from JSM scope you have to first import `const XHR = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"];` and then you can do `var xhr = new XHR()` right? – Noitidart Jul 15 '14 at 00:06
  • Great info Nils. Thank you..... I added more clarification to my original question which I hope explains my request. :) – erosman Jul 15 '14 at 04:26
  • I get an error with `xhr.send(new File("file:///C:/...root.png"));` saying `Exception: File error: Unrecognized path` – erosman Jul 16 '14 at 12:11
  • 1
    That's a file URI. You're supposed to just pass it a file path. `.send(new File("C:\\Temp\\test.txt"));` – nmaier Jul 16 '14 at 16:30
  • How do you convert the URI to path? I have a code with `nsIIOService` + `newURI()` + `QueryInterface(Components.interfaces.nsIFileURL)` + file.path` but that seems like a long way. Is there a shorter way? – erosman Jul 16 '14 at 18:44
  • This is getting off-topic quite rapidly. Post another question please. – nmaier Jul 17 '14 at 16:39
  • @erosman and nmair What if i wanted to post other data along wit the image? Like `?data=1&data2=rawr` – Noitidart Oct 30 '14 at 21:26