Sfoglia il codice sorgente

2003-12-17 Gonzalo Paniagua Javier <[email protected]>

	* System.Web.dll.sources: added CustomErrorsConfigHandler.cs

	* System.Web/HttpContext.cs: implemented IsCustomErrorEnabled and
	IsDebuggingEnabled. Added internal ErrorPage property.

	* System.Web/HttpRuntime.cs: on error, check if we have a custom error
	page enabled to handle it and redirect.

	* System.Web/HttpResponse.cs: added RedirectCustomError (), which
	actually does the redirection to the error page.

	* System.Web.Compilation/PageCompiler.cs: assign the ErrorPage property
	if provided.

	* System.Web.UI/Page.cs: assign the ErrorPage to the context if we get
	an exception when processing the page which only calls Unload.

	* System.Web.UI/PageParser.cs: handle ErrorPage.

	* System.Web.Configuration/CustomErrorsConfigHandler.cs: handle
	<system.web><customErrors />..

	Closes bug #51979.

svn path=/trunk/mcs/; revision=21286
Gonzalo Paniagua Javier 22 anni fa
parent
commit
ed575c326a

+ 4 - 0
mcs/class/System.Web/ChangeLog

@@ -1,3 +1,7 @@
+2003-12-17  Gonzalo Paniagua Javier <[email protected]>
+
+	* System.Web.dll.sources: added CustomErrorsConfigHandler.cs
+
 2003-12-16  Gonzalo Paniagua Javier <[email protected]>
 
 	* System.Web.dll.sources: added CapabilitiesLoader.cs

+ 4 - 0
mcs/class/System.Web/System.Web.Compilation/ChangeLog

@@ -1,3 +1,7 @@
+2003-12-17  Gonzalo Paniagua Javier <[email protected]>
+
+	* PageCompiler.cs: assign the ErrorPage property if provided.
+
 2003-12-15  Jackson Harper <[email protected]>
 
 	* PageCompiler.cs: Add Trace and TraceMode to framework initialize

+ 4 - 0
mcs/class/System.Web/System.Web.Compilation/PageCompiler.cs

@@ -92,6 +92,10 @@ namespace System.Web.Compilation
 			if (culture != null)
 				method.Statements.Add (CreatePropertyAssign ("UICulture", culture));
 
