905b9cb05eeaca7f2dcda42fc6abdb95a2d2da7f max Wed Sep 9 05:29:28 2026 -0700 no captcha for a command-line CGI run, and version the detailsScript module URL Two small fixes to things noticed while adding the scatterPlot plot type. A CGI run from the command line got the Cloudflare Turnstile challenge page instead of the output the caller asked for, which makes "./hgc db=hg38 g=x" - the quickest way to see what a CGI emits - useless without a hand-made hg.conf. There is no browser to solve a captcha in that situation. printCaptcha() now returns early when cgiWasSpoofed(). That flag cannot be set from an HTTP request: cgiFromCommandLine() returns early and leaves it FALSE whenever the web server has set REQUEST_METHOD. Checked that a plain argument-style run is now clean, that a run which fakes the web environment with QUERY_STRING still gets the captcha, and that an HTTP request behaves exactly as the unmodified binary does. The detailsScript module was loaded from a hardcoded import('../js/hgc.X.js'), bypassing webTimeStampedLinkToResource(), so it was the one script on the page with no ?v=. That is the mechanism that flushes a browser's cache when the CGI version changes and that keeps a mirror from pairing an old static file with new CGIs, and without it a cached module could be handed newer bedDetails JSON than it was written for. Now built through the helper, which also fixes the already-shipped histogram type. The helper errAborts on a missing file and the plot type comes from a hub, so a plot type with no module installed falls back to the plain path: a silent failed import as before, rather than one bad hub setting taking down the whole details page. refs #35415 diff --git src/hg/hgc/bigBedClick.c src/hg/hgc/bigBedClick.c index fdac6c12423..0eb19d930e3 100644 --- src/hg/hgc/bigBedClick.c +++ src/hg/hgc/bigBedClick.c @@ -716,35 +716,58 @@ jsonWriteObjectEnd(jw); } } jsonWriteObjectEnd(jw); } jsonWriteListEnd(jw); } jsonWriteObjectEnd(jw); // scripts jsonWriteObjectEnd(jw); // root // Emit as inline JavaScript struct dyString *ds = dyStringNew(1024); dyStringPrintf(ds, "var bedDetails = %s;\n", jw->dy->string); - // Dynamically import and call each plot type's module + // Dynamically import and call each plot type's module. The URL carries + // ?v=, as every other js file does, so that a browser cannot serve a + // cached module against newer bedDetails JSON and a mirror cannot pair an old + // module with new CGIs. webTimeStampedLinkToResource() errAborts on a missing + // file and plotType comes from a hub, so a plotType with no module installed + // falls back to the plain path: that leaves a silent failed import as before, + // rather than taking the whole details page down over one bad hub setting. for (hel = helList; hel != NULL; hel = hel->next) + { + char modFile[PATH_LEN]; + safef(modFile, sizeof modFile, "hgc.%s.js", hel->name); + char fallBack[PATH_LEN]; + safef(fallBack, sizeof fallBack, "../js/%s", modFile); + char *modUrl = fallBack; + char *docRoot = hDocumentRoot(); + if (docRoot != NULL) + { + char onDisk[PATH_LEN]; + safef(onDisk, sizeof onDisk, "%s/js/%s", docRoot, modFile); + if (fileExists(onDisk)) + modUrl = webTimeStampedLinkToResource(modFile, FALSE); + } dyStringPrintf(ds, "$(document).ready(function() {\n" - " import('../js/hgc.%s.js').then(function(mod) { mod.%s(bedDetails); });\n" - "});\n", hel->name, hel->name); + " import('%s').then(function(mod) { mod.%s(bedDetails); });\n" + "});\n", modUrl, hel->name); + if (modUrl != fallBack) + freeMem(modUrl); + } jsInline(dyStringCannibalize(&ds)); jsonWriteFree(&jw); hashElFreeList(&helList); hashFree(&plotTypeHash); } } if (!found) { printf("No item %s starting at %d\n", emptyForNull(item), start); } lmCleanup(&lm); bbiFileClose(&bbi); }