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