57#if !defined(DEFAULT_SQUID_ERROR_DIR)
61#define DEFAULT_SQUID_ERROR_DIR DEFAULT_SQUID_DATA_DIR"/errors"
127 std::ostream &
print(std::ostream &)
const;
139static inline std::ostream &
142 return context.
print(os);
168 "<div id=\"footer\">\n"
169 "Generated %T by %h (%s)\n"
179 "unexpected client disconnect"
187 "request start timedout"
191 "request parse timedout"
195 "relay server response"
225 const char *
text() {
return template_.c_str(); }
229 template_ =
"Internal Error: Missing Template ";
238 int tmp = (
int)anErr;
247 return (
int)anErr - (
int)anErr2;
277 static const SBuf builtIn(
"built-in");
278 ImportStaticErrorText(i,
text, builtIn);
288 ImportStaticErrorText(i, errTmpl.
text(), errTmpl.
filename);
300 ImportStaticErrorText(i, errTmpl.
text(), errTmpl.
filename);
405 snprintf(path,
sizeof(path),
"%s/%s/%s",
413 if ( strlen(lang) == 2) {
416 debugs(4,2,
"wildcard fallback errors not coded yet.");
447 template_.append(buf, len);
474 while (pos < hdr.
size()) {
487 bool invalid_byte =
false;
489 while (pos < hdr.
size() && hdr[pos] !=
';' && hdr[pos] !=
',' && !
xisspace(hdr[pos]) && dt < (lang + (langLen -1)) ) {
491#if USE_HTTP_VIOLATIONS
500 if (*dt !=
'-' && *dt !=
'*' && (*dt <
'a' || *dt >
'z') )
510 while (pos < hdr.
size() && hdr[pos] !=
',')
513 if (pos < hdr.
size() && hdr[pos] ==
',')
516 debugs(4, 9,
"STATE: lang=" << lang <<
", pos=" << pos <<
", buf='" << ((pos < hdr.
size()) ? hdr.
substr(pos,hdr.
size()) :
"") <<
"'");
519 if (*lang !=
'\0' && !invalid_byte)
540 debugs(4, 6,
"Testing Header: '" << hdr <<
"'");
545 if (lang[0] ==
'*' && lang[1] ==
'\0') {
546 debugs(4, 6,
"Found language '" << lang <<
"'. Using configured default.");
550 debugs(4, 6,
"Found language '" << lang <<
"', testing for available template");
572 cfgLocation(aCfgLocation),
573 page_redirect(static_cast<
Http::StatusCode>(atoi(page_name)))
575 const char *filenameOrUri =
nullptr;
577 if (
const char *statusCodeEnd = strchr(
page_name,
':'))
578 filenameOrUri = statusCodeEnd + 1;
587 if (filenameOrUri && strchr(filenameOrUri,
':'))
600 const auto info =
this;
616 else if (info->page_redirect < 200 || info->page_redirect > 599) {
620 }
else if ( info->page_redirect < 300 && strchr(&(
page_name[4]),
':')) {
624 }
else if (info->page_redirect >= 300 && info->page_redirect <= 399 && !strchr(&(
page_name[4]),
':')) {
628 }
else if (info->page_redirect >= 400 && strchr(&(
page_name[4]),
':')) {
640 for (
int i = 0; i <
ERR_MAX; ++i) {
677 return "ERR_UNKNOWN";
719 debugs(4, 3,
"constructed, this=" <<
static_cast<void*
>(
this) <<
' ' << *
this);
734 debugs(4, 3,
"constructed, this=" <<
static_cast<void*
>(
this) <<
" relaying " << *
this);
742 debugs(4, 4,
"storing " << err <<
" in " << *entry);
744 if (
const auto &request = err->
request) {
745 if (
const auto &bodyPipe = request->body_pipe) {
763 bodyPipe->enableAutoConsumption();
782 debugs(4, 2,
"RSTing this reply");
794 debugs(4, 3, conn <<
", err=" << err);
823 debugs(4, 3,
"errorSendComplete: callback");
826 debugs(4, 3,
"errorSendComplete: comm_close");
836 debugs(4, 7,
"destructing, this=" <<
static_cast<void*
>(
this));
857 out <<
"?subject=" <<
867 body <<
"ClientIP: " <<
src_addr <<
"\r\n";
881 body <<
"DNS ErrMsg: " << *
dnsError <<
"\r\n";
886 body <<
"HTTP Request:\r\n";
896 body <<
"FTP Request: " <<
ftp.request <<
"\r\n";
898 body <<
"FTP Reply: " <<
ftp.reply <<
"\r\n";
910#define CVT_BUF_SZ 512
925 if (*logformat !=
'%')
926 throw TexcHere(
"logformat expressions that do not start with % are not supported");
932 const auto closure = logformat + logformatLen;
934 throw TexcHere(
"Missing closing brace (})");
936 build.
input = closure + 1;
943 const auto remainingSize = strlen(build.
input);
945 build.
input += remainingSize;
952 const char *p =
nullptr;
954 int no_urlescape = 0;
962 const auto letter = build.
input[1];
988 if (building_deny_info_url)
break;
997 if (building_deny_info_url)
break;
1007 const auto compiledDetail =
compileBody(rawDetail.c_str(),
false);
1008 mb.
append(compiledDetail.rawContent(), compiledDetail.length());
1012 mb.
append(
"[No Error Detail]", 17);
1023 mb.
append(
"[No Error]", 10);
1027 if (building_deny_info_url)
break;
1036 if (building_deny_info_url)
break;
1045 if (building_deny_info_url)
break;
1048 mb.
append(
ftp.listing->content(),
ftp.listing->contentSize());
1050 }
else if (
ftp.server_msg) {
1065 }
else if (!building_deny_info_url)
1066 p =
"[unknown host]";
1076 else if (!building_deny_info_url)
1081 if (building_deny_info_url)
break;
1087 if (building_deny_info_url)
break;
1092 p =
"[not available]";
1096 if (building_deny_info_url)
break;
1101 p =
"[not available]";
1111 }
else if (!building_deny_info_url)
1112 p =
"[unknown method]";
1116 if (!building_deny_info_url)
1121 if (!p && !building_deny_info_url)
1122 p =
"[not available]";
1128 }
else if (!building_deny_info_url) {
1129 p =
"[unknown port]";
1137 }
else if (!building_deny_info_url) {
1138 p =
"[unknown protocol]";
1143 if (building_deny_info_url) {
1160 if (building_deny_info_url) {
1166 debugs(0,
DBG_CRITICAL,
"WARNING: deny_info now accepts coded tags. Use %u to get the full URL instead of %s");
1172 if (building_deny_info_url) {
1181 mb.
append(signature.rawContent(), signature.length());
1205 else if (!building_deny_info_url)
1215 else if (!building_deny_info_url)
1222 else if (!building_deny_info_url)
1227 if (building_deny_info_url)
break;
1237 mb.
append(brief.rawContent(), brief.length());
1238 }
else if (!building_deny_info_url) {
1239 p =
"[Unknown Error Code]";
1244 if (building_deny_info_url)
break;
1247 else if (
ftp.cwd_msg)
1254 if (building_deny_info_url)
break;
1268 if (building_deny_info_url)
1277 if (building_deny_info_url)
1279 else if (letter !=
';')
1295 debugs(4, 3,
"%" << (letter ? letter :
'?') <<
" --> '" << p <<
"'" );
1300 if (building_deny_info_url && !no_urlescape)
1314 (void)
compile(urlTemplate,
true,
true);
1355 rep->
setHeaders(status,
nullptr,
"text/html;charset=utf-8", 0, 0, -1);
1358 auto location =
compile(urlTemplate,
true,
true);
1385 static const SBuf acceptLanguage(
"Accept-Language");
1439 debugs(4, 2,
"No existing error page language negotiated for " <<
this <<
". Using default error file.");
1446 return compile(input,
false, allowRecursion);
1457 build.
input = input;
1459 auto blockStart = build.
input;
1460 while (
const auto letter = *build.
input) {
1461 if (letter ==
'%') {
1464 blockStart = build.
input;
1469 blockStart = build.
input;
1490 if (runtime || forceBypass) {
1494 static unsigned int seenErrors = 0;
1497 const auto debugLevel =
1505 debugs(4, debugLevel,
"WARNING: The following configuration error will be fatal in future Squid versions");
1521 return os <<
"[error page " <<
page_id <<
"]";
1531 printLocation(os) <<
": " << msg <<
" near ";
1534 const size_t maxContextLength = 15;
1535 if (strlen(errorLocation) > maxContextLength) {
1536 os.write(errorLocation, maxContextLength);
1539 os << errorLocation;
1545 if (std::current_exception())
#define Assure(condition)
CommCbFunPtrCallT< Dialer > * commCbCall(int debugSection, int debugLevel, const char *callName, const Dialer &dialer)
void IOCB(const Comm::ConnectionPointer &conn, char *, size_t size, Comm::Flag flag, int xerrno, void *data)
const char * err_type_str[]
const Ip::Address * FindListeningPortAddress(const HttpRequest *callerRequest, const AccessLogEntry *ale)
RawPointerT< Pointer > RawPointer(const char *label, const Pointer &ptr)
convenience wrapper for creating RawPointerT<> objects
std::ostream & CurrentException(std::ostream &os)
prints active (i.e., thrown but not yet handled) exception
#define TexcHere(msg)
legacy convenience macro; it is not difficult to type Here() now
const char * urlCanonicalFakeHttps(const HttpRequest *request)
#define CBDATA_CLASS_INIT(type)
void updateError(const Error &)
sets (or updates the already stored) transaction error as needed
AnyP::UriScheme const & getScheme() const
SBuf & absolutePath() const
RFC 3986 section 4.2 relative reference called 'absolute-path'.
void port(const Port p)
reset authority port subcomponent
void host(const char *src)
static SBuf Encode(const SBuf &, const CharacterSet &expected)
std::ostream manipulator to print containers as flat lists
auto & delimitedBy(const char *const d)
a c-string to print between consecutive items (if any). Caller must ensure lifetime.
char const * denyMessage(char const *const default_message=nullptr) const
char const * username() const
static const CharacterSet & RFC3986_UNRESERVED()
allowed URI characters that do not have a reserved purpose, RFC 3986
virtual SBuf verbose(const HttpRequestPointer &) const =0
virtual SBuf brief() const =0
an error page created from admin-configurable metadata (e.g. deny_info)
const char * uri
admin-configured HTTP Location header value for redirection responses
ErrorDynamicPageInfo(ErrorDynamicPageInfo &&)=delete
Http::StatusCode page_redirect
admin-configured HTTP status code
SBuf cfgLocation
deny_info directive position in squid.conf (for reporting)
ErrorDynamicPageInfo(const int anId, const char *aName, const SBuf &aCfgLocation)
int id
error_text[] index for response body (unused in redirection responses)
const char * filename
admin-configured name for the error page template (custom or standard)
void setDefault() override
recover from loadDefault() failure to load or parse() a template
const char * text()
The template text data read from disk.
ErrorPageFile(const char *name, const err_type code)
pretty-prints error page/deny_info building error
std::ostream & printLocation(std::ostream &os) const
print() helper to report where the error was found
std::ostream & print(std::ostream &) const
reports error details (for admin-visible exceptions and debugging)
BuildErrorPrinter(const SBuf &anInputLocation, int aPage, const char *aMsg, const char *anErrorLocation)
const SBuf & inputLocation
const char * errorLocation
state and parameters shared by several ErrorState::compile*() methods
bool allowRecursion
whether top-level compile() calls are OK
bool building_deny_info_url
whether we compile deny_info URI
const char * input
template bytes that need to be compiled
SBuf output
compilation result
static ErrorState * NewForwarding(err_type, HttpRequestPointer &, const AccessLogEntryPointer &)
Creates a general request forwarding error with the right http_status.
SBuf compile(const char *input, bool building_deny_info_url, bool allowRecursion)
void validate()
ensures that a future BuildHttpReply() is likely to succeed
void compileLegacyCode(Build &build)
compile a single-letter code like D
void noteBuildError_(const char *msg, const char *errorLocation, bool forceBypass)
AccessLogEntryPointer ale
transaction details (or nil)
std::optional< SBuf > dnsError
DNS lookup error message.
void bypassBuildErrorXXX(const char *const msg, const char *const errorLocation)
ErrorDetail::Pointer detail
void compileLogformatCode(Build &build)
compile @Squid{code} sequence containing a single logformat code
Auth::UserRequest::Pointer auth_user_request
SBuf inputLocation
the source of the error template (for reporting purposes)
static const SBuf LogformatMagic
marks each embedded logformat entry
HttpRequestPointer request
SBuf compileBody(const char *text, bool allowRecursion)
HttpReply * BuildHttpReply(void)
struct ErrorState::@47 ftp
SBuf buildBody()
locates the right error page template for this error and compiles it
HttpReplyPointer response_
Http::StatusCode httpStatus
void noteBuildError(const char *const msg, const char *const errorLocation)
void update(const Error &)
if necessary, stores the given error information (if any)
an error page (or a part of an error page) with hard-coded template text
const char * text
a string literal containing the error template
err_type type
identifies the error (or a special error template part)
char host[SQUIDHOSTNAMELEN]
Comm::ConnectionPointer tcpServer
TCP/IP level details of the last peer/server connection.
void set(const SBuf &newContent)
void setHeaders(Http::StatusCode status, const char *reason, const char *ctype, int64_t clen, time_t lmt, time_t expires)
const SBuf & image() const
void pack(Packable *p, bool maskSensitiveInfo=false) const
Auth::UserRequest::Pointer auth_user_request
Error error
the first transaction problem encountered (or falsy)
AnyP::Uri url
the request URI
const SBuf & effectiveRequestUri() const
RFC 7230 section 5.5 - Effective Request URI.
AnyP::ProtocolVersion http_ver
Http::StatusCode status() const
retrieve the status code for this status line
char * toStr(char *buf, const unsigned int blen, int force=AF_UNSPEC) const
void append(const char *c, int sz) override
void init(mb_size_t szInit, mb_size_t szMax)
char * content()
start of the added data
mb_size_t contentSize() const
available data size
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
SBuf buf()
bytes written so far
const char * rawContent() const
char at(size_type pos) const
size_type length() const
Returns the number of bytes stored in SBuf.
int cmp(const SBuf &S, const size_type n) const
shorthand version for compare()
SBuf & append(const SBuf &S)
int errorLogMissingLanguages
char * errorDefaultLanguage
struct SquidConfig::@90 onoff
void storeErrorResponse(HttpReply *reply)
Store a prepared error response. MemObject locks the reply object.
store_status_t store_status
String substr(size_type from, size_type to) const
char const * termedBuf() const
static ErrorDetail::Pointer NewIfAny(const int errorNo)
virtual void setDefault()
recover from loadDefault() failure to load or parse() a template
bool loadFromFile(const char *path)
SBuf template_
raw template contents
SBuf filename
where the template was loaded from
bool loaded() const
return true if the data loaded from disk without any problem
TemplateFile(const char *name, const err_type code)
bool wasLoaded
True if the template data read from disk without any problem.
bool tryLoadTemplate(const char *lang)
String templateName
The name of the template.
const char * language()
The language used for the template.
virtual bool parse()
post-process the loaded template
err_type templateCode
The internal code for this template.
String errLanguage
The error language of the template.
bool silent
Whether to print error messages on cache.log file or not. It is user defined.
bool loadFor(const HttpRequest *request)
#define debugs(SECTION, LEVEL, CONTENT)
#define EBIT_TEST(flag, bit)
@ ERR_REQUEST_PARSE_TIMEOUT
@ ERR_REQUEST_START_TIMEOUT
static const std::array< HardCodedError, 7 > HardCodedErrors
error messages that cannot be configured/customized externally
static std::ostream & operator<<(std::ostream &os, const ErrorState &err)
compactly prints top-level ErrorState information (for debugging)
err_type errorReservePageId(const char *page_name, const SBuf &cfgLocation)
allocates a new slot for the error page
static IOCB errorSendComplete
#define DEFAULT_SQUID_ERROR_DIR
bool strHdrAcptLangGetItem(const String &hdr, char *lang, int langLen, size_t &pos)
bool strHdrAcptLangGetItem(const String &hdr, char *lang, int langLen, size_t &pos)
int FD_READ_METHOD(int fd, char *buf, int len)
int file_open(const char *path, int mode)
char const * visible_appname_string
const char * external_acl_message
void errorInitialize(void)
void errorSend(const Comm::ConnectionPointer &conn, ErrorState *err)
void errorAppendEntry(StoreEntry *entry, ErrorState *err)
const char * errorPageName(int pageId)
error ID to string
static char ** error_text
static const char * errorFindHardText(err_type type)
static std::vector< ErrorDynamicPageInfo * > ErrorDynamicPages
static err_type & operator++(err_type &anErr)
static int operator-(err_type const &anErr, err_type const &anErr2)
static int errorPageId(const char *page_name)
static int error_page_count
static MemBuf error_stylesheet
char * html_quote(const char *string)
#define MAX_IPSTRLEN
Length of buffer that needs to be allocated to old a null-terminated IP-string.
bool IsConnOpen(const Comm::ConnectionPointer &conn)
void Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE *free_func)
static const char * IsDenyInfoUri(const int page_id)
static void ImportStaticErrorText(const int page_id, const char *text, const SBuf &inputLocation)
add error page template to the global index
static void ValidateStaticError(const int page_id, const SBuf &inputLocation)
validate static error page
static std::ostream & operator<<(std::ostream &os, const BuildErrorPrinter &context)
const SBuf & UrlWith2f(HttpRequest *)
AnyP::ProtocolVersion ProtocolVersion()
void errorDetailInitialize()
const char * FormatRfc1123(time_t)
const char * FormatHttpd(time_t)
#define rfc1738_escape_part(x)
SBuf ToSBuf(Args &&... args)
slowly stream-prints all arguments into a freshly allocated SBuf
SBuf text("GET http://resource.com/path HTTP/1.1\r\n" "Host: resource.com\r\n" "Cookie: laijkpk3422r j1noin \r\n" "\r\n")
void wordlistDestroy(wordlist **list)
destroy a wordlist
void wordlistCat(const wordlist *w, MemBuf *mb)
void * xcalloc(size_t n, size_t sz)
const char * xstrerr(int error)