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/Quoting.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 ale(anAle)
686{
687}
688
690 ErrorState(t, anAle)
691{
692 if (page_id >= ERR_MAX && ErrorDynamicPages[page_id - ERR_MAX]->page_redirect != Http::scNone)
693 httpStatus = ErrorDynamicPages[page_id - ERR_MAX]->page_redirect;
694 else
695 httpStatus = status;
696
697 if (req) {
698 request = req;
699 src_addr = req->client_addr;
700 }
701}
702
705{
706 Must(errorReply);
707 response_ = errorReply;
708 httpStatus = errorReply->sline.status();
709
710 if (req) {
711 request = req;
712 src_addr = req->client_addr;
713 }
714}
715
716void
718{
719 assert(entry->mem_obj != nullptr);
720 assert (entry->isEmpty());
721 debugs(4, 4, "storing " << err << " in " << *entry);
722
723 if (entry->store_status != STORE_PENDING) {
724 debugs(4, 2, "Skipping error page due to store_status: " << entry->store_status);
725 /*
726 * If the entry is not STORE_PENDING, then no clients
727 * care about it, and we don't need to generate an
728 * error message
729 */
731 assert(entry->mem_obj->nclients == 0);
732 delete err;
733 return;
734 }
735
736 if (err->page_id == TCP_RESET) {
737 if (err->request) {
738 debugs(4, 2, "RSTing this reply");
739 err->request->flags.resetTcp = true;
740 }
741 }
742
743 entry->storeErrorResponse(err->BuildHttpReply());
744 delete err;
745}
746
747void
749{
750 debugs(4, 3, conn << ", err=" << err);
752
754
755 MemBuf *mb = rep->pack();
756 AsyncCall::Pointer call = commCbCall(78, 5, "errorSendComplete",
758 Comm::Write(conn, mb, call);
759 delete mb;
760}
761
771static void
772errorSendComplete(const Comm::ConnectionPointer &conn, char *, size_t size, Comm::Flag errflag, int, void *data)
773{
774 ErrorState *err = static_cast<ErrorState *>(data);
775 debugs(4, 3, conn << ", size=" << size);
776
777 if (errflag != Comm::ERR_CLOSING) {
778 if (err->callback) {
779 debugs(4, 3, "errorSendComplete: callback");
780 err->callback(conn->fd, err->callback_data, size);
781 } else {
782 debugs(4, 3, "errorSendComplete: comm_close");
783 conn->close();
784 }
785 }
786
787 delete err;
788}
789
791{
793 safe_free(url);
795 wordlistDestroy(&ftp.server_msg);
796 safe_free(ftp.request);
797 safe_free(ftp.reply);
799#if USE_ERR_LOCALES
801#endif
803}
804
805int
807{
808 MemBuf str;
809 char ntoabuf[MAX_IPSTRLEN];
810
811 str.reset();
812 /* email subject line */
813 str.appendf("CacheErrorInfo - %s", errorPageName(type));
814 mb->appendf("?subject=%s", rfc1738_escape_part(str.buf));
815 str.reset();
816 /* email body */
817 str.appendf("CacheHost: %s\r\n", getMyHostname());
818 /* - Err Msgs */
819 str.appendf("ErrPage: %s\r\n", errorPageName(type));
820
821 if (xerrno) {
822 str.appendf("Err: (%d) %s\r\n", xerrno, strerror(xerrno));
823 } else {
824 str.append("Err: [none]\r\n", 13);
825 }
826#if USE_AUTH
828 str.appendf("Auth ErrMsg: %s\r\n", auth_user_request->denyMessage());
829#endif
830 if (dnsError)
831 str.appendf("DNS ErrMsg: " SQUIDSBUFPH "\r\n", SQUIDSBUFPRINT(*dnsError));
832
833 /* - TimeStamp */
834 str.appendf("TimeStamp: %s\r\n\r\n", Time::FormatRfc1123(squid_curtime));
835
836 /* - IP stuff */
837 str.appendf("ClientIP: %s\r\n", src_addr.toStr(ntoabuf,MAX_IPSTRLEN));
838
839 if (request && request->hier.host[0] != '\0') {
840 str.appendf("ServerIP: %s\r\n", request->hier.host);
841 }
842
843 str.append("\r\n", 2);
844 /* - HTTP stuff */
845 str.append("HTTP Request:\r\n", 15);
846 if (request) {
847 str.appendf(SQUIDSBUFPH " " SQUIDSBUFPH " %s/%d.%d\n",
852 request->header.packInto(&str);
853 }
854
855 str.append("\r\n", 2);
856 /* - FTP stuff */
857
858 if (ftp.request) {
859 str.appendf("FTP Request: %s\r\n", ftp.request);
860 str.appendf("FTP Reply: %s\r\n", (ftp.reply? ftp.reply:"[none]"));
861 str.append("FTP Msg: ", 9);
862 wordlistCat(ftp.server_msg, &str);
863 str.append("\r\n", 2);
864 }
865
866 str.append("\r\n", 2);
867 mb->appendf("&body=%s", rfc1738_escape_part(str.buf));
868 str.clean();
869 return 0;
870}
871
873#define CVT_BUF_SZ 512
874
875void
877{
879
880 try {
881 const auto logformat = build.input + LogformatMagic.length();
882
883 // Logformat supports undocumented "external" encoding specifications
884 // like [%>h] or "%<a". To preserve the possibility of extending
885 // @Squid{} syntax to non-logformat sequences, we require logformat
886 // sequences to start with '%'. This restriction does not limit
887 // logformat quoting abilities. TODO: Deprecate "external" encoding?
888 if (*logformat != '%')
889 throw TexcHere("logformat expressions that do not start with % are not supported");
890
891 static MemBuf result;
892 result.reset();
893 const auto logformatLen = Format::AssembleOne(logformat, result, ale);
894 assert(logformatLen > 0);
895 const auto closure = logformat + logformatLen;
896 if (*closure != '}')
897 throw TexcHere("Missing closing brace (})");
898 build.output.append(result.content(), result.contentSize());
899 build.input = closure + 1;
900 return;
901 } catch (...) {
902 noteBuildError("Bad @Squid{logformat} sequence", build.input);
903 }
904
905 // we cannot recover reliably so stop interpreting the rest of input
906 const auto remainingSize = strlen(build.input);
907 build.output.append(build.input, remainingSize);
908 build.input += remainingSize;
909}
910
911void
913{
914 static MemBuf mb;
915 const char *p = nullptr; /* takes priority over mb if set */
916 int do_quote = 1;
917 int no_urlescape = 0; /* if true then item is NOT to be further URL-encoded */
918 char ntoabuf[MAX_IPSTRLEN];
919
920 mb.reset();
921
922 const auto &building_deny_info_url = build.building_deny_info_url; // a change reduction hack
923
924 const auto letter = build.input[1];
925
926 switch (letter) {
927
928 case 'a':
929#if USE_AUTH
932 if (!p)
933#endif
934 p = "-";
935 break;
936
937 case 'A':
938 // TODO: When/if we get ALE here, pass it as well
939 if (const auto addr = FindListeningPortAddress(request.getRaw(), nullptr))
940 mb.appendf("%s", addr->toStr(ntoabuf, MAX_IPSTRLEN));
941 else
942 p = "-";
943 break;
944
945 case 'b':
946 mb.appendf("%u", getMyPort());
947 break;
948
949 case 'B':
950 if (building_deny_info_url) break;
951 if (request) {
952 const SBuf &tmp = Ftp::UrlWith2f(request.getRaw());
953 mb.append(tmp.rawContent(), tmp.length());
954 } else
955 p = "[no URL]";
956 break;
957
958 case 'c':
959 if (building_deny_info_url) break;
960 p = errorPageName(type);
961 break;
962
963 case 'D':
964 if (!build.allowRecursion)
965 p = "%D"; // if recursion is not allowed, do not convert
966 else if (detail) {
967 auto rawDetail = detail->verbose(request);
968 // XXX: Performance regression. c_str() reallocates
969 const auto compiledDetail = compileBody(rawDetail.c_str(), false);
970 mb.append(compiledDetail.rawContent(), compiledDetail.length());
971 do_quote = 0;
972 }
973 if (!mb.contentSize())
974 mb.append("[No Error Detail]", 17);
975 break;
976
977 case 'e':
978 mb.appendf("%d", xerrno);
979 break;
980
981 case 'E':
982 if (xerrno)
983 mb.appendf("(%d) %s", xerrno, strerror(xerrno));
984 else
985 mb.append("[No Error]", 10);
986 break;
987
988 case 'f':
989 if (building_deny_info_url) break;
990 /* FTP REQUEST LINE */
991 if (ftp.request)
992 p = ftp.request;
993 else
994 p = "nothing";
995 break;
996
997 case 'F':
998 if (building_deny_info_url) break;
999 /* FTP REPLY LINE */
1000 if (ftp.reply)
1001 p = ftp.reply;
1002 else
1003 p = "nothing";
1004 break;
1005
1006 case 'g':
1007 if (building_deny_info_url) break;
1008 /* FTP SERVER RESPONSE */
1009 if (ftp.listing) {
1010 mb.append(ftp.listing->content(), ftp.listing->contentSize());
1011 do_quote = 0;
1012 } else if (ftp.server_msg) {
1013 wordlistCat(ftp.server_msg, &mb);
1014 }
1015 break;
1016
1017 case 'h':
1018 mb.appendf("%s", getMyHostname());
1019 break;
1020
1021 case 'H':
1022 if (request) {
1023 if (request->hier.host[0] != '\0') // if non-empty string.
1024 p = request->hier.host;
1025 else
1026 p = request->url.host();
1027 } else if (!building_deny_info_url)
1028 p = "[unknown host]";
1029 break;
1030
1031 case 'i':
1032 mb.appendf("%s", src_addr.toStr(ntoabuf,MAX_IPSTRLEN));
1033 break;
1034
1035 case 'I':
1036 if (request && request->hier.tcpServer)
1038 else if (!building_deny_info_url)
1039 p = "[unknown]";
1040 break;
1041
1042 case 'l':
1043 if (building_deny_info_url) break;
1045 do_quote = 0;
1046 break;
1047
1048 case 'L':
1049 if (building_deny_info_url) break;
1050 if (Config.errHtmlText) {
1051 mb.appendf("%s", Config.errHtmlText);
1052 do_quote = 0;
1053 } else
1054 p = "[not available]";
1055 break;
1056
1057 case 'm':
1058 if (building_deny_info_url) break;
1059#if USE_AUTH
1061 p = auth_user_request->denyMessage("[not available]");
1062 else
1063 p = "[not available]";
1064#else
1065 p = "-";
1066#endif
1067 break;
1068
1069 case 'M':
1070 if (request) {
1071 const SBuf &m = request->method.image();
1072 mb.append(m.rawContent(), m.length());
1073 } else if (!building_deny_info_url)
1074 p = "[unknown method]";
1075 break;
1076
1077 case 'O':
1078 if (!building_deny_info_url)
1079 do_quote = 0;
1080 [[fallthrough]];
1081 case 'o':
1083 if (!p && !building_deny_info_url)
1084 p = "[not available]";
1085 break;
1086
1087 case 'p':
1088 if (request && request->url.port()) {
1089 mb.appendf("%hu", *request->url.port());
1090 } else if (!building_deny_info_url) {
1091 p = "[unknown port]";
1092 }
1093 break;
1094
1095 case 'P':
1096 if (request) {
1097 const SBuf &m = request->url.getScheme().image();
1098 mb.append(m.rawContent(), m.length());
1099 } else if (!building_deny_info_url) {
1100 p = "[unknown protocol]";
1101 }
1102 break;
1103
1104 case 'R':
1105 if (building_deny_info_url) {
1106 if (request != nullptr) {
1107 const SBuf &tmp = request->url.path();
1108 mb.append(tmp.rawContent(), tmp.length());
1109 no_urlescape = 1;
1110 } else
1111 p = "[no request]";
1112 break;
1113 }
1114 if (request) {
1115 mb.appendf(SQUIDSBUFPH " " SQUIDSBUFPH " %s/%d.%d\n",
1120 request->header.packInto(&mb, true); //hide authorization data
1121 } else if (request_hdrs) {
1122 p = request_hdrs;
1123 } else {
1124 p = "[no request]";
1125 }
1126 break;
1127
1128 case 's':
1129 /* for backward compat we make %s show the full URL. Drop this in some future release. */
1130 if (building_deny_info_url) {
1131 if (request) {
1132 const SBuf &tmp = request->effectiveRequestUri();
1133 mb.append(tmp.rawContent(), tmp.length());
1134 } else
1135 p = url;
1136 debugs(0, DBG_CRITICAL, "WARNING: deny_info now accepts coded tags. Use %u to get the full URL instead of %s");
1137 } else
1139 break;
1140
1141 case 'S':
1142 if (building_deny_info_url) {
1144 break;
1145 }
1146 /* signature may contain %-escapes, recursion */
1148 const int saved_id = page_id;
1150 const auto signature = buildBody();
1151 mb.append(signature.rawContent(), signature.length());
1152 page_id = saved_id;
1153 do_quote = 0;
1154 } else {
1155 /* wow, somebody put %S into ERR_SIGNATURE, stop recursion */
1156 p = "[%S]";
1157 }
1158 break;
1159
1160 case 't':
1162 break;
1163
1164 case 'T':
1166 break;
1167
1168 case 'U':
1169 /* Using the fake-https version of absolute-URI so error pages see https:// */
1170 /* even when the url-path cannot be shown as more than '*' */
1171 if (request)
1173 else if (url)
1174 p = url;
1175 else if (!building_deny_info_url)
1176 p = "[no URL]";
1177 break;
1178
1179 case 'u':
1180 if (request) {
1181 const SBuf &tmp = request->effectiveRequestUri();
1182 mb.append(tmp.rawContent(), tmp.length());
1183 } else if (url)
1184 p = url;
1185 else if (!building_deny_info_url)
1186 p = "[no URL]";
1187 break;
1188
1189 case 'w':
1190 if (Config.adminEmail)
1191 mb.appendf("%s", Config.adminEmail);
1192 else if (!building_deny_info_url)
1193 p = "[unknown]";
1194 break;
1195
1196 case 'W':
1197 if (building_deny_info_url) break;
1199 Dump(&mb);
1200 no_urlescape = 1;
1201 break;
1202
1203 case 'x':
1204 if (detail) {
1205 const auto brief = detail->brief();
1206 mb.append(brief.rawContent(), brief.length());
1207 } else if (!building_deny_info_url) {
1208 p = "[Unknown Error Code]";
1209 }
1210 break;
1211
1212 case 'z':
1213 if (building_deny_info_url) break;
1214 if (dnsError)
1215 p = dnsError->c_str();
1216 else if (ftp.cwd_msg)
1217 p = ftp.cwd_msg;
1218 else
1219 p = "[unknown]";
1220 break;
1221
1222 case 'Z':
1223 if (building_deny_info_url) break;
1224 if (err_msg)
1225 p = err_msg;
1226 else
1227 p = "[unknown]";
1228 break;
1229
1230 case '%':
1231 p = "%";
1232 break;
1233
1234 default:
1235 if (building_deny_info_url)
1236 bypassBuildErrorXXX("Unsupported deny_info %code", build.input);
1237 else if (letter != ';')
1238 bypassBuildErrorXXX("Unsupported error page %code", build.input);
1239 // else too many "font-size: 100%;" template errors to report
1240
1241 mb.append(build.input, 2);
1242 do_quote = 0;
1243 break;
1244 }
1245
1246 if (!p)
1247 p = mb.buf; /* do not use mb after this assignment! */
1248
1249 assert(p);
1250
1251 debugs(4, 3, "%" << letter << " --> '" << p << "'" );
1252
1253 if (do_quote)
1254 p = html_quote(p);
1255
1256 if (building_deny_info_url && !no_urlescape)
1257 p = rfc1738_escape_part(p);
1258
1259 // TODO: Optimize by replacing mb with direct build.output usage.
1260 build.output.append(p, strlen(p));
1261 build.input += 2;
1262}
1263
1264void
1266{
1267 if (const auto urlTemplate = ErrorPage::IsDenyInfoUri(page_id)) {
1268 (void)compile(urlTemplate, true, true);
1269 } else {
1272 (void)compileBody(error_text[page_id], true);
1273 }
1274}
1275
1276HttpReply *
1278{
1279 // Make sure error codes get back to the client side for logging and
1280 // error tracking.
1281 if (request) {
1284 } else if (ale) {
1285 Error err(type, detail);
1287 ale->updateError(err);
1288 }
1289
1290 if (response_)
1291 return response_.getRaw();
1292
1293 HttpReply *rep = new HttpReply;
1294 const char *name = errorPageName(page_id);
1295 /* no LMT for error pages; error pages expire immediately */
1296
1297 if (const auto urlTemplate = ErrorPage::IsDenyInfoUri(page_id)) {
1298 /* Redirection */
1300 // Use configured 3xx reply status if set.
1301 if (name[0] == '3')
1302 status = httpStatus;
1303 else {
1304 // Use 307 for HTTP/1.1 non-GET/HEAD requests.
1307 }
1308
1309 rep->setHeaders(status, nullptr, "text/html;charset=utf-8", 0, 0, -1);
1310
1311 if (request) {
1312 auto location = compile(urlTemplate, true, true);
1313 rep->header.putStr(Http::HdrType::LOCATION, location.c_str());
1314 }
1315
1316 httpHeaderPutStrf(&rep->header, Http::HdrType::X_SQUID_ERROR, "%d %s", httpStatus, "Access Denied");
1317 } else {
1318 const auto body = buildBody();
1319 rep->setHeaders(httpStatus, nullptr, "text/html;charset=utf-8", body.length(), 0, -1);
1320 /*
1321 * include some information for downstream caches. Implicit
1322 * replaceable content. This isn't quite sufficient. xerrno is not
1323 * necessarily meaningful to another system, so we really should
1324 * expand it. Additionally, we should identify ourselves. Someone
1325 * might want to know. Someone _will_ want to know OTOH, the first
1326 * X-CACHE-MISS entry should tell us who.
1327 */
1329
1330#if USE_ERR_LOCALES
1331 /*
1332 * If error page auto-negotiate is enabled in any way, send the Vary.
1333 * RFC 2616 section 13.6 and 14.44 says MAY and SHOULD do this.
1334 * We have even better reasons though:
1335 * see https://wiki.squid-cache.org/KnowledgeBase/VaryNotCaching
1336 */
1337 if (!Config.errorDirectory) {
1338 /* We 'negotiated' this ONLY from the Accept-Language. */
1339 static const SBuf acceptLanguage("Accept-Language");
1340 rep->header.updateOrAddStr(Http::HdrType::VARY, acceptLanguage);
1341 }
1342
1343 /* add the Content-Language header according to RFC section 14.12 */
1344 if (err_language) {
1346 } else
1347#endif /* USE_ERROR_LOCALES */
1348 {
1349 /* default templates are in English */
1350 /* language is known unless error_directory override used */
1353 }
1354
1355 rep->body.set(body);
1356 }
1357
1358 return rep;
1359}
1360
1361SBuf
1363{
1365
1366#if USE_ERR_LOCALES
1374
1375 ErrorPageFile localeTmpl(err_type_str[page_id], static_cast<err_type>(page_id));
1376 if (localeTmpl.loadFor(request.getRaw())) {
1377 inputLocation = localeTmpl.filename;
1378 assert(localeTmpl.language());
1379 err_language = xstrdup(localeTmpl.language());
1380 return compileBody(localeTmpl.text(), true);
1381 }
1382 }
1383#endif /* USE_ERR_LOCALES */
1384
1389#if USE_ERR_LOCALES
1392#endif
1393 debugs(4, 2, "No existing error page language negotiated for " << this << ". Using default error file.");
1394 return compileBody(error_text[page_id], true);
1395}
1396
1397SBuf
1398ErrorState::compileBody(const char *input, bool allowRecursion)
1399{
1400 return compile(input, false, allowRecursion);
1401}
1402
1403SBuf
1404ErrorState::compile(const char *input, bool building_deny_info_url, bool allowRecursion)
1405{
1406 assert(input);
1407
1408 Build build;
1409 build.building_deny_info_url = building_deny_info_url;
1410 build.allowRecursion = allowRecursion;
1411 build.input = input;
1412
1413 auto blockStart = build.input;
1414 while (const auto letter = *build.input) {
1415 if (letter == '%') {
1416 build.output.append(blockStart, build.input - blockStart);
1417 compileLegacyCode(build);
1418 blockStart = build.input;
1419 }
1420 else if (letter == '@' && LogformatMagic.cmp(build.input, LogformatMagic.length()) == 0) {
1421 build.output.append(blockStart, build.input - blockStart);
1422 compileLogformatCode(build);
1423 blockStart = build.input;
1424 } else {
1425 ++build.input;
1426 }
1427 }
1428 build.output.append(blockStart, build.input - blockStart);
1429 return build.output;
1430}
1431
1439void
1440ErrorState::noteBuildError_(const char *msg, const char *near, const bool forceBypass)
1441{
1443 const auto runtime = !starting_up;
1444 if (runtime || forceBypass) {
1445 // swallow this problem because the admin may not be (and/or the page
1446 // building code is not) ready to handle throwing consequences
1447
1448 static unsigned int seenErrors = 0;
1449 ++seenErrors;
1450
1451 const auto debugLevel =
1452 (seenErrors > 100) ? DBG_DATA:
1454 3; // most other errors have been reported as configuration errors
1455
1456 // Error fatality depends on the error context: Reconfiguration errors
1457 // are, like startup ones, DBG_CRITICAL but will never become FATAL.
1458 if (starting_up && seenErrors <= 10)
1459 debugs(4, debugLevel, "WARNING: The following configuration error will be fatal in future Squid versions");
1460
1461 debugs(4, debugLevel, "ERROR: " << BuildErrorPrinter(inputLocation, page_id, msg, near));
1462 } else {
1463 throw TexcHere(ToSBuf(BuildErrorPrinter(inputLocation, page_id, msg, near)));
1464 }
1465}
1466
1467/* ErrorPage::BuildErrorPrinter */
1468
1469std::ostream &
1471 if (!inputLocation.isEmpty())
1472 return os << inputLocation;
1473
1474 if (page_id < ERR_NONE || page_id >= error_page_count)
1475 return os << "[error page " << page_id << "]"; // should not happen
1476
1477 if (page_id < ERR_MAX)
1478 return os << err_type_str[page_id];
1479
1480 return os << "deny_info " << ErrorDynamicPages.at(page_id - ERR_MAX)->page_name;
1481}
1482
1483std::ostream &
1485 printLocation(os) << ": " << msg << " near ";
1486
1487 // TODO: Add support for prefix printing to Raw
1488 const size_t maxContextLength = 15; // plus "..."
1489 if (strlen(near) > maxContextLength) {
1490 os.write(near, maxContextLength);
1491 os << "...";
1492 } else {
1493 os << near;
1494 }
1495
1496 // XXX: We should not be converting (inner) exception to text if we are
1497 // going to throw again. See "add arbitrary (re)thrower-supplied details"
1498 // TODO in TextException.h for a long-term in-catcher solution.
1499 if (std::current_exception())
1500 os << "\n additional info: " << CurrentException;
1501
1502 return os;
1503}
1504
1506static void
1507ErrorPage::ImportStaticErrorText(const int page_id, const char *text, const SBuf &inputLocation)
1508{
1509 assert(!error_text[page_id]);
1510 error_text[page_id] = xstrdup(text);
1511 ValidateStaticError(page_id, inputLocation);
1512}
1513
1515static void
1516ErrorPage::ValidateStaticError(const int page_id, const SBuf &inputLocation)
1517{
1518 // Supplying nil ALE pointer limits validation to logformat %code
1519 // recognition by Format::Token::parse(). This is probably desirable
1520 // because actual %code assembly is slow and should not affect validation
1521 // when our ALE cannot have any real data (this code is not associated
1522 // with any real transaction).
1523 ErrorState anErr(err_type(page_id), Http::scNone, nullptr, nullptr);
1524 anErr.inputLocation = inputLocation;
1525 anErr.validate();
1526}
1527
1528std::ostream &
1529operator <<(std::ostream &os, const ErrorState *err)
1530{
1531 if (err)
1532 os << errorPageName(err->page_id);
1533 else
1534 os << "[none]";
1535 return os;
1536}
1537
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:733
#define assert(EX)
Definition: assert.h:17
void self_destruct(void)
Definition: cache_cf.cc:277
#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:1470
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:1484
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:1404
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:1265
err_type type
Definition: errorpage.h:170
void compileLegacyCode(Build &build)
compile a single-letter code like D
Definition: errorpage.cc:912
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:806
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:876
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:1440
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:1398
HttpReply * BuildHttpReply(void)
Definition: errorpage.cc:1277
void * callback_data
Definition: errorpage.h:186
SBuf buildBody()
locates the right error page template for this error and compiles it
Definition: errorpage.cc:1362
HttpReplyPointer response_
Definition: errorpage.h:207
ErrorState()=delete
Http::StatusCode httpStatus
Definition: errorpage.h:173
struct ErrorState::@56 ftp
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: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
Auth::UserRequest::Pointer auth_user_request
Definition: HttpRequest.h:127
Error error
the first transaction problem encountered (or falsy)
Definition: HttpRequest.h:161
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: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
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:231
char * errorStylesheet
Definition: SquidConfig.h:434
int errorLogMissingLanguages
Definition: SquidConfig.h:432
char * errorDirectory
Definition: SquidConfig.h:429
char * errorDefaultLanguage
Definition: SquidConfig.h:431
struct SquidConfig::@106 onoff
int emailErrData
Definition: SquidConfig.h:320
char * adminEmail
Definition: SquidConfig.h:193
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:748
void errorClean(void)
Definition: errorpage.cc:316
void errorAppendEntry(StoreEntry *entry, ErrorState *err)
Definition: errorpage.cc:717
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
char * html_quote(const char *string)
Definition: Quoting.cc:49
#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:1507
static void ValidateStaticError(const int page_id, const SBuf &inputLocation)
validate static error page
Definition: errorpage.cc:1516
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
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
int code
Definition: smb-errors.c:145
#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