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.Collections.Specialized;
44 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
45 [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
47 public class HttpException : ExternalException
49 const string DEFAULT_DESCRIPTION_TEXT = "Error processing request.";
50 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.";
56 const string errorStyleFonts = "\"Verdana\",\"DejaVu Sans\",sans-serif";
58 public HttpException ()
62 public HttpException (string message)
67 public HttpException (string message, Exception innerException)
68 : base (message, innerException)
72 public HttpException (int httpCode, string message) : base (message)
77 internal HttpException (int httpCode, string message, string resourceName) : this (httpCode, message)
79 resource_name = resourceName;
82 internal HttpException (int httpCode, string message, string resourceName, string description) : this (httpCode, message, resourceName)
84 this.description = description;
87 protected HttpException (SerializationInfo info, StreamingContext context)
88 : base (info, context)
90 http_code = info.GetInt32 ("_httpCode");
93 [SecurityPermission (SecurityAction.Demand, SerializationFormatter = true)]
94 public override void GetObjectData (SerializationInfo info, StreamingContext context)
96 base.GetObjectData (info, context);
97 info.AddValue ("_httpCode", http_code);
100 public HttpException (int httpCode, string message, int hr)
103 http_code = httpCode;
106 public HttpException (string message, int hr)
111 public HttpException (int httpCode, string message, Exception innerException)
112 : base (message, innerException)
114 http_code = httpCode;
117 internal HttpException (int httpCode, string message, Exception innerException, string resourceName)
118 : this (httpCode, message, innerException)
120 resource_name = resourceName;
123 public string GetHtmlErrorMessage ()
126 HttpContext ctx = HttpContext.Current;
127 if (ctx != null && ctx.IsCustomErrorEnabled) {
128 if (http_code != 404 && http_code != 403)
129 return GetCustomErrorDefaultMessage ();
131 return GetDefaultErrorMessage (false);
134 if (!(this.InnerException is HtmlizedException))
135 return GetDefaultErrorMessage (true);
137 return GetHtmlizedErrorMessage ();
138 } catch (Exception ex) {
139 Console.WriteLine (ex);
141 // we need the try/catch block in case the
142 // problem was with MapPath, which will cause
143 // IsCustomErrorEnabled to throw an exception
144 return GetCustomErrorDefaultMessage ();
148 internal virtual string Description {
150 if (description != null)
153 return DEFAULT_DESCRIPTION_TEXT;
157 if (value != null && value.Length > 0)
160 description = DEFAULT_DESCRIPTION_TEXT;
164 void WriteFileTop (StringBuilder builder, string title)
167 builder.AppendFormat ("<html><head><title>{0}</title><style type=\"text/css\">", title);
168 builder.AppendFormat (
169 @"body {{font-family:{0};font-weight:normal;font-size: 9pt;color:black;background-color: white}}
170 p {{font-family:{0};font-weight:normal;color:black;margin-top: -5px}}
171 b {{font-family:{0};font-weight:bold;color:black;margin-top: -5px}}
172 h1 {{ font-family:{0};font-weight:normal;font-size:18pt;color:red }}
173 h2 {{ font-family:{0};font-weight:normal;font-size:14pt;color:maroon }}
174 pre {{font-family:""Lucida Console"",""DejaVu Sans Mono"",monospace;font-size: 10pt}}
175 div.bodyText {{font-family: {0}}}
176 table.sampleCode {{width: 100%; background-color: #ffffcc; }}
177 .errorText {{color: red; font-weight: bold}}
178 .marker {{font-weight: bold; color: black;text-decoration: none;}}
179 .version {{color: gray;}}
180 .error {{margin-bottom: 10px;}}
181 .expandable {{ text-decoration:underline; font-weight:bold; color:navy; cursor:pointer; }}", errorStyleFonts);
183 builder.Append ("<?xml version=\"1.0\" ?>\n");
184 builder.Append ("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");
185 builder.AppendFormat ("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\"><head><title>{0}</title><style type=\"text/css\">", title);
186 builder.AppendFormat (
187 @"body {{font-family:{0};font-weight:normal;font-size: .7em;color:black;background-color: white}}
188 p {{font-family:{0};font-weight:normal;color:black;margin-top: -5px}}
189 b {{font-family:{0};font-weight:bold;color:black;margin-top: -5px}}
190 h1 {{ font-family:{0};font-weight:normal;font-size:18pt;color:red }}
191 h2 {{ font-family:{0};font-weight:normal;font-size:14pt;color:maroon }}
192 pre,code {{font-family:""Lucida Console"",""DejaVu Sans Mono"",monospace;font-size: 0.9em,white-space: pre-line}}
193 div.bodyText {{font-family: {0}}}
194 table.sampleCode {{width: 100%; background-color: #ffffcc; }}
195 .errorText {{color: red; font-weight: bold}}
196 .marker {{font-weight: bold; color: black;text-decoration: none;}}
197 .version {{color: gray;}}
198 .error {{margin-bottom: 10px;}}
199 .expandable {{ text-decoration:underline; font-weight:bold; color:navy; cursor:pointer; }}", errorStyleFonts);
202 builder.AppendFormat (
203 "</style></head><body><h1>Server Error in '{0}' Application</h1><hr style=\"color: silver\"/>",
204 HtmlEncode (HttpRuntime.AppDomainAppVirtualPath));
207 void WriteFileBottom (StringBuilder builder, bool showTrace)
210 builder.Append ("<hr style=\"color: silver\"/>");
211 builder.AppendFormat ("<strong>Version information: </strong> Mono Runtime Version: <tt>{0}</tt>; ASP.NET Version: <tt>{1}</tt></body></html>\r\n",
212 RuntimeHelpers.MonoVersion, Environment.Version);
214 string trace, message;
218 builder.Append ("\r\n<!--");
220 trace = ex.StackTrace;
221 message = ex.Message;
222 haveTrace = (trace != null && trace.Length > 0);
224 if (!haveTrace && (message == null || message.Length == 0)) {
225 ex = ex.InnerException;
229 builder.Append ("\r\n[" + ex.GetType () + "]: " + HtmlEncode (message) + "\r\n");
231 builder.Append (ex.StackTrace);
233 ex = ex.InnerException;
236 builder.Append ("\r\n-->");
238 builder.Append ("</body></html>\r\n");
241 string GetCustomErrorDefaultMessage ()
243 StringBuilder builder = new StringBuilder ();
244 WriteFileTop (builder, "Runtime Error");
245 #if TARGET_J2EE //on portal we cannot know if we run locally
246 if (!HttpContext.Current.IsServletRequest)
248 @"<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>
249 <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>
250 <table class=""sampleCode""><tr><td><pre>
252 <!-- Web.Config Configuration File -->
254 <configuration>
257 <customErrors mode="Off"/>
259 </configuration></pre>
260 </td></tr></table><br/>
264 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)." + (
265 " It could, however, be viewed by browsers running on the local server machine.")
267 <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>
268 <table class=""sampleCode""><tr><td><pre>
270 <!-- Web.Config Configuration File -->
272 <configuration>
275 <customErrors mode="Off"/>
277 </configuration></pre>
278 </td></tr></table><br/>
279 <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>
280 <table class=""sampleCode""><tr><td><pre>
281 <!-- Web.Config Configuration File -->
283 <configuration>
285 <customErrors mode="RemoteOnly" defaultRedirect="mycustompage.htm"/>
288 </configuration></pre></td></tr></table>");
289 WriteFileBottom (builder, false);
290 return builder.ToString ();
293 string GetDefaultErrorMessage (bool showTrace)
295 Exception ex, baseEx;
296 ex = baseEx = GetBaseException ();
300 StringBuilder builder = new StringBuilder ();
301 WriteFileTop (builder, String.Format ("Error{0}", http_code != 0 ? " " + http_code : String.Empty));
302 builder.Append ("<h2><em>");
303 if (http_code == 404)
304 builder.Append ("The resource cannot be found.");
306 builder.Append (HtmlEncode (ex.Message));
307 builder.Append ("</em></h2>\r\n<p><strong>Description: </strong>");
310 builder.AppendFormat ("HTTP {0}. ", http_code);
311 builder.Append (http_code == 404 ? ERROR_404_DESCRIPTION : HtmlEncode (Description));
312 builder.Append ("</p>\r\n");
314 if (resource_name != null && resource_name.Length > 0)
315 builder.AppendFormat ("<p><strong>Requested URL: </strong>{0}</p>\r\n", resource_name);
317 if (showTrace && baseEx != null && http_code != 404 && http_code != 403) {
318 builder.Append ("<p><strong>Stack Trace: </strong></p>");
319 builder.Append ("<table summary=\"Stack Trace\" class=\"sampleCode\">\r\n<tr><td>");
320 WriteTextAsCode (builder, baseEx.ToString ());
321 builder.Append ("</td></tr>\r\n</table>\r\n");
323 WriteFileBottom (builder, showTrace);
325 return builder.ToString ();
328 static string HtmlEncode (string s)
333 string res = HttpUtility.HtmlEncode (s);
334 return res.Replace ("\r\n", "<br />");
337 string FormatSourceFile (string filename)
339 if (filename == null || filename.Length == 0)
342 if (filename.StartsWith ("@@"))
343 return "[internal] <!-- " + filename + " -->";
348 string GetHtmlizedErrorMessage ()
350 StringBuilder builder = new StringBuilder ();
351 HtmlizedException exc = (HtmlizedException) this.InnerException;
353 bool isParseException = false;
354 bool isCompileException = false;
356 bool isParseException = exc is ParseException;
357 bool isCompileException = (!isParseException && exc is CompilationException);
360 WriteFileTop (builder, exc.Title);
361 builder.AppendFormat ("<h2><em>{0}</em></h2>\r\n", exc.Title);
362 builder.AppendFormat ("<p><strong>Description: </strong>{0}\r\n</p>\r\n", HtmlEncode (exc.Description));
363 string errorMessage = HtmlEncode (exc.ErrorMessage);
365 builder.Append ("<p><strong>");
366 if (isParseException)
367 builder.Append ("Parser ");
368 else if (isCompileException)
369 builder.Append ("Compiler ");
371 builder.Append ("Error Message: </strong>");
372 builder.AppendFormat ("<code>{0}</code></p>", errorMessage);
374 StringBuilder longCodeVersion = null;
376 if (exc.FileText != null) {
377 if (isParseException || isCompileException) {
378 builder.Append ("<p><strong>Source Error: </strong></p>\r\n");
379 builder.Append ("<table summary=\"Source error\" class=\"sampleCode\">\r\n<tr><td>");
381 if (isCompileException)
382 longCodeVersion = new StringBuilder ();
383 WriteSource (builder, longCodeVersion, exc);
384 builder.Append ("</pre></code></td></tr>\r\n</table>\r\n");
386 builder.Append ("<table summary=\"Source file\" class=\"sampleCode\">\r\n<tr><td>");
387 WriteSource (builder, null, exc);
388 builder.Append ("</pre></code></td></tr>\r\n</table>\r\n");
391 builder.Append ("<br/><p><strong>Source File: </strong>");
392 if (exc.SourceFile != exc.FileName)
393 builder.Append (FormatSourceFile (exc.SourceFile));
395 builder.Append (FormatSourceFile (exc.FileName));
397 if (isParseException || isCompileException) {
398 int[] errorLines = exc.ErrorLines;
399 int numErrors = errorLines != null ? errorLines.Length : 0;
401 builder.AppendFormat (" <strong>Line{0}: </strong>", numErrors > 1 ? "s" : String.Empty);
402 for (int i = 0; i < numErrors; i++) {
404 builder.Append (", ");
405 builder.Append (exc.ErrorLines [i]);
409 builder.Append ("</p>");
410 } else if (exc.FileName != null)
411 builder.AppendFormat ("{0}</p>", HtmlEncode (exc.FileName));
413 bool needToggleJS = false;
416 if (isCompileException) {
417 CompilationException cex = exc as CompilationException;
418 StringCollection output = cex.CompilerOutput;
420 if (output != null && output.Count > 0) {
422 StringBuilder sb = new StringBuilder ();
423 foreach (string s in output)
424 sb.Append (s + "\r\n");
425 WriteExpandableBlock (builder, "compilerOutput", "Show Detailed Compiler Output", sb.ToString ());
430 if (longCodeVersion != null && longCodeVersion.Length > 0) {
431 WriteExpandableBlock (builder, "fullCode", "Show Complete Compilation Source", longCodeVersion.ToString ());
436 builder.Append ("<script type=\"text/javascript\">\r\n" +
437 "function ToggleVisible (id)\r\n" +
439 "\tvar e = document.getElementById (id);\r\n" +
440 "\tif (e.style.display == 'none')\r\n" +
442 "\t\te.style.display = '';\r\n" +
444 "\t\te.style.display = 'none';\r\n" +
449 WriteFileBottom (builder, true);
451 return builder.ToString ();
454 static void WriteExpandableBlock (StringBuilder builder, string id, string title, string contents)
456 builder.AppendFormat ("<br><div class=\"expandable\" onclick=\"ToggleVisible ('{1}')\">{0}:</div><br/>" +
457 "<div id=\"{1}\" style=\"display: none\"><table summary=\"Details\" class=\"sampleCode\"><tr><td>" +
458 "<code><pre>\r\n", title, id);
459 builder.Append (contents);
460 builder.Append ("</pre></code></td></tr></table></div>");
463 static void WriteTextAsCode (StringBuilder builder, string text)
465 builder.AppendFormat ("<pre>{0}</pre>", HtmlEncode (text));
469 static void WriteSource (StringBuilder builder, StringBuilder longVersion, HtmlizedException e)
471 builder.Append ("<code><pre>");
472 WritePageSource (builder, e);
473 builder.Append ("</code></pre>\r\n");
477 static void WriteSource (StringBuilder builder, StringBuilder longVersion, HtmlizedException e)
479 builder.Append ("<code><pre>");
480 if (e is CompilationException)
481 WriteCompilationSource (builder, longVersion, e);
483 WritePageSource (builder, e);
485 builder.Append ("<code></pre>\r\n");
489 static void WriteCompilationSource (StringBuilder builder, StringBuilder longVersion, HtmlizedException e)
491 int [] a = e.ErrorLines;
497 if (a != null && a.Length > 0)
500 int begin = errline - 2;
501 int end = errline + 2;
507 using (TextReader reader = new StringReader (e.FileText)) {
508 while ((s = reader.ReadLine ()) != null) {
510 if (line < begin || line > end) {
511 if (longVersion != null)
512 longVersion.AppendFormat ("Line {0}: {1}\r\n", line, HtmlEncode (s));
516 if (errline == line) {
517 if (longVersion != null)
518 longVersion.Append ("<span style=\"color: red\">");
519 builder.Append ("<span style=\"color: red\">");
522 tmp = String.Format ("Line {0}: {1}\r\n", line, HtmlEncode (s));
523 builder.Append (tmp);
524 if (longVersion != null)
525 longVersion.Append (tmp);
527 if (line == errline) {
528 builder.Append ("</span>");
529 if (longVersion != null)
530 longVersion.Append ("</span>");
531 errline = (++index < a.Length) ? a [index] : 0;
537 static void WritePageSource (StringBuilder builder, HtmlizedException e)
541 int beginerror = e.ErrorLines [0];
542 int enderror = e.ErrorLines [1];
543 int begin = beginerror - 2;
544 int end = enderror + 2;
548 TextReader reader = new StringReader (e.FileText);
549 while ((s = reader.ReadLine ()) != null) {
557 if (beginerror == line)
558 builder.Append ("<span style=\"color: red\">");
560 builder.AppendFormat ("Line {0}: {1}\r\n", line, HtmlEncode (s));
562 if (enderror <= line) {
563 builder.Append ("</span>");
564 enderror = end + 1; // one shot
569 public int GetHttpCode ()
574 public static HttpException CreateFromLastError (string message)
576 WebTrace.WriteLine ("CreateFromLastError");
577 return new HttpException (message, 0);