如果我将表单对象动态地插入到页面中,请提交并删除该表单,它可以正常工作。
这是表单代码的示例:
<form target="_blank" enctype="multipart/form-data"
action="https://www.example.com/" method="POST">
<input value="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" name="image_content" type="hidden">
<input value="" name="filename" type="hidden">
<input value="" name="image_url" type="hidden">
</form>
当我尝试对
loadOneTab()
执行相同的过程时,结果POST
并不完全相同,因此结果与上面的结果不同。在检查标题时,“某些值”未完全发送(被裁剪),并且设置了
Content-Length: 0
。我肯定错过了什么。
let postStream = Components.classes['@mozilla.org/network/mime-input-stream;1']
.createInstance(Components.interfaces.nsIMIMEInputStream);
postStream.addHeader('Content-Type', 'multipart/form-data');
postStream.addHeader('filename', '');
postStream.addHeader('image_url', '');
postStream.addHeader('image_content', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==');
postStream.addContentLength = true;
window.gBrowser.loadOneTab('https://www.example.com/',
{inBackground: false, postData: postStream});
注意:image_content值为'data:image / png; base64'数据URI
NoScript导致发送表单和XSS的问题,我更喜欢对
loadOneTab
使用inBackground
最佳答案
通常,人们会使用FormData
来组成请求的postData
,但不幸的是,我们无法在此处这样做,因为当前无法从FormData
实例(不能编写脚本),因此我们必须自己创建一个nsIXHRSendable
流。
由于您可能还希望发布一些文件数据,因此我还添加了文件上传功能。 ;)
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;
}
(您可以使用其他
multipart/form-data
而不是将字符串串联在一起,但这会导致性能更差并且没有真正的优点)。然后可以像这样使用:
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
});