d17c507ba014280326dcbf54a3bbfd8e5f9989db
chmalee
  Mon Nov 8 16:07:32 2021 -0800
Fix pipeline timeout to properly ignore signal() returning non-zero, except in the case of a real error. Also get hgHubConnect to properly time out on hubCheck taking too long

diff --git src/hg/hgHubConnect/hgHubConnect.c src/hg/hgHubConnect/hgHubConnect.c
index 845ba41..159e3c0 100644
--- src/hg/hgHubConnect/hgHubConnect.c
+++ src/hg/hgHubConnect/hgHubConnect.c
@@ -19,30 +19,31 @@
 #include "dbDb.h"
 #include "web.h"
 #include "trackHub.h"
 #include "hubConnect.h"
 #include "dystring.h"
 #include "hPrint.h"
 #include "jsHelper.h"
 #include "obscure.h"
 #include "hgConfig.h"
 #include "trix.h"
 #include "net.h"
 #include "hubSearchText.h"
 #include "pipeline.h"
 #include "hubPublic.h"
 
+
 static boolean measureTiming;
 
 struct cart *cart;	/* The user's ui state. */
 struct hash *oldVars = NULL;
 
 static char *pageTitle = "Track Data Hubs";
 char *database = NULL;
 char *organism = NULL;
 
 struct hubOutputStructure
     {
     struct hubOutputStructure *next;
     struct dyString *metaTags;
     struct dyString *descriptionMatch;
     struct genomeOutputStructure *genomes;
@@ -371,41 +372,54 @@
 
     puts("</tr>");
     }
 
 printf("</tbody></TABLE>\n");
 puts("</FORM>");
 printf("</div>"); // .tabSection
 printf("</div>"); // #unlistedHubs
 
 }
 
 void doValidateNewHub(char *hubUrl)
 /* Run hubCheck on a hub. */
 {
 udcSetCacheTimeout(1);
+char *expireTime = cfgOptionDefault("browser.cgiExpireMinutes", "20");
+unsigned expireMinutes = sqlUnsigned(expireTime);
+int hubCheckTimeout = (expireMinutes - 1) * 60 > 0 ? (expireMinutes - 1) * 60 : 60;
 printf("<div id=\"validateHubResult\" class=\"hubTdbTree\" style=\"overflow: auto\"></div>");
 char *cmd[] = {"loader/hubCheck", "-htmlOut", "-noTracks", hubUrl, NULL};
-struct pipeline *pl = pipelineOpen1(cmd, pipelineRead | pipelineNoAbort, NULL, NULL, 0);
+struct errCatch *errCatch = errCatchNew();
+if (errCatchStart(errCatch))
+    {
+    struct pipeline *pl = pipelineOpen1(cmd, pipelineRead | pipelineNoAbort, NULL, NULL, hubCheckTimeout);
     struct lineFile *lf = pipelineLineFile(pl);
     char *line;
     while (lineFileNext(lf, &line, NULL))
         jsInlineF("%s", line);
     pipelineClose(&pl);
     // the 'false' below prevents a few hub-search specific jstree configuration options
     jsInline("hubSearchTree.init(false);");
     }
+errCatchEnd(errCatch);
+if (errCatch->gotError || errCatch->gotWarning)
+    {
+    printf("hubCheck timed out after running for %d seconds. Please try on a Unix command line", hubCheckTimeout);
+    }
+errCatchFree(&errCatch);
+}
 
 void hgHubConnectDeveloperMode()
 /* Put up the controls for the "Hub Development" Tab, which includes a button to run the
  * hubCheck utility on a hub and load a hub with the udcTimeout and measureTiming
  * variables turned on */
 {
 // put out the top of our page
 char *hubUrl = cartOptionalString(cart, "validateHubUrl");
 
 // the outer div for all the elements in the tab
 puts("<div id=\"hubDeveloper\" class=\"hubList\">");
 
 char *hubUrlVal = "";
 if (hubUrl != NULL)
     hubUrlVal = catThreeStrings(" value='", hubUrl, "'");
@@ -1457,30 +1471,35 @@
 "<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.7/themes/default/style.min.css\" />\n"
 "<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.1/jquery.min.js\"></script>\n"
 "<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.7/jstree.min.js\"></script>\n"
 "<style>.jstree-default .jstree-anchor { height: initial; } </style>\n"
 );
 jsIncludeFile("utils.js", NULL);
 jsIncludeFile("jquery-ui.js", NULL);
 webIncludeResourceFile("jquery-ui.css");
 jsIncludeFile("ajax.js", NULL);
 jsIncludeFile("hgHubConnect.js", NULL);
 webIncludeResourceFile("hgHubConnect.css");
 jsIncludeFile("jquery.cookie.js", NULL);
 jsIncludeFile("spectrum.min.js", NULL); // there is no color picker used anywhere on this page. why include this?
 }
 
