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 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)]
49 public class HttpException : ExternalException
51 const string DEFAULT_DESCRIPTION_TEXT = "Error processing request.";
52 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.";
58 const string errorStyleFonts = "\"Verdana\",\"DejaVu Sans\",sans-serif";
60 public HttpException ()
64 public HttpException (string message)
69 public HttpException (string message, Exception innerException)
70 : base (message, innerException)
74 public HttpException (int httpCode, string message) : base (message)
79 internal HttpException (int httpCode, string message, string resourceName) : this (httpCode, message)
81 resource_name = resourceName;
84 internal HttpException (int httpCode, string message, string resourceName, string description) : this (httpCode, message, resourceName)
86 this.description = description;
90 protected HttpException (SerializationInfo info, StreamingContext context)
91 : base (info, context)
93 http_code = info.GetInt32 ("_httpCode");
96 [SecurityPermission (SecurityAction.Demand, SerializationFormatter = true)]
97 public override void GetObjectData (SerializationInfo info, StreamingContext context)
99 base.GetObjectData (info, context);
100 info.AddValue ("_httpCode", http_code);
104 public HttpException (int httpCode, string message, int hr)
107 http_code = httpCode;
110 public HttpException (string message, int hr)
115 public HttpException (int httpCode, string message, Exception innerException)
116 : base (message, innerException)
118 http_code = httpCode;
121 internal HttpException (int httpCode, string message, Exception innerException, string resourceName)
122 : this (httpCode, message, innerException)
124 resource_name = resourceName;
127 public string GetHtmlErrorMessage ()
130 HttpContext ctx = HttpContext.Current;
131 if (ctx != null && ctx.IsCustomErrorEnabled)
132 return GetCustomErrorDefaultMessage ();
134 if (!(this.InnerException is HtmlizedException))
135 return GetDefaultErrorMessage ();
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)
209 builder.Append ("<hr style=\"color: silver\"/>");
210 builder.AppendFormat ("<strong>Version information: </strong> Mono Version: {0}; ASP.NET Version: {0}</body></html>\r\n<!--", Environment.Version);
214 string trace, message;
219 trace = ex.StackTrace;
220 message = ex.Message;
221 haveTrace = (trace != null && trace.Length > 0);
223 if (!haveTrace && (message == null || message.Length == 0)) {
224 ex = ex.InnerException;
228 builder.Append ("\r\n[" + ex.GetType () + "]: " + HtmlEncode (message) + "\r\n");
230 builder.Append (ex.StackTrace);
232 ex = ex.InnerException;
235 builder.Append ("\r\n-->");
238 string GetCustomErrorDefaultMessage ()
240 StringBuilder builder = new StringBuilder ();
241 WriteFileTop (builder, "Runtime Error");
242 #if TARGET_J2EE //on portal we cannot know if we run locally
243 if (!HttpContext.Current.IsServletRequest)
245 @"<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>
246 <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>
247 <table class=""sampleCode""><tr><td><pre>
249 <!-- Web.Config Configuration File -->
251 <configuration>
254 <customErrors mode="Off"/>
256 </configuration></pre>
257 </td></tr></table><br/>
261 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)." + (
262 " It could, however, be viewed by browsers running on the local server machine.")
264 <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>
265 <table class=""sampleCode""><tr><td><pre>
267 <!-- Web.Config Configuration File -->
269 <configuration>
272 <customErrors mode="Off"/>
274 </configuration></pre>
275 </td></tr></table><br/>
276 <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>
277 <table class=""sampleCode""><tr><td><pre>
278 <!-- Web.Config Configuration File -->
280 <configuration>
282 <customErrors mode="RemoteOnly" defaultRedirect="mycustompage.htm"/>
285 </configuration></pre></td></tr></table>");
286 WriteFileBottom (builder, false);
287 return builder.ToString ();
290 string GetDefaultErrorMessage ()
292 Exception ex, baseEx;
293 ex = baseEx = GetBaseException ();
297 StringBuilder builder = new StringBuilder ();
298 WriteFileTop (builder, String.Format ("Error{0}", http_code != 0 ? " " + http_code : String.Empty));
299 builder.Append ("<h2><em>");
300 if (http_code == 404)
301 builder.Append ("The resource cannot be found.");
303 builder.Append (HtmlEncode (ex.Message));
304 builder.Append ("</em></h2>\r\n<p><strong>Description: </strong>");
307 builder.AppendFormat ("HTTP {0}. ", http_code);
308 builder.Append (http_code == 404 ? ERROR_404_DESCRIPTION : HtmlEncode (Description));
309 builder.Append ("</p>\r\n");
311 if (resource_name != null && resource_name.Length > 0)
312 builder.AppendFormat ("<p><strong>Resource URL: </strong>{0}</p>\r\n", resource_name);
314 if (baseEx != null && http_code != 404) {
315 builder.Append ("<p><strong>Stack Trace: </strong></p>");
316 builder.Append ("<table summary=\"Stack Trace\" class=\"sampleCode\">\r\n<tr><td>");
317 WriteTextAsCode (builder, baseEx.ToString ());
318 builder.Append ("</td></tr>\r\n</table>\r\n");
320 WriteFileBottom (builder, true);
322 return builder.ToString ();
325 static string HtmlEncode (string s)
330 string res = HttpUtility.HtmlEncode (s);
331 return res.Replace ("\r\n", "<br />");
334 string GetHtmlizedErrorMessage ()
336 StringBuilder builder = new StringBuilder ();
337 HtmlizedException exc = (HtmlizedException) this.InnerException;
339 bool isParseException = false;
340 bool isCompileException = false;
342 bool isParseException = exc is ParseException;
343 bool isCompileException = (!isParseException && exc is CompilationException);
346 WriteFileTop (builder, exc.Title);
347 builder.AppendFormat ("<h2><em>{0}</em></h2>\r\n", exc.Title);
348 builder.AppendFormat ("<p><strong>Description: </strong>{0}\r\n</p>\r\n", HtmlEncode (exc.Description));
349 string errorMessage = HtmlEncode (exc.ErrorMessage);
351 builder.Append ("<p><strong>");
352 if (isParseException)
353 builder.Append ("Parser ");
354 else if (isCompileException)
355 builder.Append ("Compiler ");
357 builder.Append ("Error Message: </strong>");
359 builder.AppendFormat ("<code>{0}</code></p>", errorMessage);
361 builder.AppendFormat ("<blockquote><pre>{0}</pre></blockquote></p>", errorMessage);
364 StringBuilder longCodeVersion = null;
366 if (exc.FileText != null) {
367 if (isParseException || isCompileException) {
368 builder.Append ("<p><strong>Source Error: </strong></p>\r\n");
369 builder.Append ("<table summary=\"Source error\" class=\"sampleCode\">\r\n<tr><td>");
371 if (isCompileException)
372 longCodeVersion = new StringBuilder ();
373 WriteSource (builder, longCodeVersion, exc);
374 builder.Append ("</pre></code></td></tr>\r\n</table>\r\n");
376 builder.Append ("<table summary=\"Source file\" class=\"sampleCode\">\r\n<tr><td>");
377 WriteSource (builder, null, exc);
378 builder.Append ("</pre></code></td></tr>\r\n</table>\r\n");
381 builder.Append ("<br/><p><strong>Source File: </strong>");
382 if (exc.SourceFile != exc.FileName)
383 builder.Append (exc.SourceFile);
385 builder.Append (exc.FileName);
387 if ((isParseException || isCompileException) && exc.ErrorLines.Length > 0) {
388 builder.Append (" <strong>Line: </strong>");
389 builder.Append (exc.ErrorLines [0]);
391 builder.Append ("</p>");
392 } else if (exc.FileName != null)
393 builder.AppendFormat ("{0}</p>", HtmlEncode (exc.FileName));
395 bool needToggleJS = false;
398 if (isCompileException) {
399 CompilationException cex = exc as CompilationException;
400 StringCollection output = cex.CompilerOutput;
402 if (output != null && output.Count > 0) {
404 StringBuilder sb = new StringBuilder ();
405 foreach (string s in output)
406 sb.Append (s + "\r\n");
407 WriteExpandableBlock (builder, "compilerOutput", "Show Detailed Compiler Output", sb.ToString ());
412 if (longCodeVersion != null && longCodeVersion.Length > 0) {
413 WriteExpandableBlock (builder, "fullCode", "Show Complete Compilation Source", longCodeVersion.ToString ());
418 builder.Append ("<script type=\"text/javascript\">\r\n" +
419 "function ToggleVisible (id)\r\n" +
421 "\tvar e = document.getElementById (id);\r\n" +
422 "\tif (e.style.display == 'none')\r\n" +
424 "\t\te.style.display = '';\r\n" +
426 "\t\te.style.display = 'none';\r\n" +
431 WriteFileBottom (builder, true);
433 return builder.ToString ();
436 static void WriteExpandableBlock (StringBuilder builder, string id, string title, string contents)
438 builder.AppendFormat ("<br><div class=\"expandable\" onclick=\"ToggleVisible ('{1}')\">{0}:</div><br/>" +
439 "<div id=\"{1}\" style=\"display: none\"><table summary=\"Details\" class=\"sampleCode\"><tr><td>" +
440 "<code><pre>\r\n", title, id);
441 builder.Append (contents);
442 builder.Append ("</pre></code></td></tr></table></div>");
445 static void WriteTextAsCode (StringBuilder builder, string text)
447 builder.AppendFormat ("<pre>{0}</pre>", HtmlEncode (text));
451 static void WriteSource (StringBuilder builder, StringBuilder longVersion, HtmlizedException e)
453 builder.Append ("<code><pre>");
454 WritePageSource (builder, e);
455 builder.Append ("</code></pre>\r\n");
459 static void WriteSource (StringBuilder builder, StringBuilder longVersion, HtmlizedException e)
461 builder.Append ("<code><pre>");
462 if (e is CompilationException)
463 WriteCompilationSource (builder, longVersion, e);
465 WritePageSource (builder, e);
467 builder.Append ("<code></pre>\r\n");
471 static void WriteCompilationSource (StringBuilder builder, StringBuilder longVersion, HtmlizedException e)
473 int [] a = e.ErrorLines;
479 if (a != null && a.Length > 0)
482 int begin = errline - 2;
483 int end = errline + 2;
489 using (TextReader reader = new StringReader (e.FileText)) {
490 while ((s = reader.ReadLine ()) != null) {
492 if (line < begin || line > end) {
493 if (longVersion != null)
494 longVersion.AppendFormat ("Line {0}: {1}\r\n", line, HtmlEncode (s));
498 if (errline == line) {
499 if (longVersion != null)
500 longVersion.Append ("<span style=\"color: red\">");
501 builder.Append ("<span style=\"color: red\">");
504 tmp = String.Format ("Line {0}: {1}\r\n", line, HtmlEncode (s));
505 builder.Append (tmp);
506 if (longVersion != null)
507 longVersion.Append (tmp);
509 if (line == errline) {
510 builder.Append ("</span>");
511 if (longVersion != null)
512 longVersion.Append ("</span>");
513 errline = (++index < a.Length) ? a [index] : 0;
519 static void WritePageSource (StringBuilder builder, HtmlizedException e)
523 int beginerror = e.ErrorLines [0];
524 int enderror = e.ErrorLines [1];
525 int begin = beginerror - 2;
526 int end = enderror + 2;
530 TextReader reader = new StringReader (e.FileText);
531 while ((s = reader.ReadLine ()) != null) {
539 if (beginerror == line)
540 builder.Append ("<span style=\"color: red\">");
542 builder.AppendFormat ("Line {0}: {1}\r\n", line, HtmlEncode (s));
544 if (enderror <= line) {
545 builder.Append ("</span>");
546 enderror = end + 1; // one shot
551 public int GetHttpCode ()
556 public static HttpException CreateFromLastError (string message)
558 WebTrace.WriteLine ("CreateFromLastError");
559 return new HttpException (message, 0);