зеркало из https://github.com/mozilla/gecko-dev.git
bug 539843 - Need a mechanism for plugin crashed UI to trigger crash report submission. r=dtownsend
--HG-- rename : toolkit/crashreporter/content/crashes.js => toolkit/crashreporter/CrashSubmit.jsm
This commit is contained in:
Родитель
2a33518c3c
Коммит
38218420d5
|
@ -0,0 +1,366 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Ted Mielczarek <ted.mielczarek@gmail.com> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
let EXPORTED_SYMBOLS = [
|
||||
"CrashSubmit"
|
||||
];
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const STATE_START = Ci.nsIWebProgressListener.STATE_START;
|
||||
const STATE_STOP = Ci.nsIWebProgressListener.STATE_STOP;
|
||||
|
||||
let reportURL = null;
|
||||
let strings = null;
|
||||
let myListener = null;
|
||||
|
||||
function parseKeyValuePairs(text) {
|
||||
var lines = text.split('\n');
|
||||
var data = {};
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
if (lines[i] == '')
|
||||
continue;
|
||||
|
||||
// can't just .split() because the value might contain = characters
|
||||
let eq = lines[i].indexOf('=');
|
||||
if (eq != -1) {
|
||||
let [key, value] = [lines[i].substring(0, eq),
|
||||
lines[i].substring(eq + 1)];
|
||||
if (key && value)
|
||||
data[key] = value.replace("\\n", "\n", "g").replace("\\\\", "\\", "g");
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
function parseKeyValuePairsFromFile(file) {
|
||||
var fstream = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Ci.nsIFileInputStream);
|
||||
fstream.init(file, -1, 0, 0);
|
||||
var is = Cc["@mozilla.org/intl/converter-input-stream;1"].
|
||||
createInstance(Ci.nsIConverterInputStream);
|
||||
is.init(fstream, "UTF-8", 1024, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
|
||||
var str = {};
|
||||
var contents = '';
|
||||
while (is.readString(4096, str) != 0) {
|
||||
contents += str.value;
|
||||
}
|
||||
is.close();
|
||||
fstream.close();
|
||||
return parseKeyValuePairs(contents);
|
||||
}
|
||||
|
||||
function parseINIStrings(file) {
|
||||
var factory = Cc["@mozilla.org/xpcom/ini-parser-factory;1"].
|
||||
getService(Ci.nsIINIParserFactory);
|
||||
var parser = factory.createINIParser(file);
|
||||
var obj = {};
|
||||
var en = parser.getKeys("Strings");
|
||||
while (en.hasMore()) {
|
||||
var key = en.getNext();
|
||||
obj[key] = parser.getString("Strings", key);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Since we're basically re-implementing part of the crashreporter
|
||||
// client here, we'll just steal the strings we need from crashreporter.ini
|
||||
function getL10nStrings() {
|
||||
let dirSvc = Cc["@mozilla.org/file/directory_service;1"].
|
||||
getService(Ci.nsIProperties);
|
||||
let path = dirSvc.get("GreD", Ci.nsIFile);
|
||||
path.append("crashreporter.ini");
|
||||
if (!path.exists()) {
|
||||
// see if we're on a mac
|
||||
path = path.parent;
|
||||
path.append("crashreporter.app");
|
||||
path.append("Contents");
|
||||
path.append("MacOS");
|
||||
path.append("crashreporter.ini");
|
||||
if (!path.exists()) {
|
||||
// very bad, but I don't know how to recover
|
||||
return;
|
||||
}
|
||||
}
|
||||
let crstrings = parseINIStrings(path);
|
||||
strings = {
|
||||
'crashid': crstrings.CrashID,
|
||||
'reporturl': crstrings.CrashDetailsURL
|
||||
};
|
||||
|
||||
path = dirSvc.get("XCurProcD", Ci.nsIFile);
|
||||
path.append("crashreporter-override.ini");
|
||||
if (path.exists()) {
|
||||
crstrings = parseINIStrings(path);
|
||||
if ('CrashID' in crstrings)
|
||||
strings['crashid'] = crstrings.CrashID;
|
||||
if ('CrashDetailsURL' in crstrings)
|
||||
strings['reporturl'] = crstrings.CrashDetailsURL;
|
||||
}
|
||||
}
|
||||
|
||||
function getPendingMinidump(id) {
|
||||
let directoryService = Cc["@mozilla.org/file/directory_service;1"].
|
||||
getService(Ci.nsIProperties);
|
||||
let pendingDir = directoryService.get("UAppData", Ci.nsIFile);
|
||||
pendingDir.append("Crash Reports");
|
||||
pendingDir.append("pending");
|
||||
let dump = pendingDir.clone();
|
||||
let extra = pendingDir.clone();
|
||||
dump.append(id + ".dmp");
|
||||
extra.append(id + ".extra");
|
||||
return [dump, extra];
|
||||
}
|
||||
|
||||
function addFormEntry(doc, form, name, value) {
|
||||
var input = doc.createElement("input");
|
||||
input.type = "hidden";
|
||||
input.name = name;
|
||||
input.value = value;
|
||||
form.appendChild(input);
|
||||
}
|
||||
|
||||
function writeSubmittedReport(crashID, viewURL) {
|
||||
let directoryService = Cc["@mozilla.org/file/directory_service;1"].
|
||||
getService(Ci.nsIProperties);
|
||||
let reportFile = directoryService.get("UAppData", Ci.nsIFile);
|
||||
reportFile.append("Crash Reports");
|
||||
reportFile.append("submitted");
|
||||
reportFile.append(crashID + ".txt");
|
||||
var fstream = Cc["@mozilla.org/network/file-output-stream;1"].
|
||||
createInstance(Ci.nsIFileOutputStream);
|
||||
// open, write, truncate
|
||||
fstream.init(reportFile, -1, -1, 0);
|
||||
var os = Cc["@mozilla.org/intl/converter-output-stream;1"].
|
||||
createInstance(Ci.nsIConverterOutputStream);
|
||||
os.init(fstream, "UTF-8", 0, 0x0000);
|
||||
|
||||
var data = strings.crashid.replace("%s", crashID);
|
||||
if (viewURL)
|
||||
data += "\n" + strings.reporturl.replace("%s", viewURL);
|
||||
|
||||
os.writeString(data);
|
||||
os.close();
|
||||
fstream.close();
|
||||
}
|
||||
|
||||
// the Submitter class represents an individual submission.
|
||||
function Submitter(id, element, submitSuccess, submitError) {
|
||||
this.id = id;
|
||||
this.element = element;
|
||||
this.document = element.ownerDocument;
|
||||
this.successCallback = submitSuccess;
|
||||
this.errorCallback = submitError;
|
||||
}
|
||||
|
||||
Submitter.prototype = {
|
||||
submitSuccess: function Submitter_submitSuccess(ret)
|
||||
{
|
||||
if (!ret.CrashID) {
|
||||
this.cleanup();
|
||||
return;
|
||||
}
|
||||
|
||||
// Write out the details file to submitted/
|
||||
writeSubmittedReport(ret.CrashID, ret.ViewURL);
|
||||
|
||||
// Delete from pending dir
|
||||
try {
|
||||
this.dump.remove(false);
|
||||
this.extra.remove(false);
|
||||
}
|
||||
catch (ex) {
|
||||
// report an error? not much the user can do here.
|
||||
}
|
||||
|
||||
if (this.successCallback)
|
||||
this.successCallback(this.id, ret);
|
||||
this.cleanup();
|
||||
},
|
||||
|
||||
cleanup: function Submitter_cleanup() {
|
||||
// drop some references just to be nice
|
||||
this.element = null;
|
||||
this.document = null;
|
||||
this.successCallback = null;
|
||||
this.errorCallback = null;
|
||||
this.iframe = null;
|
||||
this.dump = null;
|
||||
this.extra = null;
|
||||
// remove this object from the list of active submissions
|
||||
let idx = CrashSubmit._activeSubmissions.indexOf(this);
|
||||
if (idx != -1)
|
||||
CrashSubmit._activeSubmissions.splice(idx, 1);
|
||||
},
|
||||
|
||||
submitForm: function Submitter_submitForm()
|
||||
{
|
||||
let reportData = parseKeyValuePairsFromFile(this.extra);
|
||||
let form = this.iframe.contentDocument.forms[0];
|
||||
if ('ServerURL' in reportData) {
|
||||
form.action = reportData.ServerURL;
|
||||
delete reportData.ServerURL;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
// add the other data
|
||||
for (let [name, value] in Iterator(reportData)) {
|
||||
addFormEntry(this.iframe.contentDocument, form, name, value);
|
||||
}
|
||||
// tell the server not to throttle this, since it was manually submitted
|
||||
addFormEntry(this.iframe.contentDocument, form, "Throttleable", "0");
|
||||
// add the minidump
|
||||
this.iframe.contentDocument.getElementById('minidump').value
|
||||
= this.dump.path;
|
||||
this.iframe.docShell.QueryInterface(Ci.nsIWebProgress);
|
||||
this.iframe.docShell.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
|
||||
form.submit();
|
||||
return true;
|
||||
},
|
||||
|
||||
// web progress listener
|
||||
QueryInterface: function(aIID)
|
||||
{
|
||||
if (aIID.equals(Ci.nsIWebProgressListener) ||
|
||||
aIID.equals(Ci.nsISupportsWeakReference) ||
|
||||
aIID.equals(Ci.nsISupports))
|
||||
return this;
|
||||
throw Components.results.NS_NOINTERFACE;
|
||||
},
|
||||
|
||||
onStateChange: function(aWebProgress, aRequest, aFlag, aStatus)
|
||||
{
|
||||
if(aFlag & STATE_STOP) {
|
||||
this.iframe.docShell.removeProgressListener(this);
|
||||
|
||||
// check general request status first
|
||||
if (!Components.isSuccessCode(aStatus)) {
|
||||
this.element.removeChild(this.iframe);
|
||||
if (this.errorCallback) {
|
||||
this.errorCallback(this.id);
|
||||
this.cleanup();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
// check HTTP status
|
||||
if (aRequest instanceof Ci.nsIHttpChannel &&
|
||||
aRequest.responseStatus != 200) {
|
||||
this.element.removeChild(this.iframe);
|
||||
if (this.errorCallback) {
|
||||
this.errorCallback(this.id);
|
||||
this.cleanup();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
var ret = parseKeyValuePairs(this.iframe.contentDocument.documentElement.textContent);
|
||||
this.element.removeChild(this.iframe);
|
||||
this.submitSuccess(ret);
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
|
||||
onLocationChange: function(aProgress, aRequest, aURI) {return 0;},
|
||||
onProgressChange: function() {return 0;},
|
||||
onStatusChange: function() {return 0;},
|
||||
onSecurityChange: function() {return 0;},
|
||||
|
||||
submit: function Submitter_submit()
|
||||
{
|
||||
let [dump, extra] = getPendingMinidump(this.id);
|
||||
if (!dump.exists() || !extra.exists())
|
||||
return false;
|
||||
this.dump = dump;
|
||||
this.extra = extra;
|
||||
let iframe = this.document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "iframe");
|
||||
iframe.setAttribute("type", "content");
|
||||
|
||||
let self = this;
|
||||
function loadHandler() {
|
||||
if (iframe.contentWindow.location == "about:blank")
|
||||
return;
|
||||
iframe.removeEventListener("load", loadHandler, true);
|
||||
self.submitForm();
|
||||
}
|
||||
|
||||
iframe.addEventListener("load", loadHandler, true);
|
||||
this.element.appendChild(iframe);
|
||||
this.iframe = iframe;
|
||||
iframe.webNavigation.loadURI("chrome://global/content/crash-submit-form.xhtml", 0, null, null, null);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
//===================================
|
||||
// External API goes here
|
||||
let CrashSubmit = {
|
||||
/**
|
||||
* Submit the crash report named id.dmp from the "pending" directory.
|
||||
*
|
||||
* @param id
|
||||
* Filename (minus .dmp extension) of the minidump to submit.
|
||||
* @param element
|
||||
* A DOM element to which an iframe can be appended as a child,
|
||||
* used for form submission.
|
||||
* @param submitSuccess
|
||||
* A function that will be called if the report is submitted
|
||||
* successfully with two parameters: the id that was passed
|
||||
* to this function, and an object containing the key/value
|
||||
* data returned from the server in its properties.
|
||||
* @param submitError
|
||||
* A function that will be called with one parameter if the
|
||||
* report fails to submit: the id that was passed to this
|
||||
* function.
|
||||
*
|
||||
* @return true if the submission began successfully, or false if
|
||||
* it failed for some reason. (If the dump file does not
|
||||
* exist, for example.)
|
||||
*/
|
||||
submit: function CrashSubmit_submit(id, element, submitSuccess, submitError)
|
||||
{
|
||||
let submitter = new Submitter(id, element, submitSuccess, submitError);
|
||||
CrashSubmit._activeSubmissions.push(submitter);
|
||||
return submitter.submit();
|
||||
},
|
||||
|
||||
// List of currently active submit objects
|
||||
_activeSubmissions: []
|
||||
};
|
||||
|
||||
// Run this when first loaded
|
||||
getL10nStrings();
|
|
@ -111,6 +111,10 @@ CPPSRCS = \
|
|||
|
||||
FORCE_STATIC_LIB = 1
|
||||
|
||||
EXTRA_JS_MODULES = \
|
||||
CrashSubmit.jsm \
|
||||
$(NULL)
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
TOOL_DIRS = test
|
||||
endif
|
||||
|
|
|
@ -1,150 +1,52 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dave Townsend <dtownsend@oxymoronical> (original author)
|
||||
* Ted Mielczarek <ted.mielczarek@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
var reportURL = null;
|
||||
var reportsDir, pendingDir;
|
||||
var strings = null;
|
||||
var myListener = null;
|
||||
|
||||
function parseKeyValuePairs(text) {
|
||||
var lines = text.split('\n');
|
||||
var data = {};
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
if (lines[i] == '')
|
||||
continue;
|
||||
|
||||
// can't just .split() because the value might contain = characters
|
||||
let eq = lines[i].indexOf('=');
|
||||
if (eq != -1) {
|
||||
let [key, value] = [lines[i].substring(0, eq),
|
||||
lines[i].substring(eq + 1)];
|
||||
if (key && value)
|
||||
data[key] = value.replace("\\n", "\n", "g").replace("\\\\", "\\", "g");
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
function parseKeyValuePairsFromFile(file) {
|
||||
var fstream = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Ci.nsIFileInputStream);
|
||||
fstream.init(file, -1, 0, 0);
|
||||
var is = Cc["@mozilla.org/intl/converter-input-stream;1"].
|
||||
createInstance(Ci.nsIConverterInputStream);
|
||||
is.init(fstream, "UTF-8", 1024, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
|
||||
var str = {};
|
||||
var contents = '';
|
||||
while (is.readString(4096, str) != 0) {
|
||||
contents += str.value;
|
||||
}
|
||||
is.close();
|
||||
fstream.close();
|
||||
return parseKeyValuePairs(contents);
|
||||
}
|
||||
|
||||
function parseINIStrings(file) {
|
||||
var factory = Cc["@mozilla.org/xpcom/ini-parser-factory;1"].
|
||||
getService(Ci.nsIINIParserFactory);
|
||||
var parser = factory.createINIParser(file);
|
||||
var obj = {};
|
||||
var en = parser.getKeys("Strings");
|
||||
while (en.hasMore()) {
|
||||
var key = en.getNext();
|
||||
obj[key] = parser.getString("Strings", key);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Since we're basically re-implementing part of the crashreporter
|
||||
// client here, we'll just steal the strings we need from crashreporter.ini
|
||||
function getL10nStrings() {
|
||||
let dirSvc = Cc["@mozilla.org/file/directory_service;1"].
|
||||
getService(Ci.nsIProperties);
|
||||
let path = dirSvc.get("GreD", Ci.nsIFile);
|
||||
path.append("crashreporter.ini");
|
||||
if (!path.exists()) {
|
||||
// see if we're on a mac
|
||||
path = path.parent;
|
||||
path.append("crashreporter.app");
|
||||
path.append("Contents");
|
||||
path.append("MacOS");
|
||||
path.append("crashreporter.ini");
|
||||
if (!path.exists()) {
|
||||
// very bad, but I don't know how to recover
|
||||
return;
|
||||
}
|
||||
}
|
||||
let crstrings = parseINIStrings(path);
|
||||
strings = {
|
||||
'crashid': crstrings.CrashID,
|
||||
'reporturl': crstrings.CrashDetailsURL
|
||||
};
|
||||
|
||||
path = dirSvc.get("XCurProcD", Ci.nsIFile);
|
||||
path.append("crashreporter-override.ini");
|
||||
if (path.exists()) {
|
||||
crstrings = parseINIStrings(path);
|
||||
if ('CrashID' in crstrings)
|
||||
strings['crashid'] = crstrings.CrashID;
|
||||
if ('CrashDetailsURL' in crstrings)
|
||||
strings['reporturl'] = crstrings.CrashDetailsURL;
|
||||
}
|
||||
}
|
||||
|
||||
function getPendingMinidump(id) {
|
||||
let directoryService = Cc["@mozilla.org/file/directory_service;1"].
|
||||
getService(Ci.nsIProperties);
|
||||
let dump = pendingDir.clone();
|
||||
let extra = pendingDir.clone();
|
||||
dump.append(id + ".dmp");
|
||||
extra.append(id + ".extra");
|
||||
return [dump, extra];
|
||||
}
|
||||
|
||||
function addFormEntry(doc, form, name, value) {
|
||||
var input = doc.createElement("input");
|
||||
input.type = "hidden";
|
||||
input.name = name;
|
||||
input.value = value;
|
||||
form.appendChild(input);
|
||||
}
|
||||
|
||||
function writeSubmittedReport(crashID, viewURL) {
|
||||
let reportFile = reportsDir.clone();
|
||||
reportFile.append(crashID + ".txt");
|
||||
var fstream = Cc["@mozilla.org/network/file-output-stream;1"].
|
||||
createInstance(Ci.nsIFileOutputStream);
|
||||
// open, write, truncate
|
||||
fstream.init(reportFile, -1, -1, 0);
|
||||
var os = Cc["@mozilla.org/intl/converter-output-stream;1"].
|
||||
createInstance(Ci.nsIConverterOutputStream);
|
||||
os.init(fstream, "UTF-8", 0, 0x0000);
|
||||
|
||||
var data = strings.crashid.replace("%s", crashID);
|
||||
if (viewURL)
|
||||
data += "\n" + strings.reporturl.replace("%s", viewURL);
|
||||
|
||||
os.writeString(data);
|
||||
os.close();
|
||||
fstream.close();
|
||||
}
|
||||
|
||||
function submitSuccess(ret, link, dump, extra) {
|
||||
if (!ret.CrashID)
|
||||
return;
|
||||
// Write out the details file to submitted/
|
||||
writeSubmittedReport(ret.CrashID, ret.ViewURL);
|
||||
|
||||
// Delete from pending dir
|
||||
try {
|
||||
dump.remove(false);
|
||||
extra.remove(false);
|
||||
}
|
||||
catch (ex) {
|
||||
// report an error? not much the user can do here.
|
||||
}
|
||||
Components.utils.import("resource://gre/modules/CrashSubmit.jsm");
|
||||
|
||||
function submitSuccess(dumpid, ret) {
|
||||
let link = document.getElementById(dumpid);
|
||||
if (link) {
|
||||
link.className = "";
|
||||
// reset the link to point at our new crash report. this way, if the
|
||||
// user clicks "Back", the link will be correct.
|
||||
let CrashID = ret.CrashID;
|
||||
|
@ -158,105 +60,23 @@ function submitSuccess(ret, link, dump, extra) {
|
|||
window.location.href = reportURL + CrashID;
|
||||
}
|
||||
}
|
||||
else {
|
||||
window.close();
|
||||
}
|
||||
}
|
||||
|
||||
function submitForm(iframe, dump, extra, link)
|
||||
{
|
||||
let reportData = parseKeyValuePairsFromFile(extra);
|
||||
let form = iframe.contentDocument.forms[0];
|
||||
if ('ServerURL' in reportData) {
|
||||
form.action = reportData.ServerURL;
|
||||
delete reportData.ServerURL;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
// add the other data
|
||||
for (let [name, value] in Iterator(reportData)) {
|
||||
addFormEntry(iframe.contentDocument, form, name, value);
|
||||
}
|
||||
// tell the server not to throttle this, since it was manually submitted
|
||||
addFormEntry(iframe.contentDocument, form, "Throttleable", "0");
|
||||
// add the minidump
|
||||
iframe.contentDocument.getElementById('minidump').value = dump.path;
|
||||
|
||||
// web progress listener
|
||||
const STATE_START = Ci.nsIWebProgressListener.STATE_START;
|
||||
const STATE_STOP = Ci.nsIWebProgressListener.STATE_STOP;
|
||||
myListener = {
|
||||
QueryInterface: function(aIID) {
|
||||
if (aIID.equals(Ci.nsIWebProgressListener) ||
|
||||
aIID.equals(Ci.nsISupportsWeakReference) ||
|
||||
aIID.equals(Ci.nsISupports))
|
||||
return this;
|
||||
throw Components.results.NS_NOINTERFACE;
|
||||
},
|
||||
|
||||
onStateChange: function(aWebProgress, aRequest, aFlag, aStatus) {
|
||||
if(aFlag & STATE_STOP) {
|
||||
iframe.docShell.removeProgressListener(myListener);
|
||||
myListener = null;
|
||||
if (link)
|
||||
link.className = "";
|
||||
|
||||
//XXX: give some indication of failure?
|
||||
// check general request status first
|
||||
if (!Components.isSuccessCode(aStatus)) {
|
||||
document.body.removeChild(iframe);
|
||||
return 0;
|
||||
}
|
||||
// check HTTP status
|
||||
if (aRequest instanceof Ci.nsIHttpChannel &&
|
||||
aRequest.responseStatus != 200) {
|
||||
document.body.removeChild(iframe);
|
||||
return 0;
|
||||
}
|
||||
|
||||
var ret = parseKeyValuePairs(iframe.contentDocument.documentElement.textContent);
|
||||
document.body.removeChild(iframe);
|
||||
submitSuccess(ret, link, dump, extra);
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
|
||||
onLocationChange: function(aProgress, aRequest, aURI) {return 0;},
|
||||
onProgressChange: function() {return 0;},
|
||||
onStatusChange: function() {return 0;},
|
||||
onSecurityChange: function() {return 0;},
|
||||
};
|
||||
iframe.docShell.QueryInterface(Ci.nsIWebProgress);
|
||||
iframe.docShell.addProgressListener(myListener, Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
|
||||
form.submit();
|
||||
return true;
|
||||
}
|
||||
|
||||
function createAndSubmitForm(id, link) {
|
||||
let [dump, extra] = getPendingMinidump(id);
|
||||
if (!dump.exists() || !extra.exists())
|
||||
return false;
|
||||
let iframe = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "iframe");
|
||||
iframe.setAttribute("type", "content");
|
||||
|
||||
function loadHandler() {
|
||||
if (iframe.contentWindow.location == "about:blank")
|
||||
return;
|
||||
iframe.removeEventListener("load", loadHandler, true);
|
||||
submitForm(iframe, dump, extra, link);
|
||||
}
|
||||
|
||||
iframe.addEventListener("load", loadHandler, true);
|
||||
document.body.appendChild(iframe);
|
||||
iframe.webNavigation.loadURI("chrome://global/content/crash-submit-form.xhtml", 0, null, null, null);
|
||||
return true;
|
||||
function submitError(dumpid) {
|
||||
//XXX: do something more useful here
|
||||
let link = document.getElementById(dumpid);
|
||||
if (link)
|
||||
link.className = "";
|
||||
// dispatch an event, useful for testing
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("CrashSubmitFailed", true, false);
|
||||
document.dispatchEvent(event);
|
||||
}
|
||||
|
||||
function submitPendingReport(event) {
|
||||
var link = event.target;
|
||||
var id = link.firstChild.textContent;
|
||||
if (createAndSubmitForm(id, link))
|
||||
if (CrashSubmit.submit(id, document.body, submitSuccess, submitError))
|
||||
link.className = "submitting";
|
||||
event.preventDefault();
|
||||
return false;
|
||||
|
@ -425,6 +245,5 @@ function clearReports() {
|
|||
}
|
||||
|
||||
function init() {
|
||||
getL10nStrings();
|
||||
populateReportList();
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
// This code is TEMPORARY for submitting crashes via an ugly popup dialog:
|
||||
// bug 525849 tracks the real implementation.
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
Components.utils.import("resource://gre/modules/CrashSubmit.jsm");
|
||||
|
||||
var id;
|
||||
|
||||
function collectData() {
|
||||
// HACK: crashes.js uses document.body, so we just alias it
|
||||
document.body = document.getElementById('iframe-holder');
|
||||
|
||||
getL10nStrings();
|
||||
|
||||
let directoryService = Cc["@mozilla.org/file/directory_service;1"].
|
||||
getService(Ci.nsIProperties);
|
||||
pendingDir = directoryService.get("UAppData", Ci.nsIFile);
|
||||
|
@ -31,11 +31,18 @@ function collectData() {
|
|||
extraFile.moveTo(pendingDir, "");
|
||||
}
|
||||
|
||||
function submitDone()
|
||||
{
|
||||
// we don't currently distinguish between success or failure here
|
||||
window.close();
|
||||
}
|
||||
|
||||
function onSubmit()
|
||||
{
|
||||
document.documentElement.getButton('accept').disabled = true;
|
||||
document.documentElement.getButton('accept').label = 'Sending';
|
||||
document.getElementById('throbber').src = 'chrome://global/skin/icons/loading_16.png';
|
||||
createAndSubmitForm(id, null);
|
||||
CrashSubmit.submit(id, document.getElementById('iframe-holder'),
|
||||
submitDone, submitDone);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
}
|
||||
</style>
|
||||
|
||||
<script type="application/javascript;version=1.8" src="chrome://global/content/crashes.js"/>
|
||||
<script type="application/javascript;version=1.8" src="chrome://global/content/oopcrashdialog.js"/>
|
||||
|
||||
<dialogheader title="A Plugin Crashed" />
|
||||
|
|
|
@ -53,7 +53,6 @@ function check_submit_pending(tab, crashes) {
|
|||
let CrashID = null;
|
||||
let CrashURL = null;
|
||||
function csp_onload() {
|
||||
dump('csp_onload, location = ' + browser.contentWindow.location + '\n');
|
||||
if (browser.contentWindow.location != 'about:crashes') {
|
||||
browser.removeEventListener("load", csp_onload, true);
|
||||
// loaded the crash report page
|
||||
|
@ -90,6 +89,12 @@ function check_submit_pending(tab, crashes) {
|
|||
});
|
||||
}
|
||||
}
|
||||
function csp_fail() {
|
||||
browser.removeEventListener("CrashSubmitFailed", csp_fail, true);
|
||||
ok(false, "failed to submit crash report!");
|
||||
cleanup_and_finish();
|
||||
}
|
||||
browser.addEventListener("CrashSubmitFailed", csp_fail, true);
|
||||
browser.addEventListener("load", csp_onload, true);
|
||||
function csp_pageshow() {
|
||||
browser.removeEventListener("pageshow", csp_pageshow, true);
|
||||
|
@ -107,13 +112,11 @@ function check_submit_pending(tab, crashes) {
|
|||
for each(let crash in crashes) {
|
||||
if (crash.pending) {
|
||||
SubmittedCrash = crash;
|
||||
dump('check_submit_pending: trying to submit crash ' + crash.id + '\n');
|
||||
break;
|
||||
}
|
||||
}
|
||||
EventUtils.sendMouseEvent({type:'click'}, SubmittedCrash.id,
|
||||
browser.contentWindow);
|
||||
dump('check_submit_pending: sent mouse event to ' + SubmittedCrash.id + '\n');
|
||||
}
|
||||
|
||||
function test() {
|
||||
|
|
|
@ -145,7 +145,7 @@ function handleRequest(request, response)
|
|||
else if (request.method == "POST") {
|
||||
let formData = parseMultipartForm(request);
|
||||
|
||||
if ('upload_file_minidump' in formData) {
|
||||
if (formData && 'upload_file_minidump' in formData) {
|
||||
response.setHeader("Content-Type", "text/plain", false);
|
||||
|
||||
let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]
|
||||
|
@ -161,6 +161,7 @@ function handleRequest(request, response)
|
|||
response.write("CrashID=" + uuid + "\n");
|
||||
}
|
||||
else {
|
||||
dump('*** crashreport.sjs: Malformed request?\n');
|
||||
response.setStatusLine(request.httpVersion, 400, "Bad Request");
|
||||
response.write("Missing minidump file");
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче