Merge pull request #3622 from rolfbjarne/remove-stray-file
[mono.git] / mcs / class / referencesource / System.Web / HttpException.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="HttpException.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>                                                                
5 //------------------------------------------------------------------------------
6
7 /*
8  * Exception thrown by ASP.NET managed runtime
9  * 
10  * Copyright (c) 1998 Microsoft Corporation
11  */
12
13 namespace System.Web {
14     using System.IO;
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;
28
29
30     /// <devdoc>
31     ///    <para> Enables ASP.NET
32     ///       to send exception information.</para>
33     /// </devdoc>
34     [Serializable]
35     public class HttpException : ExternalException {
36         private const int FACILITY_WIN32 = 7;
37
38         private int _httpCode;
39         private ErrorFormatter _errorFormatter;
40         private int _webEventCode = WebEventCodes.UndefinedEventCode;
41
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) {
46             int hr;
47
48             if (lastError < 0) {
49                 hr = lastError;
50             }
51             else {
52                 hr = (int)(((uint)lastError & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000);
53             }
54
55             return hr;
56         }
57
58
59         /// <devdoc>
60         ///    <para>Creates a new Exception based on the previous Exception. </para>
61         /// </devdoc>
62         public static HttpException CreateFromLastError(String message) {
63             return new HttpException(message, HResultFromLastError(Marshal.GetLastWin32Error()));
64         }
65
66
67         /// <devdoc>
68         /// <para> Default constructor.</para>
69         /// </devdoc>
70         public HttpException() {}
71
72
73         /// <devdoc>
74         ///    <para>
75         ///       Construct an exception using error message.
76         ///    </para>
77         /// </devdoc>
78         public HttpException(String message)
79
80         : base(message) {
81         }
82
83         internal HttpException(String message, Exception innerException, int code)
84         
85         : base(message, innerException) {
86             _webEventCode = code;
87         }
88         
89
90         /// <devdoc>
91         ///    <para>Construct an exception using error message and hr.</para>
92         /// </devdoc>
93         public HttpException(String message, int hr)
94
95         : base(message) {
96             HResult = hr;
97         }
98
99
100         /// <devdoc>
101         ///    <para>Construct an exception using error message, HTTP code, 
102         ///       and innerException
103         ///       .</para>
104         /// </devdoc>
105         public HttpException(String message, Exception innerException)
106
107         : base(message, innerException) {
108         }
109
110
111         /// <devdoc>
112         ///    <para>Construct an exception using HTTP error code, error message, 
113         ///       and innerException
114         ///       .</para>
115         /// </devdoc>
116         public HttpException(int httpCode, String message, Exception innerException)
117
118         : base(message, innerException) {
119             _httpCode = httpCode;
120         }
121
122
123         /// <devdoc>
124         ///    <para>Construct an
125         ///       exception using HTTP error code and error message.</para>
126         /// </devdoc>
127         public HttpException(int httpCode, String message)
128
129         : base(message) {
130             _httpCode = httpCode;
131         }
132
133
134         /// <devdoc>
135         ///    <para> Construct an exception
136         ///       using HTTP error code, error message, and hr.</para>
137         /// </devdoc>
138         public HttpException(int httpCode, String message, int hr)
139
140         : base(message) {
141             HResult = hr;
142             _httpCode = httpCode;
143         }
144
145
146         /// <devdoc>
147         ///    <para> Contructor used for derialization.</para>
148         /// </devdoc>
149         protected HttpException(SerializationInfo info, StreamingContext context)
150            :base(info, context) {
151            _httpCode = info.GetInt32("_httpCode");
152         }
153
154
155         /// <devdoc>
156         ///    <para>Serialize the object.</para>
157         /// </devdoc>
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)
161         {
162             base.GetObjectData(info, context);
163             info.AddValue("_httpCode", _httpCode);
164         }
165
166         /*
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.
169          */
170
171         /// <devdoc>
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>
176         /// </devdoc>
177         public int GetHttpCode() {
178             return GetHttpCodeForException(this);
179         }
180
181         internal void SetFormatter(ErrorFormatter errorFormatter) {
182             _errorFormatter = errorFormatter;
183         }
184
185         internal static int GetHttpCodeForException(Exception e) {
186
187             if (e is HttpException) {
188                 HttpException he = (HttpException)e;
189
190                 // If the HttpException specifies an HTTP code, use it
191                 if (he._httpCode > 0)
192                     return he._httpCode;
193             }
194 /*
195 404 conversion is done in HttpAplpication.MapHttpHandler
196
197             else if (e is FileNotFoundException || e is DirectoryNotFoundException)
198             {
199                 code = 404;
200             }
201 */
202             else if (e is UnauthorizedAccessException) {
203                 return 401;
204             }
205             else if (e is PathTooLongException) {
206                 return 414;
207             }
208
209             // If there is an inner exception, try to get the code from it
210             if (e.InnerException != null)
211                 return GetHttpCodeForException(e.InnerException);
212
213             // If all else fails, use 500
214             return 500;
215         }
216
217         /*
218          * Return the formatter associated with this exception
219          */
220         internal static ErrorFormatter GetErrorFormatter(Exception e) {
221             Exception inner = e.InnerException;
222             ErrorFormatter nestedFormatter = null;
223
224             // First, see if the inner exception has a formatter
225             if (inner != null) {
226                 nestedFormatter = GetErrorFormatter(inner);
227                 if (nestedFormatter != null)
228                     return nestedFormatter;
229
230                 if (inner is ConfigurationException)
231                 {
232                     ConfigurationException ce = inner as ConfigurationException;
233                     if (ce != null && ce.Filename != null)
234                         nestedFormatter = new ConfigErrorFormatter((ConfigurationException)inner);
235                 }
236                 else if (inner is SecurityException)
237                     nestedFormatter = new SecurityErrorFormatter(inner);
238             }
239
240             // If it does, return it rather than our own
241             if (nestedFormatter != null)
242                 return nestedFormatter;
243
244             HttpException httpExc = e as HttpException;
245             if (httpExc != null)
246                 return httpExc._errorFormatter;
247
248             return null;
249         }
250
251
252         /// <devdoc>
253         ///    <para>[To be supplied.]</para>
254         /// </devdoc>
255         public string GetHtmlErrorMessage() {
256             ErrorFormatter formatter = GetErrorFormatter(this);
257             if (formatter == null) return null;
258             return formatter.GetHtmlErrorMessage();
259         }
260
261         public int WebEventCode {
262             get { return _webEventCode; }
263             internal set { _webEventCode = value; }
264         }
265     }
266
267
268     /// <devdoc>
269     ///    <para> Exception thrown when a generic error occurs.</para>
270     /// </devdoc>
271     [Serializable]
272     public sealed class HttpUnhandledException : HttpException {
273
274
275         public HttpUnhandledException() {}
276
277
278         public HttpUnhandledException(String message)
279
280         : base(message) {
281         }
282
283
284         public HttpUnhandledException(string message, Exception innerException)
285         : base(message, innerException) {
286            
287             SetFormatter(new UnhandledErrorFormatter(innerException, message, null));
288         }
289
290
291         /// <internalonly/>
292         internal HttpUnhandledException(string message, string postMessage, Exception innerException)
293         : base(message, innerException) {
294            
295             SetFormatter(new UnhandledErrorFormatter(innerException, message, postMessage));
296         }
297
298         private HttpUnhandledException(SerializationInfo info, StreamingContext context)
299            :base(info, context) {
300         }
301     }
302
303
304     /// <devdoc>
305     ///    <para> Exception thrown when a compilation error occurs.</para>
306     /// </devdoc>
307     [Serializable]
308     public sealed class HttpCompileException : HttpException {
309
310         private CompilerResults _results;
311         private string _sourceCode;
312
313
314         public HttpCompileException() {
315         }
316
317
318         public HttpCompileException(string message) : base(message) {
319         }
320
321
322         public HttpCompileException(String message, Exception innerException) : base(message, innerException) {
323         }
324
325
326         public HttpCompileException(CompilerResults results, string sourceCode) {
327             _results = results;
328             _sourceCode = sourceCode;
329
330             SetFormatter(new DynamicCompileErrorFormatter(this));
331         }
332
333         private HttpCompileException(SerializationInfo info, StreamingContext context)
334            :base(info, context) {
335            _results = (CompilerResults) info.GetValue("_results", typeof(CompilerResults));
336            _sourceCode = info.GetString("_sourceCode");
337         }
338
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; }
344         }
345
346         // The virtualpath depdencies for current buildresult.
347         private ICollection _virtualPathDependencies;
348         internal ICollection VirtualPathDependencies {
349             get { return _virtualPathDependencies; }
350             set { _virtualPathDependencies = value; }
351         }
352
353
354         /// <devdoc>
355         ///    <para>Serialize the object.</para>
356         /// </devdoc>
357         [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter=true)]
358         public override void GetObjectData(SerializationInfo info, StreamingContext context)
359         {
360             base.GetObjectData(info, context);
361             info.AddValue("_results", _results);
362             info.AddValue("_sourceCode", _sourceCode);
363         }
364
365         private const string compileErrorFormat = "{0}({1}): error {2}: {3}";
366
367
368         /// <devdoc>
369         ///    <para> The first compilation error.</para>
370         /// </devdoc>
371         public override string Message {
372             get {
373                 // Return the first compile error as the exception message
374                 CompilerError e = FirstCompileError;
375
376                 if (e == null)
377                     return base.Message;
378
379                 string message = String.Format(CultureInfo.CurrentCulture, compileErrorFormat,
380                     e.FileName, e.Line, e.ErrorNumber, e.ErrorText);
381                 
382                 return message;
383             }
384         }
385
386
387         /// <devdoc>
388         ///    <para> The CompilerResults object describing the compile error.</para>
389         /// </devdoc>
390         public CompilerResults Results {
391             [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.High)]
392             get { 
393                 return _results;
394             } 
395         }
396
397         internal CompilerResults ResultsWithoutDemand {
398             get {
399                 return _results;
400             }
401         }
402
403         /// <devdoc>
404         ///    <para> The source code that was compiled.</para>
405         /// </devdoc>
406         public string SourceCode {
407             [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.High)]
408             get { 
409                 return _sourceCode; 
410             }
411         }
412
413         internal string SourceCodeWithoutDemand {
414             get {
415                 return _sourceCode;
416             }
417         }
418
419         // Return the first compile error, or null if there isn't one
420         internal CompilerError FirstCompileError {
421             get {
422                 if (_results == null || !_results.Errors.HasErrors)
423                     return null;
424
425                 CompilerError e = null;
426
427                 foreach (CompilerError error in _results.Errors) {
428                     
429                     // Ignore warnings
430                     if (error.IsWarning) continue;
431
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)) {
435                         e = error;
436                         break;
437                     }
438
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)
442                     if (e == null)
443                         e = error;
444                 }
445
446                 return e;
447             }
448         }
449     }
450
451
452     /// <devdoc>
453     ///    <para> Exception thrown when a parse error occurs.</para>
454     /// </devdoc>
455     [Serializable]
456     public sealed class HttpParseException : HttpException {
457
458         private VirtualPath _virtualPath;
459         private int _line;
460         private ParserErrorCollection _parserErrors;
461
462
463         public HttpParseException() {
464         }
465
466
467         public HttpParseException(string message) : base(message) {
468         }
469
470
471         public HttpParseException(String message, Exception innerException) : base(message, innerException) {
472         }
473
474
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) {}
478
479         internal HttpParseException(string message, Exception innerException, VirtualPath virtualPath,
480             string sourceCode, int line)
481             : base(message, innerException) {
482
483             _virtualPath = virtualPath;
484             _line = line;
485
486             string formatterMessage;
487             if (innerException != null)
488                 formatterMessage = innerException.Message;
489             else
490                 formatterMessage = message;
491
492             SetFormatter(new ParseErrorFormatter(this, System.Web.VirtualPath.GetVirtualPathString(virtualPath), sourceCode,
493                 line, formatterMessage));
494         }
495
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));
501        }
502
503
504         /// <devdoc>
505         ///    <para>Serialize the object.</para>
506         /// </devdoc>
507         [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter=true)]
508         public override void GetObjectData(SerializationInfo info, StreamingContext context)
509         {
510             base.GetObjectData(info, context);
511             info.AddValue("_virtualPath", _virtualPath);
512             info.AddValue("_line", _line);
513             info.AddValue("_parserErrors", _parserErrors);
514         }
515
516
517         /// <devdoc>
518         ///    <para> The physical path to source file that has the error.</para>
519         /// </devdoc>
520         public string FileName {
521             get {
522                 string physicalPath = _virtualPath.MapPathInternal();
523
524                 if (physicalPath == null)
525                     return null;
526
527                 // Demand path discovery before returning the path (ASURT 123798)
528                 InternalSecurityPermissions.PathDiscovery(physicalPath).Demand();
529                 return physicalPath;
530             } 
531         }
532
533
534         /// <devdoc>
535         ///    <para> The virtual path to source file that has the error.</para>
536         /// </devdoc>
537         public string VirtualPath {
538             get {
539                 return System.Web.VirtualPath.GetVirtualPathString(_virtualPath);
540             } 
541         }
542
543         internal VirtualPath VirtualPathObject {
544             get {
545                 return _virtualPath;
546             }
547         }
548
549         /// <devdoc>
550         ///    <para> The CompilerResults object describing the compile error.</para>
551         /// </devdoc>
552         public int Line {
553             get { return _line;} 
554         }
555
556         // The set of parser errors
557         public ParserErrorCollection ParserErrors {
558             get {
559                 if (_parserErrors == null) {
560                     _parserErrors = new ParserErrorCollection();
561                     ParserError thisError = new ParserError(Message, _virtualPath, _line);
562                     _parserErrors.Add(thisError);
563                 }
564
565                 return _parserErrors;
566             }
567         }
568     }
569
570
571     /// <devdoc>
572     ///    <para> Exception thrown when a potentially unsafe input string is detected (ASURT 122278)</para>
573     /// </devdoc>
574     [Serializable]
575     public sealed class HttpRequestValidationException : HttpException {
576
577
578         public HttpRequestValidationException() {
579         }
580
581
582         public HttpRequestValidationException(string message) : base(message) {
583
584             SetFormatter(new UnhandledErrorFormatter(
585                 this, SR.GetString(SR.Dangerous_input_detected_descr), null));
586         }
587
588
589         public HttpRequestValidationException(String message, Exception innerException) : base(message, innerException) {
590         }
591
592         private HttpRequestValidationException(SerializationInfo info, StreamingContext context)
593            :base(info, context) {
594         }
595     }
596
597     [Serializable]
598     public sealed class ParserError {
599         private int _line;
600         private VirtualPath _virtualPath;
601         private string _errorText;
602         private Exception _exception;
603
604         public ParserError() {
605         }
606
607         public ParserError(string errorText, string virtualPath, int line)
608             : this(errorText, System.Web.VirtualPath.CreateAllowNull(virtualPath), line) { 
609         }
610
611         internal ParserError(string errorText, VirtualPath virtualPath, int line) {
612             _virtualPath = virtualPath;
613             _line = line;
614             _errorText = errorText;
615         }
616
617         // The original exception that introduces the Parser Error
618         internal Exception Exception {
619             get { return _exception; }
620             set { _exception = value; }
621         }
622
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); }
627         }
628
629         // The description error text of the error.
630         public string ErrorText {
631             get { return _errorText; }
632             set { _errorText = value; }
633         }
634
635         // The line where the parser error occurs.
636         public int Line {
637             get { return _line; }
638             set { _line = value; }
639         }
640     }
641
642     [Serializable]
643     public sealed class ParserErrorCollection : CollectionBase {
644         public ParserErrorCollection() {
645         }
646
647         public ParserErrorCollection(ParserError[] value) {
648             this.AddRange(value);
649         }
650
651         public ParserError this[int index] {
652             get { return ((ParserError)List[index]); }
653             set { List[index] = value; }
654         }
655
656         public int Add(ParserError value) {
657             return List.Add(value);
658         }
659
660         public void AddRange(ParserError[] value) {
661             if (value == null) {
662                 throw new ArgumentNullException("value");
663             }
664
665             for (int i = 0; i < value.Length; i++) {
666                 this.Add(value[i]);
667             }
668         }
669
670         public void AddRange(ParserErrorCollection value) {
671             if (value == null) {
672                 throw new ArgumentNullException("value");
673             }
674
675             foreach(ParserError parserError in value) {
676                 this.Add(parserError);
677             }
678         }
679
680         public bool Contains(ParserError value) {
681             return List.Contains(value);
682         }
683
684         public void CopyTo(ParserError[] array, int index) {
685             List.CopyTo(array, index);
686         }
687
688         public int IndexOf(ParserError value) {
689             return List.IndexOf(value);
690         }
691
692         public void Insert(int index, ParserError value) {
693             List.Insert(index, value);
694         }
695
696         public void Remove(ParserError value) {
697             List.Remove(value);
698         }
699     }
700 }