cf9f4cb7f55c7beb8ad5f11118656a60770a71a5 max Thu Sep 10 01:02:36 2026 -0700 Move the extra-HTTP-header list into cheapcgi, and write the header only once Follow-on to the cgiPrintContentType() refactor. cart.c owned the mechanism for adding headers ahead of the content type: a global slPair list plus addHttpHeaders() to print it. That put it in hg/lib, out of reach of the CGIs and library code that do not use a cart, even though nothing about it is cart-specific. It now lives next to cgiPrintContentType() in lib/cheapcgi.c, behind cgiAddHttpHeader(name, value) instead of a bare global, and cgiPrintContentType() writes the queued headers itself. The one caller, hgTracks/mainMain.c, reads the same but no longer reaches into cart.h for it. cspWriteResponseHeader() stays in hg/lib where it belongs, since it needs hg.conf; cartWriteHeaderAndCont() calls it directly now, the way the other ten callers already do. cgiPrintContentType() also writes at most once per process now. A second content type cannot reach the browser as a header - it lands in the page body as text - so the later caller is always the mistaken one. cart.c had a private cartDidContentType flag for exactly this, covering only the flows that went through the cart; the guard is now in the one function every flow shares, and cartDidContentType is gone. Its public equivalent, cgiDidContentType(), is what cartWriteHeaderAndCont() checks so it does not write a second cookie. Verified: make libs, make cgi and the lib test suite are clean, hgTracks still emits Cache-Control: no-store, and hgTracks, hgc and hgTables each emit exactly one Content-Type on both their html and their text paths. diff --git src/hg/hgTracks/mainMain.c src/hg/hgTracks/mainMain.c index e827e3191a6..1be6a35cc7a 100644 --- src/hg/hgTracks/mainMain.c +++ src/hg/hgTracks/mainMain.c @@ -1,103 +1,103 @@ /* hgTracks - Human Genome browser main cgi script. */ /* Copyright (C) 2013 The Regents of the University of California * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */ #include "common.h" #include "linefile.h" #include "portable.h" #include "memalloc.h" #include "localmem.h" #include "hCommon.h" #include "obscure.h" #include "dystring.h" #include "hash.h" #include "cheapcgi.h" #include "htmshell.h" #include "web.h" #include "cart.h" #include "hdb.h" #include "hui.h" #include "hgFind.h" #include "hgTracks.h" #include "versionInfo.h" #include "net.h" #include "search.h" #include "imageV2.h" #include "extTools.h" #include "botDelay.h" #include "hgConfig.h" #include <sys/time.h> #include <sys/resource.h> boolean issueBotWarning; long enteredMainTime = 0; int main(int argc, char *argv[]) { // First, before anything has a chance to allocate: read hg.conf and set how // big a step the C library takes when it grows the heap. refs #38225 cfgSetMallocTopPad(); enteredMainTime = clock1000(); measureTime(NULL); // This is generic CGI setup code: Should be moved one day into a generic function // combined with the code cart.c:genericCgiSetup() ? cfgSetMaxMem(); // read hg.conf and set the maxMem if there cfgSetLogCgiVars(); // set logging of the CGI vars issueBotWarning = earlyBotCheck(enteredMainTime, "hgTracks", delayFraction, 0, 0, "html"); browserName = hBrowserName(); organization = "UCSC"; /* Push very early error handling - this is just * for the benefit of the cgiVarExists, which * somehow can't be moved effectively into doMiddle. */ htmlPushEarlyHandlers(); cgiSpoof(&argc, argv); char * link = webTimeStampedLinkToResourceOnFirstCall("HGStyle.css",TRUE); // resource file link if (link) // wrapped in html htmlSetStyle(link); oldVars = hashNew(10); if (cgiVarExists("hgt.redirectTool")) { // user has selected one of the tools in View > In external tools: Do not plot, just redirect. cgiPrintContentType("text/html"); errAbortSetDoContentType(FALSE); cart = cartForSession(hUserCookie(), NULL, NULL); extToolRedirect(cart, cgiString("hgt.redirectTool")); } else if (cfgOptionBooleanDefault("doMyVariants", FALSE) && cgiVarExists("myVarShareCmd")) { cart = cartForSession(hUserCookie(), NULL, NULL); myVariantsShareApiHandler(cgiString("myVarShareCmd")); } else { - httpHeaders = slPairNew("Cache-Control", "no-store"); + cgiAddHttpHeader("Cache-Control", "no-store"); cartHtmlShell("UCSC Genome Browser v"CGI_VERSION, doMiddle, hUserCookie(), excludeVars, oldVars); } // TODO: better place for this ? webIncludeResourceFile("font-awesome.min.css"); if (measureTiming) measureTime("Time to write and close cart"); if (measureTiming) { fprintf(stdout, "<span class='timing'>Overall total time: %ld millis<br /></span>\n", clock1000() - enteredMainTime); } cgiExitTime("hgTracks", enteredMainTime); // print out some resource usage stats struct rusage usage; int stat = getrusage(RUSAGE_SELF, &usage); if (stat == 0) // if you change this printf, then increment the number after RESOURCE: fprintf(stderr, "RESOURCE: 1 %ld %ld %ld\n",usage.ru_utime.tv_sec,usage.ru_stime.tv_sec, usage.ru_maxrss); return 0; }