2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 /* DEBUG: section 04 Error Generation */
11 #ifndef SQUID_ERRORPAGE_H
12 #define SQUID_ERRORPAGE_H
15 #include "comm/forward.h"
16 #include "error/Detail.h"
17 #include "error/forward.h"
18 #include "http/forward.h"
19 #include "http/StatusCode.h"
20 #include "ip/Address.h"
21 #include "log/forward.h"
22 #include "sbuf/SBuf.h"
23 #include "SquidString.h"
24 /* auth/UserRequest.h is empty unless USE_AUTH is defined */
25 #include "auth/UserRequest.h"
29 /// error page callback
30 typedef void ERCB(int fd
, void *, size_t);
33 \defgroup ErrorPageAPI Error Pages API
35 \section ErrorPageStringCodes Error Page % codes for text insertion.
39 A - Local listening IP address x
40 B - URL with FTP %2f hack x
41 c - Squid error code x
42 d - seconds elapsed since request received x
46 f - FTP request line x
48 g - FTP server message x
50 H - server host name x
51 i - client IP address x
52 I - server IP address x
53 l - HREF link for CSS stylesheet inclusion x
54 L - HREF link for more info/contact x
56 m - Error message returned by auth helper x
57 o - Message returned external acl helper x
60 R - Full HTTP Request x
61 S - squid signature from ERR_SIGNATURE x
62 s - caching proxy software with version x
65 U - URL without password x
66 u - URL with password x
67 w - cachemgr email address x
68 W - error data (to be included in the mailto links)
70 z - dns server error message x
71 Z - Preformatted error message x
74 * Plus logformat %codes embedded using @Squid{%logformat_code} syntax.
85 } // namespace ErrorPage
87 /// \ingroup ErrorPageAPI
90 CBDATA_CLASS(ErrorState
);
93 /// creates an error of type other than ERR_RELAY_REMOTE
94 ErrorState(err_type type
, Http::StatusCode
, HttpRequest
* request
, const AccessLogEntryPointer
&al
);
95 ErrorState() = delete; // not implemented.
97 /// creates an ERR_RELAY_REMOTE error
98 ErrorState(HttpRequest
* request
, HttpReply
*);
102 /// Creates a general request forwarding error with the right http_status.
103 static ErrorState
*NewForwarding(err_type
, HttpRequestPointer
&, const AccessLogEntryPointer
&);
106 * Allocates and initializes an error response
108 HttpReply
*BuildHttpReply(void);
110 /// set error type-specific detail code
111 void detailError(const ErrorDetail::Pointer
&dCode
) { detail
= dCode
; }
113 /// ensures that a future BuildHttpReply() is likely to succeed
116 /// the source of the error template (for reporting purposes)
120 typedef ErrorPage::Build Build
;
122 /// initializations shared by public constructors
123 explicit ErrorState(err_type type
);
125 /// locates the right error page template for this error and compiles it
128 /// compiles error page or error detail template (i.e. anything but deny_url)
129 /// \param input the template text to be compiled
130 /// \param allowRecursion whether to compile %codes which produce %codes
131 SBuf
compileBody(const char *text
, bool allowRecursion
);
133 /// compile a single-letter %code like %D
134 void compileLegacyCode(Build
&build
);
136 /// compile @Squid{%code} sequence containing a single logformat %code
137 void compileLogformatCode(Build
&build
);
139 /// replaces all legacy and logformat %codes in the given input
140 /// \param input the template text to be converted
141 /// \param building_deny_info_url whether input is a deny_info URL parameter
142 /// \param allowRecursion whether to compile %codes which produce %codes
143 /// \returns the given input with all %codes substituted
144 SBuf
compile(const char *input
, bool building_deny_info_url
, bool allowRecursion
);
146 /// React to a compile() error, throwing if buildContext allows.
147 /// \param msg description of what went wrong
148 /// \param near approximate start of the problematic input
149 void noteBuildError(const char *msg
, const char *near
) {
150 noteBuildError_(msg
, near
, false);
153 /// Note a compile() error but do not throw for backwards
154 /// compatibility with older configurations that may have such errors.
155 /// Should eventually be replaced with noteBuildError().
156 /// \param msg description of what went wrong
157 /// \param near approximate start of the problematic input
158 void bypassBuildErrorXXX(const char *msg
, const char *near
) {
159 noteBuildError_(msg
, near
, true);
163 * CacheManager / Debug dump of the ErrorState object.
164 * Writes output into the given MemBuf.
165 \retval 0 successful completion.
167 int Dump(MemBuf
* mb
);
170 err_type type
= ERR_NONE
;
171 int page_id
= ERR_NONE
;
172 char *err_language
= nullptr;
173 Http::StatusCode httpStatus
= Http::scNone
;
175 Auth::UserRequest::Pointer auth_user_request
;
177 HttpRequestPointer request
;
180 std::optional
<SBuf
> dnsError
; ///< DNS lookup error message
183 Ip::Address src_addr
;
184 char *redirect_url
= nullptr;
186 void *callback_data
= nullptr;
189 wordlist
*server_msg
= nullptr;
190 char *request
= nullptr;
191 char *reply
= nullptr;
192 char *cwd_msg
= nullptr;
193 MemBuf
*listing
= nullptr;
196 char *request_hdrs
= nullptr;
197 char *err_msg
= nullptr; /* Preformatted error message from the cache */
199 AccessLogEntryPointer ale
; ///< transaction details (or nil)
201 // TODO: Replace type, xerrno and detail with Error while adding a virtual
202 // Error::Detail::sysError() method to extract errno in detailError().
203 /// type-specific detail about the transaction error;
204 /// overwrites xerrno;
205 ErrorDetail::Pointer detail
;
207 HttpReplyPointer response_
;
210 void noteBuildError_(const char *msg
, const char *near
, const bool forceBypass
);
212 static const SBuf LogformatMagic
; ///< marks each embedded logformat entry
216 \ingroup ErrorPageAPI
218 * This function finds the error messages formats, and stores
219 * them in error_text[]
222 * error_text[] - is modified
224 void errorInitialize(void);
226 /// \ingroup ErrorPageAPI
227 void errorClean(void);
230 * \ingroup ErrorPageAPI
232 * This function generates a error page from the info contained
233 * by err and then sends it to the client.
234 * The callback function errorSendComplete() is called after
235 * the page has been written to the client (clientConn).
236 * errorSendComplete() deallocates err. We need to add
237 * err to the cbdata because comm_write() requires it
238 * for all callback data pointers.
240 \note normally errorSend() should only be called from
241 * routines in ssl.c and pass.c, where we don't have any
242 * StoreEntry's. In client_side.c we must allocate a StoreEntry
243 * for errors and use errorAppendEntry() to account for
244 * persistent/pipeline connections.
246 \param clientConn socket where page object is to be written
247 \param err This object is destroyed after use in this function.
249 void errorSend(const Comm::ConnectionPointer
&conn
, ErrorState
*err
);
252 \ingroup ErrorPageAPI
254 * This function generates a error page from the info contained
255 * by err and then stores the text in the specified store
257 * This function should only be called by "server
258 * side routines" which need to communicate errors to the
259 * client side. It should also be called from client_side.c
260 * because we now support persistent connections, and
261 * cannot assume that we can immediately write to the socket
265 \param err This object is destroyed after use in this function.
267 void errorAppendEntry(StoreEntry
*entry
, ErrorState
*err
);
269 /// allocates a new slot for the error page
270 err_type
errorReservePageId(const char *page_name
, const SBuf
&cfgLocation
);
272 const char *errorPageName(int pageId
); ///< error ID to string
275 \ingroup ErrorPageAPI
277 * loads text templates used for error pages and details;
278 * supports translation of templates
283 TemplateFile(const char *name
, const err_type code
);
284 virtual ~TemplateFile() {}
286 /// return true if the data loaded from disk without any problem
287 bool loaded() const {return wasLoaded
;}
290 * Load the page_name template from a file which probably exist at:
291 * (a) admin specified custom directory (error_directory)
292 * (b) default language translation directory (error_default_language)
293 * (c) English sub-directory where errors should ALWAYS exist
294 * If all of the above fail, setDefault() is called.
299 * Load an error template for a given HTTP request. This function examines the
300 * Accept-Language header and select the first available template. If the default
301 * template selected (eg because of a "Accept-Language: *"), or not available
302 * template found this function return false.
304 bool loadFor(const HttpRequest
*request
);
307 * Load the file given by "path". It uses the "parse()" method.
308 * On success return true and sets the "defined" member
310 bool loadFromFile(const char *path
);
312 /// The language used for the template
313 const char *language() {return errLanguage
.termedBuf();}
315 SBuf filename
; ///< where the template was loaded from
317 bool silent
; ///< Whether to print error messages on cache.log file or not. It is user defined.
320 /// post-process the loaded template
321 virtual bool parse() { return true; }
323 /// recover from loadDefault() failure to load or parse() a template
324 virtual void setDefault() {}
327 * Try to load the "page_name" template for a given language "lang"
328 * from squid errors directory
329 \return true on success false otherwise
331 bool tryLoadTemplate(const char *lang
);
333 SBuf template_
; ///< raw template contents
334 bool wasLoaded
; ///< True if the template data read from disk without any problem
335 String errLanguage
; ///< The error language of the template.
336 String templateName
; ///< The name of the template
337 err_type templateCode
; ///< The internal code for this template.
341 * Parses the Accept-Language header value and return one language item on
343 * Will ignore any whitespace, q-values, and detectably invalid language
344 * codes in the header.
346 * \param hdr is the Accept-Language header value
347 * \param lang a buffer to store parsed language code in
348 * \param langlen the length of the lang buffer
349 * \param pos is used to store the offset state of parsing. Must be "0" on first call.
350 * Will be altered to point at the start of next field-value.
351 * \return true if something looking like a language token has been placed in lang, false otherwise
353 bool strHdrAcptLangGetItem(const String
&hdr
, char *lang
, int langLen
, size_t &pos
);
355 std::ostream
&operator <<(std::ostream
&, const ErrorState
*);
357 #endif /* SQUID_ERRORPAGE_H */