2 // System.Web.HttpException
5 // Patrik Torstensson (Patrik.Torstensson@labs2.com)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 // (c) 2002 Patrik Torstensson
9 // (c) 2003 Ximian, Inc. (http://www.ximian.com)
10 // Copyright (C) 2005-2009 Novell, Inc (http://www.novell.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System.Runtime.Serialization;
34 using System.Runtime.InteropServices;
35 using System.Security.Permissions;
37 using System.Web.Util;
38 using System.Web.Compilation;
39 using System.Web.Management;
40 using System.Collections.Specialized;
45 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
46 [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
48 public class HttpException : ExternalException
50 const string DEFAULT_DESCRIPTION_TEXT = "Error processing request.";
51 const string ERROR_404_DESCRIPTION = "The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.";
53 int webEventCode = WebEventCodes.UndefinedEventCode;
57 ExceptionPageTemplate pageTemplate;
59 ExceptionPageTemplate PageTemplate {
61 if (pageTemplate == null)
62 pageTemplate = GetPageTemplate ();
73 get { return webEventCode; }
76 public HttpException ()
80 public HttpException (string message)
85 public HttpException (string message, Exception innerException)
86 : base (message, innerException)
90 public HttpException (int httpCode, string message) : base (message)
95 internal HttpException (int httpCode, string message, string resourceName) : this (httpCode, message)
97 resource_name = resourceName;
100 internal HttpException (int httpCode, string message, string resourceName, string description) : this (httpCode, message, resourceName)
102 this.description = description;
105 protected HttpException (SerializationInfo info, StreamingContext context)
106 : base (info, context)
108 http_code = info.GetInt32 ("_httpCode");
109 webEventCode = info.GetInt32 ("_webEventCode");
112 [SecurityPermission (SecurityAction.Demand, SerializationFormatter = true)]
113 public override void GetObjectData (SerializationInfo info, StreamingContext context)
115 base.GetObjectData (info, context);
116 info.AddValue ("_httpCode", http_code);
117 info.AddValue ("_webEventCode", webEventCode);
120 public HttpException (int httpCode, string message, int hr)
123 http_code = httpCode;
126 public HttpException (string message, int hr)
131 public HttpException (int httpCode, string message, Exception innerException)
132 : base (message, innerException)
134 http_code = httpCode;
137 internal HttpException (int httpCode, string message, Exception innerException, string resourceName)
138 : this (httpCode, message, innerException)
140 resource_name = resourceName;
143 [MonoTODO ("For now just the default template is created. Means of user-provided templates are to be implemented yet.")]
144 ExceptionPageTemplate GetPageTemplate ()
146 ExceptionPageTemplate template = new DefaultExceptionPageTemplate ();
152 public string GetHtmlErrorMessage ()
154 var values = new ExceptionPageTemplateValues ();
155 ExceptionPageTemplate template = PageTemplate;
158 values.Add (ExceptionPageTemplate.Template_RuntimeVersionInformationName, RuntimeHelpers.MonoVersion);
159 values.Add (ExceptionPageTemplate.Template_AspNetVersionInformationName, Environment.Version.ToString ());
161 HttpContext ctx = HttpContext.Current;
162 ExceptionPageTemplateType pageType = ExceptionPageTemplateType.Standard;
164 if (ctx != null && ctx.IsCustomErrorEnabled) {
165 if (http_code != 404 && http_code != 403) {
166 FillDefaultCustomErrorValues (values);
167 pageType = ExceptionPageTemplateType.CustomErrorDefault;
169 FillDefaultErrorValues (false, false, null, values);
171 Exception ex = GetBaseException ();
175 values.Add (ExceptionPageTemplate.Template_FullStackTraceName, FormatFullStackTrace ());
176 HtmlizedException htmlException = ex as HtmlizedException;
177 if (htmlException == null)
178 FillDefaultErrorValues (true, true, ex, values);
180 pageType = ExceptionPageTemplateType.Htmlized;
181 FillHtmlizedErrorValues (values, htmlException, ref pageType);
185 return template.Render (values, pageType);
186 } catch (Exception ex) {
187 Console.Error.WriteLine ("An exception has occurred while generating HttpException page:");
188 Console.Error.WriteLine (ex);
189 Console.Error.WriteLine ();
190 Console.Error.WriteLine ("The actual exception which was being reported was:");
191 Console.Error.WriteLine (this);
193 // we need the try/catch block in case the
194 // problem was with MapPath, which will cause
195 // IsCustomErrorEnabled to throw an exception
197 FillDefaultCustomErrorValues (values);
198 return template.Render (values, ExceptionPageTemplateType.CustomErrorDefault);
200 return DoubleFaultExceptionMessage;
205 internal virtual string Description {
207 if (description != null)
210 return DEFAULT_DESCRIPTION_TEXT;
214 if (value != null && value.Length > 0)
217 description = DEFAULT_DESCRIPTION_TEXT;
221 internal static HttpException NewWithCode (string message, int webEventCode)
223 var ret = new HttpException (message);
224 ret.SetWebEventCode (webEventCode);
229 internal static HttpException NewWithCode (string message, Exception innerException, int webEventCode)
231 var ret = new HttpException (message, innerException);
232 ret.SetWebEventCode (webEventCode);
237 internal static HttpException NewWithCode (int httpCode, string message, int webEventCode)
239 var ret = new HttpException (httpCode, message);
240 ret.SetWebEventCode (webEventCode);
245 internal static HttpException NewWithCode (int httpCode, string message, Exception innerException, string resourceName, int webEventCode)
247 var ret = new HttpException (httpCode, message, innerException, resourceName);
248 ret.SetWebEventCode (webEventCode);
253 internal static HttpException NewWithCode (int httpCode, string message, string resourceName, int webEventCode)
255 var ret = new HttpException (httpCode, message, resourceName);
256 ret.SetWebEventCode (webEventCode);
261 internal static HttpException NewWithCode (int httpCode, string message, Exception innerException, int webEventCode)
263 var ret = new HttpException (httpCode, message, innerException);
264 ret.SetWebEventCode (webEventCode);
269 internal void SetWebEventCode (int webEventCode)
271 this.webEventCode = webEventCode;
274 string FormatFullStackTrace ()
277 var builder = new StringBuilder ("\r\n<!--");
280 bool haveTrace, first = true;
283 trace = ex.StackTrace;
284 message = ex.Message;
285 haveTrace = !String.IsNullOrEmpty (trace);
287 if (!haveTrace && String.IsNullOrEmpty (message)) {
288 ex = ex.InnerException;
295 builder.Append ("\r\n");
297 builder.Append ("\r\n[" + ex.GetType () + "]: " + HtmlEncode (message) + "\r\n");
299 builder.Append (ex.StackTrace);
301 ex = ex.InnerException;
303 builder.Append ("\r\n-->\r\n");
305 return builder.ToString ();
308 void FillHtmlizedErrorValues (ExceptionPageTemplateValues values, HtmlizedException exc, ref ExceptionPageTemplateType pageType)
311 bool isParseException = false;
312 bool isCompileException = false;
314 bool isParseException = exc is ParseException;
315 bool isCompileException = (!isParseException && exc is CompilationException);
317 values.Add (ExceptionPageTemplate.Template_PageTitleName, HtmlEncode (exc.Title));
318 values.Add (ExceptionPageTemplate.Template_DescriptionName, HtmlEncode (exc.Description));
319 values.Add (ExceptionPageTemplate.Template_StackTraceName, HtmlEncode (exc.StackTrace));
320 values.Add (ExceptionPageTemplate.Template_ExceptionTypeName, exc.GetType ().ToString ());
321 values.Add (ExceptionPageTemplate.Template_ExceptionMessageName, HtmlEncode (exc.Message));
322 values.Add (ExceptionPageTemplate.Template_DetailsName, HtmlEncode (exc.ErrorMessage));
325 if (isParseException)
327 else if (isCompileException)
331 values.Add (ExceptionPageTemplate.Template_HtmlizedExceptionOriginName, origin);
332 if (exc.FileText != null) {
333 pageType |= ExceptionPageTemplateType.SourceError;
334 StringBuilder shortSource = new StringBuilder ();
335 StringBuilder longSource;
337 if (isCompileException)
338 longSource = new StringBuilder ();
341 FormatSource (shortSource, longSource, exc);
342 values.Add (ExceptionPageTemplate.Template_HtmlizedExceptionShortSourceName, shortSource.ToString ());
343 values.Add (ExceptionPageTemplate.Template_HtmlizedExceptionLongSourceName, longSource != null ? longSource.ToString () : null);
345 if (exc.SourceFile != exc.FileName)
346 values.Add (ExceptionPageTemplate.Template_HtmlizedExceptionSourceFileName, FormatSourceFile (exc.SourceFile));
348 values.Add (ExceptionPageTemplate.Template_HtmlizedExceptionSourceFileName, FormatSourceFile (exc.FileName));
349 if (isParseException || isCompileException) {
350 int[] errorLines = exc.ErrorLines;
351 int numErrors = errorLines != null ? errorLines.Length : 0;
352 var lines = new StringBuilder ();
353 for (int i = 0; i < numErrors; i++) {
356 lines.Append (errorLines [i]);
358 values.Add (ExceptionPageTemplate.Template_HtmlizedExceptionErrorLinesName, lines.ToString ());
361 values.Add (ExceptionPageTemplate.Template_HtmlizedExceptionSourceFileName, FormatSourceFile (exc.FileName));
364 if (isCompileException) {
365 CompilationException cex = exc as CompilationException;
366 StringCollection output = cex.CompilerOutput;
368 if (output != null && output.Count > 0) {
369 pageType |= ExceptionPageTemplateType.CompilerOutput;
370 var sb = new StringBuilder ();
372 foreach (string s in output) {
373 sb.Append (HtmlEncode (s));
381 values.Add (ExceptionPageTemplate.Template_HtmlizedExceptionCompilerOutputName, sb.ToString ());
387 void FillDefaultCustomErrorValues (ExceptionPageTemplateValues values)
389 values.Add (ExceptionPageTemplate.Template_PageTitleName, "Runtime Error");
390 values.Add (ExceptionPageTemplate.Template_ExceptionTypeName, "Runtime Error");
391 values.Add (ExceptionPageTemplate.Template_ExceptionMessageName, "A runtime error has occurred");
392 values.Add (ExceptionPageTemplate.Template_DescriptionName, "An application error occurred on the server. The current custom error settings for this application prevent the details of the application error from being viewed (for security reasons).");
393 values.Add (ExceptionPageTemplate.Template_DetailsName, "To enable the details of this specific error message to be viewable, please create a <customErrors> tag within a "web.config" configuration file located in the root directory of the current web application. This <customErrors> tag should then have its "mode" attribute set to "Off".");
396 void FillDefaultErrorValues (bool showTrace, bool showExceptionType, Exception baseEx, ExceptionPageTemplateValues values)
401 values.Add (ExceptionPageTemplate.Template_PageTitleName, String.Format ("Error{0}", http_code != 0 ? " " + http_code : String.Empty));
402 values.Add (ExceptionPageTemplate.Template_ExceptionTypeName, showExceptionType ? baseEx.GetType ().ToString () : "Runtime error");
403 values.Add (ExceptionPageTemplate.Template_ExceptionMessageName, http_code == 404 ? "The resource cannot be found." : HtmlEncode (baseEx.Message));
405 string tmp = http_code != 0 ? "HTTP " + http_code + "." : String.Empty;
406 values.Add (ExceptionPageTemplate.Template_DescriptionName, tmp + (http_code == 404 ? ERROR_404_DESCRIPTION : HtmlEncode (Description)));
408 if (!String.IsNullOrEmpty (resource_name))
409 values.Add (ExceptionPageTemplate.Template_DetailsName, "Requested URL: " + HtmlEncode (resource_name));
410 else if (http_code == 404)
411 values.Add (ExceptionPageTemplate.Template_DetailsName, "No virtual path information available.");
412 else if (baseEx is HttpException) {
413 tmp = ((HttpException)baseEx).Description;
414 values.Add (ExceptionPageTemplate.Template_DetailsName, !String.IsNullOrEmpty (tmp) ? HtmlEncode (tmp) : "Web exception occurred but no additional error description given.");
416 var sb = new StringBuilder ("Non-web exception.");
419 if (!String.IsNullOrEmpty (tmp))
420 sb.AppendFormat (" Exception origin (name of application or object): {0}.", HtmlEncode (tmp));
421 tmp = baseEx.HelpLink;
422 if (!String.IsNullOrEmpty (tmp))
423 sb.AppendFormat (" Additional information is available at {0}", HtmlEncode (tmp));
425 values.Add (ExceptionPageTemplate.Template_DetailsName, sb.ToString ());
429 string stackTrace = baseEx.StackTrace;
430 if (!String.IsNullOrEmpty (stackTrace))
431 values.Add (ExceptionPageTemplate.Template_StackTraceName, HtmlEncode (stackTrace));
435 static string HtmlEncode (string s)
437 if (String.IsNullOrEmpty (s))
440 string res = HttpUtility.HtmlEncode (s);
441 return res.Replace ("\r\n", "<br />");
444 string FormatSourceFile (string filename)
446 if (filename == null || filename.Length == 0)
449 if (filename.StartsWith ("@@"))
450 return "[internal] <!-- " + HttpUtility.HtmlEncode (filename) + " -->";
452 return HttpUtility.HtmlEncode (filename);
455 static void FormatSource (StringBuilder builder, StringBuilder longVersion, HtmlizedException e)
458 if (e is CompilationException)
459 WriteCompilationSource (builder, longVersion, e);
462 WritePageSource (builder, e);
465 static void WriteCompilationSource (StringBuilder builder, StringBuilder longVersion, HtmlizedException e)
467 int [] a = e.ErrorLines;
473 if (a != null && a.Length > 0)
476 int begin = errline - 2;
477 int end = errline + 2;
483 using (TextReader reader = new StringReader (e.FileText)) {
484 while ((s = reader.ReadLine ()) != null) {
486 if (line < begin || line > end) {
487 if (longVersion != null)
488 longVersion.AppendFormat ("{0}: {1}\r\n", line, HtmlEncode (s));
492 if (errline == line) {
493 if (longVersion != null)
494 longVersion.Append ("<span class=\"sourceErrorLine\">");
495 builder.Append ("<span class=\"sourceErrorLine\">");
498 tmp = String.Format ("{0}: {1}\r\n", line, HtmlEncode (s));
499 builder.Append (tmp);
500 if (longVersion != null)
501 longVersion.Append (tmp);
503 if (line == errline) {
504 builder.Append ("</span>");
505 if (longVersion != null)
506 longVersion.Append ("</span>");
507 errline = (++index < a.Length) ? a [index] : 0;
513 static void WritePageSource (StringBuilder builder, HtmlizedException e)
517 int beginerror = e.ErrorLines [0];
518 int enderror = e.ErrorLines [1];
519 int begin = beginerror - 2;
520 int end = enderror + 2;
524 TextReader reader = new StringReader (e.FileText);
525 while ((s = reader.ReadLine ()) != null) {
533 if (beginerror == line)
534 builder.Append ("<span class=\"sourceErrorLine\">");
536 builder.AppendFormat ("{0}: {1}\r\n", line, HtmlEncode (s));
538 if (enderror <= line) {
539 builder.Append ("</span>");
540 enderror = end + 1; // one shot
545 public int GetHttpCode ()
550 public static HttpException CreateFromLastError (string message)
552 WebTrace.WriteLine ("CreateFromLastError");
553 return new HttpException (message, 0);
556 // Putting this at the end so that the code above isn't bloated
557 const string DoubleFaultExceptionMessage = @"<?xml version=""1.0"" encoding=""utf-8""?>
558 <!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.0 Transitional//EN"" ""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"">
559 <html xmlns=""http://www.w3.org/1999/xhtml"">
561 <style type=""text/css"">
562 body { background-color: #FFFFFF; font-size: .75em; font-family: Verdana, Helvetica, Sans-Serif; margin: 0; padding: 0; color: #696969; }
563 a:link { color: #000000; text-decoration: underline; }
564 a:visited { color: #000000; }
565 a:hover { color: #000000; text-decoration: none; }
566 a:active { color: #12eb87; }
567 p, ul { margin-bottom: 20px; line-height: 1.6em; }
568 pre { font-size: 1.2em; margin-left: 20px; margin-top: 0px; }
569 h1, h2, h3, h4, h5, h6 { font-size: 1.6em; color: #000; font-family: Arial, Helvetica, sans-serif; }
570 h1 { font-weight: bold; margin-bottom: 0; margin-top: 0; padding-bottom: 0; }
571 h2 { font-size: 1em; padding: 0 0 0px 0; color: #696969; font-weight: normal; margin-top: 0; margin-bottom: 20px; }
572 h3 { font-size: 1.2em; }
573 h4 { font-size: 1.1em; }
574 h5, h6 { font-size: 1em; }
575 #header { position: relative; margin-bottom: 0px; color: #000; padding: 0; background-color: #5c87b2; height: 38px; padding-left: 10px; }
576 #header h1 { font-weight: bold; padding: 5px 0; margin: 0; color: #fff; border: none; line-height: 2em; font-family: Arial, Helvetica, sans-serif; font-size: 32px !important; }
577 #header-image { float: left; padding: 3px; margin-left: 1px; margin-right: 1px; }
578 #header-text { color: #fff; font-size: 1.4em; line-height: 38px; font-weight: bold; }
579 #main { padding: 20px 20px 15px 20px; background-color: #fff; _height: 1px; }
580 #footer { color: #999; padding: 5px 0; text-align: left; line-height: normal; margin: 20px 0px 0px 0px; font-size: .9em; border-top: solid 1px #5C87B2; }
581 #footer-powered-by { float: right; }
582 .details { font-family: monospace; border: solid 1px #e8eef4; white-space: pre; font-size: 1.2em; overflow: auto; padding: 6px; margin-top: 6px }
583 .details-wrapped { white-space: normal }
584 .details-header { margin-top: 1.5em }
585 .details-header a { font-weight: bold; text-decoration: none }
586 p { margin-bottom: 0.3em; margin-top: 0.1em }
587 .sourceErrorLine { color: #770000; font-weight: bold; }
590 <title>Double fault in exception reporting code</title>
593 <h1>Double fault in exception reporting code</h1>
594 <p>While generating HTML with exception report, a double fault has occurred. Please consult your server's console and/or log file to see the actual exception.</p>