09f26ed9a7dcc52b03b4d3e5b2f97c5177cd9334
max
Mon Sep 21 06:00:40 2026 -0700
Drop the ${hgsid} trackDb variable; add session ids to links in the browser instead
A description page's links can carry the session id without the page itself holding
one. addHgsidToLinks() in utils.js walks the rendered page and appends hgsid to every
that stays on this host and points into the same cgi-bin directory: a relative
CGI link gets one, a static .html, a link to another host, a mailto and a plain #anchor
do not, and a link that already names a session is left alone. hgc and hgTrackUi call
it through a new jsAddHgsidToLinks(), and hgTracks.js calls it on the track description
popup once the ajax content is in. A link written with a literal $hgsid is rewritten
rather than skipped, so the description pages already deployed in the GenArk hubs work
again.
hVarSubst no longer knows about hgsid: it is out of the trackDb variable list, so
hVarSubstTrackDbHtml is a hub-only pass again and needs no cart, and hVarSubstWithCart
and webIncludeHelpFileSubst, which existed only to resolve it, are gone. The variable
is taken out of the trackDb README and out of the twenty-odd description pages that
used it.
refs #38380
diff --git src/hg/lib/tests/hVarSubstHtmlTester.c src/hg/lib/tests/hVarSubstHtmlTester.c
index 4e5a0c27573..346fcc44b1a 100644
--- src/hg/lib/tests/hVarSubstHtmlTester.c
+++ src/hg/lib/tests/hVarSubstHtmlTester.c
@@ -1,138 +1,91 @@
/* hVarSubstHtmlTester - check which variables a track description page may use.
*
- * hVarSubstTrackDbHtml() runs over a track's description page at render time. How much it
- * is allowed to substitute depends on where the page came from, and #38283 is that split.
+ * hVarSubstTrackDbHtml() runs over a hub track's description page at render time. A hub's
+ * page comes straight off somebody else's web server and has never been substituted, so a
+ * short explicit list of variables is resolved here. A native page went through hgTrackDb
+ * when trackDb was loaded, so it is left alone.
*
- * A NATIVE page has already been through hgTrackDb, which resolved everything it could and
- * deferred only ${hgsid}, since a session id is per-request and cannot be baked into the
- * trackDb table. So this pass acts on ${hgsid} alone, and only in braces: hgTrackDb turns
- * an escaped $$hgsid into a literal $hgsid, and acting on the bare form here would expand
- * the very thing the author escaped.
+ * No session id is on that list, and none is available anywhere in hVarSubst. A description
+ * page is only lightly sanitized -- an assembly $db assembly ${db} $$db costs $5 million with an http src survives it -- so a page
+ * containing
would hand the reader's session id to
+ * the page's author, and a session id alone is enough to read and write that cart. The links
+ * in a description page get their session id in the browser instead, from addHgsidToLinks()
+ * in utils.js, which only touches links that stay on this server.
*
- * A HUB page comes straight off somebody else's web server and has never been substituted,
- * so the whole hub list is resolved here -- and $hgsid is deliberately NOT on that list. A
- * hub's page is only lightly sanitized, an
with an http src survives it, and a page
- * containing
would hand the reader's session
- * id to the hub's own server. A session id alone is enough to read and write that cart.
+ * That is the case this test exists for, and it is invisible twice over: the page renders
+ * identically either way, and the leak is a request to somebody else's host.
*
- * That last one is the case this test exists for, and it is invisible twice over: the page
- * renders identically either way, and the leak is a request to somebody else's host.
- *
- * It needs a cart to pin, and that is worth saying because the obvious cheaper version does
- * not work. A run with no cart leaves ${hgsid} on the page whether or not hgsid is on the
- * hub list, because the check that recognises a variable also asks whether this call can
- * resolve it, and with no cart it cannot. Adding hgsid back to hubHtmlVars was tried
- * against a cartless version of this test and changed not one line of its output. So the
- * cart below is built by hand -- cartSessionId reads two fields of it and nothing else, so
- * no database is involved -- and the assertion is that a hub page still carries the literal
- * ${hgsid} while a native page has it replaced by the session id.
- *
- * refs #38283 */
+ * refs #38380 */
/* Copyright (C) 2026 The Regents of the University of California
* See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */
#include "common.h"
#include "hash.h"
#include "trackDb.h"
-#include "cart.h"
-#include "cartDb.h"
#include "hVarSubst.h"
/* An assembly that is certainly present, for the variables that ask hdb about one. */
#define DB "hg38"
-static struct cart *fakeCart()
-/* A cart with just enough in it for cartSessionId, which reads the session id and key and
- * nothing else. No database: a real cart would need hgcentral, and what is being tested
- * here is which variables are allowed, not where a session comes from. */
-{
-struct cartDb *sessionInfo;
-AllocVar(sessionInfo);
-sessionInfo->id = 12345;
-sessionInfo->sessionKey = cloneString("abcdef");
-struct cart *cart;
-AllocVar(cart);
-cart->sessionInfo = sessionInfo;
-return cart;
-}
-
-static void showWith(struct cart *cart, char *what, char *trackName, char *html)
+static void show(char *what, char *trackName, char *html)
/* Run one description page through the substitution and print what came out. */
{
struct trackDb *tdb;
AllocVar(tdb);
tdb->track = cloneString(trackName);
tdb->table = cloneString(trackName);
tdb->type = cloneString("bed 3 .");
tdb->settings = cloneString("");
tdb->settingsHash = trackDbSettingsFromString(tdb, tdb->settings);
tdb->html = cloneString(html);
-hVarSubstTrackDbHtml(cart, tdb, DB);
+hVarSubstTrackDbHtml(tdb, DB);
printf(" %-30s %-34s -> %s\n", what, html, tdb->html);
}
-static void show(char *what, char *trackName, char *html)
-/* The common case: a render with a session, which is what a CGI always has. */
-{
-showWith(fakeCart(), what, trackName, html);
-}
-
static void hubPage()
/* track names beginning hub_ take the hub list. */
{
char *track = "hub_1_myTrack";
printf("a hub's description page\n");
show("$db resolves", track, "
");
show("${hgsid} is NOT a variable", track, "
");
show("a price is not a variable", track, "
assembly $db
"); show("a price is not a variable", track, "costs $5 million
"); } -static void noSession() -/* hgTrackDb and the command line have no cart. Nothing may be invented there, and nothing - * may crash. */ -{ -printf("\nwith no cart at all\n"); -showWith(NULL, "hub page, ${hgsid}", "hub_1_myTrack", - "assembly $db
"); -} - static void nothingToDo() /* The cases that must not crash or invent a page. */ { printf("\nnothing to substitute\n"); -show("no dollar at all", "knownGene", "plain
"); -show("empty page", "knownGene", ""); +show("no dollar at all", "hub_1_myTrack", "plain
"); +show("empty page", "hub_1_myTrack", ""); struct trackDb *tdb = NULL; -hVarSubstTrackDbHtml(fakeCart(), tdb, DB); +hVarSubstTrackDbHtml(tdb, DB); printf(" %-30s %s\n", "a NULL track", "returned, no crash"); } int main(int argc, char *argv[]) { hubPage(); nativePage(); -noSession(); nothingToDo(); printf("\n"); return 0; }