1 //------------------------------------------------------------------------------
2 // <copyright file="HttpException.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
8 * Exception thrown by ASP.NET managed runtime
10 * Copyright (c) 1998 Microsoft Corporation
13 namespace System.Web {
15 using System.Runtime.InteropServices;
16 using System.Runtime.Serialization;
17 using System.Collections;
18 using System.Collections.Specialized;
19 using System.Configuration;
20 using System.Diagnostics.CodeAnalysis;
21 using System.Security;
22 using System.Globalization;
23 using System.CodeDom.Compiler;
24 using System.Security.Permissions;
25 using System.Web.Hosting;
26 using System.Web.Management;
27 using System.Web.Util;
31 /// <para> Enables ASP.NET
32 /// to send exception information.</para>
35 public class HttpException : ExternalException {
36 private const int FACILITY_WIN32 = 7;
38 private int _httpCode;
39 private ErrorFormatter _errorFormatter;
40 private int _webEventCode = WebEventCodes.UndefinedEventCode;
42 // N.B. The last error code can be lost if we were to
43 // call UnsafeNativeMethods.GetLastError from this function
44 // and it were not yet jitted.
45 internal static int HResultFromLastError(int lastError) {
52 hr = (int)(((uint)lastError & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000);
60 /// <para>Creates a new Exception based on the previous Exception. </para>
62 public static HttpException CreateFromLastError(String message) {
63 return new HttpException(message, HResultFromLastError(Marshal.GetLastWin32Error()));
68 /// <para> Default constructor.</para>
70 public HttpException() {}
75 /// Construct an exception using error message.
78 public HttpException(String message)
83 internal HttpException(String message, Exception innerException, int code)
85 : base(message, innerException) {
91 /// <para>Construct an exception using error message and hr.</para>
93 public HttpException(String message, int hr)
101 /// <para>Construct an exception using error message, HTTP code,
102 /// and innerException
105 public HttpException(String message, Exception innerException)
107 : base(message, innerException) {
112 /// <para>Construct an exception using HTTP error code, error message,
113 /// and innerException
116 public HttpException(int httpCode, String message, Exception innerException)
118 : base(message, innerException) {
119 _httpCode = httpCode;
124 /// <para>Construct an
125 /// exception using HTTP error code and error message.</para>
127 public HttpException(int httpCode, String message)
130 _httpCode = httpCode;
135 /// <para> Construct an exception
136 /// using HTTP error code, error message, and hr.</para>
138 public HttpException(int httpCode, String message, int hr)
142 _httpCode = httpCode;
147 /// <para> Contructor used for derialization.</para>
149 protected HttpException(SerializationInfo info, StreamingContext context)
150 :base(info, context) {
151 _httpCode = info.GetInt32("_httpCode");
156 /// <para>Serialize the object.</para>
158 //[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter=true)]
159 [SuppressMessage("Microsoft.Security", "CA2110:SecureGetObjectDataOverrides", Justification = "Base class has demand")]
160 public override void GetObjectData(SerializationInfo info, StreamingContext context)
162 base.GetObjectData(info, context);
163 info.AddValue("_httpCode", _httpCode);
167 * If we have an Http code (non-zero), return it. Otherwise, return
168 * the inner exception's code. If there isn't one, return 500.
172 /// <para>HTTP return code to send back to client. If there is a
173 /// non-zero Http code, it is returned. Otherwise, the System.HttpException.innerException
174 /// code is returned. If
175 /// there isn't an inner exception, error code 500 is returned.</para>
177 public int GetHttpCode() {
178 return GetHttpCodeForException(this);
181 internal void SetFormatter(ErrorFormatter errorFormatter) {
182 _errorFormatter = errorFormatter;
185 internal static int GetHttpCodeForException(Exception e) {
187 if (e is HttpException) {
188 HttpException he = (HttpException)e;
190 // If the HttpException specifies an HTTP code, use it
191 if (he._httpCode > 0)
195 404 conversion is done in HttpAplpication.MapHttpHandler
197 else if (e is FileNotFoundException || e is DirectoryNotFoundException)
202 else if (e is UnauthorizedAccessException) {
205 else if (e is PathTooLongException) {
209 // If there is an inner exception, try to get the code from it
210 if (e.InnerException != null)
211 return GetHttpCodeForException(e.InnerException);
213 // If all else fails, use 500
218 * Return the formatter associated with this exception
220 internal static ErrorFormatter GetErrorFormatter(Exception e) {
221 Exception inner = e.InnerException;
222 ErrorFormatter nestedFormatter = null;
224 // First, see if the inner exception has a formatter
226 nestedFormatter = GetErrorFormatter(inner);
227 if (nestedFormatter != null)
228 return nestedFormatter;
230 if (inner is ConfigurationException)
232 ConfigurationException ce = inner as ConfigurationException;
233 if (ce != null && ce.Filename != null)
234 nestedFormatter = new ConfigErrorFormatter((ConfigurationException)inner);
236 else if (inner is SecurityException)
237 nestedFormatter = new SecurityErrorFormatter(inner);
240 // If it does, return it rather than our own
241 if (nestedFormatter != null)
242 return nestedFormatter;
244 HttpException httpExc = e as HttpException;
246 return httpExc._errorFormatter;
253 /// <para>[To be supplied.]</para>
255 public string GetHtmlErrorMessage() {
256 ErrorFormatter formatter = GetErrorFormatter(this);
257 if (formatter == null) return null;
258 return formatter.GetHtmlErrorMessage();
261 public int WebEventCode {
262 get { return _webEventCode; }
263 internal set { _webEventCode = value; }
269 /// <para> Exception thrown when a generic error occurs.</para>
272 public sealed class HttpUnhandledException : HttpException {
275 public HttpUnhandledException() {}
278 public HttpUnhandledException(String message)
284 public HttpUnhandledException(string message, Exception innerException)
285 : base(message, innerException) {
287 SetFormatter(new UnhandledErrorFormatter(innerException, message, null));
292 internal HttpUnhandledException(string message, string postMessage, Exception innerException)
293 : base(message, innerException) {
295 SetFormatter(new UnhandledErrorFormatter(innerException, message, postMessage));
298 private HttpUnhandledException(SerializationInfo info, StreamingContext context)
299 :base(info, context) {
305 /// <para> Exception thrown when a compilation error occurs.</para>
308 public sealed class HttpCompileException : HttpException {
310 private CompilerResults _results;
311 private string _sourceCode;
314 public HttpCompileException() {
318 public HttpCompileException(string message) : base(message) {
322 public HttpCompileException(String message, Exception innerException) : base(message, innerException) {
326 public HttpCompileException(CompilerResults results, string sourceCode) {
328 _sourceCode = sourceCode;
330 SetFormatter(new DynamicCompileErrorFormatter(this));
333 private HttpCompileException(SerializationInfo info, StreamingContext context)
334 :base(info, context) {
335 _results = (CompilerResults) info.GetValue("_results", typeof(CompilerResults));
336 _sourceCode = info.GetString("_sourceCode");
339 // Determines whether the compile exception should be cached
340 private bool _dontCache;
341 internal bool DontCache {
342 get { return _dontCache; }
343 set { _dontCache = value; }
346 // The virtualpath depdencies for current buildresult.
347 private ICollection _virtualPathDependencies;
348 internal ICollection VirtualPathDependencies {
349 get { return _virtualPathDependencies; }
350 set { _virtualPathDependencies = value; }
355 /// <para>Serialize the object.</para>
357 [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter=true)]
358 public override void GetObjectData(SerializationInfo info, StreamingContext context)
360 base.GetObjectData(info, context);
361 info.AddValue("_results", _results);
362 info.AddValue("_sourceCode", _sourceCode);
365 private const string compileErrorFormat = "{0}({1}): error {2}: {3}";
369 /// <para> The first compilation error.</para>
371 public override string Message {
373 // Return the first compile error as the exception message
374 CompilerError e = FirstCompileError;
379 string message = String.Format(CultureInfo.CurrentCulture, compileErrorFormat,
380 e.FileName, e.Line, e.ErrorNumber, e.ErrorText);
388 /// <para> The CompilerResults object describing the compile error.</para>
390 public CompilerResults Results {
391 [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.High)]
397 internal CompilerResults ResultsWithoutDemand {
404 /// <para> The source code that was compiled.</para>
406 public string SourceCode {
407 [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.High)]
413 internal string SourceCodeWithoutDemand {
419 // Return the first compile error, or null if there isn't one
420 internal CompilerError FirstCompileError {
422 if (_results == null || !_results.Errors.HasErrors)
425 CompilerError e = null;
427 foreach (CompilerError error in _results.Errors) {
430 if (error.IsWarning) continue;
432 // If we found an error that's not in the generated code, use it
433 if (HttpRuntime.CodegenDirInternal != null && error.FileName != null &&
434 !StringUtil.StringStartsWith(error.FileName, HttpRuntime.CodegenDirInternal)) {
439 // The current error is in the generated code. Keep track of
440 // it if it's the first one, but keep on looking in case we find another
441 // one that's not in the generated code (ASURT 62600)
453 /// <para> Exception thrown when a parse error occurs.</para>
456 public sealed class HttpParseException : HttpException {
458 private VirtualPath _virtualPath;
460 private ParserErrorCollection _parserErrors;
463 public HttpParseException() {
467 public HttpParseException(string message) : base(message) {
471 public HttpParseException(String message, Exception innerException) : base(message, innerException) {
475 public HttpParseException(string message, Exception innerException, string virtualPath,
476 string sourceCode, int line) : this(message, innerException,
477 System.Web.VirtualPath.CreateAllowNull(virtualPath), sourceCode, line) {}
479 internal HttpParseException(string message, Exception innerException, VirtualPath virtualPath,
480 string sourceCode, int line)
481 : base(message, innerException) {
483 _virtualPath = virtualPath;
486 string formatterMessage;
487 if (innerException != null)
488 formatterMessage = innerException.Message;
490 formatterMessage = message;
492 SetFormatter(new ParseErrorFormatter(this, System.Web.VirtualPath.GetVirtualPathString(virtualPath), sourceCode,
493 line, formatterMessage));
496 private HttpParseException(SerializationInfo info, StreamingContext context)
497 :base(info, context) {
498 _virtualPath = (VirtualPath)info.GetValue("_virtualPath", typeof(VirtualPath));
499 _line = info.GetInt32("_line");
500 _parserErrors = (ParserErrorCollection)info.GetValue("_parserErrors", typeof(ParserErrorCollection));
505 /// <para>Serialize the object.</para>
507 [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter=true)]
508 public override void GetObjectData(SerializationInfo info, StreamingContext context)
510 base.GetObjectData(info, context);
511 info.AddValue("_virtualPath", _virtualPath);
512 info.AddValue("_line", _line);
513 info.AddValue("_parserErrors", _parserErrors);
518 /// <para> The physical path to source file that has the error.</para>
520 public string FileName {
522 string physicalPath = _virtualPath.MapPathInternal();
524 if (physicalPath == null)
527 // Demand path discovery before returning the path (ASURT 123798)
528 InternalSecurityPermissions.PathDiscovery(physicalPath).Demand();
535 /// <para> The virtual path to source file that has the error.</para>
537 public string VirtualPath {
539 return System.Web.VirtualPath.GetVirtualPathString(_virtualPath);
543 internal VirtualPath VirtualPathObject {
550 /// <para> The CompilerResults object describing the compile error.</para>
556 // The set of parser errors
557 public ParserErrorCollection ParserErrors {
559 if (_parserErrors == null) {
560 _parserErrors = new ParserErrorCollection();
561 ParserError thisError = new ParserError(Message, _virtualPath, _line);
562 _parserErrors.Add(thisError);
565 return _parserErrors;
572 /// <para> Exception thrown when a potentially unsafe input string is detected (ASURT 122278)</para>
575 public sealed class HttpRequestValidationException : HttpException {
578 public HttpRequestValidationException() {
582 public HttpRequestValidationException(string message) : base(message) {
584 SetFormatter(new UnhandledErrorFormatter(
585 this, SR.GetString(SR.Dangerous_input_detected_descr), null));
589 public HttpRequestValidationException(String message, Exception innerException) : base(message, innerException) {
592 private HttpRequestValidationException(SerializationInfo info, StreamingContext context)
593 :base(info, context) {
598 public sealed class ParserError {
600 private VirtualPath _virtualPath;
601 private string _errorText;
602 private Exception _exception;
604 public ParserError() {
607 public ParserError(string errorText, string virtualPath, int line)
608 : this(errorText, System.Web.VirtualPath.CreateAllowNull(virtualPath), line) {
611 internal ParserError(string errorText, VirtualPath virtualPath, int line) {
612 _virtualPath = virtualPath;
614 _errorText = errorText;
617 // The original exception that introduces the Parser Error
618 internal Exception Exception {
619 get { return _exception; }
620 set { _exception = value; }
623 // The virtualPath where the parser error occurs.
624 public string VirtualPath {
625 get { return System.Web.VirtualPath.GetVirtualPathString(_virtualPath); }
626 set { _virtualPath = System.Web.VirtualPath.Create(value); }
629 // The description error text of the error.
630 public string ErrorText {
631 get { return _errorText; }
632 set { _errorText = value; }
635 // The line where the parser error occurs.
637 get { return _line; }
638 set { _line = value; }
643 public sealed class ParserErrorCollection : CollectionBase {
644 public ParserErrorCollection() {
647 public ParserErrorCollection(ParserError[] value) {
648 this.AddRange(value);
651 public ParserError this[int index] {
652 get { return ((ParserError)List[index]); }
653 set { List[index] = value; }
656 public int Add(ParserError value) {
657 return List.Add(value);
660 public void AddRange(ParserError[] value) {
662 throw new ArgumentNullException("value");
665 for (int i = 0; i < value.Length; i++) {
670 public void AddRange(ParserErrorCollection value) {
672 throw new ArgumentNullException("value");
675 foreach(ParserError parserError in value) {
676 this.Add(parserError);
680 public bool Contains(ParserError value) {
681 return List.Contains(value);
684 public void CopyTo(ParserError[] array, int index) {
685 List.CopyTo(array, index);
688 public int IndexOf(ParserError value) {
689 return List.IndexOf(value);
692 public void Insert(int index, ParserError value) {
693 List.Insert(index, value);
696 public void Remove(ParserError value) {