b89356a235c4592606ec4339b9dc06a6b3fedc1c
max
  Thu Jun 5 07:08:26 2025 -0700
fixing hgGateway captcha problem, at least temporarily, refs #35790

diff --git src/hg/lib/cart.c src/hg/lib/cart.c
index 698d2627e8f..aa6d1b4aeeb 100644
--- src/hg/lib/cart.c
+++ src/hg/lib/cart.c
@@ -1557,31 +1557,41 @@
     return;
 
 // no captcha for our own QA scripts running on a server with our IP address
 if (botException())
     return;
 
 // let rtracklayer user agent pass, but allow us to remove this exception in case the bots discover it one day
 if (!cfgOption("blockRtracklayer") && sameOk(cgiUserAgent(), "rtracklayer"))
     return;
 
 // QA can add a user agent after release, in case someone complains that their library is blocked
 char *okUserAgent = cfgOption("okUserAgent");
 if (okUserAgent && sameOk(cgiUserAgent(), okUserAgent))
     return;
 
-if (userId && userIdFound)
+// Do not show a captcha if we have a valid cookie 
+// but for debugging, it's nice to be force the captcha to come up
+if (userId && userIdFound && !cgiOptionalString("captcha"))
+    return;
+
+// Do not show a captcha if the request is an AJAX request coming from jQuery
+// This is a hack to work around an error in hgGateway and may soon disappear.
+// It's a hack because the header can be set by any curl script to get around
+// the captcha. Right now, hgGateway is not setting any cookie at all, so the 
+// correct solution would be to change that.
+if (sameOk(getenv("HTTP_X_REQUESTED_WITH"), "XMLHttpRequest"))
     return;
 
 char *token = cgiOptionalString("token");
 
 if (token && isValidToken(token))
 {
     cartRemove(cart, "token");
     return;
 }
 
 printCaptcha();
 }
 
 void cartRemove(struct cart *cart, char *var);
 
@@ -2707,33 +2717,33 @@
 /* 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();
 
 if (doContentType && !cartDidContentType)
     {
     addHttpHeaders();
     cartWriteCookie(cart, cookieName);
     puts("Content-Type:text/html");
-    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,
                                     struct hash *oldVars)
 /* Load cart from cookie and session cgi variable. Don't write out
  * content type or any HTML. */