+			string errorPage = pageParser.ErrorPage;
+			if (errorPage != null)
+				method.Statements.Add (CreatePropertyAssign ("ErrorPage", errorPage));
+
                         if (pageParser.Trace) {
                                 CodeAssignStatement stmt = new CodeAssignStatement ();
                                 stmt.Left = new CodePropertyReferenceExpression (thisRef, "TraceEnabled");

+ 4 - 0
mcs/class/System.Web/System.Web.Configuration/ChangeLog

@@ -1,3 +1,7 @@
+2003-12-17  Gonzalo Paniagua Javier <[email protected]>
+
+	* CustomErrorsConfigHandler.cs: handle <system.web><customErrors />..
+
 2003-12-16  Gonzalo Paniagua Javier <[email protected]>
 
 	* HttpCapabilitiesBase.cs: use the new loader.

+ 167 - 0
mcs/class/System.Web/System.Web.Configuration/CustomErrorsConfigHandler.cs

@@ -0,0 +1,167 @@
+//
+// System.Web.Configuration.CustomErrorsConfigHandler
+//
+// Authors:
+//	Gonzalo Paniagua Javier ([email protected])
+//
+// (C) 2003 Novell, Inc. (http://www.novell.com)
+//
+
+using System;
+using System.Collections;
+using System.Configuration;
+using System.IO;
+using System.Xml;
+
+namespace System.Web.Configuration
+{
+	enum CustomErrorMode
+	{
+		RemoteOnly,
+		On,
+		Off
+	}
+	
+	class CustomErrorsConfig
+	{
+		string defaultRedirect;
+		CustomErrorMode mode;
+		Hashtable redirects;
+		string configFilePath;
+
+		public CustomErrorsConfig (object parent, object context)
+		{
+			if (parent != null) {
+				CustomErrorsConfig p = (CustomErrorsConfig) parent;
+				mode = p.mode;
+				defaultRedirect = p.defaultRedirect;
+				if (p.redirects != null && p.redirects.Count > 0) {
+					redirects = new Hashtable ();
+					foreach (DictionaryEntry entry in p.redirects)
+						redirects [entry.Key] = entry.Value;
+				}
+			}
+
+			configFilePath = Path.GetDirectoryName ((string) context);
+		}
+
+		public string DefaultRedirect {
+			get { return defaultRedirect; }
+			set { defaultRedirect = value; }
+		}
+
+		public CustomErrorMode Mode {
+			get { return mode; }
+			set { mode = value; }
+		}
+
+		public string ConfigFilePath {
+			get { return configFilePath; }
+		}
+		
+		public string this [int statusCode] {
+			get {
+				if (redirects == null)
+					return null;
+					
+				return (string) redirects [statusCode];
+			}
+
+			set {
+				if (redirects == null)
+					redirects = new Hashtable ();
+
+				// Overrides any previous setting for statusCode even in the same file
+				redirects [statusCode] = value;
+			}
+		}
+	}
+	
+	class CustomErrorsConfigHandler : IConfigurationSectionHandler
+	{
+		public object Create (object parent, object context, XmlNode section)
+		{
+			CustomErrorsConfig config = new CustomErrorsConfig (parent, context);
+			
+			string defaultRedirect = AttValue ("defaultRedirect", section);
+			if (defaultRedirect != null)
+				config.DefaultRedirect = defaultRedirect;
+
+			string mode = AttValue ("mode", section);
+			if (mode != null) {
+				switch (mode) {
+				case "On":
+					config.Mode = CustomErrorMode.On;
+					break;
+				case "Off":
+					config.Mode = CustomErrorMode.Off;
+					break;
+				case "RemoteOnly":
+					config.Mode = CustomErrorMode.RemoteOnly;
+					break;
+				default:
+					ThrowException ("Invalid value for 'mode': " + mode, section);
+					break;
+				}
+			}
+			
+			if (section.Attributes != null && section.Attributes.Count != 0)
+				ThrowException ("Unrecognized attribute", section);
+
+			if (!section.HasChildNodes)
+				return config;
+
+			XmlNodeList children = section.ChildNodes;
+			foreach (XmlNode child in children) {
+				XmlNodeType ntype = child.NodeType;
+				if (ntype == XmlNodeType.Whitespace || ntype == XmlNodeType.Comment)
+					continue;
+
+				if (ntype != XmlNodeType.Element)
+					ThrowException ("Only elements allowed", child);
+
+				if (child.Name != "error")
+					ThrowException ("Unrecognized node: " + child.Name, child);
+
+				string statusCode = AttValue ("statusCode", child, false, false);
+				string redirect = AttValue ("redirect", child, false, false);
+				int code = 0;
+				try {
+					code = Int32.Parse (statusCode);
+				} catch {
+					ThrowException ("Unable to parse 'statusCode': " + statusCode, child);
+				}
+
+				if (code < 100 || code >= 1000)
+					ThrowException ("Invalid value for 'statusCode': " + code, child);
+
+				config [code] = redirect;
+			}
+
+			return config;
+		}
+
+		// To save some typing...
+		static string AttValue (string name, XmlNode node, bool optional, bool allowEmpty)
+		{
+			return HandlersUtil.ExtractAttributeValue (name, node, optional, allowEmpty);
+		}
+
+		static string AttValue (string name, XmlNode node, bool optional)
+		{
+			return HandlersUtil.ExtractAttributeValue (name, node, optional);
+		}
+
+		static string AttValue (string name, XmlNode node)
+		{
+			return HandlersUtil.ExtractAttributeValue (name, node, true);
+		}
+
+		static void ThrowException (string message, XmlNode node)
+		{
+			HandlersUtil.ThrowException (message, node);
+		}
+		//
+	}
+}
+

+ 7 - 0
mcs/class/System.Web/System.Web.UI/ChangeLog

@@ -1,3 +1,10 @@
+2003-12-17  Gonzalo Paniagua Javier <[email protected]>
+
+	* Page.cs: assign the ErrorPage to the context if we get an exception
+	when processing the page which only calls Unload.
+
+	* PageParser.cs: handle ErrorPage.
+
 2003-12-16  Gonzalo Paniagua Javier <[email protected]>
 
 	* ObjectStateFormatter.cs: added formatters for Unit and FontUnit, which

+ 10 - 5
mcs/class/System.Web/System.Web.UI/Page.cs

@@ -37,10 +37,10 @@ namespace System.Web.UI
 public class Page : TemplateControl, IHttpHandler
 {
 	private bool _viewState = true;
-	private bool _viewStateMac = false;
+	private bool _viewStateMac;
 	private string _errorPage;
 	private bool _isValid;
-	private bool _smartNavigation = false;
+	private bool _smartNavigation;
 	private int _transactionMode;
 	private HttpContext _context;
 	private ValidatorCollection _validators;
@@ -51,8 +51,8 @@ public class Page : TemplateControl, IHttpHandler
 	private ArrayList requiresPostDataChanged;
 	private IPostBackEventHandler requiresRaiseEvent;
 	private NameValueCollection secondPostData;
-	private bool requiresPostBackScript = false;
-	private bool postBackScriptRendered = false;
+	private bool requiresPostBackScript;
+	private bool postBackScriptRendered;
 	private Hashtable registeredArrayDeclares;
 	Hashtable clientScriptBlocks;
 	Hashtable startupScriptBlocks;
@@ -154,7 +154,11 @@ public class Page : TemplateControl, IHttpHandler
 	public string ErrorPage
 	{
 		get { return _errorPage; }
-		set { _errorPage = value; }
+		set {
+			_errorPage = value;
+			if (_context != null)
+				_context.ErrorPage = value;
+		}
 	}
 
 	[EditorBrowsable (EditorBrowsableState.Never)]
@@ -646,6 +650,7 @@ public class Page : TemplateControl, IHttpHandler
 		CultureInfo culture = Thread.CurrentThread.CurrentCulture;
 		CultureInfo uiculture = Thread.CurrentThread.CurrentUICulture;
 		FrameworkInitialize ();
+		context.ErrorPage = _errorPage;
 
 		try {
 			InternalProcessRequest ();

+ 7 - 3
mcs/class/System.Web/System.Web.UI/PageParser.cs

@@ -28,6 +28,7 @@ namespace System.Web.UI
 		int lcid = -1;
 		string culture;
 		string uiculture;
+		string errorPage;
 
 		// FIXME: this is here just for DesignTimeTemplateParser. Anything to do?
 		internal PageParser ()
@@ -186,13 +187,12 @@ namespace System.Web.UI
 							"one of the following values: SortByTime, SortByCategory.");
 			}
 			
+			errorPage = GetString (atts, "ErrorPage", null);
+
 			// Ignored by now
 			GetString (atts, "Buffer", null);
 			GetString (atts, "ClientTarget", null);
 			GetString (atts, "EnableViewStateMac", null);
-			GetString (atts, "ErrorPage", null);
-			GetString (atts, "Trace", null);
-			GetString (atts, "TraceMode", null);
 			GetString (atts, "SmartNavigation", null);
 			GetBool (atts, "ValidateRequest", true);
 
@@ -262,6 +262,10 @@ namespace System.Web.UI
 		internal int LCID {
 			get { return lcid; }
 		}
+
+		internal string ErrorPage {
+			get { return errorPage; }
+		}
 	}
 }
 

