8c172e6c4b985af79bf1a1f47c9db92ce0578999
max
  Tue Sep 15 05:47:36 2026 -0700
errCatch: put errAbort's doContentType back the way it found it, refs #38353

hVaUserAbort() turns doContentType on so that a user error reaches the browser when the CGI
has not pushed a warn handler of its own.  Inside an errCatch that is pointless -- the abort
is caught and never reaches the default handler -- and the flag stayed on afterwards, so a
later genuine abort on a page that had already written its header would print a second
Content-Type line into the body.  Everywhere else in the tree the flag is something a caller
turns back off.

errCatchPushHandlers() now records the flag and errCatchEnd() restores it, which covers every
caller rather than just the one that set it.  errAbortGetDoContentType() is the reader.

diff --git src/inc/errCatch.h src/inc/errCatch.h
index bcaec62dfc3..2c28edc6bd2 100644
--- src/inc/errCatch.h
+++ src/inc/errCatch.h
@@ -1,61 +1,62 @@
 /* errCatch - help catch errors so that errAborts aren't
  * fatal, and warn's don't necessarily get printed immediately. 
  * Note that error conditions caught this way will tend to
  * leak resources unless there are additional wrappers. 
  *
  * Typical usage is
  * errCatch = errCatchNew();
  * if (errCatchStart(errCatch))
  *     doFlakyStuff();
  * errCatchEnd(errCatch);
  * if (errCatch->gotError)
  *     warn("Flaky stuff failed: %s", errCatch->message->string);
  * errCatchFree(&errCatch); 
  * cleanupFlakyStuff();
  */
 #ifndef ERRCATCH_H
 #define ERRCATCH_H
 
 #ifndef DYSTRING_H
     #include "dystring.h"
 #endif
 
 struct errCatch
 /* Something to help catch errors.   */
     {
     struct errCatch *next;	 /* Next in stack. */
     jmp_buf jmpBuf;		 /* Where to jump back to for recovery. */
     struct dyString *message; /* Error message if any */
     boolean gotError;		 /* Some sort of error was caught. */
     boolean gotWarning;		 /* Some sort of error warning was raised. */
+    boolean savedDoContentType;  /* errAbort's doContentType as it was on entry; see below. */
     };
 
 struct errCatch *errCatchNew();
 /* Return new error catching structure. */
 
 void errCatchFree(struct errCatch **pErrCatch);
 /* Free up resources associated with errCatch */
 
 #define errCatchStart(e) (errCatchPushHandlers(e) && setjmp(e->jmpBuf) == 0)
 /* Little wrapper around setjmp.  This returns TRUE
  * on the main execution thread, FALSE after abort. */
 
 
 boolean errCatchPushHandlers(struct errCatch *errCatch);
 /* Push error handlers.  Not usually called directly. 
  * but rather through errCatchStart() macro.  Always
  * returns TRUE. */
 
 void errCatchEnd(struct errCatch *errCatch);
 /* Restore error handlers and pop self off of catching stack. */
 
 void errCatchReWarn(struct errCatch *errCatch);
 /* Re-warn any warnings that happened even though no abort happened 
  * to make them visible. */
 
 boolean errCatchFinish(struct errCatch **pErrCatch);
 /* Finish up error catching.  Report error if there is a
  * problem and return FALSE.  If no problem return TRUE.
  * This handles errCatchEnd and errCatchFree. */
 #endif /* ERRCATCH_H */