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)
310 bool isParseException = exc is ParseException;
311 bool isCompileException = (!isParseException && exc is CompilationException);
312 values.Add (ExceptionPageTemplate.Template_PageTitleName, HtmlEncode (exc.Title));
313 values.Add (ExceptionPageTemplate.Template_DescriptionName, HtmlEncode (exc.Description));
314 values.Add (ExceptionPageTemplate.Template_StackTraceName, HtmlEncode (exc.StackTrace));
315 values.Add (ExceptionPageTemplate.Template_ExceptionTypeName, exc.GetType ().ToString ());
316 values.Add (ExceptionPageTemplate.Template_ExceptionMessageName, HtmlEncode (exc.Message));
317 values.Add (ExceptionPageTemplate.Template_DetailsName, HtmlEncode (exc.ErrorMessage));
320 if (isParseException)
322 else if (isCompileException)
326 values.Add (ExceptionPageTemplate.Template_HtmlizedExceptionOriginName, origin);
327 if (exc.FileText != null) {
328 pageType |= ExceptionPageTemplateType.SourceError;
329 StringBuilder shortSource = new StringBuilder ();
330 StringBuilder longSource;
332 if (isCompileException)
333 longSource = new StringBuilder ();
336 FormatSource (shortSource, longSource, exc);
337 values.Add (ExceptionPageTemplate.Template_HtmlizedExceptionShortSourceName, shortSource.ToString ());
338 values.Add (ExceptionPageTemplate.Template_HtmlizedExceptionLongSourceName, longSource != null ? longSource.ToString () : null);
340 if (exc.SourceFile != exc.FileName)
341 values.Add (ExceptionPageTemplate.Template_HtmlizedExceptionSourceFileName, FormatSourceFile (exc.SourceFile));
343 values.Add (ExceptionPageTemplate.Template_HtmlizedExceptionSourceFileName, FormatSourceFile (exc.FileName));
344 if (isParseException || isCompileException) {
345 int[] errorLines = exc.ErrorLines;
346 int numErrors = errorLines != null ? errorLines.Length : 0;
347 var lines = new StringBuilder ();
348 for (int i = 0; i < numErrors; i++) {
351 lines.Append (errorLines [i]);
353 values.Add (ExceptionPageTemplate.Template_HtmlizedExceptionErrorLinesName, lines.ToString ());
356 values.Add (ExceptionPageTemplate.Template_HtmlizedExceptionSourceFileName, FormatSourceFile (exc.FileName));
358 if (isCompileException) {
359 CompilationException cex = exc as CompilationException;
360 StringCollection output = cex.CompilerOutput;
362 if (output != null && output.Count > 0) {
363 pageType |= ExceptionPageTemplateType.CompilerOutput;
364 var sb = new StringBuilder ();
366 foreach (string s in output) {
367 sb.Append (HtmlEncode (s));
375 values.Add (ExceptionPageTemplate.Template_HtmlizedExceptionCompilerOutputName, sb.ToString ());
380 void FillDefaultCustomErrorValues (ExceptionPageTemplateValues values)
382 values.Add (ExceptionPageTemplate.Template_PageTitleName, "Runtime Error");
383 values.Add (ExceptionPageTemplate.Template_ExceptionTypeName, "Runtime Error");
384 values.Add (ExceptionPageTemplate.Template_ExceptionMessageName, "A runtime error has occurred");
385 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).");
386 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".");
389 void FillDefaultErrorValues (bool showTrace, bool showExceptionType, Exception baseEx, ExceptionPageTemplateValues values)
394 values.Add (ExceptionPageTemplate.Template_PageTitleName, String.Format ("Error{0}", http_code != 0 ? " " + http_code : String.Empty));
395 values.Add (ExceptionPageTemplate.Template_ExceptionTypeName, showExceptionType ? baseEx.GetType ().ToString () : "Runtime error");
396 values.Add (ExceptionPageTemplate.Template_ExceptionMessageName, http_code == 404 ? "The resource cannot be found." : HtmlEncode (baseEx.Message));
398 string tmp = http_code != 0 ? "HTTP " + http_code + "." : String.Empty;
399 values.Add (ExceptionPageTemplate.Template_DescriptionName, tmp + (http_code == 404 ? ERROR_404_DESCRIPTION : HtmlEncode (Description)));
401 if (!String.IsNullOrEmpty (resource_name))
402 values.Add (ExceptionPageTemplate.Template_DetailsName, "Requested URL: " + HtmlEncode (resource_name));
403 else if (http_code == 404)
404 values.Add (ExceptionPageTemplate.Template_DetailsName, "No virtual path information available.");
405 else if (baseEx is HttpException) {
406 tmp = ((HttpException)baseEx).Description;
407 values.Add (ExceptionPageTemplate.Template_DetailsName, !String.IsNullOrEmpty (tmp) ? HtmlEncode (tmp) : "Web exception occurred but no additional error description given.");
409 var sb = new StringBuilder ("Non-web exception.");
412 if (!String.IsNullOrEmpty (tmp))
413 sb.AppendFormat (" Exception origin (name of application or object): {0}.", HtmlEncode (tmp));
414 tmp = baseEx.HelpLink;
415 if (!String.IsNullOrEmpty (tmp))
416 sb.AppendFormat (" Additional information is available at {0}", HtmlEncode (tmp));
418 values.Add (ExceptionPageTemplate.Template_DetailsName, sb.ToString ());
422 string stackTrace = baseEx.StackTrace;
423 if (!String.IsNullOrEmpty (stackTrace))
424 values.Add (ExceptionPageTemplate.Template_StackTraceName, HtmlEncode (stackTrace));
428 static string HtmlEncode (string s)
430 if (String.IsNullOrEmpty (s))
433 string res = HttpUtility.HtmlEncode (s);
434 return res.Replace ("\r\n", "<br />");
437 string FormatSourceFile (string filename)
439 if (filename == null || filename.Length == 0)
442 if (filename.StartsWith ("@@"))
443 return "[internal] <!-- " + HttpUtility.HtmlEncode (filename) + " -->";
445 return HttpUtility.HtmlEncode (filename);
448 static void FormatSource (StringBuilder builder, StringBuilder longVersion, HtmlizedException e)
450 if (e is CompilationException)
451 WriteCompilationSource (builder, longVersion, e);
453 WritePageSource (builder, e);
456 static void WriteCompilationSource (StringBuilder builder, StringBuilder longVersion, HtmlizedException e)
458 int [] a = e.ErrorLines;
464 if (a != null && a.Length > 0)
467 int begin = errline - 2;
468 int end = errline + 2;
474 using (TextReader reader = new StringReader (e.FileText)) {
475 while ((s = reader.ReadLine ()) != null) {
477 if (line < begin || line > end) {
478 if (longVersion != null)
479 longVersion.AppendFormat ("{0}: {1}\r\n", line, HtmlEncode (s));
483 if (errline == line) {
484 if (longVersion != null)
485 longVersion.Append ("<span class=\"sourceErrorLine\">");
486 builder.Append ("<span class=\"sourceErrorLine\">");
489 tmp = String.Format ("{0}: {1}\r\n", line, HtmlEncode (s));
490 builder.Append (tmp);
491 if (longVersion != null)
492 longVersion.Append (tmp);
494 if (line == errline) {
495 builder.Append ("</span>");
496 if (longVersion != null)
497 longVersion.Append ("</span>");
498 errline = (++index < a.Length) ? a [index] : 0;
504 static void WritePageSource (StringBuilder builder, HtmlizedException e)
508 int beginerror = e.ErrorLines [0];
509 int enderror = e.ErrorLines [1];
510 int begin = beginerror - 2;
511 int end = enderror + 2;
515 TextReader reader = new StringReader (e.FileText);
516 while ((s = reader.ReadLine ()) != null) {
524 if (beginerror == line)
525 builder.Append ("<span class=\"sourceErrorLine\">");
527 builder.AppendFormat ("{0}: {1}\r\n", line, HtmlEncode (s));
529 if (enderror <= line) {
530 builder.Append ("</span>");
531 enderror = end + 1; // one shot
536 public int GetHttpCode ()
541 public static HttpException CreateFromLastError (string message)
543 WebTrace.WriteLine ("CreateFromLastError");
544 return new HttpException (message, 0);
547 // Putting this at the end so that the code above isn't bloated
548 const string DoubleFaultExceptionMessage = @"<?xml version=""1.0"" encoding=""utf-8""?>
549 <!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.0 Transitional//EN"" ""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"">
550 <html xmlns=""http://www.w3.org/1999/xhtml"">
552 <style type=""text/css"">
553 body { background-color: #FFFFFF; font-size: .75em; font-family: Verdana, Helvetica, Sans-Serif; margin: 0; padding: 0; color: #696969; }
554 a:link { color: #000000; text-decoration: underline; }
555 a:visited { color: #000000; }
556 a:hover { color: #000000; text-decoration: none; }
557 a:active { color: #12eb87; }
558 p, ul { margin-bottom: 20px; line-height: 1.6em; }
559 pre { font-size: 1.2em; margin-left: 20px; margin-top: 0px; }
560 h1, h2, h3, h4, h5, h6 { font-size: 1.6em; color: #000; font-family: Arial, Helvetica, sans-serif; }
561 h1 { font-weight: bold; margin-bottom: 0; margin-top: 0; padding-bottom: 0; }
562 h2 { font-size: 1em; padding: 0 0 0px 0; color: #696969; font-weight: normal; margin-top: 0; margin-bottom: 20px; }
563 h3 { font-size: 1.2em; }
564 h4 { font-size: 1.1em; }
565 h5, h6 { font-size: 1em; }
566 #header { position: relative; margin-bottom: 0px; color: #000; padding: 0; background-color: #5c87b2; height: 38px; padding-left: 10px; }
567 #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; }
568 #header-image { float: left; padding: 3px; margin-left: 1px; margin-right: 1px; }
569 #header-text { color: #fff; font-size: 1.4em; line-height: 38px; font-weight: bold; }
570 #main { padding: 20px 20px 15px 20px; background-color: #fff; _height: 1px; }
571 #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; }
572 #footer-powered-by { float: right; }
573 .details { font-family: monospace; border: solid 1px #e8eef4; white-space: pre; font-size: 1.2em; overflow: auto; padding: 6px; margin-top: 6px }
574 .details-wrapped { white-space: normal }
575 .details-header { margin-top: 1.5em }
576 .details-header a { font-weight: bold; text-decoration: none }
577 p { margin-bottom: 0.3em; margin-top: 0.1em }
578 .sourceErrorLine { color: #770000; font-weight: bold; }
581 <title>Double fault in exception reporting code</title>
584 <h1>Double fault in exception reporting code</h1>
585 <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>