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/lib/customFactory.c src/hg/lib/customFactory.c index 718f748183a..5f01d3c78ed 100644 --- src/hg/lib/customFactory.c +++ src/hg/lib/customFactory.c @@ -1,30 +1,31 @@ /* customFactory - a polymorphic object for handling * creating various types of custom tracks. */ /* Copyright (C) 2014 The Regents of the University of California * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */ #include <pthread.h> #include "common.h" #include "errCatch.h" #include "hash.h" #include "linefile.h" #include "portable.h" #include "obscure.h" #include "binRange.h" #include "pipeline.h" +#include "cheapcgi.h" #include "jksql.h" #include "net.h" #include "bed.h" #include "psl.h" #include "gff.h" #include "wiggle.h" #include "genePred.h" #include "trackDb.h" #include "hgConfig.h" #include "hdb.h" #include "hui.h" #include "customTrack.h" #include "customPp.h" #include "customFactory.h" #include "trashDir.h" @@ -4109,68 +4110,85 @@ } static struct customTrack *trackLineToTrack(char *genomeDb, char *line, int lineIx) /* Convert a track specification line to a custom track structure. */ { /* Make up basic track with associated tdb. Fill in settings * from var=val pairs in line. */ struct customTrack *track; AllocVar(track); struct trackDb *tdb = customTrackTdbDefault(); track->tdb = tdb; customTrackUpdateFromSettings(track, genomeDb, line, lineIx); return track; } +static char *customMemFromSpec(char *text, char **retName, unsigned long *retSize) +/* Parse a "<scheme>://<name> <address> <size>" string made by prepCompressedFile + * or prepBigData, and return the uploaded data it names. Return NULL unless + * this program handed out that address: such a string can also arrive in a cgi + * variable, and then the address comes from whoever sent the request. If + * retName is not NULL the "<scheme>://<name>" part is cloned into it. */ +{ +char *copy = cloneString(text); +char *words[4]; +int wordCount = chopByWhite(copy, words, ArraySize(words)); +char *mem = NULL; +/* A registered address and size are each an unsigned long, at most 20 digits. + * A longer word cannot name a block we handed out, so leave mem NULL and let + * the caller fall back to treating the text as literal data. */ +if (wordCount == 3 && strlen(words[1]) <= 20 && strlen(words[2]) <= 20) + { + char spec[64]; + safef(spec, sizeof(spec), "%s %s", words[1], words[2]); + mem = cgiMemBlobFind(spec, retSize); + if (mem != NULL && retName != NULL) + *retName = cloneString(words[0]); + } +freeMem(copy); +return mem; +} + static struct lineFile *customLineFile(char *text, boolean isFile) /* Figure out input source, handling URL's and compression */ { if (!text) return NULL; struct lineFile *lf = NULL; if (isFile) { if (stringIn("://", text)) lf = netLineFileOpen(text); else lf = lineFileOpen(text, TRUE); } else { - if (startsWith("compressed://",text)) + if (startsWith("compressed://",text) || startsWith("memory://", text)) { - char *words[3]; - char *mem; - unsigned long size; - chopByWhite(text,words,3); - mem = (char *)sqlUnsignedLong(words[1]); - size = sqlUnsignedLong(words[2]); + char *name = NULL; + unsigned long size = 0; + char *mem = customMemFromSpec(text, &name, &size); + if (mem == NULL) + /* Not data this program uploaded, so it is just text that happens + * to look like a reference to some. */ + lf = lineFileOnString(CT_NO_FILE_NAME, TRUE, text); + else if (startsWith("compressed://", text)) lf = lineFileDecompressMem(TRUE, mem, size); - } - else if (startsWith("memory://", text)) - { - int len = strlen(text) + 1; - char copy[len]; - safecpy(copy, len, text); - char *words[3]; - int wordCount = chopByWhite(copy, words, 3); - if (wordCount != 3) - errAbort("customLineFile: badly formatted input '%s': expected 3 words, got %d", - text, wordCount); - char *mem = (char *)sqlUnsignedLong(words[1]); - lf = lineFileOnString(words[0], TRUE, mem); + else + lf = lineFileOnString(name, TRUE, mem); } else { lf = lineFileOnString(CT_NO_FILE_NAME, TRUE, text); } } return lf; } char *customDocParse(char *text) /* Return description text, expanding URLs as for custom track data */ { char *line; struct lineFile *lf = customLineFile(text, FALSE); if (!lf)