]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Error page auto-negotiation.
authorAmos Jeffries <squid3@treenet.co.nz>
Sat, 9 Aug 2008 05:59:55 +0000 (17:59 +1200)
committerAmos Jeffries <squid3@treenet.co.nz>
Sat, 9 Aug 2008 05:59:55 +0000 (17:59 +1200)
  * Converts error_directory squid.conf option into an optional override.
    Providing backward compatibility with older configurations and local
    customizations.

  * Adds error_default_language to administratively set the backup
    language presented by Squid.

  * Fixes design of previously broken hard-coded failover language.
    WAS: default to FreeBSD error install location. Hidden by
         error_directory being required.
    NOW: failover to build-time configured errors/ directory 'English'
         templates.

  * Adds --enable-auto-locale configure option to enable the following.

  * Adds logic to locate visitors most-preferred of available languages
    and present a tailored error page as their reply.

configure.in
doc/Makefile.am
doc/release-notes/release-3.1.sgml
errors/Makefile.am
src/Makefile.am
src/cache_cf.cc
src/cf.data.pre
src/defines.h
src/errorpage.cc
src/structs.h

index 048f073216f48bd0a91951fbe2d638230cd29159..98d03384d1486176a247c2f64ee95e062b9af3c1 100755 (executable)
@@ -30,6 +30,9 @@ AC_LANG_C
 AC_PROG_CXX
 AC_CANONICAL_HOST
 
+dnl Make location configure settings available to the code
+AC_DEFINE_UNQUOTED([DEFAULT_SQUID_CONFIG_DIR], "${sysconfdir}" , [Location of Configuration files] )
+AC_DEFINE_UNQUOTED([DEFAULT_SQUID_DATA_DIR], "${datadir}" , [Location of other data files] )
 
 use_loadable_modules=1
 AC_MSG_CHECKING(whether to use loadable modules)
@@ -1035,44 +1038,6 @@ AC_ARG_ENABLE(cache-digests,
   fi
 ])
 
