Index: src/apache-2/mod_rivet.c =================================================================== --- src/apache-2/mod_rivet.c (revision 1674152) +++ src/apache-2/mod_rivet.c (working copy) @@ -101,6 +101,32 @@ mod_rivet_globals* rivet_module_globals = NULL; +/* -- Rivet_PrintErrorMessage + * + * Utility function to print the error message stored in errorInfo + * with a custom header. This procedure is called to print standard + * errors when one of Tcl scripts fails + * + * Arguments: + * + * - Tcl_Interp* interp: the Tcl interpreter that was running the script + * (and therefore the built-in variable errorInfo + * keeps the message) + * - const char* error: Custom error header + */ + +static void +Rivet_PrintErrorMessage (Tcl_Interp* interp,const char* error_header) +{ + Tcl_Obj* errormsg = Tcl_NewObj(); + + Tcl_IncrRefCount(errormsg); + Tcl_AppendStringsToObj(errormsg,"puts \"",error_header,"
\"\n",NULL); + Tcl_AppendStringsToObj(errormsg,"puts \"
$errorInfo
\"\n",NULL); + Tcl_EvalObjEx(interp,errormsg,0); + Tcl_DecrRefCount(errormsg); +} + /* * -- Rivet_chdir_file (const char* filename) * @@ -299,6 +325,59 @@ } } +/* -- Rivet_ExecuteErrorHandler + * + * Invoking either the default error handler or the ErrorScript. + * In case the error handler fails a standard error message is printed + * (you're better off if you make your error handlers fail save) + * + * Arguments: + * + * - Tcl_Interp* interp: the Tcl interpreter + * - Tcl_Obj* tcl_script_obj: the script that failed (to retrieve error + * info from it + * - request_rec* req: current request obj pointer + * + * Returned value: + * + * - A Tcl status + */ + +static int +Rivet_ExecuteErrorHandler (Tcl_Interp* interp,Tcl_Obj* tcl_script_obj, request_rec* req) +{ + int result; + rivet_server_conf* conf = Rivet_GetConf(req); + Tcl_Obj* errscript; + + /* We extract information from the errorOutbuf variable. Notice that tcl_script_obj + * can either be the request processing script or conf->rivet_abort_script + */ + + Tcl_SetVar( interp, "errorOutbuf",Tcl_GetStringFromObj( tcl_script_obj, NULL ),TCL_GLOBAL_ONLY ); + + /* If we don't have an error script, use the default error handler. */ + if (conf->rivet_error_script) { + errscript = conf->rivet_error_script; + } else { + errscript = conf->rivet_default_error_script; + } + + Tcl_IncrRefCount(errscript); + result = Tcl_EvalObjEx(interp, errscript, 0); + if (result == TCL_ERROR) { + Rivet_PrintErrorMessage(interp,"Rivet ErrorScript failed"); + } + + /* This shouldn't make the default_error_script go away, + * because it gets a Tcl_IncrRefCount when it is created. + */ + Tcl_DecrRefCount(errscript); + + return result; +} + + /* -- Rivet_ExecuteAndCheck * * Tcl script execution central procedure. The script stored @@ -316,7 +395,8 @@ * * Returned value: * - * - invariably TCL_OK + * - One of the Tcl defined returned value of Tcl_EvelObjExe (TCL_OK, + * TCL_ERROR, TCL_BREAK etc.) * * Side effects: * @@ -330,7 +410,7 @@ { int result; rivet_server_conf* conf = Rivet_GetConf(req); - rivet_interp_globals* globals = Tcl_GetAssocData(interp, "rivet", NULL); + rivet_interp_globals* globals = Tcl_GetAssocData( conf->server_interp, "rivet", NULL ); Tcl_Preserve (interp); result = Tcl_EvalObjEx(interp, tcl_script_obj, 0); @@ -337,7 +417,6 @@ if (result == TCL_ERROR) { - Tcl_Obj* errscript; Tcl_Obj* errorCodeListObj; Tcl_Obj* errorCodeElementObj; char* errorCodeSubString; @@ -376,39 +455,37 @@ { if (conf->rivet_abort_script) { + + /* Ideally an AbortScript should be fail safe, but in case + * it fails we give a chance to the subsequent ErrorScript + * to catch this error. + */ + if (Tcl_EvalObjEx(interp,conf->rivet_abort_script,0) == TCL_ERROR) { - CONST84 char *errorinfo = Tcl_GetVar( interp, "errorInfo", 0 ); - TclWeb_PrintError("Rivet AbortScript failed!",1,globals->req); - TclWeb_PrintError(errorinfo,0,globals->req); + + /* This is not elegant, but we want to avoid to print + * the default AbortScript error message if a custom ErrorScript + * will handle this error and in case print its own error message. + */ + + if (conf->rivet_error_script == NULL) + { + Rivet_PrintErrorMessage(interp,"Rivet AbortScript failed"); + } + Rivet_ExecuteErrorHandler(interp,conf->rivet_abort_script,req); } } - goto good; } } + else if (!globals->page_aborting) + { + /* Invoke Rivet error handler */ - Tcl_SetVar( interp, "errorOutbuf",Tcl_GetStringFromObj( tcl_script_obj, NULL ),TCL_GLOBAL_ONLY ); + Rivet_ExecuteErrorHandler(interp,tcl_script_obj,req); - /* If we don't have an error script, use the default error handler. */ - if (conf->rivet_error_script) { - errscript = conf->rivet_error_script; - } else { - errscript = conf->rivet_default_error_script; } - - Tcl_IncrRefCount(errscript); - if (Tcl_EvalObjEx(interp, errscript, 0) == TCL_ERROR) { - CONST84 char *errorinfo = Tcl_GetVar( interp, "errorInfo", 0 ); - TclWeb_PrintError("Rivet ErrorScript failed!",1,globals->req); - TclWeb_PrintError( errorinfo, 0, globals->req ); - } - - /* This shouldn't make the default_error_script go away, - * because it gets a Tcl_IncrRefCount when it is created. */ - Tcl_DecrRefCount(errscript); } - -good: /* Tcl_Flush moved to the end of Rivet_SendContent */ @@ -425,7 +502,12 @@ * if a Tcl script. * * This is a separate function so that it may be called from command 'parse' + * + * Returned value: * + * - One of the Tcl defined values returned by Rivet_ExecuteAndCheck (TCL_OK, + * TCL_ERROR, TCL_BREAK etc.) + * * Arguments: * * - TclWebRequest: pointer to the structure collecting Tcl and Apache data @@ -434,6 +516,7 @@ * - toplevel: integer to be interpreted as a boolean meaning the * file is pointed by the request. When 0 that's a subtemplate * to be parsed and executed from another template + * */ int @@ -443,7 +526,7 @@ int isNew = 0; int result = 0; - Tcl_Obj *outbuf = NULL; + Tcl_Obj *outbuf = NULL; Tcl_HashEntry *entry = NULL; time_t ctime; @@ -1477,7 +1560,7 @@ if (Rivet_ParseExecFile(globals->req, r->filename, 1) != TCL_OK) { ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, r->server, - MODNAME ": Error parsing exec file '%s': %s", + MODNAME ": Error in Rivet_ParseExecFile exec file '%s': %s", r->filename, Tcl_GetVar(interp, "errorInfo", 0)); } @@ -1486,11 +1569,12 @@ if (rsc->after_every_script) { - if (Rivet_ExecuteAndCheck(interp, rsc->after_every_script,r) == TCL_ERROR) + int tcl_status; + + tcl_status = Rivet_ExecuteAndCheck(interp, rsc->after_every_script,r); + if ((tcl_status == TCL_ERROR) && !globals->page_aborting) { - CONST84 char *errorinfo = Tcl_GetVar( interp, "errorInfo", 0 ); - TclWeb_PrintError("Rivet AfterEveryScript failed!",1,globals->req); - TclWeb_PrintError( errorinfo, 0, globals->req ); + Rivet_PrintErrorMessage(interp,"Rivet AfterEveryScript failed"); } }