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. */