-dnl Select Default Error language
-AC_ARG_ENABLE(default-err-language,
-[  --enable-default-err-language=lang
-                          Select default language for Error pages (see
-                          errors directory) ],
-[
-    if test -d $srcdir/errors/$enableval; then
-       ERR_DEFAULT_LANGUAGE=$enableval
-    else
-       echo "ERROR! Unknown language $enableval, see errors/ directory"
-       exit 1
-    fi
-],[ERR_DEFAULT_LANGUAGE="English"])
-AC_SUBST(ERR_DEFAULT_LANGUAGE)
-
-dnl Select languages to be installed
-AC_ARG_ENABLE(err-languages,
-[  --enable-err-languages=\"lang1 lang2..\"
-                          Select languages to be installed. (All will be
-                          installed by default) ],
-[
-    for l in $enableval; do
-        if test -d $srcdir/errors/$l; then :; else
-           echo "ERROR! Unknown language $$l, see errors/"
-           exit 1
-       fi
-    done
-    ERR_LANGUAGES=$enableval
-],[
-    ERR_LANGUAGES=
-    for l in $srcdir/errors/*; do
-        if test -f $l/ERR_ACCESS_DENIED; then
-            ERR_LANGUAGES="$ERR_LANGUAGES `basename $l`"
-       fi
-    done
-])
-AC_SUBST(ERR_LANGUAGES)
-
 dnl Size of COSS memory buffer
 AC_ARG_WITH(coss-membuf-size,
 [  --with-coss-membuf-size COSS membuf size (default 1048576 bytes) ],
@@ -3711,6 +3676,22 @@ AC_ARG_WITH(po2html,
 AC_SUBST(DO_TRANSLATE)
 
 
+dnl Squid now has limited locale handling ...
+dnl on error pages
+AC_ARG_ENABLE(auto-locale,
+[  --enable-auto-locale  This enables squid to lookup translated error pages
+                          based on the clients request headers. Without it squid
+                          is limited to a single language set in squid.conf],
+[ if test "$enableval" = "yes" ; then
+    echo "Enabling Multi-Language Support"
+    AC_DEFINE(USE_ERR_LOCALES,1,[Use multi-language support on error pages])
+ else
+    echo "Disabling Multi-Language Support"
+    AC_DEFINE(USE_ERR_LOCALES,0,[Use multi-language support on error pages])
+  fi
+])
+
+
 dnl Need the debugging version of malloc if available
 XTRA_OBJS=''
 if test "$ac_cv_lib_malloc_main" = "yes" ; then
index b20f8657a8bf67e459aa3cc06eb616894ab83791..54d7a053366e23a92c3cc72843900ab4bce77b91 100644 (file)
@@ -9,7 +9,7 @@
 DEFAULT_CONFIG_FILE = $(sysconfdir)/squid.conf
 DEFAULT_CACHEMGR_CONFIG = $(sysconfdir)/cachemgr.conf
 DEFAULT_MIME_TABLE      = $(sysconfdir)/mime.conf
-DEFAULT_ERROR_DIR       = $(datadir)/errors/@ERR_DEFAULT_LANGUAGE@
+DEFAULT_ERROR_DIR       = $(datadir)/errors
 
 SUBSTITUTE=sed "\
        s%@DEFAULT_CONFIG_FILE@%$(DEFAULT_CONFIG_FILE)%g;\
index 4a2384e4c61132681f4a435d1522ed0962ff59b7..ce56d6543091bc49ee9895053635a3c6504e48d2 100644 (file)
@@ -41,6 +41,7 @@ The most important of these new features are:
 \r
 <itemize>\r
        <item>IPv6 Support\r
+       <item>Error Page Localization\r
 </itemize>\r
 \r
 Most user-facing changes are reflected in squid.conf (see below).\r
@@ -107,6 +108,20 @@ Most user-facing changes are reflected in squid.conf (see below).
    with the RADIUS server. A new helper will be needed for IPv6 RADIUS protocol.\r
 \r
 \r
+<sect2>Error Page Localization\r
+<p>\r
+The error pages presented by squid may now be localized per-request to match the visitors local preferred language.\r
+\r
+<p>Squid needs to be build with the --enable-auto-locale option. And the error_directory option in squid.conf needs to be removed.\r
+\r
+<p>For best coverage of languages, using the latest language pack of error files is recommended.\r
+Updates can be downloaded from <url url="http://www.squid-cahch.org/Versions/langpack/" name="www.squid-cache.org/Versions/langpack/">\r
+\r
+<p>The squid developers are interested in making squid available in a wide variety of languages.\r
+   Contributions of new languages is encouraged.\r
+   Details at <url url="http://wiki.squid-cache.org/Translations" named="The Squid wiki">\r
+\r
+\r
 <sect1>Changes to squid.conf\r
 <p>\r
 There have been changes to Squid's configuration file since Squid-3.0.\r
@@ -166,6 +181,17 @@ This section gives a thorough account of those changes in three categories:
                include /path/to/file1 /path/to/file2\r
        </verb>\r
 \r
+        <tag>error_default_language</tag>\r
+        <p>New option to replace the old configure option --enable-default-err-language\r
+        <verb>\r
+        Set the default language which squid will send error pages in\r
+        if no existing translation matches the clients language\r
+        preferences.\r
+\r
+        If unset (default) generic English will be used.\r
+       </verb>\r
+\r
+\r
 </descrip>\r
 \r
 <sect2>Changes to existing tags<label id="modifiedtags">\r
@@ -247,6 +273,28 @@ This section gives a thorough account of those changes in three categories:
        <p>option 'transparent' is being deprecated in favour of 'intercept' which more clearly identifies what the option does.\r
        For now option 'tproxy' remains with old behaviour meaning fully-invisible proxy using TPROXY support.</p>\r
 \r
+       <tag>error_directory</tag>\r
+       <p>Now an optiona entry in squid.conf. If present it will force all visitors to receive the error pages\r
+       contained in the directory it points at. If absent error page localization will be given a chance.\r
+       <verb>\r
+        If you wish to create your own versions of the default\r
+        error files to customize them to suit your company copy\r
+        the error/template files to another directory and point\r
+        this tag at them.\r
+\r
+        WARNING: This option will disable multi-language support\r
+                 on error pages if used.\r
+\r
+        The squid developers are interested in making squid available in\r
+        a wide variety of languages. If you are making translations for a\r
+        language that Squid does not currently provide please consider\r
+        contributing your translation back to the project.\r
+        http://wiki.squid-cache.org/Translations\r
+\r
+        The squid developers working on translations are happy to supply drop-in\r
+        translated error files in exchange for any new language contributions.\r
+       </verb>\r
+\r
 </descrip>\r
 \r
 \r
@@ -303,6 +351,9 @@ This section gives an account of those changes in three categories:
           but please report the bugs anyway.\r
         </p>\r
 \r
+       <tag>--enable-auto-locale</tag>\r
+       <p>Enable error page localization for visitors.</p>\r
+\r
 </descrip>\r
 </p>\r
 \r
@@ -348,7 +399,10 @@ porting one of these from Squid-2 to Squid-3 is most welcome.
 <descrip>\r
        <tag>--enable-linux-tproxy</tag>\r
        <p>Replaced by --enable-linux-tproxy2 to make way for differences in TPROXY v2 and v4 support.</p>\r
-\r
+       <tag>--enable-default-err-language</tag>\r
+       <p>Replaced by error_default_language squid.conf option</p>\r
+       <tag>--enable-err-languages</tag>\r
+       <p>Removed.</p>\r
 </descrip>\r
 \r
 </article>\r
index 34364f696f73672f71b6c58c0b74e14474d9d114..22f8c00ab67e7bd62aa87976adcaa81ef69ca026 100644 (file)
@@ -19,7 +19,6 @@ TRANSLATIONS = \
 
 # Legacy language contributions...
 #
-INSTALL_LANGUAGES      = @ERR_LANGUAGES@
 LANGUAGES      = \
                Armenian \
                Azerbaijani \
@@ -54,7 +53,7 @@ LANGUAGES     = \
                Ukrainian-utf8
 
 install-data-local: 
-       @for l in $(INSTALL_LANGUAGES); do \
+       @for l in $(LANGUAGES); do \
                $(mkinstalldirs) $(DESTDIR)$(DEFAULT_ERROR_DIR)/$$l && \
                for f in $(srcdir)/$$l/ERR_*; do \
                        echo "$(INSTALL_DATA) $$f $(DESTDIR)$(DEFAULT_ERROR_DIR)/$$l"; \
@@ -72,7 +71,7 @@ install-data-local:
        done
 
 uninstall-local:
-       @ for l in $(INSTALL_LANGUAGES); do \
+       @ for l in $(LANGUAGES); do \
                for f in $(srcdir)/$$l/ERR_*; do \
                        rm -f $(DESTDIR)$(DEFAULT_ERROR_DIR)/$$l/`basename $$f`; \
                done; \
index 6b25ca4698f5d9a541a9fe28510cef2eaa3a3cb5..ced768254b3279191dc4ac72c370fc90c170645a 100644 (file)
@@ -1053,7 +1053,7 @@ DEFAULT_PINGER            = $(libexecdir)/`echo pinger | sed '$(transform);s/$$/$(EXEEXT)/
 DEFAULT_UNLINKD                = $(libexecdir)/`echo unlinkd | sed '$(transform);s/$$/$(EXEEXT)/'`
 DEFAULT_DISKD          = $(libexecdir)/`echo diskd | sed '$(transform);s/$$/$(EXEEXT)/'`
 DEFAULT_ICON_DIR       = $(datadir)/icons
-DEFAULT_ERROR_DIR      = $(datadir)/errors/@ERR_DEFAULT_LANGUAGE@
+DEFAULT_ERROR_DIR      = $(datadir)/errors
 DEFAULT_MIB_PATH       = $(datadir)/mib.txt
 DEFAULT_HOSTS          = @OPT_DEFAULT_HOSTS@
 
@@ -1090,7 +1090,7 @@ cf_gen_defines.h: $(srcdir)/cf_gen_defines $(srcdir)/cf.data.pre
 
 
 ## FIXME: generate a sed command file from configure. Then this doesn't
-## depend on the Makefile. 
+## depend on the Makefile.
 cf.data: cf.data.pre Makefile
        sed "\
        s%@DEFAULT_HTTP_PORT@%$(DEFAULT_HTTP_PORT)%g;\
index 60ae59b223351a9d3e00b765bff7d5d239bb9e2d..82d1ec5244183d0d282aa3db04a510553db84762 100644 (file)
@@ -522,7 +522,8 @@ configDoConfigure(void)
 
     requirePathnameExists("Icon Directory", Config.icons.directory);
 
-    requirePathnameExists("Error Directory", Config.errorDirectory);
+    if(Config.errorDirectory)
+        requirePathnameExists("Error Directory", Config.errorDirectory);
 
 #if HTTP_VIOLATIONS
 
index 2b6868515ff2aa64fd58d0a43d7073f3fe92d001..086e1b71df3f556d969931d4e30cb6e289d7fd6f 100644 (file)
@@ -4712,17 +4712,42 @@ COMMENT_END
 NAME: error_directory
 TYPE: string
 LOC: Config.errorDirectory
-DEFAULT: @DEFAULT_ERROR_DIR@
+DEFAULT: none
 DOC_START
        If you wish to create your own versions of the default
-       (English) error files, either to customize them to suit your
-       language or company copy the template English files to another
-       directory and point this tag at them.
+       error files to customize them to suit your company copy
+       the error/template files to another directory and point
+       this tag at them.
+
+       WARNING: This option will disable multi-language support
+                on error pages if used.
 
        The squid developers are interested in making squid available in
        a wide variety of languages. If you are making translations for a
-       langauge that Squid does not currently provide please consider
+       language that Squid does not currently provide please consider
        contributing your translation back to the project.
+       http://wiki.squid-cache.org/Translations
+
+       The squid developers working on translations are happy to supply drop-in
+       translated error files in exchange for any new language contributions.
+DOC_END
+
+NAME: error_default_language
+IFDEF: USE_ERR_LOCALES
+TYPE: string
+LOC: Config.errorDefaultLanguage
+DEFAULT: none
+DOC_START
+       Set the default language which squid will send error pages in
+       if no existing translation matches the clients language
+       preferences.
+
+       If unset (default) generic English will be used.
+
+       The squid developers are interested in making squid available in
+       a wide variety of languages. If you are interested in making
+       translations for any language see the squid wiki for details.
+       http://wiki.squid-cache.org/Translations
 DOC_END
 
 NAME: err_html_text
@@ -4759,7 +4784,7 @@ DEFAULT: none
 DOC_START
        Usage:   deny_info err_page_name acl
        or       deny_info http://... acl
-       Example: deny_info ERR_CUSTOM_ACCESS_DENIED bad_guys
+       or       deny_info TCP_RESET acl
 
        This can be used to return a ERR_ page for requests which
        do not pass the 'http_access' rules.  Squid remembers the last
@@ -4773,8 +4798,9 @@ DOC_START
        - When none of the http_access lines matches. It's then the last
          acl processed on the last http_access line.
 
-       You may use ERR_ pages that come with Squid or create your own pages
-       and put them into the configured errors/ directory.
+       NP: If providing your own custom error pages with error_directory
+           you may also specify them by your custom file name:
+           Example: deny_info ERR_CUSTOM_ACCESS_DENIED bad_guys
 
        Alternatively you can specify an error URL. The browsers will
        get redirected (302) to the specified URL. %s in the redirection
index f5dcaf88635ac55ba91e60ba2dbaeb00b37a4bbd..ae1c701c3cc563de232904979f76892534be8521 100644 (file)
  */
 #define N_COUNT_HOUR_HIST (86400 * 3) / (60 * COUNT_INTERVAL)
 
-/* were to look for errors if config path fails */
-#ifndef DEFAULT_SQUID_ERROR_DIR
-#define DEFAULT_SQUID_ERROR_DIR "/usr/local/squid/etc/errors"
-#endif
-
 /* handy to determine the #elements in a static array */
 #define countof(arr) (sizeof(arr)/sizeof(*arr))
 
index 91b7b6dd21bd65bcd82419408e4366355836051c..dc861135f405d6b25fe36758be2254e6e31f7553 100644 (file)
  */
 
 
+#ifndef DEFAULT_SQUID_ERROR_DIR
+/** Where to look for errors if config path fails.
+ \note Please use ./configure --datadir=/path instead of patching
+ */
+#define DEFAULT_SQUID_ERROR_DIR   DEFAULT_SQUID_DATA_DIR"/errors"
+#endif
+
 /// \ingroup ErrorPageInternal
 CBDATA_CLASS_INIT(ErrorState);
 
@@ -115,7 +122,7 @@ static char **error_text = NULL;
 /// \ingroup ErrorPageInternal
 static int error_page_count = 0;
 
-static char *errorTryLoadText(const char *page_name, const char *dir);
+static char *errorTryLoadText(const char *page_name, const char *dir, bool silent = false);
 static char *errorLoadText(const char *page_name);
 static const char *errorFindHardText(err_type type);
 static ErrorDynamicPageInfo *errorDynamicPageInfoCreate(int id, const char *page_name);
@@ -147,20 +154,30 @@ errorInitialize(void)
 
     for (i = ERR_NONE, ++i; i < error_page_count; ++i) {
         safe_free(error_text[i]);
-        /* hard-coded ? */
 
-        if ((text = errorFindHardText(i)))
+        if ((text = errorFindHardText(i))) {
+            /**\par
+             * Index any hard-coded error text into defaults.
+             */
             error_text[i] = xstrdup(text);
-        else if (i < ERR_MAX) {
-            /* precompiled ? */
+
+        } else if (i < ERR_MAX) {
+            /**\par
+             * Index precompiled fixed template files from one of two sources:
+             *  (a) default language translation directory (error_default_language)
+             *  (b) admin specified custom directory (error_directory)
+             */
             error_text[i] = errorLoadText(err_type_str[i]);
+
         } else {
-            /* dynamic */
+            /** \par
+             * Index any unknown file names used by deny_info.
+             */
             ErrorDynamicPageInfo *info = ErrorDynamicPages.items[i - ERR_MAX];
             assert(info && info->id == i && info->page_name);
 
             if (strchr(info->page_name, ':') == NULL) {
-                /* Not on redirected errors... */
+                /** But only if they are not redirection URL. */
                 error_text[i] = errorLoadText(info->page_name);
             }
         }
@@ -198,17 +215,38 @@ errorFindHardText(err_type type)
     return NULL;
 }
 
-
-/// \ingroup ErrorPageInternal
+/**
+ * \ingroup ErrorPageInternal
+ *
+ * Load into the in-memory error text Index a file probably available at:
+ *  (a) admin specified custom directory (error_directory)
+ *  (b) default language translation directory (error_default_language)
+ *  (c) English sub-directory where errors should ALWAYS exist
+ */
 static char *
 errorLoadText(const char *page_name)
 {
-    /* test configured location */
-    char *text = errorTryLoadText(page_name, Config.errorDirectory);
-    /* test default location if failed */
+    char *text = NULL;
+
+    /** test error_directory configured location */
+    if(Config.errorDirectory)
+        text = errorTryLoadText(page_name, Config.errorDirectory);
+
+#if USE_ERR_LOCALES
+    /** test error_default_language location */
+    if(!text && Config.errorDefaultLanguage) {
+        char dir[256];
+        snprintf(dir,256,"%s/%s", DEFAULT_SQUID_ERROR_DIR, Config.errorDefaultLanguage);
+        text = errorTryLoadText(page_name, dir);
+        if(!text) {
+            debugs(1, DBG_CRITICAL, "Unable to load default language. Reset to English");
+        }
+    }
+#endif
 
-    if (!text && strcmp(Config.errorDirectory, DEFAULT_SQUID_ERROR_DIR))
-        text = errorTryLoadText(page_name, DEFAULT_SQUID_ERROR_DIR);
+    /* test default location if failed (templates == English translation base templates) */
+    if (!text)
+        text = errorTryLoadText(page_name, DEFAULT_SQUID_ERROR_DIR"/templates");
 
     /* giving up if failed */
     if (!text)
@@ -219,7 +257,7 @@ errorLoadText(const char *page_name)
 
 /// \ingroup ErrorPageInternal
 static char *
-errorTryLoadText(const char *page_name, const char *dir)
+errorTryLoadText(const char *page_name, const char *dir, bool silent)
 {
     int fd;
     char path[MAXPATHLEN];
@@ -232,7 +270,9 @@ errorTryLoadText(const char *page_name, const char *dir)
     fd = file_open(path, O_RDONLY | O_TEXT);
 
     if (fd < 0) {
-        debugs(4, 0, "errorTryLoadText: '" << path << "': " << xstrerror());
+        /* with dynamic locale negotiation we may see some failures before a success. */
+        if(!silent)
+            debugs(4, DBG_CRITICAL, HERE << "'" << path << "': " << xstrerror());
         return NULL;
     }
 
@@ -821,13 +861,88 @@ MemBuf *
 ErrorState::BuildContent()
 {
     MemBuf *content = new MemBuf;
-    const char *m;
+    const char *m = NULL;
     const char *p;
     const char *t;
+
     assert(page_id > ERR_NONE && page_id < error_page_count);
-    content->init();
-    m = error_text[page_id];
+
+#if USE_ERR_LOCALES
+    String hdr;
+    char dir[256];
+    int l = 0;
+
+    /** error_directory option in squid.conf overrides translations.
+     * Otherwise locate the Accept-Language header
+     */
+    if(!Config.errorDirectory && request->header.getList(HDR_ACCEPT_LANGUAGE, &hdr) ) {
+
+        const char *buf = hdr.buf(); // raw header string for parsing
+        int pos = 0; // current parsing position in header string
+        char *reset = NULL; // where to reset the p pointer for each new tag file
+        char *dt = NULL;
+
+        /* prep the directory path string to prevent snprintf ... */
+        l = strlen(DEFAULT_SQUID_ERROR_DIR);
+        memcpy(dir, DEFAULT_SQUID_ERROR_DIR, l);
+        dir[ l++ ] = '/';
+        reset = dt = dir + l;
+
+        debugs(4, 6, HERE << "Testing Header: '" << hdr << "'");
+
+        while( pos < hdr.size() ) {
+
+/*
+ * Header value format:
+ *  - sequence of whitespace delimited tags
+ *  - each tag may suffix with ';'.* which we can ignore.
+ *  - IFF a tag contains only two characters we can wildcard ANY translations matching: <it> '-'? .*
+ *    with preference given to an exact match.
+ */
+            while(pos < hdr.size() && buf[pos] != ';' && buf[pos] != ',' && !xisspace(buf[pos]) && dt < (dir+256) ) {
+                *dt++ = xtolower(buf[pos++]);
+            }
+            *dt++ = '\0'; // nul-terminated the filename content string before system use.
+
+            debugs(4, 9, HERE << "STATE: dt='" << dt << "', reset='" << reset << "', reset[1]='" << reset[1] << "', pos=" << pos << ", buf='" << &buf[pos] << "'");
+
+            /* if we found anything we might use, try it. */
+            if(*reset != '\0') {
+
+                debugs(4, 6, HERE << "Found language '" << reset << "', testing for available template in: '" << dir << "'");
+                m = errorTryLoadText( err_type_str[page_id], dir, false);
+
+                if(m) break; // FOUND IT!!
+
+#if HAVE_GLOB
+                if( (dt - reset) == 2) {
+                    /* TODO glob the error directory for sub-dirs matching: <tag> '-*'   */
+                    /* use first result. */
+                    debugs(4,2, HERE << "wildcard fallback errors not coded yet.");
+                }
+#endif
+            }
+
+            dt = reset; // reset for next tag testing. we replace the failed name instead of cloning.
+
+            // IFF we terminated the tag on ';' we need to skip the 'q=' bit to the next ',' or end.
+            while(pos < hdr.size() && buf[pos] != ',') pos++;
+            if(buf[pos] == ',') pos++;
+        }
+    }
+#endif /* USE_ERR_LOCALES */
+
+    /** \par
+     * If client-specific error templates are not enabled or available.
+     * fall back to the old style squid.conf settings.
+     */
+    if(!m) {
+        m = error_text[page_id];
+        debugs(4, 1, HERE << "No existing languages found. Fall back on default language.");
+    }
+
     assert(m);
+    content->init();
 
     while ((p = strchr(m, '%'))) {
         content->append(m, p - m);     /* copy */
index 852d3a2fd33c2076e34d018f3e9c145a8a383501..3ddfa8e5358f6a21f4fca34bed8e3e70d43314cb 100644 (file)
@@ -549,6 +549,9 @@ struct SquidConfig
         int use_short_names;
     } icons;
     char *errorDirectory;
+#if USE_ERR_LOCALES
+    char *errorDefaultLanguage;
+#endif
 
     struct
     {