130388103d6579f91a15a0922b5f237b689894b6
chmalee
  Tue May 18 15:56:51 2021 -0700
Fix hgTracks web browser caching again. This time allow CGIs to specify their own HTTP headers, as of now only hgTracks prevents caching. refs #26627

diff --git src/hg/lib/cart.c src/hg/lib/cart.c
index ce0c147..7327657 100644
--- src/hg/lib/cart.c
+++ src/hg/lib/cart.c
@@ -28,30 +28,32 @@
 #include "geoMirror.h"
 #include "hubConnect.h"
 #include "trackHub.h"
 #include "cgiApoptosis.h"
 #include "customComposite.h"
 #include "regexHelper.h"
 #include "windowsToAscii.h"
 
 static char *sessionVar = "hgsid";	/* Name of cgi variable session is stored in. */
 static char *positionCgiName = "position";
 
 DbConnector cartDefaultConnector = hConnectCart;
 DbDisconnect cartDefaultDisconnector = hDisconnectCart;
 static boolean cartDidContentType = FALSE;
 
+struct slPair *httpHeaders = NULL; // A list of headers to output before the content-type
+
 static void hashUpdateDynamicVal(struct hash *hash, char *name, void *val)
 /* Val is a dynamically allocated (freeMem-able) entity to put
  * in hash.  Override existing hash item with that name if any.
  * Otherwise make new hash item. */
 {
 struct hashEl *hel = hashLookup(hash, name);
 if (hel == NULL)
     hashAdd(hash, name, val);
 else
     {
     freeMem(hel->val);
     hel->val = val;
     }
 }
 
@@ -2279,48 +2281,59 @@
     setenv("no_proxy", noProxy, TRUE);
 char *logProxy = cfgOption("logProxy");
 if (logProxy)
     setenv("log_proxy", logProxy, TRUE);
 
 // if ignoreCookie is on the URL, don't check for cookies
 char *hguid = NULL;
 if (cgiOptionalString("ignoreCookie") == NULL)
     hguid = getCookieId(cookieName);
 char *hgsid = getSessionId();
 struct cart *cart = cartNew(hguid, hgsid, exclude, oldVars);
 cartExclude(cart, sessionVar);
 return cart;
 }
 
+static void addHttpHeaders()
+/* CGIs can initialize the global variable httpHeaders to control their own HTTP
+ * headers. This allows, for example, to prevent web browser caching of hgTracks
+ * responses, but implicitly allow web browser caching everywhere else */
+{
+struct slPair *h;
+for (h = httpHeaders; h != NULL; h = h->next)
+    {
+    printf("%s: %s\n", h->name, (char *)h->val);
+    }
+}
+
 struct cart *cartAndCookieWithHtml(char *cookieName, char **exclude,
                                    struct hash *oldVars, boolean doContentType)
 /* Load cart from cookie and session cgi variable.  Write cookie
  * and optionally content-type part HTTP preamble to web page.  Don't
  * write any HTML though. */
 {
 // Note: early abort works fine but early warn does not
 htmlPushEarlyHandlers();
 struct cart *cart = cartForSession(cookieName, exclude, oldVars);
 popWarnHandler();
 popAbortHandler();
 
 cartWriteCookie(cart, cookieName);
 if (doContentType && !cartDidContentType)
     {
+    addHttpHeaders();
     puts("Content-Type:text/html");
-    // disable web browsers from caching CGI responses:
-    puts("Cache-Control: no-cache");
     puts("\n");
     cartDidContentType = TRUE;
     }
 return cart;
 }
 
 struct cart *cartAndCookie(char *cookieName, char **exclude,
                            struct hash *oldVars)
 /* Load cart from cookie and session cgi variable.  Write cookie and
  * content-type part HTTP preamble to web page.  Don't write any HTML though. */
 {
 return cartAndCookieWithHtml(cookieName, exclude, oldVars, TRUE);
 }
 
 struct cart *cartAndCookieNoContent(char *cookieName, char **exclude,