c2a6ef817930149ad6f55818fa0196d99c47e02b
braney
  Fri Sep 11 10:40:11 2026 -0700
cheapcgi: skip a CGI pair with no =value instead of aborting, refs #38335

Both query string parsers looked for the '=' across the whole rest of the
string rather than inside the current pair.  A pair with no '=' in it
therefore ran into the pair after it and took its value.  "g-catV2&db=hg38"
was stored as one variable named "g-catV2&db", so db was lost with no
warning, and that corrupt name was copied on into the cart.  The same pair
at the end of the string had no '=' left to find and aborted the whole
request, which is what the "Mangled CGI input string g-catV2" entries in the
hgw1 logs were.

Both parsers now find the end of the pair first, keeping the existing
separator precedence ('&', then ';' for DAS), and skip a pair with no '='.
A mixed "a=1;b=2&c=3" still parses the way it did.

Adds lib/tests/cgiParseTest, which runs 18 query strings through both
parsers.  It covers the empty pair of #38185 as well.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

diff --git src/lib/tests/makefile src/lib/tests/makefile
index cfa34defdc0..2863fea0cf7 100644
--- src/lib/tests/makefile
+++ src/lib/tests/makefile
@@ -1,28 +1,28 @@
 kentSrc = ../..
 include ../../inc/common.mk
 
 MYLIBDIR = ../../lib/${MACHTYPE}
 MYLIBS = ${MYLIBDIR}/jkweb.a
 BIN_DIR = bin/${MACHTYPE}
 
 pipelineTester = ${BIN_DIR}/pipelineTester
 
 test: errCatchTest htmlPageTest htmlExpandUrlTest htmlSanitizeTest pipelineTests dyStringTest \
     mimeTests base64Tests quotedPTests safeTest hashTest fetchUrlTest gff3Test \
     tabixTest vcfTest hacTreeTest mmHashTest testSumDoubles jsonQueryTest \
-    dnaCodonTest pathSimplifyTest faSpeedReadTest
+    dnaCodonTest pathSimplifyTest faSpeedReadTest cgiParseTest
 	rm -r output fetchUrlTest testSumDoubles
 	@echo tested all
 
 
 mkdirs:
 	${MKDIR} output ${BIN_DIR}
 
 testSumDoubles: testSumDoubles.o ${MYLIBS}
 	@${MKDIR} $(dir $@)
 	${CC} ${COPT} -o ./testSumDoubles testSumDoubles.o ${MYLIBS} ${L}
 
 pathSimplifyTest: pathSimplifyTest.o ${MYLIBS} mkdirs
 	@${MKDIR} $(dir $@)
 	${CC} ${COPT} -o ${BIN_DIR}/pathSimplifyTest pathSimplifyTest.o ${MYLIBS} ${L}
 	${STRIP} ${BIN_DIR}/pathSimplifyTest${EXE}
@@ -31,30 +31,37 @@
 
 faSpeedReadTest: faSpeedReadTest.o ${MYLIBS} mkdirs
 	@${MKDIR} $(dir $@)
 	${CC} ${COPT} -o ${BIN_DIR}/faSpeedReadTest faSpeedReadTest.o ${MYLIBS} ${L}
 	${STRIP} ${BIN_DIR}/faSpeedReadTest${EXE}
 	${BIN_DIR}/faSpeedReadTest > output/faSpeedReadTest
 	diff expected/faSpeedReadTest output/faSpeedReadTest
 
 dnaCodonTest: dnaCodonTest.o ${MYLIBS} mkdirs
 	@${MKDIR} $(dir $@)
 	${CC} ${COPT} -o ${BIN_DIR}/dnaCodonTest dnaCodonTest.o ${MYLIBS} ${L}
 	${STRIP} ${BIN_DIR}/dnaCodonTest${EXE}
 	${BIN_DIR}/dnaCodonTest > output/dnaCodonTest
 	diff expected/dnaCodonTest output/dnaCodonTest
 
+cgiParseTest: cgiParseTest.o ${MYLIBS} mkdirs
+	@${MKDIR} $(dir $@)
+	${CC} ${COPT} -o ${BIN_DIR}/cgiParseTest cgiParseTest.o ${MYLIBS} ${L}
+	${STRIP} ${BIN_DIR}/cgiParseTest${EXE}
+	${BIN_DIR}/cgiParseTest > output/cgiParseTest
+	diff expected/cgiParseTest output/cgiParseTest
+
 htmlSanitizeTest: htmlSanitizeTest.o ${MYLIBS} mkdirs
 	@${MKDIR} $(dir $@)
 	${CC} ${COPT} -o ${BIN_DIR}/htmlSanitizeTest htmlSanitizeTest.o ${MYLIBS} ${L}
 	${STRIP} ${BIN_DIR}/htmlSanitizeTest${EXE}
 	${BIN_DIR}/htmlSanitizeTest > output/htmlSanitizeTest
 	diff expected/htmlSanitizeTest output/htmlSanitizeTest
 
 errCatchTest: errCatchTest.o ${MYLIBS} mkdirs
 	@${MKDIR} $(dir $@)
 	${CC} ${COPT} -o ${BIN_DIR}/errCatchTest errCatchTest.o ${MYLIBS} ${L}
 	${STRIP} ${BIN_DIR}/errCatchTest${EXE}
 	${BIN_DIR}/errCatchTest secret > output/errCatch.good
 	diff expected/errCatch.good output/errCatch.good
 	${BIN_DIR}/errCatchTest bad > output/errCatch.bad
 	diff expected/errCatch.bad output/errCatch.bad