2 // System.Web.HttpRuntime
5 // Patrik Torstensson (ptorsten@hotmail.com)
6 // Gaurav Vaish (gvaish@iitk.ac.in)
9 using System.Collections;
12 using System.Security;
13 using System.Security.Permissions;
14 using System.Threading;
15 using System.Web.Configuration;
17 using System.Web.Util;
18 using System.Web.Caching;
20 namespace System.Web {
22 public sealed class HttpRuntime {
24 // Security permission helper objects
25 private static IStackWalk appPathDiscoveryStackWalk;
26 private static IStackWalk ctrlPrincipalStackWalk;
27 private static IStackWalk sensitiveInfoStackWalk;
28 private static IStackWalk unmgdCodeStackWalk;
29 private static IStackWalk unrestrictedStackWalk;
30 private static IStackWalk reflectionStackWalk;
32 private static HttpRuntime _runtime;
33 private static string appDomainAppId;
34 private static string appDomainId;
35 private static string appDomainAppPath;
36 private static string appDomainAppVirtualPath;
39 private int _activeRequests;
40 private HttpWorkerRequest.EndOfSendNotification _endOfSendCallback;
41 private AsyncCallback _handlerCallback;
42 private WaitCallback _appDomainCallback;
44 private bool _firstRequestStarted;
45 private bool _firstRequestExecuted;
46 private DateTime _firstRequestStartTime;
48 private Exception _initError;
49 private TimeoutManager timeoutManager;
50 private QueueManager queueManager;
51 private TraceManager traceManager;
52 private WaitCallback doRequestCallback;
53 private int pendingCallbacks;
57 appPathDiscoveryStackWalk = null;
58 ctrlPrincipalStackWalk = null;
59 sensitiveInfoStackWalk = null;
60 unmgdCodeStackWalk = null;
61 unrestrictedStackWalk = null;
63 _runtime = new HttpRuntime ();
69 doRequestCallback = new WaitCallback (DoRequest);
72 static internal object CreateInternalObject(Type type) {
73 return Activator.CreateInstance(type, true);
80 _cache = new Cache ();
81 timeoutManager = new TimeoutManager ();
83 // TODO: Load all app domain data
84 _endOfSendCallback = new HttpWorkerRequest.EndOfSendNotification(OnEndOfSend);
85 _handlerCallback = new AsyncCallback(OnHandlerReady);
86 _appDomainCallback = new WaitCallback(OnAppDomainUnload);
88 catch (Exception error) {
93 private void OnFirstRequestStart(HttpContext context) {
94 if (_initError != null)
98 WebConfigurationSettings.Init (context);
99 traceManager = new TraceManager (context);
100 queueManager = new QueueManager ();
101 } catch (Exception e) {
105 // If we got an error during init, throw to client now..
106 if (null != _initError)
110 private void OnFirstRequestEnd() {
113 private void OnHandlerReady(IAsyncResult ar) {
114 HttpContext context = (HttpContext) ar.AsyncState;
116 IHttpAsyncHandler handler = context.AsyncHandler;
119 handler.EndProcessRequest(ar);
121 catch (Exception error) {
122 context.AddError(error);
126 context.AsyncHandler = null;
129 FinishRequest(context, context.Error);
132 private void OnEndOfSend(HttpWorkerRequest request, object data) {
133 HttpContext context = (HttpContext) data;
135 context.Request.Dispose();
136 context.Response.Dispose();
139 internal void FinishRequest(HttpContext context, Exception error) {
142 context.Response.FlushAtEndOfRequest();
143 } catch (Exception obj) {
148 HttpWorkerRequest request = context.WorkerRequest;
150 WebTrace.WriteLine (error.ToString ());
152 context.Response.Clear ();
153 context.Response.ClearHeaders ();
155 if (!(error is HttpException)) {
156 error = new HttpException (String.Empty, error);
157 context.Response.StatusCode = 500;
159 context.Response.StatusCode = ((HttpException) error).GetHttpCode ();
162 if (!RedirectCustomError (context))
163 context.Response.Write (((HttpException) error).GetHtmlErrorMessage ());
165 context.Response.FinalFlush ();
168 if (!_firstRequestExecuted) {
170 if (!_firstRequestExecuted) {
172 _firstRequestExecuted = true;
177 Interlocked.Decrement(ref _activeRequests);
180 request.EndOfRequest();
182 TryExecuteQueuedRequests ();
185 bool RedirectCustomError (HttpContext context)
187 if (!context.IsCustomErrorEnabled)
190 CustomErrorsConfig config = null;
192 config = (CustomErrorsConfig) context.GetConfig ("system.web/customErrors");
195 if (config == null) {
196 if (context.ErrorPage != null)
197 return context.Response.RedirectCustomError (context.ErrorPage);
202 string redirect = config [context.Response.StatusCode];
203 if (redirect == null) {
204 redirect = context.ErrorPage;
205 if (redirect == null)
206 redirect = config.DefaultRedirect;
209 if (redirect == null)
212 return context.Response.RedirectCustomError (redirect);
215 internal static void FinishUnavailable (HttpWorkerRequest wr)
217 HttpContext context = new HttpContext (wr);
218 HttpException exception = new HttpException (503, "Service unavailable");
219 Interlocked.Increment (ref _runtime._activeRequests);
220 _runtime.FinishRequest (context, exception);
223 private void OnAppDomainUnload(object state) {
227 [MonoTODO ("Move timeout value to config")]
228 internal void Dispose() {
229 WaitForRequests(5000);
230 queueManager.Dispose (); // Send a 503 to all queued requests
234 HttpApplicationFactory.EndApplication();
237 internal void WaitForRequests(int ms) {
238 DateTime timeout = DateTime.Now.AddMilliseconds(ms);
241 if (Interlocked.CompareExchange (ref _activeRequests, 0, 0) == 0)
245 } while (timeout > DateTime.Now);
248 internal void InternalExecuteRequest (HttpWorkerRequest request)
250 IHttpHandler handler;
251 IHttpAsyncHandler async_handler;
253 HttpContext context = new HttpContext(request);
255 request.SetEndOfSendNotification(_endOfSendCallback, context);
257 Interlocked.Increment(ref _activeRequests);
260 if (!_firstRequestStarted) {
262 if (!_firstRequestStarted) {
263 _firstRequestStartTime = DateTime.Now;
265 OnFirstRequestStart(context);
266 _firstRequestStarted = true;
271 // This *must* be done after the configuration is initialized.
272 context.Response.InitializeWriter ();
273 handler = HttpApplicationFactory.GetInstance(context);
275 throw new HttpException(FormatResourceString("unable_to_create_app"));
277 if (handler is IHttpAsyncHandler) {
278 async_handler = (IHttpAsyncHandler) handler;
280 context.AsyncHandler = async_handler;
281 async_handler.BeginProcessRequest(context, _handlerCallback, context);
283 handler.ProcessRequest(context);
284 FinishRequest(context, null);
287 catch (Exception error) {
288 context.Response.InitializeWriter ();
289 FinishRequest(context, error);
293 void DoRequest (object o)
295 Interlocked.Decrement (ref pendingCallbacks);
296 InternalExecuteRequest ((HttpWorkerRequest) o);
299 void TryExecuteQueuedRequests ()
301 // Wait for pending jobs to start
302 if (Interlocked.CompareExchange (ref pendingCallbacks, 3, 3) == 3) {
306 if (queueManager == null)
309 if (!queueManager.CanExecuteRequest (false)) {
313 HttpWorkerRequest wr = queueManager.Dequeue ();
318 Interlocked.Increment (ref pendingCallbacks);
319 ThreadPool.QueueUserWorkItem (doRequestCallback, wr);
320 TryExecuteQueuedRequests ();
323 public static void ProcessRequest (HttpWorkerRequest Request)
326 throw new ArgumentNullException ("Request");
328 if (!_runtime._firstRequestExecuted || _runtime.queueManager.CanExecuteRequest (false)) {
329 _runtime.InternalExecuteRequest (Request);
331 _runtime.queueManager.Queue (Request);
337 public void UnloadAppDomain ()
339 throw new NotImplementedException ();
342 public static Cache Cache {
344 return _runtime._cache;
348 public static string AppDomainAppId {
350 if (appDomainAppId == null)
351 appDomainAppId = (string) AppDomain.CurrentDomain.GetData (".appId");
353 return appDomainAppId;
357 public static string AppDomainAppPath {
359 if (appDomainAppPath == null)
360 appDomainAppPath = (string) AppDomain.CurrentDomain.GetData (".appPath");
362 return appDomainAppPath;
366 public static string AppDomainAppVirtualPath {
368 if (appDomainAppVirtualPath == null)
369 appDomainAppVirtualPath = (string) AppDomain.CurrentDomain.GetData (".appVPath");
371 return appDomainAppVirtualPath;
375 public static string AppDomainId {
377 if (appDomainId == null)
378 appDomainId = (string) AppDomain.CurrentDomain.GetData (".domainId");
385 public static string AspInstallDirectory {
387 throw new NotImplementedException ();
392 public static string BinDirectory {
394 throw new NotImplementedException ();
399 public static string ClrInstallDirectory {
401 throw new NotImplementedException ();
406 public static string CodegenDir {
408 throw new NotImplementedException ();
413 public static bool IsOnUNCShare {
415 throw new NotImplementedException ();
419 public static string MachineConfigurationDirectory {
421 return Path.GetDirectoryName (WebConfigurationSettings.MachineConfigPath);
425 internal static TimeoutManager TimeoutManager {
427 return HttpRuntime._runtime.timeoutManager;
431 internal static TraceManager TraceManager {
433 return HttpRuntime._runtime.traceManager;
437 public static void Close ()
442 internal static string FormatResourceString (string key)
444 return GetResourceString (key);
447 internal static string FormatResourceString (string key, string arg0)
449 /*string format = GetResourceString (key);
454 return String.Format (format, arg0);
456 return String.Format ("{0}: {1}", key, arg0);
459 [MonoTODO ("FormatResourceString (string, string, string)")]
460 internal static string FormatResourceString (string key, string arg0, string type) {
461 return String.Format ("{0}: {1} {2}", key, arg0, type);
464 [MonoTODO ("FormatResourceString (string, string, string, string)")]
465 internal static string FormatResourceString (string key, string arg0,
466 string arg1, string arg2)
468 return String.Format ("{0}: {1} {2} {3}", key, arg0, arg1, arg2);
471 [MonoTODO ("FormatResourceString (string, string[]")]
472 internal static string FormatResourceString (string key, string[] args)
474 //StringBuilder sb = new StringBuilder ();
475 /*sb.AppendFormat ("{0}: ", key);
476 foreach (string s in args)
477 sb.AppendFormat ("{0} ", s);
481 return sb.ToString ();*/
482 string s = key + ": ";
484 foreach (string k in args)
489 private static string GetResourceString (string key) {
490 return _runtime.GetResourceStringFromResourceManager (key);
493 [MonoTODO ("GetResourceStringFromResourceManager (string)")]
494 private string GetResourceStringFromResourceManager (string key) {
495 return "String returned by HttpRuntime.GetResourceStringFromResourceManager";
498 #region Security Internal Methods (not impl)
499 [MonoTODO ("Get Application path from the appdomain object")]
500 internal static IStackWalk AppPathDiscovery {
502 if (appPathDiscoveryStackWalk == null) {
503 appPathDiscoveryStackWalk = new FileIOPermission (
504 FileIOPermissionAccess.PathDiscovery, "<apppath>");
506 return appPathDiscoveryStackWalk;
510 internal static IStackWalk ControlPrincipal {
512 if (ctrlPrincipalStackWalk == null) {
513 ctrlPrincipalStackWalk = new SecurityPermission (
514 SecurityPermissionFlag.ControlPrincipal);
516 return ctrlPrincipalStackWalk;
520 internal static IStackWalk Reflection {
522 if (reflectionStackWalk == null) {
523 reflectionStackWalk = new ReflectionPermission (
524 ReflectionPermissionFlag.TypeInformation |
525 ReflectionPermissionFlag.MemberAccess);
527 return reflectionStackWalk;
531 internal static IStackWalk SensitiveInformation {
533 if (sensitiveInfoStackWalk == null) {
534 sensitiveInfoStackWalk = new EnvironmentPermission (
535 PermissionState.Unrestricted);
537 return sensitiveInfoStackWalk;
541 internal static IStackWalk UnmanagedCode {
543 if (unmgdCodeStackWalk == null) {
544 unmgdCodeStackWalk = new SecurityPermission (
545 SecurityPermissionFlag.UnmanagedCode);
547 return unmgdCodeStackWalk;
551 internal static IStackWalk Unrestricted {
553 if (unrestrictedStackWalk == null) {
554 unrestrictedStackWalk = new PermissionSet (
555 PermissionState.Unrestricted);
557 return unrestrictedStackWalk;
561 internal static IStackWalk FileReadAccess (string file)
563 return new FileIOPermission (FileIOPermissionAccess.Read, file);
566 internal static IStackWalk PathDiscoveryAccess (string path)
568 return new FileIOPermission (FileIOPermissionAccess.PathDiscovery, path);