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/blatServers.h src/hg/inc/blatServers.h
index d47f24c8677..60319925208 100644
--- src/hg/inc/blatServers.h
+++ src/hg/inc/blatServers.h
@@ -1,68 +1,89 @@
 /* blatServers.h was originally generated by the autoSql program, which also 
  * generated blatServers.c and blatServers.sql.  This header links the database and
  * the RAM representation of objects. */
 
 #ifndef BLATSERVERS_H
 #define BLATSERVERS_H
 
 #define BLATSERVERS_NUM_COLS 6
 
 extern char *blatServersCommaSepFieldNames;
 
 struct blatServers
 /* Description of online BLAT servers */
     {
     struct blatServers *next;  /* Next in singly linked list. */
     char *db;	/* Database name */
     char *host;	/* Host (machine) name */
     int port;	/* TCP/IP port on host */
     signed char isTrans;	/* 0 for nucleotide/1 for translated nucleotide */
     signed char canPcr;	/* 1 for use with PCR, 0 for not */
     signed char dynamic;	/* 1 for if gfServer is dynamic under xinetd, 0 for not */
     };
 
 void blatServersStaticLoad(char **row, struct blatServers *ret);
 /* Load a row from blatServers table into ret.  The contents of ret will
  * be replaced at the next call to this function. */
 
 struct blatServers *blatServersLoad(char **row);
 /* Load a blatServers from row fetched with select * from blatServers
  * from database.  Dispose of this with blatServersFree(). */
 
 struct blatServers *blatServersLoadAll(char *fileName);
 /* Load all blatServers from whitespace-separated file.
  * Dispose of this with blatServersFreeList(). */
 
 struct blatServers *blatServersLoadAllByChar(char *fileName, char chopper);
 /* Load all blatServers from chopper separated file.
  * Dispose of this with blatServersFreeList(). */
 
 #define blatServersLoadAllByTab(a) blatServersLoadAllByChar(a, '\t');
 /* Load all blatServers from tab separated file.
  * Dispose of this with blatServersFreeList(). */
 
 struct blatServers *blatServersCommaIn(char **pS, struct blatServers *ret);
 /* Create a blatServers out of a comma separated string. 
  * This will fill in ret if non-null, otherwise will
  * return a new blatServers */
 
 void blatServersFree(struct blatServers **pEl);
 /* Free a single dynamically allocated blatServers such as created
  * with blatServersLoad(). */
 
 void blatServersFreeList(struct blatServers **pList);
 /* Free a list of dynamically allocated blatServers's */
 
 void blatServersOutput(struct blatServers *el, FILE *f, char sep, char lastSep);
 /* Print out blatServers.  Separate fields with sep. Follow last field with lastSep. */
 
 #define blatServersTabOut(el,f) blatServersOutput(el,f,'\t','\n');
 /* Print out blatServers as a line in a tab-separated file. */
 
 #define blatServersCommaOut(el,f) blatServersOutput(el,f,',',',');
 /* Print out blatServers as a comma separated list including final comma. */
 
 /* -------------------------------- End autoSql Generated Code -------------------------------- */
 
+struct blatServerParams
+/* Parameters needed to connect to a gfServer and run alignments.
+ * Returned by findBlatServer(); shared by hgBlat and hubApi/blat. */
+    {
+    char *db;           /* Assembly database name. */
+    char *genome;       /* Human-readable genome name. */
+    char *host;         /* gfServer hostname. */
+    char *port;         /* gfServer port (string). */
+    char *nibDir;       /* Directory of .2bit / .nib sequence files. */
+    char *genomeDataDir;/* Dynamic-server root-relative directory, or NULL. */
+    boolean isTrans;    /* TRUE for translated (protein/rnax/dnax) queries. */
+    boolean isDynamic;  /* TRUE if served by a dynamic gfServer. */
+    };
+
+struct blatServerParams *findBlatServer(char *db, boolean isTrans);
+/* Return gfServer connection parameters for the given assembly, or NULL if
+ * none is configured.  Handles both hub and non-hub assemblies.
+ * The description-to-name fallback from hgBlat is included: if db is not
+ * found as a name in dbDb it is tried as a description.
+ * Caller should NOT free the returned struct. */
+
 #endif /* BLATSERVERS_H */