+void blankWarn()
+/* Dummy warn handler used in the iframe for returning hubCheck output */
+{
+}
+
 void doMiddle(struct cart *theCart)
 /* Write header and body of html page. */
 {
 cart = theCart;
 // hgHubConnect's own timing is tied to a special value of measureTiming, since now
 // our users use measureTiming a lot more, we need to keep a special mode for us
 measureTiming = sameString(cartUsualString(cart, "measureTiming", ""), "full");
 
 if(cgiIsOnWeb())
     checkForGeoMirrorRedirect(cart);
 
 if (cartVarExists(cart, hgHubDoClear))
     {
     doClearHub(cart);
     cartWebEnd();
@@ -1491,48 +1510,51 @@
     {
     doResetHub(cart);
     }
 
 if (cartVarExists(cart, hgHubDoRedirect))
     {
     if (doRedirect(cart))
 	{
 	cartWebEnd();
 	return;
 	}
     }
 
 if (cartVarExists(cart, hgHubDoHubCheck))
     {
+    // we aren't calling cartWebStart so we need to push 3 error handlers:
+    webPushErrHandlers();
+    pushWarnHandler(blankWarn);
     puts("<html>");
     puts("<body>");
     puts("<link rel='stylesheet' href='../style/HGStyle.css' type='text/css'>");
     printIncludes();
 
     jsInline("trackData = [];\n");
     char *hubUrl = cartOptionalString(cart, "validateHubUrl");
     jsInline("document.body.style.margin = 0;\n");
     // simulate the look and feel of a dialog window with a blue bar at the top
     puts("<div id='titlebar' style='background: #D9E4F8; border: 1px outset #000088; padding: 10px'>"
         "<span id='title' style='font-weight: bold; margin: .2em 0 .1em; color: #000088'>Hub Check</span>"
         "<a href='#' id='windowX' style='float: right' class='ui-dialog-titlebar-close ui-corner-all ui-state-hover' role='button'>"
         "<span class='ui-icon ui-icon-closethick'>close</span></a></div>");
 
     puts("<div id='content' style='margin:10px; padding: 2px'>");
     jsOnEventByIdF("click", "windowX", "closeIframe()");
     if (isEmpty(hubUrl))
-        printf("Please wait, loading and checking hub, this can take 15 seconds to several minutes.");
+        printf("Please wait, loading and checking hub, this can take 15 seconds to 5 minutes.");
     else
         {
         puts("<p><button id='reloadButton'>Check again</button>");
         puts("&nbsp;&nbsp;<button id='closeButton'>Close this window</button></p>");
         jsOnEventByIdF("click", "reloadButton", "reloadIframe()");
         jsOnEventByIdF("click", "closeButton", "closeIframe()");
 
         printf("<div>Finished checking %s</div>", hubUrl);
         doValidateNewHub(hubUrl);
         puts("<p>Our command line tool <a target=_blank href='https://hgdownload.soe.ucsc.edu/downloads.html#utilities_downloads'>hubCheck</a> "
                 "can be used to obtain the same output from a Unix command line.</p>");
         }
     puts("</div>"); // margin 10px
     puts("</div>"); // ui-dialog-titlebar
     puts("</div>"); // ui-dialog