| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580 |
- //
- // System.Web.HttpRuntime
- //
- // Authors:
- // Patrik Torstensson ([email protected])
- // Gaurav Vaish ([email protected])
- // Gonzalo Paniagua Javier ([email protected])
- //
- //
- // Permission is hereby granted, free of charge, to any person obtaining
- // a copy of this software and associated documentation files (the
- // "Software"), to deal in the Software without restriction, including
- // without limitation the rights to use, copy, modify, merge, publish,
- // distribute, sublicense, and/or sell copies of the Software, and to
- // permit persons to whom the Software is furnished to do so, subject to
- // the following conditions:
- //
- // The above copyright notice and this permission notice shall be
- // included in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
- using System;
- using System.Collections;
- using System.IO;
- using System.Text;
- using System.Security;
- using System.Security.Permissions;
- using System.Threading;
- using System.Web.Configuration;
- using System.Web.UI;
- using System.Web.Util;
- using System.Web.Caching;
- namespace System.Web {
- public sealed class HttpRuntime {
- // Security permission helper objects
- private static IStackWalk appPathDiscoveryStackWalk;
- private static IStackWalk ctrlPrincipalStackWalk;
- private static IStackWalk sensitiveInfoStackWalk;
- private static IStackWalk unmgdCodeStackWalk;
- private static IStackWalk unrestrictedStackWalk;
- private static IStackWalk reflectionStackWalk;
- private static HttpRuntime _runtime;
- private static string appDomainAppId;
- private static string appDomainId;
- private static string appDomainAppPath;
- private static string appDomainAppVirtualPath;
- private Cache _cache;
- private int _activeRequests;
- private HttpWorkerRequest.EndOfSendNotification _endOfSendCallback;
- private AsyncCallback _handlerCallback;
- private WaitCallback _appDomainCallback;
- private bool _firstRequestStarted;
- private bool _firstRequestExecuted;
- private DateTime _firstRequestStartTime;
- private Exception _initError;
- private TimeoutManager timeoutManager;
- private QueueManager queueManager;
- private TraceManager traceManager;
- private WaitCallback doRequestCallback;
- private int pendingCallbacks;
- static HttpRuntime ()
- {
- _runtime = new HttpRuntime ();
- _runtime.Init();
- }
- public HttpRuntime ()
- {
- doRequestCallback = new WaitCallback (DoRequest);
- }
- static internal object CreateInternalObject(Type type) {
- return Activator.CreateInstance(type, true);
- }
- private void Init ()
- {
- try {
- _cache = new Cache ();
- timeoutManager = new TimeoutManager ();
- _endOfSendCallback = new HttpWorkerRequest.EndOfSendNotification(OnEndOfSend);
- _handlerCallback = new AsyncCallback(OnHandlerReady);
- _appDomainCallback = new WaitCallback(OnAppDomainUnload);
- }
- catch (Exception error) {
- _initError = error;
- }
- }
- private void OnFirstRequestStart(HttpContext context) {
- if (_initError != null)
- throw _initError;
- try {
- WebConfigurationSettings.Init (context);
- traceManager = new TraceManager ();
- queueManager = new QueueManager ();
- } catch (Exception e) {
- _initError = e;
- }
- // If we got an error during init, throw to client now..
- if (null != _initError)
- throw _initError;
- }
- private void OnFirstRequestEnd() {
- }
- private void OnHandlerReady(IAsyncResult ar) {
- HttpContext context = (HttpContext) ar.AsyncState;
- try {
- IHttpAsyncHandler handler = context.AsyncHandler;
- try {
- handler.EndProcessRequest(ar);
- }
- catch (Exception error) {
- context.AddError(error);
- }
- }
- finally {
- context.AsyncHandler = null;
- }
- FinishRequest(context, context.Error);
- }
- private void OnEndOfSend(HttpWorkerRequest request, object data) {
- HttpContext context = (HttpContext) data;
- context.Request.Dispose();
- context.Response.Dispose();
- }
- internal void FinishRequest(HttpContext context, Exception error) {
- if (error == null) {
- try {
- context.Response.FlushAtEndOfRequest();
- } catch (Exception obj) {
- error = obj;
- }
- }
- HttpWorkerRequest request = context.WorkerRequest;
- if (null != error) {
- WebTrace.WriteLine (error.ToString ());
- context.Response.Clear ();
- context.Response.ClearHeaders ();
- if (!(error is HttpException)) {
- error = new HttpException (String.Empty, error);
- context.Response.StatusCode = 500;
- } else {
- context.Response.StatusCode = ((HttpException) error).GetHttpCode ();
- }
- if (!RedirectCustomError (context))
- context.Response.Write (((HttpException) error).GetHtmlErrorMessage ());
- context.Response.FinalFlush ();
- }
- /*
- * This is not being used. OnFirstRequestEnd is empty.
- if (!_firstRequestExecuted) {
- lock (this) {
- if (!_firstRequestExecuted) {
- _firstRequestExecuted = true;
- OnFirstRequestEnd();
- }
- }
- }
- */
- Interlocked.Decrement(ref _activeRequests);
- if (null != request)
- request.EndOfRequest();
- TryExecuteQueuedRequests ();
- }
- bool RedirectCustomError (HttpContext context)
- {
- if (!context.IsCustomErrorEnabled)
- return false;
- CustomErrorsConfig config = null;
- try {
- config = (CustomErrorsConfig) context.GetConfig ("system.web/customErrors");
- } catch { }
- if (config == null) {
- if (context.ErrorPage != null)
- return context.Response.RedirectCustomError (context.ErrorPage);
- return false;
- }
- string redirect = config [context.Response.StatusCode];
- if (redirect == null) {
- redirect = context.ErrorPage;
- if (redirect == null)
- redirect = config.DefaultRedirect;
- }
- if (redirect == null)
- return false;
- return context.Response.RedirectCustomError (redirect);
- }
- internal static void FinishUnavailable (HttpWorkerRequest wr)
- {
- HttpContext context = new HttpContext (wr);
- HttpException exception = new HttpException (503, "Service unavailable");
- Interlocked.Increment (ref _runtime._activeRequests);
- context.Response.InitializeWriter ();
- _runtime.FinishRequest (context, exception);
- }
- private void OnAppDomainUnload(object state) {
- Dispose();
- }
- internal void Dispose() {
- WaitForRequests(5000);
- queueManager.Dispose (); // Send a 503 to all queued requests
- queueManager = null;
-
- _cache = null;
- HttpApplicationFactory.EndApplication();
- }
- internal void WaitForRequests(int ms) {
- DateTime timeout = DateTime.Now.AddMilliseconds(ms);
- do {
- if (Interlocked.CompareExchange (ref _activeRequests, 0, 0) == 0)
- return;
- Thread.Sleep (100);
- } while (timeout > DateTime.Now);
- }
- internal void InternalExecuteRequest (HttpWorkerRequest request)
- {
- IHttpHandler handler;
- IHttpAsyncHandler async_handler;
- HttpContext context = new HttpContext(request);
- request.SetEndOfSendNotification(_endOfSendCallback, context);
-
- Interlocked.Increment(ref _activeRequests);
- try {
- if (!_firstRequestStarted) {
- lock (this) {
- if (!_firstRequestStarted) {
- _firstRequestStartTime = DateTime.Now;
- OnFirstRequestStart(context);
- _firstRequestStarted = true;
- }
- }
- }
- // This *must* be done after the configuration is initialized.
- context.Response.InitializeWriter ();
- handler = HttpApplicationFactory.GetInstance(context);
- if (null == handler)
- throw new HttpException(FormatResourceString("unable_to_create_app"));
- if (handler is IHttpAsyncHandler) {
- async_handler = (IHttpAsyncHandler) handler;
- context.AsyncHandler = async_handler;
- async_handler.BeginProcessRequest(context, _handlerCallback, context);
- } else {
- handler.ProcessRequest(context);
- FinishRequest(context, null);
- }
- }
- catch (Exception error) {
- context.Response.InitializeWriter ();
- FinishRequest(context, error);
- }
- }
- void DoRequest (object o)
- {
- Interlocked.Decrement (ref pendingCallbacks);
- InternalExecuteRequest ((HttpWorkerRequest) o);
- }
-
- void TryExecuteQueuedRequests ()
- {
- // Wait for pending jobs to start
- if (Interlocked.CompareExchange (ref pendingCallbacks, 3, 3) == 3)
- return;
- HttpWorkerRequest wr = queueManager.GetNextRequest (null);
- if (wr == null)
- return;
- Interlocked.Increment (ref pendingCallbacks);
- ThreadPool.QueueUserWorkItem (doRequestCallback, wr);
- TryExecuteQueuedRequests ();
- }
- public static void ProcessRequest (HttpWorkerRequest request)
- {
- if (request == null)
- throw new ArgumentNullException ("request");
- QueueManager mgr = _runtime.queueManager;
- if (_runtime._firstRequestStarted && mgr != null) {
- request = mgr.GetNextRequest (request);
- // We're busy, return immediately
- if (request == null)
- return;
- }
- _runtime.InternalExecuteRequest (request);
- }
- #if NET_1_1
- [MonoTODO]
- public void UnloadAppDomain ()
- {
- throw new NotImplementedException ();
- }
- #endif
- public static Cache Cache {
- get {
- return _runtime._cache;
- }
- }
- public static string AppDomainAppId {
- get {
- if (appDomainAppId == null)
- appDomainAppId = (string) AppDomain.CurrentDomain.GetData (".appId");
- return appDomainAppId;
- }
- }
- public static string AppDomainAppPath {
- get {
- if (appDomainAppPath == null)
- appDomainAppPath = (string) AppDomain.CurrentDomain.GetData (".appPath");
- return appDomainAppPath;
- }
- }
- public static string AppDomainAppVirtualPath {
- get {
- if (appDomainAppVirtualPath == null)
- appDomainAppVirtualPath = (string) AppDomain.CurrentDomain.GetData (".appVPath");
- return appDomainAppVirtualPath;
- }
- }
- public static string AppDomainId {
- get {
- if (appDomainId == null)
- appDomainId = (string) AppDomain.CurrentDomain.GetData (".domainId");
- return appDomainId;
- }
- }
- public static string AspInstallDirectory {
- get {
- return ICalls.GetMachineInstallDirectory ();
- }
- }
- public static string BinDirectory {
- get {
- return Path.Combine (AppDomainAppPath, "bin");
- }
- }
- public static string ClrInstallDirectory {
- get {
- return ICalls.GetMachineInstallDirectory ();
- }
- }
- public static string CodegenDir {
- get {
- return AppDomain.CurrentDomain.SetupInformation.DynamicBase;
- }
- }
- public static bool IsOnUNCShare {
- get {
- // IsUnc broken under unix?
- return (!((int) Environment.OSVersion.Platform == 128) &&
- new Uri ("file://" + ClrInstallDirectory).IsUnc);
- }
- }
- public static string MachineConfigurationDirectory {
- get {
- return Path.GetDirectoryName (WebConfigurationSettings.MachineConfigPath);
- }
- }
- internal static TimeoutManager TimeoutManager {
- get {
- return HttpRuntime._runtime.timeoutManager;
- }
- }
- internal static TraceManager TraceManager {
- get {
- return HttpRuntime._runtime.traceManager;
- }
- }
- public static void Close ()
- {
- _runtime.Dispose();
- }
- internal static string FormatResourceString (string key)
- {
- return GetResourceString (key);
- }
- internal static string FormatResourceString (string key, string arg0)
- {
- /*string format = GetResourceString (key);
- if (format == null)
- return null;
-
- return String.Format (format, arg0);
- */
- return String.Format ("{0}: {1}", key, arg0);
- }
- [MonoTODO ("FormatResourceString (string, string, string)")]
- internal static string FormatResourceString (string key, string arg0, string type) {
- return String.Format ("{0}: {1} {2}", key, arg0, type);
- }
- [MonoTODO ("FormatResourceString (string, string, string, string)")]
- internal static string FormatResourceString (string key, string arg0,
- string arg1, string arg2)
- {
- return String.Format ("{0}: {1} {2} {3}", key, arg0, arg1, arg2);
- }
- [MonoTODO ("FormatResourceString (string, string[]")]
- internal static string FormatResourceString (string key, string[] args)
- {
- //StringBuilder sb = new StringBuilder ();
- /*sb.AppendFormat ("{0}: ", key);
- foreach (string s in args)
- sb.AppendFormat ("{0} ", s);
- if (sb.Length > 0)
- sb.Length--;
- return sb.ToString ();*/
- string s = key + ": ";
- if (args != null)
- foreach (string k in args)
- s += k + " ";
- return s;
- }
- private static string GetResourceString (string key) {
- return _runtime.GetResourceStringFromResourceManager (key);
- }
- [MonoTODO ("GetResourceStringFromResourceManager (string)")]
- private string GetResourceStringFromResourceManager (string key) {
- return key;
- }
- #region Security Internal Methods (not impl)
- [MonoTODO ("Get Application path from the appdomain object")]
- internal static IStackWalk AppPathDiscovery {
- get {
- if (appPathDiscoveryStackWalk == null) {
- appPathDiscoveryStackWalk = new FileIOPermission (
- FileIOPermissionAccess.PathDiscovery, "<apppath>");
- }
- return appPathDiscoveryStackWalk;
- }
- }
- internal static IStackWalk ControlPrincipal {
- get {
- if (ctrlPrincipalStackWalk == null) {
- ctrlPrincipalStackWalk = new SecurityPermission (
- SecurityPermissionFlag.ControlPrincipal);
- }
- return ctrlPrincipalStackWalk;
- }
- }
- internal static IStackWalk Reflection {
- get {
- if (reflectionStackWalk == null) {
- reflectionStackWalk = new ReflectionPermission (
- ReflectionPermissionFlag.TypeInformation |
- ReflectionPermissionFlag.MemberAccess);
- }
- return reflectionStackWalk;
- }
- }
- internal static IStackWalk SensitiveInformation {
- get {
- if (sensitiveInfoStackWalk == null) {
- sensitiveInfoStackWalk = new EnvironmentPermission (
- PermissionState.Unrestricted);
- }
- return sensitiveInfoStackWalk;
- }
- }
- internal static IStackWalk UnmanagedCode {
- get {
- if (unmgdCodeStackWalk == null) {
- unmgdCodeStackWalk = new SecurityPermission (
- SecurityPermissionFlag.UnmanagedCode);
- }
- return unmgdCodeStackWalk;
- }
- }
- internal static IStackWalk Unrestricted {
- get {
- if (unrestrictedStackWalk == null) {
- unrestrictedStackWalk = new PermissionSet (
- PermissionState.Unrestricted);
- }
- return unrestrictedStackWalk;
- }
- }
- internal static IStackWalk FileReadAccess (string file)
- {
- return new FileIOPermission (FileIOPermissionAccess.Read, file);
- }
- internal static IStackWalk PathDiscoveryAccess (string path)
- {
- return new FileIOPermission (FileIOPermissionAccess.PathDiscovery, path);
- }
- #endregion
- }
- }
|