1<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
4<html xmlns="http://www.w3.org/1999/xhtml">
5  <head>
6    <meta name="generator" content="HTML Tidy, see www.w3.org" />
7
8    <title>International Customized Server Error Messages</title>
9  </head>
10  <!-- Background white, links blue (unvisited), navy (visited), red (active) -->
11
12  <body bgcolor="#FFFFFF" text="#000000" link="#0000FF"
13  vlink="#000080" alink="#FF0000">
14        <div align="CENTER">
15      <img src="../images/sub.gif" alt="[APACHE DOCUMENTATION]" />
16
17      <h3>Apache HTTP Server Version 1.3</h3>
18    </div>
19
20
21    <h1 align="CENTER">Using XSSI and <samp>ErrorDocument</samp> to
22    configure customized international server error responses</h1>
23
24    <h2>Index</h2>
25
26    <ul>
27      <li><a href="#intro">Introduction</a></li>
28
29      <li><a href="#createdir">Creating an ErrorDocument
30      directory</a></li>
31
32      <li><a href="#docnames">Naming the individual error document
33      files</a></li>
34
35      <li><a href="#headfoot">The common header and footer
36      files</a></li>
37
38      <li><a href="#createdocs">Creating ErrorDocuments in
39      different languages</a></li>
40
41      <li><a href="#fallback">The fallback language</a></li>
42
43      <li><a href="#proxy">Customizing Proxy Error
44      Messages</a></li>
45
46      <li><a href="#listings">HTML listing of the discussed
47      example</a></li>
48    </ul>
49    <hr />
50
51    <h2><a id="intro" name="intro">Introduction</a></h2>
52
53    <p>This document describes an easy way to provide your apache
54    WWW server with a set of customized error messages which take
55    advantage of <a href="../content-negotiation.html">Content
56    Negotiation</a> and <a href="../mod/mod_include.html">eXtended
57    Server Side Includes (XSSI)</a> to return error messages
58    generated by the server in the client's native language.</p>
59
60    <p>By using XSSI, all <a
61    href="../mod/core.html#errordocument">customized messages</a>
62    can share a homogenous and consistent style and layout, and
63    maintenance work (changing images, changing links) is kept to a
64    minimum because all layout information can be kept in a single
65    file.<br />
66     Error documents can be shared across different servers, or
67    even hosts, because all varying information is inserted at the
68    time the error document is returned on behalf of a failed
69    request.</p>
70
71    <p>Content Negotiation then selects the appropriate language
72    version of a particular error message text, honoring the
73    language preferences passed in the client's request. (Users
74    usually select their favorite languages in the preferences
75    options menu of today's browsers). When an error document in
76    the client's primary language version is unavailable, the
77    secondary languages are tried or a default (fallback) version
78    is used.</p>
79
80    <p>You have full flexibility in designing your error documents
81    to your personal taste (or your company's conventions). For
82    demonstration purposes, we present a simple generic error
83    document scheme. For this hypothetic server, we assume that all
84    error messages...</p>
85
86    <ul>
87      <li>possibly are served by different virtual hosts (different
88      host name, different IP address, or different port) on the
89      server machine,</li>
90
91      <li>show a predefined company logo in the right top of the
92      message (selectable by virtual host),</li>
93
94      <li>print the error title first, followed by an explanatory
95      text and (depending on the error context) help on how to
96      resolve the error,</li>
97
98      <li>have some kind of standardized background image,</li>
99
100      <li>display an apache logo and a feedback email address at
101      the bottom of the error message.</li>
102    </ul>
103
104    <p>An example of a "document not found" message for a german
105    client might look like this:<br />
106     <img src="../images/custom_errordocs.gif"
107    alt="[Needs graphics capability to display]" /><br />
108     All links in the document as well as links to the server's
109    administrator mail address, and even the name and port of the
110    serving virtual host are inserted in the error document at
111    "run-time", <em>i.e.</em>, when the error actually occurs.</p>
112
113    <h2><a id="createdir" name="createdir">Creating an
114    ErrorDocument directory</a></h2>
115    For this concept to work as easily as possible, we must take
116    advantage of as much server support as we can get:
117
118    <ol>
119      <li>By defining the <a
120      href="../mod/core.html#options">MultiViews option</a>, we
121      enable the language selection of the most appropriate
122      language alternative (content negotiation).</li>
123
124      <li>By setting the <a
125      href="../mod/mod_negotiation.html#languagepriority">LanguagePriority</a>
126      directive we define a set of default fallback languages in
127      the situation where the client's browser did not express any
128      preference at all.</li>
129
130      <li>By enabling <a href="../mod/mod_include.html">Server Side
131      Includes</a> (and disallowing execution of cgi scripts for
132      security reasons), we allow the server to include building
133      blocks of the error message, and to substitute the value of
134      certain environment variables into the generated document
135      (dynamic HTML) or even to conditionally include or omit parts
136      of the text.</li>
137
138      <li>The <a
139      href="../mod/mod_mime.html#addhandler">AddHandler</a> and <a
140      href="../mod/mod_mime.html#addtype">AddType</a> directives
141      are useful for automatically XSSI-expanding all files with a
142      <samp>.shtml</samp> suffix to <em>text/html</em>.</li>
143
144      <li>By using the <a
145      href="../mod/mod_alias.html#alias">Alias</a> directive, we
146      keep the error document directory outside of the document
147      tree because it can be regarded more as a server part than
148      part of the document tree.</li>
149
150      <li>The <a
151      href="../mod/core.html#directory">&lt;Directory&gt;</a>-Block
152      restricts these "special" settings to the error document
153      directory and avoids an impact on any of the settings for the
154      regular document tree.</li>
155
156      <li>For each of the error codes to be handled (see RFC2068
157      for an exact description of each error code, or look at
158      <code>src/main/http_protocol.c</code> if you wish to see
159      apache's standard messages), an <a
160      href="../mod/core.html#errordocument">ErrorDocument</a> in
161      the aliased <samp>/errordocs</samp> directory is defined.
162      Note that we only define the basename of the document here
163      because the MultiViews option will select the best candidate
164      based on the language suffixes and the client's preferences.
165      Any error situation with an error code <em>not</em> handled
166      by a custom document will be dealt with by the server in the
167      standard way (<em>i.e.</em>, a plain error message in
168      english).</li>
169
170      <li>Finally, the <a
171      href="../mod/core.html#allowoverride">AllowOverride</a>
172      directive tells apache that it is not necessary to look for a
173      .htaccess file in the /errordocs directory: a minor speed
174      optimization.</li>
175    </ol>
176    The resulting <samp>httpd.conf</samp> configuration would then
177    look similar to this: <small>(Note that you can define your own
178    error messages using this method for only part of the document
179    tree, e.g., a /~user/ subtree. In this case, the configuration
180    could as well be put into the .htaccess file at the root of the
181    subtree, and the &lt;Directory&gt; and &lt;/Directory&gt;
182    directives -but not the contained directives- must be
183    omitted.)</small>
184<pre>
185  LanguagePriority en fr de
186  Alias  /errordocs  /usr/local/apache/errordocs
187  &lt;Directory /usr/local/apache/errordocs&gt;
188   AllowOverride none
189   Options MultiViews IncludesNoExec FollowSymLinks
190   AddType text/html .shtml
191   AddHandler server-parsed .shtml
192  &lt;/Directory&gt;
193  #    "400 Bad Request",
194  ErrorDocument  400  /errordocs/400
195  #    "401 Authorization Required",
196  ErrorDocument  401  /errordocs/401
197  #    "403 Forbidden",
198  ErrorDocument  403  /errordocs/403
199  #    "404 Not Found",
200  ErrorDocument  404  /errordocs/404
201  #    "500 Internal Server Error",
202  ErrorDocument  500  /errordocs/500
203</pre>
204    The directory for the error messages (here:
205    <samp>/usr/local/apache/errordocs/</samp>) must then be created
206    with the appropriate permissions (readable and executable by
207    the server uid or gid, only writable for the administrator).
208
209    <h3><a id="docnames" name="docnames">Naming the individual
210    error document files</a></h3>
211    By defining the <samp>MultiViews</samp> option, the server was
212    told to automatically scan the directory for matching variants
213    (looking at language and content type suffixes) when a
214    requested document was not found. In the configuration, we
215    defined the names for the error documents to be just their
216    error number (without any suffix).
217
218    <p>The names of the individual error documents are now
219    determined like this (I'm using 403 as an example, think of it
220    as a placeholder for any of the configured error
221    documents):</p>
222
223    <ul>
224      <li>No file errordocs/403 should exist. Otherwise, it would
225      be found and served (with the DefaultType, usually
226      text/plain), all negotiation would be bypassed.</li>
227
228      <li>For each language for which we have an internationalized
229      version (note that this need not be the same set of languages
230      for each error code - you can get by with a single language
231      version until you actually <em>have</em> translated
232      versions), a document
233      <samp>errordocs/403.shtml.<em>lang</em></samp> is created and
234      filled with the error text in that language (<a
235      href="#createdocs">see below</a>).</li>
236
237      <li>One fallback document called
238      <samp>errordocs/403.shtml</samp> is created, usually by
239      creating a symlink to the default language variant (<a
240      href="#fallback">see below</a>).</li>
241    </ul>
242
243    <h3><a id="headfoot" name="headfoot">The common header and
244    footer files</a></h3>
245    By putting as much layout information in two special "include
246    files", the error documents can be reduced to a bare minimum.
247
248    <p>One of these layout files defines the HTML document header
249    and a configurable list of paths to the icons to be shown in
250    the resulting error document. These paths are exported as a set
251    of XSSI environment variables and are later evaluated by the
252    "footer" special file. The title of the current error (which is
253    put into the TITLE tag and an H1 header) is simply passed in
254    from the main error document in a variable called
255    <code>title</code>.<br />
256     <strong>By changing this file, the layout of all generated
257    error messages can be changed in a second.</strong> (By
258    exploiting the features of XSSI, you can easily define
259    different layouts based on the current virtual host, or even
260    based on the client's domain name).</p>
261
262    <p>The second layout file describes the footer to be displayed
263    at the bottom of every error message. In this example, it shows
264    an apache logo, the current server time, the server version
265    string and adds a mail reference to the site's webmaster.</p>
266
267    <p>For simplicity, the header file is simply called
268    <code>head.shtml</code> because it contains server-parsed
269    content but no language specific information. The footer file
270    exists once for each language translation, plus a symlink for
271    the default language.</p>
272
273    <p><strong>Example:</strong> for English, French and German
274    versions (default english)<br />
275     <code>foot.shtml.en</code>,<br />
276     <code>foot.shtml.fr</code>,<br />
277     <code>foot.shtml.de</code>,<br />
278     <code>foot.shtml</code> symlink to
279    <code>foot.shtml.en</code></p>
280
281    <p>Both files are included into the error document by using the
282    directives <code>&lt;!--#include virtual="head" --&gt;</code>
283    and <code>&lt;!--#include virtual="foot" --&gt;</code>
284    respectively: the rest of the magic occurs in mod_negotiation
285    and in mod_include.</p>
286
287    <p>See <a href="#listings">the listings below</a> to see an
288    actual HTML implementation of the discussed example.</p>
289
290    <h3><a id="createdocs" name="createdocs">Creating
291    ErrorDocuments in different languages</a></h3>
292    After all this preparation work, little remains to be said
293    about the actual documents. They all share a simple common
294    structure:
295<pre>
296&lt;!--#set var="title" value="<em>error description title</em>" --&gt;
297&lt;!--#include virtual="head" --&gt;
298   <em>explanatory error text</em>
299&lt;!--#include virtual="foot" --&gt;
300</pre>
301    In the <a href="#listings">listings section</a>, you can see an
302    example of a [400 Bad Request] error document. Documents as
303    simple as that certainly cause no problems to translate or
304    expand.
305
306    <h3><a id="fallback" name="fallback">The fallback
307    language</a></h3>
308    Do we need a special handling for languages other than those we
309    have translations for? We did set the LanguagePriority, didn't
310    we?!
311
312    <p>Well, the LanguagePriority directive is for the case where
313    the client does not express any language priority at all. But
314    what happens in the situation where the client wants one of the
315    languages we do not have, and none of those we do have?</p>
316
317    <p>Without doing anything, the Apache server will usually
318    return a [406 no acceptable variant] error, listing the choices
319    from which the client may select. But we're in an error message
320    already, and important error information might get lost when
321    the client had to choose a language representation first.</p>
322
323    <p>So, in this situation it appears to be easier to define a
324    fallback language (by copying or linking, <em>e.g.</em>, the
325    english version to a language-less version). Because the
326    negotiation algorithm prefers "more specialized" variants over
327    "more generic" variants, these generic alternatives will only
328    be chosen when the normal negotiation did not succeed.</p>
329
330    <p>A simple shell script to do it (execute within the
331    errordocs/ dir):</p>
332<pre>
333  for f in *.shtml.en
334  do
335     ln -s $f `basename $f .en`
336  done
337</pre>
338
339    <h2><a id="proxy" name="proxy">Customizing Proxy Error
340    Messages</a></h2>
341
342    <p>As of Apache-1.3, it is possible to use the
343    <code>ErrorDocument</code> mechanism for proxy error messages
344    as well (previous versions always returned fixed predefined
345    error messages).</p>
346
347    <p>Most proxy errors return an error code of [500 Internal
348    Server Error]. To find out whether a particular error document
349    was invoked on behalf of a proxy error or because of some other
350    server error, and what the reason for the failure was, you can
351    check the contents of the new <code>ERROR_NOTES</code> CGI
352    environment variable: if invoked for a proxy error, this
353    variable will contain the actual proxy error message text in
354    HTML form.</p>
355
356    <p>The following excerpt demonstrates how to exploit the
357    <code>ERROR_NOTES</code> variable within an error document:</p>
358<pre>
359 &lt;!--#if expr="$REDIRECT_ERROR_NOTES = ''" --&gt;
360  &lt;p&gt;
361   The server encountered an unexpected condition
362   which prevented it from fulfilling the request.
363  &lt;/p&gt;
364  &lt;p&gt;
365   &lt;A HREF="mailto:&lt;!--#echo var="SERVER_ADMIN" --&gt;"
366    SUBJECT="Error message [&lt;!--#echo var="REDIRECT_STATUS" --&gt;] &lt;!--#echo var="title" --&gt; for &lt;!--#echo var="REQUEST_URI" --&gt;"&gt;
367   Please forward this error screen to &lt;!--#echo var="SERVER_NAME" --&gt;'s
368   WebMaster&lt;/A&gt;; it includes useful debugging information about
369   the Request which caused the error.
370   &lt;pre&gt;&lt;!--#printenv --&gt;&lt;/pre&gt;
371  &lt;/p&gt;
372 &lt;!--#else --&gt;
373  &lt;!--#echo var="REDIRECT_ERROR_NOTES" --&gt;
374 &lt;!--#endif --&gt;
375</pre>
376
377    <h2><a id="listings" name="listings">HTML listing of the
378    discussed example</a></h2>
379    So, to summarize our example, here's the complete listing of
380    the <samp>400.shtml.en</samp> document. You will notice that it
381    contains almost nothing but the error text (with conditional
382    additions). Starting with this example, you will find it easy
383    to add more error documents, or to translate the error
384    documents to different languages.
385    <hr />
386<pre>
387&lt;!--#set var="title" value="Bad Request"
388--&gt;&lt;!--#include virtual="head" --&gt;&lt;P&gt;
389   Your browser sent a request that this server could not understand:
390   &lt;BLOCKQUOTE&gt;
391     &lt;STRONG&gt;&lt;!--#echo var="REQUEST_URI" --&gt;&lt;/STRONG&gt;
392   &lt;/BLOCKQUOTE&gt;
393   The request could not be understood by the server due to malformed
394   syntax. The client should not repeat the request without
395   modifications.
396   &lt;/P&gt;
397   &lt;P&gt;
398   &lt;!--#if expr="$HTTP_REFERER != ''" --&gt;
399    Please inform the owner of
400    &lt;A HREF="&lt;!--#echo var="HTTP_REFERER" --&gt;"&gt;the referring page&lt;/A&gt; about
401    the malformed link.
402   &lt;!--#else --&gt;
403    Please check your request for typing errors and retry.
404   &lt;!--#endif --&gt;
405   &lt;/P&gt;
406&lt;!--#include virtual="foot" --&gt;
407</pre>
408    <hr />
409    Here is the complete <samp>head.shtml</samp> file (the funny
410    line breaks avoid empty lines in the document after XSSI
411    processing). Note the configuration section at top. That's
412    where you configure the images and logos as well as the apache
413    documentation directory. Look how this file displays two
414    different logos depending on the content of the virtual host
415    name ($SERVER_NAME), and that an animated apache logo is shown
416    if the browser appears to support it (the latter requires
417    server configuration lines of the form <br />
418     <code>BrowserMatch "^Mozilla/[2-4]" anigif</code><br />
419     for browser types which support animated GIFs).
420    <hr />
421<pre>
422&lt;!--#if expr="$SERVER_NAME = /.*\.mycompany\.com/"
423--&gt;&lt;!--#set var="IMG_CorpLogo"
424            value="http://$SERVER_NAME:$SERVER_PORT/errordocs/CorpLogo.gif"
425--&gt;&lt;!--#set var="ALT_CorpLogo" value="Powered by Linux!"
426--&gt;&lt;!--#else
427--&gt;&lt;!--#set var="IMG_CorpLogo"
428            value="http://$SERVER_NAME:$SERVER_PORT/errordocs/PrivLogo.gif"
429--&gt;&lt;!--#set var="ALT_CorpLogo" value="Powered by Linux!"
430--&gt;&lt;!--#endif
431--&gt;&lt;!--#set var="IMG_BgImage" value="http://$SERVER_NAME:$SERVER_PORT/errordocs/BgImage.gif"
432--&gt;&lt;!--#set var="DOC_Apache" value="http://$SERVER_NAME:$SERVER_PORT/Apache/"
433--&gt;&lt;!--#if expr="$anigif"
434--&gt;&lt;!--#set var="IMG_Apache" value="http://$SERVER_NAME:$SERVER_PORT/icons/apache_anim.gif"
435--&gt;&lt;!--#else
436--&gt;&lt;!--#set var="IMG_Apache" value="http://$SERVER_NAME:$SERVER_PORT/icons/apache_pb.gif"
437--&gt;&lt;!--#endif
438--&gt;&lt;!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"&gt;
439&lt;HTML&gt;
440 &lt;HEAD&gt;
441  &lt;TITLE&gt;
442   [&lt;!--#echo var="REDIRECT_STATUS" --&gt;] &lt;!--#echo var="title" --&gt;
443  &lt;/TITLE&gt;
444 &lt;/HEAD&gt;
445 &lt;BODY BGCOLOR="white" BACKGROUND="&lt;!--#echo var="IMG_BgImage" --&gt;"&gt;&lt;UL&gt;
446  &lt;H1 ALIGN="center"&gt;
447   [&lt;!--#echo var="REDIRECT_STATUS" --&gt;] &lt;!--#echo var="title" --&gt;
448   &lt;IMG SRC="&lt;!--#echo var="IMG_CorpLogo" --&gt;"
449        ALT="&lt;!--#echo var="ALT_CorpLogo" --&gt;" ALIGN=right&gt;
450  &lt;/H1&gt;
451  &lt;HR&gt;&lt;!-- ======================================================== --&gt;
452  &lt;DIV&gt;
453</pre>
454    <hr />
455    and this is the <samp>foot.shtml.en</samp> file:
456    <hr />
457<pre>
458  &lt;/DIV&gt;
459  &lt;HR&gt;
460  &lt;DIV ALIGN="right"&gt;&lt;SMALL&gt;&lt;SUP&gt;Local Server time:
461      &lt;!--#echo var="DATE_LOCAL" --&gt;
462  &lt;/SUP&gt;&lt;/SMALL&gt;&lt;/DIV&gt;
463  &lt;DIV ALIGN="center"&gt;
464    &lt;A HREF="&lt;!--#echo var="DOC_Apache" --&gt;"&gt;
465    &lt;IMG SRC="&lt;!--#echo var="IMG_Apache" --&gt;" BORDER=0 ALIGN="bottom"
466         ALT="Powered by &lt;!--#echo var="SERVER_SOFTWARE" --&gt;"&gt;&lt;/A&gt;&lt;BR&gt;
467    &lt;SMALL&gt;&lt;SUP&gt;&lt;!--#set var="var"
468     value="Powered by $SERVER_SOFTWARE -- File last modified on $LAST_MODIFIED"
469    --&gt;&lt;!--#echo var="var" --&gt;&lt;/SUP&gt;&lt;/SMALL&gt;
470  &lt;/DIV&gt;
471  &lt;ADDRESS&gt;If the indicated error looks like a misconfiguration, please inform
472   &lt;A HREF="mailto:&lt;!--#echo var="SERVER_ADMIN" --&gt;"
473      SUBJECT="Feedback about Error message [&lt;!--#echo var="REDIRECT_STATUS"
474        --&gt;] &lt;!--#echo var="title" --&gt;, req=&lt;!--#echo var="REQUEST_URI" --&gt;"&gt;
475   &lt;!--#echo var="SERVER_NAME" --&gt;'s WebMaster&lt;/A&gt;.
476  &lt;/ADDRESS&gt;
477 &lt;/UL&gt;&lt;/BODY&gt;
478&lt;/HTML&gt;
479</pre>
480    <hr />
481
482    <h3>More welcome!</h3>
483    If you have tips to contribute, send mail to <a
484    href="mailto:martin@apache.org">martin@apache.org</a>
485        <hr />
486
487    <h3 align="CENTER">Apache HTTP Server Version 1.3</h3>
488    <a href="./"><img src="../images/index.gif" alt="Index" /></a>
489    <a href="../"><img src="../images/home.gif" alt="Home" /></a>
490
491  </body>
492</html>
493
494