/*
- * DEBUG: section 04 Error Generation
- * AUTHOR: Duane Wessels
- *
- * SQUID Web Proxy Cache http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- * Squid is the result of efforts by numerous individuals from
- * the Internet community; see the CONTRIBUTORS file for full
- * details. Many organizations have provided support for Squid's
- * development; see the SPONSORS file for full details. Squid is
- * Copyrighted (C) 2001 by the Regents of the University of
- * California; see the COPYRIGHT file for full details. Squid
- * incorporates software developed and/or copyrighted by other
- * sources; see the CREDITS file for full details.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
*
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
*/
+
+/* DEBUG: section 04 Error Generation */
+
#include "squid.h"
#include "cache_cf.h"
+#include "clients/forward.h"
#include "comm/Connection.h"
#include "comm/Write.h"
#include "disk.h"
#include "err_detail_type.h"
#include "errorpage.h"
-#include "ftp.h"
-#include "Store.h"
+#include "fde.h"
#include "html_quote.h"
#include "HttpHeaderTools.h"
#include "HttpReply.h"
#include "HttpRequest.h"
-#include "MemObject.h"
-#include "fde.h"
#include "MemBuf.h"
+#include "MemObject.h"
#include "rfc1738.h"
#include "SquidConfig.h"
-#include "URL.h"
-#include "URLScheme.h"
-#include "URL.h"
+#include "Store.h"
#include "tools.h"
+#include "URL.h"
#include "wordlist.h"
#if USE_AUTH
#include "auth/UserRequest.h"
#endif
#include "SquidTime.h"
-#if USE_SSL
+#if USE_OPENSSL
#include "ssl/ErrorDetailManager.h"
#endif
typedef struct {
int id;
char *page_name;
- http_status page_redirect;
+ Http::StatusCode page_redirect;
} ErrorDynamicPageInfo;
/* local constant and vars */
* automagically to give you more control on the format
*/
static const struct {
- int type; /* and page_id */
+ int type; /* and page_id */
const char *text;
}
};
/// \ingroup ErrorPageInternal
-static Vector<ErrorDynamicPageInfo *> ErrorDynamicPages;
+static std::vector<ErrorDynamicPageInfo *> ErrorDynamicPages;
/* local prototypes */
class ErrorPageFile: public TemplateFile
{
public:
- ErrorPageFile(const char *name, const err_type code): TemplateFile(name,code) { textBuf.init();}
+ ErrorPageFile(const char *name, const err_type code) : TemplateFile(name,code) {textBuf.init();}
/// The template text data read from disk
const char *text() { return textBuf.content(); }
private:
/// stores the data read from disk to a local buffer
- virtual bool parse(const char *buf, int len, bool eof) {
+ virtual bool parse(const char *buf, int len, bool) {
if (len)
textBuf.append(buf, len);
return true;
/** \par
* Index any unknown file names used by deny_info.
*/
- ErrorDynamicPageInfo *info = ErrorDynamicPages.items[i - ERR_MAX];
+ ErrorDynamicPageInfo *info = ErrorDynamicPages.at(i - ERR_MAX);
assert(info && info->id == i && info->page_name);
const char *pg = info->page_name;
- if (info->page_redirect != HTTP_STATUS_NONE)
+ if (info->page_redirect != Http::scNone)
pg = info->page_name +4;
if (strchr(pg, ':') == NULL) {
error_stylesheet.Printf("%s",tmpl.text());
}
-#if USE_SSL
+#if USE_OPENSSL
Ssl::errorDetailInitialize();
#endif
}
safe_free(error_text);
}
- while (ErrorDynamicPages.size())
- errorDynamicPageInfoDestroy(ErrorDynamicPages.pop_back());
+ while (!ErrorDynamicPages.empty()) {
+ errorDynamicPageInfoDestroy(ErrorDynamicPages.back());
+ ErrorDynamicPages.pop_back();
+ }
error_page_count = 0;
-#if USE_SSL
+#if USE_OPENSSL
Ssl::errorDetailClean();
#endif
}
while (pos < hdr.size()) {
char *dt = lang;
- if (!pos) {
- /* skip any initial whitespace. */
- while (pos < hdr.size() && xisspace(hdr[pos]))
- ++pos;
- } else {
- // 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;
- }
+ /* skip any initial whitespace. */
+ while (pos < hdr.size() && xisspace(hdr[pos]))
+ ++pos;
/*
* Header value format:
*dt = '\0'; // nul-terminated the filename content string before system use.
++dt;
+ // if we terminated the tag on garbage or ';' we need to skip to the next ',' or end of header.
+ while (pos < hdr.size() && hdr[pos] != ',')
+ ++pos;
+
+ if (pos < hdr.size() && hdr[pos] == ',')
+ ++pos;
+
debugs(4, 9, HERE << "STATE: dt='" << dt << "', lang='" << lang << "', pos=" << pos << ", buf='" << ((pos < hdr.size()) ? hdr.substr(pos,hdr.size()) : "") << "'");
/* if we found anything we might use, try it. */
}
bool
-TemplateFile::loadFor(HttpRequest *request)
+TemplateFile::loadFor(const HttpRequest *request)
{
String hdr;
ErrorDynamicPageInfo *info = new ErrorDynamicPageInfo;
info->id = id;
info->page_name = xstrdup(page_name);
- info->page_redirect = static_cast<http_status>(atoi(page_name));
+ info->page_redirect = static_cast<Http::StatusCode>(atoi(page_name));
/* WARNING on redirection status:
* 2xx are permitted, but not documented officially.
* - current result is Squid crashing or XSS problems as dynamic deny_info load random disk files.
* - a future redesign of the file loading may result in loading remote objects sent inline as local body.
*/
- if (info->page_redirect == HTTP_STATUS_NONE)
+ if (info->page_redirect == Http::scNone)
; // special case okay.
else if (info->page_redirect < 200 || info->page_redirect > 599) {
// out of range
}
for (size_t j = 0; j < ErrorDynamicPages.size(); ++j) {
- if (strcmp(ErrorDynamicPages.items[j]->page_name, page_name) == 0)
+ if (strcmp(ErrorDynamicPages[j]->page_name, page_name) == 0)
return j + ERR_MAX;
}
const char *
errorPageName(int pageId)
{
- if (pageId >= ERR_NONE && pageId < ERR_MAX) /* common case */
+ if (pageId >= ERR_NONE && pageId < ERR_MAX) /* common case */
return err_type_str[pageId];
if (pageId >= ERR_MAX && pageId - ERR_MAX < (ssize_t)ErrorDynamicPages.size())
- return ErrorDynamicPages.items[pageId - ERR_MAX]->page_name;
+ return ErrorDynamicPages[pageId - ERR_MAX]->page_name;
- return "ERR_UNKNOWN"; /* should not happen */
+ return "ERR_UNKNOWN"; /* should not happen */
}
-ErrorState::ErrorState(err_type t, http_status status, HttpRequest * req) :
- type(t),
- page_id(t),
- err_language(NULL),
- httpStatus(status),
+ErrorState *
+ErrorState::NewForwarding(err_type type, HttpRequest *request)
+{
+ assert(request);
+ const Http::StatusCode status = request->flags.needValidation ?
+ Http::scGatewayTimeout : Http::scServiceUnavailable;
+ return new ErrorState(type, status, request);
+}
+
+ErrorState::ErrorState(err_type t, Http::StatusCode status, HttpRequest * req) :
+ type(t),
+ page_id(t),
+ err_language(NULL),
+ httpStatus(status),
#if USE_AUTH
- auth_user_request (NULL),
+ auth_user_request (NULL),
#endif
- request(NULL),
- url(NULL),
- xerrno(0),
- port(0),
- dnsError(),
- ttl(0),
- src_addr(),
- redirect_url(NULL),
- callback(NULL),
- callback_data(NULL),
- request_hdrs(NULL),
- err_msg(NULL),
-#if USE_SSL
- detail(NULL),
+ request(NULL),
+ url(NULL),
+ xerrno(0),
+ port(0),
+ dnsError(),
+ ttl(0),
+ src_addr(),
+ redirect_url(NULL),
+ callback(NULL),
+ callback_data(NULL),
+ request_hdrs(NULL),
+ err_msg(NULL),
+#if USE_OPENSSL
+ detail(NULL),
#endif
- detailCode(ERR_DETAIL_NONE)
+ detailCode(ERR_DETAIL_NONE)
{
- memset(&flags, 0, sizeof(flags));
memset(&ftp, 0, sizeof(ftp));
- if (page_id >= ERR_MAX && ErrorDynamicPages.items[page_id - ERR_MAX]->page_redirect != HTTP_STATUS_NONE)
- httpStatus = ErrorDynamicPages.items[page_id - ERR_MAX]->page_redirect;
+ if (page_id >= ERR_MAX && ErrorDynamicPages[page_id - ERR_MAX]->page_redirect != Http::scNone)
+ httpStatus = ErrorDynamicPages[page_id - ERR_MAX]->page_redirect;
if (req != NULL) {
- request = HTTPMSGLOCK(req);
+ request = req;
+ HTTPMSGLOCK(request);
src_addr = req->client_addr;
}
}
if (err->page_id == TCP_RESET) {
if (err->request) {
debugs(4, 2, "RSTing this reply");
- err->request->flags.resetTcp=true;
+ err->request->flags.resetTcp = true;
}
}
- entry->lock();
- entry->buffer();
- entry->replaceHttpReply( err->BuildHttpReply() );
- EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
- entry->flush();
- entry->complete();
- entry->negativeCache();
- entry->releaseRequest();
- entry->unlock();
+ entry->storeErrorResponse(err->BuildHttpReply());
delete err;
}
debugs(4, 3, HERE << conn << ", err=" << err);
assert(Comm::IsConnOpen(conn));
- /* moved in front of errorBuildBuf @?@ */
- err->flags.flag_cbdata = 1;
-
rep = err->BuildHttpReply();
MemBuf *mb = rep->pack();
* closing the FD, otherwise we do it ourselves.
*/
static void
-errorSendComplete(const Comm::ConnectionPointer &conn, char *bufnotused, size_t size, comm_err_t errflag, int xerrno, void *data)
+errorSendComplete(const Comm::ConnectionPointer &conn, char *, size_t size, Comm::Flag errflag, int, void *data)
{
ErrorState *err = static_cast<ErrorState *>(data);
debugs(4, 3, HERE << conn << ", size=" << size);
- if (errflag != COMM_ERR_CLOSING) {
+ if (errflag != Comm::ERR_CLOSING) {
if (err->callback) {
debugs(4, 3, "errorSendComplete: callback");
err->callback(conn->fd, err->callback_data, size);
if (err_language != Config.errorDefaultLanguage)
#endif
safe_free(err_language);
-#if USE_SSL
+#if USE_OPENSSL
delete detail;
#endif
}
str.Printf("Err: [none]\r\n");
}
#if USE_AUTH
- if (auth_user_request->denyMessage())
+ if (auth_user_request.getRaw() && auth_user_request->denyMessage())
str.Printf("Auth ErrMsg: %s\r\n", auth_user_request->denyMessage());
#endif
if (dnsError.size() > 0)
str.Printf("TimeStamp: %s\r\n\r\n", mkrfc1123(squid_curtime));
/* - IP stuff */
- str.Printf("ClientIP: %s\r\n", src_addr.NtoA(ntoabuf,MAX_IPSTRLEN));
+ str.Printf("ClientIP: %s\r\n", src_addr.toStr(ntoabuf,MAX_IPSTRLEN));
if (request && request->hier.host[0] != '\0') {
str.Printf("ServerIP: %s\r\n", request->hier.host);
else
urlpath_or_slash = "/";
- str.Printf("%s " SQUIDSTRINGPH " %s/%d.%d\n",
- RequestMethodStr(request->method),
+ str.Printf(SQUIDSBUFPH " " SQUIDSTRINGPH " %s/%d.%d\n",
+ SQUIDSBUFPRINT(request->method.image()),
SQUIDSTRINGPRINT(urlpath_or_slash),
AnyP::ProtocolType_str[request->http_ver.protocol],
request->http_ver.major, request->http_ver.minor);
ErrorState::Convert(char token, bool building_deny_info_url, bool allowRecursion)
{
static MemBuf mb;
- const char *p = NULL; /* takes priority over mb if set */
+ const char *p = NULL; /* takes priority over mb if set */
int do_quote = 1;
int no_urlescape = 0; /* if true then item is NOT to be further URL-encoded */
char ntoabuf[MAX_IPSTRLEN];
case 'B':
if (building_deny_info_url) break;
- p = request ? ftpUrlWith2f(request) : "[no URL]";
+ p = request ? Ftp::UrlWith2f(request) : "[no URL]";
break;
case 'c':
case 'D':
if (!allowRecursion)
p = "%D"; // if recursion is not allowed, do not convert
-#if USE_SSL
+#if USE_OPENSSL
// currently only SSL error details implemented
else if (detail) {
detail->useRequest(request);
const String &errDetail = detail->toString();
- if (errDetail.defined()) {
+ if (errDetail.size() > 0) {
MemBuf *detail_mb = ConvertText(errDetail.termedBuf(), false);
mb.append(detail_mb->content(), detail_mb->contentSize());
delete detail_mb;
break;
case 'i':
- mb.Printf("%s", src_addr.NtoA(ntoabuf,MAX_IPSTRLEN));
+ mb.Printf("%s", src_addr.toStr(ntoabuf,MAX_IPSTRLEN));
break;
case 'I':
if (request && request->hier.tcpServer != NULL)
- p = request->hier.tcpServer->remote.NtoA(ntoabuf,MAX_IPSTRLEN);
+ p = request->hier.tcpServer->remote.toStr(ntoabuf,MAX_IPSTRLEN);
else if (!building_deny_info_url)
p = "[unknown]";
break;
break;
case 'M':
- if (request)
- p = RequestMethodStr(request->method);
- else if (!building_deny_info_url)
- p= "[unknown method]";
+ if (request) {
+ const SBuf &m = request->method.image();
+ mb.append(m.rawContent(), m.length());
+ } else if (!building_deny_info_url)
+ p = "[unknown method]";
break;
case 'o':
case 'P':
if (request) {
- p = AnyP::ProtocolType_str[request->protocol];
+ p = request->url.getScheme().c_str();
} else if (!building_deny_info_url) {
p = "[unknown protocol]";
}
else
urlpath_or_slash = "/";
- mb.Printf("%s " SQUIDSTRINGPH " %s/%d.%d\n",
- RequestMethodStr(request->method),
+ mb.Printf(SQUIDSBUFPH " " SQUIDSTRINGPH " %s/%d.%d\n",
+ SQUIDSBUFPRINT(request->method.image()),
SQUIDSTRINGPRINT(urlpath_or_slash),
AnyP::ProtocolType_str[request->http_ver.protocol],
request->http_ver.major, request->http_ver.minor);
break;
case 'x':
-#if USE_SSL
+#if USE_OPENSSL
if (detail)
mb.Printf("%s", detail->errorName());
else
}
if (!p)
- p = mb.buf; /* do not use mb after this assignment! */
+ p = mb.buf; /* do not use mb after this assignment! */
assert(p);
}
void
-ErrorState::DenyInfoLocation(const char *name, HttpRequest *aRequest, MemBuf &result)
+ErrorState::DenyInfoLocation(const char *name, HttpRequest *, MemBuf &result)
{
char const *m = name;
char const *p = m;
if (name[0] == '3' || (name[0] != '2' && name[0] != '4' && name[0] != '5' && strchr(name, ':'))) {
/* Redirection */
- http_status status = HTTP_MOVED_TEMPORARILY;
+ Http::StatusCode status = Http::scFound;
// 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;
+ if (request->method != Http::METHOD_GET && request->method != Http::METHOD_HEAD && request->http_ver >= Http::ProtocolVersion(1,1))
+ status = Http::scTemporaryRedirect;
}
- rep->setHeaders(status, NULL, "text/html", 0, 0, -1);
+ rep->setHeaders(status, NULL, "text/html;charset=utf-8", 0, 0, -1);
if (request) {
MemBuf redirect_location;
httpHeaderPutStrf(&rep->header, HDR_X_SQUID_ERROR, "%d %s", httpStatus, "Access Denied");
} else {
MemBuf *content = BuildContent();
- rep->setHeaders(httpStatus, NULL, "text/html", content->contentSize(), 0, -1);
+ rep->setHeaders(httpStatus, NULL, "text/html;charset=utf-8", content->contentSize(), 0, -1);
/*
* include some information for downstream caches. Implicit
* replaceable content. This isn't quite sufficient. xerrno is not
// error tracking.
if (request) {
int edc = ERR_DETAIL_NONE; // error detail code
-#if USE_SSL
+#if USE_OPENSSL
if (detail)
edc = detail->errorNo();
else
content->init();
while ((p = strchr(m, '%'))) {
- content->append(m, p - m); /* copy */
- const char *t = Convert(*++p, false, allowRecursion); /* convert */
- content->Printf("%s", t); /* copy */
- m = p + 1; /* advance */
+ content->append(m, p - m); /* copy */
+ const char *t = Convert(*++p, false, allowRecursion); /* convert */
+ content->Printf("%s", t); /* copy */
+ m = p + 1; /* advance */
}
if (*m)
- content->Printf("%s", m); /* copy tail */
+ content->Printf("%s", m); /* copy tail */
+
+ content->terminate();
assert((size_t)content->contentSize() == strlen(content->content()));
return content;
}
+