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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors