7181c0af889a0eee451b91ff0b23d67f35e0e772
braney
  Tue Aug 18 08:39:08 2026 -0700
cheapcgi, customTrack, hgSession, hgPhyloPlace: track in-memory uploads in a registry

Uploaded file contents are handed to the reading code as a text address and
size.  Collect that bookkeeping in cheapcgi, which now records each block it
makes and hands back a name for it, and have the custom track, session and
phyloPlace upload paths look the block up by that name.

Also removes the duplicated address/size parsing those callers each had, and
makes lineFileDecompressMem ignore a too-small buffer.

refs #38108

diff --git src/hg/hgSession/hgSession.c src/hg/hgSession/hgSession.c
index 0f7eaa4de1c..96fab2a9824 100644
--- src/hg/hgSession/hgSession.c
+++ src/hg/hgSession/hgSession.c
@@ -1601,38 +1601,36 @@
 					hgsLoadLocalFileName "__binary");
     char *fileName = cartOptionalString(cart,
 					hgsLoadLocalFileName "__filename");
     if (isNotEmpty(filePlainContents))
 	{
 	char *settings = trimSpaces(filePlainContents);
 	dyStringAppend(dyMessage, "Loaded settings from local file ");
 	if (isNotEmpty(fileName))
 	    dyStringPrintf(dyMessage, "<B>%s</B> ", fileName);
 	dyStringPrintf(dyMessage, "(%lu bytes).",
 		       (unsigned long)strlen(settings));
 	lf = lineFileOnString("settingsFromFile", TRUE, cloneString(settings));
 	}
     else if (isNotEmpty(fileBinaryCoords))
 	{
-	char *binInfo = cloneString(fileBinaryCoords);
-	char *words[2];
-	char *mem;
-	unsigned long size;
-	chopByWhite(binInfo, words, ArraySize(words));
-	mem = (char *)sqlUnsignedLong(words[0]);
-	size = sqlUnsignedLong(words[1]);
-	lf = lineFileDecompressMem(TRUE, mem, size);
+	/* The cart holds the address and size of the uploaded bytes, but any
+	 * request can set that variable, so only use a block cheapcgi
+	 * handed out. */
+	unsigned long size = 0;
+	char *mem = cgiMemBlobFind(fileBinaryCoords, &size);
+	lf = (mem == NULL) ? NULL : lineFileDecompressMem(TRUE, mem, size);
 	if (lf != NULL)
 	    {
 	    dyStringAppend(dyMessage, "Loaded settings from local file ");
 	    if (isNotEmpty(fileName))
 		dyStringPrintf(dyMessage, "<B>%s</B> ", fileName);
 	    dyStringPrintf(dyMessage, "(%lu bytes).", size);
 	    }
 	else
 	    dyStringPrintf(dyMessage,
 			   "Sorry, I don't recognize the file type of "
 			   "<B>%s</B>.  Please submit plain text or "
 			   "compressed text in one of the formats offered in "
 			   "<B>Save Settings</B>.", fileName);
 	}
     else
@@ -1974,37 +1972,37 @@
     {
     if (endsWith(hel->name, "__binary"))
 	binaryParam = cloneString(hel->name);
     }
 
 if (!binaryParam)
     {
     htmlOpen("No file selected");
     printf("Please choose a saved session custom tracks local backup archive file (.tar.gz) to upload");
     htmlClose();
     exit(0);
     } 
 
 char *binaryValue = cartOptionalString(cart, binaryParam);
 
-char *binInfo = cloneString(binaryValue);
-char *words[2];
-char *mem;
-unsigned long size;
-chopByWhite(binInfo, words, ArraySize(words));
-mem = (char *)sqlUnsignedLong(words[0]);
-size = sqlUnsignedLong(words[1]);
+/* The cart holds the address and size of the uploaded bytes, but any request
+ * can set that variable, so only use a block cheapcgi handed out. */
+unsigned long size = 0;
+char *mem = cgiMemBlobFind(binaryValue, &size);
+if (mem == NULL)
+    errAbort("The contents of the uploaded file are no longer available.  "
+	     "Please choose the file again.");
 
 struct tempName tn;
 trashDirFile(&tn, "backGround", cartSessionId(cart), ".bin");
 
 writeGulp(tn.forCgi, mem, size); 
 
 // add new cart var with trash path
 // hgS_extractUpload_hub_9614_Anc11__filepath
 char *varName = replaceChars(binaryParam, "__binary", "__filepath");
 cartRemove(cart, varName);  // just in case
 cartSetString(cart, varName, tn.forCgi);  // update the cart
 }
 
 void hgSession()
 /* hgSession - Interface with wiki login and do session saving/loading.