/*
- * DEBUG: section 04 Error Generation
- * AUTHOR: Duane Wessels
+ * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
*
- * 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) 2003, Robert Collins <robertc@squid-cache.org>
+ * 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 */
+
#ifndef SQUID_ERRORPAGE_H
#define SQUID_ERRORPAGE_H
-#include "squid.h"
-#if USE_AUTH
-#include "auth/UserRequest.h"
-#endif
#include "cbdata.h"
+#include "comm/forward.h"
+#include "error/Detail.h"
+#include "error/forward.h"
+#include "http/forward.h"
+#include "http/StatusCode.h"
#include "ip/Address.h"
-#if USE_SSL
-#include "ssl/ErrorDetail.h"
-#endif
+#include "log/forward.h"
+#include "sbuf/SBuf.h"
+#include "SquidString.h"
+/* auth/UserRequest.h is empty unless USE_AUTH is defined */
+#include "auth/UserRequest.h"
+
+/// error page callback
+typedef void ERCB(int fd, void *, size_t);
/**
\defgroup ErrorPageAPI Error Pages API
*
\verbatim
a - User identity x
+ A - Local listening IP address x
B - URL with FTP %2f hack x
c - Squid error code x
d - seconds elapsed since request received x
z - dns server error message x
Z - Preformatted error message x
\endverbatim
+ *
+ * Plus logformat %codes embedded using @Squid{%logformat_code} syntax.
*/
-class HttpReply;
class MemBuf;
+class StoreEntry;
+class wordlist;
+
+namespace ErrorPage {
+
+class Build;
+
+} // namespace ErrorPage
/// \ingroup ErrorPageAPI
class ErrorState
{
+ CBDATA_CLASS(ErrorState);
+
public:
+ /// creates an error of type other than ERR_RELAY_REMOTE
+ ErrorState(err_type type, Http::StatusCode, HttpRequest * request, const AccessLogEntryPointer &al);
+ ErrorState() = delete; // not implemented.
+
+ /// creates an ERR_RELAY_REMOTE error
+ ErrorState(HttpRequest * request, HttpReply *);
+
+ ~ErrorState();
+
+ /// Creates a general request forwarding error with the right http_status.
+ static ErrorState *NewForwarding(err_type, HttpRequestPointer &, const AccessLogEntryPointer &);
+
/**
* Allocates and initializes an error response
*/
HttpReply *BuildHttpReply(void);
+ /// set error type-specific detail code
+ void detailError(const ErrorDetail::Pointer &dCode) { detail = dCode; }
+
+ /// ensures that a future BuildHttpReply() is likely to succeed
+ void validate();
+
+ /// the source of the error template (for reporting purposes)
+ SBuf inputLocation;
+
private:
- /**
- * Locates error page template to be used for this error
- * and constructs the HTML page content from it.
- */
- MemBuf *BuildContent(void);
+ typedef ErrorPage::Build Build;
- /**
- * Convert the given template string into textual output
- *
- * \param text The string to be converted
- * \param allowRecursion Whether to convert codes which output may contain codes
- */
- MemBuf *ConvertText(const char *text, bool allowRecursion);
+ /// initializations shared by public constructors
+ explicit ErrorState(err_type type);
- /**
- * Generates the Location: header value for a deny_info error page
- * to be used for this error.
- */
- void DenyInfoLocation(const char *name, HttpRequest *request, MemBuf &result);
+ /// locates the right error page template for this error and compiles it
+ SBuf buildBody();
- /**
- * Map the Error page and deny_info template % codes into textual output.
- *
- * Several of the codes produce blocks of non-URL compatible results.
- * When processing the deny_info location URL they will be skipped.
- *
- * \param token The token following % which need to be converted
- * \param building_deny_info_url Perform special deny_info actions, such as URL-encoding and token skipping.
- * \ allowRecursion True if the codes which do recursions should converted
- */
- const char *Convert(char token, bool building_deny_info_url, bool allowRecursion);
+ /// compiles error page or error detail template (i.e. anything but deny_url)
+ /// \param input the template text to be compiled
+ /// \param allowRecursion whether to compile %codes which produce %codes
+ SBuf compileBody(const char *text, bool allowRecursion);
+
+ /// compile a single-letter %code like %D
+ void compileLegacyCode(Build &build);
+
+ /// compile @Squid{%code} sequence containing a single logformat %code
+ void compileLogformatCode(Build &build);
+
+ /// replaces all legacy and logformat %codes in the given input
+ /// \param input the template text to be converted
+ /// \param building_deny_info_url whether input is a deny_info URL parameter
+ /// \param allowRecursion whether to compile %codes which produce %codes
+ /// \returns the given input with all %codes substituted
+ SBuf compile(const char *input, bool building_deny_info_url, bool allowRecursion);
+
+ /// React to a compile() error, throwing if buildContext allows.
+ /// \param msg description of what went wrong
+ /// \param near approximate start of the problematic input
+ void noteBuildError(const char *msg, const char *near) {
+ noteBuildError_(msg, near, false);
+ }
+
+ /// Note a compile() error but do not throw for backwards
+ /// compatibility with older configurations that may have such errors.
+ /// Should eventually be replaced with noteBuildError().
+ /// \param msg description of what went wrong
+ /// \param near approximate start of the problematic input
+ void bypassBuildErrorXXX(const char *msg, const char *near) {
+ noteBuildError_(msg, near, true);
+ }
/**
* CacheManager / Debug dump of the ErrorState object.
int Dump(MemBuf * mb);
public:
- err_type type;
- int page_id;
- char *err_language;
- http_status httpStatus;
+ err_type type = ERR_NONE;
+ int page_id = ERR_NONE;
+ char *err_language = nullptr;
+ Http::StatusCode httpStatus = Http::scNone;
#if USE_AUTH
- AuthUserRequest::Pointer auth_user_request;
+ Auth::UserRequest::Pointer auth_user_request;
#endif
- HttpRequest *request;
- char *url;
- int xerrno;
- u_short port;
+ HttpRequestPointer request;
+ char *url = nullptr;
+ int xerrno = 0;
+ unsigned short port = 0;
String dnsError; ///< DNS lookup error message
- time_t ttl;
+ time_t ttl = 0;
Ip::Address src_addr;
- char *redirect_url;
+ char *redirect_url = nullptr;
ERCB *callback;
- void *callback_data;
-
- struct {
- unsigned int flag_cbdata:1;
- } flags;
+ void *callback_data = nullptr;
struct {
- wordlist *server_msg;
- char *request;
- char *reply;
- char *cwd_msg;
- MemBuf *listing;
+ wordlist *server_msg = nullptr;
+ char *request = nullptr;
+ char *reply = nullptr;
+ char *cwd_msg = nullptr;
+ MemBuf *listing = nullptr;
} ftp;
- char *request_hdrs;
- char *err_msg; /* Preformatted error message from the cache */
+ char *request_hdrs = nullptr;
+ char *err_msg = nullptr; /* Preformatted error message from the cache */
+
+ AccessLogEntryPointer ale; ///< transaction details (or nil)
+
+ // TODO: Replace type, xerrno and detail with Error while adding a virtual
+ // Error::Detail::sysError() method to extract errno in detailError().
+ /// type-specific detail about the transaction error;
+ /// overwrites xerrno;
+ ErrorDetail::Pointer detail;
+
+ HttpReplyPointer response_;
-#if USE_SSL
- Ssl::ErrorDetail *detail;
-#endif
private:
- CBDATA_CLASS2(ErrorState);
+ void noteBuildError_(const char *msg, const char *near, const bool forceBypass);
+
+ static const SBuf LogformatMagic; ///< marks each embedded logformat entry
};
/**
\par Global effects:
* error_text[] - is modified
*/
-SQUIDCEXTERN void errorInitialize(void);
+void errorInitialize(void);
/// \ingroup ErrorPageAPI
-SQUIDCEXTERN void errorClean(void);
+void errorClean(void);
/**
- \ingroup ErrorPageAPI
+ * \ingroup ErrorPageAPI
*
* This function generates a error page from the info contained
* by err and then sends it to the client.
* The callback function errorSendComplete() is called after
- * the page has been written to the client socket (fd).
+ * the page has been written to the client (clientConn).
* errorSendComplete() deallocates err. We need to add
* err to the cbdata because comm_write() requires it
* for all callback data pointers.
* for errors and use errorAppendEntry() to account for
* persistent/pipeline connections.
*
- \param fd socket where page object is to be written
- \param err This object is destroyed after use in this function.
+ \param clientConn socket where page object is to be written
+ \param err This object is destroyed after use in this function.
*/
-SQUIDCEXTERN void errorSend(int fd, ErrorState *err);
+void errorSend(const Comm::ConnectionPointer &conn, ErrorState *err);
/**
\ingroup ErrorPageAPI
\param entry ??
\param err This object is destroyed after use in this function.
*/
-SQUIDCEXTERN void errorAppendEntry(StoreEntry *entry, ErrorState *err);
+void errorAppendEntry(StoreEntry *entry, ErrorState *err);
-/// \ingroup ErrorPageAPI
-SQUIDCEXTERN void errorStateFree(ErrorState * err);
+/// allocates a new slot for the error page
+err_type errorReservePageId(const char *page_name, const SBuf &cfgLocation);
-/// \ingroup ErrorPageAPI
-SQUIDCEXTERN err_type errorReservePageId(const char *page_name);
+const char *errorPageName(int pageId); ///< error ID to string
/**
\ingroup ErrorPageAPI
*
- * This function creates a ErrorState object.
+ * loads text templates used for error pages and details;
+ * supports translation of templates
+ */
+class TemplateFile
+{
+public:
+ TemplateFile(const char *name, const err_type code);
+ virtual ~TemplateFile() {}
+
+ /// return true if the data loaded from disk without any problem
+ bool loaded() const {return wasLoaded;}
+
+ /**
+ * Load the page_name template from a file which probably exist 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
+ * If all of the above fail, setDefault() is called.
+ */
+ void loadDefault();
+
+ /**
+ * Load an error template for a given HTTP request. This function examines the
+ * Accept-Language header and select the first available template. If the default
+ * template selected (eg because of a "Accept-Language: *"), or not available
+ * template found this function return false.
+ */
+ bool loadFor(const HttpRequest *request);
+
+ /**
+ * Load the file given by "path". It uses the "parse()" method.
+ * On success return true and sets the "defined" member
+ */
+ bool loadFromFile(const char *path);
+
+ /// The language used for the template
+ const char *language() {return errLanguage.termedBuf();}
+
+ SBuf filename; ///< where the template was loaded from
+
+ bool silent; ///< Whether to print error messages on cache.log file or not. It is user defined.
+
+protected:
+ /// post-process the loaded template
+ virtual bool parse() { return true; }
+
+ /// recover from loadDefault() failure to load or parse() a template
+ virtual void setDefault() {}
+
+ /**
+ * Try to load the "page_name" template for a given language "lang"
+ * from squid errors directory
+ \return true on success false otherwise
+ */
+ bool tryLoadTemplate(const char *lang);
+
+ SBuf template_; ///< raw template contents
+ bool wasLoaded; ///< True if the template data read from disk without any problem
+ String errLanguage; ///< The error language of the template.
+ String templateName; ///< The name of the template
+ err_type templateCode; ///< The internal code for this template.
+};
+
+/**
+ * Parses the Accept-Language header value and return one language item on
+ * each call.
+ * Will ignore any whitespace, q-values, and detectably invalid language
+ * codes in the header.
+ *
+ * \param hdr is the Accept-Language header value
+ * \param lang a buffer to store parsed language code in
+ * \param langlen the length of the lang buffer
+ * \param pos is used to store the offset state of parsing. Must be "0" on first call.
+ * Will be altered to point at the start of next field-value.
+ * \return true if something looking like a language token has been placed in lang, false otherwise
*/
-SQUIDCEXTERN ErrorState *errorCon(err_type type, http_status, HttpRequest * request);
-SQUIDCEXTERN const char *errorPageName(int pageId); ///< error ID to string
+bool strHdrAcptLangGetItem(const String &hdr, char *lang, int langLen, size_t &pos);
+
+std::ostream &operator <<(std::ostream &, const ErrorState *);
#endif /* SQUID_ERRORPAGE_H */
+