undo. Proper fix was in BuildManager
[mono.git] / mcs / class / System.Web / System.Web / HttpContext.cs
1 //
2 // System.Web.HttpContext.cs 
3 //
4 // Author:
5 //      Miguel de Icaza (miguel@novell.com)
6 //      Gonzalo Paniagua Javier (gonzalo@novell.com)
7 //
8
9 //
10 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
11 //
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:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
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.
30 //
31
32 using System.Collections;
33 using System.Configuration;
34 using System.Globalization;
35 using System.Runtime.Remoting.Messaging;
36 using System.Security.Permissions;
37 using System.Security.Principal;
38 using System.Threading;
39 using System.Web.Caching;
40 using System.Web.Configuration;
41 using System.Web.SessionState;
42 using System.Web.UI;
43 using System.Web.Util;
44 using System.Reflection;
45 #if NET_2_0
46 using System.Collections.Generic;
47 using System.IO;
48 using System.Resources;
49 using System.Web.Compilation;
50 using System.Web.Profile;
51 using CustomErrorMode = System.Web.Configuration.CustomErrorsMode;
52 #endif
53
54 namespace System.Web {
55         // CAS - no InheritanceDemand here as the class is sealed
56         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
57         public sealed partial class HttpContext : IServiceProvider {
58                 internal HttpWorkerRequest WorkerRequest;
59                 HttpApplication app_instance;
60                 HttpRequest request;
61                 HttpResponse response;
62                 HttpSessionState session_state;
63                 HttpServerUtility server;
64                 TraceContext trace_context;
65                 IHttpHandler handler;
66                 string error_page;
67                 bool skip_authorization = false;
68                 IPrincipal user;
69                 object errors;
70                 Hashtable items;
71                 object config_timeout;
72                 int timeout_possible;
73                 DateTime time_stamp = DateTime.UtcNow;
74                 Timer timer;
75                 Thread thread;
76                 bool _isProcessingInclude;
77
78 #if NET_2_0
79                 [ThreadStatic]
80                 static ResourceProviderFactory provider_factory;
81
82                 [ThreadStatic]
83                 static DefaultResourceProviderFactory default_provider_factory;
84                 
85                 [ThreadStatic]
86                 static Dictionary <string, IResourceProvider> resource_providers;
87                 
88 #if TARGET_JVM
89                 const string app_global_res_key = "HttpContext.app_global_res_key";
90                 internal static Assembly AppGlobalResourcesAssembly {
91                         get { return (Assembly) AppDomain.CurrentDomain.GetData (app_global_res_key); }
92                         set { AppDomain.CurrentDomain.SetData (app_global_res_key, value); }
93                 }
94 #else
95                 internal static Assembly AppGlobalResourcesAssembly;
96 #endif
97                 ProfileBase profile = null;
98                 LinkedList<IHttpHandler> handlers;
99
100                 static DefaultResourceProviderFactory DefaultProviderFactory {
101                         get {
102                                 if (default_provider_factory == null)
103                                         default_provider_factory = new DefaultResourceProviderFactory ();
104                                 return default_provider_factory;
105                         }
106                 }
107 #endif
108                 
109                 public HttpContext (HttpWorkerRequest wr)
110                 {
111                         WorkerRequest = wr;
112                         request = new HttpRequest (WorkerRequest, this);
113                         response = new HttpResponse (WorkerRequest, this);
114                 }
115
116                 public HttpContext (HttpRequest request, HttpResponse response)
117                 {
118                         this.request = request;
119                         this.response = response;
120                         
121                 }
122
123                 internal bool IsProcessingInclude {
124                         get { return _isProcessingInclude; }
125                         set { _isProcessingInclude = value; }
126                 }
127
128                 public Exception [] AllErrors {
129                         get {
130                                 if (errors == null)
131                                         return null;
132
133                                 if (errors is Exception){
134                                         Exception [] all = new Exception [1];
135                                         all [0] = (Exception) errors;
136                                         return all;
137                                 } 
138                                 return (Exception []) (((ArrayList) errors).ToArray (typeof (Exception)));
139                         }
140                 }
141
142                 public HttpApplicationState Application {
143                         get {
144                                 return HttpApplicationFactory.ApplicationState;
145                         }
146                 }
147
148                 public HttpApplication ApplicationInstance {
149                         get {
150                                 return app_instance;
151                         }
152
153                         set {
154                                 app_instance = value;
155                         }
156                               
157                 }
158
159                 public Cache Cache {
160                         get {
161                                 return HttpRuntime.Cache;
162                         }
163                 }
164
165                 internal Cache InternalCache {
166                         get {
167                                 return HttpRuntime.InternalCache;
168                         }
169                 }
170                 
171                 //
172                 // The "Current" property is set just after we have constructed it with 
173                 // the 'HttpContext (HttpWorkerRequest)' constructor.
174                 //
175 #if !TARGET_JVM // No remoting CallContext support in Grasshopper
176                 public static HttpContext Current {
177                         get {
178                                 return (HttpContext) CallContext.GetData ("c");
179                         }
180
181                         set {
182                                 CallContext.SetData ("c", value);
183                         }
184                 }
185 #endif
186
187                 public Exception Error {
188                         get {
189                                 if (errors == null || (errors is Exception))
190                                         return (Exception) errors;
191                                 return (Exception) (((ArrayList) errors) [0]);
192                         }
193                 }
194
195                 public IHttpHandler Handler {
196                         get {
197                                 return handler;
198                         }
199
200                         set {
201                                 handler = value;
202                         }
203                 }
204
205                 public bool IsCustomErrorEnabled {
206                         get {
207                                 try {
208                                         return IsCustomErrorEnabledUnsafe;
209                                 }
210                                 catch {
211                                         return false;
212                                 }
213                         }
214                 }
215
216                 internal bool IsCustomErrorEnabledUnsafe {
217                         get {
218 #if NET_2_0
219                                 CustomErrorsSection cfg = (CustomErrorsSection) WebConfigurationManager.GetSection ("system.web/customErrors");
220 #else
221                                 CustomErrorsConfig cfg = null;
222                                 try {
223                                         cfg = (CustomErrorsConfig) GetConfig ("system.web/customErrors");
224                                 } catch {
225                                 }
226
227                                 if (cfg == null)
228                                         return false;
229 #endif
230
231                                 if (cfg.Mode == CustomErrorMode.On)
232                                         return true;
233
234                                 return (cfg.Mode == CustomErrorMode.RemoteOnly) && !Request.IsLocal;
235                         }
236                 }
237 #if !TARGET_JVM
238                 public bool IsDebuggingEnabled {
239                         get { return HttpRuntime.IsDebuggingEnabled; }
240                 }
241 #endif
242                 public IDictionary Items {
243                         get {
244                                 if (items == null)
245                                         items = new Hashtable ();
246                                 return items;
247                         }
248                 }
249
250                 public HttpRequest Request {
251                         get {
252                                 return request;
253                         }
254                 }
255
256                 public HttpResponse Response {
257                         get {
258                                 return response;
259                         }
260                 }
261
262                 public HttpServerUtility Server {
263                         get {
264                                 if (server == null)
265                                         server = new HttpServerUtility (this);
266                                 return server;
267                         }
268                 }
269
270                 public HttpSessionState Session {
271                         get {
272                                 return session_state;
273                         }
274                 }
275
276                 public bool SkipAuthorization {
277                         get {
278                                 return skip_authorization;
279                         }
280
281                         [SecurityPermission (SecurityAction.Demand, ControlPrincipal = true)]
282                         set {
283                                 skip_authorization = value;
284                         }
285                 }
286
287                 public DateTime Timestamp {
288                         get {
289                                 return time_stamp.ToLocalTime ();
290                         }
291                 }
292                 
293                 public TraceContext Trace {
294                         get {
295                                 if (trace_context == null)
296                                         trace_context = new TraceContext (this);
297                                 return trace_context;
298                         }
299                 }
300
301                 public IPrincipal User {
302                         get {
303                                 return user;
304                         }
305
306                         [SecurityPermission (SecurityAction.Demand, ControlPrincipal = true)]
307                         set {
308                                 user = value;
309                         }
310                 }
311
312 #if NET_2_0
313                 internal bool MapRequestHandlerDone {
314                         get;
315                         set;
316                 }
317                 
318                 // The two properties below are defined only when the IIS7 integrated mode is used.
319                 // They are useless under Mono
320                 public RequestNotification CurrentNotification {
321                         get { throw new PlatformNotSupportedException ("This property is not supported on Mono.");  }
322                 }
323
324                 public bool IsPostNotification {
325                         get { throw new PlatformNotSupportedException ("This property is not supported on Mono."); }
326                 }
327                 
328                 internal void PushHandler (IHttpHandler handler)
329                 {
330                         if (handler == null)
331                                 return;
332                         if (handlers == null)
333                                 handlers = new LinkedList <IHttpHandler> ();
334                         handlers.AddLast (handler);
335                 }
336
337                 internal void PopHandler ()
338                 {
339                         if (handlers == null || handlers.Count == 0)
340                                 return;
341                         handlers.RemoveLast ();
342                 }
343                 
344                 IHttpHandler GetCurrentHandler ()
345                 {
346                         if (handlers == null || handlers.Count == 0)
347                                 return null;
348                         
349                         return handlers.Last.Value;
350                 }
351
352                 IHttpHandler GetPreviousHandler ()
353                 {
354                         if (handlers == null || handlers.Count <= 1)
355                                 return null;
356                         LinkedListNode <IHttpHandler> previous = handlers.Last.Previous;
357                         if (previous != null)
358                                 return previous.Value;
359                         return null;
360                 }
361                 
362                 public IHttpHandler CurrentHandler {
363                         get { return GetCurrentHandler (); }
364                 }
365
366                 public IHttpHandler PreviousHandler {
367                         get { return GetPreviousHandler (); }
368                 }
369
370                 internal bool ProfileInitialized {
371                         get { return profile != null; }
372                 }
373
374                 public ProfileBase Profile {
375                         get {
376                                 if (profile == null) {
377                                         if (Request.IsAuthenticated)
378                                                 profile = ProfileBase.Create (User.Identity.Name);
379                                         else
380                                                 profile = ProfileBase.Create (Request.AnonymousID, false);
381                                 }
382                                 return profile;
383                         }
384
385                         internal set {
386                                 profile = value;
387                         }
388                 }
389 #endif
390
391                 public void AddError (Exception errorInfo)
392                 {
393                         if (errors == null){
394                                 errors = errorInfo;
395                                 return;
396                         }
397                         ArrayList l;
398                         if (errors is Exception){
399                                 l = new ArrayList ();
400                                 l.Add (errors);
401                                 errors = l;
402                         } else 
403                                 l = (ArrayList) errors;
404                         l.Add (errorInfo);
405                 }
406
407                 internal void ClearError (Exception e)
408                 {
409                         if (errors == e)
410                                 errors = null;
411                 }
412
413                 internal bool HasError (Exception e)
414                 {
415                         if (errors == e)
416                                 return true;
417
418                         return (errors is ArrayList) ?
419                                 ((ArrayList) errors).Contains (e) : false;
420                 }
421
422                 public void ClearError ()
423                 {
424                         errors = null;
425                 }
426
427 #if NET_2_0
428                 [Obsolete ("use WebConfigurationManager.GetWebApplicationSection")]
429 #endif
430                 public static object GetAppConfig (string name)
431                 {
432                         object o = ConfigurationSettings.GetConfig (name);
433
434                         return o;
435                 }
436
437 #if NET_2_0
438                 [Obsolete ("see GetSection")]
439 #endif
440                 public object GetConfig (string name)
441                 {
442 #if NET_2_0
443                         return GetSection (name);
444 #else
445                         return WebConfigurationSettings.GetConfig (name, this);
446 #endif
447                 }
448
449 #if NET_2_0
450                 public static object GetGlobalResourceObject (string classKey, string resourceKey)
451                 {
452                         return GetGlobalResourceObject (classKey, resourceKey, Thread.CurrentThread.CurrentUICulture);
453                 }
454
455                 static bool EnsureProviderFactory ()
456                 {
457                         if (resource_providers == null)
458                                 resource_providers = new Dictionary <string, IResourceProvider> ();
459
460                         if (provider_factory != null)
461                                 return true;
462                         
463                         GlobalizationSection gs = WebConfigurationManager.GetSection ("system.web/globalization") as GlobalizationSection;
464
465                         if (gs == null)
466                                 return false;
467
468                         String rsfTypeName = gs.ResourceProviderFactoryType;
469                         bool usingDefault = false;
470                         if (String.IsNullOrEmpty (rsfTypeName)) {
471                                 usingDefault = true;
472                                 rsfTypeName = typeof (DefaultResourceProviderFactory).AssemblyQualifiedName;
473                         }
474                         
475                         Type rsfType = HttpApplication.LoadType (rsfTypeName, true);
476                         ResourceProviderFactory rpf = Activator.CreateInstance (rsfType) as ResourceProviderFactory;
477                         
478                         if (rpf == null && usingDefault)
479                                 return false;
480
481                         provider_factory = rpf;
482                         if (usingDefault)
483                                 default_provider_factory = rpf as DefaultResourceProviderFactory;
484                         
485                         return true;
486                 }
487                 
488                 internal static IResourceProvider GetResourceProvider (string virtualPath, bool isLocal)
489                 {
490                         if (!EnsureProviderFactory ())
491                                 return null;
492
493                         // TODO: check if it makes sense to cache the providers and, if yes, maybe
494                         // we should expire the entries (or just store them in InternalCache?)
495                         IResourceProvider rp = null;
496                         if (!resource_providers.TryGetValue (virtualPath, out rp)) {
497                                 if (isLocal) {
498                                         HttpContext ctx = HttpContext.Current;
499                                         HttpRequest req = ctx != null ? ctx.Request : null;
500                                         rp = provider_factory.CreateLocalResourceProvider (virtualPath);
501                                 } else
502                                         rp = provider_factory.CreateGlobalResourceProvider (virtualPath);
503                                 
504                                 if (rp == null) {
505                                         if (isLocal) {
506                                                 HttpContext ctx = HttpContext.Current;
507                                                 HttpRequest req = ctx != null ? ctx.Request : null;
508                                                 rp = DefaultProviderFactory.CreateLocalResourceProvider (virtualPath);
509                                         } else
510                                                 rp = DefaultProviderFactory.CreateGlobalResourceProvider (virtualPath);
511
512                                         if (rp == null)
513                                                 return null;
514                                 }
515                                 
516                                 resource_providers.Add (virtualPath, rp);
517                         }
518
519                         return rp;
520                 }
521
522                 static object GetGlobalObjectFromFactory (string classKey, string resourceKey, CultureInfo culture)
523                 {
524                         // FIXME: Retention of data
525                         IResourceProvider rp = GetResourceProvider (classKey, false);
526                         if (rp == null)
527                                 return null;
528                         
529                         return rp.GetObject (resourceKey, culture);
530                 }
531                 
532                 public static object GetGlobalResourceObject (string classKey, string resourceKey, CultureInfo culture)
533                 {
534                         return GetGlobalObjectFromFactory ("Resources." + classKey, resourceKey, culture);
535                 }
536
537                 public static object GetLocalResourceObject (string virtualPath, string resourceKey)
538                 {
539                         return GetLocalResourceObject (virtualPath, resourceKey, Thread.CurrentThread.CurrentUICulture);
540                 }
541
542                 static object GetLocalObjectFromFactory (string virtualPath, string resourceKey, CultureInfo culture)
543                 {
544                         IResourceProvider rp = GetResourceProvider (virtualPath, true);
545                         if (rp == null)
546                                 return null;
547                         
548                         return rp.GetObject (resourceKey, culture);
549                 }
550                 
551                 public static object GetLocalResourceObject (string virtualPath, string resourceKey, CultureInfo culture)
552                 {
553                         if (!VirtualPathUtility.IsAbsolute (virtualPath))
554                                 throw new ArgumentException ("The specified virtualPath was not rooted.");
555
556                         return GetLocalObjectFromFactory (virtualPath, resourceKey, culture);
557                 }
558
559                 public object GetSection (string name)
560                 {
561                         return WebConfigurationManager.GetSection (name);
562                 }
563 #endif
564                 object IServiceProvider.GetService (Type service)
565                 {
566                         if (service == typeof (HttpWorkerRequest))
567                                 return WorkerRequest;
568
569                         //
570                         // We return everything out of properties in case
571                         // they are dynamically computed in some form in the future.
572                         //
573                         if (service == typeof (HttpApplication))
574                                 return ApplicationInstance;
575
576                         if (service == typeof (HttpRequest))
577                                 return Request;
578
579                         if (service == typeof (HttpResponse))
580                                 return Response;
581
582                         if (service == typeof (HttpSessionState))
583                                 return Session;
584
585                         if (service == typeof (HttpApplicationState))
586                                 return Application;
587
588                         if (service == typeof (IPrincipal))
589                                 return User;
590
591                         if (service == typeof (Cache))
592                                 return Cache;
593
594                         if (service == typeof (HttpContext))
595                                 return Current;
596
597                         if (service == typeof (IHttpHandler))
598                                 return Handler;
599
600                         if (service == typeof (HttpServerUtility))
601                                 return Server;
602                         
603                         if (service == typeof (TraceContext))
604                                 return Trace;
605                         
606                         return null;
607                 }
608
609 #if NET_2_0
610                 public void RemapHandler (IHttpHandler handler)
611                 {
612                         if (MapRequestHandlerDone)
613                                 throw new InvalidOperationException ("The RemapHandler method was called after the MapRequestHandler event occurred.");
614                         Handler = handler;
615                 }
616 #endif
617                 
618                 public void RewritePath (string path)
619                 {
620 #if NET_2_0
621                         RewritePath (path, true);
622 #else
623                         RewritePath (path, false);
624 #endif
625                 }
626
627                 public void RewritePath (string filePath, string pathInfo, string queryString)
628                 {
629                         RewritePath (filePath, pathInfo, queryString, false);
630                 }
631
632 #if NET_2_0
633                 public
634 #else
635                 internal
636 #endif
637                 void RewritePath (string path, bool rebaseClientPath)
638                 {
639                         int qmark = path.IndexOf ('?');
640                         if (qmark != -1)
641                                 RewritePath (path.Substring (0, qmark), "", path.Substring (qmark + 1), rebaseClientPath);
642                         else
643                                 RewritePath (path, null, null, rebaseClientPath);
644                 }
645
646 #if NET_2_0
647                 public
648 #else
649                 internal
650 #endif
651                 void RewritePath (string filePath, string pathInfo, string queryString, bool setClientFilePath)
652                 {
653                         if (filePath == null)
654                                 throw new ArgumentNullException ("filePath");
655                         if (!VirtualPathUtility.IsValidVirtualPath (filePath))
656                                 throw new HttpException ("'" + HttpUtility.HtmlEncode (filePath) + "' is not a valid virtual path.");
657
658                         bool pathRelative = VirtualPathUtility.IsAppRelative (filePath);
659                         bool pathAbsolute = pathRelative ? false : VirtualPathUtility.IsAbsolute (filePath);
660                         if (pathRelative || pathAbsolute) {
661                                 bool needSubstring = false;
662
663                                 if (pathRelative && filePath.Length > 1)
664                                         needSubstring = true;
665
666                                 string bvd = Request.BaseVirtualDir;
667                                 if (bvd.Length > 1)
668                                         bvd += "/";
669
670                                 string canonizedFilePath = VirtualPathUtility.Canonize (filePath);
671                                 filePath = VirtualPathUtility.Combine (bvd, needSubstring ? canonizedFilePath.Substring (2) : canonizedFilePath);
672                         } else 
673                                 filePath = VirtualPathUtility.Combine (VirtualPathUtility.GetDirectory (Request.FilePath), filePath);
674                         
675                         if (!StrUtils.StartsWith (filePath, HttpRuntime.AppDomainAppVirtualPath))
676                                 throw new HttpException (404, "The virtual path '" + HttpUtility.HtmlEncode (filePath) + "' maps to another application.", filePath);
677                         
678                         Request.SetCurrentExePath (filePath);
679                         if (setClientFilePath)
680                                 Request.SetFilePath (filePath);
681                         
682                         // A null pathInfo or queryString is ignored and previous values remain untouched
683                         if (pathInfo != null)
684                                 Request.SetPathInfo (pathInfo);
685
686                         if (queryString != null)
687                                 Request.QueryStringRaw = queryString;
688                 }
689
690 #region internals
691                 
692                 internal void SetSession (HttpSessionState state)
693                 {
694                         session_state = state;
695                 }
696
697                 // URL of a page used for error redirection.
698                 internal string ErrorPage {
699                         get {
700                                 return error_page;
701                         }
702
703                         set {
704                                 error_page = value;
705                         }
706                 }
707
708                 internal TimeSpan ConfigTimeout {
709                         get {
710                                 if (config_timeout == null) {
711 #if NET_2_0
712                                         HttpRuntimeSection section = (HttpRuntimeSection)WebConfigurationManager.GetSection ("system.web/httpRuntime");
713                                         config_timeout = section.ExecutionTimeout;
714 #else
715                                         HttpRuntimeConfig config = (HttpRuntimeConfig)
716                                                                 GetConfig ("system.web/httpRuntime");
717                                         config_timeout = new TimeSpan (0, 0, config.ExecutionTimeout);
718 #endif
719                                 }
720
721                                 return (TimeSpan) config_timeout;
722                         }
723
724                         set {
725                                 config_timeout = value;
726 #if !TARGET_J2EE
727                                 if (timer != null) {
728                                         TimeSpan remaining = value - (DateTime.UtcNow - time_stamp);
729                                         long remaining_ms = Math.Max ((long)remaining.TotalMilliseconds, 0);
730
731                                         // See http://msdn2.microsoft.com/en-us/library/7hs7492w.aspx
732                                         if (remaining_ms > 4294967294)
733                                                 remaining_ms = 4294967294;
734                                         
735                                         timer.Change (remaining_ms, (long)Timeout.Infinite);
736                                 }
737 #endif
738                         }
739                 }
740
741 #if !TARGET_J2EE
742                 void TimeoutReached(object state) {
743                         HttpRuntime.QueuePendingRequest (false);
744                         if (Interlocked.CompareExchange (ref timeout_possible, 0, 0) == 0) {
745                                 timer.Change(2000, 0);
746                                 return;                 
747                         }
748                         StopTimeoutTimer();
749                         
750                         thread.Abort (new StepTimeout ());
751                 }
752                 
753                 internal void StartTimeoutTimer() {
754                         thread = Thread.CurrentThread;
755                         timer = new Timer (TimeoutReached, null, (int)ConfigTimeout.TotalMilliseconds, Timeout.Infinite);
756                 }
757                 
758                 internal void StopTimeoutTimer() {
759                         if(timer != null) {
760                                 timer.Dispose ();
761                                 timer = null;
762                         }
763                 }
764
765                 internal bool TimeoutPossible {
766                         get { return (Interlocked.CompareExchange (ref timeout_possible, 1, 1) == 1); }
767                 }
768
769                 internal void BeginTimeoutPossible ()
770                 {
771                         timeout_possible = 1;
772                 }
773
774                 internal void EndTimeoutPossible ()
775                 {
776                         Interlocked.CompareExchange (ref timeout_possible, 0, 1);
777                 }
778 #endif
779 #endregion
780         }
781         
782         class StepTimeout
783         {
784         }
785 }