[System.Net] Add support for .pac proxy config scripts on mac
[mono.git] / mcs / class / System.Web / System.Web / HttpRuntime.cs
1 //
2 // System.Web.HttpRuntime.cs 
3 // 
4 // Authors:
5 //      Miguel de Icaza (miguel@novell.com)
6 //      Marek Habersack <mhabersack@novell.com>
7 //
8 //
9 // Copyright (C) 2005-2010 Novell, Inc (http://www.novell.com)
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 //
32 // TODO: Call HttpRequest.CloseInputStream when we finish a request, as we are using the IntPtr stream.
33 //
34 using System.IO;
35 using System.Text;
36 using System.Globalization;
37 using System.Collections;
38 using System.Collections.Concurrent;
39 using System.Reflection;
40 using System.Security;
41 using System.Security.Permissions;
42 using System.Web.Caching;
43 using System.Web.Configuration;
44 using System.Web.Management;
45 using System.Web.UI;
46 using System.Web.Util;
47 using Mono.Web.Util;
48 using System.Threading;
49 #if TARGET_J2EE
50 using Mainsoft.Web;
51 #else
52 using System.CodeDom.Compiler;
53 using System.Web.Compilation;
54 #endif
55
56 namespace System.Web
57 {       
58         // CAS - no InheritanceDemand here as the class is sealed
59         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
60         public sealed class HttpRuntime
61         {
62                 static bool domainUnloading;
63                 static SplitOrderedList <string, string> registeredAssemblies;
64 #if TARGET_J2EE
65                 static QueueManager queue_manager { get { return _runtime._queue_manager; } }
66                 static TraceManager trace_manager { get { return _runtime._trace_manager; } }
67                 static Cache cache { get { return _runtime._cache; } }
68                 static Cache internalCache { get { return _runtime._internalCache; } }
69                 static WaitCallback do_RealProcessRequest;
70                 
71                 QueueManager _queue_manager;
72                 TraceManager _trace_manager;
73                 Cache _cache;
74                 Cache _internalCache;
75
76                 public HttpRuntime ()
77                 {
78                         WebConfigurationManager.Init ();
79                         _queue_manager = new QueueManager ();
80                         _trace_manager = new TraceManager ();
81                         _cache = new Cache ();
82                         _internalCache = new Cache();
83                         _internalCache.DependencyCache = _cache;
84                 }
85
86                 static HttpRuntime _runtimeInstance {
87                         get {
88                                 HttpRuntime runtime = (HttpRuntime) AppDomain.CurrentDomain.GetData ("HttpRuntime");
89                                 if (runtime == null)
90                                         lock (typeof (HttpRuntime)) {
91                                                 runtime = (HttpRuntime) AppDomain.CurrentDomain.GetData ("HttpRuntime");
92                                                 if (runtime == null) {
93                                                         runtime = new HttpRuntime ();
94                                                         AppDomain.CurrentDomain.SetData ("HttpRuntime", runtime);
95                                                 }
96                                         }
97                                 return runtime;
98                         }
99                 }
100                 static HttpRuntime _runtime
101                 {
102                         get
103                         {
104                                 if (HttpContext.Current != null)
105                                         return HttpContext.Current.HttpRuntimeInstance;
106                                 else
107                                         return _runtimeInstance;
108                         }
109                 }
110 #else
111                 static QueueManager queue_manager;
112                 static TraceManager trace_manager;
113                 static Cache cache;
114                 static Cache internalCache;
115                 static WaitCallback do_RealProcessRequest;
116                 static HttpWorkerRequest.EndOfSendNotification end_of_send_cb;
117                 static Exception initialException;
118                 static bool firstRun;
119                 static bool assemblyMappingEnabled;
120                 static object assemblyMappingLock = new object ();
121                 static object appOfflineLock = new object ();
122                 static HttpRuntimeSection runtime_section;
123                 
124                 public HttpRuntime ()
125                 {
126
127                 }
128 #endif
129
130                 static HttpRuntime ()
131                 {
132 #if !TARGET_J2EE
133                         firstRun = true;
134
135                         try {
136                                 WebConfigurationManager.Init ();
137                                 SettingsMappingManager.Init ();
138                                 runtime_section = (HttpRuntimeSection) WebConfigurationManager.GetSection ("system.web/httpRuntime");
139                         } catch (Exception ex) {
140                                 initialException = ex;
141                         }
142
143                         // The classes in whose constructors exceptions may be thrown, should be handled the same way QueueManager
144                         // and TraceManager are below. The constructors themselves MUST NOT throw any exceptions - we MUST be sure
145                         // the objects are created here. The exceptions will be dealt with below, in RealProcessRequest.
146                         queue_manager = new QueueManager ();
147                         if (queue_manager.HasException) {
148                                 if (initialException == null)
149                                         initialException = queue_manager.InitialException;
150                                 else {
151                                         Console.Error.WriteLine ("Exception during QueueManager initialization:");
152                                         Console.Error.WriteLine (queue_manager.InitialException);
153                                 }
154                         }
155
156                         trace_manager = new TraceManager ();
157                         if (trace_manager.HasException) {
158                                 if (initialException == null)
159                                         initialException = trace_manager.InitialException;
160                                 else {
161                                         Console.Error.WriteLine ("Exception during TraceManager initialization:");
162                                         Console.Error.WriteLine (trace_manager.InitialException);
163                                 }
164                         }
165
166                         registeredAssemblies = new SplitOrderedList <string, string> (StringComparer.Ordinal);
167                         cache = new Cache ();
168                         internalCache = new Cache ();
169                         internalCache.DependencyCache = internalCache;
170 #endif
171                         do_RealProcessRequest = new WaitCallback (state => {
172                                 try {
173                                         RealProcessRequest (state);
174                                 } catch {}
175                                 });
176                         end_of_send_cb = new HttpWorkerRequest.EndOfSendNotification (EndOfSend);
177                 }
178
179                 internal static SplitOrderedList <string, string> RegisteredAssemblies {
180                         get { return registeredAssemblies; }
181                 }
182                 
183 #region AppDomain handling
184                 internal static bool DomainUnloading {
185                         get { return domainUnloading; }
186                 }
187
188                 [MonoDocumentationNote ("Currently returns path to the application root")]
189                 public static string AspClientScriptPhysicalPath { get { return AppDomainAppPath; } }
190
191                 [MonoDocumentationNote ("Currently returns path to the application root")]
192                 public static string AspClientScriptVirtualPath { get { return AppDomainAppVirtualPath; } }
193                 
194                 //
195                 // http://radio.weblogs.com/0105476/stories/2002/07/12/executingAspxPagesWithoutAWebServer.html
196                 //
197                 public static string AppDomainAppId {
198                         [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.High)]
199                         get {
200                                 //
201                                 // This value should not change across invocations
202                                 //
203                                 string dirname = (string) AppDomain.CurrentDomain.GetData (".appId");
204                                 if ((dirname != null) && (dirname.Length > 0) && SecurityManager.SecurityEnabled) {
205                                         new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dirname).Demand ();
206                                 }
207                                 return dirname;
208                         }
209                 }
210
211                 // Physical directory for the application
212                 public static string AppDomainAppPath {
213                         get {
214                                 string dirname = (string) AppDomain.CurrentDomain.GetData (".appPath");
215                                 if (SecurityManager.SecurityEnabled) {
216                                         new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dirname).Demand ();
217                                 }
218                                 return dirname;
219                         }
220                 }
221
222                 public static string AppDomainAppVirtualPath {
223                         get {
224                                 return (string) AppDomain.CurrentDomain.GetData (".appVPath");
225                         }
226                 }
227
228                 public static string AppDomainId {
229                         [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.High)]
230                         get {
231                                 return (string) AppDomain.CurrentDomain.GetData (".domainId");
232                         }
233                 }
234
235                 public static string AspInstallDirectory {
236                         get {
237                                 string dirname = (string) AppDomain.CurrentDomain.GetData (".hostingInstallDir");
238                                 if ((dirname != null) && (dirname.Length > 0) && SecurityManager.SecurityEnabled) {
239                                         new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dirname).Demand ();
240                                 }
241                                 return dirname;
242                         }
243                 }
244 #endregion
245
246                 static string _actual_bin_directory;
247                 public static string BinDirectory {
248                         get {
249                                 if (_actual_bin_directory == null) {
250                                         string[] parts = AppDomain.CurrentDomain.SetupInformation.PrivateBinPath.Split (';');
251                                         string mypath = AppDomainAppPath;
252                                         string tmp;
253                                         
254                                         foreach (string p in parts) {
255                                                 tmp = Path.Combine (mypath, p);
256                                                 if (Directory.Exists (tmp)) {
257                                                         _actual_bin_directory = tmp;
258                                                         break;
259                                                 }
260                                         }
261
262                                         if (_actual_bin_directory == null)
263                                                 _actual_bin_directory = Path.Combine (mypath, "bin");
264
265                                         if (_actual_bin_directory [_actual_bin_directory.Length - 1] != Path.DirectorySeparatorChar)
266                                                 _actual_bin_directory += Path.DirectorySeparatorChar;
267                                 }
268                                 
269                                 if (SecurityManager.SecurityEnabled)
270                                         new FileIOPermission (FileIOPermissionAccess.PathDiscovery, _actual_bin_directory).Demand ();
271
272                                 return _actual_bin_directory;
273                         }
274                 }
275
276                 public static Cache Cache {
277                         get {
278                                 return cache;
279                         }
280                 }
281
282                 internal static Cache InternalCache {
283                         get {
284                                 return internalCache;
285                         }
286                 }
287                 
288                 public static string ClrInstallDirectory {
289                         get {
290                                 string dirname = Path.GetDirectoryName (typeof (Object).Assembly.Location);
291                                 if ((dirname != null) && (dirname.Length > 0) && SecurityManager.SecurityEnabled) {
292                                         new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dirname).Demand ();
293                                 }
294                                 return dirname;
295                         }
296                 }
297
298                 public static string CodegenDir {
299                         get {
300                                 string dirname = AppDomain.CurrentDomain.SetupInformation.DynamicBase;
301                                 if (SecurityManager.SecurityEnabled) {
302                                         new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dirname).Demand ();
303                                 }
304                                 return dirname;
305                         }
306                 }
307
308                 public static bool IsOnUNCShare {
309                         [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Low)]
310                         get {
311                                 return RuntimeHelpers.IsUncShare;
312                         }
313                 }
314
315                 public static string MachineConfigurationDirectory {
316                         get {
317                                 string dirname = Path.GetDirectoryName (ICalls.GetMachineConfigPath ());
318                                 if ((dirname != null) && (dirname.Length > 0) && SecurityManager.SecurityEnabled) {
319                                         new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dirname).Demand ();
320                                 }
321                                 return dirname;
322                         }
323                 }
324
325                 internal static HttpRuntimeSection Section { get { return runtime_section; } }
326
327                 public static bool UsingIntegratedPipeline { get { return false; } }
328
329 #if NET_4_5
330                 public static Version IISVersion {
331                         get {
332                                 // Null means not hosted by IIS
333                                 return null;
334                         }
335                 }
336                 
337                 public static Version TargetFramework {
338                         get {
339                                 return runtime_section.TargetFramework;
340                         }
341                 }
342 #endif
343                 
344                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
345                 public static void Close ()
346                 {
347                         // Remove all items from cache.
348                 }
349
350                 internal static HttpWorkerRequest QueuePendingRequest (bool started_internally)
351                 {
352                         HttpWorkerRequest next = queue_manager.GetNextRequest (null);
353                         if (next == null)
354                                 return null;
355
356                         if (!started_internally) {
357                                 next.StartedInternally = true;
358                                 ThreadPool.QueueUserWorkItem (do_RealProcessRequest, next);
359                                 return null;
360                         }
361                         return next;
362                 }
363
364 #if !TARGET_J2EE
365                 static readonly string[] app_offline_files = {"app_offline.htm", "App_Offline.htm", "APP_OFFLINE.HTM"};
366                 static string app_offline_file;
367                 
368                 static bool AppIsOffline (HttpContext context)
369                 {
370                         if (!HttpApplicationFactory.ApplicationDisabled || app_offline_file == null)
371                                 return false;
372
373                         HttpResponse response = context.Response;
374                         response.Clear ();
375                         response.ContentType = "text/html";
376                         response.ExpiresAbsolute = DateTime.UtcNow;
377                         response.StatusCode = 503;
378                         response.TransmitFile (app_offline_file, true);
379                         
380                         context.Request.ReleaseResources ();
381                         context.Response.ReleaseResources ();
382                         HttpContext.Current = null;
383                         HttpApplication.requests_total_counter.Increment ();
384                         
385                         return true;
386                 }
387
388                 static void AppOfflineFileRenamed (object sender, RenamedEventArgs args)
389                 {
390                         AppOfflineFileChanged (sender, args);
391                 }
392
393                 static void AppOfflineFileChanged (object sender, FileSystemEventArgs args)
394                 {
395                         lock (appOfflineLock) {
396                                 bool offline;
397                                 
398                                 switch (args.ChangeType) {
399                                         case WatcherChangeTypes.Created:
400                                         case WatcherChangeTypes.Changed:
401                                                 offline = true;
402                                                 break;
403
404                                         case WatcherChangeTypes.Deleted:
405                                                 offline = false;
406                                                 break;
407
408                                         case WatcherChangeTypes.Renamed:
409                                                 RenamedEventArgs rargs = args as RenamedEventArgs;
410
411                                                 if (rargs != null &&
412                                                     String.Compare (rargs.Name, "app_offline.htm", StringComparison.OrdinalIgnoreCase) == 0)
413                                                         offline = true;
414                                                 else
415                                                         offline = false;
416                                                 break;
417
418                                         default:
419                                                 offline = false;
420                                                 break;
421                                 }
422                                 SetOfflineMode (offline, args.FullPath);
423                         }
424                 }
425
426                 static void SetOfflineMode (bool offline, string filePath)
427                 {
428                         if (!offline) {
429                                 app_offline_file = null;
430                                 if (HttpApplicationFactory.ApplicationDisabled)
431                                         HttpRuntime.UnloadAppDomain ();
432                         } else {
433                                 app_offline_file = filePath;
434                                 HttpApplicationFactory.DisableWatchers ();
435                                 HttpApplicationFactory.ApplicationDisabled = true;
436                                 InternalCache.InvokePrivateCallbacks ();
437                                 HttpApplicationFactory.Dispose ();
438                         }
439                 }
440                 
441                 static void SetupOfflineWatch ()
442                 {
443                         lock (appOfflineLock) {
444                                 FileSystemEventHandler seh = new FileSystemEventHandler (AppOfflineFileChanged);
445                                 RenamedEventHandler reh = new RenamedEventHandler (AppOfflineFileRenamed);
446
447                                 string app_dir = AppDomainAppPath;
448                                 FileSystemWatcher watcher;
449                                 string offlineFile = null, tmp;
450                                 
451                                 foreach (string f in app_offline_files) {
452                                         watcher = new FileSystemWatcher ();
453                                         watcher.Path = Path.GetDirectoryName (app_dir);
454                                         watcher.Filter = Path.GetFileName (f);
455                                         watcher.NotifyFilter |= NotifyFilters.Size;
456                                         watcher.Deleted += seh;
457                                         watcher.Changed += seh;
458                                         watcher.Created += seh;
459                                         watcher.Renamed += reh;
460                                         watcher.EnableRaisingEvents = true;
461
462                                         tmp = Path.Combine (app_dir, f);
463                                         if (File.Exists (tmp))
464                                                 offlineFile = tmp;
465                                 }
466
467                                 if (offlineFile != null)
468                                         SetOfflineMode (true, offlineFile);
469                         }
470                 }
471 #endif
472                 
473                 static void RealProcessRequest (object o)
474                 {
475                         if (domainUnloading) {
476                                 Console.Error.WriteLine ("Domain is unloading, not processing the request.");
477                                 return;
478                         }
479
480                         HttpWorkerRequest req = (HttpWorkerRequest) o;
481                         bool started_internally = req.StartedInternally;
482                         do {
483                                 Process (req);
484                                 req = QueuePendingRequest (started_internally);
485                         } while (started_internally && req != null);
486                 }
487
488                 static void Process (HttpWorkerRequest req)
489                 {
490                         bool error = false;
491 #if TARGET_J2EE
492                         HttpContext context = HttpContext.Current;
493                         if (context == null)
494                                 context = new HttpContext (req);
495                         else
496                                 context.SetWorkerRequest (req);
497 #else
498                         if (firstRun) {
499                                 firstRun = false;
500                                 if (initialException != null) {
501                                         FinishWithException (req, HttpException.NewWithCode ("Initial exception", initialException, WebEventCodes.RuntimeErrorRequestAbort));
502                                         error = true;
503                                 }
504                                 SetupOfflineWatch ();
505                         }
506                         HttpContext context = new HttpContext (req);
507 #endif
508                         HttpContext.Current = context;
509 #if !TARGET_J2EE
510                         if (AppIsOffline (context))
511                                 return;
512 #endif
513                         
514                         //
515                         // Get application instance (create or reuse an instance of the correct class)
516                         //
517                         HttpApplication app = null;
518                         if (!error) {
519                                 try {
520                                         app = HttpApplicationFactory.GetApplication (context);
521                                 } catch (Exception e) {
522                                         FinishWithException (req, HttpException.NewWithCode (String.Empty, e, WebEventCodes.RuntimeErrorRequestAbort));
523                                         error = true;
524                                 }
525                         }
526                         
527                         if (error) {
528                                 context.Request.ReleaseResources ();
529                                 context.Response.ReleaseResources ();
530                                 HttpContext.Current = null;
531                         } else {
532                                 context.ApplicationInstance = app;
533                                 req.SetEndOfSendNotification (end_of_send_cb, context);
534
535                                 //
536                                 // Ask application to service the request
537                                 //
538                                 
539 #if TARGET_J2EE
540                                 IHttpAsyncHandler ihah = app;
541                                 if (context.Handler == null)
542                                         ihah.BeginProcessRequest (context, new AsyncCallback (request_processed), context);
543                                 else
544                                         app.Tick ();
545                                 //ihh.ProcessRequest (context);
546                                 IHttpExtendedHandler extHandler = context.Handler as IHttpExtendedHandler;
547                                 if (extHandler != null && !extHandler.IsCompleted)
548                                         return;
549                                 if (context.Error is UnifyRequestException)
550                                         return;
551
552                                 ihah.EndProcessRequest (null);
553 #else
554                                 IHttpHandler ihh = app;
555 //                              IAsyncResult appiar = ihah.BeginProcessRequest (context, new AsyncCallback (request_processed), context);
556 //                              ihah.EndProcessRequest (appiar);
557                                 ihh.ProcessRequest (context);
558 #endif
559
560                                 HttpApplicationFactory.Recycle (app);
561                         }
562                 }
563
564                 static void EndOfSend (HttpWorkerRequest ignored1, object ignored2)
565                 {
566                 }
567
568                 //
569                 // ProcessRequest method is executed in the AppDomain of the application
570                 //
571                 // Observations:
572                 //    ProcessRequest does not guarantee that `wr' will be processed synchronously,
573                 //    the request can be queued and processed later.
574                 //
575                 [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Medium)]
576                 public static void ProcessRequest (HttpWorkerRequest wr)
577                 {
578                         if (wr == null)
579                                 throw new ArgumentNullException ("wr");
580                         //
581                         // Queue our request, fetch the next available one from the queue
582                         //
583                         HttpWorkerRequest request = queue_manager.GetNextRequest (wr);
584                         if (request == null)
585                                 return;
586
587                         QueuePendingRequest (false);
588                         RealProcessRequest (request);
589                 }
590
591 #if TARGET_J2EE
592                 //
593                 // Callback to be invoked by IHttpAsyncHandler.BeginProcessRequest
594                 //
595                 static void request_processed (IAsyncResult iar)
596                 {
597                         HttpContext context = (HttpContext) iar.AsyncState;
598
599                         context.Request.ReleaseResources ();
600                         context.Response.ReleaseResources ();
601                 }
602 #endif
603                 
604 #if TARGET_JVM
605                 [MonoNotSupported ("UnloadAppDomain is not supported")]
606                 public static void UnloadAppDomain ()
607                 {
608                         throw new NotImplementedException ("UnloadAppDomain is not supported");
609                 }
610 #else
611                 //
612                 // Called when we are shutting down or we need to reload an application
613                 // that has been modified (touch global.asax) 
614                 //
615                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
616                 public static void UnloadAppDomain ()
617                 {
618                         //
619                         // TODO: call ReleaseResources
620                         //
621                         domainUnloading = true;
622                         HttpApplicationFactory.DisableWatchers ();
623                         ThreadPool.QueueUserWorkItem (delegate {
624                                 try {
625                                         ShutdownAppDomain ();
626                                 } catch (Exception e){
627                                         Console.Error.WriteLine (e);
628                                 }
629                         });
630                 }
631 #endif
632                 //
633                 // Shuts down the AppDomain
634                 //
635                 static void ShutdownAppDomain ()
636                 {
637                         queue_manager.Dispose ();
638                         // This will call Session_End if needed.
639                         InternalCache.InvokePrivateCallbacks ();
640                         // Kill our application.
641                         HttpApplicationFactory.Dispose ();
642                         ThreadPool.QueueUserWorkItem (delegate {
643                                 try {
644                                         DoUnload ();
645                                 } catch {
646                                 }});
647                 }
648
649                 static void DoUnload ()
650                 {
651 #if TARGET_J2EE
652                         // No unload support for appdomains under Grasshopper
653 #else
654                         AppDomain.Unload (AppDomain.CurrentDomain);
655 #endif
656                 }
657
658                 static string content503 = "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n" +
659                         "<html><head>\n<title>503 Server Unavailable</title>\n</head><body>\n" +
660                         "<h1>Server Unavailable</h1>\n" +
661                         "</body></html>\n";
662
663                 static void FinishWithException (HttpWorkerRequest wr, HttpException e)
664                 {
665                         int code = e.GetHttpCode ();
666                         wr.SendStatus (code, HttpWorkerRequest.GetStatusDescription (code));
667                         wr.SendUnknownResponseHeader ("Connection", "close");
668                         Encoding enc = Encoding.ASCII;
669                         wr.SendUnknownResponseHeader ("Content-Type", "text/html; charset=" + enc.WebName);
670                         string msg = e.GetHtmlErrorMessage ();
671                         byte [] contentBytes = enc.GetBytes (msg);
672                         wr.SendUnknownResponseHeader ("Content-Length", contentBytes.Length.ToString ());
673                         wr.SendResponseFromMemory (contentBytes, contentBytes.Length);
674                         wr.FlushResponse (true);
675                         wr.CloseConnection ();
676                         HttpApplication.requests_total_counter.Increment ();
677                 }
678
679                 //
680                 // This is called from the QueueManager if a request
681                 // can not be processed (load, no resources, or
682                 // appdomain unload).
683                 //
684                 static internal void FinishUnavailable (HttpWorkerRequest wr)
685                 {
686                         wr.SendStatus (503, "Service unavailable");
687                         wr.SendUnknownResponseHeader ("Connection", "close");
688                         Encoding enc = Encoding.ASCII;
689                         wr.SendUnknownResponseHeader ("Content-Type", "text/html; charset=" + enc.WebName);
690                         byte [] contentBytes = enc.GetBytes (content503);
691                         wr.SendUnknownResponseHeader ("Content-Length", contentBytes.Length.ToString ());
692                         wr.SendResponseFromMemory (contentBytes, contentBytes.Length);
693                         wr.FlushResponse (true);
694                         wr.CloseConnection ();
695                         HttpApplication.requests_total_counter.Increment ();
696                 }
697
698                 [AspNetHostingPermissionAttribute(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Unrestricted)]
699                 [MonoDocumentationNote ("Always returns null on Mono")]
700                 public static NamedPermissionSet GetNamedPermissionSet ()
701                 {
702                         return null;
703                 }
704                 
705 #if !TARGET_J2EE
706                 static internal void WritePreservationFile (Assembly asm, string genericNameBase)
707                 {
708                         if (asm == null)
709                                 throw new ArgumentNullException ("asm");
710                         if (String.IsNullOrEmpty (genericNameBase))
711                                 throw new ArgumentNullException ("genericNameBase");
712
713                         string compiled = Path.Combine (AppDomain.CurrentDomain.SetupInformation.DynamicBase,
714                                                         genericNameBase + ".compiled");
715                         PreservationFile pf = new PreservationFile ();
716                         try {
717                                 pf.VirtualPath = String.Concat ("/", genericNameBase, "/");
718
719                                 AssemblyName an = asm.GetName ();
720                                 pf.Assembly = an.Name;
721                                 pf.ResultType = BuildResultTypeCode.TopLevelAssembly;
722                                 pf.Save (compiled);
723                         } catch (Exception ex) {
724                                 throw new HttpException (
725                                         String.Format ("Failed to write preservation file {0}", genericNameBase + ".compiled"),
726                                         ex);
727                         }
728                 }
729                 
730                 static Assembly ResolveAssemblyHandler(object sender, ResolveEventArgs e)
731                 {
732                         AssemblyName an = new AssemblyName (e.Name);
733                         string dynamic_base = AppDomain.CurrentDomain.SetupInformation.DynamicBase;
734                         string compiled = Path.Combine (dynamic_base, an.Name + ".compiled");
735                         string asmPath;
736
737                         if (!File.Exists (compiled)) {
738                                 string fn = an.FullName;
739                                 if (!RegisteredAssemblies.Find ((uint)fn.GetHashCode (), fn, out asmPath))
740                                         return null;
741                         } else {
742                                 PreservationFile pf;
743                                 try {
744                                         pf = new PreservationFile (compiled);
745                                 } catch (Exception ex) {
746                                         throw new HttpException (
747                                                 String.Format ("Failed to read preservation file {0}", an.Name + ".compiled"),
748                                                 ex);
749                                 }
750                                 asmPath = Path.Combine (dynamic_base, pf.Assembly + ".dll");
751                         }
752
753                         if (String.IsNullOrEmpty (asmPath))
754                                 return null;
755                         
756                         Assembly ret = null;
757                         try {
758                                 ret = Assembly.LoadFrom (asmPath);
759                         } catch (Exception) {
760                                 // ignore
761                         }
762                         
763                         return ret;
764                 }
765                 
766                 internal static void EnableAssemblyMapping (bool enable)
767                 {
768                         lock (assemblyMappingLock) {
769                                 if (assemblyMappingEnabled == enable)
770                                         return;
771                                 if (enable)
772                                         AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler (ResolveAssemblyHandler);
773                                 else
774                                         AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler (ResolveAssemblyHandler);
775                                 assemblyMappingEnabled = enable;
776                         }
777                 }
778 #endif // #if !TARGET_J2EE
779                 
780                 internal static TraceManager TraceManager {
781                         get {
782                                 return trace_manager;
783                         }
784                 }
785         }
786 }