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 ();
69 get { return webEventCode; }
72 public HttpException ()
76 public HttpException (string message)
81 public HttpException (string message, Exception innerException)
82 : base (message, innerException)
86 public HttpException (int httpCode, string message) : base (message)
91 internal HttpException (int httpCode, string message, string resourceName) : this (httpCode, message)
93 resource_name = resourceName;
96 internal HttpException (int httpCode, string message, string resourceName, string description) : this (httpCode, message, resourceName)
98 this.description = description;
101 protected HttpException (SerializationInfo info, StreamingContext context)
102 : base (info, context)
104 http_code = info.GetInt32 ("_httpCode");
105 webEventCode = info.GetInt32 ("_webEventCode");
108 [SecurityPermission (SecurityAction.Demand, SerializationFormatter = true)]
109 public override void GetObjectData (SerializationInfo info, StreamingContext context)
111 base.GetObjectData (info, context);
112 info.AddValue ("_httpCode", http_code);
113 info.AddValue ("_webEventCode", webEventCode);
116 public HttpException (int httpCode, string message, int hr)
119 http_code = httpCode;
122 public HttpException (string message, int hr)
127 public HttpException (int httpCode, string message, Exception innerException)
128 : base (message, innerException)
130 http_code = httpCode;
133 internal HttpException (int httpCode, string message, Exception innerException, string resourceName)
134 : this (httpCode, message, innerException)
136 resource_name = resourceName;
139 [MonoTODO ("For now just the default template is created. Means of user-provided templates are to be implemented yet.")]
140 ExceptionPageTemplate GetPageTemplate ()
142 ExceptionPageTemplate template = new DefaultExceptionPageTemplate ();
148 public string GetHtmlErrorMessage ()
150 var values = new ExceptionPageTemplateValues ();
151 ExceptionPageTemplate template = PageTemplate;
154 values.Add (ExceptionPageTemplate.Template_RuntimeVersionInformationName, RuntimeHelpers.MonoVersion);
155 values.Add (ExceptionPageTemplate.Template_AspNetVersionInformationName, Environment.Version.ToString ());
157 HttpContext ctx = HttpContext.Current;
158 ExceptionPageTemplateType pageType = ExceptionPageTemplateType.Standard;
160 if (ctx != null && ctx.IsCustomErrorEnabled) {
161 if (http_code != 404 && http_code != 403) {
162 FillDefaultCustomErrorValues (values);
163 pageType = ExceptionPageTemplateType.CustomErrorDefault;
165 FillDefaultErrorValues (false, false, null, values);
167 Exception ex = GetBaseException ();
171 values.Add (ExceptionPageTemplate.Template_FullStackTraceName, FormatFullStackTrace ());
172 HtmlizedException htmlException = ex as HtmlizedException;
173 if (htmlException == null)
174 FillDefaultErrorValues (true, true, ex, values);
176 pageType = ExceptionPageTemplateType.Htmlized;
177 FillHtmlizedErrorValues (values, htmlException, ref pageType);
181 return template.Render (values, pageType);
182 } catch (Exception ex) {
183 Console.Error.WriteLine ("An exception has occurred while generating HttpException page:");
184 Console.Error.WriteLine (ex);
185 Console.Error.WriteLine ();
186 Console.Error.WriteLine ("The actual exception which was being reported was:");
187 Console.Error.WriteLine (this);
189 // we need the try/catch block in case the
190 // problem was with MapPath, which will cause
191 // IsCustomErrorEnabled to throw an exception
193 FillDefaultCustomErrorValues (values);
194 return template.Render (values, ExceptionPageTemplateType.CustomErrorDefault);
196 return DoubleFaultExceptionMessage;
201 internal virtual string Description {
203 if (description != null)
206 return DEFAULT_DESCRIPTION_TEXT;
210 if (value != null && value.Length > 0)
213 description = DEFAULT_DESCRIPTION_TEXT;
217 internal static HttpException NewWithCode (string message, int webEventCode)
219 var ret = new HttpException (message);
220 ret.SetWebEventCode (webEventCode);
225 internal static HttpException NewWithCode (string message, Exception innerException, int webEventCode)
227 var ret = new HttpException (message, innerException);
228 ret.SetWebEventCode (webEventCode);
233 internal static HttpException NewWithCode (int httpCode, string message, int webEventCode)
235 var ret = new HttpException (httpCode, message);
236 ret.SetWebEventCode (webEventCode);
241 internal static HttpException NewWithCode (int httpCode, string message, Exception innerException, string resourceName, int webEventCode)
243 var ret = new HttpException (httpCode, message, innerException, resourceName);
244 ret.SetWebEventCode (webEventCode);
249 internal static HttpException NewWithCode (int httpCode, string message, string resourceName, int webEventCode)
251 var ret = new HttpException (httpCode, message, resourceName);
252 ret.SetWebEventCode (webEventCode);
257 internal static HttpException NewWithCode (int httpCode, string message, Exception innerException, int webEventCode)
259 var ret = new HttpException (httpCode, message, innerException);
260 ret.SetWebEventCode (webEventCode);
265 internal void SetWebEventCode (int webEventCode)
267 this.webEventCode = webEventCode;
270 string FormatFullStackTrace ()
273 var builder = new StringBuilder ("\r\n<!--");
276 bool haveTrace, first = true;
279 trace = ex.StackTrace;
280 message = ex.Message;
281 haveTrace = !String.IsNullOrEmpty (trace);
283 if (!haveTrace && String.IsNullOrEmpty (message)) {
284 ex = ex.InnerException;
291 builder.Append ("\r\n");
293 builder.Append ("\r\n[" + ex.GetType () + "]: " + HtmlEncode (message) + "\r\n");
295 builder.Append (ex.StackTrace);
297 ex = ex.InnerException;
299 builder.Append ("\r\n-->\r\n");
301 return builder.ToString ();
304 void FillHtmlizedErrorValues (ExceptionPageTemplateValues values, HtmlizedException exc, ref ExceptionPageTemplateType pageType)
306 bool isParseException = exc is ParseException;
307 bool isCompileException = (!isParseException && exc is CompilationException);
308 values.Add (ExceptionPageTemplate.Template_PageTitleName, HtmlEncode (exc.Title));
309 values.Add (ExceptionPageTemplate.Template_DescriptionName, HtmlEncode (exc.Description));
310 values.Add (ExceptionPageTemplate.Template_StackTraceName, HtmlEncode (exc.StackTrace));
311 values.Add (ExceptionPageTemplate.Template_ExceptionTypeName, exc.GetType ().ToString ());
312 values.Add (ExceptionPageTemplate.Template_ExceptionMessageName, HtmlEncode (exc.Message));
313 values.Add (ExceptionPageTemplate.Template_DetailsName, HtmlEncode (exc.ErrorMessage));
316 if (isParseException)
318 else if (isCompileException)
322 values.Add (ExceptionPageTemplate.Template_HtmlizedExceptionOriginName, origin);
323 if (exc.FileText != null) {
324 pageType |= ExceptionPageTemplateType.SourceError;
325 StringBuilder shortSource = new StringBuilder ();
326 StringBuilder longSource;
328 if (isCompileException)
329 longSource = new StringBuilder ();
332 FormatSource (shortSource, longSource, exc);
333 values.Add (ExceptionPageTemplate.Template_HtmlizedExceptionShortSourceName, shortSource.ToString ());
334 values.Add (ExceptionPageTemplate.Template_HtmlizedExceptionLongSourceName, longSource != null ? longSource.ToString () : null);
336 if (exc.SourceFile != exc.FileName)
337 values.Add (ExceptionPageTemplate.Template_HtmlizedExceptionSourceFileName, FormatSourceFile (exc.SourceFile));
339 values.Add (ExceptionPageTemplate.Template_HtmlizedExceptionSourceFileName, FormatSourceFile (exc.FileName));
340 if (isParseException || isCompileException) {
341 int[] errorLines = exc.ErrorLines;
342 int numErrors = errorLines != null ? errorLines.Length : 0;
343 var lines = new StringBuilder ();
344 for (int i = 0; i < numErrors; i++) {
347 lines.Append (errorLines [i]);
349 values.Add (ExceptionPageTemplate.Template_HtmlizedExceptionErrorLinesName, lines.ToString ());
352 values.Add (ExceptionPageTemplate.Template_HtmlizedExceptionSourceFileName, FormatSourceFile (exc.FileName));
354 if (isCompileException) {
355 CompilationException cex = exc as CompilationException;
356 StringCollection output = cex.CompilerOutput;
358 if (output != null && output.Count > 0) {
359 pageType |= ExceptionPageTemplateType.CompilerOutput;
360 var sb = new StringBuilder ();
362 foreach (string s in output) {
363 sb.Append (HtmlEncode (s));
371 values.Add (ExceptionPageTemplate.Template_HtmlizedExceptionCompilerOutputName, sb.ToString ());
376 void FillDefaultCustomErrorValues (ExceptionPageTemplateValues values)
378 values.Add (ExceptionPageTemplate.Template_PageTitleName, "Runtime Error");
379 values.Add (ExceptionPageTemplate.Template_ExceptionTypeName, "Runtime Error");
380 values.Add (ExceptionPageTemplate.Template_ExceptionMessageName, "A runtime error has occurred");
381 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).");
382 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".");
385 void FillDefaultErrorValues (bool showTrace, bool showExceptionType, Exception baseEx, ExceptionPageTemplateValues values)
390 values.Add (ExceptionPageTemplate.Template_PageTitleName, String.Format ("Error{0}", http_code != 0 ? " " + http_code : String.Empty));
391 values.Add (ExceptionPageTemplate.Template_ExceptionTypeName, showExceptionType ? baseEx.GetType ().ToString () : "Runtime error");
392 values.Add (ExceptionPageTemplate.Template_ExceptionMessageName, http_code == 404 ? "The resource cannot be found." : HtmlEncode (baseEx.Message));
394 string tmp = http_code != 0 ? "HTTP " + http_code + "." : String.Empty;
395 values.Add (ExceptionPageTemplate.Template_DescriptionName, tmp + (http_code == 404 ? ERROR_404_DESCRIPTION : HtmlEncode (Description)));
397 if (!String.IsNullOrEmpty (resource_name))
398 values.Add (ExceptionPageTemplate.Template_DetailsName, "Requested URL: " + HtmlEncode (resource_name));
399 else if (http_code == 404)
400 values.Add (ExceptionPageTemplate.Template_DetailsName, "No virtual path information available.");
401 else if (baseEx is HttpException) {
402 tmp = ((HttpException)baseEx).Description;
403 values.Add (ExceptionPageTemplate.Template_DetailsName, !String.IsNullOrEmpty (tmp) ? HtmlEncode (tmp) : "Web exception occurred but no additional error description given.");
405 var sb = new StringBuilder ("Non-web exception.");
408 if (!String.IsNullOrEmpty (tmp))
409 sb.AppendFormat (" Exception origin (name of application or object): {0}.", HtmlEncode (tmp));
410 tmp = baseEx.HelpLink;
411 if (!String.IsNullOrEmpty (tmp))
412 sb.AppendFormat (" Additional information is available at {0}", HtmlEncode (tmp));
414 values.Add (ExceptionPageTemplate.Template_DetailsName, sb.ToString ());
418 string stackTrace = baseEx.StackTrace;
419 if (!String.IsNullOrEmpty (stackTrace))
420 values.Add (ExceptionPageTemplate.Template_StackTraceName, HtmlEncode (stackTrace));
424 static string HtmlEncode (string s)
426 if (String.IsNullOrEmpty (s))
429 string res = HttpUtility.HtmlEncode (s);
430 return res.Replace ("\r\n", "<br />");
433 string FormatSourceFile (string filename)
435 if (filename == null || filename.Length == 0)
438 if (filename.StartsWith ("@@"))
439 return "[internal] <!-- " + HttpUtility.HtmlEncode (filename) + " -->";
441 return HttpUtility.HtmlEncode (filename);
444 static void FormatSource (StringBuilder builder, StringBuilder longVersion, HtmlizedException e)
446 if (e is CompilationException)
447 WriteCompilationSource (builder, longVersion, e);
449 WritePageSource (builder, e);
452 static void WriteCompilationSource (StringBuilder builder, StringBuilder longVersion, HtmlizedException e)
454 int [] a = e.ErrorLines;
460 if (a != null && a.Length > 0)
463 int begin = errline - 2;
464 int end = errline + 2;
470 using (TextReader reader = new StringReader (e.FileText)) {
471 while ((s = reader.ReadLine ()) != null) {
473 if (line < begin || line > end) {
474 if (longVersion != null)
475 longVersion.AppendFormat ("{0}: {1}\r\n", line, HtmlEncode (s));
479 if (errline == line) {
480 if (longVersion != null)
481 longVersion.Append ("<span class=\"sourceErrorLine\">");
482 builder.Append ("<span class=\"sourceErrorLine\">");
485 tmp = String.Format ("{0}: {1}\r\n", line, HtmlEncode (s));
486 builder.Append (tmp);
487 if (longVersion != null)
488 longVersion.Append (tmp);
490 if (line == errline) {
491 builder.Append ("</span>");
492 if (longVersion != null)
493 longVersion.Append ("</span>");
494 errline = (++index < a.Length) ? a [index] : 0;
500 static void WritePageSource (StringBuilder builder, HtmlizedException e)
504 int beginerror = e.ErrorLines [0];
505 int enderror = e.ErrorLines [1];
506 int begin = beginerror - 2;
507 int end = enderror + 2;
511 TextReader reader = new StringReader (e.FileText);
512 while ((s = reader.ReadLine ()) != null) {
520 if (beginerror == line)
521 builder.Append ("<span class=\"sourceErrorLine\">");
523 builder.AppendFormat ("{0}: {1}\r\n", line, HtmlEncode (s));
525 if (enderror <= line) {
526 builder.Append ("</span>");
527 enderror = end + 1; // one shot
532 public int GetHttpCode ()
537 public static HttpException CreateFromLastError (string message)
539 WebTrace.WriteLine ("CreateFromLastError");
540 return new HttpException (message, 0);
543 // Putting this at the end so that the code above isn't bloated
544 const string DoubleFaultExceptionMessage = @"<?xml version=""1.0"" encoding=""utf-8""?>
545 <!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.0 Transitional//EN"" ""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"">
546 <html xmlns=""http://www.w3.org/1999/xhtml"">
548 <style type=""text/css"">
549 body { background-color: #FFFFFF; font-size: .75em; font-family: Verdana, Helvetica, Sans-Serif; margin: 0; padding: 0; color: #696969; }
550 a:link { color: #000000; text-decoration: underline; }
551 a:visited { color: #000000; }
552 a:hover { color: #000000; text-decoration: none; }
553 a:active { color: #12eb87; }
554 p, ul { margin-bottom: 20px; line-height: 1.6em; }
555 pre { font-size: 1.2em; margin-left: 20px; margin-top: 0px; }
556 h1, h2, h3, h4, h5, h6 { font-size: 1.6em; color: #000; font-family: Arial, Helvetica, sans-serif; }
557 h1 { font-weight: bold; margin-bottom: 0; margin-top: 0; padding-bottom: 0; }
558 h2 { font-size: 1em; padding: 0 0 0px 0; color: #696969; font-weight: normal; margin-top: 0; margin-bottom: 20px; }
559 h3 { font-size: 1.2em; }
560 h4 { font-size: 1.1em; }
561 h5, h6 { font-size: 1em; }
562 #header { position: relative; margin-bottom: 0px; color: #000; padding: 0; background-color: #5c87b2; height: 38px; padding-left: 10px; }
563 #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; }
564 #header-image { float: left; padding: 3px; margin-left: 1px; margin-right: 1px; }
565 #header-text { color: #fff; font-size: 1.4em; line-height: 38px; font-weight: bold; }
566 #main { padding: 20px 20px 15px 20px; background-color: #fff; _height: 1px; }
567 #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; }
568 #footer-powered-by { float: right; }
569 .details { font-family: monospace; border: solid 1px #e8eef4; white-space: pre; font-size: 1.2em; overflow: auto; padding: 6px; margin-top: 6px }
570 .details-wrapped { white-space: normal }
571 .details-header { margin-top: 1.5em }
572 .details-header a { font-weight: bold; text-decoration: none }
573 p { margin-bottom: 0.3em; margin-top: 0.1em }
574 .sourceErrorLine { color: #770000; font-weight: bold; }
577 <title>Double fault in exception reporting code</title>
580 <h1>Double fault in exception reporting code</h1>
581 <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>