2 // System.Web.HttpRuntime.cs
5 // Miguel de Icaza (miguel@novell.com)
8 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 // TODO: Call HttpRequest.CloseInputStream when we finish a request, as we are using the IntPtr stream.
35 using System.Globalization;
36 using System.Collections;
37 using System.Security;
38 using System.Security.Permissions;
39 using System.Web.Caching;
40 using System.Web.Configuration;
42 using System.Threading;
44 #if NET_2_0 && !TARGET_JVM
45 using System.CodeDom.Compiler;
46 using System.Web.Compilation;
49 namespace System.Web {
51 // CAS - no InheritanceDemand here as the class is sealed
52 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
53 public sealed class HttpRuntime {
55 static QueueManager queue_manager { get { return _runtime._queue_manager; } }
56 static TraceManager trace_manager { get { return _runtime._trace_manager; } }
57 static Cache cache { get { return _runtime._cache; } }
58 static WaitCallback do_RealProcessRequest;
60 QueueManager _queue_manager;
61 TraceManager _trace_manager;
66 do_RealProcessRequest = new WaitCallback (RealProcessRequest);
71 _queue_manager = new QueueManager ();
72 _trace_manager = new TraceManager ();
73 _cache = new Cache ();
76 static private HttpRuntime _runtime {
78 HttpRuntime runtime = (HttpRuntime)AppDomain.CurrentDomain.GetData("HttpRuntime");
80 lock (typeof(HttpRuntime)) {
81 runtime = (HttpRuntime)AppDomain.CurrentDomain.GetData("HttpRuntime");
82 if (runtime == null) {
83 runtime = new HttpRuntime();
84 AppDomain.CurrentDomain.SetData("HttpRuntime", runtime);
91 static QueueManager queue_manager;
92 static TraceManager trace_manager;
93 static TimeoutManager timeout_manager;
95 static WaitCallback do_RealProcessRequest;
99 queue_manager = new QueueManager ();
100 trace_manager = new TraceManager ();
101 timeout_manager = new TimeoutManager ();
102 cache = new Cache ();
103 do_RealProcessRequest = new WaitCallback (RealProcessRequest);
107 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
109 public HttpRuntime ()
114 #region AppDomain handling
116 // http://radio.weblogs.com/0105476/stories/2002/07/12/executingAspxPagesWithoutAWebServer.html
118 public static string AppDomainAppId {
119 [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.High)]
122 // This value should not change across invocations
124 string dirname = (string) AppDomain.CurrentDomain.GetData (".appId");
125 if ((dirname != null) && (dirname.Length > 0) && SecurityManager.SecurityEnabled) {
126 new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dirname).Demand ();
132 // Physical directory for the application
133 public static string AppDomainAppPath {
135 string dirname = (string) AppDomain.CurrentDomain.GetData (".appPath");
136 if (SecurityManager.SecurityEnabled) {
137 new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dirname).Demand ();
143 public static string AppDomainAppVirtualPath {
145 return (string) AppDomain.CurrentDomain.GetData (".appVPath");
149 public static string AppDomainId {
150 [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.High)]
152 return (string) AppDomain.CurrentDomain.GetData (".domainId");
156 public static string AspInstallDirectory {
158 string dirname = (string) AppDomain.CurrentDomain.GetData (".hostingInstallDir");
159 if ((dirname != null) && (dirname.Length > 0) && SecurityManager.SecurityEnabled) {
160 new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dirname).Demand ();
167 public static string BinDirectory {
169 string dirname = Path.Combine (AppDomainAppPath, "bin");
170 if (SecurityManager.SecurityEnabled) {
171 new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dirname).Demand ();
177 public static Cache Cache {
183 public static string ClrInstallDirectory {
185 string dirname = Path.GetDirectoryName (typeof (Object).Assembly.Location);
186 if ((dirname != null) && (dirname.Length > 0) && SecurityManager.SecurityEnabled) {
187 new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dirname).Demand ();
193 public static string CodegenDir {
195 string dirname = AppDomain.CurrentDomain.SetupInformation.DynamicBase;
196 if (SecurityManager.SecurityEnabled) {
197 new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dirname).Demand ();
204 public static bool IsOnUNCShare {
205 [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Low)]
207 throw new NotImplementedException ();
211 public static string MachineConfigurationDirectory {
214 string dirname = Path.GetDirectoryName (WebConfigurationManager.OpenMachineConfiguration().FilePath);
216 string dirname = Path.GetDirectoryName (WebConfigurationSettings.MachineConfigPath);
218 if ((dirname != null) && (dirname.Length > 0) && SecurityManager.SecurityEnabled) {
219 new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dirname).Demand ();
225 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
226 public static void Close ()
228 // Remove all items from cache.
231 static void QueuePendingRequests ()
233 HttpWorkerRequest request = queue_manager.GetNextRequest (null);
236 ThreadPool.QueueUserWorkItem (do_RealProcessRequest, request);
239 static void RealProcessRequest (object o)
241 HttpContext context = new HttpContext ((HttpWorkerRequest) o);
242 HttpContext.Current = context;
245 // Get application instance (create or reuse an instance of the correct class)
247 HttpApplication app = null;
250 app = HttpApplicationFactory.GetApplication (context);
251 } catch (Exception e) {
252 FinishWithException ((HttpWorkerRequest) o, new HttpException ("", e));
257 context.Request.ReleaseResources ();
258 context.Response.ReleaseResources ();
259 HttpContext.Current = null;
261 context.ApplicationInstance = app;
263 #if NET_2_0 && !TARGET_JVM
265 // Compile the local resources, if any
267 AppLocalResourcesCompiler alrc = new AppLocalResourcesCompiler();
272 // Ask application to service the request
274 IHttpAsyncHandler ihah = app;
276 IAsyncResult appiar = ihah.BeginProcessRequest (context, new AsyncCallback (request_processed), context);
277 ihah.EndProcessRequest (appiar);
279 HttpApplicationFactory.Recycle (app);
282 QueuePendingRequests ();
286 // ProcessRequest method is executed in the AppDomain of the application
289 // ProcessRequest does not guarantee that `wr' will be processed synchronously,
290 // the request can be queued and processed later.
292 [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Medium)]
293 public static void ProcessRequest (HttpWorkerRequest wr)
296 throw new ArgumentNullException ("wr");
298 // Queue our request, fetch the next available one from the queue
300 HttpWorkerRequest request = queue_manager.GetNextRequest (wr);
304 RealProcessRequest (request);
308 // Callback to be invoked by IHttpAsyncHandler.BeginProcessRequest
310 static void request_processed (IAsyncResult iar)
312 HttpContext context = (HttpContext) iar.AsyncState;
314 context.Request.ReleaseResources ();
315 context.Response.ReleaseResources ();
319 // Called when we are shutting down or we need to reload an application
320 // that has been modified (touch global.asax)
322 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
323 public static void UnloadAppDomain ()
326 // TODO: call ReleaseResources
328 ThreadPool.QueueUserWorkItem (new WaitCallback (ShutdownAppDomain), null);
332 // Shuts down the AppDomain
334 static void ShutdownAppDomain (object args)
336 queue_manager.Dispose ();
337 // This will call Session_End if needed.
338 Cache.InvokePrivateCallbacks ();
339 // Kill our application.
340 HttpApplicationFactory.Dispose ();
341 ThreadPool.QueueUserWorkItem (new WaitCallback (DoUnload), null);
344 #if TARGET_J2EE // No unload support for appdomains under Grasshopper
345 static void DoUnload (object state)
349 static void DoUnload (object state)
351 AppDomain.Unload (AppDomain.CurrentDomain);
355 static string content503 = "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n" +
356 "<html><head>\n<title>503 Server Unavailable</title>\n</head><body>\n" +
357 "<h1>Server Unavailable</h1>\n" +
360 static void FinishWithException (HttpWorkerRequest wr, HttpException e)
362 int code = e.GetHttpCode ();
363 wr.SendStatus (code, HttpWorkerRequest.GetStatusDescription (code));
364 wr.SendUnknownResponseHeader ("Connection", "close");
365 wr.SendUnknownResponseHeader ("Date", DateTime.Now.ToUniversalTime ().ToString ("r"));
366 Encoding enc = Encoding.ASCII;
367 wr.SendUnknownResponseHeader ("Content-Type", "text/html; charset=" + enc.WebName);
368 string msg = e.GetHtmlErrorMessage ();
369 byte [] contentBytes = enc.GetBytes (msg);
370 wr.SendUnknownResponseHeader ("Content-Length", contentBytes.Length.ToString ());
371 wr.SendResponseFromMemory (contentBytes, contentBytes.Length);
372 wr.FlushResponse (true);
373 wr.CloseConnection ();
377 // This is called from the QueueManager if a request
378 // can not be processed (load, no resources, or
379 // appdomain unload).
381 static internal void FinishUnavailable (HttpWorkerRequest wr)
383 wr.SendStatus (503, "Service unavailable");
384 wr.SendUnknownResponseHeader ("Connection", "close");
385 wr.SendUnknownResponseHeader ("Date", DateTime.Now.ToUniversalTime ().ToString ("r"));
386 Encoding enc = Encoding.ASCII;
387 wr.SendUnknownResponseHeader ("Content-Type", "text/html; charset=" + enc.WebName);
388 byte [] contentBytes = enc.GetBytes (content503);
389 wr.SendUnknownResponseHeader ("Content-Length", contentBytes.Length.ToString ());
390 wr.SendResponseFromMemory (contentBytes, contentBytes.Length);
391 wr.FlushResponse (true);
392 wr.CloseConnection ();
395 internal static TraceManager TraceManager {
397 return trace_manager;
402 internal static TimeoutManager TimeoutManager {
404 return timeout_manager;