Squid Web Cache master
Loading...
Searching...
No Matches
errorpage.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2026 The Squid Software Foundation and contributors
3 *
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.
7 */
8
9/* DEBUG: section 04 Error Generation */
10
11#include "squid.h"
12#include "AccessLogEntry.h"
13#include "base/CharacterSet.h"
14#include "base/IoManip.h"
15#include "cache_cf.h"
16#include "clients/forward.h"
17#include "comm/Connection.h"
18#include "comm/Write.h"
19#include "error/Detail.h"
21#include "errorpage.h"
22#include "fde.h"
23#include "format/Format.h"
24#include "fs_io.h"
25#include "html/Quoting.h"
26#include "HttpHeaderTools.h"
27#include "HttpReply.h"
28#include "HttpRequest.h"
29#include "MemBuf.h"
30#include "MemObject.h"
31#include "rfc1738.h"
32#include "sbuf/Stream.h"
33#include "SquidConfig.h"
34#include "Store.h"
35#include "tools.h"
36#include "wordlist.h"
37#if USE_AUTH
38#include "auth/UserRequest.h"
39#endif
40#if USE_OPENSSL
42#endif
43
44#include <array>
45
57#if !defined(DEFAULT_SQUID_ERROR_DIR)
61#define DEFAULT_SQUID_ERROR_DIR DEFAULT_SQUID_DATA_DIR"/errors"
62#endif
63
66
67const SBuf ErrorState::LogformatMagic("@Squid{");
68
69/* local types */
70
73public:
74 ErrorDynamicPageInfo(const int anId, const char *aName, const SBuf &aCfgLocation);
76
78 int id;
79
83 char *page_name;
84
86 const char *uri;
87
89 const char *filename;
90
93
94 // XXX: Misnamed. Not just for redirects.
97
98private:
99 // no copying of any kind
101};
102
103namespace ErrorPage {
104
106class Build
107{
108public:
110 const char *input = nullptr;
112 bool allowRecursion = false;
113};
114
117{
118public:
119 BuildErrorPrinter(const SBuf &anInputLocation, int aPage, const char *aMsg, const char *anErrorLocation):
120 inputLocation(anInputLocation),
121 page_id(aPage),
122 msg(aMsg),
123 errorLocation(anErrorLocation)
124 {}
125
127 std::ostream &print(std::ostream &) const;
128
130 std::ostream &printLocation(std::ostream &os) const;
131
132 /* saved constructor parameters */
134 const int page_id;
135 const char *msg;
136 const char *errorLocation;
137};
138
139static inline std::ostream &
140operator <<(std::ostream &os, const BuildErrorPrinter &context)
141{
142 return context.print(os);
143}
144
145static const char *IsDenyInfoUri(const int page_id);
146
147static void ImportStaticErrorText(const int page_id, const char *text, const SBuf &inputLocation);
148static void ValidateStaticError(const int page_id, const SBuf &inputLocation);
149
150} // namespace ErrorPage
151
152/* local constant and vars */
153
156public:
158 const char *text;
159};
160
162static const std::array<HardCodedError, 7> HardCodedErrors = {
163 {
164 {
166 "\n<br>\n"
167 "<hr>\n"
168 "<div id=\"footer\">\n"
169 "Generated %T by %h (%s)\n"
170 "</div>\n"
171 "</body></html>\n"
172 },
173 {
174 TCP_RESET,
175 "reset"
176 },
177 {
179 "unexpected client disconnect"
180 },
181 {
183 "secure accept fail"
184 },
185 {
187 "request start timedout"
188 },
189 {
191 "request parse timedout"
192 },
193 {
195 "relay server response"
196 }
197 }
198};
199
201static std::vector<ErrorDynamicPageInfo *> ErrorDynamicPages;
202
203/* local prototypes */
204
206static char **error_text = nullptr;
207
209static int error_page_count = 0;
210
213
214static const char *errorFindHardText(err_type type);
216
220{
221public:
222 ErrorPageFile(const char *name, const err_type code) : TemplateFile(name, code) {}
223
225 const char *text() { return template_.c_str(); }
226
227protected:
228 void setDefault() override {
229 template_ = "Internal Error: Missing Template ";
230 template_.append(templateName.termedBuf());
231 }
232};
233
235static err_type &
237{
238 int tmp = (int)anErr;
239 anErr = (err_type)(++tmp);
240 return anErr;
241}
242
244static int
245operator -(err_type const &anErr, err_type const &anErr2)
246{
247 return (int)anErr - (int)anErr2;
248}
249
252static const char *
253ErrorPage::IsDenyInfoUri(const int page_id)
254{
255 if (ERR_MAX <= page_id && page_id < error_page_count)
256 return ErrorDynamicPages.at(page_id - ERR_MAX)->uri; // may be nil
257 return nullptr;
258}
259
260void
262{
264
265 err_type i;
266 const char *text;
268 error_text = static_cast<char **>(xcalloc(error_page_count, sizeof(char *)));
269
270 for (i = ERR_NONE, ++i; i < error_page_count; ++i) {
272
273 if ((text = errorFindHardText(i))) {
277 static const SBuf builtIn("built-in");
278 ImportStaticErrorText(i, text, builtIn);
279
280 } else if (i < ERR_MAX) {
286 ErrorPageFile errTmpl(err_type_str[i], i);
287 errTmpl.loadDefault();
288 ImportStaticErrorText(i, errTmpl.text(), errTmpl.filename);
289 } else {
294 assert(info && info->id == i && info->page_name);
295
296 if (info->filename) {
298 ErrorPageFile errTmpl(info->filename, ERR_MAX);
299 errTmpl.loadDefault();
300 ImportStaticErrorText(i, errTmpl.text(), errTmpl.filename);
301 } else {
302 assert(info->uri);
304 }
305 }
306 }
307
309
310 // look for and load stylesheet into global MemBuf for it.
312 ErrorPageFile tmpl("StylesSheet", ERR_MAX);
314 error_stylesheet.appendf("%s",tmpl.text());
315 }
316
317#if USE_OPENSSL
319#endif
320}
321
322void
324{
325 if (error_text) {
326 int i;
327
328 for (i = ERR_NONE + 1; i < error_page_count; ++i)
330
332 }
333
334 while (!ErrorDynamicPages.empty()) {
335 delete ErrorDynamicPages.back();
336 ErrorDynamicPages.pop_back();
337 }
338
340
341#if USE_OPENSSL
343#endif
344}
345
347static const char *
349{
350 for (const auto &m: HardCodedErrors) {
351 if (m.type == type)
352 return m.text;
353 }
354 return nullptr;
355}
356
357TemplateFile::TemplateFile(const char *name, const err_type code): silent(false), wasLoaded(false), templateName(name), templateCode(code)
358{
359 assert(name);
360}
361
362void
364{
365 if (loaded()) // already loaded?
366 return;
367
370 char path[MAXPATHLEN];
371 snprintf(path, sizeof(path), "%s/%s", Config.errorDirectory, templateName.termedBuf());
372 loadFromFile(path);
373 }
374
375#if USE_ERR_LOCALES
379 debugs(1, (templateCode < TCP_RESET ? DBG_CRITICAL : 3), "ERROR: Unable to load default error language files. Reset to backups.");
380 }
381 }
382#endif
383
384 /* test default location if failed (templates == English translation base templates) */
385 if (!loaded()) {
386 tryLoadTemplate("templates");
387 }
388
389 /* giving up if failed */
390 if (!loaded()) {
391 debugs(1, (templateCode < TCP_RESET ? DBG_CRITICAL : 3), "WARNING: failed to find or read error text file " << templateName);
392 template_.clear();
393 setDefault();
394 wasLoaded = true;
395 }
396}
397
398bool
400{
401 assert(lang);
402
403 char path[MAXPATHLEN];
404 /* TODO: prep the directory path string to prevent snprintf ... */
405 snprintf(path, sizeof(path), "%s/%s/%s",
407 path[MAXPATHLEN-1] = '\0';
408
409 if (loadFromFile(path))
410 return true;
411
412#if HAVE_GLOB
413 if ( strlen(lang) == 2) {
414 /* TODO glob the error directory for sub-dirs matching: <tag> '-*' */
415 /* use first result. */
416 debugs(4,2, "wildcard fallback errors not coded yet.");
417 }
418#endif
419
420 return false;
421}
422
423bool
425{
426 int fd;
427 char buf[4096];
428 ssize_t len;
429
430 if (loaded()) // already loaded?
431 return true;
432
433 fd = file_open(path, O_RDONLY | O_TEXT);
434
435 if (fd < 0) {
436 /* with dynamic locale negotiation we may see some failures before a success. */
437 if (!silent && templateCode < TCP_RESET) {
438 int xerrno = errno;
439 debugs(4, DBG_CRITICAL, "ERROR: loading file '" << path << "': " << xstrerr(xerrno));
440 }
441 wasLoaded = false;
442 return wasLoaded;
443 }
444
445 template_.clear();
446 while ((len = FD_READ_METHOD(fd, buf, sizeof(buf))) > 0) {
447 template_.append(buf, len);
448 }
449
450 if (len < 0) {
451 int xerrno = errno;
452 file_close(fd);
453 debugs(4, DBG_CRITICAL, MYNAME << "ERROR: failed to fully read: '" << path << "': " << xstrerr(xerrno));
454 wasLoaded = false;
455 return false;
456 }
457
458 file_close(fd);
459
460 filename = SBuf(path);
461
462 if (!parse()) {
463 debugs(4, DBG_CRITICAL, "ERROR: parsing error in template file: " << path);
464 wasLoaded = false;
465 return false;
466 }
467
468 wasLoaded = true;
469 return wasLoaded;
470}
471
472bool strHdrAcptLangGetItem(const String &hdr, char *lang, int langLen, size_t &pos)
473{
474 while (pos < hdr.size()) {
475
476 /* skip any initial whitespace. */
477 while (pos < hdr.size() && xisspace(hdr[pos]))
478 ++pos;
479
480 /*
481 * Header value format:
482 * - sequence of whitespace delimited tags
483 * - each tag may suffix with ';'.* which we can ignore.
484 * - IFF a tag contains only two characters we can wildcard ANY translations matching: <it> '-'? .*
485 * with preference given to an exact match.
486 */
487 bool invalid_byte = false;
488 char *dt = lang;
489 while (pos < hdr.size() && hdr[pos] != ';' && hdr[pos] != ',' && !xisspace(hdr[pos]) && dt < (lang + (langLen -1)) ) {
490 if (!invalid_byte) {
491#if USE_HTTP_VIOLATIONS
492 // if accepting violations we may as well accept some broken browsers
493 // which may send us the right code, wrong ISO formatting.
494 if (hdr[pos] == '_')
495 *dt = '-';
496 else
497#endif
498 *dt = xtolower(hdr[pos]);
499 // valid codes only contain A-Z, hyphen (-) and *
500 if (*dt != '-' && *dt != '*' && (*dt < 'a' || *dt > 'z') )
501 invalid_byte = true;
502 else
503 ++dt; // move to next destination byte.
504 }
505 ++pos;
506 }
507 *dt = '\0'; // nul-terminated the filename content string before system use.
508
509 // if we terminated the tag on garbage or ';' we need to skip to the next ',' or end of header.
510 while (pos < hdr.size() && hdr[pos] != ',')
511 ++pos;
512
513 if (pos < hdr.size() && hdr[pos] == ',')
514 ++pos;
515
516 debugs(4, 9, "STATE: lang=" << lang << ", pos=" << pos << ", buf='" << ((pos < hdr.size()) ? hdr.substr(pos,hdr.size()) : "") << "'");
517
518 /* if we found anything we might use, try it. */
519 if (*lang != '\0' && !invalid_byte)
520 return true;
521 }
522 return false;
523}
524
525bool
527{
528 String hdr;
529
530#if USE_ERR_LOCALES
531 if (loaded()) // already loaded?
532 return true;
533
534 if (!request || !request->header.getList(Http::HdrType::ACCEPT_LANGUAGE, &hdr))
535 return false;
536
537 char lang[256];
538 size_t pos = 0; // current parsing position in header string
539
540 debugs(4, 6, "Testing Header: '" << hdr << "'");
541
542 while ( strHdrAcptLangGetItem(hdr, lang, 256, pos) ) {
543
544 /* wildcard uses the configured default language */
545 if (lang[0] == '*' && lang[1] == '\0') {
546 debugs(4, 6, "Found language '" << lang << "'. Using configured default.");
547 return false;
548 }
549
550 debugs(4, 6, "Found language '" << lang << "', testing for available template");
551
552 if (tryLoadTemplate(lang)) {
553 /* store the language we found for the Content-Language reply header */
554 errLanguage = lang;
555 break;
556 } else if (Config.errorLogMissingLanguages) {
557 debugs(4, DBG_IMPORTANT, "WARNING: Error Pages Missing Language: " << lang);
558 }
559 }
560#else
561 (void)request;
562#endif
563
564 return loaded();
565}
566
567ErrorDynamicPageInfo::ErrorDynamicPageInfo(const int anId, const char *aName, const SBuf &aCfgLocation):
568 id(anId),
569 page_name(xstrdup(aName)),
570 uri(nullptr),
571 filename(nullptr),
572 cfgLocation(aCfgLocation),
573 page_redirect(static_cast<Http::StatusCode>(atoi(page_name)))
574{
575 const char *filenameOrUri = nullptr;
576 if (xisdigit(*page_name)) {
577 if (const char *statusCodeEnd = strchr(page_name, ':'))
578 filenameOrUri = statusCodeEnd + 1;
579 } else {
581 filenameOrUri = page_name;
582 }
583
584 const auto looksLikeUrl = [](const char * const name) { return name && strchr(name, ':'); };
585
586 // Guessed uri, filename, or both values may be nil or malformed.
587 // They are validated later.
588 if (!page_redirect) {
589 if (looksLikeUrl(filenameOrUri))
590 uri = filenameOrUri;
591 else
592 filename = filenameOrUri;
593 }
594 else if (page_redirect/100 == 3) {
595 // redirects imply a URL
596 uri = filenameOrUri;
597 } else {
598 // non-redirects imply an error page name
599 filename = filenameOrUri;
600 }
601
602 const auto info = this; // source code change reduction hack
603 // TODO: Move and refactor to avoid self_destruct()s in reconfigure.
604
605 /* WARNING on redirection status:
606 * 2xx are permitted, but not documented officially.
607 * - might be useful for serving static files (PAC etc) in special cases
608 * 3xx require a URL suitable for Location: header.
609 * - the current design does not allow for a Location: URI as well as a local file template
610 * although this possibility is explicitly permitted in the specs.
611 * 4xx-5xx require a local file template.
612 * - sending Location: on these codes with no body is invalid by the specs.
613 * - current result is Squid crashing or XSS problems as dynamic deny_info load random disk files.
614 * - a future redesign of the file loading may result in loading remote objects sent inline as local body.
615 */
616 if (info->page_redirect == Http::scNone)
617 ; // special case okay.
618 else if (info->page_redirect < 200 || info->page_redirect > 599) {
619 // out of range
620 debugs(0, DBG_CRITICAL, "FATAL: status " << info->page_redirect << " is not valid on '" << page_name << "'");
622 } else if ( /* >= 200 && */ info->page_redirect < 300 && looksLikeUrl(filenameOrUri)) {
623 // 2xx require a local template file
624 debugs(0, DBG_CRITICAL, "FATAL: status " << info->page_redirect << " requires a template on '" << page_name << "'");
626 } else if (info->page_redirect >= 300 && info->page_redirect <= 399 && !looksLikeUrl(filenameOrUri)) {
627 // 3xx require an absolute URL
628 debugs(0, DBG_CRITICAL, "FATAL: status " << info->page_redirect << " requires a URL on '" << page_name << "'");
630 } else if (info->page_redirect >= 400 /* && <= 599 */ && looksLikeUrl(filenameOrUri)) {
631 // 4xx/5xx require a local template file
632 debugs(0, DBG_CRITICAL, "FATAL: status " << info->page_redirect << " requires a template on '" << page_name << "'");
634 }
635 // else okay.
636}
637
639static int
640errorPageId(const char *page_name)
641{
642 for (int i = 0; i < ERR_MAX; ++i) {
643 if (strcmp(err_type_str[i], page_name) == 0)
644 return i;
645 }
646
647 for (size_t j = 0; j < ErrorDynamicPages.size(); ++j) {
648 if (strcmp(ErrorDynamicPages[j]->page_name, page_name) == 0)
649 return j + ERR_MAX;
650 }
651
652 return ERR_NONE;
653}
654
656errorReservePageId(const char *page_name, const SBuf &cfgLocation)
657{
658 int id = errorPageId(page_name);
659
660 if (id == ERR_NONE) {
661 id = ERR_MAX + ErrorDynamicPages.size();
662 const auto info = new ErrorDynamicPageInfo(id, page_name, cfgLocation);
663 ErrorDynamicPages.push_back(info);
664 }
665
666 return (err_type)id;
667}
668
670const char *
671errorPageName(int pageId)
672{
673 if (pageId >= ERR_NONE && pageId < ERR_MAX) /* common case */
674 return err_type_str[pageId];
675
676 if (pageId >= ERR_MAX && pageId - ERR_MAX < (ssize_t)ErrorDynamicPages.size())
677 return ErrorDynamicPages[pageId - ERR_MAX]->page_name;
678
679 return "ERR_UNKNOWN"; /* should not happen */
680}
681
683static std::ostream &
684operator <<(std::ostream &os, const ErrorState &err)
685{
686 os << errorPageName(err.type);
687 if (err.httpStatus != Http::scNone)
688 os << "/http_status=" << err.httpStatus;
689 return os;
690}
691
699
701 type(t),
702 page_id(t),
703 callback(nullptr),
704 ale(anAle)
705{
706}
707
709 ErrorState(t, anAle)
710{
711 if (page_id >= ERR_MAX && ErrorDynamicPages[page_id - ERR_MAX]->page_redirect != Http::scNone)
712 httpStatus = ErrorDynamicPages[page_id - ERR_MAX]->page_redirect;
713 else
714 httpStatus = status;
715
716 if (req) {
717 request = req;
718 src_addr = req->client_addr;
719 }
720
721 debugs(4, 3, "constructed, this=" << static_cast<void*>(this) << ' ' << *this);
722}
723
726{
727 Must(errorReply);
728 response_ = errorReply;
729 httpStatus = errorReply->sline.status();
730
731 if (req) {
732 request = req;
733 src_addr = req->client_addr;
734 }
735
736 debugs(4, 3, "constructed, this=" << static_cast<void*>(this) << " relaying " << *this);
737}
738
739void
741{
742 assert(entry->mem_obj != nullptr);
743 assert (entry->isEmpty());
744 debugs(4, 4, "storing " << err << " in " << *entry);
745
746 if (const auto &request = err->request) {
747 if (const auto &bodyPipe = request->body_pipe) {
748 // We cannot expectNoConsumption() here (yet): This request may be a
749 // virgin request being consumed by adaptation that should continue
750 // even in error-handling cases. startAutoConsumptionIfNeeded() call
751 // triggered by enableAutoConsumption() below skips such requests.
752 //
753 // Today, we also cannot enableAutoConsumption() earlier because it
754 // could result in premature consumption in BodyPipe::postAppend()
755 // followed by an unwanted setConsumerIfNotLate() failure.
756 //
757 // TODO: Simplify BodyPipe auto-consumption by automatically
758 // enabling it when no new consumers are expected, removing the need
759 // for explicit enableAutoConsumption() calls like the one below.
760 //
761 // Code like clientReplyContext::sendClientOldEntry() might use
762 // another StoreEntry for this master transaction, but we want to
763 // consume this request body even in those hypothetical error cases
764 // to prevent stuck (client-Squid or REQMOD) transactions.
765 bodyPipe->enableAutoConsumption();
766 }
767 }
768
769 if (entry->store_status != STORE_PENDING) {
770 debugs(4, 2, "Skipping error page due to store_status: " << entry->store_status);
771 /*
772 * If the entry is not STORE_PENDING, then no clients
773 * care about it, and we don't need to generate an
774 * error message
775 */
777 assert(entry->mem_obj->nclients == 0);
778 delete err;
779 return;
780 }
781
782 if (err->page_id == TCP_RESET) {
783 if (err->request) {
784 debugs(4, 2, "RSTing this reply");
785 err->request->flags.resetTcp = true;
786 }
787 }
788
789 entry->storeErrorResponse(err->BuildHttpReply());
790 delete err;
791}
792
793void
795{
796 debugs(4, 3, conn << ", err=" << err);
798
800
801 MemBuf *mb = rep->pack();
802 AsyncCall::Pointer call = commCbCall(78, 5, "errorSendComplete",
804 Comm::Write(conn, mb, call);
805 delete mb;
806}
807
817static void
818errorSendComplete(const Comm::ConnectionPointer &conn, char *, size_t size, Comm::Flag errflag, int, void *data)
819{
820 ErrorState *err = static_cast<ErrorState *>(data);
821 debugs(4, 3, conn << ", size=" << size);
822
823 if (errflag != Comm::ERR_CLOSING) {
824 if (err->callback) {
825 debugs(4, 3, "errorSendComplete: callback");
826 err->callback(conn->fd, err->callback_data, size);
827 } else {
828 debugs(4, 3, "errorSendComplete: comm_close");
829 conn->close();
830 }
831 }
832
833 delete err;
834}
835
837{
838 debugs(4, 7, "destructing, this=" << static_cast<void*>(this));
839
841 safe_free(url);
842 wordlistDestroy(&ftp.server_msg);
843 safe_free(ftp.request);
844 safe_free(ftp.reply);
845 safe_free(ftp.cwd_msg);
847#if USE_ERR_LOCALES
849#endif
851}
852
853int
855{
856 PackableStream out(*mb);
857 const auto &encoding = CharacterSet::RFC3986_UNRESERVED();
858
859 out << "?subject=" <<
860 AnyP::Uri::Encode(SBuf("CacheErrorInfo - "),encoding) <<
862
863 SBufStream body;
864 body << "CacheHost: " << getMyHostname() << "\r\n" <<
865 "ErrPage: " << errorPageName(type) << "\r\n" <<
866 "TimeStamp: " << Time::FormatRfc1123(squid_curtime) << "\r\n" <<
867 "\r\n";
868
869 body << "ClientIP: " << src_addr << "\r\n";
870
871 if (request && request->hier.host[0] != '\0')
872 body << "ServerIP: " << request->hier.host << "\r\n";
873
874 if (xerrno)
875 body << "Err: (" << xerrno << ") " << strerror(xerrno) << "\r\n";
876
877#if USE_AUTH
879 body << "Auth ErrMsg: " << auth_user_request->denyMessage() << "\r\n";
880#endif
881
882 if (dnsError)
883 body << "DNS ErrMsg: " << *dnsError << "\r\n";
884
885 body << "\r\n";
886
887 if (request) {
888 body << "HTTP Request:\r\n";
889 MemBuf r;
890 r.init();
891 request->pack(&r, true /* hide authorization data */);
892 body << r.content();
893 }
894
895 /* - FTP stuff */
896
897 if (ftp.request) {
898 body << "FTP Request: " << ftp.request << "\r\n";
899 if (ftp.reply)
900 body << "FTP Reply: " << ftp.reply << "\r\n";
901 if (ftp.server_msg)
902 body << "FTP Msg: " << AsList(*ftp.server_msg).delimitedBy("\n") << "\r\n";
903 body << "\r\n";
904 }
905
906 out << "&body=" << AnyP::Uri::Encode(body.buf(), encoding);
907
908 return 0;
909}
910
912#define CVT_BUF_SZ 512
913
914void
916{
918
919 try {
920 const auto logformat = build.input + LogformatMagic.length();
921
922 // Logformat supports undocumented "external" encoding specifications
923 // like [%>h] or "%<a". To preserve the possibility of extending
924 // @Squid{} syntax to non-logformat sequences, we require logformat
925 // sequences to start with '%'. This restriction does not limit
926 // logformat quoting abilities. TODO: Deprecate "external" encoding?
927 if (*logformat != '%')
928 throw TexcHere("logformat expressions that do not start with % are not supported");
929
930 static MemBuf result;
931 result.reset();
932 const auto logformatLen = Format::AssembleOne(logformat, result, ale);
933 assert(logformatLen > 0);
934 const auto closure = logformat + logformatLen;
935 if (*closure != '}')
936 throw TexcHere("Missing closing brace (})");
937 build.output.append(result.content(), result.contentSize());
938 build.input = closure + 1;
939 return;
940 } catch (...) {
941 noteBuildError("Bad @Squid{logformat} sequence", build.input);
942 }
943
944 // we cannot recover reliably so stop interpreting the rest of input
945 const auto remainingSize = strlen(build.input);
946 build.output.append(build.input, remainingSize);
947 build.input += remainingSize;
948}
949
950void
952{
953 static MemBuf mb;
954 const char *p = nullptr; /* takes priority over mb if set */
955 int do_quote = 1;
956 int no_urlescape = 0; /* if true then item is NOT to be further URL-encoded */
957 char ntoabuf[MAX_IPSTRLEN];
958
959 mb.reset();
960
961 const auto &building_deny_info_url = build.building_deny_info_url; // a change reduction hack
962
963 Assure(*build.input == '%');
964 const auto letter = build.input[1]; // may be the terminating NUL
965
966 switch (letter) {
967
968 case 'a':
969#if USE_AUTH
972 if (!p)
973#endif
974 p = "-";
975 break;
976
977 case 'A':
978 // TODO: When/if we get ALE here, pass it as well
979 if (const auto addr = FindListeningPortAddress(request.getRaw(), nullptr))
980 mb.appendf("%s", addr->toStr(ntoabuf, MAX_IPSTRLEN));
981 else
982 p = "-";
983 break;
984
985 case 'b':
986 mb.appendf("%u", getMyPort());
987 break;
988
989 case 'B':
990 if (building_deny_info_url) break;
991 if (request) {
992 const SBuf &tmp = Ftp::UrlWith2f(request.getRaw());
993 mb.append(tmp.rawContent(), tmp.length());
994 } else
995 p = "[no URL]";
996 break;
997
998 case 'c':
999 if (building_deny_info_url) break;
1000 p = errorPageName(type);
1001 break;
1002
1003 case 'D':
1004 if (!build.allowRecursion)
1005 p = "%D"; // if recursion is not allowed, do not convert
1006 else if (detail) {
1007 auto rawDetail = detail->verbose(request);
1008 // XXX: Performance regression. c_str() reallocates
1009 const auto compiledDetail = compileBody(rawDetail.c_str(), false);
1010 mb.append(compiledDetail.rawContent(), compiledDetail.length());
1011 do_quote = 0;
1012 }
1013 if (!mb.contentSize())
1014 mb.append("[No Error Detail]", 17);
1015 break;
1016
1017 case 'e':
1018 mb.appendf("%d", xerrno);
1019 break;
1020
1021 case 'E':
1022 if (xerrno)
1023 mb.appendf("(%d) %s", xerrno, strerror(xerrno));
1024 else
1025 mb.append("[No Error]", 10);
1026 break;
1027
1028 case 'f':
1029 if (building_deny_info_url) break;
1030 /* FTP REQUEST LINE */
1031 if (ftp.request)
1032 p = ftp.request;
1033 else
1034 p = "nothing";
1035 break;
1036
1037 case 'F':
1038 if (building_deny_info_url) break;
1039 /* FTP REPLY LINE */
1040 if (ftp.reply)
1041 p = ftp.reply;
1042 else
1043 p = "nothing";
1044 break;
1045
1046 case 'g':
1047 if (building_deny_info_url) break;
1048 /* FTP SERVER RESPONSE */
1049 if (ftp.listing) {
1050 mb.append(ftp.listing->content(), ftp.listing->contentSize());
1051 do_quote = 0;
1052 } else if (ftp.server_msg) {
1053 wordlistCat(ftp.server_msg, &mb);
1054 }
1055 break;
1056
1057 case 'h':
1058 mb.appendf("%s", getMyHostname());
1059 break;
1060
1061 case 'H':
1062 if (request) {
1063 if (request->hier.host[0] != '\0') // if non-empty string.
1064 p = request->hier.host;
1065 else
1066 p = request->url.host();
1067 } else if (!building_deny_info_url)
1068 p = "[unknown host]";
1069 break;
1070
1071 case 'i':
1072 mb.appendf("%s", src_addr.toStr(ntoabuf,MAX_IPSTRLEN));
1073 break;
1074
1075 case 'I':
1076 if (request && request->hier.tcpServer)
1078 else if (!building_deny_info_url)
1079 p = "[unknown]";
1080 break;
1081
1082 case 'l':
1083 if (building_deny_info_url) break;
1085 do_quote = 0;
1086 break;
1087
1088 case 'L':
1089 if (building_deny_info_url) break;
1090 if (Config.errHtmlText) {
1091 mb.appendf("%s", Config.errHtmlText);
1092 do_quote = 0;
1093 } else
1094 p = "[not available]";
1095 break;
1096
1097 case 'm':
1098 if (building_deny_info_url) break;
1099#if USE_AUTH
1101 p = auth_user_request->denyMessage("[not available]");
1102 else
1103 p = "[not available]";
1104#else
1105 p = "-";
1106#endif
1107 break;
1108
1109 case 'M':
1110 if (request) {
1111 const SBuf &m = request->method.image();
1112 mb.append(m.rawContent(), m.length());
1113 } else if (!building_deny_info_url)
1114 p = "[unknown method]";
1115 break;
1116
1117 case 'O':
1118 if (!building_deny_info_url)
1119 do_quote = 0;
1120 [[fallthrough]];
1121 case 'o':
1123 if (!p && !building_deny_info_url)
1124 p = "[not available]";
1125 break;
1126
1127 case 'p':
1128 if (request && request->url.port()) {
1129 mb.appendf("%hu", *request->url.port());
1130 } else if (!building_deny_info_url) {
1131 p = "[unknown port]";
1132 }
1133 break;
1134
1135 case 'P':
1136 if (request) {
1137 const SBuf &m = request->url.getScheme().image();
1138 mb.append(m.rawContent(), m.length());
1139 } else if (!building_deny_info_url) {
1140 p = "[unknown protocol]";
1141 }
1142 break;
1143
1144 case 'R':
1145 if (building_deny_info_url) {
1146 if (request != nullptr) {
1147 const SBuf &tmp = request->url.absolutePath();
1148 mb.append(tmp.rawContent(), tmp.length());
1149 no_urlescape = 1;
1150 } else
1151 p = "[no request]";
1152 break;
1153 }
1154 else if (request)
1155 request->pack(&mb, true /* hide authorization data */);
1156 else
1157 p = "[no request]";
1158 break;
1159
1160 case 's':
1161 /* for backward compat we make %s show the full URL. Drop this in some future release. */
1162 if (building_deny_info_url) {
1163 if (request) {
1164 const SBuf &tmp = request->effectiveRequestUri();
1165 mb.append(tmp.rawContent(), tmp.length());
1166 } else
1167 p = url;
1168 debugs(0, DBG_CRITICAL, "WARNING: deny_info now accepts coded tags. Use %u to get the full URL instead of %s");
1169 } else
1171 break;
1172
1173 case 'S':
1174 if (building_deny_info_url) {
1176 break;
1177 }
1178 /* signature may contain %-escapes, recursion */
1180 const int saved_id = page_id;
1182 const auto signature = buildBody();
1183 mb.append(signature.rawContent(), signature.length());
1184 page_id = saved_id;
1185 do_quote = 0;
1186 } else {
1187 /* wow, somebody put %S into ERR_SIGNATURE, stop recursion */
1188 p = "[%S]";
1189 }
1190 break;
1191
1192 case 't':
1194 break;
1195
1196 case 'T':
1198 break;
1199
1200 case 'U':
1201 /* Using the fake-https version of absolute-URI so error pages see https:// */
1202 /* even when the url-path cannot be shown as more than '*' */
1203 if (request)
1205 else if (url)
1206 p = url;
1207 else if (!building_deny_info_url)
1208 p = "[no URL]";
1209 break;
1210
1211 case 'u':
1212 if (request) {
1213 const SBuf &tmp = request->effectiveRequestUri();
1214 mb.append(tmp.rawContent(), tmp.length());
1215 } else if (url)
1216 p = url;
1217 else if (!building_deny_info_url)
1218 p = "[no URL]";
1219 break;
1220
1221 case 'w':
1222 if (Config.adminEmail)
1223 mb.appendf("%s", Config.adminEmail);
1224 else if (!building_deny_info_url)
1225 p = "[unknown]";
1226 break;
1227
1228 case 'W':
1229 if (building_deny_info_url) break;
1231 Dump(&mb);
1232 no_urlescape = 1;
1233 do_quote = 0;
1234 break;
1235
1236 case 'x':
1237 if (detail) {
1238 const auto brief = detail->brief();
1239 mb.append(brief.rawContent(), brief.length());
1240 } else if (!building_deny_info_url) {
1241 p = "[Unknown Error Code]";
1242 }
1243 break;
1244
1245 case 'z':
1246 if (building_deny_info_url) break;
1247 if (dnsError)
1248 p = dnsError->c_str();
1249 else if (ftp.cwd_msg)
1250 p = ftp.cwd_msg;
1251 else
1252 p = "[unknown]";
1253 break;
1254
1255 case 'Z':
1256 if (building_deny_info_url) break;
1257 if (err_msg)
1258 p = err_msg;
1259 else
1260 p = "[unknown]";
1261 break;
1262
1263 case '%':
1264 p = "%";
1265 break;
1266
1267 case '\0':
1268 // XXX: Partially duplicates error handling code of the `default:` case.
1269 // TODO: Refactor bypassBuildErrorXXX() to accept `build` and determine the source of the error.
1270 if (building_deny_info_url)
1271 bypassBuildErrorXXX("Bare % at the end of deny_info", build.input);
1272 else
1273 bypassBuildErrorXXX("Bare % at the end of error page", build.input);
1274 p = "%";
1275 do_quote = 0;
1276 break;
1277
1278 default:
1279 if (building_deny_info_url)
1280 bypassBuildErrorXXX("Unsupported deny_info %code", build.input);
1281 else if (letter != ';')
1282 bypassBuildErrorXXX("Unsupported error page %code", build.input);
1283 // else too many "font-size: 100%;" template errors to report
1284
1285 Assure(build.input[1]);
1286 mb.append(build.input, 2);
1287 do_quote = 0;
1288 break;
1289 }
1290
1291 if (!p)
1292 p = mb.buf; /* do not use mb after this assignment! */
1293
1294 assert(p);
1295
1296 // TODO: Add an I/O manipulator to report non-printable chars better.
1297 debugs(4, 3, "%" << (letter ? letter : '?') << " --> '" << p << "'" );
1298
1299 if (do_quote)
1300 p = html_quote(p);
1301
1302 if (building_deny_info_url && !no_urlescape)
1303 p = rfc1738_escape_part(p);
1304
1305 // TODO: Optimize by replacing mb with direct build.output usage.
1306 build.output.append(p, strlen(p));
1307 ++build.input; // skip the parsed % character
1308 if (letter)
1309 ++build.input; // when it was present, skip the parsed letter after %
1310}
1311
1312void
1314{
1315 if (const auto urlTemplate = ErrorPage::IsDenyInfoUri(page_id)) {
1316 (void)compile(urlTemplate, true, true);
1317 } else {
1320 (void)compileBody(error_text[page_id], true);
1321 }
1322}
1323
1324HttpReply *
1326{
1327 // Make sure error codes get back to the client side for logging and
1328 // error tracking.
1329 if (request) {
1332 } else if (ale) {
1333 Error err(type, detail);
1335 ale->updateError(err);
1336 }
1337
1338 if (response_)
1339 return response_.getRaw();
1340
1341 HttpReply *rep = new HttpReply;
1342 const char *name = errorPageName(page_id);
1343 /* no LMT for error pages; error pages expire immediately */
1344
1345 if (const auto urlTemplate = ErrorPage::IsDenyInfoUri(page_id)) {
1346 /* Redirection */
1348 // Use configured 3xx reply status if set.
1349 if (name[0] == '3')
1350 status = httpStatus;
1351 else {
1352 // Use 307 for HTTP/1.1 non-GET/HEAD requests.
1355 }
1356
1357 rep->setHeaders(status, nullptr, "text/html;charset=utf-8", 0, 0, -1);
1358
1359 if (request) {
1360 auto location = compile(urlTemplate, true, true);
1361 rep->header.putStr(Http::HdrType::LOCATION, location.c_str());
1362 }
1363
1364 httpHeaderPutStrf(&rep->header, Http::HdrType::X_SQUID_ERROR, "%d %s", httpStatus, "Access Denied");
1365 } else {
1366 const auto body = buildBody();
1367 rep->setHeaders(httpStatus, nullptr, "text/html;charset=utf-8", body.length(), 0, -1);
1368 /*
1369 * include some information for downstream caches. Implicit
1370 * replaceable content. This isn't quite sufficient. xerrno is not
1371 * necessarily meaningful to another system, so we really should
1372 * expand it. Additionally, we should identify ourselves. Someone
1373 * might want to know. Someone _will_ want to know OTOH, the first
1374 * X-CACHE-MISS entry should tell us who.
1375 */
1377
1378#if USE_ERR_LOCALES
1379 /*
1380 * If error page auto-negotiate is enabled in any way, send the Vary.
1381 * RFC 2616 section 13.6 and 14.44 says MAY and SHOULD do this.
1382 * We have even better reasons though:
1383 * see https://wiki.squid-cache.org/KnowledgeBase/VaryNotCaching
1384 */
1385 if (!Config.errorDirectory) {
1386 /* We 'negotiated' this ONLY from the Accept-Language. */
1387 static const SBuf acceptLanguage("Accept-Language");
1388 rep->header.updateOrAddStr(Http::HdrType::VARY, acceptLanguage);
1389 }
1390
1391 /* add the Content-Language header according to RFC section 14.12 */
1392 if (err_language) {
1394 } else
1395#endif /* USE_ERROR_LOCALES */
1396 {
1397 /* default templates are in English */
1398 /* language is known unless error_directory override used */
1401 }
1402
1403 rep->body.set(body);
1404 }
1405
1406 return rep;
1407}
1408
1409SBuf
1411{
1413
1414#if USE_ERR_LOCALES
1422
1423 ErrorPageFile localeTmpl(err_type_str[page_id], static_cast<err_type>(page_id));
1424 if (localeTmpl.loadFor(request.getRaw())) {
1425 inputLocation = localeTmpl.filename;
1426 assert(localeTmpl.language());
1427 err_language = xstrdup(localeTmpl.language());
1428 return compileBody(localeTmpl.text(), true);
1429 }
1430 }
1431#endif /* USE_ERR_LOCALES */
1432
1437#if USE_ERR_LOCALES
1440#endif
1441 debugs(4, 2, "No existing error page language negotiated for " << this << ". Using default error file.");
1442 return compileBody(error_text[page_id], true);
1443}
1444
1445SBuf
1446ErrorState::compileBody(const char *input, bool allowRecursion)
1447{
1448 return compile(input, false, allowRecursion);
1449}
1450
1451SBuf
1452ErrorState::compile(const char *input, bool building_deny_info_url, bool allowRecursion)
1453{
1454 assert(input);
1455
1456 Build build;
1457 build.building_deny_info_url = building_deny_info_url;
1458 build.allowRecursion = allowRecursion;
1459 build.input = input;
1460
1461 auto blockStart = build.input;
1462 while (const auto letter = *build.input) {
1463 if (letter == '%') {
1464 build.output.append(blockStart, build.input - blockStart);
1465 compileLegacyCode(build);
1466 blockStart = build.input;
1467 }
1468 else if (letter == '@' && LogformatMagic.cmp(build.input, LogformatMagic.length()) == 0) {
1469 build.output.append(blockStart, build.input - blockStart);
1470 compileLogformatCode(build);
1471 blockStart = build.input;
1472 } else {
1473 ++build.input;
1474 }
1475 }
1476 build.output.append(blockStart, build.input - blockStart);
1477 return build.output;
1478}
1479
1487void
1488ErrorState::noteBuildError_(const char *const msg, const char * const errorLocation, const bool forceBypass)
1489{
1491 const auto runtime = !starting_up;
1492 if (runtime || forceBypass) {
1493 // swallow this problem because the admin may not be (and/or the page
1494 // building code is not) ready to handle throwing consequences
1495
1496 static unsigned int seenErrors = 0;
1497 ++seenErrors;
1498
1499 const auto debugLevel =
1500 (seenErrors > 100) ? DBG_DATA:
1502 3; // most other errors have been reported as configuration errors
1503
1504 // Error fatality depends on the error context: Reconfiguration errors
1505 // are, like startup ones, DBG_CRITICAL but will never become FATAL.
1506 if (starting_up && seenErrors <= 10)
1507 debugs(4, debugLevel, "WARNING: The following configuration error will be fatal in future Squid versions");
1508
1509 debugs(4, debugLevel, "ERROR: " << BuildErrorPrinter(inputLocation, page_id, msg, errorLocation));
1510 } else {
1511 throw TexcHere(ToSBuf(BuildErrorPrinter(inputLocation, page_id, msg, errorLocation)));
1512 }
1513}
1514
1515/* ErrorPage::BuildErrorPrinter */
1516
1517std::ostream &
1519 if (!inputLocation.isEmpty())
1520 return os << inputLocation;
1521
1522 if (page_id < ERR_NONE || page_id >= error_page_count)
1523 return os << "[error page " << page_id << "]"; // should not happen
1524
1525 if (page_id < ERR_MAX)
1526 return os << err_type_str[page_id];
1527
1528 return os << "deny_info " << ErrorDynamicPages.at(page_id - ERR_MAX)->page_name;
1529}
1530
1531std::ostream &
1533 printLocation(os) << ": " << msg << " near ";
1534
1535 // TODO: Add support for prefix printing to Raw
1536 const size_t maxContextLength = 15; // plus "..."
1537 if (strlen(errorLocation) > maxContextLength) {
1538 os.write(errorLocation, maxContextLength);
1539 os << "...";
1540 } else {
1541 os << errorLocation;
1542 }
1543
1544 // XXX: We should not be converting (inner) exception to text if we are
1545 // going to throw again. See "add arbitrary (re)thrower-supplied details"
1546 // TODO in TextException.h for a long-term in-catcher solution.
1547 if (std::current_exception())
1548 os << "\n additional info: " << CurrentException;
1549
1550 return os;
1551}
1552
1554static void
1555ErrorPage::ImportStaticErrorText(const int page_id, const char *text, const SBuf &inputLocation)
1556{
1557 assert(!error_text[page_id]);
1558 error_text[page_id] = xstrdup(text);
1559 ValidateStaticError(page_id, inputLocation);
1560}
1561
1563static void
1564ErrorPage::ValidateStaticError(const int page_id, const SBuf &inputLocation)
1565{
1566 // Supplying nil ALE pointer limits validation to logformat %code
1567 // recognition by Format::Token::parse(). This is probably desirable
1568 // because actual %code assembly is slow and should not affect validation
1569 // when our ALE cannot have any real data (this code is not associated
1570 // with any real transaction).
1571 ErrorState anErr(err_type(page_id), Http::scNone, nullptr, nullptr);
1572 anErr.inputLocation = inputLocation;
1573 anErr.validate();
1574}
1575
1576std::ostream &
1577operator <<(std::ostream &os, const ErrorState *err)
1578{
1579 os << RawPointer(err).orNil();
1580 return os;
1581}
1582
#define Assure(condition)
Definition Assure.h:35
CommCbFunPtrCallT< Dialer > * commCbCall(int debugSection, int debugLevel, const char *callName, const Dialer &dialer)
Definition CommCalls.h:312
void IOCB(const Comm::ConnectionPointer &conn, char *, size_t size, Comm::Flag flag, int xerrno, void *data)
Definition CommCalls.h:34
const char * err_type_str[]
void httpHeaderPutStrf(HttpHeader *hdr, Http::HdrType id, const char *fmt,...)
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
Definition IoManip.h:73
int size
Definition ModDevPoll.cc:70
time_t squid_curtime
class SquidConfig Config
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
#define Must(condition)
const char * urlCanonicalFakeHttps(const HttpRequest *request)
Definition Uri.cc:819
#define assert(EX)
Definition assert.h:17
void self_destruct(void)
Definition cache_cf.cc:275
#define CBDATA_CLASS_INIT(type)
Definition cbdata.h:325
void updateError(const Error &)
sets (or updates the already stored) transaction error as needed
SBuf image() const
Definition UriScheme.h:57
AnyP::UriScheme const & getScheme() const
Definition Uri.h:58
SBuf & absolutePath() const
RFC 3986 section 4.2 relative reference called 'absolute-path'.
Definition Uri.cc:775
void port(const Port p)
reset authority port subcomponent
Definition Uri.h:90
void host(const char *src)
Definition Uri.cc:154
static SBuf Encode(const SBuf &, const CharacterSet &expected)
Definition Uri.cc:76
std::ostream manipulator to print containers as flat lists
Definition IoManip.h:177
auto & delimitedBy(const char *const d)
a c-string to print between consecutive items (if any). Caller must ensure lifetime.
Definition IoManip.h:188
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
Ip::Address remote
Definition Connection.h:152
virtual SBuf verbose(const HttpRequestPointer &) const =0
virtual SBuf brief() const =0
an error page created from admin-configurable metadata (e.g. deny_info)
Definition errorpage.cc:72
const char * uri
admin-configured HTTP Location header value for redirection responses
Definition errorpage.cc:86
ErrorDynamicPageInfo(ErrorDynamicPageInfo &&)=delete
Http::StatusCode page_redirect
admin-configured HTTP status code
Definition errorpage.cc:96
SBuf cfgLocation
deny_info directive position in squid.conf (for reporting)
Definition errorpage.cc:92
ErrorDynamicPageInfo(const int anId, const char *aName, const SBuf &aCfgLocation)
Definition errorpage.cc:567
int id
error_text[] index for response body (unused in redirection responses)
Definition errorpage.cc:78
const char * filename
admin-configured name for the error page template (custom or standard)
Definition errorpage.cc:89
void setDefault() override
recover from loadDefault() failure to load or parse() a template
Definition errorpage.cc:228
const char * text()
The template text data read from disk.
Definition errorpage.cc:225
ErrorPageFile(const char *name, const err_type code)
Definition errorpage.cc:222
pretty-prints error page/deny_info building error
Definition errorpage.cc:117
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)
Definition errorpage.cc:119
state and parameters shared by several ErrorState::compile*() methods
Definition errorpage.cc:107
bool allowRecursion
whether top-level compile() calls are OK
Definition errorpage.cc:112
bool building_deny_info_url
whether we compile deny_info URI
Definition errorpage.cc:111
const char * input
template bytes that need to be compiled
Definition errorpage.cc:110
SBuf output
compilation result
Definition errorpage.cc:109
static ErrorState * NewForwarding(err_type, HttpRequestPointer &, const AccessLogEntryPointer &)
Creates a general request forwarding error with the right http_status.
Definition errorpage.cc:693
SBuf compile(const char *input, bool building_deny_info_url, bool allowRecursion)
char * redirect_url
Definition errorpage.h:184
char * err_msg
Definition errorpage.h:196
void validate()
ensures that a future BuildHttpReply() is likely to succeed
err_type type
Definition errorpage.h:170
void compileLegacyCode(Build &build)
compile a single-letter code like D
Definition errorpage.cc:951
void noteBuildError_(const char *msg, const char *errorLocation, bool forceBypass)
AccessLogEntryPointer ale
transaction details (or nil)
Definition errorpage.h:198
ERCB * callback
Definition errorpage.h:185
std::optional< SBuf > dnsError
DNS lookup error message.
Definition errorpage.h:180
void bypassBuildErrorXXX(const char *const msg, const char *const errorLocation)
Definition errorpage.h:158
int Dump(MemBuf *mb)
Definition errorpage.cc:854
ErrorDetail::Pointer detail
Definition errorpage.h:204
char * err_language
Definition errorpage.h:172
void compileLogformatCode(Build &build)
compile @Squid{code} sequence containing a single logformat code
Definition errorpage.cc:915
char * url
Definition errorpage.h:178
Auth::UserRequest::Pointer auth_user_request
Definition errorpage.h:175
SBuf inputLocation
the source of the error template (for reporting purposes)
Definition errorpage.h:117
Ip::Address src_addr
Definition errorpage.h:183
static const SBuf LogformatMagic
marks each embedded logformat entry
Definition errorpage.h:211
HttpRequestPointer request
Definition errorpage.h:177
SBuf compileBody(const char *text, bool allowRecursion)
HttpReply * BuildHttpReply(void)
struct ErrorState::@47 ftp
void * callback_data
Definition errorpage.h:186
SBuf buildBody()
locates the right error page template for this error and compiles it
HttpReplyPointer response_
Definition errorpage.h:206
ErrorState()=delete
Http::StatusCode httpStatus
Definition errorpage.h:173
void noteBuildError(const char *const msg, const char *const errorLocation)
Definition errorpage.h:149
a transaction problem
Definition Error.h:27
void update(const Error &)
if necessary, stores the given error information (if any)
Definition Error.cc:51
an error page (or a part of an error page) with hard-coded template text
Definition errorpage.cc:155
const char * text
a string literal containing the error template
Definition errorpage.cc:158
err_type type
identifies the error (or a special error template part)
Definition errorpage.cc:157
char host[SQUIDHOSTNAMELEN]
Comm::ConnectionPointer tcpServer
TCP/IP level details of the last peer/server connection.
void set(const SBuf &newContent)
Definition HttpBody.h:26
void putStr(Http::HdrType id, const char *str)
String getList(Http::HdrType id) const
void updateOrAddStr(Http::HdrType, const SBuf &)
Http::StatusLine sline
Definition HttpReply.h:56
MemBuf * pack() const
Definition HttpReply.cc:112
void setHeaders(Http::StatusCode status, const char *reason, const char *ctype, int64_t clen, time_t lmt, time_t expires)
Definition HttpReply.cc:170
HttpBody body
Definition HttpReply.h:58
const SBuf & image() const
HttpRequestMethod method
void pack(Packable *p, bool maskSensitiveInfo=false) const
HierarchyLogEntry hier
String extacl_message
RequestFlags flags
Auth::UserRequest::Pointer auth_user_request
Error error
the first transaction problem encountered (or falsy)
AnyP::Uri url
the request URI
Ip::Address client_addr
const SBuf & effectiveRequestUri() const
RFC 7230 section 5.5 - Effective Request URI.
HttpHeader header
Definition Message.h:74
AnyP::ProtocolVersion http_ver
Definition Message.h:72
Http::StatusCode status() const
retrieve the status code for this status line
Definition StatusLine.h:45
char * toStr(char *buf, const unsigned int blen, int force=AF_UNSPEC) const
Definition Address.cc:804
void append(const char *c, int sz) override
Definition MemBuf.cc:209
void init(mb_size_t szInit, mb_size_t szMax)
Definition MemBuf.cc:93
char * buf
Definition MemBuf.h:134
char * content()
start of the added data
Definition MemBuf.h:41
mb_size_t contentSize() const
available data size
Definition MemBuf.h:47
void reset()
Definition MemBuf.cc:129
int nclients
Definition MemObject.h:156
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
Definition Packable.h:61
C * getRaw() const
Definition RefCount.h:89
bool needValidation
SBuf buf()
bytes written so far
Definition Stream.h:41
Definition SBuf.h:94
const char * rawContent() const
Definition SBuf.cc:509
char at(size_type pos) const
Definition SBuf.h:253
size_type length() const
Returns the number of bytes stored in SBuf.
Definition SBuf.h:419
int cmp(const SBuf &S, const size_type n) const
shorthand version for compare()
Definition SBuf.h:279
bool isEmpty() const
Definition SBuf.h:435
SBuf & append(const SBuf &S)
Definition SBuf.cc:185
char * errHtmlText
char * errorStylesheet
int errorLogMissingLanguages
char * errorDirectory
char * errorDefaultLanguage
struct SquidConfig::@90 onoff
char * adminEmail
uint16_t flags
Definition Store.h:231
void storeErrorResponse(HttpReply *reply)
Store a prepared error response. MemObject locks the reply object.
Definition store.cc:1688
MemObject * mem_obj
Definition Store.h:220
store_status_t store_status
Definition Store.h:243
bool isEmpty() const
Definition Store.h:65
String substr(size_type from, size_type to) const
Definition String.cc:197
char const * termedBuf() const
Definition SquidString.h:97
size_type size() const
Definition SquidString.h:78
static ErrorDetail::Pointer NewIfAny(const int errorNo)
virtual void setDefault()
recover from loadDefault() failure to load or parse() a template
Definition errorpage.h:323
bool loadFromFile(const char *path)
Definition errorpage.cc:424
SBuf template_
raw template contents
Definition errorpage.h:332
SBuf filename
where the template was loaded from
Definition errorpage.h:314
bool loaded() const
return true if the data loaded from disk without any problem
Definition errorpage.h:286
TemplateFile(const char *name, const err_type code)
Definition errorpage.cc:357
bool wasLoaded
True if the template data read from disk without any problem.
Definition errorpage.h:333
bool tryLoadTemplate(const char *lang)
Definition errorpage.cc:399
String templateName
The name of the template.
Definition errorpage.h:335
void loadDefault()
Definition errorpage.cc:363
const char * language()
The language used for the template.
Definition errorpage.h:312
virtual bool parse()
post-process the loaded template
Definition errorpage.h:320
err_type templateCode
The internal code for this template.
Definition errorpage.h:336
String errLanguage
The error language of the template.
Definition errorpage.h:334
bool silent
Whether to print error messages on cache.log file or not. It is user defined.
Definition errorpage.h:316
bool loadFor(const HttpRequest *request)
Definition errorpage.cc:526
#define DBG_DATA
Definition Stream.h:40
#define MYNAME
Definition Stream.h:219
#define DBG_IMPORTANT
Definition Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition Stream.h:192
#define DBG_CRITICAL
Definition Stream.h:37
#define O_TEXT
Definition defines.h:131
#define EBIT_TEST(flag, bit)
Definition defines.h:67
@ ENTRY_ABORTED
Definition enums.h:110
@ STORE_PENDING
Definition enums.h:46
err_type
Definition forward.h:14
@ ERR_SECURE_ACCEPT_FAIL
Definition forward.h:80
@ TCP_RESET
Definition forward.h:77
@ ERR_MAX
Definition forward.h:88
@ ERR_NONE
Definition forward.h:15
@ ERR_REQUEST_PARSE_TIMEOUT
Definition forward.h:82
@ ERR_REQUEST_START_TIMEOUT
Definition forward.h:81
@ ERR_CLIENT_GONE
Definition forward.h:79
@ ERR_SQUID_SIGNATURE
Definition forward.h:71
@ ERR_RELAY_REMOTE
Definition forward.h:83
static const std::array< HardCodedError, 7 > HardCodedErrors
error messages that cannot be configured/customized externally
Definition errorpage.cc:162
static std::ostream & operator<<(std::ostream &os, const ErrorState &err)
compactly prints top-level ErrorState information (for debugging)
Definition errorpage.cc:684
err_type errorReservePageId(const char *page_name, const SBuf &cfgLocation)
allocates a new slot for the error page
Definition errorpage.cc:656
static IOCB errorSendComplete
Definition errorpage.cc:215
#define DEFAULT_SQUID_ERROR_DIR
Definition errorpage.cc:61
bool strHdrAcptLangGetItem(const String &hdr, char *lang, int langLen, size_t &pos)
Definition errorpage.cc:472
bool strHdrAcptLangGetItem(const String &hdr, char *lang, int langLen, size_t &pos)
Definition errorpage.cc:472
int FD_READ_METHOD(int fd, char *buf, int len)
Definition fde.h:192
int file_open(const char *path, int mode)
Definition fs_io.cc:66
void file_close(int fd)
Definition fs_io.cc:92
char const * visible_appname_string
const char * external_acl_message
int starting_up
int reconfiguring
void errorInitialize(void)
Definition errorpage.cc:261
void errorSend(const Comm::ConnectionPointer &conn, ErrorState *err)
Definition errorpage.cc:794
void errorClean(void)
Definition errorpage.cc:323
void errorAppendEntry(StoreEntry *entry, ErrorState *err)
Definition errorpage.cc:740
const char * errorPageName(int pageId)
error ID to string
Definition errorpage.cc:671
static char ** error_text
Definition errorpage.cc:206
static const char * errorFindHardText(err_type type)
Definition errorpage.cc:348
static std::vector< ErrorDynamicPageInfo * > ErrorDynamicPages
Definition errorpage.cc:201
static err_type & operator++(err_type &anErr)
Definition errorpage.cc:236
static int operator-(err_type const &anErr, err_type const &anErr2)
Definition errorpage.cc:245
static int errorPageId(const char *page_name)
Definition errorpage.cc:640
static int error_page_count
Definition errorpage.cc:209
static MemBuf error_stylesheet
Definition errorpage.cc:212
char * html_quote(const char *string)
Definition Quoting.cc:42
#define MAX_IPSTRLEN
Length of buffer that needs to be allocated to old a null-terminated IP-string.
Definition forward.h:25
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition Connection.cc:27
void Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE *free_func)
Definition Write.cc:33
Flag
Definition Flag.h:15
@ ERR_CLOSING
Definition Flag.h:24
static const char * IsDenyInfoUri(const int page_id)
Definition errorpage.cc:253
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)
Definition errorpage.cc:140
size_t AssembleOne(const char *start, MemBuf &buf, const AccessLogEntryPointer &ale)
Definition Format.cc:99
const SBuf & UrlWith2f(HttpRequest *)
Definition forward.h:18
StatusCode
Definition StatusCode.h:20
@ scGatewayTimeout
Definition StatusCode.h:77
@ scFound
Definition StatusCode.h:39
@ scNone
Definition StatusCode.h:21
@ scTemporaryRedirect
Definition StatusCode.h:43
@ scServiceUnavailable
Definition StatusCode.h:76
@ METHOD_GET
Definition MethodType.h:25
@ METHOD_HEAD
Definition MethodType.h:28
AnyP::ProtocolVersion ProtocolVersion()
void errorDetailClean()
void errorDetailInitialize()
const char * FormatRfc1123(time_t)
Definition rfc1123.cc:202
const char * FormatHttpd(time_t)
Definition gadgets.cc:116
#define xfree
#define xstrdup
#define rfc1738_escape_part(x)
Definition rfc1738.h:51
SBuf ToSBuf(Args &&... args)
slowly stream-prints all arguments into a freshly allocated SBuf
Definition Stream.h:63
#define MAXPATHLEN
Definition stdio.h:62
char * strerror(int ern)
Definition strerror.c:22
void unsigned int
Definition stub_fd.cc:16
SBuf text("GET http://resource.com/path HTTP/1.1\r\n" "Host: resource.com\r\n" "Cookie: laijkpk3422r j1noin \r\n" "\r\n")
const char * getMyHostname(void)
Definition tools.cc:460
int getMyPort(void)
Definition tools.cc:1063
void wordlistDestroy(wordlist **list)
destroy a wordlist
Definition wordlist.cc:16
void wordlistCat(const wordlist *w, MemBuf *mb)
Definition wordlist.cc:35
void * xcalloc(size_t n, size_t sz)
Definition xalloc.cc:71
#define safe_free(x)
Definition xalloc.h:73
#define xisspace(x)
Definition xis.h:15
#define xisdigit(x)
Definition xis.h:18
#define xtolower(x)
Definition xis.h:17
const char * xstrerr(int error)
Definition xstrerror.cc:83