IIS7 custom error module work in SendResponse stage with priority high (priority high in send response actually means lowest priority) which makes it one of the last modules to run in the pipeline. It produces custom errors only if current statusCode > 400. IIS7 custom error module produces four kinds of custom error responses. These are
1. Custom – This error is produced as per settings in the system.webServer/httpErrors section as seen for the requested URL. For information on how a merged view of section for current URL is produced, go here.
2. Detailed – These errors are produced by custom error module based on information available from IHttpResponse::GetStatus call and some static data. Error response include some internal pipeline information as well and is expected to be viewed by server administrators only.
3. One liners – If custom error module detects that we are about to return a blank response, it sends a one-liner error response in few cases. One line responses are hardcoded for various status codes and are not configurable. These are close to “default” errors of IIS6.
4. Original –If custom error module see a non-blank response text, it assumes that module which changed the status code also produced a useful error message and can return that.
Lets understand various properties available in system.webServer/httpErrors section first before going to special gotchas you should care about when dealing with custom error module. Always remember that custom error module will read a merged view of system.webServer/httpErrors section for current URL configuration path and make decisions based on values seen in this merged view.
This is the first property custom error module uses to decide if it should do detailed error or custom error. If effective value of errorMode is “Detailed”, custom error module ignores the custom error settings and generate a detailed error report which contains information like physicalPath, pipeline stage, module which generated the error etc. This property can have following values.
– Custom – When errorMode is set to “Custom”, custom error module will generate error as per custom effective responseMode and path both for local and remote clients.
– Detailed – If errorMode is “Detailed”, custom error module generates a detailed error both for local and remote clients.
– DetailedLocalOnly – This is the default value and custom error module generates different responses for local and remote clients. If request is from local machine effective errorMode is “Detailed” but if request is from a remote machine, effective errorMode is “Custom”.
Value of this section level property tells custom error module what to do when response text is not blank. If a module call IHttpResponse::SetStatus to set an error code and also sets up response text, existingResponse property tells if custom error module should replace current response text with its own error text or should it let the current response text pass through. Asp.Net and WCF are example of modules which sets error response text. This property can be set to following three values.
– Replace – This value make custom error module to always replace the error information with text generated by custom error module. If existingResponse is set to “Replace”, errors/exceptions generated by Asp.Net/WCF are replaced by IIS7 errors.
– PassThrough – If existingResponse is seen as “PassThrough”, custom error module will always pass through responses from modules. This setting will make custom error module return blank response if modules don’t set any text.
– Auto – This is the default value and tells custom error module to do the *right* thing. Actual error text seen by clients will be affected depending on value of fTrySkipCustomErrors returned in IHttpResponse::GetStatus call. When fTrySkipCustomErrors is set to true, custom error module will let the response pass through but if it is set to false, custom errors module replaces text with its own text. Asp.Net/WCF call IHttpResponse::SetStatus with fTrySkipCustomErrors true so that IIS doesn’t override their errors with its own. When effective errorMode is “Detailed” and response is non-empty, this value of existingResponse will act as “PassThrough” regardless of value of fTrySkipCustomErrors.
These properties affect error response only when effective value of errorMode is “Custom”. Custom error module look for error configuration for statusCode.subStatusCode in the merged view of the section. If entry for the current statusCode.subStatusCode is not found, custom error module looks for an entry for current statusCode with subStatusCode -1. If this is not found as well, it reads section level defaultResponseMode and defaultPath as value of responseMode and path. If section level defaultPath is also not set, custom error module will produce a one-liner reply regardless of value of defaultResponseMode. Here are few path gotchas for different response modes.
– path is treated as a file path. In addition to setting the response, custom error module make sure that right content-type header is set based on extension and mime-map configuration.
– prefixLanguageFilePath property helps in doing localized custom errors based on request information. If a request contains Accept-Language header, custom error module will build a list of language packs installed on the machine and try to find a match with value of Accept-Language header (based on which appears first and its q value). If a match is found this language code is used. Else a default language code is used depending on default locale. Language code and path value is appended to prefixLanguageFilePath to build effective error file path.
– If path is set to blank, module will generate a one-liner reply. This can only happen when <error> entry is not found and section level defaultPath is effective because path contains a non-empty validation in schema.
– path is treated as URL to execute. Response returned by executing the URL is returned to client as response. On successful child execute, client will see a 200 response. Child request will enter the pipeline in the same worker process. If this request is supposed to be executed by some other application pool, IIS core will generate 403.14. If child execute produce some other error, that error code along with child execute response is returned.
– If path starts with “http://”, exact URL specified by path is executed. Hostname has to be current hostname. Else server will produce 404.
– When path starts with “/”, it is assumed as URL for the current site and do a child execute on that.
– If path doesn’t start with “/” or “http://”, server will produce 404 when trying to execute the URL.
– Custom error module blindly uses the path as location header value and send a 302 response. If path is set to “/otherpath/otherpage.htm”, this will be used as the destination and most browsers send this request back to the same host. If you set path to www.iis.net, browsers do the right thing and send the new request to www.iis.net instead.
– IIS doesn’t handle application relative paths both for “Redirect” and “ExecuteURL” as handled by Asp.Net (e.g. ~/error/404.htm).
What to expect in case of invalid configuration
Read this article to understand when custom error module will see configuration errors. If custom error modules fails to read system.webServer/staticContent or system.webServer/httpErrors configuration section, it will always override errors from other modules with the configuration error. If this happens, you cannot control the behavior of custom error module by setting properties in httpErrors configuration section as module won’t be able to read the configuration. Custom error module will only generate a 500.19 and will assume default values for responseMode, errorMode, existingResponse which are “File”, “DetailedLocalOnly” and “Auto”. So local clients will always see a detailed error message and remote clients will see a one-liner (because responseMode is “File” path is seen as blank). Detailed errors will have blank detailed information link as this information is obtained from the configuration section. If the original request was sent to Asp.Net page or WCF service, there is a bug in custom error module which makes it return blank responses in case of configuration errors. This will be fixed in next service pack.