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.Web.Caching;
38 using System.Web.Configuration;
40 using System.Threading;
42 namespace System.Web {
44 public sealed class HttpRuntime {
46 static QueueManager queue_manager { get { return _runtime._queue_manager; } }
47 static TraceManager trace_manager { get { return _runtime._trace_manager; } }
48 static Cache cache { get { return _runtime._cache; } }
49 static WaitCallback do_RealProcessRequest;
51 QueueManager _queue_manager;
52 TraceManager _trace_manager;
57 do_RealProcessRequest = new WaitCallback (RealProcessRequest);
62 _queue_manager = new QueueManager ();
63 _trace_manager = new TraceManager ();
64 _cache = new Cache ();
67 static private HttpRuntime _runtime {
69 HttpRuntime runtime = (HttpRuntime)AppDomain.CurrentDomain.GetData("HttpRuntime");
71 lock (typeof(HttpRuntime)) {
72 runtime = (HttpRuntime)AppDomain.CurrentDomain.GetData("HttpRuntime");
73 if (runtime == null) {
74 runtime = new HttpRuntime();
75 AppDomain.CurrentDomain.SetData("HttpRuntime", runtime);
82 static QueueManager queue_manager;
83 static TraceManager trace_manager;
84 static TimeoutManager timeout_manager;
86 static WaitCallback do_RealProcessRequest;
90 Console.WriteLine ("Jelou");
91 queue_manager = new QueueManager ();
92 trace_manager = new TraceManager ();
93 timeout_manager = new TimeoutManager ();
95 do_RealProcessRequest = new WaitCallback (RealProcessRequest);
103 #region AppDomain handling
105 // http://radio.weblogs.com/0105476/stories/2002/07/12/executingAspxPagesWithoutAWebServer.html
107 public static string AppDomainAppId {
110 // This value should not change across invocations
113 return (string) AppDomain.CurrentDomain.GetData (".appId");
117 // Physical directory for the application
118 public static string AppDomainAppPath {
120 return (string) AppDomain.CurrentDomain.GetData (".appPath");
124 public static string AppDomainAppVirtualPath {
126 return (string) AppDomain.CurrentDomain.GetData (".appVPath");
130 public static string AppDomainId {
132 return (string) AppDomain.CurrentDomain.GetData (".domainId");
136 public static string AspInstallDirectory {
138 return (string) AppDomain.CurrentDomain.GetData (".hostingInstallDir");
143 public static string BinDirectory {
145 return Path.Combine (AppDomainAppPath, "bin");
149 public static Cache Cache {
155 public static string ClrInstallDirectory {
157 return Path.GetDirectoryName (typeof (Object).Assembly.CodeBase);
161 public static string CodegenDir {
163 return AppDomain.CurrentDomain.SetupInformation.DynamicBase;
167 public static bool IsOnUNCShare {
169 throw new NotImplementedException ();
173 public static string MachineConfigurationDirectory {
175 return Path.GetDirectoryName (WebConfigurationSettings.MachineConfigPath);
179 public static void Close ()
181 // Remove all items from cache.
184 static void QueuePendingRequests ()
186 HttpWorkerRequest request = queue_manager.GetNextRequest (null);
189 ThreadPool.QueueUserWorkItem (do_RealProcessRequest, request);
192 static void RealProcessRequest (object o)
194 HttpContext context = new HttpContext ((HttpWorkerRequest) o);
195 HttpContext.Current = context;
198 // Get application instance (create or reuse an instance of the correct class)
200 HttpApplication app = HttpApplicationFactory.GetApplication (context);
202 context.ApplicationInstance = app;
205 // Initialize, load modules specific on the config file.
209 // Ask application to service the request
211 IHttpAsyncHandler ihah = app;
213 IAsyncResult appiar = ihah.BeginProcessRequest (context, new AsyncCallback (request_processed), context);
214 ihah.EndProcessRequest (appiar);
216 HttpApplicationFactory.Recycle (app);
218 QueuePendingRequests ();
222 // ProcessRequest method is executed in the AppDomain of the application
225 // ProcessRequest does not guarantee that `wr' will be processed synchronously,
226 // the request can be queued and processed later.
228 public static void ProcessRequest (HttpWorkerRequest wr)
230 HttpWorkerRequest request;
233 // Queue our request, fetch the next available one from the queue
235 request = queue_manager.GetNextRequest (wr);
239 RealProcessRequest (request);
243 // Callback to be invoked by IHttpAsyncHandler.BeginProcessRequest
245 static void request_processed (IAsyncResult iar)
247 HttpContext context = (HttpContext) iar.AsyncState;
249 context.Request.ReleaseResources ();
250 context.Response.ReleaseResources ();
254 // Called when we are shutting down or we need to reload an application
255 // that has been modified (touch global.asax)
257 public static void UnloadAppDomain ()
260 // TODO: call ReleaseResources
262 ThreadPool.QueueUserWorkItem (new WaitCallback (ShutdownAppDomain), null);
266 // Shuts down the AppDomain
268 static void ShutdownAppDomain (object args)
270 // Kill our application.
271 HttpApplicationFactory.Dispose ();
272 ThreadPool.QueueUserWorkItem (new WaitCallback (DoUnload), null);
275 static void DoUnload (object state)
277 AppDomain.Unload (AppDomain.CurrentDomain);
280 static string content503 = "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n" +
281 "<html><head>\n<title>503 Server Unavailable</title>\n</head><body>\n" +
282 "<h1>Server Unavailable</h1>\n" +
286 // This is called from the QueueManager if a request
287 // can not be processed (load, no resources, or
288 // appdomain unload).
290 static internal void FinishUnavailable (HttpWorkerRequest wr)
292 wr.SendStatus (503, "Service unavailable");
293 wr.SendUnknownResponseHeader ("Connection", "close");
294 wr.SendUnknownResponseHeader ("Date", DateTime.Now.ToUniversalTime ().ToString ("r"));
295 Encoding enc = Encoding.ASCII;
296 wr.SendUnknownResponseHeader ("Content-Type", "text/html; charset=" + enc.WebName);
297 byte [] contentBytes = enc.GetBytes (content503);
298 wr.SendUnknownResponseHeader ("Content-Length", contentBytes.Length.ToString ());
299 wr.SendResponseFromMemory (contentBytes, contentBytes.Length);
300 wr.FlushResponse (true);
301 wr.CloseConnection ();
304 internal static TraceManager TraceManager {
306 return trace_manager;
311 internal static TimeoutManager TimeoutManager {
313 return timeout_manager;
319 static ApplicationShutdownReason shutdown_reason = ApplicationShutdownReason.None;
322 public static ApplicationShutdownReason ShutdownReason {
325 // Unlike previously believed by Gonzalo and
326 // myself HttpRuntime.UnloadAppDomain is not
327 // something that happens right away, UnloadAppDomain
328 // mereley "queues" the domain for destruction, but
329 // the application continues to execute until it
330 // is time to terminate. Only at that point is
331 // the domain unloaded.
333 // This means that we should probably not use the
334 // QueueUserWorkItem above to shutdown the appdomain
335 // in a separate thread, but rather just flag this
336 // app for termination, and then unload the domain
338 // The user can continue executing for a long time
340 // See the sample in the docs for ShutdownReason.
343 return shutdown_reason;