+ 1 - 0
mcs/class/System.Web/System.Web.dll.sources

@@ -99,6 +99,7 @@ System.Web.Configuration/ClientTargetSectionHandler.cs
 System.Web.Configuration/CompilationConfiguration.cs
 System.Web.Configuration/CompilationConfigurationHandler.cs
 System.Web.Configuration/CompilerCollection.cs
+System.Web.Configuration/CustomErrorsConfigHandler.cs
 System.Web.Configuration/FormsAuthPasswordFormat.cs
 System.Web.Configuration/FormsProtectionEnum.cs
 System.Web.Configuration/GlobalizationConfiguration.cs

+ 11 - 0
mcs/class/System.Web/System.Web/ChangeLog

@@ -1,3 +1,14 @@
+2003-12-17  Gonzalo Paniagua Javier <[email protected]>
+
+	* HttpContext.cs: implemented IsCustomErrorEnabled and
+	IsDebuggingEnabled. Added internal ErrorPage property.
+
+	* HttpRuntime.cs: on error, check if we have a custom error page enabled
+	to handle it and redirect.
+
+	* HttpResponse.cs: added RedirectCustomError (), which actually does
+	the redirection to the error page.
+	
 2003-12-16  Jackson Harper <[email protected]>
 
 	* TraceContext.cs: Render all the data, and the stylesheet.

