3eedbb7636648978b0371f2c54378e75fd1ac78c braney Fri Sep 11 12:20:14 2026 -0700 Skip a CGI or cookie pair with no =value in three more parsers, refs #38340 The loop that #38335 fixed in the query string parsers is copied in three more places, and each one still looks for the '=' across the whole rest of the string instead of inside the pair it is reading. A pair with no value therefore runs into the pair after it and takes its value, and the same pair at the end of the string has no '=' left to find and aborts. lib/cheapcgi.c parseCookies one bad cookie aborts every CGI for that browser, on every request, until the reader clears the cookie by hand hg/hgSession/backup.c a session backup silently leaves out a custom track hg/utils/refreshNamedSessionCustomTracks one bad session aborts the child, the parent exits non-zero, and every session after it goes unscanned, so the trash cleaner removes their custom track files All three are behind the hg.conf flag skipMalformedCgiPairs, off by default, and registered as a release gate in hgConfCatalog. The kent libraries do not read hg.conf, so hgConfig.c hands the setting to cheapcgi the way cfgSetLogCgiVars already hands it cgiSetMaxLogLen. The query string parsers do not read the flag; they were fixed unconditionally under #38335. refreshNamedSessionCustomTracks rebuilds the session contents as it walks, so it copies a malformed pair through untouched rather than stepping over it. A session carrying one comes back byte for byte the same. Adds lib/tests/cgiCookieTest and hg/hgSession/tests/backupParseTest. Both read every case with the flag off and on, so they pin the old behavior as well as the new one. The nightly tool has no seam for a unit test; its loop sits inside a function that runs its own query. Co-Authored-By: Claude Opus 5 (1M context) diff --git src/hg/utils/hgConfCatalog/hgConfCatalog.py src/hg/utils/hgConfCatalog/hgConfCatalog.py index 24152d01a8a..4d2713464ec 100755 --- src/hg/utils/hgConfCatalog/hgConfCatalog.py +++ src/hg/utils/hgConfCatalog/hgConfCatalog.py @@ -248,30 +248,39 @@ "vars": [ h("showTxCodonNumbers", "flag", "hg/hgTracks/cds.c", default="FALSE", role="gate", verified=True, ticket="38298", note="A second codon number in the gene-track codon mouseover, counted in the " "transcript's own coordinates, for a transcript that aligns with bases the " "assembly does not have. The number the browser has always shown is counted " "along the genome, so for those transcripts it disagrees with the number NCBI " "reports, by one codon per three missing bases. It affects 58 coding " "transcripts on hg38's primary chromosomes but 656 on canFam3, and gets worse " "the poorer the assembly. With the gate on, such codons also draw in the " "browser's existing query-insertion orange with a \"!\" after the codon " "number. Read once in txCodonNumbersEnabled(); with it off no alignment is " "looked up, no codon carries a transcript number, and the rendering and the " "mouseover are byte-identical to before. Off during QA; flip to TRUE once " "released."), + h("skipMalformedCgiPairs", "flag", "lib/cheapcgi.c", default="FALSE", + role="gate", verified=True, ticket="38340", + note="Step over a CGI or cookie pair that has no =value, instead of losing the " + "pair after it or aborting the request. Covers parseCookies in cheapcgi, " + "hgSession's session backup, and refreshNamedSessionCustomTracks. The query " + "string parsers were fixed unconditionally under #38335 and do not read this " + "flag. The kent libraries cannot read hg.conf, so hgConfig.c hands the " + "setting to cheapcgi through cgiSkipMalformedPairs. Off during QA; flip to " + "TRUE once released."), h("collectionHubCopyOnWrite", "flag", "hg/lib/cart.c", default="FALSE", role="gate", verified=True, ticket="38273", note="Copy a track collection's generated hub file when the program that writes " "it (only hgCollection) asks for a copy, instead of on every session load. " "With it off, loading any session that carries a collection copies the hub to " "a new trash file and registers that copy in hgcentral.hubStatus, which is " "where 81% of the RR's 3.1M hubStatus rows came from. Read in " "cartCollectionHubCopyOnWrite() and branched on at four places in three " "files: cart.c makes the copy when cartRequestLocalHubCopy() was called, and " "skips a hub the cart already owns in copyLocalHubs(); " "cartCopyLocalHubsOnSessionLoad() does nothing (that one is the old behavior, " "and it plus its five callers in cart.c and hgSession.c go away with the " "gate); sessionData.c's saveTrackFile splits a hub that came from another " "session. Off during QA; flip to TRUE once released."), h("bigNet", "flag", "hg/lib/trackHub.c", default="FALSE",