2007-08-23 Marek Habersack <mhabersack@novell.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 //
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 #if NET_2_0
45 using System.Collections.Generic;
46 using System.IO;
47 using System.Reflection;
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         
56         // CAS - no InheritanceDemand here as the class is sealed
57         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
58         public sealed partial class HttpContext : IServiceProvider {
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 #if NET_2_0
76 #if TARGET_JVM
77                 const string app_global_res_key = "HttpContext.app_global_res_key";
78                 internal static Assembly AppGlobalResourcesAssembly {
79                         get { return (Assembly) AppDomain.CurrentDomain.GetData (app_global_res_key); }
80                         set { AppDomain.CurrentDomain.SetData (app_global_res_key, value); }
81                 }
82 #else
83                 internal static Assembly AppGlobalResourcesAssembly;
84 #endif
85                 ProfileBase profile = null;
86                 LinkedList<IHttpHandler> handlers;
87 #endif
88
89                 public HttpContext (HttpWorkerRequest wr)
90                 {
91                         WorkerRequest = wr;
92                         request = new HttpRequest (WorkerRequest, this);
93                         response = new HttpResponse (WorkerRequest, this);
94                 }
95
96                 public HttpContext (HttpRequest request, HttpResponse response)
97                 {
98                         this.request = request;
99                         this.response = response;
100                         
101                 }
102
103                 public Exception [] AllErrors {
104                         get {
105                                 if (errors == null)
106                                         return null;
107
108                                 if (errors is Exception){
109                                         Exception [] all = new Exception [1];
110                                         all [0] = (Exception) errors;
111                                         return all;
112                                 } 
113                                 return (Exception []) (((ArrayList) errors).ToArray (typeof (Exception)));
114                         }
115                 }
116
117                 public HttpApplicationState Application {
118                         get {
119                                 return HttpApplicationFactory.ApplicationState;
120                         }
121                 }
122
123                 public HttpApplication ApplicationInstance {
124                         get {
125                                 return app_instance;
126                         }
127
128                         set {
129                                 app_instance = value;
130                         }
131                               
132                 }
133
134                 public Cache Cache {
135                         get {
136                                 return HttpRuntime.Cache;
137                         }
138                 }
139
140                 internal Cache InternalCache {
141                         get {
142                                 return HttpRuntime.InternalCache;
143                         }
144                 }
145                 
146                 //
147                 // The "Current" property is set just after we have constructed it with 
148                 // the 'HttpContext (HttpWorkerRequest)' constructor.
149                 //
150 #if !TARGET_JVM // No remoting CallContext support in Grasshopper
151                 public static HttpContext Current {
152                         get {
153                                 return (HttpContext) CallContext.GetData ("c");
154                         }
155
156                         set {
157                                 CallContext.SetData ("c", value);
158                         }
159                 }
160 #endif
161
162                 public Exception Error {
163                         get {
164                                 if (errors == null || (errors is Exception))
165                                         return (Exception) errors;
166                                 return (Exception) (((ArrayList) errors) [0]);
167                         }
168                 }
169
170                 public IHttpHandler Handler {
171                         get {
172                                 return handler;
173                         }
174
175                         set {
176                                 handler = value;
177                         }
178                 }
179
180                 public bool IsCustomErrorEnabled {
181                         get {
182                                 try {
183                                         return IsCustomErrorEnabledUnsafe;
184                                 }
185                                 catch {
186                                         return false;
187                                 }
188                         }
189                 }
190
191                 internal bool IsCustomErrorEnabledUnsafe {
192                         get {
193 #if NET_2_0
194                                 CustomErrorsSection cfg = (CustomErrorsSection) WebConfigurationManager.GetSection ("system.web/customErrors");
195 #else
196                                 CustomErrorsConfig cfg = null;
197                                 try {
198                                         cfg = (CustomErrorsConfig) GetConfig ("system.web/customErrors");
199                                 } catch {
200                                 }
201
202                                 if (cfg == null)
203                                         return false;
204 #endif
205
206                                 if (cfg.Mode == CustomErrorMode.On)
207                                         return true;
208
209                                 return (cfg.Mode == CustomErrorMode.RemoteOnly) && !Request.IsLocal;
210                         }
211                 }
212 #if !TARGET_JVM
213                 public bool IsDebuggingEnabled {
214                         get {
215 #if NET_2_0
216                                 CompilationSection section = (CompilationSection) WebConfigurationManager.GetSection ("system.web/compilation");
217                                 return section.Debug;
218 #else
219                                 try {
220                                         return CompilationConfiguration.GetInstance (this).Debug;
221                                 } catch {
222                                         return false;
223                                 }
224 #endif
225                         }
226                 }
227 #endif
228                 public IDictionary Items {
229                         get {
230                                 if (items == null)
231                                         items = new Hashtable ();
232                                 return items;
233                         }
234                 }
235
236                 public HttpRequest Request {
237                         get {
238                                 return request;
239                         }
240                 }
241
242                 public HttpResponse Response {
243                         get {
244                                 return response;
245                         }
246                 }
247
248                 public HttpServerUtility Server {
249                         get {
250                                 if (server == null)
251                                         server = new HttpServerUtility (this);
252                                 return server;
253                         }
254                 }
255
256                 public HttpSessionState Session {
257                         get {
258                                 return session_state;
259                         }
260                 }
261
262                 public bool SkipAuthorization {
263                         get {
264                                 return skip_authorization;
265                         }
266
267                         [SecurityPermission (SecurityAction.Demand, ControlPrincipal = true)]
268                         set {
269                                 skip_authorization = value;
270                         }
271                 }
272
273                 public DateTime Timestamp {
274                         get {
275                                 return time_stamp.ToLocalTime ();
276                         }
277                 }
278                 
279                 public TraceContext Trace {
280                         get {
281                                 if (trace_context == null)
282                                         trace_context = new TraceContext (this);
283                                 return trace_context;
284                         }
285                 }
286
287                 public IPrincipal User {
288                         get {
289                                 return user;
290                         }
291
292                         [SecurityPermission (SecurityAction.Demand, ControlPrincipal = true)]
293                         set {
294                                 user = value;
295                         }
296                 }
297
298 #if NET_2_0             
299                 internal void PushHandler (IHttpHandler handler)
300                 {
301                         if (handler == null)
302                                 return;
303                         if (handlers == null)
304                                 handlers = new LinkedList <IHttpHandler> ();
305                         handlers.AddLast (handler);
306                 }
307
308                 internal void PopHandler ()
309                 {
310                         if (handlers == null || handlers.Count == 0)
311                                 return;
312                         handlers.RemoveLast ();
313                 }
314                 
315                 IHttpHandler GetCurrentHandler ()
316                 {
317                         if (handlers == null || handlers.Count == 0)
318                                 return null;
319                         
320                         return handlers.Last.Value;
321                 }
322
323                 IHttpHandler GetPreviousHandler ()
324                 {
325                         if (handlers == null || handlers.Count <= 1)
326                                 return null;
327                         LinkedListNode <IHttpHandler> previous = handlers.Last.Previous;
328                         if (previous != null)
329                                 return previous.Value;
330                         return null;
331                 }
332                 
333                 public IHttpHandler CurrentHandler {
334                         get { return GetCurrentHandler (); }
335                 }
336
337                 public IHttpHandler PreviousHandler {
338                         get { return GetPreviousHandler (); }
339                 }
340
341                 internal bool ProfileInitialized {
342                         get { return profile != null; }
343                 }
344
345                 public ProfileBase Profile {
346                         get {
347                                 if (profile == null) {
348                                         if (Request.IsAuthenticated)
349                                                 profile = ProfileBase.Create (User.Identity.Name);
350                                         else
351                                                 profile = ProfileBase.Create (Request.AnonymousID, false);
352                                 }
353                                 return profile;
354                         }
355
356                         internal set {
357                                 profile = value;
358                         }
359                 }
360 #endif
361
362                 public void AddError (Exception errorInfo)
363                 {
364                         if (errors == null){
365                                 errors = errorInfo;
366                                 return;
367                         }
368                         ArrayList l;
369                         if (errors is Exception){
370                                 l = new ArrayList ();
371                                 l.Add (errors);
372                                 errors = l;
373                         } else 
374                                 l = (ArrayList) errors;
375                         l.Add (errorInfo);
376                 }
377
378                 internal void ClearError (Exception e)
379                 {
380                         if (errors == e)
381                                 errors = null;
382                 }
383
384                 public void ClearError ()
385                 {
386                         errors = null;
387                 }
388
389 #if NET_2_0
390                 [Obsolete ("use WebConfigurationManager.GetWebApplicationSection")]
391 #endif
392                 public static object GetAppConfig (string name)
393                 {
394                         object o = ConfigurationSettings.GetConfig (name);
395
396                         return o;
397                 }
398
399 #if NET_2_0
400                 [Obsolete ("see GetSection")]
401 #endif
402                 public object GetConfig (string name)
403                 {
404 #if NET_2_0
405                         return GetSection (name);
406 #else
407                         return WebConfigurationSettings.GetConfig (name, this);
408 #endif
409                 }
410
411 #if NET_2_0
412                 static object GetResourceObject (string classKey, string resourceKey, CultureInfo culture, Assembly assembly)
413                 {
414                         ResourceManager rm;
415                         try {
416                                 rm = new ResourceManager (classKey, assembly);
417                                 rm.IgnoreCase = true;
418                                 return rm.GetObject (resourceKey, culture);
419                         } catch (MissingManifestResourceException) {
420                                 throw;
421                         } catch (Exception ex) {
422                                 throw new HttpException ("Failed to retrieve the specified global resource object.", ex);
423                         }
424                 }
425                 
426                 public static object GetGlobalResourceObject (string classKey, string resourceKey)
427                 {
428                         return GetGlobalResourceObject (classKey, resourceKey, Thread.CurrentThread.CurrentUICulture);
429                 }
430
431                 public static object GetGlobalResourceObject (string classKey, string resourceKey, CultureInfo culture)
432                 {
433                         if (AppGlobalResourcesAssembly == null)
434                                 throw new MissingManifestResourceException ();
435                         return GetResourceObject ("Resources." + classKey, resourceKey, culture, AppGlobalResourcesAssembly);
436                 }
437
438                 public static object GetLocalResourceObject (string virtualPath, string resourceKey)
439                 {
440                         return GetLocalResourceObject (virtualPath, resourceKey, Thread.CurrentThread.CurrentUICulture);
441                 }
442
443                 public static object GetLocalResourceObject (string virtualPath, string resourceKey, CultureInfo culture)
444                 {
445                         if (!VirtualPathUtility.IsAbsolute (virtualPath))
446                                 throw new ArgumentException ("The specified virtualPath was not rooted.");
447                         
448                         string path = Path.GetDirectoryName (virtualPath);
449                         Assembly asm = AppResourcesCompiler.GetCachedLocalResourcesAssembly (path);
450                         if (asm == null) {
451                                 AppResourcesCompiler ac = new AppResourcesCompiler (path);
452                                 asm = ac.Compile ();
453                                 if (asm == null)
454                                         throw new MissingManifestResourceException ("A resource object was not found at the specified virtualPath.");
455                         }
456                         
457                         path = Path.GetFileName (virtualPath);
458                         return GetResourceObject (path, resourceKey, culture, asm);
459                 }
460
461                 public object GetSection (string name)
462                 {
463                         return WebConfigurationManager.GetSection (name);
464                 }
465 #endif
466                 object IServiceProvider.GetService (Type service)
467                 {
468                         if (service == typeof (HttpWorkerRequest))
469                                 return WorkerRequest;
470
471                         //
472                         // We return everything out of properties in case
473                         // they are dynamically computed in some form in the future.
474                         //
475                         if (service == typeof (HttpApplication))
476                                 return ApplicationInstance;
477
478                         if (service == typeof (HttpRequest))
479                                 return Request;
480
481                         if (service == typeof (HttpResponse))
482                                 return Response;
483
484                         if (service == typeof (HttpSessionState))
485                                 return Session;
486
487                         if (service == typeof (HttpApplicationState))
488                                 return Application;
489
490                         if (service == typeof (IPrincipal))
491                                 return User;
492
493                         if (service == typeof (Cache))
494                                 return Cache;
495
496                         if (service == typeof (HttpContext))
497                                 return Current;
498
499                         if (service == typeof (IHttpHandler))
500                                 return Handler;
501
502                         if (service == typeof (HttpServerUtility))
503                                 return Server;
504                         
505                         if (service == typeof (TraceContext))
506                                 return Trace;
507                         
508                         return null;
509                 }
510
511                 public void RewritePath (string path)
512                 {
513 #if NET_2_0
514                         RewritePath (path, true);
515 #else
516                         RewritePath (path, false);
517 #endif
518                 }
519
520                 public void RewritePath (string filePath, string pathInfo, string queryString)
521                 {
522                         RewritePath (filePath, pathInfo, queryString, false);
523                 }
524
525 #if NET_2_0
526                 public
527 #else
528                 internal
529 #endif
530                 void RewritePath (string path, bool rebaseClientPath)
531                 {
532                         int qmark = path.IndexOf ('?');
533                         if (qmark != -1)
534                                 RewritePath (path.Substring (0, qmark), "", path.Substring (qmark + 1), rebaseClientPath);
535                         else
536                                 RewritePath (path, null, null, rebaseClientPath);
537                 }
538
539 #if NET_2_0
540                 public
541 #else
542                 internal
543 #endif
544                 void RewritePath (string filePath, string pathInfo, string queryString, bool setClientFilePath)
545                 {
546                         filePath = UrlUtils.Combine (Request.BaseVirtualDir, filePath);
547                         if (!StrUtils.StartsWith (filePath, HttpRuntime.AppDomainAppVirtualPath))
548                                 throw new HttpException (404, "The virtual path '" + filePath +
549                                         "' maps to another application.");
550
551                         Request.SetCurrentExePath (filePath);
552                         // A null pathInfo or queryString is ignored and previous values remain untouched
553                         if (pathInfo != null)
554                                 Request.SetPathInfo (pathInfo);
555
556                         if (queryString != null)
557                                 Request.QueryStringRaw = queryString;
558 #if NET_2_0
559                         if (setClientFilePath)
560                                 Request.SetFilePath (filePath);
561 #endif
562                 }
563
564 #region internals
565                 
566                 internal void SetSession (HttpSessionState state)
567                 {
568                         session_state = state;
569                 }
570
571                 // URL of a page used for error redirection.
572                 internal string ErrorPage {
573                         get {
574                                 return error_page;
575                         }
576
577                         set {
578                                 error_page = value;
579                         }
580                 }
581
582                 internal TimeSpan ConfigTimeout {
583                         get {
584                                 if (config_timeout == null) {
585 #if NET_2_0
586                                         HttpRuntimeSection section = (HttpRuntimeSection)WebConfigurationManager.GetSection ("system.web/httpRuntime");
587                                         config_timeout = section.ExecutionTimeout;
588 #else
589                                         HttpRuntimeConfig config = (HttpRuntimeConfig)
590                                                                 GetConfig ("system.web/httpRuntime");
591                                         config_timeout = new TimeSpan (0, 0, config.ExecutionTimeout);
592 #endif
593                                 }
594
595                                 return (TimeSpan) config_timeout;
596                         }
597
598                         set {
599                                 config_timeout = value;
600                         }
601                 }
602
603 #if !TARGET_J2EE
604                 internal bool CheckIfTimeout (DateTime t)
605                 {
606                         if (Interlocked.CompareExchange (ref timeout_possible, 0, 0) == 0)
607                                 return false;
608
609                         TimeSpan ts = t - time_stamp;
610                         return (ts > ConfigTimeout);
611                 }
612
613                 internal bool TimeoutPossible {
614                         get { return (Interlocked.CompareExchange (ref timeout_possible, 1, 1) == 1); }
615                 }
616
617                 internal void BeginTimeoutPossible ()
618                 {
619                         timeout_possible = 1;
620                 }
621
622                 internal void EndTimeoutPossible ()
623                 {
624                         Interlocked.CompareExchange (ref timeout_possible, 0, 1);
625                 }
626 #endif
627 #endregion
628
629 #if NET_2_0
630                 Page last_page;
631                 
632                 internal Page LastPage {
633                         get {
634                                 return last_page;
635                         }
636
637                         set {
638                                 last_page = value;
639                         }
640                 }
641 #endif
642         }
643 }