]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/errorpage.cc
SourceFormat: enforcement
[thirdparty/squid.git] / src / errorpage.cc
index 4d0ec4317b9adb369b89697cf2abfe727fb40d89..b5d039d33ed8b5f39aaae0b2c146bb0b5d3bea96 100644 (file)
@@ -35,7 +35,7 @@
 #include "config.h"
 
 #include "errorpage.h"
-#include "AuthUserRequest.h"
+#include "auth/UserRequest.h"
 #include "SquidTime.h"
 #include "Store.h"
 #include "HttpReply.h"
@@ -469,7 +469,7 @@ errorSend(int fd, ErrorState * err)
  * to the client socket.
  *
  \note If there is a callback, the callback is responsible for
- *     closeing the FD, otherwise we do it ourseves.
+ *     closing the FD, otherwise we do it ourselves.
  */
 static void
 errorSendComplete(int fd, char *bufnotused, size_t size, comm_err_t errflag, int xerrno, void *data)
@@ -496,7 +496,6 @@ errorStateFree(ErrorState * err)
     HTTPMSGUNLOCK(err->request);
     safe_free(err->redirect_url);
     safe_free(err->url);
-    safe_free(err->dnsserver_msg);
     safe_free(err->request_hdrs);
     wordlistDestroy(&err->ftp.server_msg);
     safe_free(err->ftp.request);
@@ -536,9 +535,8 @@ ErrorState::Dump(MemBuf * mb)
     if (auth_user_request->denyMessage())
         str.Printf("Auth ErrMsg: %s\r\n", auth_user_request->denyMessage());
 
-    if (dnsserver_msg) {
-        str.Printf("DNS Server ErrMsg: %s\r\n", dnsserver_msg);
-    }
+    if (dnsError.size() > 0)
+        str.Printf("DNS ErrMsg: %s\r\n", dnsError.termedBuf());
 
     /* - TimeStamp */
     str.Printf("TimeStamp: %s\r\n\r\n", mkrfc1123(squid_curtime));
@@ -546,7 +544,7 @@ ErrorState::Dump(MemBuf * mb)
     /* - IP stuff */
     str.Printf("ClientIP: %s\r\n", src_addr.NtoA(ntoabuf,MAX_IPSTRLEN));
 
