Search code examples
javascriptajaxfirefox-addonfirefox-addon-restartless

Firefox Addon: Uploading Image


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


Solution

  • 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.