After spending a great deal of time trying to get my 404 custom error page working, I finally came up with something that works ok. So I thought I would take a few minutes to post some of the things I found out, in the hope that the information will help someone else save some time and frustration.
I am hosted on the new Windows cluster, so this stuff will likely not apply to those of you who are hosted on one of the Unix servers. The current version of control panel does not properly update the relative path to your error page, so you must open a ticket so the tech support guys can do it for you. Yash has stated that this will be fixed in the next release (version 2.4, I think). Also, it is important to remember that the server is currently (as of 1/29/04) configured in a way that dynamic pages cannot be used for custom error pages. That means you will have to use a static (html) page. Definitely a bit clumsy, but you can still get the job done. And when they do get dynamic pages working, much of this information should still be useful.
If the server were able to handle dynamic pages for custom errors, a great deal of information would be available through server variables (referrer, querystring, etc.). But, alas, because client-side scripts (javascript) in html pages cannot access this information, the information available to us in static pages is limited. To take the greatest advantage of the limited information that is available, there are a few things to remember when constructing the 404 handler page.
IIS will do different things, based on the type or page that caused the 404 error. If a request is made for a .html (or .htm) page, the error handling page will assume the context of the requested page. For example, if a request made for http://www.mydomain.com/example.htm and example.htm cannot be found, IIS will redirect to the custom error page you set up (lets call it http://www.mydomain.com/err404.htm), but the browser?s location bar will show the following: http://www.mydomain.com/example.htm (the originally requested url). Therefore, the name of the offending page is available to your javascript as document.URL (the url in the location bar).
If a request is made for a .asp page, IIS will ?pass context? to the error handler (lets stay with http://www.mydomain.com/err404.htm). Additionally, the url will include a search string that contains the error number (404) and the url of the page that caused the error. For example, if a request made for http://www.mydomain.com/example.asp and example.asp cannot be found, IIS will redirect to the custom error page, and the browser?s location bar will look something like this (shown here as code to avoid wrapping):
Note that the page is properly identified in the location bar, and the name of the offending page is supplied in the querystring. Hence, the name of the offending page is available to your javascript in window.location.search (although it is preceded by ??404;?).
Knowing where to get this information, we could use javascript to redirect to a dynamic page, and place the appropriate information in the querystring. However, we have to be careful of a couple things. We should not redirect if the target of our redirection is the page that caused the problem in the first place. In other words, if mypage.asp caused the error, don?t try to redirect to mypage.asp. In this case, we would just show the contents of the static custom error page.
Here is an example:
The other important factor about redirecting to an active page is that the information passed on the query string should be properly checked by your code, to avoid any nasty problems a malicious visitor might try to cause. You could display the information, like:
?The page you requested (http://www.mydomain.com/example.asp) could not be found.? This is where it becomes dangerous. Before you display the data from the querystring (http://www.mydomain.com/example.asp), you should use Server.HtmlEncode to encode it. This will change any potentially nasty characters (<>! and so on) to their corresponding html entities (< > etc). I wont give any samples here; I don?t want to give anybody any bad ideas. Suffice to say, this is a critical step.
ASP.Net adds a whole other layer of complication to custom errors, and I?m still trying to learn the subtleties. In your web.config file, you can set custom errors for .Net pages. There?s a lot of stuff you can do, but here is a simple example:
As best I can tell, this only controls the server?s behavior for .aspx files. So if you set customErrors mode="Off", .aspx files that cause 404 errors will produce the default error page, while other types of files are still handled by the custom error page you set up for IIS. I need to study this some more.
I sure hope this information helps anyone who had the patients to read it all. I?m sure that there are many other aspects that I didn?t cover (or perhaps some things I misstated), but that?s why these forums include a reply button.
riley
I am hosted on the new Windows cluster, so this stuff will likely not apply to those of you who are hosted on one of the Unix servers. The current version of control panel does not properly update the relative path to your error page, so you must open a ticket so the tech support guys can do it for you. Yash has stated that this will be fixed in the next release (version 2.4, I think). Also, it is important to remember that the server is currently (as of 1/29/04) configured in a way that dynamic pages cannot be used for custom error pages. That means you will have to use a static (html) page. Definitely a bit clumsy, but you can still get the job done. And when they do get dynamic pages working, much of this information should still be useful.
If the server were able to handle dynamic pages for custom errors, a great deal of information would be available through server variables (referrer, querystring, etc.). But, alas, because client-side scripts (javascript) in html pages cannot access this information, the information available to us in static pages is limited. To take the greatest advantage of the limited information that is available, there are a few things to remember when constructing the 404 handler page.
IIS will do different things, based on the type or page that caused the 404 error. If a request is made for a .html (or .htm) page, the error handling page will assume the context of the requested page. For example, if a request made for http://www.mydomain.com/example.htm and example.htm cannot be found, IIS will redirect to the custom error page you set up (lets call it http://www.mydomain.com/err404.htm), but the browser?s location bar will show the following: http://www.mydomain.com/example.htm (the originally requested url). Therefore, the name of the offending page is available to your javascript as document.URL (the url in the location bar).
If a request is made for a .asp page, IIS will ?pass context? to the error handler (lets stay with http://www.mydomain.com/err404.htm). Additionally, the url will include a search string that contains the error number (404) and the url of the page that caused the error. For example, if a request made for http://www.mydomain.com/example.asp and example.asp cannot be found, IIS will redirect to the custom error page, and the browser?s location bar will look something like this (shown here as code to avoid wrapping):
Code:
http://www.mydomain.com/err404.htm?404;http://www.mydomain.com/example.asp
Knowing where to get this information, we could use javascript to redirect to a dynamic page, and place the appropriate information in the querystring. However, we have to be careful of a couple things. We should not redirect if the target of our redirection is the page that caused the problem in the first place. In other words, if mypage.asp caused the error, don?t try to redirect to mypage.asp. In this case, we would just show the contents of the static custom error page.
Here is an example:
Code:
var redirectPage=?http://www.mydomain.com/sitedirectory.aspx?;
// try to get querystring
var qstring=window.location.search;
// no qstring, use this doc?s url
if (qstring.length==0) qstring=??404;? +document.URL;
// make sure it?s a good querystring
if (qstring.substring(0,1)!="?") qstring ="?"+qstring;
// only redirect if target is not offending page
if (qstring.indexOf(redirectPage)==-1) {
if (window.location.replace)
window.location.replace(redirectUrl+qstring)
else
window.location=redirectUrl+qstring
}
The other important factor about redirecting to an active page is that the information passed on the query string should be properly checked by your code, to avoid any nasty problems a malicious visitor might try to cause. You could display the information, like:
?The page you requested (http://www.mydomain.com/example.asp) could not be found.? This is where it becomes dangerous. Before you display the data from the querystring (http://www.mydomain.com/example.asp), you should use Server.HtmlEncode to encode it. This will change any potentially nasty characters (<>! and so on) to their corresponding html entities (< > etc). I wont give any samples here; I don?t want to give anybody any bad ideas. Suffice to say, this is a critical step.
ASP.Net adds a whole other layer of complication to custom errors, and I?m still trying to learn the subtleties. In your web.config file, you can set custom errors for .Net pages. There?s a lot of stuff you can do, but here is a simple example:
Code:
<customErrors mode="On">
<error statusCode="404" redirect="err404.htm"/>
</customErrors>
I sure hope this information helps anyone who had the patients to read it all. I?m sure that there are many other aspects that I didn?t cover (or perhaps some things I misstated), but that?s why these forums include a reply button.
riley