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/lib/snapshotSession.c src/hg/lib/snapshotSession.c
index b85d37d18e8..007a24897be 100644
--- src/hg/lib/snapshotSession.c
+++ src/hg/lib/snapshotSession.c
@@ -2,30 +2,31 @@
 
 /* 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 "dystring.h"
 #include "cheapcgi.h"
 #include "jksql.h"
 #include "cart.h"
 #include "hgConfig.h"
 #include "portable.h"
 #include "md5.h"
 #include "htmshell.h"
 #include "sessionData.h"
+#include "trashDir.h"
 #include "snapshotSession.h"
 
 /* Bits of randomness in a server-generated snapshot token.  128 bits -> ~24 URL-safe chars, so
  * collisions are astronomically unlikely; snapshotNewName() also checks the DB and retries, so the
  * name is guaranteed unique regardless. */
 #define snapshotTokenBits 128
 
 /* ---- Registry of snapshot types ------------------------------------------------------------- */
 
 /* BLAT: a single alignment (or the hgBlat results table) rebuilds from just the pinned bigPsl file;
  * the query sequence lives inside the bigPsl, so no .fa/.pslx is needed.  "db" is added implicitly. */
 static char *blatVars[] = { "blatLastBigBed", NULL };
 
 static struct snapshotType snapshotTypes[] =
     {
@@ -131,33 +132,36 @@
 struct dyString *dy = dyStringNew(512);
 
 char *db = cartOptionalString(cart, "db");
 if (isNotEmpty(db))
     appendVar(dy, "db", db);
 
 int i;
 for (i = 0;  type->vars[i] != NULL;  i++)
     {
     char *var = type->vars[i];
     char *val = cartOptionalString(cart, var);
     if (isEmpty(val))
         continue;
     /* Move the referenced trash file into durable storage when sessionData is configured, and store
      * the durable path.  sessionDataSaveTrashFile returns NULL if the file is gone (expired) - in
-     * that case keep the original value so the reconstruct path can report a clean "expired". */
+     * that case keep the original value so the reconstruct path can report a clean "expired".
+     *   Only a trash path is ours to move, and the value came out of the cart, so check it the way
+     * sessionData.c's own callers do.  A value that is already a durable path (a snapshot being
+     * re-shared) or anything else is stored as it stands. */
     char *durable = NULL;
-    if (isNotEmpty(sessionDir))
+    if (isNotEmpty(sessionDir) && isTrashPath(val))
         durable = sessionDataSaveTrashFile(val, sessionDir);
     appendVar(dy, var, isNotEmpty(durable) ? durable : val);
     freez(&durable);
     }
 freez(&sessionDir);
 return dyStringCannibalize(&dy);
 }
 
 int saveSnapshotSession(struct sqlConnection *conn, char *snapshotTypeName,
                         char *encUserName, char *encSessionName, struct cart *cart)
 /* See snapshotSession.h. */
 {
 struct snapshotType *type = snapshotTypeFind(snapshotTypeName);
 if (type == NULL)
     errAbort("saveSnapshotSession: unknown snapshot type '%s'", snapshotTypeName);