-    if (request && request->hier.host) {
+    if (request && request->hier.host[0] != '\0') {
         str.Printf("ServerIP: %s\r\n", request->hier.host);
     }
 
@@ -556,9 +554,16 @@ ErrorState::Dump(MemBuf * mb)
 
     if (NULL != request) {
         Packer p;
-        str.Printf("%s %s HTTP/%d.%d\n",
+        String urlpath_or_slash;
+
+        if (request->urlpath.size() != 0)
+            urlpath_or_slash = request->urlpath;
+        else
+            urlpath_or_slash = "/";
+
+        str.Printf("%s " SQUIDSTRINGPH " HTTP/%d.%d\n",
                    RequestMethodStr(request->method),
-                   request->urlpath.size() ? request->urlpath.unsafeBuf() : "/",
+                   SQUIDSTRINGPRINT(urlpath_or_slash),
                    request->http_ver.major, request->http_ver.minor);
         packerToMemInit(&p, &str);
         request->header.packInto(&p);
@@ -661,12 +666,11 @@ ErrorState::Convert(char token)
 
     case 'h':
         mb.Printf("%s", getMyHostname());
-
         break;
 
     case 'H':
         if (request) {
-            if (request->hier.host)
+            if (request->hier.host[0] != '\0') // if non-empty string.
                 p = request->hier.host;
             else
                 p = request->GetHost();
@@ -681,9 +685,9 @@ ErrorState::Convert(char token)
         break;
 
     case 'I':
-        if (request && request->hier.host) {
+        if (request && request->hier.host[0] != '\0') // if non-empty string
             mb.Printf("%s", request->hier.host);
-        else
+        else
             p = "[unknown]";
 
         break;
@@ -734,9 +738,16 @@ ErrorState::Convert(char token)
 
         if (NULL != request) {
             Packer p;
-            mb.Printf("%s %s HTTP/%d.%d\n",
+            String urlpath_or_slash;
+
+            if (request->urlpath.size() != 0)
+                urlpath_or_slash = request->urlpath;
+            else
+                urlpath_or_slash = "/";
+
+            mb.Printf("%s " SQUIDSTRINGPH " HTTP/%d.%d\n",
                       RequestMethodStr(request->method),
-                      request->urlpath.size() ? request->urlpath.unsafeBuf() : "/",
+                      SQUIDSTRINGPRINT(urlpath_or_slash),
                       request->http_ver.major, request->http_ver.minor);
             packerToMemInit(&p, &mb);
             request->header.packInto(&p);
@@ -781,7 +792,9 @@ ErrorState::Convert(char token)
         break;
 
     case 'U':
-        p = request ? urlCanonicalClean(request) : url ? url : "[no URL]";
+        /* Using the fake-https version of canonical so error pages see https:// */
+        /* even when the url-path cannot be shown as more than '*' */
+        p = request ? urlCanonicalFakeHttps(request) : url ? url : "[no URL]";
         break;
 
     case 'u':
@@ -804,8 +817,8 @@ ErrorState::Convert(char token)
         break;
 
     case 'z':
-        if (dnsserver_msg)
-            p = dnsserver_msg;
+        if (dnsError.size() > 0)
+            p = dnsError.termedBuf();
         else
             p = "[unknown]";
 
@@ -855,7 +868,7 @@ ErrorState::BuildHttpReply()
 
     if (strchr(name, ':')) {
         /* Redirection */
-        rep->setHeaders(version, HTTP_MOVED_TEMPORARILY, NULL, "text/html", 0, 0, squid_curtime);
+        rep->setHeaders(version, HTTP_MOVED_TEMPORARILY, NULL, "text/html", 0, 0, -1);
 
         if (request) {
             char *quoted_url = rfc1738_escape_part(urlCanonical(request));
@@ -865,7 +878,7 @@ ErrorState::BuildHttpReply()
         httpHeaderPutStrf(&rep->header, HDR_X_SQUID_ERROR, "%d %s", httpStatus, "Access Denied");
     } else {
         MemBuf *content = BuildContent();
-        rep->setHeaders(version, httpStatus, NULL, "text/html", content->contentSize(), 0, squid_curtime);
+        rep->setHeaders(version, httpStatus, NULL, "text/html", content->contentSize(), 0, -1);
         /*
          * include some information for downstream caches. Implicit
          * replaceable content. This isn't quite sufficient. xerrno is not
@@ -928,8 +941,7 @@ ErrorState::BuildContent()
      */
     if (!Config.errorDirectory && request && request->header.getList(HDR_ACCEPT_LANGUAGE, &hdr) ) {
 
-        const char *unsafeBuf = hdr.unsafeBuf(); // raw header string for parsing
-        int pos = 0; // current parsing position in header string
+        size_t 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;
 
@@ -943,6 +955,9 @@ ErrorState::BuildContent()
 
         while ( pos < hdr.size() ) {
 
+            /* skip any initial whitespace. */
+            while (pos < hdr.size() && xisspace(hdr[pos])) pos++;
+
             /*
              * Header value format:
              *  - sequence of whitespace delimited tags
@@ -950,17 +965,43 @@ ErrorState::BuildContent()
              *  - 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() && unsafeBuf[pos] != ';' && unsafeBuf[pos] != ',' && !xisspace(unsafeBuf[pos]) && dt < (dir+256) ) {
-                *dt++ = xtolower(unsafeBuf[pos++]);
+            bool invalid_byte = false;
+            while (pos < hdr.size() && hdr[pos] != ';' && hdr[pos] != ',' && !xisspace(hdr[pos]) && dt < (dir+256) ) {
+                if (!invalid_byte) {
+#if HTTP_VIOLATIONS
+                    // if accepting violations we may as well accept some broken browsers
+                    //  which may send us the right code, wrong ISO formatting.
+                    if (hdr[pos] == '_')
+                        *dt = '-';
+                    else
+#endif
+                        *dt = xtolower(hdr[pos]);
+                    // valid codes only contain A-Z, hyphen (-) and *
+                    if (*dt != '-' && *dt != '*' && (*dt < 'a' || *dt > 'z') )
+                        invalid_byte = true;
+                    else
+                        dt++; // move to next destination byte.
+                }
+                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='" << &unsafeBuf[pos] << "'");
+            debugs(4, 9, HERE << "STATE: dt='" << dt << "', reset='" << reset << "', pos=" << pos << ", buf='" << ((pos < hdr.size()) ? hdr.substr(pos,hdr.size()) : "") << "'");
 
             /* if we found anything we might use, try it. */
-            if (*reset != '\0') {
+            if (*reset != '\0' && !invalid_byte) {
+
+                /* wildcard uses the configured default language */
+                if (reset[0] == '*' && reset[1] == '\0') {
+                    debugs(4, 6, HERE << "Found language '" << reset << "'. Using configured default.");
+                    m = error_text[page_id];
+                    if (!Config.errorDirectory)
+                        err_language = Config.errorDefaultLanguage;
+                    break;
+                }
 
                 debugs(4, 6, HERE << "Found language '" << reset << "', testing for available template in: '" << dir << "'");
+
                 m = errorTryLoadText( err_type_str[page_id], dir, false);
 
                 if (m) {
@@ -982,9 +1023,9 @@ ErrorState::BuildContent()
 
             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() && unsafeBuf[pos] != ',') pos++;
-            if (unsafeBuf[pos] == ',') pos++;
+            // IFF we terminated the tag on whitespace or ';' we need to skip to the next ',' or end of header.
+            while (pos < hdr.size() && hdr[pos] != ',') pos++;
+            if (hdr[pos] == ',') pos++;
         }
     }
 #endif /* USE_ERR_LOCALES */