=== modified file 'src/cf.data.pre' --- src/cf.data.pre 2010-11-18 08:01:53 +0000 +++ src/cf.data.pre 2010-11-23 10:33:18 +0000 @@ -5917,12 +5917,18 @@ you may also specify them by your custom file name: Example: deny_info ERR_CUSTOM_ACCESS_DENIED bad_guys + By defaut Squid will send "403 Forbidden". A different 4xx or 5xx + may be specified by prefixing the file name with the code and a colon. + e.g. 404:ERR_CUSTOM_ACCESS_DENIED + Alternatively you can tell Squid to reset the TCP connection by specifying TCP_RESET. Or you can specify an error URL or URL pattern. The browsers will - get redirected (302) to the specified URL after formatting tags have - been replaced. + get redirected to the specified URL after formatting tags have + been replaced. Redirect will be done with 302 or 307 according to + HTTP/1.1 specs. A different 3xx code may be specified by prefixing + the URL. e.g. 303:http://example.com/ URL FORMAT TAGS: %a - username (if available. Password NOT included) === modified file 'src/errorpage.cc' --- src/errorpage.cc 2010-11-01 05:44:28 +0000 +++ src/errorpage.cc 2010-11-23 10:21:30 +0000 @@ -76,6 +76,7 @@ typedef struct { int id; char *page_name; + http_status page_redirect; } ErrorDynamicPageInfo; /* local constant and vars */ @@ -179,9 +180,13 @@ ErrorDynamicPageInfo *info = ErrorDynamicPages.items[i - ERR_MAX]; assert(info && info->id == i && info->page_name); - if (strchr(info->page_name, ':') == NULL) { + const char *pg = info->page_name; + if (info->page_redirect != HTTP_STATUS_NONE) + pg = info->page_name +4; + + if (strchr(pg, ':') == NULL) { /** But only if they are not redirection URL. */ - error_text[i] = errorLoadText(info->page_name); + error_text[i] = errorLoadText(pg); } } } @@ -325,6 +330,24 @@ ErrorDynamicPageInfo *info = new ErrorDynamicPageInfo; info->id = id; info->page_name = xstrdup(page_name); + info->page_redirect = static_cast(atoi(page_name)); + if (info->page_redirect == HTTP_STATUS_NONE) + ; // special case okay. + else if (info->page_redirect < 300 || info->page_redirect > 599) { + // out of range + debugs(0, DBG_CRITICAL, "FATAL: status " << info->page_redirect << " is not valid on '" << page_name << "'"); + self_destruct(); + } else if (/* >= 300 && */ info->page_redirect <= 399 && !strchr(&(page_name[4]), ':')) { + // 3xx require an absolute URL + debugs(0, DBG_CRITICAL, "FATAL: status " << info->page_redirect << " is not valid on '" << page_name << "'"); + self_destruct(); + } else if (info->page_redirect >= 400 /* && <= 599 */ && strchr(&(page_name[4]), ':')) { + // 4xx/5xx require a local template file + debugs(0, DBG_CRITICAL, "FATAL: status " << info->page_redirect << " is not valid on '" << page_name << "'"); + self_destruct(); + } + // else okay. + return info; } @@ -390,6 +413,8 @@ err->err_language = NULL; err->type = type; err->httpStatus = status; + if (err->page_id >= ERR_MAX && ErrorDynamicPages.items[err->page_id - ERR_MAX]->page_redirect != HTTP_STATUS_NONE) + err->httpStatus = ErrorDynamicPages.items[err->page_id - ERR_MAX]->page_redirect; if (request != NULL) { err->request = HTTPMSGLOCK(request); @@ -894,6 +919,9 @@ char const *p = m; char const *t; + if (m[0] == '3') + m += 4; // skip "3xx:" + while ((p = strchr(m, '%'))) { result.append(m, p - m); /* copy */ t = Convert(*++p, true); /* convert */ @@ -914,9 +942,19 @@ const char *name = errorPageName(page_id); /* no LMT for error pages; error pages expire immediately */ - if (strchr(name, ':')) { + if (name[0] == '3' || (name[0] != '4' && name[0] != '5' && strchr(name, ':'))) { /* Redirection */ - rep->setHeaders(HTTP_MOVED_TEMPORARILY, NULL, "text/html", 0, 0, -1); + http_status status = HTTP_MOVED_TEMPORARILY; + // Use configured 3xx reply status if set. + if (name[0] == '3') + status = httpStatus; + else { + // Use 307 for HTTP/1.1 non-GET/HEAD requests. + if (request->method != METHOD_GET && request->method != METHOD_HEAD && request->http_ver >= HttpVersion(1,1)) + status = HTTP_TEMPORARY_REDIRECT; + } + + rep->setHeaders(status, NULL, "text/html", 0, 0, -1); if (request) { MemBuf redirect_location;