f73fe5e18b354f9595d22a4c2961b7b98b250b6a jcasper Mon Mar 16 01:31:11 2026 -0700 First pass at a tool for users to fetch content from CORS-enabled track files, refs #36320 diff --git src/hg/hgFetch/hgFetch.c src/hg/hgFetch/hgFetch.c new file mode 100644 index 00000000000..ac455856f02 --- /dev/null +++ src/hg/hgFetch/hgFetch.c @@ -0,0 +1,94 @@ +/* hgFetch - Fetch and provide remote content associated with hubs for UIs running +afoul of CORS restrictions. */ +#include "common.h" +#include "linefile.h" +#include "hash.h" +#include "options.h" +#include "jksql.h" +#include "htmshell.h" +#include "web.h" +#include "cheapcgi.h" +#include "cart.h" +#include "hui.h" +#include "udc.h" +#include "knetUdc.h" +#include "genbank.h" +#include "hubConnect.h" +#include "filePath.h" + +/* Global Variables */ +struct cart *cart; /* CGI and other variables */ +struct hash *oldVars = NULL; + +boolean fileUrlMatchesHub(char *fileUrl, struct hubConnectStatus *hubStatus) +{ +char baseDir[2048]; +splitPath(hubStatus->hubUrl, baseDir, NULL, NULL); +return startsWith(baseDir, fileUrl); +} + +void doMiddle(struct cart *theCart) +/* Set up globals, do sanity checks, and generate response */ +{ +cart = theCart; +char *database = NULL; +char *genome = NULL; +getDbAndGenome(cart, &database, &genome, oldVars); +initGenbankTableNames(database); + +int timeout = cartUsualInt(cart, "udcTimeout", 300); +if (udcCacheTimeout() < timeout) + udcSetCacheTimeout(timeout); +knetUdcInstall(); + +char *fileUrl = cartOptionalString(cart, "fileUrl"); +if (fileUrl == NULL) + { + puts("Status: 400 Bad Request"); + errAbort("Missing required parameter: fileUrl"); + } + +cgiDecode(fileUrl, fileUrl, strlen(fileUrl)); +boolean matchFound = FALSE; + +// Next task: Need to first check local dirs for genark hubs, valid local tracks +// + +struct slName *hubIds = hubConnectHubsInCart(cart); +struct slName *thisHubId = hubIds; +while (thisHubId != NULL) + { + struct hubConnectStatus *hubStatus = hubFromId(sqlUnsigned(thisHubId->name)); + if (fileUrlMatchesHub(fileUrl, hubStatus)) + { + matchFound = TRUE; + break; + } + thisHubId = thisHubId->next; + } +if (!matchFound) + { + puts("Status: 400 Bad Request"); + errAbort("Supplied fileUrl does not match any connected hubs."); + } + +// By now we know that fileUrl points to something valid to fetch and return to the user. +// Now we just have to fetch the file contents and retransmit it. +puts("Content-Type: text/plain\n\n"); // Hacky, but functional for now + +char *content = udcFileReadAll(fileUrl, NULL, 0, NULL); +puts(content); +freeMem(content); +} + +/* Null terminated list of CGI Variables we don't want to save + * permanently. */ +char *excludeVars[] = {"Submit", "submit", "fileUrl", NULL,}; + +int main(int argc, char *argv[]) +/* Process command line. */ +{ +cgiSpoof(&argc, argv); +cartEmptyShellNoContent(doMiddle, hUserCookie(), excludeVars, oldVars); +return 0; +}