0441be0515c7b1988115a3161659563dc13cdbb6
hiram
  Thu Jul 23 08:02:54 2026 -0700
fixup the problem of using getenv() for the host name to correctly use gethostname() refs #31811

diff --git src/hg/hubApi/liftOver.c src/hg/hubApi/liftOver.c
index 848c6dd9bbe..7a93ee56d96 100644
--- src/hg/hubApi/liftOver.c
+++ src/hg/hubApi/liftOver.c
@@ -161,48 +161,68 @@
                 {
                 jsonWriteBoolean(jw, "pending", TRUE);
                 jsonWriteNumber(jw, "pendingStatus", sqlSigned(row[1]));
                 jsonWriteString(jw, "pendingRequestTime", row[2]);
                 }
             sqlFreeResult(&sr);
             }
         hDisconnectOtto(&ottoConn);
         }
     }
 
 apiFinishOutput(0, NULL, jw);
 hDisconnectCentral(&conn);
 }
 
+static char *thisHostName()
+/* Return this machine's own hostname via gethostname().  Unlike hHttpHost(),
+ * which reflects the client-supplied HTTP_HOST/Host: header, this can't be
+ * spoofed by the request and doesn't change depending on which round-robin
+ * name (e.g. genome.ucsc.edu) the client used to reach this box -- using
+ * hHttpHost() here made onGenomeRRMachine() misclassify RR machines reached
+ * via the genome.ucsc.edu name, sending them into an infinite self-relay
+ * loop in fetchGbMembersFromCentral(). */
+{
+static char host[256];
+static boolean init = FALSE;
+if (!init)
+    {
+    if (gethostname(host, sizeof(host)) != 0)
+        host[0] = '\0';
+    init = TRUE;
+    }
+return host;
+}
+
 static boolean inUcscEduDomain()
 /* Return TRUE if this host is anywhere under the ucsc.edu domain. */
 {
-char *httpHost = hHttpHost();
-return (httpHost != NULL && endsWith(httpHost, ".ucsc.edu"));
+char *hostName = thisHostName();
+return (hostName[0] != '\0' && endsWith(hostName, ".ucsc.edu"));
 }
 
 static boolean onGenomeRRMachine()
 /* Return TRUE if running on one of the genome.ucsc.edu round-robin
  * machines (hgw0, hgw1, hgw2, ...), which carry SQL grants on
  * hgcentral.gbMembers.  Only meaningful within inUcscEduDomain(). */
 {
 if (hIsPrivateHost())	// stay on localhost for hgwdev and hgwbeta
     return TRUE;
-char *httpHost = hHttpHost();
-if (httpHost == NULL || !startsWith("hgw", httpHost))
+char *hostName = thisHostName();
+if (hostName[0] == '\0' || !startsWith("hgw", hostName))
     return FALSE;
-char afterHgw = httpHost[3];
+char afterHgw = hostName[3];
 return (afterHgw >= '0' && afterHgw <= '9');
 }
 
 static boolean fetchGbMembersFromCentral(char *userName, char **retEmail, char **retRealName)
 /* Relay to genome.ucsc.edu's own loginStatus endpoint to get email/realName
  * for userName, forwarding this request's Cookie header so genome.ucsc.edu
  * authenticates the same session.  Used on ucsc.edu hosts that lack SQL
  * grants on hgcentral.gbMembers.  Returns FALSE on any failure. */
 {
 char *cookieHeader = getenv("HTTP_COOKIE");
 if (isEmpty(cookieHeader))
     return FALSE;
 
 struct dyString *reqHeader = dyStringNew(0);
 dyStringPrintf(reqHeader, "Cookie: %s\r\n", cookieHeader);