214e76748ab09f24db9e390c633482be7901e8ab
max
  Tue Jun 30 16:58:26 2026 -0700
adding captcha tracing to cart.c, no redmine

diff --git src/hg/lib/cart.c src/hg/lib/cart.c
index 0bd6dd90b68..19181c4a8a7 100644
--- src/hg/lib/cart.c
+++ src/hg/lib/cart.c
@@ -1502,37 +1502,44 @@
     if (!secret)
         errAbort("'cloudFlareSecretKey' must be set in hg.conf if cloudflare is activated in hg.conf");
 
     char data[3000]; // cloudflare token is at most 2000 bytes
     safef(data, sizeof(data), "secret=%s&response=%s", secret, token);
     char *reply = curlPostUrl(url, data);
 
     boolean res = strstr(reply, "\"success\":true") != NULL;
     freez(&reply);
     return res;
 }
 
 // hg.conf key with the cloud flare secret key, used twice here, so a global macro
 #define CLOUDFLARESITEKEY "cloudFlareSiteKey"
 
+static char *getSessionId()
+/* Get session id if any from CGI. */
+{
+return cgiOptionalString("hgsid");
+}
+
 void printCaptcha() 
 /* print an html page that shows the captcha and on success, reloads the page with the token added as token=x */
 {
     char *cfSiteKey = cfgVal(CLOUDFLARESITEKEY);
     if (!cfSiteKey)
         return;
 
+    fprintf(stderr, "CAPTCHA_PRINT %s\n", getSessionId());
     puts("Content-Type:text/html\n"); // puts outputs one newline. Header requires two newlines.
     puts("<html><head>");
     puts("<script>");
     printf("function showWidget() { \n"
        "turnstile.render('#myWidget', {\n"
          "sitekey: '%s',\n"
          "theme: 'light',\n"
          "callback: function (token) {\n"
          "     const parser = new URL(window.location);\n"
          "     parser.searchParams.set('token', token);\n"
          "     window.location = parser.href;\n"
          "   },\n"
        "});\n"
        "}\n", cfSiteKey);
     puts("</script>");
@@ -1596,59 +1603,61 @@
     return;
 
 // Do not show a captcha if we have a valid cookie 
 // but for debugging, it's nice to be able to force the captcha
 if (userId && userIdFound && !cgiOptionalString("captcha"))
     return;
 
 // when the captcha is solved, our JS code does a full page-reload, no AJAX. That saves us one round-trip.
 // After the reload, the new page URL has the captcha token in the URL argument list, so now we need to validate it
 // and remove it from the cart
 char *token = cgiOptionalString("token");
 if (token)
 {
     if (isValidToken(token))
         {
+        fprintf(stderr, "CAPTCHA_VALID %s\n", getSessionId());
         cgiVarExclude("token");
         // Drop any IP-tracking rows for this hguid so a legitimate user
         // who roams networks isn't repeatedly captcha-gated.
         if (cfgOptionBooleanDefault("hguidIpTracking.enabled", FALSE) && isNotEmpty(userId))
             {
             unsigned long userIdNum = cartDbParseId(userId, NULL);
             if (userIdNum != 0)
                 {
                 struct sqlConnection *conn = hConnectCentralNoCache();
                 char *table = cfgOptionDefault("hguidIpTracking.table", "hguidIpAccess");
                 char query[256];
                 sqlSafef(query, sizeof(query),
                          "DELETE FROM %s WHERE userId=%lu", table, userIdNum);
                 sqlUpdate(conn, query);
                 sqlDisconnect(&conn);
                 }
             }
         return;
         }
     else
         {
         puts("Content-Type: text/html\n");
         puts("<html><body>Internal captcha error: Cloudflare rejected the captcha token. "
                 "Something is not working internally, we are very sorry. You can try reloading the page. "
                 "If this problem persists, send an email to genome-www@soe.ucsc.edu and we will "
                 "look into it as quickly as we can in the PST timezone. You can use any internet browser "
                 "where you have used the genome browser before, but not from this internet browser. "
                 "You can try our mirror sites, "
                 "genome-euro.ucsc.edu or genome-asia.ucsc.edu, while we are working on a solution.</body></html>");
+        fprintf(stderr, "CAPTCHA_REJECT %s\n", getSessionId());
         exit(0);
         }
 }
 
 printCaptcha();
 }
 
 void cartRemove(struct cart *cart, char *var);
 
 static void genericCgiSetup()
 /* Run steps that all CGIs must do that unrelated to the cart: timeout, logging setup, UDC.
  */
 {
 static boolean genericSetupDone = FALSE;
 
@@ -2538,36 +2547,30 @@
 
 
 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 char *getCookieId(char *cookieName)
 /* Get id value from cookie. */
 {
 return findCookieData(cookieName);
 }
 
-static char *getSessionId()
-/* Get session id if any from CGI. */
-{
-return cgiOptionalString("hgsid");
-}
-
 static void clearDbContents(struct sqlConnection *conn, char *table, char * secureId)
 /* Clear out contents field of row in table that matches id. */
 {
 if (!secureId)
     return;
 struct dyString *query = dyStringNew(256);
 char *sessionKey = NULL;	    
 unsigned long id = cartDbParseId(secureId, &sessionKey);
 char *defaultCartContents = getDefaultCart(conn);
 sqlDyStringPrintf(query, "update %s set contents='%s' where id=%lu", table, defaultCartContents, id);
 if (cartDbUseSessionKey())
     {
     if (!sessionKey)
 	sessionKey = "";
     sqlDyStringPrintf(query, " and sessionKey='%s'", sessionKey);