5a249cd50f592a3b7598110eec792cfc942fab3f
max
Wed Sep 9 08:52:06 2026 -0700
Address the v504 code review
hgSession: an anonymous share name that arrives with the request is saved only
when it is not already in the table. Every anonymous link sits under the one
reserved user "l", so a name already there stays as it is and the caller is told
so. The top-right Share dialog is unaffected, since it passes a name it has
just reserved and such a name does not exist yet. Snapshot names are now left
out of both My Sessions listings, which is what their "__" prefix has claimed
all along.
Share dialog: "Create link & copy" reports the copy instead of promising it.
copyToClipboard says whether the text reached the clipboard, the dialog passes
that on when a browser refuses, and it tries the asynchronous clipboard API
before giving up. The preview is built with the same encoding the server uses,
so a name holding a hyphen or a slash previews as the link that really gets
made. Cancelling out of the name editor no longer copies a second time, and a
reply with no link in it says so rather than showing "undefined".
hgBlat: a second click on the share button while the first request is still out
no longer mints a second snapshot session, and a box dismissed during the wait
stays closed.
Also: a snapshot moves a cart value into durable storage only when it is a
trash path, the way sessionData's own callers check; sqlAddressMatch keeps to
its own documented precondition when handed an empty address; alphaGenomeToWig
compares its output with its input rather than with itself, rejects a position
that is not all digits and skips an empty score; and hgc's default iframe width
reaches the browser as one percent sign.
refs #38294
diff --git src/hg/hgc/hgc.c src/hg/hgc/hgc.c
index 03d3741d2ab..6c1dc70566b 100644
--- src/hg/hgc/hgc.c
+++ src/hg/hgc/hgc.c
@@ -945,49 +945,54 @@
/* Prepare an iframe with the URL specified in trackDb (iframeUrl), can have
* the standard codes in it (like $$ for itemName, etc)
* The iframe is not written out here: it is held back and printed by
* printPendingIframe(), just after the position / "View DNA" block, so it shows
* up with the rest of the item details instead of above them. refs #37595
*/
{
char *url = getUrlSetting(tdb, "iframeUrl");
if (url==NULL)
return;
char *eUrl = replaceInUrl(url, itemName, cart, database, seqName, winStart, winEnd,
tdb->track, FALSE, NULL);
if (eUrl==NULL)
return;
-char *iframeOptions = trackDbSettingOrDefault(tdb, "iframeOptions", "width='100%%' height='1024'");
+/* One percent sign, not two: this is an argument to the dyStringCreate below, not part of its
+ * format string, so a doubled one would reach the browser as a doubled one. */
+char *iframeOptions = trackDbSettingOrDefault(tdb, "iframeOptions", "width='100%' height='1024'");
// Resizing requires the hgcDetails pages to include a bit of javascript.
//
// Explanation how this works and why the javascript is needed:
// http://stackoverflow.com/questions/153152/resizing-an-iframe-based-on-content
// In short:
// - iframes have a fixed size in html, resizing can only be done in javascript
// - the iframed page cannot call the resize() function in the hgc html directly, as they have
// been loaded from different webservers
// - one way around it is that the iframed page includes a helper page on our server and
// send their size to the helper page (pages can call functions of included pages)
// - the helper page then sends the size back to hgc (pages on the same server can
// call each others' functions)
// width='%s' height='%s' src='%s' seamless scrolling='%s' frameborder='%s'
// The nonce is required: our CSP puts a nonce in script-src, which makes
// browsers ignore 'unsafe-inline', so an un-nonced inline script never runs.
// The script stays here, ahead of the iframe, so resizeIframe is defined
// before the iframed page loads and calls it.
+/* Only one iframe is queued at a time. Every caller pairs with a printPos/bedPrintPos that
+ * flushes it, and printTrackHtml is a backstop on the paths that do not, so a second call while
+ * one is still queued would mean a new caller has skipped both. */
dyStringFree(&pendingIframe);
pendingIframe = dyStringCreate("
\
\
\
\
", getNonce(), eUrl, iframeOptions); } void printPendingIframe() /* Write out the iframe queued up by printIframe(), if there is one. Called from