+ 24 - 8
mcs/class/System.Web/System.Web/HttpContext.cs

@@ -40,6 +40,7 @@ namespace System.Web
 		int timeoutPossible;
 		long timeoutBegin;
 		object configTimeout;
+		string errorPage;
 
 		public HttpContext (HttpRequest Request, HttpResponse Response)
 		{
@@ -158,20 +159,31 @@ namespace System.Web
 			}
 		}
 
-		[MonoTODO("bool IsCustomErrorEnabled")]
-		public bool IsCustomErrorEnabled
-		{
+		public bool IsCustomErrorEnabled {
 			get {
-				return false;
-				//throw new NotImplementedException ();
+				CustomErrorsConfig cfg;
+				try {
+					cfg = (CustomErrorsConfig) GetConfig ("system.web/customErrors");
+				} catch (Exception e) {
+					return false;
+				}
+				
+				if (cfg == null)
+					return false;
+
+				CustomErrorMode mode = cfg.Mode;
+				if (mode == CustomErrorMode.On)
+					return true;
+
+				return (mode == CustomErrorMode.RemoteOnly &&
+					_oRequest.ServerVariables ["LOCAL_ADDR"] == _oRequest.UserHostAddress);
 			}
 		}
 
-		[MonoTODO("bool IsDebuggingEnabled")]
 		public bool IsDebuggingEnabled
 		{
 			get {
-				throw new NotImplementedException ();
+				return CompilationConfiguration.GetInstance (this).Debug;
 			}
 		}
 
@@ -234,7 +246,6 @@ namespace System.Web
 			}
 		}
 
-		[MonoTODO("TraceContext Trace")]
 		public TraceContext Trace
 		{
 			get {
@@ -292,6 +303,11 @@ namespace System.Web
 			}
 		}
 		
+		internal string ErrorPage {
+			get { return errorPage; }
+			set { errorPage = value; }
+		}
+		
 		internal void SetSession (HttpSessionState session)
 		{
 			_oSession = session;

+ 12 - 0
mcs/class/System.Web/System.Web/HttpResponse.cs

@@ -861,6 +861,18 @@ namespace System.Web
 				End ();
 		}
 
+		internal bool RedirectCustomError (string errorPage)
+		{
+			if (_bHeadersSent)
+				return false;
+
+			if (Request.QueryString ["aspxerrorpath"] != null)
+				return false; // Prevent endless loop
+
+			Redirect (errorPage + "?aspxerrorpath=" + Request.Path, false);
+			return true;
+		}
+		
 		public void Write (char ch)
 		{
 			_TextWriter.Write(ch);

+ 35 - 1
mcs/class/System.Web/System.Web/HttpRuntime.cs

@@ -150,13 +150,17 @@ namespace System.Web {
 
 				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 ();
 				}
-				context.Response.Write (((HttpException) error).GetHtmlErrorMessage ());
+
+				if (!RedirectCustomError (context))
+					context.Response.Write (((HttpException) error).GetHtmlErrorMessage ());
+
 				context.Response.FinalFlush ();
 			}
 
@@ -177,6 +181,36 @@ namespace System.Web {
 			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);