cb99f0b11bdeee5dfa76064d38b6410da0f4a709
max
Thu Sep 10 00:55:21 2026 -0700
Centralize CGI Content-Type printing in one cgiPrintContentType() helper
Around 90 places across the tree hand-rolled the CGI response header, each
with its own spelling: "Content-Type:" or "Content-type:", \n or \r\n, and
the terminating blank line written as part of the same string, as a separate
puts("\n") (which emits two newlines, so a stray blank line led the body) or
as printf("\r\n\r\n") (two blank lines). A handful forgot the terminator
entirely and relied on a following header to supply it.
cgiPrintContentType() in lib/cheapcgi.c now writes the Content-Type line and
the blank line that ends the header. Header lines are not ordered, so the
callers that also send Status, Set-Cookie, Content-Disposition, Content-Length
or X-Sendfile write those first and call this last to close the header; that
keeps it to a single helper rather than a print-the-line / end-the-header pair
that a caller can half-use. cart.c's existing httpHeaders list already worked
this way.
Only the CGI response path is touched. The dyStringPrintf("Content-type: ...")
calls that build outgoing HTTP *requests* (genomeSpace, oauthLogin, eapMetaSync,
edwWebAuthLogin, ga4ghToBed) are unrelated and left alone.
Also fills out the apiKey error message in botDelay.c to say where to create a
key and that keys are server-specific.
No behavior change on the wire beyond dropping those stray blank lines and
adding the missing newline after Retry-After.
diff --git src/hg/phyloPng/phyloPng.c src/hg/phyloPng/phyloPng.c
index a7fb6cdaff9..38080002361 100644
--- src/hg/phyloPng/phyloPng.c
+++ src/hg/phyloPng/phyloPng.c
@@ -368,35 +368,31 @@
/* this will cause it to kick out the set-cookie: http response header line */
cart = cartAndCookieNoContent(hUserCookie(), excludeVars, oldVars);
}
else
{
if (!cgiOptionalString("phyloPng_tree"))
usage("-phyloPng_tree is a required 'option' or cgi variable.");
}
useCart = (!cgiOptionalString("phyloPng_tree") || cgiVarExists("phyloPng_restore"));
htmlPageWrapper = cgiVarExists("phyloPng_htmlPage"); /* wrap output in a page */
if (onWeb && sameString(getenv("REQUEST_METHOD"),"HEAD"))
{ /* tell browser it's static just so it can save it */
- if (htmlPageWrapper)
- printf("Content-type: text/html\r\n");
- else
- printf("Content-type: image/png\r\n");
- printf("\r\n");
+ cgiPrintContentType(htmlPageWrapper ? "text/html" : "image/png");
return 0;
}
if (useCart)
{
width = cartUsualInt(cart,"phyloPng_width",width);
height = cartUsualInt(cart,"phyloPng_height",height);
phyloData = cloneString(cartOptionalString(cart,"phyloPng_tree"));
branchLengths = cartVarExists(cart,"phyloPng_branchLengths");
lengthLegend = cartVarExists(cart,"phyloPng_lengthLegend");
branchLabels = cartVarExists(cart,"phyloPng_branchLabels");
branchDecimals = cartUsualInt(cart,"phyloPng_branchDecimals", branchDecimals);
branchMultiplier = cartUsualInt(cart,"phyloPng_branchMultiplier", branchMultiplier);
stripUnderscoreSuff = cartVarExists(cart,"phyloPng_undersuff_strip");
dashToSpace = cartVarExists(cart,"phyloPng_dash_to_space");
@@ -411,32 +407,31 @@
branchLengths = cgiVarExists("phyloPng_branchLengths");
lengthLegend = cgiVarExists("phyloPng_lengthLegend");
branchLabels = cgiVarExists("phyloPng_branchLabels");
branchDecimals = cgiUsualInt("phyloPng_branchDecimals", branchDecimals);
branchMultiplier = cgiUsualInt("phyloPng_branchMultiplier", branchMultiplier);
stripUnderscoreSuff = cgiVarExists("phyloPng_undersuff_strip");
dashToSpace = cgiVarExists("phyloPng_dash_to_space");
underToSpace = cgiVarExists("phyloPng_under_to_space");
monospace = cgiVarExists("phyloPng_monospace");
}
if (useCart)
{
if (onWeb)
{
- printf("Content-type: text/html\r\n");
- printf("\r\n");
+ cgiPrintContentType("text/html");
cartWebStart(cart, NULL, "%s", "phyloPng Interactive Phylogenetic Tree Png Maker");
if (isMSIE) /* cannot handle long urls */
puts("<form method=\"POST\" action=\"phyloPng\" name=\"mainForm\">");
else
puts("<form method=\"GET\" action=\"phyloPng\" name=\"mainForm\">");
cartSaveSession(cart);
puts("<table>");
puts("<tr><td>Width:</td><td>"); cartMakeIntVar(cart, "phyloPng_width", width, 4); puts("</td></tr>");
puts("<tr><td>Height:</td><td>"); cartMakeIntVar(cart, "phyloPng_height", height, 4); puts("</td></tr>");
puts("<tr><td>Use branch lengths?</td><td>"); cartMakeCheckBox(cart, "phyloPng_branchLengths", branchLengths); puts("</td></tr>");
puts("<tr><td> Show length ruler?</td><td>"); cartMakeCheckBox(cart, "phyloPng_lengthLegend", lengthLegend); puts("</td></tr>");
puts("<tr><td> Show length values?</td><td>"); cartMakeCheckBox(cart, "phyloPng_branchLabels", branchLabels); puts("</td></tr>");
puts("<tr><td> How many decimal places?</td><td>"); cartMakeIntVar(cart, "phyloPng_branchDecimals", branchDecimals,1); puts("</td></tr>");
@@ -537,32 +532,31 @@
"to two or three figures.<br>\n"
"<br>\n"
"6. Wrap-in-html is useful when the browser automatically shrinks a large image.\n"
"This option keeps the image view full in the browser automatically.\n"
"<br>"
);
cartWebEnd();
return 0;
}
else
usage("-phyloPng_tree is a required 'option' or cgi variable.");
}
if (htmlPageWrapper)
{
- printf("Content-type: text/html\r\n");
- printf("\r\n");
+ cgiPrintContentType("text/html");
printf("<html><head>\n%s<title>Phylogenetic Tree</title></head><body>",getCspMetaHeader());
printf("<IMAGE SRC=\"http://%s%s"
"?phyloPng_width=%d"
"&phyloPng_height=%d"
"&phyloPng_tree=%s"
,getenv("SERVER_NAME"),getenv("SCRIPT_NAME"),width,height,cgiEncode(phyloData)); // tree into URL, cgiEncode (XSS)
if (branchLengths)
printf("&phyloPng_branchLengths=1");
if (lengthLegend)
printf("&phyloPng_lengthLegend=1");
if (branchLabels)
printf("&phyloPng_branchLabels=1");
printf("&phyloPng_branchDecimals=%d",branchDecimals);
printf("&phyloPng_branchMultipliers=%d",branchMultiplier);
if (stripUnderscoreSuff)
@@ -616,32 +610,31 @@
char *errMsg = NULL;
if (errCatchStart(errCatch))
{
phyloTree = phyloParseString(phyloData);
}
errCatchEnd(errCatch);
if (errCatch->gotError)
{
errMsg = cloneString(errCatch->message->string);
}
errCatchFree(&errCatch);
if (errMsg)
{
if (onWeb)
{
- printf("Content-type: text/html\r\n");
- printf("\r\n");
+ cgiPrintContentType("text/html");
printf("<html><head>\n%s<title>PhyloTree parse error</title></head><body><pre>",getCspMetaHeader());
/* we dont think the specific error message coming back are correct or useful
* so supply a generic err msg */
htmlPrintf("Original input tree:\n[%s]\n\n",cgiString("phyloPng_tree"));
htmlPrintf("Input tree as passed to parser:\n[%s]\n\n",phyloData);
printf("Parser syntax error:\n%s",errMsg);
puts("</pre></body></html>");
}
else
{
warn("%s", errMsg);
}
freez(&errMsg);
freez(&phyloData);
return 0;
@@ -663,32 +656,31 @@
mgClearPixels(mg);
lengthLegend = lengthLegend && branchLengths; /* moot without lengths */
if (lengthLegend)
{
int fHeight = mgFontPixelHeight(font);
height -= (MARGIN+2*fHeight);
}
phyloTreeLayoutBL(phyloTree, &maxDepth, &numLeafs, 0, font, &maxLabelWidth, width, &minMaxFactor, 0.0);
if (layoutErrMsg[0] != 0)
{
if (onWeb)
{
- printf("Content-type: text/html\r\n");
- printf("\r\n");
+ cgiPrintContentType("text/html");
printf("<html><head>\n%s<title>PhyloTree error</title></head><body><pre>",getCspMetaHeader());
printf("input tree: [%s]\n\n%s",cgiString("phyloPng_tree"),layoutErrMsg);
puts("</pre></body></html>");
}
else
{
warn("%s", layoutErrMsg);
}
freez(&phyloData);
mgFree(&mg);
return 0;
}
if (branchLengths)
phyloTreePngBL(phyloTree, maxDepth, numLeafs, maxLabelWidth, width, height,
@@ -726,32 +718,31 @@
{
dh = fHeight / 4;
}
mgDrawLine(mg, MARGIN+x, height+fHeight/2-dh,
MARGIN+x, height+fHeight/2+dh, MG_BLACK);
++i;
}
}
}
if (onWeb)
{
- printf("Content-type: image/png\r\n");
- printf("\r\n");
+ cgiPrintContentType("image/png");
}
if (!mgSaveToPng(stdout, mg, FALSE))
{
errAbort("Couldn't save png to stdout");
}
if (cgiOptionalString("phyloPng_submit"))
cartCheckout(&cart);
/* there's no code for freeing the phyloTree yet in phyloTree.c */
mgFree(&mg);
freez(&phyloData);