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