Less Talk, More Do Christopher Finke is a software engineer. He is available for birthday parties and bar mitzvahs.

Posts tagged with 'Mozilla'

Uploading form data and files with JavaScript (Mozilla)

Saturday, January 30th, 2010

One problem I stumble across occasionally in writing Firefox extensions is properly uploading form data that includes a file - that is, assembling the POST request in JavaScript while still maintaining the sanctity of any file or string data. You can't just do this:

var request = "--boundary\r\n some text\r\n--boundary" + fileBytes + "\r\n--boundary--";

I had to spend a bit of time getting this just right in order to allow ScribeFire to upload media to Posterous, so I'm posting below the final solution at which I arrived; it was cobbled together from a dozen different examples I found around the Web (none of them solving the full problem), then lovingly massaged into the elegant function you see before you. With this function, you can pass in an array of fields and files, and the request will be crafted and returned to you, ready for upload.

Instructions for use are in the comment block at the top of the function.

function createPostRequest(args) {
  /**
   * Generates a POST request body for uploading.
   *
   * args is an associative array of the form fields.
   *
   * Example:
   * var args = { "field1": "abc", "field2" : "def", "fileField" :
   *              { "file": theFile, "headers" : [ "X-Fake-Header: foo" ] } };
   *
   * theFile is an nsILocalFile; the headers param for the file field is optional.
   *
   * This function returns an array like this:
   * { "requestBody" : uploadStream, "boundary" : BOUNDARY }
   *
   * To upload:
   *
   * var postRequest = createPostRequest(args);
   * var req = new XMLHttpRequest();
   * req.open("POST", ...);
   * req.setRequestHeader("Content-Type","multipart/form-data; boundary="+postRequest.boundary);
   * req.setRequestHeader("Content-Length", (postRequest.requestBody.available()));
   * req.send(postRequest.requestBody);
   */

  function stringToStream(str) {
    function encodeToUtf8(oStr) {
      var utfStr = oStr;
      var uConv = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"]
                    .createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
      uConv.charset = "UTF-8";
      utfStr = uConv.ConvertFromUnicode(oStr);

      return utfStr;
    }

    str = encodeToUtf8(str);

    var stream = Components.classes["@mozilla.org/io/string-input-stream;1"]
                   .createInstance(Components.interfaces.nsIStringInputStream);
    stream.setData(str, str.length);

    return stream;
  }

  function fileToStream(file) {
    var fpLocal  = Components.classes['@mozilla.org/file/local;1']
                     .createInstance(Components.interfaces.nsILocalFile);
    fpLocal.initWithFile(file);

    var finStream = Components.classes["@mozilla.org/network/file-input-stream;1"]
                      .createInstance(Components.interfaces.nsIFileInputStream);
    finStream.init(fpLocal, 1, 0, false);

    var bufStream = Components.classes["@mozilla.org/network/buffered-input-stream;1"]
                      .createInstance(Components.interfaces.nsIBufferedInputStream);
    bufStream.init(finStream, 9000000);

    return bufStream;
  }

  var mimeSvc = Components.classes["@mozilla.org/mime;1"]
                  .getService(Components.interfaces.nsIMIMEService);
  const BOUNDARY = "---------------------------32191240128944"; 

  var streams = [];

  for (var i in args) {
    var buffer = "--" + BOUNDARY + "\r\n";
    buffer += "Content-Disposition: form-data; name=\"" + i + "\"";
    streams.push(stringToStream(buffer));

    if (typeof args[i] == "object") {
      buffer = "; filename=\"" + args[i].file.leafName + "\"";

      if ("headers" in args[i]) {
        if (args[i].headers.length > 0) {
          for (var q = 0; q < args[i].headers.length; q++){
            buffer += "\r\n" + args[i].headers[q];
          }
        }
      }

      var theMimeType = mimeSvc.getTypeFromFile(args[i].file);

      buffer += "\r\nContent-Type: " + theMimeType;
      buffer += "\r\n\r\n";

      streams.push(stringToStream(buffer));

      streams.push(fileToStream(args[i].file));
    }
    else {
      buffer = "\r\n\r\n";
      buffer += args[i];
      buffer += "\r\n";
      streams.push(stringToStream(buffer));
    }
  }

  var buffer = "--" + BOUNDARY + "--\r\n";
  streams.push(stringToStream(buffer));

  var uploadStream = Components.classes["@mozilla.org/io/multiplex-input-stream;1"]
                       .createInstance(Components.interfaces.nsIMultiplexInputStream);

  for (var i = 0; i < streams.length; i++) {
    uploadStream.appendStream(streams[i]);
  }

  return { "requestBody" : uploadStream, "boundary": BOUNDARY };
}

Netscape is dead; long live Mozilla.

Friday, December 28th, 2007

Tom just posted the official announcement: As of February 1, 2008, Netscape will no longer exist as a product-producing entity.

"AOL's focus on transitioning to an ad-supported web business leaves little room for the size of investment needed to get the Netscape browser to a point many of its fans expect it to be. Given AOL's current business focus and the success the Mozilla Foundation has had in developing critically-acclaimed products, we feel it's the right time to end development of Netscape branded browsers, hand the reigns fully to Mozilla and encourage Netscape users to adopt Firefox."

This means end-of-life for all Netscape desktop applications, including Navigator and Messenger. (The Netscape.com portal will still exist as a co-branded AOL service.)

Hindsight being 20/20, AOL should have made this kind of announcement immediately after the Mozilla foundation was established, rather than pitting Netscape against its former self. This is not to say that I didn't immensely enjoy working on Navigator and Messenger, but I think we can agree that with AOL's massive Web presence, a little support (and advertising) from them might have meant that Internet Explorer might be trying to dethrone Mozilla as the market leader, rather than the other way around.

If you're looking for a job, I bet Mozilla's hiring.

Thursday, October 11th, 2007

Mozilla seems to be having a problem retaining their employees. Last week, the only two developers paid to work on Thunderbird quit, and today Firefox build engineer Paul Reed announced that he's leaving. I wonder what's up...

New Book of Mozilla verse

Tuesday, June 5th, 2007

If you're running Netscape Navigator 9.0, type "about:mozilla" into the address bar to see the newest verse from the Book of Mozilla:

"And thus the Creator looked upon the beast reborn and saw that it was good. -- from The Book of Mozilla, 8:20"

A cookie goes to the first person who can identify the true meaning of the symbolism used therein.