2005-11-02 Gonzalo Paniagua Javier <gonzalo@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 //
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.Web.Profile;
46 #endif
47
48 namespace System.Web {
49         
50         // CAS - no InheritanceDemand here as the class is sealed
51         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
52         public sealed class HttpContext : IServiceProvider {
53                 internal HttpWorkerRequest WorkerRequest;
54                 HttpApplication app_instance;
55                 HttpRequest request;
56                 HttpResponse response;
57                 HttpSessionState session_state;
58                 HttpServerUtility server;
59                 TraceContext trace_context;
60                 IHttpHandler handler;
61                 string error_page;
62                 bool skip_authorization = false;
63                 IPrincipal user;
64                 object errors;
65                 Hashtable items;
66                 object config_timeout;
67                 int timeout_possible;
68                 DateTime time_stamp = DateTime.UtcNow;
69 #if TARGET_JVM // No remoting support (CallContext) yet in Grasshopper
70                 static LocalDataStoreSlot _ContextSlot = Thread.GetNamedDataSlot ("Context");
71 #endif
72                 
73                 public HttpContext (HttpWorkerRequest wr)
74                 {
75                         WorkerRequest = wr;
76                         request = new HttpRequest (WorkerRequest, this);
77                         response = new HttpResponse (WorkerRequest, this);
78                 }
79
80                 public HttpContext (HttpRequest request, HttpResponse response)
81                 {
82                         this.request = request;
83                         this.response = response;
84                         
85                 }
86
87                 public Exception [] AllErrors {
88                         get {
89                                 if (errors == null)
90                                         return null;
91
92                                 if (errors is Exception){
93                                         Exception [] all = new Exception [1];
94                                         all [0] = (Exception) errors;
95                                         return all;
96                                 } 
97                                 return (Exception []) (((ArrayList) errors).ToArray (typeof (Exception)));
98                         }
99                 }
100
101                 public HttpApplicationState Application {
102                         get {
103                                 return HttpApplicationFactory.ApplicationState;
104                         }
105                 }
106
107                 public HttpApplication ApplicationInstance {
108                         get {
109                                 return app_instance;
110                         }
111
112                         set {
113                                 app_instance = value;
114                         }
115                               
116                 }
117
118                 public Cache Cache {
119                         get {
120                                 return HttpRuntime.Cache;
121                         }
122                 }
123
124                 //
125                 // The "Current" property is set just after we have constructed it with 
126                 // the 'HttpContext (HttpWorkerRequest)' constructor.
127                 //
128 #if TARGET_JVM // No remoting support (CallContext) yet in Grasshopper
129                 [MonoTODO("Context - Use System.Remoting.Messaging.CallContext instead of Thread storage")]
130                 public static HttpContext Current
131                 {
132                         get { return (HttpContext) Thread.GetData (_ContextSlot); }
133                         set { Thread.SetData (_ContextSlot, value); }
134                 }
135 #else
136                 public static HttpContext Current {
137                         get {
138                                 return (HttpContext) CallContext.GetData ("c");
139                         }
140
141                         set {
142                                 CallContext.SetData ("c", value);
143                         }
144                 }
145 #endif
146
147                 public Exception Error {
148                         get {
149                                 if (errors == null || (errors is Exception))
150                                         return (Exception) errors;
151                                 return (Exception) (((ArrayList) errors) [0]);
152                         }
153                 }
154
155                 public IHttpHandler Handler {
156                         get {
157                                 return handler;
158                         }
159
160                         set {
161                                 handler = value;
162                         }
163                 }
164
165                 public bool IsCustomErrorEnabled {
166                         get {
167                                 CustomErrorsConfig cfg = null;
168                                 try {
169                                         cfg = (CustomErrorsConfig) GetConfig ("system.web/customErrors");
170                                 } catch {
171                                 }
172                                 if (cfg == null)
173                                         return false;
174
175                                 if (cfg.Mode == CustomErrorMode.On)
176                                         return true;
177
178                                 return (cfg.Mode == CustomErrorMode.RemoteOnly) &&
179                                         (Request.WorkerRequest.GetLocalAddress () != Request.UserHostAddress);
180                         }
181                 }
182 #if TARGET_JVM
183                 public bool IsDebuggingEnabled { get { return false; } }
184 #else
185                 public bool IsDebuggingEnabled {
186                         get {
187                                 try {
188                                         return CompilationConfiguration.GetInstance (this).Debug;
189                                 } catch {
190                                         return false;
191                                 }
192                         }
193                 }
194 #endif
195                 public IDictionary Items {
196                         get {
197                                 if (items == null)
198                                         items = new Hashtable ();
199                                 return items;
200                         }
201                 }
202
203                 public HttpRequest Request {
204                         get {
205                                 return request;
206                         }
207                 }
208
209                 public HttpResponse Response {
210                         get {
211                                 return response;
212                         }
213                 }
214
215                 public HttpServerUtility Server {
216                         get {
217                                 if (server == null)
218                                         server = new HttpServerUtility (this);
219                                 return server;
220                         }
221                 }
222
223                 public HttpSessionState Session {
224                         get {
225                                 return session_state;
226                         }
227                 }
228
229                 public bool SkipAuthorization {
230                         get {
231                                 return skip_authorization;
232                         }
233
234                         [SecurityPermission (SecurityAction.Demand, ControlPrincipal = true)]
235                         set {
236                                 skip_authorization = value;
237                         }
238                 }
239
240                 public DateTime Timestamp {
241                         get {
242                                 return time_stamp.ToLocalTime ();
243                         }
244                 }
245                 
246                 public TraceContext Trace {
247                         get {
248                                 if (trace_context == null)
249                                         trace_context = new TraceContext (this);
250                                 return trace_context;
251                         }
252                 }
253
254                 public IPrincipal User {
255                         get {
256                                 return user;
257                         }
258
259                         [SecurityPermission (SecurityAction.Demand, ControlPrincipal = true)]
260                         set {
261                                 user = value;
262                         }
263                 }
264
265 #if NET_2_0
266                 [MonoTODO]
267                 public IHttpHandler CurrentHandler {
268                         get { throw new NotImplementedException (); }
269                 }
270
271                 [MonoTODO]
272                 public IHttpHandler PreviousHandler {
273                         get { throw new NotImplementedException (); }
274                 }
275
276         #if false
277                 [MonoTODO]
278                 public ProfileBase Profile {
279                         get { throw new NotImplementedException (); }
280                 }
281         #endif
282 #endif
283
284                 public void AddError (Exception errorInfo)
285                 {
286                         if (errors == null){
287                                 errors = errorInfo;
288                                 return;
289                         }
290                         ArrayList l;
291                         if (errors is Exception){
292                                 l = new ArrayList ();
293                                 l.Add (errors);
294                                 errors = l;
295                         } else 
296                                 l = (ArrayList) errors;
297                         l.Add (errorInfo);
298                 }
299
300                 internal void ClearError (Exception e)
301                 {
302                         if (errors == e)
303                                 errors = null;
304                 }
305
306                 public void ClearError ()
307                 {
308                         errors = null;
309                 }
310
311 #if NET_2_0
312                 [Obsolete ("see WebConfigurationManager")]
313 #endif
314                 public static object GetAppConfig (string name)
315                 {
316                         object o = ConfigurationSettings.GetConfig (name);
317
318                         return o;
319                 }
320
321 #if NET_2_0
322                 [Obsolete ("see GetSection")]
323 #endif
324                 public object GetConfig (string name)
325                 {
326                         return WebConfigurationSettings.GetConfig (name, this);
327                 }
328
329 #if NET_2_0
330                 [MonoTODO]
331                 public static object GetGlobalResourceObject (string classKey, string resourceKey)
332                 {
333                         throw new NotImplementedException ();
334                 }
335
336                 [MonoTODO]
337                 public static object GetGlobalResourceObject (string classKey, string resourceKey, CultureInfo culture)
338                 {
339                         throw new NotImplementedException ();
340                 }
341
342                 [MonoTODO]
343                 public static object GetLocalResourceObject (string virtualPath, string resourceKey)
344                 {
345                         throw new NotImplementedException ();
346                 }
347
348                 [MonoTODO]
349                 public static object GetLocalResourceObject (string virtualPath, string resourceKey, CultureInfo culture)
350                 {
351                         throw new NotImplementedException ();
352                 }
353
354                 [MonoTODO]
355                 public object GetSection (string name)
356                 {
357                         throw new NotImplementedException ();
358                 }
359 #endif
360                 object IServiceProvider.GetService (Type service)
361                 {
362                         if (service == typeof (HttpWorkerRequest))
363                                 return WorkerRequest;
364
365                         //
366                         // We return everything out of properties in case
367                         // they are dynamically computed in some form in the future.
368                         //
369                         if (service == typeof (HttpApplication))
370                                 return ApplicationInstance;
371
372                         if (service == typeof (HttpRequest))
373                                 return Request;
374
375                         if (service == typeof (HttpResponse))
376                                 return Response;
377
378                         if (service == typeof (HttpSessionState))
379                                 return Session;
380
381                         if (service == typeof (HttpApplicationState))
382                                 return Application;
383
384                         if (service == typeof (IPrincipal))
385                                 return User;
386
387                         if (service == typeof (Cache))
388                                 return Cache;
389
390                         if (service == typeof (HttpContext))
391                                 return Current;
392
393                         if (service == typeof (IHttpHandler))
394                                 return Handler;
395
396                         if (service == typeof (HttpServerUtility))
397                                 return Server;
398                         
399                         if (service == typeof (TraceContext))
400                                 return Trace;
401                         
402                         return null;
403                 }
404
405                 public void RewritePath (string path)
406                 {
407                         int qmark = path.IndexOf ('?');
408                         if (qmark != -1)
409                                 RewritePath (path.Substring (0, qmark), "", path.Substring (qmark + 1));
410                         else
411                                 RewritePath (path, null, null);
412                 }
413
414                 public void RewritePath (string filePath, string pathInfo, string queryString)
415                 {
416                         filePath = UrlUtils.Combine (Request.BaseVirtualDir, filePath);
417                         if (!filePath.StartsWith (HttpRuntime.AppDomainAppVirtualPath))
418                                 throw new HttpException (404, "The virtual path '" + filePath +
419                                         "' maps to another application.");
420
421                         Request.SetCurrentExePath (filePath);
422                         // A null pathInfo or queryString is ignored and previous values remain untouched
423                         if (pathInfo != null)
424                                 Request.SetPathInfo (pathInfo);
425
426                         if (queryString != null)
427                                 Request.QueryStringRaw = queryString;
428                 }
429
430 #if NET_2_0
431                 [MonoTODO]
432                 public void RewritePath (string path, bool rebaseClientPath)
433                 {
434                         throw new NotImplementedException ();
435                 }
436 #endif
437
438 #region internals
439                 
440                 internal void SetSession (HttpSessionState state)
441                 {
442                         session_state = state;
443                 }
444
445                 // URL of a page used for error redirection.
446                 internal string ErrorPage {
447                         get {
448                                 return error_page;
449                         }
450
451                         set {
452                                 error_page = value;
453                         }
454                 }
455
456                 internal TimeSpan ConfigTimeout {
457                         get {
458                                 if (config_timeout == null) {
459                                         HttpRuntimeConfig config = (HttpRuntimeConfig)
460                                                                 GetConfig ("system.web/httpRuntime");
461                                         config_timeout = new TimeSpan (0, 0, config.ExecutionTimeout);
462                                 }
463
464                                 return (TimeSpan) config_timeout;
465                         }
466
467                         set {
468                                 config_timeout = value;
469                         }
470                 }
471
472                 internal bool CheckIfTimeout (DateTime t)
473                 {
474                         if (Interlocked.CompareExchange (ref timeout_possible, 0, 0) == 0)
475                                 return false;
476
477                         TimeSpan ts = t - time_stamp;
478                         return (ts > ConfigTimeout);
479                 }
480
481                 internal bool TimeoutPossible {
482                         get { return (Interlocked.CompareExchange (ref timeout_possible, 1, 1) == 1); }
483                 }
484
485                 internal void BeginTimeoutPossible ()
486                 {
487                         timeout_possible = 1;
488                 }
489
490                 internal void EndTimeoutPossible ()
491                 {
492                         Interlocked.CompareExchange (ref timeout_possible, 0, 1);
493                 }
494 #endregion
495
496 #if NET_2_0
497                 Page last_page;
498                 
499                 internal Page LastPage {
500                         get {
501                                 return last_page;
502                         }
503
504                         set {
505                                 last_page = value;
506                         }
507                 }
508 #endif
509         }
510 }