Replication of Form method with loadOneTab

后端 未结 1 740
猫巷女王i
猫巷女王i 2020-12-11 11:46

If I dynamically insert a form object into a page, submit and remove the form and it works fine.

Here is an example of the form code:

相关标签:
1条回答
  • 2020-12-11 12:30

    Normally, one would use FormData to compose the postData of a request, but unfortunately we cannot do so here, as there is currently no way to get the stream (and other information) from a FormData instance (nsIXHRSendable is not scriptable, unfortunately), so we'll have to create a multipart/form-data stream ourselves.

    Since it is likely you'll want to post some file data as well, I added file uploads as well. ;)

    function encodeFormData(data, charset) {
      let encoder = Cc["@mozilla.org/intl/saveascharset;1"].
                    createInstance(Ci.nsISaveAsCharset);
      encoder.Init(charset || "utf-8",
                   Ci.nsISaveAsCharset.attr_EntityAfterCharsetConv + 
                   Ci.nsISaveAsCharset.attr_FallbackDecimalNCR,
                   0);
      let encode = function(val, header) {
        val = encoder.Convert(val);
        if (header) {
          val = val.replace(/\r\n/g, " ").replace(/"/g, "\\\"");
        }
        return val;
      }
    
      let boundary = "----boundary--" + Date.now();
      let mpis = Cc['@mozilla.org/io/multiplex-input-stream;1'].
                 createInstance(Ci.nsIMultiplexInputStream);
      let item = "";
      for (let k of Object.keys(data)) {
        item += "--" + boundary + "\r\n";
        let v = data[k];
        if (v instanceof Ci.nsIFile) {
          let fstream = Cc["@mozilla.org/network/file-input-stream;1"].
                        createInstance(Ci.nsIFileInputStream); 
          fstream.init(v, -1, -1, Ci.nsIFileInputStream.DEFER_OPEN);
          item += "Content-Disposition: form-data; name=\"" + encode(k, true) + "\";" +
                  " filename=\"" + encode(v.leafName, true) + "\"\r\n";
          let ctype = "application/octet-stream";
          try {
            let mime = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
            ctype = mime.getTypeFromFile(v) || ctype;
          }
          catch (ex) {
            console.warn("failed to get type", ex);
          }
          item += "Content-Type: " + ctype + "\r\n\r\n";
          let ss = Cc["@mozilla.org/io/string-input-stream;1"].
                   createInstance(Ci.nsIStringInputStream);
          ss.data = item;
          mpis.appendStream(ss);
          mpis.appendStream(fstream);
          item = "";
        }
        else {
          item += "Content-Disposition: form-data; name=\"" + encode(k, true) + "\"\r\n\r\n";
          item += encode(v);
        }
        item += "\r\n";
      }
      item += "--" + boundary + "--\r\n";
      let ss = Cc["@mozilla.org/io/string-input-stream;1"].
               createInstance(Ci.nsIStringInputStream);
      ss.data = item;
      mpis.appendStream(ss);
      let postStream = Cc["@mozilla.org/network/mime-input-stream;1"].
                       createInstance(Ci.nsIMIMEInputStream);
      postStream.addHeader("Content-Type",
                           "multipart/form-data; boundary=" + boundary);
      postStream.setData(mpis);
      postStream.addContentLength = true;
      return postStream;
    }
    

    (You could use additional nsIMIMEInputStream instead of string-concatenating stuff together, but this would perform worse and has no real merit).

    Which can then be used like e.g.:

    let file = Services.dirsvc.get("Desk", Ci.nsIFile);
    file.append("australis-xp hällow, wörld.png");
    
    let postData = encodeFormData({
      "filename": "",
      "image_url": "",
      "image_content": "--somne value ---",
      "contents": file
    }, "iso8859-1");
    
    gBrowser.loadOneTab("http://www.example.org/", {
      inBackground: false,
      postData: postData
    });
    
    0 讨论(0)
提交回复
热议问题