//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ /* * Exception thrown by ASP.NET managed runtime * * Copyright (c) 1998 Microsoft Corporation */ namespace System.Web { using System.IO; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Collections; using System.Collections.Specialized; using System.Configuration; using System.Diagnostics.CodeAnalysis; using System.Security; using System.Globalization; using System.CodeDom.Compiler; using System.Security.Permissions; using System.Web.Hosting; using System.Web.Management; using System.Web.Util; /// /// Enables ASP.NET /// to send exception information. /// [Serializable] public class HttpException : ExternalException { private const int FACILITY_WIN32 = 7; private int _httpCode; private ErrorFormatter _errorFormatter; private int _webEventCode = WebEventCodes.UndefinedEventCode; // N.B. The last error code can be lost if we were to // call UnsafeNativeMethods.GetLastError from this function // and it were not yet jitted. internal static int HResultFromLastError(int lastError) { int hr; if (lastError < 0) { hr = lastError; } else { hr = (int)(((uint)lastError & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000); } return hr; } /// /// Creates a new Exception based on the previous Exception. /// public static HttpException CreateFromLastError(String message) { return new HttpException(message, HResultFromLastError(Marshal.GetLastWin32Error())); } /// /// Default constructor. /// public HttpException() {} /// /// /// Construct an exception using error message. /// /// public HttpException(String message) : base(message) { } internal HttpException(String message, Exception innerException, int code) : base(message, innerException) { _webEventCode = code; } /// /// Construct an exception using error message and hr. /// public HttpException(String message, int hr) : base(message) { HResult = hr; } /// /// Construct an exception using error message, HTTP code, /// and innerException /// . /// public HttpException(String message, Exception innerException) : base(message, innerException) { } /// /// Construct an exception using HTTP error code, error message, /// and innerException /// . /// public HttpException(int httpCode, String message, Exception innerException) : base(message, innerException) { _httpCode = httpCode; } /// /// Construct an /// exception using HTTP error code and error message. /// public HttpException(int httpCode, String message) : base(message) { _httpCode = httpCode; } /// /// Construct an exception /// using HTTP error code, error message, and hr. /// public HttpException(int httpCode, String message, int hr) : base(message) { HResult = hr; _httpCode = httpCode; } /// /// Contructor used for derialization. /// protected HttpException(SerializationInfo info, StreamingContext context) :base(info, context) { _httpCode = info.GetInt32("_httpCode"); } /// /// Serialize the object. /// //[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter=true)] [SuppressMessage("Microsoft.Security", "CA2110:SecureGetObjectDataOverrides", Justification = "Base class has demand")] public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); info.AddValue("_httpCode", _httpCode); } /* * If we have an Http code (non-zero), return it. Otherwise, return * the inner exception's code. If there isn't one, return 500. */ /// /// HTTP return code to send back to client. If there is a /// non-zero Http code, it is returned. Otherwise, the System.HttpException.innerException /// code is returned. If /// there isn't an inner exception, error code 500 is returned. /// public int GetHttpCode() { return GetHttpCodeForException(this); } internal void SetFormatter(ErrorFormatter errorFormatter) { _errorFormatter = errorFormatter; } internal static int GetHttpCodeForException(Exception e) { if (e is HttpException) { HttpException he = (HttpException)e; // If the HttpException specifies an HTTP code, use it if (he._httpCode > 0) return he._httpCode; } /* 404 conversion is done in HttpAplpication.MapHttpHandler else if (e is FileNotFoundException || e is DirectoryNotFoundException) { code = 404; } */ else if (e is UnauthorizedAccessException) { return 401; } else if (e is PathTooLongException) { return 414; } // If there is an inner exception, try to get the code from it if (e.InnerException != null) return GetHttpCodeForException(e.InnerException); // If all else fails, use 500 return 500; } /* * Return the formatter associated with this exception */ internal static ErrorFormatter GetErrorFormatter(Exception e) { Exception inner = e.InnerException; ErrorFormatter nestedFormatter = null; // First, see if the inner exception has a formatter if (inner != null) { nestedFormatter = GetErrorFormatter(inner); if (nestedFormatter != null) return nestedFormatter; if (inner is ConfigurationException) { ConfigurationException ce = inner as ConfigurationException; if (ce != null && ce.Filename != null) nestedFormatter = new ConfigErrorFormatter((ConfigurationException)inner); } else if (inner is SecurityException) nestedFormatter = new SecurityErrorFormatter(inner); } // If it does, return it rather than our own if (nestedFormatter != null) return nestedFormatter; HttpException httpExc = e as HttpException; if (httpExc != null) return httpExc._errorFormatter; return null; } /// /// [To be supplied.] /// public string GetHtmlErrorMessage() { ErrorFormatter formatter = GetErrorFormatter(this); if (formatter == null) return null; return formatter.GetHtmlErrorMessage(); } public int WebEventCode { get { return _webEventCode; } internal set { _webEventCode = value; } } } /// /// Exception thrown when a generic error occurs. /// [Serializable] public sealed class HttpUnhandledException : HttpException { public HttpUnhandledException() {} public HttpUnhandledException(String message) : base(message) { } public HttpUnhandledException(string message, Exception innerException) : base(message, innerException) { SetFormatter(new UnhandledErrorFormatter(innerException, message, null)); } /// internal HttpUnhandledException(string message, string postMessage, Exception innerException) : base(message, innerException) { SetFormatter(new UnhandledErrorFormatter(innerException, message, postMessage)); } private HttpUnhandledException(SerializationInfo info, StreamingContext context) :base(info, context) { } } /// /// Exception thrown when a compilation error occurs. /// [Serializable] public sealed class HttpCompileException : HttpException { private CompilerResults _results; private string _sourceCode; public HttpCompileException() { } public HttpCompileException(string message) : base(message) { } public HttpCompileException(String message, Exception innerException) : base(message, innerException) { } public HttpCompileException(CompilerResults results, string sourceCode) { _results = results; _sourceCode = sourceCode; SetFormatter(new DynamicCompileErrorFormatter(this)); } private HttpCompileException(SerializationInfo info, StreamingContext context) :base(info, context) { _results = (CompilerResults) info.GetValue("_results", typeof(CompilerResults)); _sourceCode = info.GetString("_sourceCode"); } // Determines whether the compile exception should be cached private bool _dontCache; internal bool DontCache { get { return _dontCache; } set { _dontCache = value; } } // The virtualpath depdencies for current buildresult. private ICollection _virtualPathDependencies; internal ICollection VirtualPathDependencies { get { return _virtualPathDependencies; } set { _virtualPathDependencies = value; } } /// /// Serialize the object. /// [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter=true)] public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); info.AddValue("_results", _results); info.AddValue("_sourceCode", _sourceCode); } private const string compileErrorFormat = "{0}({1}): error {2}: {3}"; /// /// The first compilation error. /// public override string Message { get { // Return the first compile error as the exception message CompilerError e = FirstCompileError; if (e == null) return base.Message; string message = String.Format(CultureInfo.CurrentCulture, compileErrorFormat, e.FileName, e.Line, e.ErrorNumber, e.ErrorText); return message; } } /// /// The CompilerResults object describing the compile error. /// public CompilerResults Results { [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.High)] get { return _results; } } internal CompilerResults ResultsWithoutDemand { get { return _results; } } /// /// The source code that was compiled. /// public string SourceCode { [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.High)] get { return _sourceCode; } } internal string SourceCodeWithoutDemand { get { return _sourceCode; } } // Return the first compile error, or null if there isn't one internal CompilerError FirstCompileError { get { if (_results == null || !_results.Errors.HasErrors) return null; CompilerError e = null; foreach (CompilerError error in _results.Errors) { // Ignore warnings if (error.IsWarning) continue; // If we found an error that's not in the generated code, use it if (HttpRuntime.CodegenDirInternal != null && error.FileName != null && !StringUtil.StringStartsWith(error.FileName, HttpRuntime.CodegenDirInternal)) { e = error; break; } // The current error is in the generated code. Keep track of // it if it's the first one, but keep on looking in case we find another // one that's not in the generated code (ASURT 62600) if (e == null) e = error; } return e; } } } /// /// Exception thrown when a parse error occurs. /// [Serializable] public sealed class HttpParseException : HttpException { private VirtualPath _virtualPath; private int _line; private ParserErrorCollection _parserErrors; public HttpParseException() { } public HttpParseException(string message) : base(message) { } public HttpParseException(String message, Exception innerException) : base(message, innerException) { } public HttpParseException(string message, Exception innerException, string virtualPath, string sourceCode, int line) : this(message, innerException, System.Web.VirtualPath.CreateAllowNull(virtualPath), sourceCode, line) {} internal HttpParseException(string message, Exception innerException, VirtualPath virtualPath, string sourceCode, int line) : base(message, innerException) { _virtualPath = virtualPath; _line = line; string formatterMessage; if (innerException != null) formatterMessage = innerException.Message; else formatterMessage = message; SetFormatter(new ParseErrorFormatter(this, System.Web.VirtualPath.GetVirtualPathString(virtualPath), sourceCode, line, formatterMessage)); } private HttpParseException(SerializationInfo info, StreamingContext context) :base(info, context) { _virtualPath = (VirtualPath)info.GetValue("_virtualPath", typeof(VirtualPath)); _line = info.GetInt32("_line"); _parserErrors = (ParserErrorCollection)info.GetValue("_parserErrors", typeof(ParserErrorCollection)); } /// /// Serialize the object. /// [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter=true)] public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); info.AddValue("_virtualPath", _virtualPath); info.AddValue("_line", _line); info.AddValue("_parserErrors", _parserErrors); } /// /// The physical path to source file that has the error. /// public string FileName { get { string physicalPath = _virtualPath.MapPathInternal(); if (physicalPath == null) return null; // Demand path discovery before returning the path (ASURT 123798) InternalSecurityPermissions.PathDiscovery(physicalPath).Demand(); return physicalPath; } } /// /// The virtual path to source file that has the error. /// public string VirtualPath { get { return System.Web.VirtualPath.GetVirtualPathString(_virtualPath); } } internal VirtualPath VirtualPathObject { get { return _virtualPath; } } /// /// The CompilerResults object describing the compile error. /// public int Line { get { return _line;} } // The set of parser errors public ParserErrorCollection ParserErrors { get { if (_parserErrors == null) { _parserErrors = new ParserErrorCollection(); ParserError thisError = new ParserError(Message, _virtualPath, _line); _parserErrors.Add(thisError); } return _parserErrors; } } } /// /// Exception thrown when a potentially unsafe input string is detected (ASURT 122278) /// [Serializable] public sealed class HttpRequestValidationException : HttpException { public HttpRequestValidationException() { } public HttpRequestValidationException(string message) : base(message) { SetFormatter(new UnhandledErrorFormatter( this, SR.GetString(SR.Dangerous_input_detected_descr), null)); } public HttpRequestValidationException(String message, Exception innerException) : base(message, innerException) { } private HttpRequestValidationException(SerializationInfo info, StreamingContext context) :base(info, context) { } } [Serializable] public sealed class ParserError { private int _line; private VirtualPath _virtualPath; private string _errorText; private Exception _exception; public ParserError() { } public ParserError(string errorText, string virtualPath, int line) : this(errorText, System.Web.VirtualPath.CreateAllowNull(virtualPath), line) { } internal ParserError(string errorText, VirtualPath virtualPath, int line) { _virtualPath = virtualPath; _line = line; _errorText = errorText; } // The original exception that introduces the Parser Error internal Exception Exception { get { return _exception; } set { _exception = value; } } // The virtualPath where the parser error occurs. public string VirtualPath { get { return System.Web.VirtualPath.GetVirtualPathString(_virtualPath); } set { _virtualPath = System.Web.VirtualPath.Create(value); } } // The description error text of the error. public string ErrorText { get { return _errorText; } set { _errorText = value; } } // The line where the parser error occurs. public int Line { get { return _line; } set { _line = value; } } } [Serializable] public sealed class ParserErrorCollection : CollectionBase { public ParserErrorCollection() { } public ParserErrorCollection(ParserError[] value) { this.AddRange(value); } public ParserError this[int index] { get { return ((ParserError)List[index]); } set { List[index] = value; } } public int Add(ParserError value) { return List.Add(value); } public void AddRange(ParserError[] value) { if (value == null) { throw new ArgumentNullException("value"); } for (int i = 0; i < value.Length; i++) { this.Add(value[i]); } } public void AddRange(ParserErrorCollection value) { if (value == null) { throw new ArgumentNullException("value"); } foreach(ParserError parserError in value) { this.Add(parserError); } } public bool Contains(ParserError value) { return List.Contains(value); } public void CopyTo(ParserError[] array, int index) { List.CopyTo(array, index); } public int IndexOf(ParserError value) { return List.IndexOf(value); } public void Insert(int index, ParserError value) { List.Insert(index, value); } public void Remove(ParserError value) { List.Remove(value); } } }