706c8c2b49fcbd941c9da43c1b8a950c0c33f5ba
galt
  Mon Feb 10 23:54:13 2014 -0800
now converting hgsid and hguid to strings. when the hgsid cart var or hguid cookie is not found it returns NULL instead of 0.
diff --git src/hg/lib/cart.c src/hg/lib/cart.c
index 99d36e7..a16a699 100644
--- src/hg/lib/cart.c
+++ src/hg/lib/cart.c
@@ -48,61 +48,71 @@
 }
 
 void cartTrace(struct cart *cart, char *when, struct sqlConnection *conn)
 /* Write some properties of the cart to stderr for debugging. */
 {
 if (cfgOption("cart.trace") == NULL)
     return;
 struct cartDb *u = cart->userInfo, *s = cart->sessionInfo;
 char *pix = hashFindVal(cart->hash, "pix");
 char *textSize = hashFindVal(cart->hash, "textSize");
 char *trackControls = hashFindVal(cart->hash, "trackControlsOnMain");
 int uLen, sLen;
 if (conn != NULL)
     {
     /* Since the content string is chopped, query for the actual length. */
-    char query[1024];
-    sqlSafef(query, sizeof(query), "select length(contents) from userDb "
+    struct dyString *query = dyStringNew(1024);
+    sqlDyStringPrintf(query, "select length(contents) from userDb"
 	  " where id = %d", u->id);
-    uLen = sqlQuickNum(conn, query);
-    sqlSafef(query, sizeof(query), "select length(contents) from sessionDb "
+    if (cartDbUseSessionKey())
+	  sqlDyStringPrintf(query, " and sessionKey='%s'", u->sessionKey);
+    uLen = sqlQuickNum(conn, query->string);
+    dyStringClear(query);
+    sqlDyStringPrintf(query, "select length(contents) from sessionDb"
 	  " where id = %d", s->id);
-    sLen = sqlQuickNum(conn, query);
+    if (cartDbUseSessionKey())
+	  sqlDyStringPrintf(query, " and sessionKey='%s'", s->sessionKey);
+    sLen = sqlQuickNum(conn, query->string);
+    dyStringFree(&query);
     }
 else
     {
     uLen = strlen(u->contents);
     sLen = strlen(s->contents);
     }
 if (pix == NULL)
     pix = "-";
 if (textSize == NULL)
     textSize = "-";
 if (trackControls == NULL)
     trackControls = "-";
 fprintf(stderr, "ASH: %22s: "
 	"u.i=%d u.l=%d u.c=%d s.i=%d s.l=%d s.c=%d "
 	"p=%s f=%s t=%s pid=%ld %s\n",
 	when,
 	u->id, uLen, u->useCount, s->id, sLen, s->useCount,
 	pix, textSize, trackControls, (long)getpid(), cgiRemoteAddr());
-if (cart->userId != 0 && u->id != cart->userId)
-    fprintf(stderr, "ASH: bad userId %d --> %d!  pid=%ld\n",
-	    cart->userId, u->id, (long)getpid());
-if (cart->sessionId != 0 && s->id != cart->sessionId)
-    fprintf(stderr, "ASH: bad sessionId %d --> %d!  pid=%ld\n",
-	    cart->sessionId, s->id, (long)getpid());
+char userIdKey[256];
+cartDbSecureId(userIdKey, sizeof userIdKey, u);
+if (cart->userId && !sameString(userIdKey, cart->userId))
+    fprintf(stderr, "ASH: bad userId %s --> %d_%s!  pid=%ld\n",
+	    cart->userId, u->id, u->sessionKey, (long)getpid());
+char sessionIdKey[256];
+cartDbSecureId(sessionIdKey, sizeof sessionIdKey, s);
+if (cart->sessionId && !sameString(sessionIdKey, cart->sessionId))
+    fprintf(stderr, "ASH: bad sessionId %s --> %d_%s!  pid=%ld\n",
+	    cart->sessionId, s->id, s->sessionKey, (long)getpid());
 }
 
 boolean cartTablesOk(struct sqlConnection *conn)
 /* Return TRUE if cart tables are accessible (otherwise, the connection
  * doesn't do us any good). */
 {
 if (!sqlTableExists(conn, "userDb"))
     {
     fprintf(stderr, "ASH: cartTablesOk failed on %s.userDb!  pid=%ld\n",
 	    sqlGetDatabase(conn), (long)getpid());
     return FALSE;
     }
 if (!sqlTableExists(conn, "sessionDb"))
     {
     fprintf(stderr, "ASH: cartTablesOk failed on %s.sessionDb!  pid=%ld\n",
@@ -155,72 +165,88 @@
     else
 	{
 	time_t theTime = time(NULL);
 	struct tm *tm = localtime(&theTime);
 	int year = atoi(words[0]);
 	int month = atoi(words[1]);
 	if ((year < 2000) || (year > (1900+tm->tm_year)) ||
 	    (month < 1) || (month > 12))
 	    isCorr = TRUE;
 	}
     freez(&fu);
     return isCorr;
     }
 }
 
-struct cartDb *cartDbLoadFromId(struct sqlConnection *conn, char *table, int id)
+struct cartDb *cartDbLoadFromId(struct sqlConnection *conn, char *table, char *secureId)
 /* Load up cartDb entry for particular ID.  Returns NULL if no such id. */
 {
-if (id == 0)
+
+if (!secureId)
     return NULL;
 else
     {
     struct cartDb *cdb = NULL;
-   char where[64];
-   sqlSafefFrag(where, sizeof(where), "id = %u", id);
-   cdb = cartDbLoadWhere(conn, table, where);
+    struct dyString *where = dyStringNew(256);
+    char *sessionKey = NULL;	    
+    unsigned int id = cartDbParseId(secureId, &sessionKey);
+    sqlDyStringPrintfFrag(where, "id = %u", id);
+    if (cartDbUseSessionKey())
+	{
+	if (!sessionKey)
+	    sessionKey = "";
+	sqlDyStringPrintfFrag(where, " and sessionKey='%s'", sessionKey);
+	}
+    cdb = cartDbLoadWhere(conn, table, where->string);
+    dyStringFree(&where);
     if (looksCorrupted(cdb))
        {
        /* Can't use warn here -- it interrupts the HTML header, causing an
 	* err500 (and nothing useful in error_log) instead of a warning. */
        fprintf(stderr,
-	       "%s id=%d looks corrupted -- starting over with new %s id.\n",
+	       "%s id=%u looks corrupted -- starting over with new %s id.\n",
 	       table, id, table);
        cdb = NULL;
        }
     return cdb;
     }
 }
 
-struct cartDb *loadDb(struct sqlConnection *conn, char *table, int id, boolean *found)
+struct cartDb *loadDb(struct sqlConnection *conn, char *table, char *secureId, boolean *found)
 /* Load bits from database and save in hash. */
 {
 struct cartDb *cdb;
-char query[256];
 boolean result = TRUE;
 
-cdb = cartDbLoadFromId(conn, table, id);
+cdb = cartDbLoadFromId(conn, table, secureId);
 if (!cdb)
     {
     result = FALSE;
-    sqlSafef(query, sizeof(query), "INSERT %s VALUES(0,'',0,now(),now(),0%-s)",
-	  table,
-	  cartDbHasSessionKey(conn, table) ? ",''" : "");
-    sqlUpdate(conn, query);
-    id = sqlLastAutoId(conn);
-    if ((cdb = cartDbLoadFromId(conn,table,id)) == NULL)
-        errAbort("Couldn't get cartDb for id=%d right after loading.  "
+    struct dyString *query = dyStringNew(256);
+    sqlDyStringPrintf(query, "INSERT %s VALUES(0,'',0,now(),now(),0", table);
+    char *sessionKey = "";
+    // TODO should I be inserting a new random sessionKey value right now?
+    if (cartDbHasSessionKey(conn, table)) 
+	sqlDyStringPrintf(query, ",'%s'", sessionKey);
+    sqlDyStringPrintf(query, ")");
+    sqlUpdate(conn, query->string);
+    dyStringFree(&query);
+    unsigned int id = sqlLastAutoId(conn);
+    char newSecureId[256];
+    safef(newSecureId, sizeof newSecureId, "%u_%s", id, sessionKey);
+    if ((cdb = cartDbLoadFromId(conn,table,newSecureId)) == NULL)
+        errAbort("Couldn't get cartDb for id=%u right after loading.  "
 		 "MySQL problem??", id);
     }
 *found = result;
 return cdb;
 }
 
 void cartExclude(struct cart *cart, char *var)
 /* Exclude var from persistent storage. */
 {
 hashAdd(cart->exclude, var, NULL);
 }
 
 
 void sessionTouchLastUse(struct sqlConnection *conn, char *encUserName,
 			 char *encSessionName)
@@ -438,36 +464,36 @@
     errAbort("Please go back and enter a wiki user name for this session.");
 if (isEmpty(sessionName))
     errAbort("Please go back and enter a session name to load.");
 
 sqlSafef(query, sizeof(query), "SELECT shared, contents FROM %s "
       "WHERE userName = '%s' AND sessionName = '%s';",
       namedSessionTable, encSessionOwner, encSessionName);
 sr = sqlGetResult(conn, query);
 if ((row = sqlNextRow(sr)) != NULL)
     {
     boolean shared = atoi(row[0]);
     if (shared ||
 	(userName && sameString(sessionOwner, userName)))
 	{
 	char *sessionVar = cartSessionVarName();
-	unsigned hgsid = cartSessionId(cart);
+	char *hgsid = cartSessionId(cart);
 	struct sqlConnection *conn2 = hConnectCentral();
 	sessionTouchLastUse(conn2, encSessionOwner, encSessionName);
 	cartRemoveLike(cart, "*");
 	cartParseOverHash(cart, row[1]);
-	cartSetInt(cart, sessionVar, hgsid);
+	cartSetString(cart, sessionVar, hgsid);
 	if (oldVars)
 	    hashEmpty(oldVars);
 	/* Overload settings explicitly passed in via CGI (except for the
 	 * command that sent us here): */
 	loadCgiOverHash(cart, oldVars);
 #ifndef GBROWSE
 	cartCopyCustomTracks(cart);
 #endif /* GBROWSE */
 	if (isNotEmpty(actionVar))
 	    cartRemove(cart, actionVar);
 	hDisconnectCentral(&conn2);
 	}
     else
 	errAbort("Sharing has not been enabled for user %s's session %s.",
 		 sessionOwner, sessionName);
@@ -479,34 +505,34 @@
 freeMem(encSessionName);
 }
 #endif /* GBROWSE */
 
 void cartLoadSettings(struct lineFile *lf, struct cart *cart,
 		      struct hash *oldVars, char *actionVar)
 /* Load settings (cartDump output) into current session, and then
  * reload the CGI settings (to support override of session settings).
  * If non-NULL, oldVars will contain values overloaded when reloading CGI.
  * If non-NULL, actionVar is a cartRemove wildcard string specifying the
  * CGI action variable that sent us here. */
 {
 char *line = NULL;
 int size = 0;
 char *sessionVar = cartSessionVarName();
-unsigned hgsid = cartSessionId(cart);
+char *hgsid = cartSessionId(cart);
 
 cartRemoveLike(cart, "*");
-cartSetInt(cart, sessionVar, hgsid);
+cartSetString(cart, sessionVar, hgsid);
 while (lineFileNext(lf, &line, &size))
     {
     char *var = nextWord(&line);
     char *val = line;
 
     if (sameString(var, sessionVar))
 	continue;
     else
 	{
 	if (val != NULL)
 	    {
 	    struct dyString *dy = dyStringSub(val, "\\n", "\n");
 	    cartAddString(cart, var, dy->string);
 	    dyStringFree(&dy);
 	    }
@@ -557,72 +583,72 @@
 struct cart *cart;
 AllocVar(cart);
 cart->hash = hash;
 cart->exclude = newHash(7);
 cart->userInfo = emptyCartDb();
 cart->sessionInfo = emptyCartDb();
 return cart;
 }
 
 struct cart *cartOfNothing()
 /* Create a new, empty, cart with no real connection to the database. */
 {
 return cartFromHash(newHash(0));
 }
 
-struct cart *cartFromCgiOnly(unsigned int userId, unsigned int sessionId,
+struct cart *cartFromCgiOnly(char *userId, char *sessionId,
 	char **exclude, struct hash *oldVars)
 /* Create a new cart that contains only CGI variables, nothing from the
  * database. */
 {
 struct cart *cart = cartOfNothing();
 cart->userId = userId;
 cart->sessionId = sessionId;
 loadCgiOverHash(cart, oldVars);
 
 if (exclude != NULL)
     {
     char *ex;
     while ((ex = *exclude++))
 	cartExclude(cart, ex);
     }
 return cart;
 }
 
-struct cart *cartNew(unsigned int userId, unsigned int sessionId,
+struct cart *cartNew(char *userId, char *sessionId,
                      char **exclude, struct hash *oldVars)
 /* Load up cart from user & session id's.  Exclude is a null-terminated list of
  * strings to not include */
 {
 struct cart *cart;
 struct sqlConnection *conn = cartDefaultConnector();
 char *ex;
 boolean userIdFound = FALSE, sessionIdFound = FALSE;
 
 AllocVar(cart);
 cart->hash = newHash(12);
 cart->exclude = newHash(7);
 cart->userId = userId;
 cart->sessionId = sessionId;
 cart->userInfo = loadDb(conn, "userDb", userId, &userIdFound);
 cart->sessionInfo = loadDb(conn, "sessionDb", sessionId, &sessionIdFound);
 if (sessionIdFound)
     cartParseOverHash(cart, cart->sessionInfo->contents);
 else if (userIdFound)
     cartParseOverHash(cart, cart->userInfo->contents);
 char when[1024];
-safef(when, sizeof(when), "open %d %d", userId, sessionId);
+safef(when, sizeof(when), "open %s %s", userId, sessionId);
 cartTrace(cart, when, conn);
 
 loadCgiOverHash(cart, oldVars);
 
 // I think this is the place to justify old and new values
 cartJustify(cart, oldVars);
 
 #ifndef GBROWSE
 /* If some CGI other than hgSession been passed hgSession loading instructions,
  * apply those to cart before we do anything else.  (If this is hgSession,
  * let it handle the settings so it can display feedback to the user.) */
 if (! (cgiScriptName() && endsWith(cgiScriptName(), "hgSession")))
     {
     if (cartVarExists(cart, hgsDoOtherUser))
 	{
@@ -742,48 +768,52 @@
     cartDefaultDisconnector(&conn);
     cartDbFree(&cart->userInfo);
     cartDbFree(&cart->sessionInfo);
     freeHash(&cart->hash);
     freeHash(&cart->exclude);
     freez(pCart);
     }
 }
 
 char *cartSessionVarName()
 /* Return name of CGI session ID variable. */
 {
 return sessionVar;
 }
 
-unsigned int cartSessionId(struct cart *cart)
+char *cartSessionId(struct cart *cart)
 /* Return session id. */
 {
-return cart->sessionInfo->id;
+static char buf[256];
+cartDbSecureId(buf, sizeof buf, cart->sessionInfo);
+return buf;
 }
 
 char *cartSidUrlString(struct cart *cart)
 /* Return session id string as in hgsid=N . */
 {
 static char buf[64];
-safef(buf, sizeof(buf), "%s=%u", cartSessionVarName(), cartSessionId(cart));
+safef(buf, sizeof(buf), "%s=%s", cartSessionVarName(), cartSessionId(cart));
 return buf;
 }
 
-unsigned int cartUserId(struct cart *cart)
+char *cartUserId(struct cart *cart)
 /* Return session id. */
 {
-return cart->userInfo->id;
+static char buf[256];
+cartDbSecureId(buf, sizeof buf, cart->userInfo);
+return buf;
 }
 
 static char *cartMultShadowVar(struct cart *cart, char *var)
 /* Return a pointer to the list variable shadow variable name for var.
  * Don't modify or free result. */
 {
 static char multShadowVar[PATH_LEN];
 safef(multShadowVar, sizeof(multShadowVar), "%s%s", cgiMultListShadowPrefix(), var);
 return multShadowVar;
 }
 
 static int cartRemoveAndCountNoShadow(struct cart *cart, char *var)
 /* Remove variable from cart, returning count of removed vars. */
 {
 int removed = 0;
@@ -1313,88 +1343,97 @@
 struct hashEl *cartFindPrefix(struct cart *cart, char *prefix)
 /* Return list of name/val pairs from cart where name starts with
  * prefix.  Free when done with hashElFreeList. */
 {
 return cartFindSome(cart, prefix, startsWith);
 }
 
 
 static char *cookieDate()
 /* Return date string for cookie format.   We'll have to
  * revisit this in 35 years.... */
 {
 return "Thu, 31-Dec-2037 23:59:59 GMT";
 }
 
-static int getCookieId(char *cookieName)
+static char *getCookieId(char *cookieName)
 /* Get id value from cookie. */
 {
-char *hguidString = findCookieData(cookieName);
-return (hguidString == NULL ? 0 : atoi(hguidString));
+return findCookieData(cookieName);
 }
 
-static int getSessionId()
+static char *getSessionId()
 /* Get session id if any from CGI. */
 {
-return cgiUsualInt("hgsid", 0);
+return cgiOptionalString("hgsid");
 }
 
-static void clearDbContents(struct sqlConnection *conn, char *table, unsigned id)
+static void clearDbContents(struct sqlConnection *conn, char *table, char * secureId)
 /* Clear out contents field of row in table that matches id. */
 {
-char query[256];
-if (id == 0)
+if (!secureId)
     return;
-sqlSafef(query, sizeof(query), "update %s set contents='' where id=%u",
-      table, id);
-sqlUpdate(conn, query);
+struct dyString *query = dyStringNew(256);
+char *sessionKey = NULL;	    
+unsigned int id = cartDbParseId(secureId, &sessionKey);
+sqlDyStringPrintf(query, "update %s set contents='' where id=%u", table, id);
+if (cartDbUseSessionKey())
+    {
+    if (!sessionKey)
+	sessionKey = "";
+    sqlDyStringPrintf(query, " and sessionKey='%s'", sessionKey);
+    }
+sqlUpdate(conn, query->string);
+dyStringFree(&query);
+
+
 }
 
 void cartResetInDb(char *cookieName)
 /* Clear cart in database. */
 {
-int hguid = getCookieId(cookieName);
-int hgsid = getSessionId();
+char *hguid = getCookieId(cookieName);
+char *hgsid = getSessionId();
 struct sqlConnection *conn = cartDefaultConnector();
 clearDbContents(conn, "userDb", hguid);
 clearDbContents(conn, "sessionDb", hgsid);
 cartDefaultDisconnector(&conn);
 }
 
 void cartWriteCookie(struct cart *cart, char *cookieName)
 /* Write out HTTP Set-Cookie statement for cart. */
 {
 printf("Set-Cookie: %s=%u; path=/; domain=%s; expires=%s\r\n",
         cookieName, cart->userInfo->id, cfgVal("central.domain"), cookieDate());
 if(geoMirrorEnabled())
     {
     // This occurs after the user has manually choosen to go back to the original site; we store redirect value into a cookie so we 
     // can use it in subsequent hgGateway requests before loading the user's cart
     char *redirect = cgiOptionalString("redirect");
     if (redirect)
         {
         printf("Set-Cookie: redirect=%s; path=/; domain=%s; expires=%s\r\n", redirect, cgiServerName(), cookieDate());
         }
     }
 }
 
 struct cart *cartForSession(char *cookieName, char **exclude,
                             struct hash *oldVars)
 /* This gets the cart without writing any HTTP lines at all to stdout. */
 {
-int hguid = getCookieId(cookieName);
-int hgsid = getSessionId();
+char *hguid = getCookieId(cookieName);
+char *hgsid = getSessionId();
 struct cart *cart = cartNew(hguid, hgsid, exclude, oldVars);
 cartExclude(cart, sessionVar);
 if (sameOk(cfgOption("signalsHandler"), "on"))  /* most cgis call this routine */
     initSigHandlers(hDumpStackEnabled());
 char *httpProxy = cfgOption("httpProxy");  /* most cgis call this routine */
 if (httpProxy)
     setenv("http_proxy", httpProxy, TRUE);   /* net.c cannot see the cart, pass the value through env var */
 return cart;
 }
 
 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. */