bug 380421 - get crash reporter params from nsXULAppInfo. r=bsmedberg
authorted.mielczarek@gmail.com
Wed, 16 May 2007 10:14:59 -0700
changeset 1527 9b59a5036593d47b02bf5f8fd8b743b307e179fb
parent 1526 dcc14e8ea04da52b634756d5fa8df60bae64473b
child 1528 4369a4cf2b0ac1fc5d2c1be266be102999b17d66
push idunknown
push userunknown
push dateunknown
reviewersbsmedberg
bugs380421
milestone1.9a5pre
bug 380421 - get crash reporter params from nsXULAppInfo. r=bsmedberg
browser/app/application.ini
browser/app/nsBrowserApp.cpp
toolkit/airbag/client/crashreporter.cpp
toolkit/airbag/client/crashreporter.h
toolkit/airbag/client/crashreporter.ini
toolkit/airbag/client/crashreporter_win.cpp
toolkit/airbag/nsAirbagExceptionHandler.cpp
toolkit/airbag/nsAirbagExceptionHandler.h
toolkit/airbag/test/TestCrashReporterAPI.cpp
toolkit/xre/nsAppData.cpp
toolkit/xre/nsAppRunner.cpp
toolkit/xre/nsXULAppAPI.h
--- a/browser/app/application.ini
+++ b/browser/app/application.ini
@@ -46,8 +46,12 @@ ID={ec8030f7-c20a-464f-9b0e-13a3a9e97384
 
 [Gecko]
 MinVersion=@GRE_BUILD_ID@
 MaxVersion=@GRE_BUILD_ID@
 
 [XRE]
 EnableProfileMigrator=1
 EnableExtensionManager=1
+
+[Crash Reporter]
+Enabled=0
+ServerURL=https://crash-reports.mozilla.com/submit
--- a/browser/app/nsBrowserApp.cpp
+++ b/browser/app/nsBrowserApp.cpp
@@ -39,26 +39,30 @@
 #include "nsXULAppAPI.h"
 #ifdef XP_WIN
 #include <windows.h>
 #include <stdlib.h>
 #endif
 #include "nsBuildID.h"
 
 static const nsXREAppData kAppData = {
-  offsetof(nsXREAppData, xreDirectory),
+  sizeof(nsXREAppData),
   nsnull,
   "Mozilla",
   "Firefox",
   NS_STRINGIFY(APP_VERSION),
   NS_STRINGIFY(BUILD_ID),
   "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}",
   "Copyright (c) 1998 - 2007 mozilla.org",
   NS_XRE_ENABLE_PROFILE_MIGRATOR |
-  NS_XRE_ENABLE_EXTENSION_MANAGER
+  NS_XRE_ENABLE_EXTENSION_MANAGER,
+  nsnull, // xreDirectory
+  nsnull, // minVersion
+  nsnull, // maxVersion
+  "https://crash-reports.mozilla.com/submit"
 };
 
 int main(int argc, char* argv[])
 {
   return XRE_main(argc, argv, &kAppData);
 }
 
 #if defined( XP_WIN ) && defined( WIN32 ) && !defined(__GNUC__)
--- a/toolkit/airbag/client/crashreporter.cpp
+++ b/toolkit/airbag/client/crashreporter.cpp
@@ -34,36 +34,35 @@
  * 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 ***** */
 
 #include "crashreporter.h"
 
+// Disable exception handler warnings.
+#pragma warning( disable : 4530 )
 #include <fstream>
 #include <sstream>
 
 using std::string;
 using std::istream;
 using std::ifstream;
 using std::istringstream;
 using std::ostream;
 using std::ofstream;
 
 StringTable  gStrings;
 int          gArgc;
 const char** gArgv;
 
-static string       gSendURL;
 static string       gDumpFile;
 static string       gExtraFile;
 static string       gSettingsPath;
-static bool         gDeleteDump = true;
-
 
 static string kExtraDataExtension = ".extra";
 
 static bool ReadStrings(istream &in, StringTable &strings)
 {
   string currentSection;
   while (!in.eof()) {
     string line;
@@ -93,21 +92,16 @@ static bool ReadConfig()
 {
   string iniPath;
   if (!UIGetIniPath(iniPath))
     return false;
 
   if (!ReadStringsFromFile(iniPath, gStrings))
     return false;
 
-  gSendURL = gStrings["URL"];
-
-  string deleteSetting = gStrings["Delete"];
-  gDeleteDump = deleteSetting.empty() || atoi(deleteSetting.c_str()) != 0;
-
   return true;
 }
 
 static string GetExtraDataFilename(const string& dumpfile)
 {
   string filename(dumpfile);
   int dot = filename.rfind('.');
   if (dot < 0)
@@ -191,22 +185,20 @@ static bool AddSubmittedReport(const str
   return true;
 
 }
 
 bool CrashReporterSendCompleted(bool success,
                                 const string& serverResponse)
 {
   if (success) {
-    if (gDeleteDump) {
-      if (!gDumpFile.empty())
-        UIDeleteFile(gDumpFile);
-      if (!gExtraFile.empty())
-        UIDeleteFile(gExtraFile);
-    }
+    if (!gDumpFile.empty())
+      UIDeleteFile(gDumpFile);
+    if (!gExtraFile.empty())
+      UIDeleteFile(gExtraFile);
 
     return AddSubmittedReport(serverResponse);
   }
   return true;
 }
 
 int main(int argc, const char** argv)
 {
@@ -241,30 +233,47 @@ int main(int argc, const char** argv)
       return 0;
     }
 
     if (queryParameters.find("ProductName") == queryParameters.end()) {
       UIError("No product name specified");
       return 0;
     }
 
+    if (queryParameters.find("ServerURL") == queryParameters.end()) {
+      UIError("No server URL specified");
+      return 0;
+    }
+
     string product = queryParameters["ProductName"];
     string vendor = queryParameters["Vendor"];
     if (!UIGetSettingsPath(vendor, product, gSettingsPath)) {
       UIError("Couldn't get settings path");
       return 0;
     }
 
     string pendingDir = gSettingsPath + UI_DIR_SEPARATOR + "pending";
     if (!MoveCrashData(pendingDir, gDumpFile, gExtraFile)) {
       UIError("Couldn't move crash data");
       return 0;
     }
 
-    UIShowCrashUI(gDumpFile, queryParameters, gSendURL);
+    string sendURL = queryParameters["ServerURL"];
+    // we don't need to actually send this
+    queryParameters.erase("ServerURL");
+
+    // allow override of the server url via environment variable
+    //XXX: remove this in the far future when our robot
+    // masters force everyone to use XULRunner
+    char* urlEnv = getenv("MOZ_CRASHREPORTER_URL");
+    if (urlEnv && *urlEnv) {
+      sendURL = urlEnv;
+    }
+
+    UIShowCrashUI(gDumpFile, queryParameters, sendURL);
   }
 
   UIShutdown();
 
   return 0;
 }
 
 #if defined(XP_WIN) && !defined(__GNUC__)
--- a/toolkit/airbag/client/crashreporter.h
+++ b/toolkit/airbag/client/crashreporter.h
@@ -1,11 +1,14 @@
 #ifndef CRASHREPORTER_H__
 #define CRASHREPORTER_H__
 
+#pragma warning( push )
+// Disable exception handler warnings.
+#pragma warning( disable : 4530 )
 #include <string>
 #include <map>
 #include <stdlib.h>
 #include <stdio.h>
 
 #if defined(XP_WIN32)
 
 #include <windows.h>
@@ -66,9 +69,10 @@ void UIError(const std::string& message)
 bool UIGetIniPath(std::string& path);
 bool UIGetSettingsPath(const std::string& vendor,
                        const std::string& product,
                        std::string& settingsPath);
 bool UIEnsurePathExists(const std::string& path);
 bool UIMoveFile(const std::string& oldfile, const std::string& newfile);
 bool UIDeleteFile(const std::string& oldfile);
 
+#pragma warning( pop )
 #endif
--- a/toolkit/airbag/client/crashreporter.ini
+++ b/toolkit/airbag/client/crashreporter.ini
@@ -9,11 +9,8 @@ CrashReporterTitle=Mozilla Crash Reporte
 CrashReporterDescription=Crash reporting blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah
 RadioEnable=Enable Crash Reporting
 RadioDisable=Disable Crash Reporting
 SendTitle=Sending Crash Report...
 SubmitSuccess=Crash report submitted successfully
 SubmitFailed=Failed to submit crash report
 CrashID=Crash ID: %s
 CrashDetailsURL=You can view details of this crash at %s
-
-[Settings]
-URL=https://crash-reports.mozilla.com/submit
--- a/toolkit/airbag/client/crashreporter_win.cpp
+++ b/toolkit/airbag/client/crashreporter_win.cpp
@@ -425,15 +425,16 @@ bool UIEnsurePathExists(const string& pa
       return false;
   }
 
   return true;
 }
 
 bool UIMoveFile(const string& oldfile, const string& newfile)
 {
-  return MoveFile(UTF8ToWide(oldfile).c_str(), UTF8ToWide(newfile).c_str());
+  return MoveFile(UTF8ToWide(oldfile).c_str(), UTF8ToWide(newfile).c_str())
+    == TRUE;
 }
 
 bool UIDeleteFile(const string& oldfile)
 {
-  return DeleteFile(UTF8ToWide(oldfile).c_str());
+  return DeleteFile(UTF8ToWide(oldfile).c_str()) == TRUE;
 }
--- a/toolkit/airbag/nsAirbagExceptionHandler.cpp
+++ b/toolkit/airbag/nsAirbagExceptionHandler.cpp
@@ -283,31 +283,24 @@ static nsresult GetExecutablePath(nsStri
   path[len + 1] = '\0';
 
   exePath = NS_ConvertUTF8toUTF16(path);
 
   return NS_OK;
 #endif
 }
 
-nsresult SetExceptionHandler(nsILocalFile* aXREDirectory)
+nsresult SetExceptionHandler(nsILocalFile* aXREDirectory,
+                             const char* aServerURL)
 {
   nsresult rv;
 
   if (gExceptionHandler)
     return NS_ERROR_ALREADY_INITIALIZED;
 
-  // check environment var to see if we're enabled.
-  // we're off by default until we sort out the
-  // rest of the infrastructure,
-  // so it must exist and be set to a non-empty value.
-  const char* airbagEnv = PR_GetEnv("MOZ_AIRBAG");
-  if (airbagEnv == NULL || *airbagEnv == '\0')
-    return NS_ERROR_NOT_AVAILABLE;
-
   // this environment variable prevents us from launching
   // the crash reporter client
   const char* noReportEnv = PR_GetEnv("MOZ_CRASHREPORTER_NO_REPORT");
   if (noReportEnv && *noReportEnv)
     doReport = false;
 
   // allocate our strings
   crashReporterAPIData = new nsCString();
@@ -358,27 +351,32 @@ nsresult SetExceptionHandler(nsILocalFil
     return NS_ERROR_FAILURE;
   tempPath = NS_ConvertUTF8toUTF16(path);
 
 #else
   //XXX: implement get temp path on other platforms
   return NS_ERROR_NOT_IMPLEMENTED;
 #endif
 
-  // finally, set the exception handler
+  // now set the exception handler
   gExceptionHandler = new google_breakpad::
     ExceptionHandler(CONVERT_UTF16_TO_XP_CHAR(tempPath).get(),
                      nsnull,
                      MinidumpCallback,
                      nsnull,
                      true);
 
   if (!gExceptionHandler)
     return NS_ERROR_OUT_OF_MEMORY;
 
+  // store server URL with the API data
+  if (aServerURL)
+    AnnotateCrashReport(NS_LITERAL_CSTRING("ServerURL"),
+                        nsDependentCString(aServerURL));
+
   return NS_OK;
 }
 
 nsresult SetMinidumpPath(const nsAString& aPath)
 {
   if (!gExceptionHandler)
     return NS_ERROR_NOT_INITIALIZED;
 
--- a/toolkit/airbag/nsAirbagExceptionHandler.h
+++ b/toolkit/airbag/nsAirbagExceptionHandler.h
@@ -38,15 +38,16 @@
 #ifndef nsAirbagExceptionHandler_h__
 #define nsAirbagExceptionHandler_h__
 
 #include "nscore.h"
 #include "nsXPCOM.h"
 #include "nsStringGlue.h"
 
 namespace CrashReporter {
-nsresult SetExceptionHandler(nsILocalFile* aXREDirectory);
+nsresult SetExceptionHandler(nsILocalFile* aXREDirectory,
+                             const char* aServerURL);
 nsresult SetMinidumpPath(const nsAString& aPath);
 nsresult UnsetExceptionHandler();
 nsresult AnnotateCrashReport(const nsACString &key, const nsACString &data);
 }
 
 #endif /* nsAirbagExceptionHandler_h__ */
--- a/toolkit/airbag/test/TestCrashReporterAPI.cpp
+++ b/toolkit/airbag/test/TestCrashReporterAPI.cpp
@@ -58,17 +58,17 @@
 #define mu_run_test(test) do { char *message = test(); tests_run++; \
                                 if (message) return message; } while (0)
 int tests_run;
 
 char *
 test_init_exception_handler()
 {
   mu_assert("CrashReporter::SetExceptionHandler",
-            CrashReporter::SetExceptionHandler(nsnull));
+            CrashReporter::SetExceptionHandler(nsnull, nsnull));
   return 0;
 }
 
 char *
 test_set_minidump_path()
 {
   nsresult rv;
   nsCOMPtr<nsIProperties> directoryService = 
--- a/toolkit/xre/nsAppData.cpp
+++ b/toolkit/xre/nsAppData.cpp
@@ -78,32 +78,38 @@ ScopedAppData::ScopedAppData(const nsXRE
   SetStrongPtr(this->directory, aAppData->directory);
   this->flags = aAppData->flags;
 
   if (aAppData->size > offsetof(nsXREAppData, xreDirectory)) {
     SetStrongPtr(this->xreDirectory, aAppData->xreDirectory);
     SetAllocatedString(this->minVersion, aAppData->minVersion);
     SetAllocatedString(this->maxVersion, aAppData->maxVersion);
   }
+
+  if (aAppData->size > offsetof(nsXREAppData, crashReporterURL)) {
+    SetAllocatedString(this->crashReporterURL, aAppData->crashReporterURL);
+  }
 }
 
 ScopedAppData::~ScopedAppData()
 {
   SetAllocatedString(this->vendor, nsnull);
   SetAllocatedString(this->name, nsnull);
   SetAllocatedString(this->version, nsnull);
   SetAllocatedString(this->buildID, nsnull);
   SetAllocatedString(this->ID, nsnull);
   SetAllocatedString(this->copyright, nsnull);
 
   NS_IF_RELEASE(this->directory);
 
   SetStrongPtr(this->xreDirectory, (nsILocalFile*) nsnull);
   SetAllocatedString(this->minVersion, nsnull);
   SetAllocatedString(this->maxVersion, nsnull);
+
+  SetAllocatedString(this->crashReporterURL, nsnull);
 }
 
 nsresult
 XRE_CreateAppData(nsILocalFile* aINIFile, nsXREAppData **aAppData)
 {
   NS_ENSURE_ARG(aINIFile && aAppData);
 
   nsXREAppData *data = new ScopedAppData();
@@ -206,16 +212,29 @@ XRE_ParseAppData(nsILocalFile* aINIFile,
     ReadString strings2[] = {
       { "Gecko", "MinVersion", &aAppData->minVersion },
       { "Gecko", "MaxVersion", &aAppData->maxVersion },
       { nsnull }
     };
     ReadStrings(parser, strings2);
   }
 
+  if (aAppData->size > offsetof(nsXREAppData, crashReporterURL)) {
+    ReadString strings3[] = {
+      { "Crash Reporter", "ServerURL", &aAppData->crashReporterURL },
+      { nsnull }
+    };
+    ReadStrings(parser, strings3);
+    ReadFlag flags2[] = {
+      { "Crash Reporter", "Enabled", NS_XRE_ENABLE_CRASH_REPORTER },
+      { nsnull }
+    };
+    ReadFlags(parser, flags2, &aAppData->flags);
+  }
+
   return NS_OK;
 }
 
 void
 XRE_FreeAppData(nsXREAppData *aAppData)
 {
   if (!aAppData) {
     NS_ERROR("Invalid arg");
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -2183,18 +2183,25 @@ XRE_main(int argc, char* argv[], const n
   NS_TIMELINE_MARK("enter main");
 
 #ifdef DEBUG
   if (PR_GetEnv("XRE_MAIN_BREAK"))
     NS_BREAK();
 #endif
 
 #ifdef MOZ_AIRBAG
-  if (NS_SUCCEEDED(
-        CrashReporter::SetExceptionHandler(aAppData->xreDirectory))) {
+  //XXX: remove me when we turn this on by default
+  const char* airbagEnv = PR_GetEnv("MOZ_AIRBAG");
+  //XXX: can't set the flag here, since aAppData is const
+  if (((airbagEnv && *airbagEnv) ||
+      ((aAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) &&
+       aAppData->crashReporterURL)) &&
+      NS_SUCCEEDED(CrashReporter::SetExceptionHandler(aAppData->xreDirectory,
+                                                      aAppData->crashReporterURL)))
+    {
     // pass some basic info from the app data
     if (aAppData->vendor)
       CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Vendor"),
                                      nsDependentCString(aAppData->vendor));
     if (aAppData->name)
       CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProductName"),
                                      nsDependentCString(aAppData->name));
     if (aAppData->version)
@@ -2303,16 +2310,23 @@ XRE_main(int argc, char* argv[], const n
         NS_CompareVersions(appData.maxVersion, TOOLKIT_EM_VERSION) < 0) {
       Output(PR_TRUE, "Error: Platform version " TOOLKIT_EM_VERSION " is not compatible with\n"
              "minVersion >= %s\nmaxVersion <= %s\n",
              appData.minVersion, appData.maxVersion);
       return 1;
     }
   }
 
+#ifdef MOZ_AIRBAG
+  //XXX: remove me when this is on by default
+  if (airbagEnv && *airbagEnv) {
+    appData.flags |= NS_XRE_ENABLE_CRASH_REPORTER;
+  }
+#endif
+
   ScopedLogging log;
 
   if (!appData.xreDirectory) {
     nsCOMPtr<nsILocalFile> lf;
     rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
     if (NS_FAILED(rv))
       return 2;
 
@@ -2560,17 +2574,18 @@ XRE_main(int argc, char* argv[], const n
     NS_ENSURE_SUCCESS(rv, 1);
 
     rv = dirProvider.SetProfile(profD, profLD);
     NS_ENSURE_SUCCESS(rv, 1);
 
     //////////////////////// NOW WE HAVE A PROFILE ////////////////////////
 
 #ifdef MOZ_AIRBAG
-    MakeOrSetMinidumpPath(profD);
+    if (appData.flags & NS_XRE_ENABLE_CRASH_REPORTER)
+        MakeOrSetMinidumpPath(profD);
 #endif
 
     PRBool upgraded = PR_FALSE;
 
     nsCAutoString version;
     BuildVersion(version);
 
 #ifdef TARGET_OS_ABI
@@ -2889,21 +2904,23 @@ XRE_main(int argc, char* argv[], const n
           PR_SetEnv(ToNewCString(desktopStartupEnv));
         }
       }
 #endif
 
       rv = LaunchChild(nativeApp, appInitiatedRestart, upgraded ? -1 : 0);
 
 #ifdef MOZ_AIRBAG
-      CrashReporter::UnsetExceptionHandler();
+      if (appData.flags & NS_XRE_ENABLE_CRASH_REPORTER)
+        CrashReporter::UnsetExceptionHandler();
 #endif
 
       return rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ? 0 : 1;
     }
   }
 
 #ifdef MOZ_AIRBAG
-  CrashReporter::UnsetExceptionHandler();
+  if (appData.flags & NS_XRE_ENABLE_CRASH_REPORTER)
+      CrashReporter::UnsetExceptionHandler();
 #endif
 
   return NS_FAILED(rv) ? 1 : 0;
 }
--- a/toolkit/xre/nsXULAppAPI.h
+++ b/toolkit/xre/nsXULAppAPI.h
@@ -128,31 +128,41 @@ struct nsXREAppData
    */
   nsILocalFile* xreDirectory;
 
   /**
    * The minimum/maximum compatible XRE version.
    */
   const char *minVersion;
   const char *maxVersion;
+
+  /**
+   * The server URL to send crash reports to.
+   */
+  const char *crashReporterURL;
 };
 
 /**
  * Indicates whether or not the profile migrator service may be
  * invoked at startup when creating a profile.
  */
 #define NS_XRE_ENABLE_PROFILE_MIGRATOR (1 << 1)
 
 /**
  * Indicates whether or not the extension manager service should be
  * initialized at startup.
  */
 #define NS_XRE_ENABLE_EXTENSION_MANAGER (1 << 2)
 
 /**
+ * Indicates whether or not to use Breakpad crash reporting.
+ */
+#define NS_XRE_ENABLE_CRASH_REPORTER (1 << 3)
+
+/**
  * The contract id for the nsIXULAppInfo service.
  */
 #define XULAPPINFO_SERVICE_CONTRACTID \
   "@mozilla.org/xre/app-info;1"
 
 /**
  * A directory service key which provides the platform-correct
  * "application data" directory.