errorpage.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2021 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 "SquidTime.h"
33 #include "Store.h"
34 #include "tools.h"
35 #include "wordlist.h"
36 #if USE_AUTH
37 #include "auth/UserRequest.h"
38 #endif
39 #if USE_OPENSSL
40 #include "ssl/ErrorDetailManager.h"
41 #endif
42 
54 #if !defined(DEFAULT_SQUID_ERROR_DIR)
55 
58 #define DEFAULT_SQUID_ERROR_DIR DEFAULT_SQUID_DATA_DIR"/errors"
59 #endif
60 
63 
64 const SBuf ErrorState::LogformatMagic("@Squid{");
65 
66 /* local types */
67 
70 public:
71  ErrorDynamicPageInfo(const int anId, const char *aName, const SBuf &aCfgLocation);
73 
75  int id;
76 
80  char *page_name;
81 
83  const char *uri;
84 
86  const char *filename;
87 
90 
91  // XXX: Misnamed. Not just for redirects.
94 
95 private:
96  // no copying of any kind
98 };
99 
100 namespace ErrorPage {
101 
103 class Build
104 {
105 public:
107  const char *input = nullptr;
108  bool building_deny_info_url = false;
109  bool allowRecursion = false;
110 };
111 
114 {
115 public:
116  BuildErrorPrinter(const SBuf &anInputLocation, int aPage, const char *aMsg, const char *aNear): inputLocation(anInputLocation), page_id(aPage), msg(aMsg), near(aNear) {}
117 
119  std::ostream &print(std::ostream &) const;
120 
122  std::ostream &printLocation(std::ostream &os) const;
123 
124  /* saved constructor parameters */
126  const int page_id;
127  const char *msg;
128  const char *near;
129 };
130 
131 static inline std::ostream &
132 operator <<(std::ostream &os, const BuildErrorPrinter &context)
133 {
134  return context.print(os);
135 }
136 
137 static const char *IsDenyInfoUri(const int page_id);
138 
139 static void ImportStaticErrorText(const int page_id, const char *text, const SBuf &inputLocation);
140 static void ValidateStaticError(const int page_id, const SBuf &inputLocation);
141 
142 } // namespace ErrorPage
143 
144 /* local constant and vars */
145 
152 static const struct {
153  int type; /* and page_id */
154  const char *text;
155 }
156 
157 error_hard_text[] = {
158 
159  {
161  "\n<br>\n"
162  "<hr>\n"
163  "<div id=\"footer\">\n"
164  "Generated %T by %h (%s)\n"
165  "</div>\n"
166  "</body></html>\n"
167  },
168  {
169  TCP_RESET,
170  "reset"
171  },
172  {
174  "unexpected client disconnect"
175  },
176  {
178  "secure accept fail"
179  },
180  {
182  "request start timedout"
183  },
184  {
185  MGR_INDEX,
186  "mgr_index"
187  }
188 };
189 
191 static std::vector<ErrorDynamicPageInfo *> ErrorDynamicPages;
192 
193 /* local prototypes */
194 
196 static const int error_hard_text_count = sizeof(error_hard_text) / sizeof(*error_hard_text);
197 
199 static char **error_text = NULL;
200 
202 static int error_page_count = 0;
203 
206 
207 static const char *errorFindHardText(err_type type);
209 
213 {
214 public:
215  ErrorPageFile(const char *name, const err_type code) : TemplateFile(name, code) {}
216 
218  const char *text() { return template_.c_str(); }
219 
220 protected:
221  virtual void setDefault() override {
222  template_ = "Internal Error: Missing Template ";
223  template_.append(templateName.termedBuf());
224  }
225 };
226 
229 {
230  int tmp = (int)anErr;
231  anErr = (err_type)(++tmp);
232  return anErr;
233 }
234 
236 int operator - (err_type const &anErr, err_type const &anErr2)
237 {
238  return (int)anErr - (int)anErr2;
239 }
240 
243 static const char *
244 ErrorPage::IsDenyInfoUri(const int page_id)
245 {
246  if (ERR_MAX <= page_id && page_id < error_page_count)
247  return ErrorDynamicPages.at(page_id - ERR_MAX)->uri; // may be nil
248  return nullptr;
249 }
250 
251 void
253 {
255 
256  err_type i;
257  const char *text;
259  error_text = static_cast<char **>(xcalloc(error_page_count, sizeof(char *)));
260 
261  for (i = ERR_NONE, ++i; i < error_page_count; ++i) {
262  safe_free(error_text[i]);
263 
264  if ((text = errorFindHardText(i))) {
268  static const SBuf builtIn("built-in");
270 
271  } else if (i < ERR_MAX) {
277  ErrorPageFile errTmpl(err_type_str[i], i);
278  errTmpl.loadDefault();
279  ImportStaticErrorText(i, errTmpl.text(), errTmpl.filename);
280  } else {
285  assert(info && info->id == i && info->page_name);
286 
287  if (info->filename) {
289  ErrorPageFile errTmpl(info->filename, ERR_MAX);
290  errTmpl.loadDefault();
291  ImportStaticErrorText(i, errTmpl.text(), errTmpl.filename);
292  } else {
293  assert(info->uri);
295  }
296  }
297  }
298 
300 
301  // look for and load stylesheet into global MemBuf for it.
302  if (Config.errorStylesheet) {
303  ErrorPageFile tmpl("StylesSheet", ERR_MAX);
304  tmpl.loadFromFile(Config.errorStylesheet);
305  error_stylesheet.appendf("%s",tmpl.text());
306  }
307 
308 #if USE_OPENSSL
310 #endif
311 }
312 
313 void
315 {
316  if (error_text) {
317  int i;
318 
319  for (i = ERR_NONE + 1; i < error_page_count; ++i)
320  safe_free(error_text[i]);
321 
323  }
324 
325  while (!ErrorDynamicPages.empty()) {
326  delete ErrorDynamicPages.back();
327  ErrorDynamicPages.pop_back();
328  }
329 
330  error_page_count = 0;
331 
332 #if USE_OPENSSL
334 #endif
335 }
336 
338 static const char *
340 {
341  int i;
342 
343  for (i = 0; i < error_hard_text_count; ++i)
344  if (error_hard_text[i].type == type)
345  return error_hard_text[i].text;
346 
347  return NULL;
348 }
349 
350 TemplateFile::TemplateFile(const char *name, const err_type code): silent(false), wasLoaded(false), templateName(name), templateCode(code)
351 {
352  assert(name);
353 }
354 
355 void
357 {
358  if (loaded()) // already loaded?
359  return;
360 
362  if (Config.errorDirectory) {
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
369 
370  if (!loaded() && Config.errorDefaultLanguage) {
372  debugs(1, (templateCode < TCP_RESET ? DBG_CRITICAL : 3), "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 
391 bool
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, HERE << "wildcard fallback errors not coded yet.");
410  }
411 #endif
412 
413  return false;
414 }
415 
416 bool
417 TemplateFile::loadFromFile(const char *path)
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 
465 bool 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 
518 bool
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, HERE << "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, HERE << "Found language '" << lang << "'. Using configured default.");
540  return false;
541  }
542 
543  debugs(4, 6, HERE << "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 #endif
554 
555  return loaded();
556 }
557 
558 ErrorDynamicPageInfo::ErrorDynamicPageInfo(const int anId, const char *aName, const SBuf &aCfgLocation):
559  id(anId),
560  page_name(xstrdup(aName)),
561  uri(nullptr),
562  filename(nullptr),
563  cfgLocation(aCfgLocation),
564  page_redirect(static_cast<Http::StatusCode>(atoi(page_name)))
565 {
566  const char *filenameOrUri = nullptr;
567  if (xisdigit(*page_name)) {
568  if (const char *statusCodeEnd = strchr(page_name, ':'))
569  filenameOrUri = statusCodeEnd + 1;
570  } else {
572  filenameOrUri = page_name;
573  }
574 
575  // Guessed uri, filename, or both values may be nil or malformed.
576  // They are validated later.
577  if (!page_redirect) {
578  if (filenameOrUri && strchr(filenameOrUri, ':')) // looks like a URL
579  uri = filenameOrUri;
580  else
581  filename = filenameOrUri;
582  }
583  else if (page_redirect/100 == 3) {
584  // redirects imply a URL
585  uri = filenameOrUri;
586  } else {
587  // non-redirects imply an error page name
588  filename = filenameOrUri;
589  }
590 
591  const auto info = this; // source code change reduction hack
592  // TODO: Move and refactor to avoid self_destruct()s in reconfigure.
593 
594  /* WARNING on redirection status:
595  * 2xx are permitted, but not documented officially.
596  * - might be useful for serving static files (PAC etc) in special cases
597  * 3xx require a URL suitable for Location: header.
598  * - the current design does not allow for a Location: URI as well as a local file template
599  * although this possibility is explicitly permitted in the specs.
600  * 4xx-5xx require a local file template.
601  * - sending Location: on these codes with no body is invalid by the specs.
602  * - current result is Squid crashing or XSS problems as dynamic deny_info load random disk files.
603  * - a future redesign of the file loading may result in loading remote objects sent inline as local body.
604  */
605  if (info->page_redirect == Http::scNone)
606  ; // special case okay.
607  else if (info->page_redirect < 200 || info->page_redirect > 599) {
608  // out of range
609  debugs(0, DBG_CRITICAL, "FATAL: status " << info->page_redirect << " is not valid on '" << page_name << "'");
610  self_destruct();
611  } else if ( /* >= 200 && */ info->page_redirect < 300 && strchr(&(page_name[4]), ':')) {
612  // 2xx require a local template file
613  debugs(0, DBG_CRITICAL, "FATAL: status " << info->page_redirect << " requires a template on '" << page_name << "'");
614  self_destruct();
615  } else if (info->page_redirect >= 300 && info->page_redirect <= 399 && !strchr(&(page_name[4]), ':')) {
616  // 3xx require an absolute URL
617  debugs(0, DBG_CRITICAL, "FATAL: status " << info->page_redirect << " requires a URL on '" << page_name << "'");
618  self_destruct();
619  } else if (info->page_redirect >= 400 /* && <= 599 */ && strchr(&(page_name[4]), ':')) {
620  // 4xx/5xx require a local template file
621  debugs(0, DBG_CRITICAL, "FATAL: status " << info->page_redirect << " requires a template on '" << page_name << "'");
622  self_destruct();
623  }
624  // else okay.
625 }
626 
628 static int
629 errorPageId(const char *page_name)
630 {
631  for (int i = 0; i < ERR_MAX; ++i) {
632  if (strcmp(err_type_str[i], page_name) == 0)
633  return i;
634  }
635 
636  for (size_t j = 0; j < ErrorDynamicPages.size(); ++j) {
637  if (strcmp(ErrorDynamicPages[j]->page_name, page_name) == 0)
638  return j + ERR_MAX;
639  }
640 
641  return ERR_NONE;
642 }
643 
644 err_type
645 errorReservePageId(const char *page_name, const SBuf &cfgLocation)
646 {
647  int id = errorPageId(page_name);
648 
649  if (id == ERR_NONE) {
650  id = ERR_MAX + ErrorDynamicPages.size();
651  const auto info = new ErrorDynamicPageInfo(id, page_name, cfgLocation);
652  ErrorDynamicPages.push_back(info);
653  }
654 
655  return (err_type)id;
656 }
657 
659 const char *
660 errorPageName(int pageId)
661 {
662  if (pageId >= ERR_NONE && pageId < ERR_MAX) /* common case */
663  return err_type_str[pageId];
664 
665  if (pageId >= ERR_MAX && pageId - ERR_MAX < (ssize_t)ErrorDynamicPages.size())
666  return ErrorDynamicPages[pageId - ERR_MAX]->page_name;
667 
668  return "ERR_UNKNOWN"; /* should not happen */
669 }
670 
671 ErrorState *
673 {
674  const Http::StatusCode status = (request && request->flags.needValidation) ?
676  return new ErrorState(type, status, request.getRaw(), ale);
677 }
678 
680  type(t),
681  page_id(t),
682  callback(nullptr)
683 {
684 }
685 
687  ErrorState(t)
688 {
689  if (page_id >= ERR_MAX && ErrorDynamicPages[page_id - ERR_MAX]->page_redirect != Http::scNone)
690  httpStatus = ErrorDynamicPages[page_id - ERR_MAX]->page_redirect;
691  else
692  httpStatus = status;
693 
694  if (req) {
695  request = req;
696  src_addr = req->client_addr;
697  }
698 
699  ale = anAle;
700 }
701 
704 {
705  Must(errorReply);
706  response_ = errorReply;
707  httpStatus = errorReply->sline.status();
708 
709  if (req) {
710  request = req;
711  src_addr = req->client_addr;
712  }
713 }
714 
715 void
717 {
718  assert(entry->mem_obj != NULL);
719  assert (entry->isEmpty());
720  debugs(4, 4, "storing " << err << " in " << *entry);
721 
722  if (entry->store_status != STORE_PENDING) {
723  debugs(4, 2, "Skipping error page due to store_status: " << entry->store_status);
724  /*
725  * If the entry is not STORE_PENDING, then no clients
726  * care about it, and we don't need to generate an
727  * error message
728  */
730  assert(entry->mem_obj->nclients == 0);
731  delete err;
732  return;
733  }
734 
735  if (err->page_id == TCP_RESET) {
736  if (err->request) {
737  debugs(4, 2, "RSTing this reply");
738  err->request->flags.resetTcp = true;
739  }
740  }
741 
742  entry->storeErrorResponse(err->BuildHttpReply());
743  delete err;
744 }
745 
746 void
748 {
749  debugs(4, 3, conn << ", err=" << err);
751 
752  HttpReplyPointer rep(err->BuildHttpReply());
753 
754  MemBuf *mb = rep->pack();
755  AsyncCall::Pointer call = commCbCall(78, 5, "errorSendComplete",
757  Comm::Write(conn, mb, call);
758  delete mb;
759 }
760 
770 static void
771 errorSendComplete(const Comm::ConnectionPointer &conn, char *, size_t size, Comm::Flag errflag, int, void *data)
772 {
773  ErrorState *err = static_cast<ErrorState *>(data);
774  debugs(4, 3, HERE << conn << ", size=" << size);
775 
776  if (errflag != Comm::ERR_CLOSING) {
777  if (err->callback) {
778  debugs(4, 3, "errorSendComplete: callback");
779  err->callback(conn->fd, err->callback_data, size);
780  } else {
781  debugs(4, 3, "errorSendComplete: comm_close");
782  conn->close();
783  }
784  }
785 
786  delete err;
787 }
788 
790 {
792  safe_free(url);
794  wordlistDestroy(&ftp.server_msg);
795  safe_free(ftp.request);
796  safe_free(ftp.reply);
798 #if USE_ERR_LOCALES
800 #endif
802 }
803 
804 int
806 {
807  MemBuf str;
808  char ntoabuf[MAX_IPSTRLEN];
809 
810  str.reset();
811  /* email subject line */
812  str.appendf("CacheErrorInfo - %s", errorPageName(type));
813  mb->appendf("?subject=%s", rfc1738_escape_part(str.buf));
814  str.reset();
815  /* email body */
816  str.appendf("CacheHost: %s\r\n", getMyHostname());
817  /* - Err Msgs */
818  str.appendf("ErrPage: %s\r\n", errorPageName(type));
819 
820  if (xerrno) {
821  str.appendf("Err: (%d) %s\r\n", xerrno, strerror(xerrno));
822  } else {
823  str.append("Err: [none]\r\n", 13);
824  }
825 #if USE_AUTH
827  str.appendf("Auth ErrMsg: %s\r\n", auth_user_request->denyMessage());
828 #endif
829  if (dnsError.size() > 0)
830  str.appendf("DNS ErrMsg: %s\r\n", dnsError.termedBuf());
831 
832  /* - TimeStamp */
833  str.appendf("TimeStamp: %s\r\n\r\n", mkrfc1123(squid_curtime));
834 
835  /* - IP stuff */
836  str.appendf("ClientIP: %s\r\n", src_addr.toStr(ntoabuf,MAX_IPSTRLEN));
837 
838  if (request && request->hier.host[0] != '\0') {
839  str.appendf("ServerIP: %s\r\n", request->hier.host);
840  }
841 
842  str.append("\r\n", 2);
843  /* - HTTP stuff */
844  str.append("HTTP Request:\r\n", 15);
845  if (request) {
846  str.appendf(SQUIDSBUFPH " " SQUIDSBUFPH " %s/%d.%d\n",
851  request->header.packInto(&str);
852  }
853 
854  str.append("\r\n", 2);
855  /* - FTP stuff */
856 
857  if (ftp.request) {
858  str.appendf("FTP Request: %s\r\n", ftp.request);
859  str.appendf("FTP Reply: %s\r\n", (ftp.reply? ftp.reply:"[none]"));
860  str.append("FTP Msg: ", 9);
861  wordlistCat(ftp.server_msg, &str);
862  str.append("\r\n", 2);
863  }
864 
865  str.append("\r\n", 2);
866  mb->appendf("&body=%s", rfc1738_escape_part(str.buf));
867  str.clean();
868  return 0;
869 }
870 
872 #define CVT_BUF_SZ 512
873 
874 void
876 {
878 
879  try {
880  const auto logformat = build.input + LogformatMagic.length();
881 
882  // Logformat supports undocumented "external" encoding specifications
883  // like [%>h] or "%<a". To preserve the possibility of extending
884  // @Squid{} syntax to non-logformat sequences, we require logformat
885  // sequences to start with '%'. This restriction does not limit
886  // logformat quoting abilities. TODO: Deprecate "external" encoding?
887  if (*logformat != '%')
888  throw TexcHere("logformat expressions that do not start with % are not supported");
889 
890  static MemBuf result;
891  result.reset();
892  const auto logformatLen = Format::AssembleOne(logformat, result, ale);
893  assert(logformatLen > 0);
894  const auto closure = logformat + logformatLen;
895  if (*closure != '}')
896  throw TexcHere("Missing closing brace (})");
897  build.output.append(result.content(), result.contentSize());
898  build.input = closure + 1;
899  return;
900  } catch (...) {
901  noteBuildError("Bad @Squid{logformat} sequence", build.input);
902  }
903 
904  // we cannot recover reliably so stop interpreting the rest of input
905  const auto remainingSize = strlen(build.input);
906  build.output.append(build.input, remainingSize);
907  build.input += remainingSize;
908 }
909 
910 void
912 {
913  static MemBuf mb;
914  const char *p = NULL; /* takes priority over mb if set */
915  int do_quote = 1;
916  int no_urlescape = 0; /* if true then item is NOT to be further URL-encoded */
917  char ntoabuf[MAX_IPSTRLEN];
918 
919  mb.reset();
920 
921  const auto &building_deny_info_url = build.building_deny_info_url; // a change reduction hack
922 
923  const auto letter = build.input[1];
924 
925  switch (letter) {
926 
927  case 'a':
928 #if USE_AUTH
931  if (!p)
932 #endif
933  p = "-";
934  break;
935 
936  case 'A':
937  // TODO: When/if we get ALE here, pass it as well
938  if (const auto addr = FindListeningPortAddress(request.getRaw(), nullptr))
939  mb.appendf("%s", addr->toStr(ntoabuf, MAX_IPSTRLEN));
940  else
941  p = "-";
942  break;
943 
944  case 'b':
945  mb.appendf("%u", getMyPort());
946  break;
947 
948  case 'B':
949  if (building_deny_info_url) break;
950  if (request) {
951  const SBuf &tmp = Ftp::UrlWith2f(request.getRaw());
952  mb.append(tmp.rawContent(), tmp.length());
953  } else
954  p = "[no URL]";
955  break;
956 
957  case 'c':
958  if (building_deny_info_url) break;
959  p = errorPageName(type);
960  break;
961 
962  case 'D':
963  if (!build.allowRecursion)
964  p = "%D"; // if recursion is not allowed, do not convert
965  else if (detail) {
966  auto rawDetail = detail->verbose(request);
967  // XXX: Performance regression. c_str() reallocates
968  const auto compiledDetail = compileBody(rawDetail.c_str(), false);
969  mb.append(compiledDetail.rawContent(), compiledDetail.length());
970  do_quote = 0;
971  }
972  if (!mb.contentSize())
973  mb.append("[No Error Detail]", 17);
974  break;
975 
976  case 'e':
977  mb.appendf("%d", xerrno);
978  break;
979 
980  case 'E':
981  if (xerrno)
982  mb.appendf("(%d) %s", xerrno, strerror(xerrno));
983  else
984  mb.append("[No Error]", 10);
985  break;
986 
987  case 'f':
988  if (building_deny_info_url) break;
989  /* FTP REQUEST LINE */
990  if (ftp.request)
991  p = ftp.request;
992  else
993  p = "nothing";
994  break;
995 
996  case 'F':
997  if (building_deny_info_url) break;
998  /* FTP REPLY LINE */
999  if (ftp.reply)
1000  p = ftp.reply;
1001  else
1002  p = "nothing";
1003  break;
1004 
1005  case 'g':
1006  if (building_deny_info_url) break;
1007  /* FTP SERVER RESPONSE */
1008  if (ftp.listing) {
1009  mb.append(ftp.listing->content(), ftp.listing->contentSize());
1010  do_quote = 0;
1011  } else if (ftp.server_msg) {
1012  wordlistCat(ftp.server_msg, &mb);
1013  }
1014  break;
1015 
1016  case 'h':
1017  mb.appendf("%s", getMyHostname());
1018  break;
1019 
1020  case 'H':
1021  if (request) {
1022  if (request->hier.host[0] != '\0') // if non-empty string.
1023  p = request->hier.host;
1024  else
1025  p = request->url.host();
1026  } else if (!building_deny_info_url)
1027  p = "[unknown host]";
1028  break;
1029 
1030  case 'i':
1031  mb.appendf("%s", src_addr.toStr(ntoabuf,MAX_IPSTRLEN));
1032  break;
1033 
1034  case 'I':
1035  if (request && request->hier.tcpServer)
1036  p = request->hier.tcpServer->remote.toStr(ntoabuf,MAX_IPSTRLEN);
1037  else if (!building_deny_info_url)
1038  p = "[unknown]";
1039  break;
1040 
1041  case 'l':
1042  if (building_deny_info_url) break;
1044  do_quote = 0;
1045  break;
1046 
1047  case 'L':
1048  if (building_deny_info_url) break;
1049  if (Config.errHtmlText) {
1050  mb.appendf("%s", Config.errHtmlText);
1051  do_quote = 0;
1052  } else
1053  p = "[not available]";
1054  break;
1055 
1056  case 'm':
1057  if (building_deny_info_url) break;
1058 #if USE_AUTH
1059  if (auth_user_request.getRaw())
1060  p = auth_user_request->denyMessage("[not available]");
1061  else
1062  p = "[not available]";
1063 #else
1064  p = "-";
1065 #endif
1066  break;
1067 
1068  case 'M':
1069  if (request) {
1070  const SBuf &m = request->method.image();
1071  mb.append(m.rawContent(), m.length());
1072  } else if (!building_deny_info_url)
1073  p = "[unknown method]";
1074  break;
1075 
1076  case 'O':
1077  if (!building_deny_info_url)
1078  do_quote = 0;
1079  case 'o':
1081  if (!p && !building_deny_info_url)
1082  p = "[not available]";
1083  break;
1084 
1085  case 'p':
1086  if (request) {
1087  mb.appendf("%u", request->url.port());
1088  } else if (!building_deny_info_url) {
1089  p = "[unknown port]";
1090  }
1091  break;
1092 
1093  case 'P':
1094  if (request) {
1095  const SBuf &m = request->url.getScheme().image();
1096  mb.append(m.rawContent(), m.length());
1097  } else if (!building_deny_info_url) {
1098  p = "[unknown protocol]";
1099  }
1100  break;
1101 
1102  case 'R':
1103  if (building_deny_info_url) {
1104  if (request != NULL) {
1105  const SBuf &tmp = request->url.path();
1106  mb.append(tmp.rawContent(), tmp.length());
1107  no_urlescape = 1;
1108  } else
1109  p = "[no request]";
1110  break;
1111  }
1112  if (request) {
1113  mb.appendf(SQUIDSBUFPH " " SQUIDSBUFPH " %s/%d.%d\n",
1118  request->header.packInto(&mb, true); //hide authorization data
1119  } else if (request_hdrs) {
1120  p = request_hdrs;
1121  } else {
1122  p = "[no request]";
1123  }
1124  break;
1125 
1126  case 's':
1127  /* for backward compat we make %s show the full URL. Drop this in some future release. */
1128  if (building_deny_info_url) {
1129  if (request) {
1130  const SBuf &tmp = request->effectiveRequestUri();
1131  mb.append(tmp.rawContent(), tmp.length());
1132  } else
1133  p = url;
1134  debugs(0, DBG_CRITICAL, "WARNING: deny_info now accepts coded tags. Use %u to get the full URL instead of %s");
1135  } else
1137  break;
1138 
1139  case 'S':
1140  if (building_deny_info_url) {
1142  break;
1143  }
1144  /* signature may contain %-escapes, recursion */
1145  if (page_id != ERR_SQUID_SIGNATURE) {
1146  const int saved_id = page_id;
1148  const auto signature = buildBody();
1149  mb.append(signature.rawContent(), signature.length());
1150  page_id = saved_id;
1151  do_quote = 0;
1152  } else {
1153  /* wow, somebody put %S into ERR_SIGNATURE, stop recursion */
1154  p = "[%S]";
1155  }
1156  break;
1157 
1158  case 't':
1160  break;
1161 
1162  case 'T':
1163  mb.appendf("%s", mkrfc1123(squid_curtime));
1164  break;
1165 
1166  case 'U':
1167  /* Using the fake-https version of absolute-URI so error pages see https:// */
1168  /* even when the url-path cannot be shown as more than '*' */
1169  if (request)
1171  else if (url)
1172  p = url;
1173  else if (!building_deny_info_url)
1174  p = "[no URL]";
1175  break;
1176 
1177  case 'u':
1178  if (request) {
1179  const SBuf &tmp = request->effectiveRequestUri();
1180  mb.append(tmp.rawContent(), tmp.length());
1181  } else if (url)
1182  p = url;
1183  else if (!building_deny_info_url)
1184  p = "[no URL]";
1185  break;
1186 
1187  case 'w':
1188  if (Config.adminEmail)
1189  mb.appendf("%s", Config.adminEmail);
1190  else if (!building_deny_info_url)
1191  p = "[unknown]";
1192  break;
1193 
1194  case 'W':
1195  if (building_deny_info_url) break;
1197  Dump(&mb);
1198  no_urlescape = 1;
1199  break;
1200 
1201  case 'x':
1202  if (detail) {
1203  const auto brief = detail->brief();
1204  mb.append(brief.rawContent(), brief.length());
1205  } else if (!building_deny_info_url) {
1206  p = "[Unknown Error Code]";
1207  }
1208  break;
1209 
1210  case 'z':
1211  if (building_deny_info_url) break;
1212  if (dnsError.size() > 0)
1213  p = dnsError.termedBuf();
1214  else if (ftp.cwd_msg)
1215  p = ftp.cwd_msg;
1216  else
1217  p = "[unknown]";
1218  break;
1219 
1220  case 'Z':
1221  if (building_deny_info_url) break;
1222  if (err_msg)
1223  p = err_msg;
1224  else
1225  p = "[unknown]";
1226  break;
1227 
1228  case '%':
1229  p = "%";
1230  break;
1231 
1232  default:
1233  if (building_deny_info_url)
1234  bypassBuildErrorXXX("Unsupported deny_info %code", build.input);
1235  else if (letter != ';')
1236  bypassBuildErrorXXX("Unsupported error page %code", build.input);
1237  // else too many "font-size: 100%;" template errors to report
1238 
1239  mb.append(build.input, 2);
1240  do_quote = 0;
1241  break;
1242  }
1243 
1244  if (!p)
1245  p = mb.buf; /* do not use mb after this assignment! */
1246 
1247  assert(p);
1248 
1249  debugs(4, 3, "%" << letter << " --> '" << p << "'" );
1250 
1251  if (do_quote)
1252  p = html_quote(p);
1253 
1254  if (building_deny_info_url && !no_urlescape)
1255  p = rfc1738_escape_part(p);
1256 
1257  // TODO: Optimize by replacing mb with direct build.output usage.
1258  build.output.append(p, strlen(p));
1259  build.input += 2;
1260 }
1261 
1262 void
1264 {
1265  if (const auto urlTemplate = ErrorPage::IsDenyInfoUri(page_id)) {
1266  (void)compile(urlTemplate, true, true);
1267  } else {
1268  assert(page_id > ERR_NONE);
1270  (void)compileBody(error_text[page_id], true);
1271  }
1272 }
1273 
1274 HttpReply *
1276 {
1277  if (response_)
1278  return response_.getRaw();
1279 
1280  HttpReply *rep = new HttpReply;
1281  const char *name = errorPageName(page_id);
1282  /* no LMT for error pages; error pages expire immediately */
1283 
1284  if (const auto urlTemplate = ErrorPage::IsDenyInfoUri(page_id)) {
1285  /* Redirection */
1287  // Use configured 3xx reply status if set.
1288  if (name[0] == '3')
1289  status = httpStatus;
1290  else {
1291  // Use 307 for HTTP/1.1 non-GET/HEAD requests.
1293  status = Http::scTemporaryRedirect;
1294  }
1295 
1296  rep->setHeaders(status, NULL, "text/html;charset=utf-8", 0, 0, -1);
1297 
1298  if (request) {
1299  auto location = compile(urlTemplate, true, true);
1300  rep->header.putStr(Http::HdrType::LOCATION, location.c_str());
1301  }
1302 
1303  httpHeaderPutStrf(&rep->header, Http::HdrType::X_SQUID_ERROR, "%d %s", httpStatus, "Access Denied");
1304  } else {
1305  const auto body = buildBody();
1306  rep->setHeaders(httpStatus, NULL, "text/html;charset=utf-8", body.length(), 0, -1);
1307  /*
1308  * include some information for downstream caches. Implicit
1309  * replaceable content. This isn't quite sufficient. xerrno is not
1310  * necessarily meaningful to another system, so we really should
1311  * expand it. Additionally, we should identify ourselves. Someone
1312  * might want to know. Someone _will_ want to know OTOH, the first
1313  * X-CACHE-MISS entry should tell us who.
1314  */
1316 
1317 #if USE_ERR_LOCALES
1318  /*
1319  * If error page auto-negotiate is enabled in any way, send the Vary.
1320  * RFC 2616 section 13.6 and 14.44 says MAY and SHOULD do this.
1321  * We have even better reasons though:
1322  * see http://wiki.squid-cache.org/KnowledgeBase/VaryNotCaching
1323  */
1324  if (!Config.errorDirectory) {
1325  /* We 'negotiated' this ONLY from the Accept-Language. */
1327  rep->header.putStr(Http::HdrType::VARY, "Accept-Language");
1328  }
1329 
1330  /* add the Content-Language header according to RFC section 14.12 */
1331  if (err_language) {
1333  } else
1334 #endif /* USE_ERROR_LOCALES */
1335  {
1336  /* default templates are in English */
1337  /* language is known unless error_directory override used */
1338  if (!Config.errorDirectory)
1340  }
1341 
1342  rep->body.set(body);
1343  }
1344 
1345  // Make sure error codes get back to the client side for logging and
1346  // error tracking.
1347  if (request) {
1348  if (detail)
1350  else
1352  }
1353 
1354  return rep;
1355 }
1356 
1357 SBuf
1359 {
1361 
1362 #if USE_ERR_LOCALES
1363 
1367  if (!Config.errorDirectory && page_id < ERR_MAX) {
1370 
1371  ErrorPageFile localeTmpl(err_type_str[page_id], static_cast<err_type>(page_id));
1372  if (localeTmpl.loadFor(request.getRaw())) {
1373  inputLocation = localeTmpl.filename;
1374  assert(localeTmpl.language());
1375  err_language = xstrdup(localeTmpl.language());
1376  return compileBody(localeTmpl.text(), true);
1377  }
1378  }
1379 #endif /* USE_ERR_LOCALES */
1380 
1385 #if USE_ERR_LOCALES
1386  if (!Config.errorDirectory)
1388 #endif
1389  debugs(4, 2, "No existing error page language negotiated for " << this << ". Using default error file.");
1390  return compileBody(error_text[page_id], true);
1391 }
1392 
1393 SBuf
1394 ErrorState::compileBody(const char *input, bool allowRecursion)
1395 {
1396  return compile(input, false, allowRecursion);
1397 }
1398 
1399 SBuf
1400 ErrorState::compile(const char *input, bool building_deny_info_url, bool allowRecursion)
1401 {
1402  assert(input);
1403 
1404  Build build;
1405  build.building_deny_info_url = building_deny_info_url;
1406  build.allowRecursion = allowRecursion;
1407  build.input = input;
1408 
1409  auto blockStart = build.input;
1410  while (const auto letter = *build.input) {
1411  if (letter == '%') {
1412  build.output.append(blockStart, build.input - blockStart);
1413  compileLegacyCode(build);
1414  blockStart = build.input;
1415  }
1416  else if (letter == '@' && LogformatMagic.cmp(build.input, LogformatMagic.length()) == 0) {
1417  build.output.append(blockStart, build.input - blockStart);
1418  compileLogformatCode(build);
1419  blockStart = build.input;
1420  } else {
1421  ++build.input;
1422  }
1423  }
1424  build.output.append(blockStart, build.input - blockStart);
1425  return build.output;
1426 }
1427 
1435 void
1436 ErrorState::noteBuildError_(const char *msg, const char *near, const bool forceBypass)
1437 {
1439  const auto runtime = !starting_up;
1440  if (runtime || forceBypass) {
1441  // swallow this problem because the admin may not be (and/or the page
1442  // building code is not) ready to handle throwing consequences
1443 
1444  static unsigned int seenErrors = 0;
1445  ++seenErrors;
1446 
1447  const auto debugLevel =
1448  (seenErrors > 100) ? DBG_DATA:
1450  3; // most other errors have been reported as configuration errors
1451 
1452  // Error fatality depends on the error context: Reconfiguration errors
1453  // are, like startup ones, DBG_CRITICAL but will never become FATAL.
1454  if (starting_up && seenErrors <= 10)
1455  debugs(4, debugLevel, "WARNING: The following configuration error will be fatal in future Squid versions");
1456 
1457  debugs(4, debugLevel, "ERROR: " << BuildErrorPrinter(inputLocation, page_id, msg, near));
1458  } else {
1459  throw TexcHere(ToSBuf(BuildErrorPrinter(inputLocation, page_id, msg, near)));
1460  }
1461 }
1462 
1463 /* ErrorPage::BuildErrorPrinter */
1464 
1465 std::ostream &
1467  if (!inputLocation.isEmpty())
1468  return os << inputLocation;
1469 
1470  if (page_id < ERR_NONE || page_id >= error_page_count)
1471  return os << "[error page " << page_id << "]"; // should not happen
1472 
1473  if (page_id < ERR_MAX)
1474  return os << err_type_str[page_id];
1475 
1476  return os << "deny_info " << ErrorDynamicPages.at(page_id - ERR_MAX)->page_name;
1477 }
1478 
1479 std::ostream &
1480 ErrorPage::BuildErrorPrinter::print(std::ostream &os) const {
1481  printLocation(os) << ": " << msg << " near ";
1482 
1483  // TODO: Add support for prefix printing to Raw
1484  const size_t maxContextLength = 15; // plus "..."
1485  if (strlen(near) > maxContextLength) {
1486  os.write(near, maxContextLength);
1487  os << "...";
1488  } else {
1489  os << near;
1490  }
1491 
1492  // XXX: We should not be converting (inner) exception to text if we are
1493  // going to throw again. See "add arbitrary (re)thrower-supplied details"
1494  // TODO in TextException.h for a long-term in-catcher solution.
1495  if (std::current_exception())
1496  os << "\n additional info: " << CurrentException;
1497 
1498  return os;
1499 }
1500 
1502 static void
1503 ErrorPage::ImportStaticErrorText(const int page_id, const char *text, const SBuf &inputLocation)
1504 {
1505  assert(!error_text[page_id]);
1506  error_text[page_id] = xstrdup(text);
1507  ValidateStaticError(page_id, inputLocation);
1508 }
1509 
1511 static void
1512 ErrorPage::ValidateStaticError(const int page_id, const SBuf &inputLocation)
1513 {
1514  // Supplying nil ALE pointer limits validation to logformat %code
1515  // recognition by Format::Token::parse(). This is probably desirable
1516  // because actual %code assembly is slow and should not affect validation
1517  // when our ALE cannot have any real data (this code is not associated
1518  // with any real transaction).
1519  ErrorState anErr(err_type(page_id), Http::scNone, nullptr, nullptr);
1520  anErr.inputLocation = inputLocation;
1521  anErr.validate();
1522 }
1523 
1524 std::ostream &
1525 operator <<(std::ostream &os, const ErrorState *err)
1526 {
1527  if (err)
1528  os << errorPageName(err->page_id);
1529  else
1530  os << "[none]";
1531  return os;
1532 }
1533 
char * errorDirectory
Definition: SquidConfig.h:434
const char * xstrerr(int error)
Definition: xstrerror.cc:83
an error page created from admin-configurable metadata (e.g. deny_info)
Definition: errorpage.cc:69
static IOCB errorSendComplete
Definition: errorpage.cc:208
std::ostream & printLocation(std::ostream &os) const
print() helper to report where the error was found
Definition: errorpage.cc:1466
char * buf
Definition: MemBuf.h:134
#define MYNAME
Definition: Debug.h:170
void * xcalloc(size_t n, size_t sz)
Definition: xalloc.cc:72
unsigned int major
major version number
void wordlistDestroy(wordlist **list)
destroy a wordlist
Definition: wordlist.cc:16
int getMyPort(void)
Definition: tools.cc:1003
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
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:199
static std::ostream & operator<<(std::ostream &os, const BuildErrorPrinter &context)
Definition: errorpage.cc:132
err_type errorReservePageId(const char *page_name, const SBuf &cfgLocation)
allocates a new slot for the error page
Definition: errorpage.cc:645
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:191
bool loadFromFile(const char *path)
Definition: errorpage.cc:417
void errorAppendEntry(StoreEntry *entry, ErrorState *err)
Definition: errorpage.cc:716
bool isEmpty() const
Definition: SBuf.h:424
err_type & operator++(err_type &anErr)
Definition: errorpage.cc:228
MemObject * mem_obj
Definition: Store.h:213
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:805
static const int error_hard_text_count
Definition: errorpage.cc:196
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:93
HttpReplyPointer response_
Definition: errorpage.h:206
#define O_TEXT
Definition: defines.h:201
HttpReply * BuildHttpReply(void)
Definition: errorpage.cc:1275
unsigned int minor
minor version number
const char * ProtocolType_str[]
Definition: SBuf.h:87
int const char int
Definition: stub_libmem.cc:75
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:660
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:86
@ 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:153
C * getRaw() const
Definition: RefCount.h:80
virtual void append(const char *c, int sz)
Definition: MemBuf.cc:216
uint16_t flags
Definition: Store.h:224
const SBuf & image() const
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:26
char * errorDefaultLanguage
Definition: SquidConfig.h:436
Http::StatusLine sline
Definition: HttpReply.h:56
char * errHtmlText
Definition: SquidConfig.h:228
@ ERR_NONE
Definition: forward.h:15
#define DBG_CRITICAL
Definition: Debug.h:45
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:76
#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:437
#define DBG_IMPORTANT
Definition: Debug.h:46
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:267
const char * text()
The template text data read from disk.
Definition: errorpage.cc:218
const char * input
template bytes that need to be compiled
Definition: errorpage.cc:107
static void ValidateStaticError(const int page_id, const SBuf &inputLocation)
validate static error page
Definition: errorpage.cc:1512
size_t AssembleOne(const char *start, MemBuf &buf, const AccessLogEntryPointer &ale)
Definition: Format.cc:100
char * toStr(char *buf, const unsigned int blen, int force=AF_UNSPEC) const
Definition: Address.cc:802
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:58
SBuf output
compilation result
Definition: errorpage.cc:106
char * strerror(int ern)
Definition: strerror.c:22
bool building_deny_info_url
whether we compile deny_info URI
Definition: errorpage.cc:108
void errorDetailInitialize()
#define MAX_IPSTRLEN
Length of buffer that needs to be allocated to old a null-terminated IP-string.
Definition: forward.h:23
ErrorPageFile(const char *name, const err_type code)
Definition: errorpage.cc:215
void compileLogformatCode(Build &build)
compile @Squid{code} sequence containing a single logformat code
Definition: errorpage.cc:875
@ scGatewayTimeout
Definition: StatusCode.h:75
TemplateFile(const char *name, const err_type code)
Definition: errorpage.cc:350
void noteBuildError_(const char *msg, const char *near, const bool forceBypass)
Definition: errorpage.cc:1436
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
struct SquidConfig::@113 onoff
@ 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:356
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:109
int size
Definition: ModDevPoll.cc:77
void errorSend(const Comm::ConnectionPointer &conn, ErrorState *err)
Definition: errorpage.cc:747
#define NULL
Definition: types.h:166
const char * rawContent() const
Definition: SBuf.cc:509
ErrorState()=delete
#define SQUIDSBUFPRINT(s)
Definition: SBuf.h:32
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:128
struct ErrorState::@60 ftp
BuildErrorPrinter(const SBuf &anInputLocation, int aPage, const char *aMsg, const char *aNear)
Definition: errorpage.cc:116
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:154
HttpRequestPointer request
Definition: errorpage.h:175
bool strHdrAcptLangGetItem(const String &hdr, char *lang, int langLen, size_t &pos)
Definition: errorpage.cc:465
char * request_hdrs
Definition: errorpage.h:195
Definition: MemBuf.h:24
#define EBIT_TEST(flag, bit)
Definition: defines.h:107
void clean()
Definition: MemBuf.cc:113
unsigned char code
Definition: html_quote.c:20
bool tryLoadTemplate(const char *lang)
Definition: errorpage.cc:392
SBuf cfgLocation
deny_info directive position in squid.conf (for reporting)
Definition: errorpage.cc:89
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:157
int starting_up
int delById(Http::HdrType id)
Definition: HttpHeader.cc:710
pretty-prints error page/deny_info building error
Definition: errorpage.cc:114
virtual bool parse()
post-process the loaded template
Definition: errorpage.h:320
void const char HLPCB void * data
Definition: stub_helper.cc:16
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:190
void validate()
ensures that a future BuildHttpReply() is likely to succeed
Definition: errorpage.cc:1263
int reconfiguring
int emailErrData
Definition: SquidConfig.h:327
void wordlistCat(const wordlist *w, MemBuf *mb)
Definition: wordlist.cc:35
static const struct @59 error_hard_text[]
Ip::Address src_addr
Definition: errorpage.h:182
#define safe_free(x)
Definition: xalloc.h:73
Ip::Address remote
Definition: Connection.h:159
store_status_t store_status
Definition: Store.h:236
state and parameters shared by several ErrorState::compile*() methods
Definition: errorpage.cc:104
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:91
SBuf compileBody(const char *text, bool allowRecursion)
Definition: errorpage.cc:1394
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:583
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:35
#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_time.cc:17
@ 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:558
int xerrno
Definition: errorpage.h:177
const char * mkrfc1123(time_t)
Definition: rfc1123.c:202
const char * uri
admin-configured HTTP Location header value for redirection responses
Definition: errorpage.cc:83
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:786
virtual void setDefault() override
recover from loadDefault() failure to load or parse() a template
Definition: errorpage.cc:221
const char * urlCanonicalFakeHttps(const HttpRequest *request)
Definition: Uri.cc:648
void compileLegacyCode(Build &build)
compile a single-letter code like D
Definition: errorpage.cc:911
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
@ ENTRY_ABORTED
Definition: enums.h:115
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:2588
int cmp(const SBuf &S, const size_type n) const
shorthand version for compare()
Definition: SBuf.h:268
@ ERR_SQUID_SIGNATURE
Definition: forward.h:71
static ErrorState * NewForwarding(err_type, HttpRequestPointer &, const AccessLogEntryPointer &)
Creates a general request forwarding error with the right http_status.
Definition: errorpage.cc:672
char * content()
start of the added data
Definition: MemBuf.h:41
void putStr(Http::HdrType id, const char *str)
Definition: HttpHeader.cc:1067
#define DEFAULT_SQUID_ERROR_DIR
Definition: errorpage.cc:58
@ ERR_CLIENT_GONE
Definition: forward.h:79
size_type size() const
Definition: SquidString.h:72
const char * getMyHostname(void)
Definition: tools.cc:412
bool loadFor(const HttpRequest *request)
Definition: errorpage.cc:519
bool isEmpty() const
Definition: Store.h:67
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:124
static MemBuf error_stylesheet
Definition: errorpage.cc:205
char * errorStylesheet
Definition: SquidConfig.h:439
#define Must(condition)
Like assert() but throws an exception instead of aborting the process.
Definition: TextException.h:73
void const char HLPCB * callback
Definition: stub_helper.cc:16
SBuf buildBody()
locates the right error page template for this error and compiles it
Definition: errorpage.cc:1358
int unsigned int const char *desc STUB void int len
Definition: stub_fd.cc:20
void reset()
Definition: MemBuf.cc:132
String extacl_message
Definition: HttpRequest.h:184
int operator-(err_type const &anErr, err_type const &anErr2)
Definition: errorpage.cc:236
char host[SQUIDHOSTNAMELEN]
const char * FormatHttpd(time_t t)
Definition: time.cc:111
String substr(size_type from, size_type to) const
Definition: String.cc:223
int id
error_text[] index for response body (unused in redirection responses)
Definition: errorpage.cc:75
static void ImportStaticErrorText(const int page_id, const char *text, const SBuf &inputLocation)
add error page template to the global index
Definition: errorpage.cc:1503
std::ostream & print(std::ostream &) const
reports error details (for admin-visible exceptions and debugging)
Definition: errorpage.cc:1480
@ 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:168
#define xisspace(x)
Definition: xis.h:17
#define MAXPATHLEN
Definition: stdio.h:62
static const char * IsDenyInfoUri(const int page_id)
Definition: errorpage.cc:244
SBuf template_
raw template contents
Definition: errorpage.h:332
int file_open(const char *path, int mode)
Definition: fs_io.cc:46
static const char * errorFindHardText(err_type type)
Definition: errorpage.cc:339
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:688
void errorClean(void)
Definition: errorpage.cc:314
SBuf compile(const char *input, bool building_deny_info_url, bool allowRecursion)
Definition: errorpage.cc:1400
Ip::Address client_addr
Definition: HttpRequest.h:149
void host(const char *src)
Definition: Uri.cc:98
struct _request * request(char *urlin)
Definition: tcp-banger2.c:291
static const SBuf LogformatMagic
marks each embedded logformat entry
Definition: errorpage.h:211
int nclients
Definition: MemObject.h:146
void const char * buf
Definition: stub_helper.cc:16
static int errorPageId(const char *page_name)
Definition: errorpage.cc:629
Http::StatusCode httpStatus
Definition: errorpage.h:171
void storeErrorResponse(HttpReply *reply)
Store a prepared error response. MemObject locks the reply object.
Definition: store.cc:1702
Auth::UserRequest::Pointer auth_user_request
Definition: errorpage.h:173
void errorInitialize(void)
Definition: errorpage.cc:252
#define SQUIDSBUFPH
Definition: SBuf.h:31
class SquidConfig Config
Definition: SquidConfig.cc:12
void noteBuildError(const char *msg, const char *near)
Definition: errorpage.h:147
static int error_page_count
Definition: errorpage.cc:202
AnyP::ProtocolVersion ProtocolVersion(unsigned int aMajor, unsigned int aMinor)
HTTP version label information.
#define DBG_DATA
Definition: Debug.h:48
@ STORE_PENDING
Definition: enums.h:51

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors