mirror of
https://github.com/apache/httpd.git
synced 2025-05-19 02:21:09 +03:00
bare or in single quotes, not double quotes. PR: 6736 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@86738 13f79535-47bb-0310-9956-ffa450edef68
432 lines
19 KiB
HTML
432 lines
19 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
|
<HTML>
|
|
<HEAD>
|
|
<TITLE>International Customized Server Error Messages</TITLE>
|
|
</HEAD>
|
|
|
|
<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
|
|
<BODY
|
|
BGCOLOR="#FFFFFF"
|
|
TEXT="#000000"
|
|
LINK="#0000FF"
|
|
VLINK="#000080"
|
|
ALINK="#FF0000"
|
|
>
|
|
<!--#include virtual="header.html" -->
|
|
|
|
<H1 ALIGN="CENTER">Using XSSI and <SAMP>ErrorDocument</SAMP> to configure
|
|
customized international server error responses</H1>
|
|
<P>
|
|
<H2>Index</H2>
|
|
<UL>
|
|
<LI><A HREF="#intro">Introduction</A>
|
|
<LI><A HREF="#createdir">Creating an ErrorDocument directory</A>
|
|
<LI><A HREF="#docnames">Naming the individual error document files</A>
|
|
<LI><A HREF="#headfoot">The common header and footer files</A>
|
|
<LI><A HREF="#createdocs">Creating ErrorDocuments in different languages</A>
|
|
<LI><A HREF="#fallback">The fallback language</A>
|
|
<LI><A HREF="#proxy">Customizing Proxy Error Messages</A>
|
|
<LI><A HREF="#listings">HTML listing of the discussed example</A>
|
|
</UL>
|
|
<HR>
|
|
<H2><A NAME="intro">Introduction</A></H2>
|
|
This document describes an easy way to provide your apache WWW server
|
|
with a set of customized error messages which take advantage of
|
|
<A HREF="../content-negotiation.html">Content Negotiation</A>
|
|
and <A HREF="../mod/mod_include.html">eXtended Server Side Includes (XSSI)</A>
|
|
to return error messages generated by the server in the client's
|
|
native language.
|
|
</P>
|
|
<P>
|
|
By using XSSI, all
|
|
<A HREF="../mod/core.html#errordocument">customized messages</A>
|
|
can share a homogenous and consistent style and layout, and maintenance work
|
|
(changing images, changing links) is kept to a minimum because all layout
|
|
information can be kept in a single file.<BR>
|
|
Error documents can be shared across different servers, or even hosts,
|
|
because all varying information is inserted at the time the error document
|
|
is returned on behalf of a failed request.
|
|
</P>
|
|
<P>
|
|
Content Negotiation then selects the appropriate language version of a
|
|
particular error message text, honoring the language preferences passed
|
|
in the client's request. (Users usually select their favorite languages
|
|
in the preferences options menu of today's browsers). When an error
|
|
document in the client's primary language version is unavailable, the
|
|
secondary languages are tried or a default (fallback) version is used.
|
|
</P>
|
|
<P>
|
|
You have full flexibility in designing your error documents to
|
|
your personal taste (or your company's conventions). For demonstration
|
|
purposes, we present a simple generic error document scheme.
|
|
For this hypothetic server, we assume that all error messages...
|
|
<UL>
|
|
<LI>possibly are served by different virtual hosts (different host name,
|
|
different IP address, or different port) on the server machine,
|
|
<LI>show a predefined company logo in the right top of the message
|
|
(selectable by virtual host),
|
|
<LI>print the error title first, followed by an explanatory text and
|
|
(depending on the error context) help on how to resolve the error,
|
|
<LI>have some kind of standardized background image,
|
|
<LI>display an apache logo and a feedback email address at the bottom
|
|
of the error message.
|
|
</UL>
|
|
</P>
|
|
|
|
<P>
|
|
An example of a "document not found" message for a german client might
|
|
look like this:<BR>
|
|
<IMG SRC="../images/custom_errordocs.gif"
|
|
ALT="[Needs graphics capability to display]"><BR>
|
|
All links in the document as well as links to the server's administrator
|
|
mail address, and even the name and port of the serving virtual host
|
|
are inserted in the error document at "run-time", <EM>i.e.</EM>, when the error
|
|
actually occurs.
|
|
</P>
|
|
|
|
<H2><A NAME="createdir">Creating an ErrorDocument directory</A></H2>
|
|
|
|
For this concept to work as easily as possible, we must take advantage
|
|
of as much server support as we can get:
|
|
<OL>
|
|
<LI>By defining the <A HREF="../mod/core.html#options">MultiViews option</A>,
|
|
we enable the language selection of the most appropriate language
|
|
alternative (content negotiation).
|
|
<LI>By setting the
|
|
<A HREF="../mod/mod_negotiation.html#languagepriority"
|
|
>LanguagePriority</A>
|
|
directive we define a set of default fallback languages in the situation
|
|
where the client's browser did not express any preference at all.
|
|
<LI>By enabling <A HREF="../mod/mod_include.html">Server Side Includes</A>
|
|
(and disallowing execution of cgi scripts for security reasons),
|
|
we allow the server to include building blocks of the error message,
|
|
and to substitute the value of certain environment variables into the
|
|
generated document (dynamic HTML) or even to conditionally include
|
|
or omit parts of the text.
|
|
<LI>The <A HREF="../mod/mod_mime.html#addhandler">AddHandler</A> and
|
|
<A HREF="../mod/mod_mime.html#addtype">AddType</A> directives are useful
|
|
for automatically XSSI-expanding all files with a <SAMP>.shtml</SAMP>
|
|
suffix to <EM>text/html</EM>.
|
|
<LI>By using the <A HREF="../mod/mod_alias.html#alias">Alias</A> directive,
|
|
we keep the error document directory outside of the document tree
|
|
because it can be regarded more as a server part than part of
|
|
the document tree.
|
|
<LI>The <A HREF="../mod/core.html#directory"><Directory></A>-Block
|
|
restricts these "special" settings to the error document directory
|
|
and avoids an impact on any of the settings for the regular document tree.
|
|
<LI>For each of the error codes to be handled (see RFC2068 for an exact
|
|
description of each error code, or look at
|
|
<CODE>src/main/http_protocol.c</CODE>
|
|
if you wish to see apache's standard messages), an
|
|
<A HREF="../mod/core.html#errordocument">ErrorDocument</A>
|
|
in the aliased <SAMP>/errordocs</SAMP> directory is defined.
|
|
Note that we only define the basename of the document here
|
|
because the MultiViews option will select the best candidate
|
|
based on the language suffixes and the client's preferences.
|
|
Any error situation with an error code <EM>not</EM> handled by a
|
|
custom document will be dealt with by the server in the standard way
|
|
(<EM>i.e.</EM>, a plain error message in english).
|
|
<LI>Finally, the <A HREF="../mod/core.html#allowoverride">AllowOverride</A>
|
|
directive tells apache that it is not necessary to look for
|
|
a .htaccess file in the /errordocs directory: a minor speed
|
|
optimization.
|
|
</OL>
|
|
The resulting <SAMP>httpd.conf</SAMP> configuration would then look
|
|
similar to this: <SMALL>(Note that you can define your own error
|
|
messages using this method for only part of the document tree,
|
|
e.g., a /~user/ subtree. In this case, the configuration could as well
|
|
be put into the .htaccess file at the root of the subtree, and
|
|
the <Directory> and </Directory> directives -but not
|
|
the contained directives- must be omitted.)</SMALL>
|
|
<PRE>
|
|
LanguagePriority en fr de
|
|
Alias /errordocs /usr/local/apache/errordocs
|
|
<Directory /usr/local/apache/errordocs>
|
|
AllowOverride none
|
|
Options MultiViews IncludesNoExec FollowSymLinks
|
|
AddType text/html .shtml
|
|
AddHandler server-parsed .shtml
|
|
</Directory>
|
|
# "400 Bad Request",
|
|
ErrorDocument 400 /errordocs/400
|
|
# "401 Authorization Required",
|
|
ErrorDocument 401 /errordocs/401
|
|
# "403 Forbidden",
|
|
ErrorDocument 403 /errordocs/403
|
|
# "404 Not Found",
|
|
ErrorDocument 404 /errordocs/404
|
|
# "500 Internal Server Error",
|
|
ErrorDocument 500 /errordocs/500
|
|
</PRE>
|
|
The directory for the error messages (here:
|
|
<SAMP>/usr/local/apache/errordocs/</SAMP>) must then be created with the
|
|
appropriate permissions (readable and executable by the server uid or gid,
|
|
only writable for the administrator).
|
|
|
|
<H3><A NAME="docnames">Naming the individual error document files</A></H3>
|
|
|
|
By defining the <SAMP>MultiViews</SAMP> option, the server was told to
|
|
automatically scan the directory for matching variants (looking at language
|
|
and content type suffixes) when a requested document was not found.
|
|
In the configuration, we defined the names for the error documents to be
|
|
just their error number (without any suffix).
|
|
<P>
|
|
The names of the individual error documents are now determined like this
|
|
(I'm using 403 as an example, think of it as a placeholder for any of
|
|
the configured error documents):
|
|
<UL>
|
|
<LI>No file errordocs/403 should exist. Otherwise, it would be found and
|
|
served (with the DefaultType, usually text/plain), all negotiation
|
|
would be bypassed.
|
|
<LI>For each language for which we have an internationalized version
|
|
(note that this need not be the same set of languages for each
|
|
error code - you can get by with a single language version until
|
|
you actually <EM>have</EM> translated versions), a document
|
|
<SAMP>errordocs/403.shtml.<EM>lang</EM></SAMP> is created and
|
|
filled with the error text in that language (<A HREF="#createdocs">see
|
|
below</A>).
|
|
<LI>One fallback document called <SAMP>errordocs/403.shtml</SAMP> is
|
|
created, usually by creating a symlink to the default language
|
|
variant (<A HREF="#fallback">see below</A>).
|
|
</UL>
|
|
|
|
<H3><A NAME="headfoot">The common header and footer files</A></H3>
|
|
|
|
By putting as much layout information in two special "include files",
|
|
the error documents can be reduced to a bare minimum.
|
|
<P>
|
|
One of these layout files defines the HTML document header
|
|
and a configurable list of paths to the icons to be shown in the resulting
|
|
error document. These paths are exported as a set of XSSI environment
|
|
variables and are later evaluated by the "footer" special file.
|
|
The title of the current error (which is
|
|
put into the TITLE tag and an H1 header) is simply passed in from the main
|
|
error document in a variable called <CODE>title</CODE>.<BR>
|
|
<STRONG>By changing this file, the layout of all generated error
|
|
messages can be changed in a second.</STRONG>
|
|
(By exploiting the features of XSSI, you can easily define different
|
|
layouts based on the current virtual host, or even based on the
|
|
client's domain name).
|
|
<P>
|
|
The second layout file describes the footer to be displayed at the bottom
|
|
of every error message. In this example, it shows an apache logo, the current
|
|
server time, the server version string and adds a mail reference to the
|
|
site's webmaster.
|
|
<P>
|
|
For simplicity, the header file is simply called <CODE>head.shtml</CODE>
|
|
because it contains server-parsed content but no language specific
|
|
information. The footer file exists once for each language translation,
|
|
plus a symlink for the default language.<P>
|
|
<STRONG>Example:</STRONG> for English, French and German versions
|
|
(default english)<BR>
|
|
<CODE>foot.shtml.en</CODE>,<BR>
|
|
<CODE>foot.shtml.fr</CODE>,<BR>
|
|
<CODE>foot.shtml.de</CODE>,<BR>
|
|
<CODE>foot.shtml</CODE> symlink to <CODE>foot.shtml.en</CODE><P>
|
|
Both files are included into the error document by using the
|
|
directives <CODE><!--#include virtual="head" --></CODE>
|
|
and <CODE><!--#include virtual="foot" --></CODE>
|
|
respectively: the rest of the magic occurs in mod_negotiation and
|
|
in mod_include.
|
|
<P>
|
|
|
|
See <A HREF="#listings">the listings below</A> to see an actual HTML
|
|
implementation of the discussed example.
|
|
|
|
|
|
<H3><A NAME="createdocs">Creating ErrorDocuments in different languages</A>
|
|
</H3>
|
|
|
|
After all this preparation work, little remains to be said about the
|
|
actual documents. They all share a simple common structure:
|
|
<PRE>
|
|
<!--#set var="title" value="<EM>error description title</EM>" -->
|
|
<!--#include virtual="head" -->
|
|
<EM>explanatory error text</EM>
|
|
<!--#include virtual="foot" -->
|
|
</PRE>
|
|
In the <A HREF="#listings">listings section</A>, you can see an example
|
|
of a [400 Bad Request] error document. Documents as simple as that
|
|
certainly cause no problems to translate or expand.
|
|
|
|
<H3><A NAME="fallback">The fallback language</A></H3>
|
|
|
|
Do we need a special handling for languages other than those we have
|
|
translations for? We did set the LanguagePriority, didn't we?!
|
|
<P>
|
|
Well, the LanguagePriority directive is for the case where the client does
|
|
not express any language priority at all. But what
|
|
happens in the situation where the client wants one
|
|
of the languages we do not have, and none of those we do have?
|
|
<P>
|
|
Without doing anything, the Apache server will usually return a
|
|
[406 no acceptable variant] error, listing the choices from which the client
|
|
may select. But we're in an error message already, and important error
|
|
information might get lost when the client had to choose a language
|
|
representation first.
|
|
<P>
|
|
So, in this situation it appears to be easier to define a fallback language
|
|
(by copying or linking, <EM>e.g.</EM>, the english version to a language-less version).
|
|
Because the negotiation algorithm prefers "more specialized" variants over
|
|
"more generic" variants, these generic alternatives will only be chosen
|
|
when the normal negotiation did not succeed.
|
|
<P>
|
|
A simple shell script to do it (execute within the errordocs/ dir):
|
|
<PRE>
|
|
for f in *.shtml.en
|
|
do
|
|
ln -s $f `basename $f .en`
|
|
done
|
|
</PRE>
|
|
|
|
<P>
|
|
</P>
|
|
|
|
<H2><A NAME="proxy">Customizing Proxy Error Messages</A></H2>
|
|
|
|
<P>
|
|
As of Apache-1.3, it is possible to use the <CODE>ErrorDocument</CODE>
|
|
mechanism for proxy error messages as well (previous versions always
|
|
returned fixed predefined error messages).
|
|
</P>
|
|
<P>
|
|
Most proxy errors return an error code of [500 Internal Server Error].
|
|
To find out whether a particular error document was invoked on behalf
|
|
of a proxy error or because of some other server error, and what the reason
|
|
for the failure was, you can check the contents of the new
|
|
<CODE>ERROR_NOTES</CODE> CGI environment variable:
|
|
if invoked for a proxy error, this variable will contain the actual proxy
|
|
error message text in HTML form.
|
|
</P>
|
|
<P>
|
|
The following excerpt demonstrates how to exploit the <CODE>ERROR_NOTES</CODE>
|
|
variable within an error document:
|
|
</P>
|
|
<PRE>
|
|
<!--#if expr="$REDIRECT_ERROR_NOTES = ''" -->
|
|
<p>
|
|
The server encountered an unexpected condition
|
|
which prevented it from fulfilling the request.
|
|
</p>
|
|
<p>
|
|
<A HREF="mailto:<!--#echo var="SERVER_ADMIN" -->"
|
|
SUBJECT="Error message [<!--#echo var="REDIRECT_STATUS" -->] <!--#echo var="title" --> for <!--#echo var="REQUEST_URI" -->">
|
|
Please forward this error screen to <!--#echo var="SERVER_NAME" -->'s
|
|
WebMaster</A>; it includes useful debugging information about
|
|
the Request which caused the error.
|
|
<pre><!--#printenv --></pre>
|
|
</p>
|
|
<!--#else -->
|
|
<!--#echo var="REDIRECT_ERROR_NOTES" -->
|
|
<!--#endif -->
|
|
</PRE>
|
|
|
|
<H2><A NAME="listings">HTML listing of the discussed example</A></H2>
|
|
|
|
So, to summarize our example, here's the complete listing of the
|
|
<SAMP>400.shtml.en</SAMP> document. You will notice that it contains
|
|
almost nothing but the error text (with conditional additions).
|
|
Starting with this example, you will find it easy to add more error
|
|
documents, or to translate the error documents to different languages.
|
|
<HR><PRE>
|
|
<!--#set var="title" value="Bad Request"
|
|
--><!--#include virtual="head" --><P>
|
|
Your browser sent a request that this server could not understand:
|
|
<BLOCKQUOTE>
|
|
<STRONG><!--#echo var="REQUEST_URI" --></STRONG>
|
|
</BLOCKQUOTE>
|
|
The request could not be understood by the server due to malformed
|
|
syntax. The client should not repeat the request without
|
|
modifications.
|
|
</P>
|
|
<P>
|
|
<!--#if expr="$HTTP_REFERER != ''" -->
|
|
Please inform the owner of
|
|
<A HREF="<!--#echo var="HTTP_REFERER" -->">the referring page</A> about
|
|
the malformed link.
|
|
<!--#else -->
|
|
Please check your request for typing errors and retry.
|
|
<!--#endif -->
|
|
</P>
|
|
<!--#include virtual="foot" -->
|
|
</PRE><HR>
|
|
|
|
Here is the complete <SAMP>head.shtml</SAMP> file (the funny line
|
|
breaks avoid empty lines in the document after XSSI processing). Note the
|
|
configuration section at top. That's where you configure the images and logos
|
|
as well as the apache documentation directory. Look how this file displays
|
|
two different logos depending on the content of the virtual host name
|
|
($SERVER_NAME), and that an animated apache logo is shown if the browser
|
|
appears to support it (the latter requires server configuration lines
|
|
of the form <BR><CODE>BrowserMatch "^Mozilla/[2-4]" anigif</CODE><BR>
|
|
for browser types which support animated GIFs).
|
|
<HR><PRE>
|
|
<!--#if expr="$SERVER_NAME = /.*\.mycompany\.com/"
|
|
--><!--#set var="IMG_CorpLogo"
|
|
value="http://$SERVER_NAME:$SERVER_PORT/errordocs/CorpLogo.gif"
|
|
--><!--#set var="ALT_CorpLogo" value="Powered by Linux!"
|
|
--><!--#else
|
|
--><!--#set var="IMG_CorpLogo"
|
|
value="http://$SERVER_NAME:$SERVER_PORT/errordocs/PrivLogo.gif"
|
|
--><!--#set var="ALT_CorpLogo" value="Powered by Linux!"
|
|
--><!--#endif
|
|
--><!--#set var="IMG_BgImage" value="http://$SERVER_NAME:$SERVER_PORT/errordocs/BgImage.gif"
|
|
--><!--#set var="DOC_Apache" value="http://$SERVER_NAME:$SERVER_PORT/Apache/"
|
|
--><!--#if expr="$anigif"
|
|
--><!--#set var="IMG_Apache" value="http://$SERVER_NAME:$SERVER_PORT/icons/apache_anim.gif"
|
|
--><!--#else
|
|
--><!--#set var="IMG_Apache" value="http://$SERVER_NAME:$SERVER_PORT/icons/apache_pb.gif"
|
|
--><!--#endif
|
|
--><!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
|
<HTML>
|
|
<HEAD>
|
|
<TITLE>
|
|
[<!--#echo var="REDIRECT_STATUS" -->] <!--#echo var="title" -->
|
|
</TITLE>
|
|
</HEAD>
|
|
<BODY BGCOLOR="white" BACKGROUND="<!--#echo var="IMG_BgImage" -->"><UL>
|
|
<H1 ALIGN="center">
|
|
[<!--#echo var="REDIRECT_STATUS" -->] <!--#echo var="title" -->
|
|
<IMG SRC="<!--#echo var="IMG_CorpLogo" -->"
|
|
ALT="<!--#echo var="ALT_CorpLogo" -->" ALIGN=right>
|
|
</H1>
|
|
<HR><!-- ======================================================== -->
|
|
<DIV>
|
|
</PRE><HR>
|
|
and this is the <SAMP>foot.shtml.en</SAMP> file:
|
|
<HR><PRE>
|
|
|
|
</DIV>
|
|
<HR>
|
|
<DIV ALIGN="right"><SMALL><SUP>Local Server time:
|
|
<!--#echo var="DATE_LOCAL" -->
|
|
</SUP></SMALL></DIV>
|
|
<DIV ALIGN="center">
|
|
<A HREF="<!--#echo var="DOC_Apache" -->">
|
|
<IMG SRC="<!--#echo var="IMG_Apache" -->" BORDER=0 ALIGN="bottom"
|
|
ALT="Powered by <!--#echo var="SERVER_SOFTWARE" -->"></A><BR>
|
|
<SMALL><SUP><!--#set var="var"
|
|
value="Powered by $SERVER_SOFTWARE -- File last modified on $LAST_MODIFIED"
|
|
--><!--#echo var="var" --></SUP></SMALL>
|
|
</DIV>
|
|
<ADDRESS>If the indicated error looks like a misconfiguration, please inform
|
|
<A HREF="mailto:<!--#echo var="SERVER_ADMIN" -->"
|
|
SUBJECT="Feedback about Error message [<!--#echo var="REDIRECT_STATUS"
|
|
-->] <!--#echo var="title" -->, req=<!--#echo var="REQUEST_URI" -->">
|
|
<!--#echo var="SERVER_NAME" -->'s WebMaster</A>.
|
|
</ADDRESS>
|
|
</UL></BODY>
|
|
</HTML>
|
|
</PRE><HR>
|
|
|
|
|
|
<H3>More welcome!</H3>
|
|
|
|
If you have tips to contribute, send mail to <A
|
|
HREF="mailto:martin@apache.org">martin@apache.org</A>
|
|
|
|
<!--#include virtual="footer.html" -->
|
|
</BODY>
|
|
</HTML>
|
|
|