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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors