//
// System.Web.HttpRuntime.cs
//
-// Author:
+// Authors:
// Miguel de Icaza (miguel@novell.com)
+// Marek Habersack <mhabersack@novell.com>
//
//
-// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2005-2010 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
using System.Text;
using System.Globalization;
using System.Collections;
+using System.Collections.Concurrent;
using System.Reflection;
using System.Security;
using System.Security.Permissions;
using System.Web.Caching;
using System.Web.Configuration;
+using System.Web.Management;
using System.Web.UI;
using System.Web.Util;
-#if MONOWEB_DEP
using Mono.Web.Util;
-#endif
using System.Threading;
-#if TARGET_J2EE
-using Mainsoft.Web;
-#endif
-
-#if NET_2_0 && !TARGET_JVM
using System.CodeDom.Compiler;
using System.Web.Compilation;
-#endif
-namespace System.Web {
-
+namespace System.Web
+{
// CAS - no InheritanceDemand here as the class is sealed
[AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
- public sealed class HttpRuntime {
-#if TARGET_J2EE
- static QueueManager queue_manager { get { return _runtime._queue_manager; } }
- static TraceManager trace_manager { get { return _runtime._trace_manager; } }
- static Cache cache { get { return _runtime._cache; } }
- static Cache internalCache { get { return _runtime._internalCache; } }
- static WaitCallback do_RealProcessRequest;
-
- QueueManager _queue_manager;
- TraceManager _trace_manager;
- Cache _cache;
- Cache _internalCache;
-
- static HttpRuntime ()
- {
- do_RealProcessRequest = new WaitCallback (RealProcessRequest);
- }
-
- public HttpRuntime ()
- {
- WebConfigurationManager.Init ();
- _queue_manager = new QueueManager ();
- _trace_manager = new TraceManager ();
- _cache = new Cache ();
- _internalCache = new Cache();
- _internalCache.DependencyCache = _cache;
- }
-
- static private HttpRuntime _runtimeInstance {
- get {
- HttpRuntime runtime = (HttpRuntime) AppDomain.CurrentDomain.GetData ("HttpRuntime");
- if (runtime == null)
- lock (typeof (HttpRuntime)) {
- runtime = (HttpRuntime) AppDomain.CurrentDomain.GetData ("HttpRuntime");
- if (runtime == null) {
- runtime = new HttpRuntime ();
- AppDomain.CurrentDomain.SetData ("HttpRuntime", runtime);
- }
- }
- return runtime;
- }
- }
- static private HttpRuntime _runtime
- {
- get
- {
- if (HttpContext.Current != null)
- return HttpContext.Current.HttpRuntimeInstance;
- else
- return _runtimeInstance;
- }
- }
-#else
+ public sealed class HttpRuntime
+ {
+ static bool domainUnloading;
+ static SplitOrderedList <string, string> registeredAssemblies;
static QueueManager queue_manager;
static TraceManager trace_manager;
static Cache cache;
static Cache internalCache;
static WaitCallback do_RealProcessRequest;
+ static HttpWorkerRequest.EndOfSendNotification end_of_send_cb;
static Exception initialException;
static bool firstRun;
- static bool caseInsensitive;
- static bool runningOnWindows;
-
-#if NET_2_0
static bool assemblyMappingEnabled;
static object assemblyMappingLock = new object ();
static object appOfflineLock = new object ();
-#endif
+ static HttpRuntimeSection runtime_section;
+ public HttpRuntime ()
+ {
+
+ }
+
static HttpRuntime ()
{
- PlatformID pid = Environment.OSVersion.Platform;
- runningOnWindows = ((int) pid != 128 && (int) pid != 4);
-
- if (runningOnWindows)
- caseInsensitive = true;
- else {
- string mono_iomap = Environment.GetEnvironmentVariable ("MONO_IOMAP");
- if (mono_iomap != null) {
- if (mono_iomap == "all")
- caseInsensitive = true;
- else {
- string[] parts = mono_iomap.Split (':');
- foreach (string p in parts) {
- if (p == "all" || p == "case") {
- caseInsensitive = true;
- break;
- }
- }
- }
- }
- }
-
firstRun = true;
-#if NET_2_0
+
try {
WebConfigurationManager.Init ();
-#if MONOWEB_DEP
SettingsMappingManager.Init ();
-#endif
+ runtime_section = (HttpRuntimeSection) WebConfigurationManager.GetSection ("system.web/httpRuntime");
} catch (Exception ex) {
initialException = ex;
}
-#endif
// The classes in whose constructors exceptions may be thrown, should be handled the same way QueueManager
// and TraceManager are below. The constructors themselves MUST NOT throw any exceptions - we MUST be sure
// the objects are created here. The exceptions will be dealt with below, in RealProcessRequest.
queue_manager = new QueueManager ();
- if (queue_manager.HasException)
- initialException = queue_manager.InitialException;
+ if (queue_manager.HasException) {
+ if (initialException == null)
+ initialException = queue_manager.InitialException;
+ else {
+ Console.Error.WriteLine ("Exception during QueueManager initialization:");
+ Console.Error.WriteLine (queue_manager.InitialException);
+ }
+ }
trace_manager = new TraceManager ();
- if (trace_manager.HasException)
+ if (trace_manager.HasException) {
+ if (initialException == null)
initialException = trace_manager.InitialException;
+ else {
+ Console.Error.WriteLine ("Exception during TraceManager initialization:");
+ Console.Error.WriteLine (trace_manager.InitialException);
+ }
+ }
+ registeredAssemblies = new SplitOrderedList <string, string> (StringComparer.Ordinal);
cache = new Cache ();
internalCache = new Cache ();
- internalCache.DependencyCache = cache;
- do_RealProcessRequest = new WaitCallback (RealProcessRequest);
+ internalCache.DependencyCache = internalCache;
+ do_RealProcessRequest = new WaitCallback (state => {
+ try {
+ RealProcessRequest (state);
+ } catch {}
+ });
+ end_of_send_cb = new HttpWorkerRequest.EndOfSendNotification (EndOfSend);
}
-#if ONLY_1_1
- [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
-#endif
- public HttpRuntime ()
- {
-
+ internal static SplitOrderedList <string, string> RegisteredAssemblies {
+ get { return registeredAssemblies; }
}
-#endif
#region AppDomain handling
+ internal static bool DomainUnloading {
+ get { return domainUnloading; }
+ }
+
+ [MonoDocumentationNote ("Currently returns path to the application root")]
+ public static string AspClientScriptPhysicalPath { get { return AppDomainAppPath; } }
+
+ [MonoDocumentationNote ("Currently returns path to the application root")]
+ public static string AspClientScriptVirtualPath { get { return AppDomainAppVirtualPath; } }
+
//
// http://radio.weblogs.com/0105476/stories/2002/07/12/executingAspxPagesWithoutAWebServer.html
//
}
}
- [MonoTODO]
public static bool IsOnUNCShare {
[AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Low)]
get {
- throw new NotImplementedException ();
+ return RuntimeHelpers.IsUncShare;
}
}
}
}
+ internal static HttpRuntimeSection Section { get { return runtime_section; } }
+
+ public static bool UsingIntegratedPipeline { get { return false; } }
+
+ public static Version IISVersion {
+ get {
+ // Null means not hosted by IIS
+ return null;
+ }
+ }
+
+ public static Version TargetFramework {
+ get {
+ return runtime_section.TargetFramework;
+ }
+ }
[SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
public static void Close ()
// Remove all items from cache.
}
- static void QueuePendingRequests ()
+ internal static HttpWorkerRequest QueuePendingRequest (bool started_internally)
{
- HttpWorkerRequest request = queue_manager.GetNextRequest (null);
- if (request == null)
- return;
- ThreadPool.QueueUserWorkItem (do_RealProcessRequest, request);
+ HttpWorkerRequest next = queue_manager.GetNextRequest (null);
+ if (next == null)
+ return null;
+
+ if (!started_internally) {
+ next.StartedInternally = true;
+ ThreadPool.QueueUserWorkItem (do_RealProcessRequest, next);
+ return null;
+ }
+ return next;
}
-#if !TARGET_J2EE
-#if NET_2_0
static readonly string[] app_offline_files = {"app_offline.htm", "App_Offline.htm", "APP_OFFLINE.HTM"};
- static FileSystemWatcher[] app_offline_watchers;
static string app_offline_file;
static bool AppIsOffline (HttpContext context)
context.Request.ReleaseResources ();
context.Response.ReleaseResources ();
HttpContext.Current = null;
+ HttpApplication.requests_total_counter.Increment ();
return true;
}
RenamedEventHandler reh = new RenamedEventHandler (AppOfflineFileRenamed);
string app_dir = AppDomainAppPath;
- ArrayList watchers = new ArrayList ();
FileSystemWatcher watcher;
string offlineFile = null, tmp;
watcher.Created += seh;
watcher.Renamed += reh;
watcher.EnableRaisingEvents = true;
-
- watchers.Add (watcher);
tmp = Path.Combine (app_dir, f);
if (File.Exists (tmp))
SetOfflineMode (true, offlineFile);
}
}
-#endif
-#endif
static void RealProcessRequest (object o)
{
-#if TARGET_J2EE
- HttpContext context = HttpContext.Current;
- if (context == null)
- context = new HttpContext ((HttpWorkerRequest) o);
- else
- context.SetWorkerRequest ((HttpWorkerRequest) o);
-#else
- HttpContext context = new HttpContext ((HttpWorkerRequest) o);
-#endif
- HttpContext.Current = context;
+ if (domainUnloading) {
+ Console.Error.WriteLine ("Domain is unloading, not processing the request.");
+ return;
+ }
+
+ HttpWorkerRequest req = (HttpWorkerRequest) o;
+ bool started_internally = req.StartedInternally;
+ do {
+ Process (req);
+ req = QueuePendingRequest (started_internally);
+ } while (started_internally && req != null);
+ }
+
+ static void Process (HttpWorkerRequest req)
+ {
bool error = false;
-#if !TARGET_J2EE
if (firstRun) {
-#if NET_2_0
- SetupOfflineWatch ();
-#endif
firstRun = false;
if (initialException != null) {
- FinishWithException ((HttpWorkerRequest) o, new HttpException ("Initial exception", initialException));
+ FinishWithException (req, HttpException.NewWithCode ("Initial exception", initialException, WebEventCodes.RuntimeErrorRequestAbort));
error = true;
}
+ SetupOfflineWatch ();
}
-
-#if NET_2_0
+ HttpContext context = new HttpContext (req);
+ HttpContext.Current = context;
if (AppIsOffline (context))
return;
-#endif
-#endif
//
// Get application instance (create or reuse an instance of the correct class)
try {
app = HttpApplicationFactory.GetApplication (context);
} catch (Exception e) {
- FinishWithException ((HttpWorkerRequest) o, new HttpException ("", e));
+ FinishWithException (req, HttpException.NewWithCode (String.Empty, e, WebEventCodes.RuntimeErrorRequestAbort));
error = true;
}
}
HttpContext.Current = null;
} else {
context.ApplicationInstance = app;
-
+ req.SetEndOfSendNotification (end_of_send_cb, context);
+
//
// Ask application to service the request
//
- IHttpAsyncHandler ihah = app;
-
-#if TARGET_J2EE
- if (context.Handler == null)
- ihah.BeginProcessRequest (context, new AsyncCallback (request_processed), context);
- else
- app.Tick ();
- //ihh.ProcessRequest (context);
- IHttpExtendedHandler extHandler = context.Handler as IHttpExtendedHandler;
- if (extHandler != null && !extHandler.IsCompleted)
- return;
- if (context.Error is UnifyRequestException)
- return;
-
- ihah.EndProcessRequest (null);
-#else
- IAsyncResult appiar = ihah.BeginProcessRequest (context, new AsyncCallback (request_processed), context);
- ihah.EndProcessRequest (appiar);
-#endif
+
+ IHttpHandler ihh = app;
+// IAsyncResult appiar = ihah.BeginProcessRequest (context, new AsyncCallback (request_processed), context);
+// ihah.EndProcessRequest (appiar);
+ ihh.ProcessRequest (context);
HttpApplicationFactory.Recycle (app);
}
-
- QueuePendingRequests ();
}
-
+
+ static void EndOfSend (HttpWorkerRequest ignored1, object ignored2)
+ {
+ }
+
//
// ProcessRequest method is executed in the AppDomain of the application
//
if (request == null)
return;
+ QueuePendingRequest (false);
RealProcessRequest (request);
}
- //
- // Callback to be invoked by IHttpAsyncHandler.BeginProcessRequest
- //
- static void request_processed (IAsyncResult iar)
- {
- HttpContext context = (HttpContext) iar.AsyncState;
-
- context.Request.ReleaseResources ();
- context.Response.ReleaseResources ();
- }
-
+
//
// Called when we are shutting down or we need to reload an application
// that has been modified (touch global.asax)
//
// TODO: call ReleaseResources
//
- ThreadPool.QueueUserWorkItem (new WaitCallback (ShutdownAppDomain), null);
+ domainUnloading = true;
+ HttpApplicationFactory.DisableWatchers ();
+ ThreadPool.QueueUserWorkItem (delegate {
+ try {
+ ShutdownAppDomain ();
+ } catch (Exception e){
+ Console.Error.WriteLine (e);
+ }
+ });
}
-
//
// Shuts down the AppDomain
//
- static void ShutdownAppDomain (object args)
+ static void ShutdownAppDomain ()
{
queue_manager.Dispose ();
// This will call Session_End if needed.
InternalCache.InvokePrivateCallbacks ();
// Kill our application.
HttpApplicationFactory.Dispose ();
- ThreadPool.QueueUserWorkItem (new WaitCallback (DoUnload), null);
+ ThreadPool.QueueUserWorkItem (delegate {
+ try {
+ DoUnload ();
+ } catch {
+ }});
}
- static void DoUnload (object state)
+ static void DoUnload ()
{
- if (Environment.GetEnvironmentVariable ("MONO_ASPNET_NODELETE") == null)
- System.Web.Hosting.ApplicationHost.ClearDynamicBaseDirectory (
- AppDomain.CurrentDomain.SetupInformation.DynamicBase
- );
-#if TARGET_J2EE
- // No unload support for appdomains under Grasshopper
-#else
AppDomain.Unload (AppDomain.CurrentDomain);
-#endif
}
static string content503 = "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n" +
int code = e.GetHttpCode ();
wr.SendStatus (code, HttpWorkerRequest.GetStatusDescription (code));
wr.SendUnknownResponseHeader ("Connection", "close");
- wr.SendUnknownResponseHeader ("Date", DateTime.Now.ToUniversalTime ().ToString ("r"));
Encoding enc = Encoding.ASCII;
wr.SendUnknownResponseHeader ("Content-Type", "text/html; charset=" + enc.WebName);
string msg = e.GetHtmlErrorMessage ();
wr.SendResponseFromMemory (contentBytes, contentBytes.Length);
wr.FlushResponse (true);
wr.CloseConnection ();
+ HttpApplication.requests_total_counter.Increment ();
}
//
{
wr.SendStatus (503, "Service unavailable");
wr.SendUnknownResponseHeader ("Connection", "close");
- wr.SendUnknownResponseHeader ("Date", DateTime.Now.ToUniversalTime ().ToString ("r"));
Encoding enc = Encoding.ASCII;
wr.SendUnknownResponseHeader ("Content-Type", "text/html; charset=" + enc.WebName);
byte [] contentBytes = enc.GetBytes (content503);
wr.SendResponseFromMemory (contentBytes, contentBytes.Length);
wr.FlushResponse (true);
wr.CloseConnection ();
+ HttpApplication.requests_total_counter.Increment ();
}
-#if NET_2_0 && !TARGET_J2EE
+ [AspNetHostingPermissionAttribute(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Unrestricted)]
+ [MonoDocumentationNote ("Always returns null on Mono")]
+ public static NamedPermissionSet GetNamedPermissionSet ()
+ {
+ return null;
+ }
+
static internal void WritePreservationFile (Assembly asm, string genericNameBase)
{
if (asm == null)
AssemblyName an = new AssemblyName (e.Name);
string dynamic_base = AppDomain.CurrentDomain.SetupInformation.DynamicBase;
string compiled = Path.Combine (dynamic_base, an.Name + ".compiled");
+ string asmPath;
- if (!File.Exists (compiled))
- return null;
-
- PreservationFile pf;
- try {
- pf = new PreservationFile (compiled);
- } catch (Exception ex) {
- throw new HttpException (
- String.Format ("Failed to read preservation file {0}", an.Name + ".compiled"),
- ex);
+ if (!File.Exists (compiled)) {
+ string fn = an.FullName;
+ if (!RegisteredAssemblies.Find ((uint)fn.GetHashCode (), fn, out asmPath))
+ return null;
+ } else {
+ PreservationFile pf;
+ try {
+ pf = new PreservationFile (compiled);
+ } catch (Exception ex) {
+ throw new HttpException (
+ String.Format ("Failed to read preservation file {0}", an.Name + ".compiled"),
+ ex);
+ }
+ asmPath = Path.Combine (dynamic_base, pf.Assembly + ".dll");
}
+
+ if (String.IsNullOrEmpty (asmPath))
+ return null;
Assembly ret = null;
try {
- string asmPath = Path.Combine (dynamic_base, pf.Assembly + ".dll");
ret = Assembly.LoadFrom (asmPath);
} catch (Exception) {
// ignore
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler (ResolveAssemblyHandler);
else
AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler (ResolveAssemblyHandler);
+ assemblyMappingEnabled = enable;
}
}
-
- internal static bool RunningOnWindows {
- get { return runningOnWindows; }
- }
-
- internal static bool CaseInsensitive {
- get { return caseInsensitive; }
- }
-#endif
-
- internal static TraceManager TraceManager {
+
+ internal static TraceManager TraceManager {
get {
return trace_manager;
}