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;
58 const string errorStyleFonts = "\"Verdana\",\"DejaVu Sans\",sans-serif";
67 get { return webEventCode; }
70 public HttpException ()
74 public HttpException (string message)
79 public HttpException (string message, Exception innerException)
80 : base (message, innerException)
84 public HttpException (int httpCode, string message) : base (message)
89 internal HttpException (int httpCode, string message, string resourceName) : this (httpCode, message)
91 resource_name = resourceName;
94 internal HttpException (int httpCode, string message, string resourceName, string description) : this (httpCode, message, resourceName)
96 this.description = description;
99 protected HttpException (SerializationInfo info, StreamingContext context)
100 : base (info, context)
102 http_code = info.GetInt32 ("_httpCode");
103 webEventCode = info.GetInt32 ("_webEventCode");
106 [SecurityPermission (SecurityAction.Demand, SerializationFormatter = true)]
107 public override void GetObjectData (SerializationInfo info, StreamingContext context)
109 base.GetObjectData (info, context);
110 info.AddValue ("_httpCode", http_code);
111 info.AddValue ("_webEventCode", webEventCode);
114 public HttpException (int httpCode, string message, int hr)
117 http_code = httpCode;
120 public HttpException (string message, int hr)
125 public HttpException (int httpCode, string message, Exception innerException)
126 : base (message, innerException)
128 http_code = httpCode;
131 internal HttpException (int httpCode, string message, Exception innerException, string resourceName)
132 : this (httpCode, message, innerException)
134 resource_name = resourceName;
137 public string GetHtmlErrorMessage ()
140 HttpContext ctx = HttpContext.Current;
141 if (ctx != null && ctx.IsCustomErrorEnabled) {
142 if (http_code != 404 && http_code != 403)
143 return GetCustomErrorDefaultMessage ();
145 return GetDefaultErrorMessage (false, null);
148 Exception ex = GetBaseException ();
152 HtmlizedException htmlException = ex as HtmlizedException;
153 if (htmlException == null)
154 return GetDefaultErrorMessage (true, ex);
156 return GetHtmlizedErrorMessage (htmlException);
157 } catch (Exception ex) {
158 Console.WriteLine (ex);
160 // we need the try/catch block in case the
161 // problem was with MapPath, which will cause
162 // IsCustomErrorEnabled to throw an exception
163 return GetCustomErrorDefaultMessage ();
167 internal virtual string Description {
169 if (description != null)
172 return DEFAULT_DESCRIPTION_TEXT;
176 if (value != null && value.Length > 0)
179 description = DEFAULT_DESCRIPTION_TEXT;
183 internal static HttpException NewWithCode (string message, int webEventCode)
185 var ret = new HttpException (message);
186 ret.SetWebEventCode (webEventCode);
191 internal static HttpException NewWithCode (string message, Exception innerException, int webEventCode)
193 var ret = new HttpException (message, innerException);
194 ret.SetWebEventCode (webEventCode);
199 internal static HttpException NewWithCode (int httpCode, string message, int webEventCode)
201 var ret = new HttpException (httpCode, message);
202 ret.SetWebEventCode (webEventCode);
207 internal static HttpException NewWithCode (int httpCode, string message, Exception innerException, string resourceName, int webEventCode)
209 var ret = new HttpException (httpCode, message, innerException, resourceName);
210 ret.SetWebEventCode (webEventCode);
215 internal static HttpException NewWithCode (int httpCode, string message, string resourceName, int webEventCode)
217 var ret = new HttpException (httpCode, message, resourceName);
218 ret.SetWebEventCode (webEventCode);
223 internal static HttpException NewWithCode (int httpCode, string message, Exception innerException, int webEventCode)
225 var ret = new HttpException (httpCode, message, innerException);
226 ret.SetWebEventCode (webEventCode);
231 internal void SetWebEventCode (int webEventCode)
233 this.webEventCode = webEventCode;
236 void WriteFileTop (StringBuilder builder, string title)
239 builder.AppendFormat ("<html><head><title>{0}</title><style type=\"text/css\">", title);
240 builder.AppendFormat (
241 @"body {{font-family:{0};font-weight:normal;font-size: 9pt;color:black;background-color: white}}
242 p {{font-family:{0};font-weight:normal;color:black;margin-top: -5px}}
243 b {{font-family:{0};font-weight:bold;color:black;margin-top: -5px}}
244 h1 {{ font-family:{0};font-weight:normal;font-size:18pt;color:red }}
245 h2 {{ font-family:{0};font-weight:normal;font-size:14pt;color:maroon }}
246 pre {{font-family:""Lucida Console"",""DejaVu Sans Mono"",monospace;font-size: 10pt}}
247 div.bodyText {{font-family: {0}}}
248 table.sampleCode {{width: 100%; background-color: #ffffcc; }}
249 .errorText {{color: red; font-weight: bold}}
250 .marker {{font-weight: bold; color: black;text-decoration: none;}}
251 .version {{color: gray;}}
252 .error {{margin-bottom: 10px;}}
253 .expandable {{ text-decoration:underline; font-weight:bold; color:navy; cursor:pointer; }}", errorStyleFonts);
255 builder.Append ("<?xml version=\"1.0\" ?>\n");
256 builder.Append ("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");
257 builder.AppendFormat ("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\"><head><title>{0}</title><style type=\"text/css\">", title);
258 builder.AppendFormat (
259 @"body {{font-family:{0};font-weight:normal;font-size: .7em;color:black;background-color: white}}
260 p {{font-family:{0};font-weight:normal;color:black;margin-top: -5px}}
261 b {{font-family:{0};font-weight:bold;color:black;margin-top: -5px}}
262 h1 {{ font-family:{0};font-weight:normal;font-size:18pt;color:red }}
263 h2 {{ font-family:{0};font-weight:normal;font-size:14pt;color:maroon }}
264 pre,code {{font-family:""Lucida Console"",""DejaVu Sans Mono"",monospace;font-size: 0.9em,white-space: pre-line}}
265 div.bodyText {{font-family: {0}}}
266 table.sampleCode {{width: 100%; background-color: #ffffcc; }}
267 .errorText {{color: red; font-weight: bold}}
268 .marker {{font-weight: bold; color: black;text-decoration: none;}}
269 .version {{color: gray;}}
270 .error {{margin-bottom: 10px;}}
271 .expandable {{ text-decoration:underline; font-weight:bold; color:navy; cursor:pointer; }}", errorStyleFonts);
274 builder.AppendFormat (
275 "</style></head><body><h1>Server Error in '{0}' Application</h1><hr style=\"color: silver\"/>",
276 HtmlEncode (HttpRuntime.AppDomainAppVirtualPath));
279 void WriteFileBottom (StringBuilder builder, bool showTrace)
282 builder.Append ("<hr style=\"color: silver\"/>");
283 builder.AppendFormat ("<strong>Version information: </strong> Mono Runtime Version: <tt>{0}</tt>; ASP.NET Version: <tt>{1}</tt></body></html>\r\n",
284 RuntimeHelpers.MonoVersion, Environment.Version);
286 string trace, message;
290 builder.Append ("\r\n<!--");
292 trace = ex.StackTrace;
293 message = ex.Message;
294 haveTrace = (trace != null && trace.Length > 0);
296 if (!haveTrace && (message == null || message.Length == 0)) {
297 ex = ex.InnerException;
301 builder.Append ("\r\n[" + ex.GetType () + "]: " + HtmlEncode (message) + "\r\n");
303 builder.Append (ex.StackTrace);
305 ex = ex.InnerException;
308 builder.Append ("\r\n-->");
310 builder.Append ("</body></html>\r\n");
313 string GetCustomErrorDefaultMessage ()
315 StringBuilder builder = new StringBuilder ();
316 WriteFileTop (builder, "Runtime Error");
317 #if TARGET_J2EE //on portal we cannot know if we run locally
318 if (!HttpContext.Current.IsServletRequest)
320 @"<p><strong>Description:</strong> 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).</p>
321 <p><strong>Details:</strong> 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".</p>
322 <table class=""sampleCode""><tr><td><pre>
324 <!-- Web.Config Configuration File -->
326 <configuration>
329 <customErrors mode="Off"/>
331 </configuration></pre>
332 </td></tr></table><br/>
336 builder.Append (@"<p><strong>Description:</strong> 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 remotely (for security reasons)." + (
337 " It could, however, be viewed by browsers running on the local server machine.")
339 <p><strong>Details:</strong> To enable the details of this specific error message to be viewable on remote machines, 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".</p>
340 <table class=""sampleCode""><tr><td><pre>
342 <!-- Web.Config Configuration File -->
344 <configuration>
347 <customErrors mode="Off"/>
349 </configuration></pre>
350 </td></tr></table><br/>
351 <p><strong>Notes:</strong> The current error page you are seeing can be replaced by a custom error page by modifying the "defaultRedirect" attribute of the application's <customErrors> configuration tag to point to a custom error page URL.</p>
352 <table class=""sampleCode""><tr><td><pre>
353 <!-- Web.Config Configuration File -->
355 <configuration>
357 <customErrors mode="RemoteOnly" defaultRedirect="mycustompage.htm"/>
360 </configuration></pre></td></tr></table>");
361 WriteFileBottom (builder, false);
362 return builder.ToString ();
365 string GetDefaultErrorMessage (bool showTrace, Exception baseEx)
372 StringBuilder builder = new StringBuilder ();
373 WriteFileTop (builder, String.Format ("Error{0}", http_code != 0 ? " " + http_code : String.Empty));
374 builder.Append ("<h2><em>");
375 if (http_code == 404)
376 builder.Append ("The resource cannot be found.");
378 builder.Append (HtmlEncode (ex.Message));
379 builder.Append ("</em></h2>\r\n<p><strong>Description: </strong>");
382 builder.AppendFormat ("HTTP {0}. ", http_code);
383 builder.Append (http_code == 404 ? ERROR_404_DESCRIPTION : HtmlEncode (Description));
384 builder.Append ("</p>\r\n");
386 if (resource_name != null && resource_name.Length > 0)
387 builder.AppendFormat ("<p><strong>Requested URL: </strong>{0}</p>\r\n", resource_name);
389 if (showTrace && baseEx != null && http_code != 404 && http_code != 403) {
390 builder.Append ("<p><strong>Stack Trace: </strong></p>");
391 builder.Append ("<table summary=\"Stack Trace\" class=\"sampleCode\">\r\n<tr><td>");
392 WriteTextAsCode (builder, baseEx.ToString ());
393 builder.Append ("</td></tr>\r\n</table>\r\n");
395 WriteFileBottom (builder, showTrace);
397 return builder.ToString ();
400 static string HtmlEncode (string s)
405 string res = HttpUtility.HtmlEncode (s);
406 return res.Replace ("\r\n", "<br />");
409 string FormatSourceFile (string filename)
411 if (filename == null || filename.Length == 0)
414 if (filename.StartsWith ("@@"))
415 return "[internal] <!-- " + filename + " -->";
420 string GetHtmlizedErrorMessage (HtmlizedException exc)
422 StringBuilder builder = new StringBuilder ();
424 bool isParseException = false;
425 bool isCompileException = false;
427 bool isParseException = exc is ParseException;
428 bool isCompileException = (!isParseException && exc is CompilationException);
431 WriteFileTop (builder, exc.Title);
432 builder.AppendFormat ("<h2><em>{0}</em></h2>\r\n", exc.Title);
433 builder.AppendFormat ("<p><strong>Description: </strong>{0}\r\n</p>\r\n", HtmlEncode (exc.Description));
434 string errorMessage = HtmlEncode (exc.ErrorMessage);
436 builder.Append ("<p><strong>");
437 if (isParseException)
438 builder.Append ("Parser ");
439 else if (isCompileException)
440 builder.Append ("Compiler ");
442 builder.Append ("Error Message: </strong>");
443 builder.AppendFormat ("<code>{0}</code></p>", errorMessage);
445 StringBuilder longCodeVersion = null;
447 if (exc.FileText != null) {
448 if (isParseException || isCompileException) {
449 builder.Append ("<p><strong>Source Error: </strong></p>\r\n");
450 builder.Append ("<table summary=\"Source error\" class=\"sampleCode\">\r\n<tr><td>");
452 if (isCompileException)
453 longCodeVersion = new StringBuilder ();
454 WriteSource (builder, longCodeVersion, exc);
455 builder.Append ("</pre></code></td></tr>\r\n</table>\r\n");
457 builder.Append ("<table summary=\"Source file\" class=\"sampleCode\">\r\n<tr><td>");
458 WriteSource (builder, null, exc);
459 builder.Append ("</pre></code></td></tr>\r\n</table>\r\n");
462 builder.Append ("<br/><p><strong>Source File: </strong>");
463 if (exc.SourceFile != exc.FileName)
464 builder.Append (FormatSourceFile (exc.SourceFile));
466 builder.Append (FormatSourceFile (exc.FileName));
468 if (isParseException || isCompileException) {
469 int[] errorLines = exc.ErrorLines;
470 int numErrors = errorLines != null ? errorLines.Length : 0;
472 builder.AppendFormat (" <strong>Line{0}: </strong>", numErrors > 1 ? "s" : String.Empty);
473 for (int i = 0; i < numErrors; i++) {
475 builder.Append (", ");
476 builder.Append (exc.ErrorLines [i]);
480 builder.Append ("</p>");
481 } else if (exc.FileName != null)
482 builder.AppendFormat ("{0}</p>", HtmlEncode (exc.FileName));
484 bool needToggleJS = false;
487 if (isCompileException) {
488 CompilationException cex = exc as CompilationException;
489 StringCollection output = cex.CompilerOutput;
491 if (output != null && output.Count > 0) {
493 StringBuilder sb = new StringBuilder ();
494 foreach (string s in output)
495 sb.Append (s + "\r\n");
496 WriteExpandableBlock (builder, "compilerOutput", "Show Detailed Compiler Output", sb.ToString ());
501 if (longCodeVersion != null && longCodeVersion.Length > 0) {
502 WriteExpandableBlock (builder, "fullCode", "Show Complete Compilation Source", longCodeVersion.ToString ());
507 builder.Append ("<script type=\"text/javascript\">\r\n" +
508 "function ToggleVisible (id)\r\n" +
510 "\tvar e = document.getElementById (id);\r\n" +
511 "\tif (e.style.display == 'none')\r\n" +
513 "\t\te.style.display = '';\r\n" +
515 "\t\te.style.display = 'none';\r\n" +
520 WriteFileBottom (builder, true);
522 return builder.ToString ();
525 static void WriteExpandableBlock (StringBuilder builder, string id, string title, string contents)
527 builder.AppendFormat ("<br><div class=\"expandable\" onclick=\"ToggleVisible ('{1}')\">{0}:</div><br/>" +
528 "<div id=\"{1}\" style=\"display: none\"><table summary=\"Details\" class=\"sampleCode\"><tr><td>" +
529 "<code><pre>\r\n", title, id);
530 builder.Append (contents);
531 builder.Append ("</pre></code></td></tr></table></div>");
534 static void WriteTextAsCode (StringBuilder builder, string text)
536 builder.AppendFormat ("<pre>{0}</pre>", HtmlEncode (text));
540 static void WriteSource (StringBuilder builder, StringBuilder longVersion, HtmlizedException e)
542 builder.Append ("<code><pre>");
543 WritePageSource (builder, e);
544 builder.Append ("</code></pre>\r\n");
548 static void WriteSource (StringBuilder builder, StringBuilder longVersion, HtmlizedException e)
550 builder.Append ("<code><pre>");
551 if (e is CompilationException)
552 WriteCompilationSource (builder, longVersion, e);
554 WritePageSource (builder, e);
556 builder.Append ("<code></pre>\r\n");
560 static void WriteCompilationSource (StringBuilder builder, StringBuilder longVersion, HtmlizedException e)
562 int [] a = e.ErrorLines;
568 if (a != null && a.Length > 0)
571 int begin = errline - 2;
572 int end = errline + 2;
578 using (TextReader reader = new StringReader (e.FileText)) {
579 while ((s = reader.ReadLine ()) != null) {
581 if (line < begin || line > end) {
582 if (longVersion != null)
583 longVersion.AppendFormat ("Line {0}: {1}\r\n", line, HtmlEncode (s));
587 if (errline == line) {
588 if (longVersion != null)
589 longVersion.Append ("<span style=\"color: red\">");
590 builder.Append ("<span style=\"color: red\">");
593 tmp = String.Format ("Line {0}: {1}\r\n", line, HtmlEncode (s));
594 builder.Append (tmp);
595 if (longVersion != null)
596 longVersion.Append (tmp);
598 if (line == errline) {
599 builder.Append ("</span>");
600 if (longVersion != null)
601 longVersion.Append ("</span>");
602 errline = (++index < a.Length) ? a [index] : 0;
608 static void WritePageSource (StringBuilder builder, HtmlizedException e)
612 int beginerror = e.ErrorLines [0];
613 int enderror = e.ErrorLines [1];
614 int begin = beginerror - 2;
615 int end = enderror + 2;
619 TextReader reader = new StringReader (e.FileText);
620 while ((s = reader.ReadLine ()) != null) {
628 if (beginerror == line)
629 builder.Append ("<span style=\"color: red\">");
631 builder.AppendFormat ("Line {0}: {1}\r\n", line, HtmlEncode (s));
633 if (enderror <= line) {
634 builder.Append ("</span>");
635 enderror = end + 1; // one shot
640 public int GetHttpCode ()
645 public static HttpException CreateFromLastError (string message)
647 WebTrace.WriteLine ("CreateFromLastError");
648 return new HttpException (message, 0);