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;
94 HttpException (SerializationInfo info, StreamingContext context)
95 : base (info, context)
97 http_code = info.GetInt32 ("_httpCode");
101 [SecurityPermission (SecurityAction.Demand, SerializationFormatter = true)]
102 public override void GetObjectData (SerializationInfo info, StreamingContext context)
104 base.GetObjectData (info, context);
105 info.AddValue ("_httpCode", http_code);
109 public HttpException (int httpCode, string message, int hr)
112 http_code = httpCode;
115 public HttpException (string message, int hr)
120 public HttpException (int httpCode, string message, Exception innerException)
121 : base (message, innerException)
123 http_code = httpCode;
126 internal HttpException (int httpCode, string message, Exception innerException, string resourceName)
127 : this (httpCode, message, innerException)
129 resource_name = resourceName;
132 public string GetHtmlErrorMessage ()
135 HttpContext ctx = HttpContext.Current;
136 if (ctx != null && ctx.IsCustomErrorEnabled) {
137 if (http_code != 404 && http_code != 403)
138 return GetCustomErrorDefaultMessage ();
140 return GetDefaultErrorMessage (false);
143 if (!(this.InnerException is HtmlizedException))
144 return GetDefaultErrorMessage (true);
146 return GetHtmlizedErrorMessage ();
147 } catch (Exception ex) {
148 Console.WriteLine (ex);
150 // we need the try/catch block in case the
151 // problem was with MapPath, which will cause
152 // IsCustomErrorEnabled to throw an exception
153 return GetCustomErrorDefaultMessage ();
157 internal virtual string Description {
159 if (description != null)
162 return DEFAULT_DESCRIPTION_TEXT;
166 if (value != null && value.Length > 0)
169 description = DEFAULT_DESCRIPTION_TEXT;
173 void WriteFileTop (StringBuilder builder, string title)
176 builder.AppendFormat ("<html><head><title>{0}</title><style type=\"text/css\">", title);
177 builder.AppendFormat (
178 @"body {{font-family:{0};font-weight:normal;font-size: 9pt;color:black;background-color: white}}
179 p {{font-family:{0};font-weight:normal;color:black;margin-top: -5px}}
180 b {{font-family:{0};font-weight:bold;color:black;margin-top: -5px}}
181 h1 {{ font-family:{0};font-weight:normal;font-size:18pt;color:red }}
182 h2 {{ font-family:{0};font-weight:normal;font-size:14pt;color:maroon }}
183 pre {{font-family:""Lucida Console"",""DejaVu Sans Mono"",monospace;font-size: 10pt}}
184 div.bodyText {{font-family: {0}}}
185 table.sampleCode {{width: 100%; background-color: #ffffcc; }}
186 .errorText {{color: red; font-weight: bold}}
187 .marker {{font-weight: bold; color: black;text-decoration: none;}}
188 .version {{color: gray;}}
189 .error {{margin-bottom: 10px;}}
190 .expandable {{ text-decoration:underline; font-weight:bold; color:navy; cursor:pointer; }}", errorStyleFonts);
192 builder.Append ("<?xml version=\"1.0\" ?>\n");
193 builder.Append ("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");
194 builder.AppendFormat ("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\"><head><title>{0}</title><style type=\"text/css\">", title);
195 builder.AppendFormat (
196 @"body {{font-family:{0};font-weight:normal;font-size: .7em;color:black;background-color: white}}
197 p {{font-family:{0};font-weight:normal;color:black;margin-top: -5px}}
198 b {{font-family:{0};font-weight:bold;color:black;margin-top: -5px}}
199 h1 {{ font-family:{0};font-weight:normal;font-size:18pt;color:red }}
200 h2 {{ font-family:{0};font-weight:normal;font-size:14pt;color:maroon }}
201 pre,code {{font-family:""Lucida Console"",""DejaVu Sans Mono"",monospace;font-size: 0.9em,white-space: pre-line}}
202 div.bodyText {{font-family: {0}}}
203 table.sampleCode {{width: 100%; background-color: #ffffcc; }}
204 .errorText {{color: red; font-weight: bold}}
205 .marker {{font-weight: bold; color: black;text-decoration: none;}}
206 .version {{color: gray;}}
207 .error {{margin-bottom: 10px;}}
208 .expandable {{ text-decoration:underline; font-weight:bold; color:navy; cursor:pointer; }}", errorStyleFonts);
211 builder.AppendFormat (
212 "</style></head><body><h1>Server Error in '{0}' Application</h1><hr style=\"color: silver\"/>",
213 HtmlEncode (HttpRuntime.AppDomainAppVirtualPath));
216 void WriteFileBottom (StringBuilder builder, bool showTrace)
219 builder.Append ("<hr style=\"color: silver\"/>");
220 builder.AppendFormat ("<strong>Version information: </strong> Mono Version: {0}; ASP.NET Version: {0}</body></html>\r\n", Environment.Version);
222 string trace, message;
226 builder.Append ("\r\n<!--");
228 trace = ex.StackTrace;
229 message = ex.Message;
230 haveTrace = (trace != null && trace.Length > 0);
232 if (!haveTrace && (message == null || message.Length == 0)) {
233 ex = ex.InnerException;
237 builder.Append ("\r\n[" + ex.GetType () + "]: " + HtmlEncode (message) + "\r\n");
239 builder.Append (ex.StackTrace);
241 ex = ex.InnerException;
244 builder.Append ("\r\n-->");
246 builder.Append ("</body></html>\r\n");
249 string GetCustomErrorDefaultMessage ()
251 StringBuilder builder = new StringBuilder ();
252 WriteFileTop (builder, "Runtime Error");
253 #if TARGET_J2EE //on portal we cannot know if we run locally
254 if (!HttpContext.Current.IsServletRequest)
256 @"<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>
257 <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>
258 <table class=""sampleCode""><tr><td><pre>
260 <!-- Web.Config Configuration File -->
262 <configuration>
265 <customErrors mode="Off"/>
267 </configuration></pre>
268 </td></tr></table><br/>
272 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)." + (
273 " It could, however, be viewed by browsers running on the local server machine.")
275 <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>
276 <table class=""sampleCode""><tr><td><pre>
278 <!-- Web.Config Configuration File -->
280 <configuration>
283 <customErrors mode="Off"/>
285 </configuration></pre>
286 </td></tr></table><br/>
287 <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>
288 <table class=""sampleCode""><tr><td><pre>
289 <!-- Web.Config Configuration File -->
291 <configuration>
293 <customErrors mode="RemoteOnly" defaultRedirect="mycustompage.htm"/>
296 </configuration></pre></td></tr></table>");
297 WriteFileBottom (builder, false);
298 return builder.ToString ();
301 string GetDefaultErrorMessage (bool showTrace)
303 Exception ex, baseEx;
304 ex = baseEx = GetBaseException ();
308 StringBuilder builder = new StringBuilder ();
309 WriteFileTop (builder, String.Format ("Error{0}", http_code != 0 ? " " + http_code : String.Empty));
310 builder.Append ("<h2><em>");
311 if (http_code == 404)
312 builder.Append ("The resource cannot be found.");
314 builder.Append (HtmlEncode (ex.Message));
315 builder.Append ("</em></h2>\r\n<p><strong>Description: </strong>");
318 builder.AppendFormat ("HTTP {0}. ", http_code);
319 builder.Append (http_code == 404 ? ERROR_404_DESCRIPTION : HtmlEncode (Description));
320 builder.Append ("</p>\r\n");
322 if (resource_name != null && resource_name.Length > 0)
323 builder.AppendFormat ("<p><strong>Requested URL: </strong>{0}</p>\r\n", resource_name);
325 if (showTrace && baseEx != null && http_code != 404 && http_code != 403) {
326 builder.Append ("<p><strong>Stack Trace: </strong></p>");
327 builder.Append ("<table summary=\"Stack Trace\" class=\"sampleCode\">\r\n<tr><td>");
328 WriteTextAsCode (builder, baseEx.ToString ());
329 builder.Append ("</td></tr>\r\n</table>\r\n");
331 WriteFileBottom (builder, showTrace);
333 return builder.ToString ();
336 static string HtmlEncode (string s)
341 string res = HttpUtility.HtmlEncode (s);
342 return res.Replace ("\r\n", "<br />");
345 string FormatSourceFile (string filename)
347 if (filename == null || filename.Length == 0)
350 if (filename.StartsWith ("@@"))
351 return "[internal] <!-- " + filename + " -->";
356 string GetHtmlizedErrorMessage ()
358 StringBuilder builder = new StringBuilder ();
359 HtmlizedException exc = (HtmlizedException) this.InnerException;
361 bool isParseException = false;
362 bool isCompileException = false;
364 bool isParseException = exc is ParseException;
365 bool isCompileException = (!isParseException && exc is CompilationException);
368 WriteFileTop (builder, exc.Title);
369 builder.AppendFormat ("<h2><em>{0}</em></h2>\r\n", exc.Title);
370 builder.AppendFormat ("<p><strong>Description: </strong>{0}\r\n</p>\r\n", HtmlEncode (exc.Description));
371 string errorMessage = HtmlEncode (exc.ErrorMessage);
373 builder.Append ("<p><strong>");
374 if (isParseException)
375 builder.Append ("Parser ");
376 else if (isCompileException)
377 builder.Append ("Compiler ");
379 builder.Append ("Error Message: </strong>");
381 builder.AppendFormat ("<code>{0}</code></p>", errorMessage);
383 builder.AppendFormat ("<blockquote><pre>{0}</pre></blockquote></p>", errorMessage);
386 StringBuilder longCodeVersion = null;
388 if (exc.FileText != null) {
389 if (isParseException || isCompileException) {
390 builder.Append ("<p><strong>Source Error: </strong></p>\r\n");
391 builder.Append ("<table summary=\"Source error\" class=\"sampleCode\">\r\n<tr><td>");
393 if (isCompileException)
394 longCodeVersion = new StringBuilder ();
395 WriteSource (builder, longCodeVersion, exc);
396 builder.Append ("</pre></code></td></tr>\r\n</table>\r\n");
398 builder.Append ("<table summary=\"Source file\" class=\"sampleCode\">\r\n<tr><td>");
399 WriteSource (builder, null, exc);
400 builder.Append ("</pre></code></td></tr>\r\n</table>\r\n");
403 builder.Append ("<br/><p><strong>Source File: </strong>");
404 if (exc.SourceFile != exc.FileName)
405 builder.Append (FormatSourceFile (exc.SourceFile));
407 builder.Append (FormatSourceFile (exc.FileName));
409 if (isParseException || isCompileException) {
410 int[] errorLines = exc.ErrorLines;
411 int numErrors = errorLines != null ? errorLines.Length : 0;
413 builder.AppendFormat (" <strong>Line{0}: </strong>", numErrors > 1 ? "s" : String.Empty);
414 for (int i = 0; i < numErrors; i++) {
416 builder.Append (", ");
417 builder.Append (exc.ErrorLines [i]);
421 builder.Append ("</p>");
422 } else if (exc.FileName != null)
423 builder.AppendFormat ("{0}</p>", HtmlEncode (exc.FileName));
425 bool needToggleJS = false;
428 if (isCompileException) {
429 CompilationException cex = exc as CompilationException;
430 StringCollection output = cex.CompilerOutput;
432 if (output != null && output.Count > 0) {
434 StringBuilder sb = new StringBuilder ();
435 foreach (string s in output)
436 sb.Append (s + "\r\n");
437 WriteExpandableBlock (builder, "compilerOutput", "Show Detailed Compiler Output", sb.ToString ());
442 if (longCodeVersion != null && longCodeVersion.Length > 0) {
443 WriteExpandableBlock (builder, "fullCode", "Show Complete Compilation Source", longCodeVersion.ToString ());
448 builder.Append ("<script type=\"text/javascript\">\r\n" +
449 "function ToggleVisible (id)\r\n" +
451 "\tvar e = document.getElementById (id);\r\n" +
452 "\tif (e.style.display == 'none')\r\n" +
454 "\t\te.style.display = '';\r\n" +
456 "\t\te.style.display = 'none';\r\n" +
461 WriteFileBottom (builder, true);
463 return builder.ToString ();
466 static void WriteExpandableBlock (StringBuilder builder, string id, string title, string contents)
468 builder.AppendFormat ("<br><div class=\"expandable\" onclick=\"ToggleVisible ('{1}')\">{0}:</div><br/>" +
469 "<div id=\"{1}\" style=\"display: none\"><table summary=\"Details\" class=\"sampleCode\"><tr><td>" +
470 "<code><pre>\r\n", title, id);
471 builder.Append (contents);
472 builder.Append ("</pre></code></td></tr></table></div>");
475 static void WriteTextAsCode (StringBuilder builder, string text)
477 builder.AppendFormat ("<pre>{0}</pre>", HtmlEncode (text));
481 static void WriteSource (StringBuilder builder, StringBuilder longVersion, HtmlizedException e)
483 builder.Append ("<code><pre>");
484 WritePageSource (builder, e);
485 builder.Append ("</code></pre>\r\n");
489 static void WriteSource (StringBuilder builder, StringBuilder longVersion, HtmlizedException e)
491 builder.Append ("<code><pre>");
492 if (e is CompilationException)
493 WriteCompilationSource (builder, longVersion, e);
495 WritePageSource (builder, e);
497 builder.Append ("<code></pre>\r\n");
501 static void WriteCompilationSource (StringBuilder builder, StringBuilder longVersion, HtmlizedException e)
503 int [] a = e.ErrorLines;
509 if (a != null && a.Length > 0)
512 int begin = errline - 2;
513 int end = errline + 2;
519 using (TextReader reader = new StringReader (e.FileText)) {
520 while ((s = reader.ReadLine ()) != null) {
522 if (line < begin || line > end) {
523 if (longVersion != null)
524 longVersion.AppendFormat ("Line {0}: {1}\r\n", line, HtmlEncode (s));
528 if (errline == line) {
529 if (longVersion != null)
530 longVersion.Append ("<span style=\"color: red\">");
531 builder.Append ("<span style=\"color: red\">");
534 tmp = String.Format ("Line {0}: {1}\r\n", line, HtmlEncode (s));
535 builder.Append (tmp);
536 if (longVersion != null)
537 longVersion.Append (tmp);
539 if (line == errline) {
540 builder.Append ("</span>");
541 if (longVersion != null)
542 longVersion.Append ("</span>");
543 errline = (++index < a.Length) ? a [index] : 0;
549 static void WritePageSource (StringBuilder builder, HtmlizedException e)
553 int beginerror = e.ErrorLines [0];
554 int enderror = e.ErrorLines [1];
555 int begin = beginerror - 2;
556 int end = enderror + 2;
560 TextReader reader = new StringReader (e.FileText);
561 while ((s = reader.ReadLine ()) != null) {
569 if (beginerror == line)
570 builder.Append ("<span style=\"color: red\">");
572 builder.AppendFormat ("Line {0}: {1}\r\n", line, HtmlEncode (s));
574 if (enderror <= line) {
575 builder.Append ("</span>");
576 enderror = end + 1; // one shot
581 public int GetHttpCode ()
586 public static HttpException CreateFromLastError (string message)
588 WebTrace.WriteLine ("CreateFromLastError");
589 return new HttpException (message, 0);