2197f6d5208aff4c48ccbe42e61a116d988ac392
max
  Tue May 19 08:23:54 2026 -0700
hubApi: add /blat endpoint with apiKey gating, format=hgblat, and known-agent bypass

New src/hg/hubApi/blat.c implements /blat/<type> (dna, protein, transRna,
transDna, guess) backed by the same gfServer logic as hgBlat.  Key details:

- Requires an apiKey for rate-limiting; botException() and
botExceptionUserAgent() exempt IPs/user-agents in hg.conf (same
policy as captcha bypass elsewhere in the browser stack).
- Invalid apiKey returns a clean JSON 403 rather than an HTML 500
(pre-validated in hubApi.c main() before hgBotDelayTimeFrac runs).
- Extra bot-delay fraction (default 0.3, 10x hubApi default) is
configurable via hubApi.blatDelayFraction in hg.conf.
- format=text/psl  -> PSL text; format=hgblat -> byte-for-byte
hgBlat?output=json shape; jsonOutputArrays=1 -> hubApi envelope
with arrays (parallel to getData behaviour); default -> objects.
- botExceptionUserAgent() carved out of cart.c's static
isUserAgentException() into botDelay.c so non-cart callers can use it.
- Cross-reference comments added in hgBlat.c and blat.c noting the
shared logic so fixes get applied to both.

refs #36315

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

diff --git src/hg/inc/botDelay.h src/hg/inc/botDelay.h
index 882163a7e31..d29f9c64818 100644
--- src/hg/inc/botDelay.h
+++ src/hg/inc/botDelay.h
@@ -1,43 +1,46 @@
 /* botDelay - contact bottleneck server and sleep 
  * for a little bit if IP address looks like it is
  * being just too demanding. */
 
 /* Copyright (C) 2004 The Regents of the University of California 
  * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */
 
 int botDelayTime(char *host, int port, char *ip);
 /* Figure out suggested delay time for ip address in
  * milliseconds. */
 
 char *botDelayWarningMsg(char *ip, int millis);
 /* return the string for the default botDelay message
  * not all users of botDelay want the message to go to stderr
  * return it for their own use case
  */
 
 void botDelayMessage(char *ip, int millis);
 /* Print out message saying why you are stalled. */
 
 int hgBotDelayTime();
 /* Get suggested delay time from cgi using the standard penalty. */
 
 int hgBotDelayTimeFrac(double fraction);
 /* Get suggested delay time from cgi using the specified fraction of the standard penalty. */
 
 extern int botDelayMillis;
 
 boolean earlyBotCheck(long enteredMainTime, char *cgiName, double delayFrac, int warnMs, int exitMs, char *exitType);
 /* for use before the CGI has started any
  * output or setup the cart of done any MySQL operations.  The boolean
  * return is used later in the CGI after it has done all its setups and
  * started output so it can issue the warning.  Pass in delayFrac 0.0
  * to use the default 1.0, pass in 0 for warnMs and exitMs to use defaults,
  * and exitType is either 'html' or 'json' to do that type of exit output in
  * the case of hogExit();
  */
 
 int hgBotDelayCurrWarnMs();
 /* get number of millis that are tolerated until a warning is shown on the most recent call to earlyBotCheck */
 
 boolean botException();
 /* check if the remote ip address is on the exceptions list */
+
+boolean botExceptionUserAgent();
+/* Return TRUE if HTTP_USER_AGENT matches a noCaptchaAgent. pattern in hg.conf. */