errorpage.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2019 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 "err_detail_type.h"
18 #include "errorpage.h"
19 #include "fde.h"
20 #include "format/Format.h"
21 #include "fs_io.h"
22 #include "html_quote.h"
23 #include "HttpHeaderTools.h"
24 #include "HttpReply.h"
25 #include "HttpRequest.h"
26 #include "MemBuf.h"
27 #include "MemObject.h"
28 #include "rfc1738.h"
29 #include "sbuf/Stream.h"
30 #include "SquidConfig.h"
31 #include "SquidTime.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  "secure accept fail"
174  },
175  {
177  "request start timedout"
178  },
179  {
180  MGR_INDEX,
181  "mgr_index"
182  }
183 };
184 
186 static std::vector<ErrorDynamicPageInfo *> ErrorDynamicPages;
187 
188 /* local prototypes */
189 
191 static const int error_hard_text_count = sizeof(error_hard_text) / sizeof(*error_hard_text);
192 
194 static char **error_text = NULL;
195 
197 static int error_page_count = 0;
198 
201 
202 static const char *errorFindHardText(err_type type);
204 
208 {
209 public:
210  ErrorPageFile(const char *name, const err_type code) : TemplateFile(name, code) {}
211 
213  const char *text() { return template_.c_str(); }
214 
215 protected:
216  virtual void setDefault() override {
217  template_ = "Internal Error: Missing Template ";
218  template_.append(templateName.termedBuf());
219  }
220 };
221 
224 {
225  int tmp = (int)anErr;
226  anErr = (err_type)(++tmp);
227  return anErr;
228 }
229 
231 int operator - (err_type const &anErr, err_type const &anErr2)
232 {
233  return (int)anErr - (int)anErr2;
234 }
235 
238 static const char *
239 ErrorPage::IsDenyInfoUri(const int page_id)
240 {
241  if (ERR_MAX <= page_id && page_id < error_page_count)
242  return ErrorDynamicPages.at(page_id - ERR_MAX)->uri; // may be nil
243  return nullptr;
244 }
245 
246 void
248 {
250 
251  err_type i;
252  const char *text;
253  error_page_count = ERR_MAX + ErrorDynamicPages.size();
254  error_text = static_cast<char **>(xcalloc(error_page_count, sizeof(char *)));
255 
256  for (i = ERR_NONE, ++i; i < error_page_count; ++i) {
257  safe_free(error_text[i]);
258 
259  if ((text = errorFindHardText(i))) {
263  static const SBuf builtIn("built-in");
264  ImportStaticErrorText(i, text, builtIn);
265 
266  } else if (i < ERR_MAX) {
272  ErrorPageFile errTmpl(err_type_str[i], i);
273  errTmpl.loadDefault();
274  ImportStaticErrorText(i, errTmpl.text(), errTmpl.filename);
275  } else {
279  ErrorDynamicPageInfo *info = ErrorDynamicPages.at(i - ERR_MAX);
280  assert(info && info->id == i && info->page_name);
281 
282  if (info->filename) {
284  ErrorPageFile errTmpl(info->filename, ERR_MAX);
285  errTmpl.loadDefault();
286  ImportStaticErrorText(i, errTmpl.text(), errTmpl.filename);
287  } else {
288  assert(info->uri);
290  }
291  }
292  }
293 
294  error_stylesheet.reset();
295 
296  // look for and load stylesheet into global MemBuf for it.
297  if (Config.errorStylesheet) {
298  ErrorPageFile tmpl("StylesSheet", ERR_MAX);
300  error_stylesheet.appendf("%s",tmpl.text());
301  }
302 
303 #if USE_OPENSSL
305 #endif
306 }
307 
308 void
310 {
311  if (error_text) {
312  int i;
313 
314  for (i = ERR_NONE + 1; i < error_page_count; ++i)
315  safe_free(error_text[i]);
316 
317  safe_free(error_text);
318  }
319 
320  while (!ErrorDynamicPages.empty()) {
321  delete ErrorDynamicPages.back();
322  ErrorDynamicPages.pop_back();
323  }
324 
325  error_page_count = 0;
326 
327 #if USE_OPENSSL
329 #endif
330 }
331 
333 static const char *
335 {
336  int i;
337 
338  for (i = 0; i < error_hard_text_count; ++i)
339  if (error_hard_text[i].type == type)
340  return error_hard_text[i].text;
341 
342  return NULL;
343 }
344 
345 TemplateFile::TemplateFile(const char *name, const err_type code): silent(false), wasLoaded(false), templateName(name), templateCode(code)
346 {
347  assert(name);
348 }
349 
350 void
352 {
353  if (loaded()) // already loaded?
354  return;
355 
357  if (Config.errorDirectory) {
358  char path[MAXPATHLEN];
359  snprintf(path, sizeof(path), "%s/%s", Config.errorDirectory, templateName.termedBuf());
360  loadFromFile(path);
361  }
362 
363 #if USE_ERR_LOCALES
364 
365  if (!loaded() && Config.errorDefaultLanguage) {
367  debugs(1, (templateCode < TCP_RESET ? DBG_CRITICAL : 3), "Unable to load default error language files. Reset to backups.");
368  }
369  }
370 #endif
371 
372  /* test default location if failed (templates == English translation base templates) */
373  if (!loaded()) {
374  tryLoadTemplate("templates");
375  }
376 
377  /* giving up if failed */
378  if (!loaded()) {
379  debugs(1, (templateCode < TCP_RESET ? DBG_CRITICAL : 3), "WARNING: failed to find or read error text file " << templateName);
380  template_.clear();
381  setDefault();
382  wasLoaded = true;
383  }
384 }
385 
386 bool
388 {
389  assert(lang);
390 
391  char path[MAXPATHLEN];
392  /* TODO: prep the directory path string to prevent snprintf ... */
393  snprintf(path, sizeof(path), "%s/%s/%s",
395  path[MAXPATHLEN-1] = '\0';
396 
397  if (loadFromFile(path))
398  return true;
399 
400 #if HAVE_GLOB
401  if ( strlen(lang) == 2) {
402  /* TODO glob the error directory for sub-dirs matching: <tag> '-*' */
403  /* use first result. */
404  debugs(4,2, HERE << "wildcard fallback errors not coded yet.");
405  }
406 #endif
407 
408  return false;
409 }
410 
411 bool
412 TemplateFile::loadFromFile(const char *path)
413 {
414  int fd;
415  char buf[4096];
416  ssize_t len;
417 
418  if (loaded()) // already loaded?
419  return true;
420 
421  fd = file_open(path, O_RDONLY | O_TEXT);
422 
423  if (fd < 0) {
424  /* with dynamic locale negotiation we may see some failures before a success. */
425  if (!silent && templateCode < TCP_RESET) {
426  int xerrno = errno;
427  debugs(4, DBG_CRITICAL, "ERROR: loading file '" << path << "': " << xstrerr(xerrno));
428  }
429  wasLoaded = false;
430  return wasLoaded;
431  }
432 
433  template_.clear();
434  while ((len = FD_READ_METHOD(fd, buf, sizeof(buf))) > 0) {
435  template_.append(buf, len);
436  }
437 
438  if (len < 0) {
439  int xerrno = errno;
440  file_close(fd);
441  debugs(4, DBG_CRITICAL, MYNAME << "ERROR: failed to fully read: '" << path << "': " << xstrerr(xerrno));
442  wasLoaded = false;
443  return false;
444  }
445 
446  file_close(fd);
447 
448  filename = SBuf(path);
449 
450  if (!parse()) {
451  debugs(4, DBG_CRITICAL, "ERROR: parsing error in template file: " << path);
452  wasLoaded = false;
453  return false;
454  }
455 
456  wasLoaded = true;
457  return wasLoaded;
458 }
459 
460 bool strHdrAcptLangGetItem(const String &hdr, char *lang, int langLen, size_t &pos)
461 {
462  while (pos < hdr.size()) {
463 
464  /* skip any initial whitespace. */
465  while (pos < hdr.size() && xisspace(hdr[pos]))
466  ++pos;
467 
468  /*
469  * Header value format:
470  * - sequence of whitespace delimited tags
471  * - each tag may suffix with ';'.* which we can ignore.
472  * - IFF a tag contains only two characters we can wildcard ANY translations matching: <it> '-'? .*
473  * with preference given to an exact match.
474  */
475  bool invalid_byte = false;
476  char *dt = lang;
477  while (pos < hdr.size() && hdr[pos] != ';' && hdr[pos] != ',' && !xisspace(hdr[pos]) && dt < (lang + (langLen -1)) ) {
478  if (!invalid_byte) {
479 #if USE_HTTP_VIOLATIONS
480  // if accepting violations we may as well accept some broken browsers
481  // which may send us the right code, wrong ISO formatting.
482  if (hdr[pos] == '_')
483  *dt = '-';
484  else
485 #endif
486  *dt = xtolower(hdr[pos]);
487  // valid codes only contain A-Z, hyphen (-) and *
488  if (*dt != '-' && *dt != '*' && (*dt < 'a' || *dt > 'z') )
489  invalid_byte = true;
490  else
491  ++dt; // move to next destination byte.
492  }
493  ++pos;
494  }
495  *dt = '\0'; // nul-terminated the filename content string before system use.
496 
497  // if we terminated the tag on garbage or ';' we need to skip to the next ',' or end of header.
498  while (pos < hdr.size() && hdr[pos] != ',')
499  ++pos;
500 
501  if (pos < hdr.size() && hdr[pos] == ',')
502  ++pos;
503 
504  debugs(4, 9, "STATE: lang=" << lang << ", pos=" << pos << ", buf='" << ((pos < hdr.size()) ? hdr.substr(pos,hdr.size()) : "") << "'");
505 
506  /* if we found anything we might use, try it. */
507  if (*lang != '\0' && !invalid_byte)
508  return true;
509  }
510  return false;
511 }
512 
513 bool
515 {
516  String hdr;
517 
518 #if USE_ERR_LOCALES
519  if (loaded()) // already loaded?
520  return true;
521 
522  if (!request || !request->header.getList(Http::HdrType::ACCEPT_LANGUAGE, &hdr))
523  return false;
524 
525  char lang[256];
526  size_t pos = 0; // current parsing position in header string
527 
528  debugs(4, 6, HERE << "Testing Header: '" << hdr << "'");
529 
530  while ( strHdrAcptLangGetItem(hdr, lang, 256, pos) ) {
531 
532  /* wildcard uses the configured default language */
533  if (lang[0] == '*' && lang[1] == '\0') {
534  debugs(4, 6, HERE << "Found language '" << lang << "'. Using configured default.");
535  return false;
536  }
537 
538  debugs(4, 6, HERE << "Found language '" << lang << "', testing for available template");
539 
540  if (tryLoadTemplate(lang)) {
541  /* store the language we found for the Content-Language reply header */
542  errLanguage = lang;
543  break;
544  } else if (Config.errorLogMissingLanguages) {
545  debugs(4, DBG_IMPORTANT, "WARNING: Error Pages Missing Language: " << lang);
546  }
547  }
548 #endif
549 
550  return loaded();
551 }
552 
553 ErrorDynamicPageInfo::ErrorDynamicPageInfo(const int anId, const char *aName, const SBuf &aCfgLocation):
554  id(anId),
555  page_name(xstrdup(aName)),
556  uri(nullptr),
557  filename(nullptr),
558  cfgLocation(aCfgLocation),
559  page_redirect(static_cast<Http::StatusCode>(atoi(page_name)))
560 {
561  const char *filenameOrUri = nullptr;
562  if (xisdigit(*page_name)) {
563  if (const char *statusCodeEnd = strchr(page_name, ':'))
564  filenameOrUri = statusCodeEnd + 1;
565  } else {
567  filenameOrUri = page_name;
568  }
569 
570  // Guessed uri, filename, or both values may be nil or malformed.
571  // They are validated later.
572  if (!page_redirect) {
573  if (filenameOrUri && strchr(filenameOrUri, ':')) // looks like a URL
574  uri = filenameOrUri;
575  else
576  filename = filenameOrUri;
577  }
578  else if (page_redirect/100 == 3) {
579  // redirects imply a URL
580  uri = filenameOrUri;
581  } else {
582  // non-redirects imply an error page name
583  filename = filenameOrUri;
584  }
585 
586  const auto info = this; // source code change reduction hack
587  // TODO: Move and refactor to avoid self_destruct()s in reconfigure.
588 
589  /* WARNING on redirection status:
590  * 2xx are permitted, but not documented officially.
591  * - might be useful for serving static files (PAC etc) in special cases
592  * 3xx require a URL suitable for Location: header.
593  * - the current design does not allow for a Location: URI as well as a local file template
594  * although this possibility is explicitly permitted in the specs.
595  * 4xx-5xx require a local file template.
596  * - sending Location: on these codes with no body is invalid by the specs.
597  * - current result is Squid crashing or XSS problems as dynamic deny_info load random disk files.
598  * - a future redesign of the file loading may result in loading remote objects sent inline as local body.
599  */
600  if (info->page_redirect == Http::scNone)
601  ; // special case okay.
602  else if (info->page_redirect < 200 || info->page_redirect > 599) {
603  // out of range
604  debugs(0, DBG_CRITICAL, "FATAL: status " << info->page_redirect << " is not valid on '" << page_name << "'");
605  self_destruct();
606  } else if ( /* >= 200 && */ info->page_redirect < 300 && strchr(&(page_name[4]), ':')) {
607  // 2xx require a local template file
608  debugs(0, DBG_CRITICAL, "FATAL: status " << info->page_redirect << " requires a template on '" << page_name << "'");
609  self_destruct();
610  } else if (info->page_redirect >= 300 && info->page_redirect <= 399 && !strchr(&(page_name[4]), ':')) {
611  // 3xx require an absolute URL
612  debugs(0, DBG_CRITICAL, "FATAL: status " << info->page_redirect << " requires a URL on '" << page_name << "'");
613  self_destruct();
614  } else if (info->page_redirect >= 400 /* && <= 599 */ && strchr(&(page_name[4]), ':')) {
615  // 4xx/5xx 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  }
619  // else okay.
620 }
621 
623 static int
624 errorPageId(const char *page_name)
625 {
626  for (int i = 0; i < ERR_MAX; ++i) {
627  if (strcmp(err_type_str[i], page_name) == 0)
628  return i;
629  }
630 
631  for (size_t j = 0; j < ErrorDynamicPages.size(); ++j) {
632  if (strcmp(ErrorDynamicPages[j]->page_name, page_name) == 0)
633  return j + ERR_MAX;
634  }
635 
636  return ERR_NONE;
637 }
638 
639 err_type
641 {
642  int id = errorPageId(page_name);
643 
644  if (id == ERR_NONE) {
645  id = ERR_MAX + ErrorDynamicPages.size();
646  const auto info = new ErrorDynamicPageInfo(id, page_name, cfgLocation);
647  ErrorDynamicPages.push_back(info);
648  }
649 
650  return (err_type)id;
651 }
652 
654 const char *
655 errorPageName(int pageId)
656 {
657  if (pageId >= ERR_NONE && pageId < ERR_MAX) /* common case */
658  return err_type_str[pageId];
659 
660  if (pageId >= ERR_MAX && pageId - ERR_MAX < (ssize_t)ErrorDynamicPages.size())
661  return ErrorDynamicPages[pageId - ERR_MAX]->page_name;
662 
663  return "ERR_UNKNOWN"; /* should not happen */
664 }
665 
666 ErrorState *
668 {
669  const Http::StatusCode status = (request && request->flags.needValidation) ?
671  return new ErrorState(type, status, request.getRaw(), ale);
672 }
673 
675  type(t),
676  page_id(t),
677  callback(nullptr)
678 {
679 }
680 
682  ErrorState(t)
683 {
684  if (page_id >= ERR_MAX && ErrorDynamicPages[page_id - ERR_MAX]->page_redirect != Http::scNone)
685  httpStatus = ErrorDynamicPages[page_id - ERR_MAX]->page_redirect;
686  else
687  httpStatus = status;
688 
689  if (req) {
690  request = req;
691  src_addr = req->client_addr;
692  }
693 
694  ale = anAle;
695 }
696 
699 {
700  Must(errorReply);
701  response_ = errorReply;
702  httpStatus = errorReply->sline.status();
703 
704  if (req) {
705  request = req;
706  src_addr = req->client_addr;
707  }
708 }
709 
710 void
712 {
713  assert(entry->mem_obj != NULL);
714  assert (entry->isEmpty());
715  debugs(4, 4, "Creating an error page for entry " << entry <<
716  " with errorstate " << err <<
717  " page id " << err->page_id);
718 
719  if (entry->store_status != STORE_PENDING) {
720  debugs(4, 2, "Skipping error page due to store_status: " << entry->store_status);
721  /*
722  * If the entry is not STORE_PENDING, then no clients
723  * care about it, and we don't need to generate an
724  * error message
725  */
727  assert(entry->mem_obj->nclients == 0);
728  delete err;
729  return;
730  }
731 
732  if (err->page_id == TCP_RESET) {
733  if (err->request) {
734  debugs(4, 2, "RSTing this reply");
735  err->request->flags.resetTcp = true;
736  }
737  }
738 
739  entry->storeErrorResponse(err->BuildHttpReply());
740  delete err;
741 }
742 
743 void
745 {
746  debugs(4, 3, conn << ", err=" << err);
747  assert(Comm::IsConnOpen(conn));
748 
749  HttpReplyPointer rep(err->BuildHttpReply());
750 
751  MemBuf *mb = rep->pack();
752  AsyncCall::Pointer call = commCbCall(78, 5, "errorSendComplete",
753  CommIoCbPtrFun(&errorSendComplete, err));
754  Comm::Write(conn, mb, call);
755  delete mb;
756 }
757 
767 static void
768 errorSendComplete(const Comm::ConnectionPointer &conn, char *, size_t size, Comm::Flag errflag, int, void *data)
769 {
770  ErrorState *err = static_cast<ErrorState *>(data);
771  debugs(4, 3, HERE << conn << ", size=" << size);
772 
773  if (errflag != Comm::ERR_CLOSING) {
774  if (err->callback) {
775  debugs(4, 3, "errorSendComplete: callback");
776  err->callback(conn->fd, err->callback_data, size);
777  } else {
778  debugs(4, 3, "errorSendComplete: comm_close");
779  conn->close();
780  }
781  }
782 
783  delete err;
784 }
785 
787 {
789  safe_free(url);
791  wordlistDestroy(&ftp.server_msg);
792  safe_free(ftp.request);
793  safe_free(ftp.reply);
795 #if USE_ERR_LOCALES
797 #endif
799 #if USE_OPENSSL
800  delete detail;
801 #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 #if USE_OPENSSL
966  // currently only SSL error details implemented
967  else if (detail) {
969  const String &errDetail = detail->toString();
970  if (errDetail.size() > 0) {
971  const auto compiledDetail = compileBody(errDetail.termedBuf(), false);
972  mb.append(compiledDetail.rawContent(), compiledDetail.length());
973  do_quote = 0;
974  }
975  }
976 #endif
977  if (!mb.contentSize())
978  mb.append("[No Error Detail]", 17);
979  break;
980 
981  case 'e':
982  mb.appendf("%d", xerrno);
983  break;
984 
985  case 'E':
986  if (xerrno)
987  mb.appendf("(%d) %s", xerrno, strerror(xerrno));
988  else
989  mb.append("[No Error]", 10);
990  break;
991 
992  case 'f':
993  if (building_deny_info_url) break;
994  /* FTP REQUEST LINE */
995  if (ftp.request)
996  p = ftp.request;
997  else
998  p = "nothing";
999  break;
1000 
1001  case 'F':
1002  if (building_deny_info_url) break;
1003  /* FTP REPLY LINE */
1004  if (ftp.reply)
1005  p = ftp.reply;
1006  else
1007  p = "nothing";
1008  break;
1009 
1010  case 'g':
1011  if (building_deny_info_url) break;
1012  /* FTP SERVER RESPONSE */
1013  if (ftp.listing) {
1014  mb.append(ftp.listing->content(), ftp.listing->contentSize());
1015  do_quote = 0;
1016  } else if (ftp.server_msg) {
1017  wordlistCat(ftp.server_msg, &mb);
1018  }
1019  break;
1020 
1021  case 'h':
1022  mb.appendf("%s", getMyHostname());
1023  break;
1024 
1025  case 'H':
1026  if (request) {
1027  if (request->hier.host[0] != '\0') // if non-empty string.
1028  p = request->hier.host;
1029  else
1030  p = request->url.host();
1031  } else if (!building_deny_info_url)
1032  p = "[unknown host]";
1033  break;
1034 
1035  case 'i':
1036  mb.appendf("%s", src_addr.toStr(ntoabuf,MAX_IPSTRLEN));
1037  break;
1038 
1039  case 'I':
1040  if (request && request->hier.tcpServer)
1041  p = request->hier.tcpServer->remote.toStr(ntoabuf,MAX_IPSTRLEN);
1042  else if (!building_deny_info_url)
1043  p = "[unknown]";
1044  break;
1045 
1046  case 'l':
1047  if (building_deny_info_url) break;
1048  mb.append(error_stylesheet.content(), error_stylesheet.contentSize());
1049  do_quote = 0;
1050  break;
1051 
1052  case 'L':
1053  if (building_deny_info_url) break;
1054  if (Config.errHtmlText) {
1055  mb.appendf("%s", Config.errHtmlText);
1056  do_quote = 0;
1057  } else
1058  p = "[not available]";
1059  break;
1060 
1061  case 'm':
1062  if (building_deny_info_url) break;
1063 #if USE_AUTH
1064  if (auth_user_request.getRaw())
1065  p = auth_user_request->denyMessage("[not available]");
1066  else
1067  p = "[not available]";
1068 #else
1069  p = "-";
1070 #endif
1071  break;
1072 
1073  case 'M':
1074  if (request) {
1075  const SBuf &m = request->method.image();
1076  mb.append(m.rawContent(), m.length());
1077  } else if (!building_deny_info_url)
1078  p = "[unknown method]";
1079  break;
1080 
1081  case 'O':
1082  if (!building_deny_info_url)
1083  do_quote = 0;
1084  case 'o':
1086  if (!p && !building_deny_info_url)
1087  p = "[not available]";
1088  break;
1089 
1090  case 'p':
1091  if (request) {
1092  mb.appendf("%u", request->url.port());
1093  } else if (!building_deny_info_url) {
1094  p = "[unknown port]";
1095  }
1096  break;
1097 
1098  case 'P':
1099  if (request) {
1100  const SBuf &m = request->url.getScheme().image();
1101  mb.append(m.rawContent(), m.length());
1102  } else if (!building_deny_info_url) {
1103  p = "[unknown protocol]";
1104  }
1105  break;
1106 
1107  case 'R':
1108  if (building_deny_info_url) {
1109  if (request != NULL) {
1110  const SBuf &tmp = request->url.path();
1111  mb.append(tmp.rawContent(), tmp.length());
1112  no_urlescape = 1;
1113  } else
1114  p = "[no request]";
1115  break;
1116  }
1117  if (request) {
1118  mb.appendf(SQUIDSBUFPH " " SQUIDSBUFPH " %s/%d.%d\n",
1123  request->header.packInto(&mb, true); //hide authorization data
1124  } else if (request_hdrs) {
1125  p = request_hdrs;
1126  } else {
1127  p = "[no request]";
1128  }
1129  break;
1130 
1131  case 's':
1132  /* for backward compat we make %s show the full URL. Drop this in some future release. */
1133  if (building_deny_info_url) {
1134  if (request) {
1135  const SBuf &tmp = request->effectiveRequestUri();
1136  mb.append(tmp.rawContent(), tmp.length());
1137  } else
1138  p = url;
1139  debugs(0, DBG_CRITICAL, "WARNING: deny_info now accepts coded tags. Use %u to get the full URL instead of %s");
1140  } else
1142  break;
1143 
1144  case 'S':
1145  if (building_deny_info_url) {
1147  break;
1148  }
1149  /* signature may contain %-escapes, recursion */
1150  if (page_id != ERR_SQUID_SIGNATURE) {
1151  const int saved_id = page_id;
1153  const auto signature = buildBody();
1154  mb.append(signature.rawContent(), signature.length());
1155  page_id = saved_id;
1156  do_quote = 0;
1157  } else {
1158  /* wow, somebody put %S into ERR_SIGNATURE, stop recursion */
1159  p = "[%S]";
1160  }
1161  break;
1162 
1163  case 't':
1165  break;
1166 
1167  case 'T':
1168  mb.appendf("%s", mkrfc1123(squid_curtime));
1169  break;
1170 
1171  case 'U':
1172  /* Using the fake-https version of absolute-URI so error pages see https:// */
1173  /* even when the url-path cannot be shown as more than '*' */
1174  if (request)
1176  else if (url)
1177  p = url;
1178  else if (!building_deny_info_url)
1179  p = "[no URL]";
1180  break;
1181 
1182  case 'u':
1183  if (request) {
1184  const SBuf &tmp = request->effectiveRequestUri();
1185  mb.append(tmp.rawContent(), tmp.length());
1186  } else if (url)
1187  p = url;
1188  else if (!building_deny_info_url)
1189  p = "[no URL]";
1190  break;
1191 
1192  case 'w':
1193  if (Config.adminEmail)
1194  mb.appendf("%s", Config.adminEmail);
1195  else if (!building_deny_info_url)
1196  p = "[unknown]";
1197  break;
1198 
1199  case 'W':
1200  if (building_deny_info_url) break;
1202  Dump(&mb);
1203  no_urlescape = 1;
1204  break;
1205 
1206  case 'x':
1207 #if USE_OPENSSL
1208  if (detail)
1209  mb.appendf("%s", detail->errorName());
1210  else
1211 #endif
1212  if (!building_deny_info_url)
1213  p = "[Unknown Error Code]";
1214  break;
1215 
1216  case 'z':
1217  if (building_deny_info_url) break;
1218  if (dnsError.size() > 0)
1219  p = dnsError.termedBuf();
1220  else if (ftp.cwd_msg)
1221  p = ftp.cwd_msg;
1222  else
1223  p = "[unknown]";
1224  break;
1225 
1226  case 'Z':
1227  if (building_deny_info_url) break;
1228  if (err_msg)
1229  p = err_msg;
1230  else
1231  p = "[unknown]";
1232  break;
1233 
1234  case '%':
1235  p = "%";
1236  break;
1237 
1238  default:
1239  if (building_deny_info_url)
1240  bypassBuildErrorXXX("Unsupported deny_info %code", build.input);
1241  else if (letter != ';')
1242  bypassBuildErrorXXX("Unsupported error page %code", build.input);
1243  // else too many "font-size: 100%;" template errors to report
1244 
1245  mb.append(build.input, 2);
1246  do_quote = 0;
1247  break;
1248  }
1249 
1250  if (!p)
1251  p = mb.buf; /* do not use mb after this assignment! */
1252 
1253  assert(p);
1254 
1255  debugs(4, 3, "%" << letter << " --> '" << p << "'" );
1256 
1257  if (do_quote)
1258  p = html_quote(p);
1259 
1260  if (building_deny_info_url && !no_urlescape)
1261  p = rfc1738_escape_part(p);
1262 
1263  // TODO: Optimize by replacing mb with direct build.output usage.
1264  build.output.append(p, strlen(p));
1265  build.input += 2;
1266 }
1267 
1268 void
1270 {
1271  if (const auto urlTemplate = ErrorPage::IsDenyInfoUri(page_id)) {
1272  (void)compile(urlTemplate, true, true);
1273  } else {
1274  assert(page_id > ERR_NONE);
1275  assert(page_id < error_page_count);
1276  (void)compileBody(error_text[page_id], true);
1277  }
1278 }
1279 
1280 HttpReply *
1282 {
1283  if (response_)
1284  return response_.getRaw();
1285 
1286  HttpReply *rep = new HttpReply;
1287  const char *name = errorPageName(page_id);
1288  /* no LMT for error pages; error pages expire immediately */
1289 
1290  if (const auto urlTemplate = ErrorPage::IsDenyInfoUri(page_id)) {
1291  /* Redirection */
1293  // Use configured 3xx reply status if set.
1294  if (name[0] == '3')
1295  status = httpStatus;
1296  else {
1297  // Use 307 for HTTP/1.1 non-GET/HEAD requests.
1299  status = Http::scTemporaryRedirect;
1300  }
1301 
1302  rep->setHeaders(status, NULL, "text/html;charset=utf-8", 0, 0, -1);
1303 
1304  if (request) {
1305  auto location = compile(urlTemplate, true, true);
1306  rep->header.putStr(Http::HdrType::LOCATION, location.c_str());
1307  }
1308 
1309  httpHeaderPutStrf(&rep->header, Http::HdrType::X_SQUID_ERROR, "%d %s", httpStatus, "Access Denied");
1310  } else {
1311  const auto body = buildBody();
1312  rep->setHeaders(httpStatus, NULL, "text/html;charset=utf-8", body.length(), 0, -1);
1313  /*
1314  * include some information for downstream caches. Implicit
1315  * replaceable content. This isn't quite sufficient. xerrno is not
1316  * necessarily meaningful to another system, so we really should
1317  * expand it. Additionally, we should identify ourselves. Someone
1318  * might want to know. Someone _will_ want to know OTOH, the first
1319  * X-CACHE-MISS entry should tell us who.
1320  */
1322 
1323 #if USE_ERR_LOCALES
1324  /*
1325  * If error page auto-negotiate is enabled in any way, send the Vary.
1326  * RFC 2616 section 13.6 and 14.44 says MAY and SHOULD do this.
1327  * We have even better reasons though:
1328  * see http://wiki.squid-cache.org/KnowledgeBase/VaryNotCaching
1329  */
1330  if (!Config.errorDirectory) {
1331  /* We 'negotiated' this ONLY from the Accept-Language. */
1333  rep->header.putStr(Http::HdrType::VARY, "Accept-Language");
1334  }
1335 
1336  /* add the Content-Language header according to RFC section 14.12 */
1337  if (err_language) {
1339  } else
1340 #endif /* USE_ERROR_LOCALES */
1341  {
1342  /* default templates are in English */
1343  /* language is known unless error_directory override used */
1344  if (!Config.errorDirectory)
1346  }
1347 
1348  rep->body.set(body);
1349  }
1350 
1351  // Make sure error codes get back to the client side for logging and
1352  // error tracking.
1353  if (request) {
1354  int edc = ERR_DETAIL_NONE; // error detail code
1355 #if USE_OPENSSL
1356  if (detail)
1357  edc = detail->errorNo();
1358  else
1359 #endif
1360  if (detailCode)
1361  edc = detailCode;
1362  else
1363  edc = xerrno;
1364  request->detailError(type, edc);
1365  }
1366 
1367  return rep;
1368 }
1369 
1370 SBuf
1372 {
1373  assert(page_id > ERR_NONE && page_id < error_page_count);
1374 
1375 #if USE_ERR_LOCALES
1376 
1380  if (!Config.errorDirectory && page_id < ERR_MAX) {
1383 
1384  ErrorPageFile localeTmpl(err_type_str[page_id], static_cast<err_type>(page_id));
1385  if (localeTmpl.loadFor(request.getRaw())) {
1386  inputLocation = localeTmpl.filename;
1387  assert(localeTmpl.language());
1388  err_language = xstrdup(localeTmpl.language());
1389  return compileBody(localeTmpl.text(), true);
1390  }
1391  }
1392 #endif /* USE_ERR_LOCALES */
1393 
1398 #if USE_ERR_LOCALES
1399  if (!Config.errorDirectory)
1401 #endif
1402  debugs(4, 2, "No existing error page language negotiated for " << errorPageName(page_id) << ". Using default error file.");
1403  return compileBody(error_text[page_id], true);
1404 }
1405 
1406 SBuf
1407 ErrorState::compileBody(const char *input, bool allowRecursion)
1408 {
1409  return compile(input, false, allowRecursion);
1410 }
1411 
1412 SBuf
1413 ErrorState::compile(const char *input, bool building_deny_info_url, bool allowRecursion)
1414 {
1415  assert(input);
1416 
1417  Build build;
1418  build.building_deny_info_url = building_deny_info_url;
1419  build.allowRecursion = allowRecursion;
1420  build.input = input;
1421 
1422  auto blockStart = build.input;
1423  while (const auto letter = *build.input) {
1424  if (letter == '%') {
1425  build.output.append(blockStart, build.input - blockStart);
1426  compileLegacyCode(build);
1427  blockStart = build.input;
1428  }
1429  else if (letter == '@' && LogformatMagic.cmp(build.input, LogformatMagic.length()) == 0) {
1430  build.output.append(blockStart, build.input - blockStart);
1431  compileLogformatCode(build);
1432  blockStart = build.input;
1433  } else {
1434  ++build.input;
1435  }
1436  }
1437  build.output.append(blockStart, build.input - blockStart);
1438  return build.output;
1439 }
1440 
1448 void
1449 ErrorState::noteBuildError_(const char *msg, const char *near, const bool forceBypass)
1450 {
1452  const auto runtime = !starting_up;
1453  if (runtime || forceBypass) {
1454  // swallow this problem because the admin may not be (and/or the page
1455  // building code is not) ready to handle throwing consequences
1456 
1457  static unsigned int seenErrors = 0;
1458  ++seenErrors;
1459 
1460  const auto debugLevel =
1461  (seenErrors > 100) ? DBG_DATA:
1463  3; // most other errors have been reported as configuration errors
1464 
1465  // Error fatality depends on the error context: Reconfiguration errors
1466  // are, like startup ones, DBG_CRITICAL but will never become FATAL.
1467  if (starting_up && seenErrors <= 10)
1468  debugs(4, debugLevel, "WARNING: The following configuration error will be fatal in future Squid versions");
1469 
1470  debugs(4, debugLevel, "ERROR: " << BuildErrorPrinter(inputLocation, page_id, msg, near));
1471  } else {
1472  throw TexcHere(ToSBuf(BuildErrorPrinter(inputLocation, page_id, msg, near)));
1473  }
1474 }
1475 
1476 /* ErrorPage::BuildErrorPrinter */
1477 
1478 std::ostream &
1480  if (!inputLocation.isEmpty())
1481  return os << inputLocation;
1482 
1483  if (page_id < ERR_NONE || page_id >= error_page_count)
1484  return os << "[error page " << page_id << "]"; // should not happen
1485 
1486  if (page_id < ERR_MAX)
1487  return os << err_type_str[page_id];
1488 
1489  return os << "deny_info " << ErrorDynamicPages.at(page_id - ERR_MAX)->page_name;
1490 }
1491 
1492 std::ostream &
1493 ErrorPage::BuildErrorPrinter::print(std::ostream &os) const {
1494  printLocation(os) << ": " << msg << " near ";
1495 
1496  // TODO: Add support for prefix printing to Raw
1497  const size_t maxContextLength = 15; // plus "..."
1498  if (strlen(near) > maxContextLength) {
1499  os.write(near, maxContextLength);
1500  os << "...";
1501  } else {
1502  os << near;
1503  }
1504 
1505  // XXX: We should not be converting (inner) exception to text if we are
1506  // going to throw again. See "add arbitrary (re)thrower-supplied details"
1507  // TODO in TextException.h for a long-term in-catcher solution.
1508  if (std::current_exception())
1509  os << "\n additional info: " << CurrentException;
1510 
1511  return os;
1512 }
1513 
1515 static void
1517 {
1518  assert(!error_text[page_id]);
1519  error_text[page_id] = xstrdup(text);
1520  ValidateStaticError(page_id, inputLocation);
1521 }
1522 
1524 static void
1526 {
1527  // Supplying nil ALE pointer limits validation to logformat %code
1528  // recognition by Format::Token::parse(). This is probably desirable
1529  // because actual %code assembly is slow and should not affect validation
1530  // when our ALE cannot have any real data (this code is not associated
1531  // with any real transaction).
1532  ErrorState anErr(err_type(page_id), Http::scNone, nullptr, nullptr);
1533  anErr.inputLocation = inputLocation;
1534  anErr.validate();
1535 }
1536 
size_type length() const
Returns the number of bytes stored in SBuf.
Definition: SBuf.h:404
int delById(Http::HdrType id)
Definition: HttpHeader.cc:681
HierarchyLogEntry hier
Definition: HttpRequest.h:157
const char * filename
admin-configured name for the error page template (custom or standard)
Definition: errorpage.cc:85
AnyP::ProtocolVersion ProtocolVersion(unsigned int aMajor, unsigned int aMinor)
HTTP version label information.
HttpReplyPointer response_
Definition: errorpage.h:210
static void ImportStaticErrorText(const int page_id, const char *text, const SBuf &inputLocation)
add error page template to the global index
Definition: errorpage.cc:1516
ErrorDynamicPageInfo(const int anId, const char *aName, const SBuf &aCfgLocation)
Definition: errorpage.cc:553
void bypassBuildErrorXXX(const char *msg, const char *near)
Definition: errorpage.h:159
void compileLegacyCode(Build &build)
compile a single-letter code like D
Definition: errorpage.cc:911
#define assert(EX)
Definition: assert.h:17
char * strerror(int ern)
Definition: strerror.c:22
void const char HLPCB * callback
Definition: stub_helper.cc:16
void noteBuildError(const char *msg, const char *near)
Definition: errorpage.h:150
int emailErrData
Definition: SquidConfig.h:323
const char * mkrfc1123(time_t)
Definition: rfc1123.c:202
int id
error_text[] index for response body (unused in redirection responses)
Definition: errorpage.cc:74
SBuf cfgLocation
deny_info directive position in squid.conf (for reporting)
Definition: errorpage.cc:88
virtual void append(const char *c, int sz)
Definition: MemBuf.cc:216
SBuf image() const
Definition: UriScheme.h:50
int FD_READ_METHOD(int fd, char *buf, int len)
Definition: fde.h:179
virtual void setDefault() override
recover from loadDefault() failure to load or parse() a template
Definition: errorpage.cc:216
int type
Definition: errorpage.cc:152
void path(const char *p)
Definition: Uri.h:88
void compileLogformatCode(Build &build)
compile {code} sequence containing a single logformat code
Definition: errorpage.cc:875
Definition: SBuf.h:86
Comm::ConnectionPointer tcpServer
TCP/IP level details of the last peer/server connection.
#define xcalloc
Definition: membanger.c:57
const char * urlCanonicalFakeHttps(const HttpRequest *request)
Definition: Uri.cc:570
String getList(Http::HdrType id) const
Definition: HttpHeader.cc:828
void self_destruct(void)
Definition: cache_cf.cc:256
HttpRequestMethod method
Definition: HttpRequest.h:114
String errLanguage
The error language of the template.
Definition: errorpage.h:338
struct _request * request(char *urlin)
Definition: tcp-banger2.c:291
char * adminEmail
Definition: SquidConfig.h:186
int i
Definition: membanger.c:49
#define xstrdup
SBuf & append(const SBuf &S)
Definition: SBuf.cc:195
int page_id
Definition: errorpage.h:172
#define MAXPATHLEN
Definition: stdio.h:62
bool building_deny_info_url
whether we compile deny_info URI
Definition: errorpage.cc:107
SBuf ToSBuf(Args &&... args)
slowly stream-prints all arguments into a freshly allocated SBuf
Definition: Stream.h:124
ERCB * callback
Definition: errorpage.h:187
#define safe_free(x)
Definition: xalloc.h:73
void wordlistDestroy(wordlist **list)
destroy a wordlist
Definition: wordlist.cc:16
char * html_quote(const char *)
Definition: html_quote.c:53
char * url
Definition: errorpage.h:179
int file_open(const char *path, int mode)
Definition: fs_io.cc:46
static std::vector< ErrorDynamicPageInfo * > ErrorDynamicPages
Definition: errorpage.cc:186
#define Must(condition)
Like assert() but throws an exception instead of aborting the process.
Definition: TextException.h:69
bool isEmpty() const
Definition: SBuf.h:420
AnyP::ProtocolVersion http_ver
Definition: Message.h:73
#define xisspace(x)
Definition: xis.h:17
#define DBG_CRITICAL
Definition: Debug.h:45
Auth::UserRequest::Pointer auth_user_request
Definition: errorpage.h:176
char * p
Definition: membanger.c:43
char * err_msg
Definition: errorpage.h:199
int conn
the current server connection FD
Definition: Transport.cc:26
static MemBuf error_stylesheet
Definition: errorpage.cc:200
const char * getMyHostname(void)
Definition: tools.cc:412
void * callback_data
Definition: errorpage.h:188
SBuf output
compilation result
Definition: errorpage.cc:105
bool loaded() const
return true if the data loaded from disk without any problem
Definition: errorpage.h:290
bool wasLoaded
True if the template data read from disk without any problem.
Definition: errorpage.h:337
char host[SQUIDHOSTNAMELEN]
const char * err_type_str[]
time_t squid_curtime
Definition: stub_time.cc:17
void errorSend(const Comm::ConnectionPointer &conn, ErrorState *err)
Definition: errorpage.cc:744
struct SquidConfig::@111 onoff
int detailCode
Definition: errorpage.h:208
bool silent
Whether to print error messages on cache.log file or not. It is user defined.
Definition: errorpage.h:320
err_type templateCode
The internal code for this template.
Definition: errorpage.h:340
bool tryLoadTemplate(const char *lang)
Definition: errorpage.cc:387
char * errorStylesheet
Definition: SquidConfig.h:433
char const * username() const
Definition: UserRequest.cc:32
void httpHeaderPutStrf(HttpHeader *hdr, Http::HdrType id, const char *fmt,...)
String extacl_message
Definition: HttpRequest.h:185
char * errorDirectory
Definition: SquidConfig.h:428
void errorClean(void)
Definition: errorpage.cc:309
const SBuf & effectiveRequestUri() const
RFC 7230 section 5.5 - Effective Request URI.
Definition: HttpRequest.cc:707
err_type errorReservePageId(const char *page_name, const SBuf &cfgLocation)
allocates a new slot for the error page
Definition: errorpage.cc:640
Http::StatusCode page_redirect
admin-configured HTTP status code
Definition: errorpage.cc:92
an error page created from admin-configurable metadata (e.g. deny_info)
Definition: errorpage.cc:68
static std::ostream & operator<<(std::ostream &os, const BuildErrorPrinter &context)
Definition: errorpage.cc:131
const char * xstrerr(int error)
Definition: xstrerror.cc:83
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:24
unsigned int major
major version number
void const char HLPCB void * data
Definition: stub_helper.cc:16
StatusCode
Definition: StatusCode.h:20
char * toStr(char *buf, const unsigned int blen, int force=AF_UNSPEC) const
Definition: Address.cc:802
int getMyPort(void)
Definition: tools.cc:1003
void port(unsigned short p)
Definition: Uri.h:83
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:124
void setHeaders(Http::StatusCode status, const char *reason, const char *ctype, int64_t clen, time_t lmt, time_t expires)
Definition: HttpReply.cc:161
#define DBG_IMPORTANT
Definition: Debug.h:46
err_type & operator++(err_type &anErr)
Definition: errorpage.cc:223
SBuf inputLocation
the source of the error template (for reporting purposes)
Definition: errorpage.h:118
mb_size_t contentSize() const
available data size
Definition: MemBuf.h:47
void reset()
Definition: MemBuf.cc:132
virtual bool parse()
post-process the loaded template
Definition: errorpage.h:324
Ip::Address client_addr
Definition: HttpRequest.h:149
#define DEFAULT_SQUID_ERROR_DIR
Definition: errorpage.cc:57
const String & toString() const
An error detail string to embed in squid error pages.
Definition: ErrorDetail.cc:635
SBuf compile(const char *input, bool building_deny_info_url, bool allowRecursion)
Definition: errorpage.cc:1413
const char * input
template bytes that need to be compiled
Definition: errorpage.cc:106
size_t AssembleOne(const char *start, MemBuf &buf, const AccessLogEntryPointer &ale)
Definition: Format.cc:99
ErrorState()=delete
BuildErrorPrinter(const SBuf &anInputLocation, int aPage, const char *aMsg, const char *aNear)
Definition: errorpage.cc:115
const char * errorPageName(int pageId)
error ID to string
Definition: errorpage.cc:655
bool isEmpty() const
Definition: Store.h:60
const SBuf & UrlWith2f(HttpRequest *)
Definition: FtpGateway.cc:2642
static ErrorState * NewForwarding(err_type, HttpRequestPointer &, const AccessLogEntryPointer &)
Creates a general request forwarding error with the right http_status.
Definition: errorpage.cc:667
AnyP::Uri url
the request URI
Definition: HttpRequest.h:115
void * addr
Definition: membanger.c:46
TemplateFile(const char *name, const err_type code)
Definition: errorpage.cc:345
std::ostream & CurrentException(std::ostream &os)
prints active (i.e., thrown but not yet handled) exception
SBuf compileBody(const char *text, bool allowRecursion)
Definition: errorpage.cc:1407
Http::StatusCode httpStatus
Definition: errorpage.h:174
uint16_t flags
Definition: Store.h:210
static const SBuf LogformatMagic
marks each embedded logformat entry
Definition: errorpage.h:215
static const char * IsDenyInfoUri(const int page_id)
Definition: errorpage.cc:239
void wordlistCat(const wordlist *w, MemBuf *mb)
Definition: wordlist.cc:35
virtual void setDefault()
recover from loadDefault() failure to load or parse() a template
Definition: errorpage.h:327
static void ValidateStaticError(const int page_id, const SBuf &inputLocation)
validate static error page
Definition: errorpage.cc:1525
void loadDefault()
Definition: errorpage.cc:351
Http::StatusLine sline
Definition: HttpReply.h:60
bool allowRecursion
whether top-level compile() calls are OK
Definition: errorpage.cc:108
void host(const char *src)
Definition: Uri.cc:47
SBuf filename
where the template was loaded from
Definition: errorpage.h:318
void noteBuildError_(const char *msg, const char *near, const bool forceBypass)
Definition: errorpage.cc:1449
static const char * errorFindHardText(err_type type)
Definition: errorpage.cc:334
char const * denyMessage(char const *const default_message=NULL) const
Definition: UserRequest.cc:127
MemObject * mem_obj
Definition: Store.h:199
static int errorPageId(const char *page_name)
Definition: errorpage.cc:624
struct ErrorState::@60 ftp
const char * uri
admin-configured HTTP Location header value for redirection responses
Definition: errorpage.cc:82
char const * termedBuf() const
Definition: SquidString.h:91
int unsigned int const char *desc STUB void int len
Definition: stub_fd.cc:20
char * content()
start of the added data
Definition: MemBuf.h:41
unsigned char code
Definition: html_quote.c:20
void const char * buf
Definition: stub_helper.cc:16
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:153
void IOCB(const Comm::ConnectionPointer &conn, char *, size_t size, Comm::Flag flag, int xerrno, void *data)
Definition: CommCalls.h:36
#define O_TEXT
Definition: defines.h:201
const SBuf & image() const
Flag
Definition: Flag.h:15
HttpHeader header
Definition: Message.h:75
void errorDetailClean()
bool SIGHDLR int STUB void int
Definition: stub_tools.cc:68
void clean()
Definition: MemBuf.cc:113
char * buf
Definition: MemBuf.h:134
ErrorPageFile(const char *name, const err_type code)
Definition: errorpage.cc:210
RequestFlags flags
Definition: HttpRequest.h:141
void useRequest(HttpRequest *aRequest)
Definition: ErrorDetail.h:49
store_status_t store_status
Definition: Store.h:222
#define MYNAME
Definition: Debug.h:166
const char * text()
The template text data read from disk.
Definition: errorpage.cc:213
int operator-(err_type const &anErr, err_type const &anErr2)
Definition: errorpage.cc:231
err_type type
Definition: errorpage.h:171
Ip::Address remote
Definition: Connection.h:138
void putStr(Http::HdrType id, const char *str)
Definition: HttpHeader.cc:1038
String dnsError
DNS lookup error message.
Definition: errorpage.h:182
HttpBody body
Definition: HttpReply.h:62
static IOCB errorSendComplete
Definition: errorpage.cc:203
const char * external_acl_message
const Ip::Address * FindListeningPortAddress(const HttpRequest *callerRequest, const AccessLogEntry *ale)
Definition: HttpRequest.cc:805
int cmp(const SBuf &S, const size_type n) const
shorthand version for compare()
Definition: SBuf.h:264
void errorDetailInitialize()
#define CBDATA_CLASS_INIT(type)
Definition: cbdata.h:318
void detailError(err_type aType, int aDetail)
sets error detail if no earlier detail was available
Definition: HttpRequest.cc:476
#define xisdigit(x)
Definition: xis.h:20
const char * FormatHttpd(time_t t)
Definition: stub_time.cc:25
HttpRequestPointer request
Definition: errorpage.h:178
C * getRaw() const
Definition: RefCount.h:74
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
Definition: Packable.h:61
SBuf buildBody()
locates the right error page template for this error and compiles it
Definition: errorpage.cc:1371
Definition: MemBuf.h:23
bool strHdrAcptLangGetItem(const String &hdr, char *lang, int langLen, size_t &pos)
Definition: errorpage.cc:460
#define TexcHere(msg)
legacy convenience macro; it is not difficult to type Here() now
Definition: TextException.h:55
Auth::UserRequest::Pointer auth_user_request
Definition: HttpRequest.h:127
char * errorDefaultLanguage
Definition: SquidConfig.h:430
void errorAppendEntry(StoreEntry *entry, ErrorState *err)
Definition: errorpage.cc:711
int Dump(MemBuf *mb)
Definition: errorpage.cc:805
const char * ProtocolType_str[]
CommCbFunPtrCallT< Dialer > * commCbCall(int debugSection, int debugLevel, const char *callName, const Dialer &dialer)
Definition: CommCalls.h:342
int nclients
Definition: MemObject.h:111
Http::StatusCode status() const
retrieve the status code for this status line
Definition: StatusLine.h:45
char * errHtmlText
Definition: SquidConfig.h:224
AccessLogEntryPointer ale
transaction details (or nil)
Definition: errorpage.h:201
char * request_hdrs
Definition: errorpage.h:198
std::ostream & print(std::ostream &) const
reports error details (for admin-visible exceptions and debugging)
Definition: errorpage.cc:1493
void validate()
ensures that a future BuildHttpReply() is likely to succeed
Definition: errorpage.cc:1269
pretty-prints error page/deny_info building error
Definition: errorpage.cc:112
bool loadFor(const HttpRequest *request)
Definition: errorpage.cc:514
HttpReply * BuildHttpReply(void)
Definition: errorpage.cc:1281
void storeErrorResponse(HttpReply *reply)
Store a prepared error response. MemObject locks the reply object.
Definition: store.cc:1771
#define MAX_IPSTRLEN
Length of buffer that needs to be allocated to old a null-terminated IP-string.
Definition: forward.h:23
const char * language()
The language used for the template.
Definition: errorpage.h:316
static const int error_hard_text_count
Definition: errorpage.cc:191
void errorInitialize(void)
Definition: errorpage.cc:247
unsigned int minor
minor version number
int xerrno
Definition: errorpage.h:180
#define rfc1738_escape_part(x)
Definition: rfc1738.h:55
int errorLogMissingLanguages
Definition: SquidConfig.h:431
state and parameters shared by several ErrorState::compile*() methods
Definition: errorpage.cc:102
const char * errorName() const
The error name to embed in squid error pages.
Definition: ErrorDetail.h:51
AnyP::UriScheme const & getScheme() const
Definition: Uri.h:67
Ip::Address src_addr
Definition: errorpage.h:185
#define SQUIDSBUFPH
Definition: SBuf.h:31
static int error_page_count
Definition: errorpage.cc:197
#define DBG_DATA
Definition: Debug.h:48
char * redirect_url
Definition: errorpage.h:186
ProtocolType protocol
which protocol this version is for
static const struct @59 error_hard_text[]
Ssl::ErrorDetail * detail
Definition: errorpage.h:204
#define xfree
void file_close(int fd)
Definition: fs_io.cc:76
#define SQUIDSBUFPRINT(s)
Definition: SBuf.h:32
String substr(size_type from, size_type to) const
Definition: String.cc:223
char const * visible_appname_string
#define xtolower(x)
Definition: xis.h:19
size_type size() const
Definition: SquidString.h:72
Definition: forward.h:21
Security::ErrorCode errorNo() const
The error no.
Definition: ErrorDetail.h:53
#define EBIT_TEST(flag, bit)
Definition: defines.h:107
int starting_up
class SquidConfig Config
Definition: SquidConfig.cc:12
#define NULL
Definition: types.h:166
void set(const SBuf &newContent)
Definition: HttpBody.h:26
const char * text
Definition: errorpage.cc:153
bool needValidation
Definition: RequestFlags.h:46
void packInto(Packable *p, bool mask_sensitive_info=false) const
Definition: HttpHeader.cc:554
int reconfiguring
int size
Definition: ModDevPoll.cc:77
String templateName
The name of the template.
Definition: errorpage.h:339
const char * rawContent() const
Definition: SBuf.cc:519
#define false
Definition: GnuRegex.c:233
bool loadFromFile(const char *path)
Definition: errorpage.cc:412
void Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE *free_func)
Definition: Write.cc:35
std::ostream & printLocation(std::ostream &os) const
print() helper to report where the error was found
Definition: errorpage.cc:1479
err_type
Definition: err_type.h:12
char * err_language
Definition: errorpage.h:173

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors