704da00109657134150e13c3791548e747593cb3
braney
  Fri May 19 16:34:23 2023 -0700
dump the cart to trash if the browser took too long to draw

diff --git src/hg/lib/cart.c src/hg/lib/cart.c
index e171df9..d94542a 100644
--- src/hg/lib/cart.c
+++ src/hg/lib/cart.c
@@ -2357,30 +2357,56 @@
 }
 
 static void cartJsonStart()
 /* Write the necessary headers for Apache */
 {
 puts("Content-Type: application/json\n");
 }
 
 static void cartJsonEnd(struct jsonWrite *jw)
 /* Write the final string which may have nothing in it */
 {
 if (jw)
     puts(jw->dy->string);
 }
 
+static void dumpCartWithTime(struct cart *cart, char *timeStr)
+/* Dump out the current cart to trash named by how long a page draw took using it. */
+{
+char prefix[128];
+
+// zero pad so the files will alphanumerically sort by elapsed time
+sprintf(prefix, "%06d.", atoi(timeStr));
+
+// make a temp file in trash
+struct tempName hubTn;
+trashDirDateFile(&hubTn, "cartDumps", prefix , ".txt");
+char *dumpName = cloneString(hubTn.forCgi);
+
+// write out the cart into the tempfile
+FILE *f = mustOpen(dumpName, "w");
+
+struct hashEl *el;
+struct hashEl *elList = hashElListHash(cart->hash);
+for (el = elList; el != NULL; el = el->next)
+    fprintf(f, "%s %s\n", el->name, (char *)el->val);
+fclose(f);
+
+// put something in the log to say we did this
+fprintf(stderr, "warnTiming %s time=%s skipNotif=%s\n", getSessionId(), timeStr, cartUsualString(cart, "skipNotif", "null"));
+}
+
 struct cart *cartForSession(char *cookieName, char **exclude,
                             struct hash *oldVars)
 /* This gets the cart without writing any HTTP lines at all to stdout. */
 {
 /* Most cgis call this routine */
 if (sameOk(cfgOption("signalsHandler"), "on"))  /* most cgis call this routine */
     initSigHandlers(hDumpStackEnabled());
 
 /* HTTPS SSL Cert Checking Settings */
 char *httpsCertCheck = cfgOption("httpsCertCheck");  
 if (httpsCertCheck)
     setenv("https_cert_check", httpsCertCheck, TRUE);
 char *httpsCertCheckVerbose = cfgOption("httpsCertCheckVerbose");  
 if (httpsCertCheckVerbose)
     setenv("https_cert_check_verbose", httpsCertCheckVerbose, TRUE);
@@ -2426,30 +2452,37 @@
 
 // if _dumpToLog is on the URL, we can exit early with whatever
 // message we are trying to write to the stderr/error_log
 char *logMsg = NULL;
 if ( (logMsg = cgiOptionalString("_dumpToLog")) != NULL)
     {
     cartJsonStart();
     fprintf(stderr, "%s", logMsg);
     cartJsonEnd(NULL);
     exit(0);
     }
 char *hgsid = getSessionId();
 struct cart *cart = cartNew(hguid, hgsid, exclude, oldVars);
 cartExclude(cart, sessionVar);
 
+char *timeStr;
+if ( (timeStr = cgiOptionalString("_dumpCart")) != NULL)
+    {
+    dumpCartWithTime(cart, timeStr);
+    exit(0);
+    }
+
 // activate optional debuging output for CGIs
 verboseCgi(cartCgiUsualString(cart, "verbose", NULL));
 
 return cart;
 }
 
 static void addHttpHeaders()
 /* CGIs can initialize the global variable httpHeaders to control their own HTTP
  * headers. This allows, for example, to prevent web browser caching of hgTracks
  * responses, but implicitly allow web browser caching everywhere else */
 {
 struct slPair *h;
 for (h = httpHeaders; h != NULL; h = h->next)
     {
     printf("%s: %s\n", h->name, (char *)h->val);