errorpage.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2018 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 "cache_cf.h"
13 #include "clients/forward.h"
14 #include "comm/Connection.h"
15 #include "comm/Write.h"
16 #include "err_detail_type.h"
17 #include "errorpage.h"
18 #include "fde.h"
19 #include "fs_io.h"
20 #include "html_quote.h"
21 #include "HttpHeaderTools.h"
22 #include "HttpReply.h"
23 #include "HttpRequest.h"
24 #include "MemBuf.h"
25 #include "MemObject.h"
26 #include "rfc1738.h"
27 #include "SquidConfig.h"
28 #include "Store.h"
29 #include "tools.h"
30 #include "wordlist.h"
31 #if USE_AUTH
32 #include "auth/UserRequest.h"
33 #endif
34 #include "SquidTime.h"
35 #if USE_OPENSSL
36 #include "ssl/ErrorDetailManager.h"
37 #endif
38 
50 #if !defined(DEFAULT_SQUID_ERROR_DIR)
51 
54 #define DEFAULT_SQUID_ERROR_DIR DEFAULT_SQUID_DATA_DIR"/errors"
55 #endif
56 
59 
60 /* local types */
61 
63 typedef struct {
64  int id;
65  char *page_name;
68 
69 /* local constant and vars */
70 
77 static const struct {
78  int type; /* and page_id */
79  const char *text;
80 }
81 
82 error_hard_text[] = {
83 
84  {
86  "\n<br>\n"
87  "<hr>\n"
88  "<div id=\"footer\">\n"
89  "Generated %T by %h (%s)\n"
90  "</div>\n"
91  "</body></html>\n"
92  },
93  {
94  TCP_RESET,
95  "reset"
96  }
97 };
98 
100 static std::vector<ErrorDynamicPageInfo *> ErrorDynamicPages;
101 
102 /* local prototypes */
103 
105 static const int error_hard_text_count = sizeof(error_hard_text) / sizeof(*error_hard_text);
106 
108 static char **error_text = NULL;
109 
111 static int error_page_count = 0;
112 
115 
116 static const char *errorFindHardText(err_type type);
117 static ErrorDynamicPageInfo *errorDynamicPageInfoCreate(int id, const char *page_name);
120 
124 {
125 public:
126  ErrorPageFile(const char *name, const err_type code) : TemplateFile(name,code) {textBuf.init();}
127 
129  const char *text() { return textBuf.content(); }
130 
131 private:
133  virtual bool parse(const char *buf, int len, bool) {
134  if (len)
135  textBuf.append(buf, len);
136  return true;
137  }
138 
140 };
141 
144 {
145  int tmp = (int)anErr;
146  anErr = (err_type)(++tmp);
147  return anErr;
148 }
149 
151 int operator - (err_type const &anErr, err_type const &anErr2)
152 {
153  return (int)anErr - (int)anErr2;
154 }
155 
156 void
158 {
159  err_type i;
160  const char *text;
161  error_page_count = ERR_MAX + ErrorDynamicPages.size();
162  error_text = static_cast<char **>(xcalloc(error_page_count, sizeof(char *)));
163 
164  for (i = ERR_NONE, ++i; i < error_page_count; ++i) {
165  safe_free(error_text[i]);
166 
167  if ((text = errorFindHardText(i))) {
171  error_text[i] = xstrdup(text);
172 
173  } else if (i < ERR_MAX) {
179  ErrorPageFile errTmpl(err_type_str[i], i);
180  error_text[i] = errTmpl.loadDefault() ? xstrdup(errTmpl.text()) : NULL;
181  } else {
185  ErrorDynamicPageInfo *info = ErrorDynamicPages.at(i - ERR_MAX);
186  assert(info && info->id == i && info->page_name);
187 
188  const char *pg = info->page_name;
189  if (info->page_redirect != Http::scNone)
190  pg = info->page_name +4;
191 
192  if (strchr(pg, ':') == NULL) {
194  ErrorPageFile errTmpl(pg, ERR_MAX);
195  error_text[i] = errTmpl.loadDefault() ? xstrdup(errTmpl.text()) : NULL;
196  }
197  }
198  }
199 
200  error_stylesheet.reset();
201 
202  // look for and load stylesheet into global MemBuf for it.
203  if (Config.errorStylesheet) {
204  ErrorPageFile tmpl("StylesSheet", ERR_MAX);
206  error_stylesheet.appendf("%s",tmpl.text());
207  }
208 
209 #if USE_OPENSSL
211 #endif
212 }
213 
214 void
216 {
217  if (error_text) {
218  int i;
219 
220  for (i = ERR_NONE + 1; i < error_page_count; ++i)
221  safe_free(error_text[i]);
222 
223  safe_free(error_text);
224  }
225 
226  while (!ErrorDynamicPages.empty()) {
227  errorDynamicPageInfoDestroy(ErrorDynamicPages.back());
228  ErrorDynamicPages.pop_back();
229  }
230 
231  error_page_count = 0;
232 
233 #if USE_OPENSSL
235 #endif
236 }
237 
239 static const char *
241 {
242  int i;
243 
244  for (i = 0; i < error_hard_text_count; ++i)
245  if (error_hard_text[i].type == type)
246  return error_hard_text[i].text;
247 
248  return NULL;
249 }
250 
251 TemplateFile::TemplateFile(const char *name, const err_type code): silent(false), wasLoaded(false), templateName(name), templateCode(code)
252 {
253  assert(name);
254 }
255 
256 bool
258 {
259  if (loaded()) // already loaded?
260  return true;
261 
263  if (Config.errorDirectory) {
264  char path[MAXPATHLEN];
265  snprintf(path, sizeof(path), "%s/%s", Config.errorDirectory, templateName.termedBuf());
266  loadFromFile(path);
267  }
268 
269 #if USE_ERR_LOCALES
270 
271  if (!loaded() && Config.errorDefaultLanguage) {
273  debugs(1, (templateCode < TCP_RESET ? DBG_CRITICAL : 3), "Unable to load default error language files. Reset to backups.");
274  }
275  }
276 #endif
277 
278  /* test default location if failed (templates == English translation base templates) */
279  if (!loaded()) {
280  tryLoadTemplate("templates");
281  }
282 
283  /* giving up if failed */
284  if (!loaded()) {
285  debugs(1, (templateCode < TCP_RESET ? DBG_CRITICAL : 3), "WARNING: failed to find or read error text file " << templateName);
286  parse("Internal Error: Missing Template ", 33, '\0');
288  }
289 
290  return true;
291 }
292 
293 bool
295 {
296  assert(lang);
297 
298  char path[MAXPATHLEN];
299  /* TODO: prep the directory path string to prevent snprintf ... */
300  snprintf(path, sizeof(path), "%s/%s/%s",
302  path[MAXPATHLEN-1] = '\0';
303 
304  if (loadFromFile(path))
305  return true;
306 
307 #if HAVE_GLOB
308  if ( strlen(lang) == 2) {
309  /* TODO glob the error directory for sub-dirs matching: <tag> '-*' */
310  /* use first result. */
311  debugs(4,2, HERE << "wildcard fallback errors not coded yet.");
312  }
313 #endif
314 
315  return false;
316 }
317 
318 bool
319 TemplateFile::loadFromFile(const char *path)
320 {
321  int fd;
322  char buf[4096];
323  ssize_t len;
324 
325  if (loaded()) // already loaded?
326  return true;
327 
328  fd = file_open(path, O_RDONLY | O_TEXT);
329 
330  if (fd < 0) {
331  /* with dynamic locale negotiation we may see some failures before a success. */
332  if (!silent && templateCode < TCP_RESET) {
333  int xerrno = errno;
334  debugs(4, DBG_CRITICAL, "ERROR: loading file '" << path << "': " << xstrerr(xerrno));
335  }
336  wasLoaded = false;
337  return wasLoaded;
338  }
339 
340  while ((len = FD_READ_METHOD(fd, buf, sizeof(buf))) > 0) {
341  if (!parse(buf, len, false)) {
342  debugs(4, DBG_CRITICAL, "ERROR: parsing error in template file: " << path);
343  wasLoaded = false;
344  return wasLoaded;
345  }
346  }
347  parse(buf, 0, true);
348 
349  if (len < 0) {
350  int xerrno = errno;
351  debugs(4, DBG_CRITICAL, MYNAME << "ERROR: failed to fully read: '" << path << "': " << xstrerr(xerrno));
352  }
353 
354  file_close(fd);
355 
356  wasLoaded = true;
357  return wasLoaded;
358 }
359 
360 bool strHdrAcptLangGetItem(const String &hdr, char *lang, int langLen, size_t &pos)
361 {
362  while (pos < hdr.size()) {
363 
364  /* skip any initial whitespace. */
365  while (pos < hdr.size() && xisspace(hdr[pos]))
366  ++pos;
367 
368  /*
369  * Header value format:
370  * - sequence of whitespace delimited tags
371  * - each tag may suffix with ';'.* which we can ignore.
372  * - IFF a tag contains only two characters we can wildcard ANY translations matching: <it> '-'? .*
373  * with preference given to an exact match.
374  */
375  bool invalid_byte = false;
376  char *dt = lang;
377  while (pos < hdr.size() && hdr[pos] != ';' && hdr[pos] != ',' && !xisspace(hdr[pos]) && dt < (lang + (langLen -1)) ) {
378  if (!invalid_byte) {
379 #if USE_HTTP_VIOLATIONS
380  // if accepting violations we may as well accept some broken browsers
381  // which may send us the right code, wrong ISO formatting.
382  if (hdr[pos] == '_')
383  *dt = '-';
384  else
385 #endif
386  *dt = xtolower(hdr[pos]);
387  // valid codes only contain A-Z, hyphen (-) and *
388  if (*dt != '-' && *dt != '*' && (*dt < 'a' || *dt > 'z') )
389  invalid_byte = true;
390  else
391  ++dt; // move to next destination byte.
392  }
393  ++pos;
394  }
395  *dt = '\0'; // nul-terminated the filename content string before system use.
396 
397  // if we terminated the tag on garbage or ';' we need to skip to the next ',' or end of header.
398  while (pos < hdr.size() && hdr[pos] != ',')
399  ++pos;
400 
401  if (pos < hdr.size() && hdr[pos] == ',')
402  ++pos;
403 
404  debugs(4, 9, "STATE: lang=" << lang << ", pos=" << pos << ", buf='" << ((pos < hdr.size()) ? hdr.substr(pos,hdr.size()) : "") << "'");
405 
406  /* if we found anything we might use, try it. */
407  if (*lang != '\0' && !invalid_byte)
408  return true;
409  }
410  return false;
411 }
412 
413 bool
415 {
416  String hdr;
417 
418 #if USE_ERR_LOCALES
419  if (loaded()) // already loaded?
420  return true;
421 
422  if (!request || !request->header.getList(Http::HdrType::ACCEPT_LANGUAGE, &hdr))
423  return false;
424 
425  char lang[256];
426  size_t pos = 0; // current parsing position in header string
427 
428  debugs(4, 6, HERE << "Testing Header: '" << hdr << "'");
429 
430  while ( strHdrAcptLangGetItem(hdr, lang, 256, pos) ) {
431 
432  /* wildcard uses the configured default language */
433  if (lang[0] == '*' && lang[1] == '\0') {
434  debugs(4, 6, HERE << "Found language '" << lang << "'. Using configured default.");
435  return false;
436  }
437 
438  debugs(4, 6, HERE << "Found language '" << lang << "', testing for available template");
439 
440  if (tryLoadTemplate(lang)) {
441  /* store the language we found for the Content-Language reply header */
442  errLanguage = lang;
443  break;
444  } else if (Config.errorLogMissingLanguages) {
445  debugs(4, DBG_IMPORTANT, "WARNING: Error Pages Missing Language: " << lang);
446  }
447  }
448 #endif
449 
450  return loaded();
451 }
452 
454 static ErrorDynamicPageInfo *
455 errorDynamicPageInfoCreate(int id, const char *page_name)
456 {
458  info->id = id;
459  info->page_name = xstrdup(page_name);
460  info->page_redirect = static_cast<Http::StatusCode>(atoi(page_name));
461 
462  /* WARNING on redirection status:
463  * 2xx are permitted, but not documented officially.
464  * - might be useful for serving static files (PAC etc) in special cases
465  * 3xx require a URL suitable for Location: header.
466  * - the current design does not allow for a Location: URI as well as a local file template
467  * although this possibility is explicitly permitted in the specs.
468  * 4xx-5xx require a local file template.
469  * - sending Location: on these codes with no body is invalid by the specs.
470  * - current result is Squid crashing or XSS problems as dynamic deny_info load random disk files.
471  * - a future redesign of the file loading may result in loading remote objects sent inline as local body.
472  */
473  if (info->page_redirect == Http::scNone)
474  ; // special case okay.
475  else if (info->page_redirect < 200 || info->page_redirect > 599) {
476  // out of range
477  debugs(0, DBG_CRITICAL, "FATAL: status " << info->page_redirect << " is not valid on '" << page_name << "'");
478  self_destruct();
479  } else if ( /* >= 200 && */ info->page_redirect < 300 && strchr(&(page_name[4]), ':')) {
480  // 2xx require a local template file
481  debugs(0, DBG_CRITICAL, "FATAL: status " << info->page_redirect << " requires a template on '" << page_name << "'");
482  self_destruct();
483  } else if (info->page_redirect >= 300 && info->page_redirect <= 399 && !strchr(&(page_name[4]), ':')) {
484  // 3xx require an absolute URL
485  debugs(0, DBG_CRITICAL, "FATAL: status " << info->page_redirect << " requires a URL on '" << page_name << "'");
486  self_destruct();
487  } else if (info->page_redirect >= 400 /* && <= 599 */ && strchr(&(page_name[4]), ':')) {
488  // 4xx/5xx require a local template file
489  debugs(0, DBG_CRITICAL, "FATAL: status " << info->page_redirect << " requires a template on '" << page_name << "'");
490  self_destruct();
491  }
492  // else okay.
493 
494  return info;
495 }
496 
498 static void
500 {
501  assert(info);
502  safe_free(info->page_name);
503  delete info;
504 }
505 
507 static int
508 errorPageId(const char *page_name)
509 {
510  for (int i = 0; i < ERR_MAX; ++i) {
511  if (strcmp(err_type_str[i], page_name) == 0)
512  return i;
513  }
514 
515  for (size_t j = 0; j < ErrorDynamicPages.size(); ++j) {
516  if (strcmp(ErrorDynamicPages[j]->page_name, page_name) == 0)
517  return j + ERR_MAX;
518  }
519 
520  return ERR_NONE;
521 }
522 
523 err_type
524 errorReservePageId(const char *page_name)
525 {
526  ErrorDynamicPageInfo *info;
527  int id = errorPageId(page_name);
528 
529  if (id == ERR_NONE) {
530  info = errorDynamicPageInfoCreate(ERR_MAX + ErrorDynamicPages.size(), page_name);
531  ErrorDynamicPages.push_back(info);
532  id = info->id;
533  }
534 
535  return (err_type)id;
536 }
537 
539 const char *
540 errorPageName(int pageId)
541 {
542  if (pageId >= ERR_NONE && pageId < ERR_MAX) /* common case */
543  return err_type_str[pageId];
544 
545  if (pageId >= ERR_MAX && pageId - ERR_MAX < (ssize_t)ErrorDynamicPages.size())
546  return ErrorDynamicPages[pageId - ERR_MAX]->page_name;
547 
548  return "ERR_UNKNOWN"; /* should not happen */
549 }
550 
551 ErrorState *
553 {
554  const Http::StatusCode status = (request && request->flags.needValidation) ?
556  return new ErrorState(type, status, request.getRaw());
557 }
558 
560  type(t),
561  page_id(t),
562  httpStatus(status),
563  callback(nullptr)
564 {
565  if (page_id >= ERR_MAX && ErrorDynamicPages[page_id - ERR_MAX]->page_redirect != Http::scNone)
566  httpStatus = ErrorDynamicPages[page_id - ERR_MAX]->page_redirect;
567 
568  if (req) {
569  request = req;
570  src_addr = req->client_addr;
571  }
572 }
573 
574 void
576 {
577  assert(entry->mem_obj != NULL);
578  assert (entry->isEmpty());
579  debugs(4, 4, "Creating an error page for entry " << entry <<
580  " with errorstate " << err <<
581  " page id " << err->page_id);
582 
583  if (entry->store_status != STORE_PENDING) {
584  debugs(4, 2, "Skipping error page due to store_status: " << entry->store_status);
585  /*
586  * If the entry is not STORE_PENDING, then no clients
587  * care about it, and we don't need to generate an
588  * error message
589  */
591  assert(entry->mem_obj->nclients == 0);
592  delete err;
593  return;
594  }
595 
596  if (err->page_id == TCP_RESET) {
597  if (err->request) {
598  debugs(4, 2, "RSTing this reply");
599  err->request->flags.resetTcp = true;
600  }
601  }
602 
603  entry->storeErrorResponse(err->BuildHttpReply());
604  delete err;
605 }
606 
607 void
609 {
610  debugs(4, 3, conn << ", err=" << err);
611  assert(Comm::IsConnOpen(conn));
612 
613  HttpReplyPointer rep(err->BuildHttpReply());
614 
615  MemBuf *mb = rep->pack();
616  AsyncCall::Pointer call = commCbCall(78, 5, "errorSendComplete",
617  CommIoCbPtrFun(&errorSendComplete, err));
618  Comm::Write(conn, mb, call);
619  delete mb;
620 }
621 
631 static void
632 errorSendComplete(const Comm::ConnectionPointer &conn, char *, size_t size, Comm::Flag errflag, int, void *data)
633 {
634  ErrorState *err = static_cast<ErrorState *>(data);
635  debugs(4, 3, HERE << conn << ", size=" << size);
636 
637  if (errflag != Comm::ERR_CLOSING) {
638  if (err->callback) {
639  debugs(4, 3, "errorSendComplete: callback");
640  err->callback(conn->fd, err->callback_data, size);
641  } else {
642  debugs(4, 3, "errorSendComplete: comm_close");
643  conn->close();
644  }
645  }
646 
647  delete err;
648 }
649 
651 {
653  safe_free(url);
655  wordlistDestroy(&ftp.server_msg);
656  safe_free(ftp.request);
657  safe_free(ftp.reply);
659 #if USE_ERR_LOCALES
661 #endif
663 #if USE_OPENSSL
664  delete detail;
665 #endif
666 }
667 
668 int
670 {
671  MemBuf str;
672  char ntoabuf[MAX_IPSTRLEN];
673 
674  str.reset();
675  /* email subject line */
676  str.appendf("CacheErrorInfo - %s", errorPageName(type));
677  mb->appendf("?subject=%s", rfc1738_escape_part(str.buf));
678  str.reset();
679  /* email body */
680  str.appendf("CacheHost: %s\r\n", getMyHostname());
681  /* - Err Msgs */
682  str.appendf("ErrPage: %s\r\n", errorPageName(type));
683 
684  if (xerrno) {
685  str.appendf("Err: (%d) %s\r\n", xerrno, strerror(xerrno));
686  } else {
687  str.append("Err: [none]\r\n", 13);
688  }
689 #if USE_AUTH
691  str.appendf("Auth ErrMsg: %s\r\n", auth_user_request->denyMessage());
692 #endif
693  if (dnsError.size() > 0)
694  str.appendf("DNS ErrMsg: %s\r\n", dnsError.termedBuf());
695 
696  /* - TimeStamp */
697  str.appendf("TimeStamp: %s\r\n\r\n", mkrfc1123(squid_curtime));
698 
699  /* - IP stuff */
700  str.appendf("ClientIP: %s\r\n", src_addr.toStr(ntoabuf,MAX_IPSTRLEN));
701 
702  if (request && request->hier.host[0] != '\0') {
703  str.appendf("ServerIP: %s\r\n", request->hier.host);
704  }
705 
706  str.append("\r\n", 2);
707  /* - HTTP stuff */
708  str.append("HTTP Request:\r\n", 15);
709  if (request) {
710  str.appendf(SQUIDSBUFPH " " SQUIDSBUFPH " %s/%d.%d\n",
715  request->header.packInto(&str);
716  }
717 
718  str.append("\r\n", 2);
719  /* - FTP stuff */
720 
721  if (ftp.request) {
722  str.appendf("FTP Request: %s\r\n", ftp.request);
723  str.appendf("FTP Reply: %s\r\n", (ftp.reply? ftp.reply:"[none]"));
724  str.append("FTP Msg: ", 9);
725  wordlistCat(ftp.server_msg, &str);
726  str.append("\r\n", 2);
727  }
728 
729  str.append("\r\n", 2);
730  mb->appendf("&body=%s", rfc1738_escape_part(str.buf));
731  str.clean();
732  return 0;
733 }
734 
736 #define CVT_BUF_SZ 512
737 
738 const char *
739 ErrorState::Convert(char token, bool building_deny_info_url, bool allowRecursion)
740 {
741  static MemBuf mb;
742  const char *p = NULL; /* takes priority over mb if set */
743  int do_quote = 1;
744  int no_urlescape = 0; /* if true then item is NOT to be further URL-encoded */
745  char ntoabuf[MAX_IPSTRLEN];
746 
747  mb.reset();
748 
749  switch (token) {
750 
751  case 'a':
752 #if USE_AUTH
755  if (!p)
756 #endif
757  p = "-";
758  break;
759 
760  case 'A':
761  // TODO: When/if we get ALE here, pass it as well
762  if (const auto addr = FindListeningPortAddress(request.getRaw(), nullptr))
763  mb.appendf("%s", addr->toStr(ntoabuf, MAX_IPSTRLEN));
764  else
765  p = "-";
766  break;
767 
768  case 'b':
769  mb.appendf("%u", getMyPort());
770  break;
771 
772  case 'B':
773  if (building_deny_info_url) break;
774  if (request) {
775  const SBuf &tmp = Ftp::UrlWith2f(request.getRaw());
776  mb.append(tmp.rawContent(), tmp.length());
777  } else
778  p = "[no URL]";
779  break;
780 
781  case 'c':
782  if (building_deny_info_url) break;
783  p = errorPageName(type);
784  break;
785 
786  case 'D':
787  if (!allowRecursion)
788  p = "%D"; // if recursion is not allowed, do not convert
789 #if USE_OPENSSL
790  // currently only SSL error details implemented
791  else if (detail) {
793  const String &errDetail = detail->toString();
794  if (errDetail.size() > 0) {
795  MemBuf *detail_mb = ConvertText(errDetail.termedBuf(), false);
796  mb.append(detail_mb->content(), detail_mb->contentSize());
797  delete detail_mb;
798  do_quote = 0;
799  }
800  }
801 #endif
802  if (!mb.contentSize())
803  mb.append("[No Error Detail]", 17);
804  break;
805 
806  case 'e':
807  mb.appendf("%d", xerrno);
808  break;
809 
810  case 'E':
811  if (xerrno)
812  mb.appendf("(%d) %s", xerrno, strerror(xerrno));
813  else
814  mb.append("[No Error]", 10);
815  break;
816 
817  case 'f':
818  if (building_deny_info_url) break;
819  /* FTP REQUEST LINE */
820  if (ftp.request)
821  p = ftp.request;
822  else
823  p = "nothing";
824  break;
825 
826  case 'F':
827  if (building_deny_info_url) break;
828  /* FTP REPLY LINE */
829  if (ftp.reply)
830  p = ftp.reply;
831  else
832  p = "nothing";
833  break;
834 
835  case 'g':
836  if (building_deny_info_url) break;
837  /* FTP SERVER RESPONSE */
838  if (ftp.listing) {
839  mb.append(ftp.listing->content(), ftp.listing->contentSize());
840  do_quote = 0;
841  } else if (ftp.server_msg) {
842  wordlistCat(ftp.server_msg, &mb);
843  }
844  break;
845 
846  case 'h':
847  mb.appendf("%s", getMyHostname());
848  break;
849 
850  case 'H':
851  if (request) {
852  if (request->hier.host[0] != '\0') // if non-empty string.
853  p = request->hier.host;
854  else
855  p = request->url.host();
856  } else if (!building_deny_info_url)
857  p = "[unknown host]";
858  break;
859 
860  case 'i':
861  mb.appendf("%s", src_addr.toStr(ntoabuf,MAX_IPSTRLEN));
862  break;
863 
864  case 'I':
865  if (request && request->hier.tcpServer)
867  else if (!building_deny_info_url)
868  p = "[unknown]";
869  break;
870 
871  case 'l':
872  if (building_deny_info_url) break;
873  mb.append(error_stylesheet.content(), error_stylesheet.contentSize());
874  do_quote = 0;
875  break;
876 
877  case 'L':
878  if (building_deny_info_url) break;
879  if (Config.errHtmlText) {
880  mb.appendf("%s", Config.errHtmlText);
881  do_quote = 0;
882  } else
883  p = "[not available]";
884  break;
885 
886  case 'm':
887  if (building_deny_info_url) break;
888 #if USE_AUTH
890  p = auth_user_request->denyMessage("[not available]");
891  else
892  p = "[not available]";
893 #else
894  p = "-";
895 #endif
896  break;
897 
898  case 'M':
899  if (request) {
900  const SBuf &m = request->method.image();
901  mb.append(m.rawContent(), m.length());
902  } else if (!building_deny_info_url)
903  p = "[unknown method]";
904  break;
905 
906  case 'O':
907  if (!building_deny_info_url)
908  do_quote = 0;
909  case 'o':
911  if (!p && !building_deny_info_url)
912  p = "[not available]";
913  break;
914 
915  case 'p':
916  if (request) {
917  mb.appendf("%u", request->url.port());
918  } else if (!building_deny_info_url) {
919  p = "[unknown port]";
920  }
921  break;
922 
923  case 'P':
924  if (request) {
925  const SBuf &m = request->url.getScheme().image();
926  mb.append(m.rawContent(), m.length());
927  } else if (!building_deny_info_url) {
928  p = "[unknown protocol]";
929  }
930  break;
931 
932  case 'R':
933  if (building_deny_info_url) {
934  if (request != NULL) {
935  const SBuf &tmp = request->url.path();
936  mb.append(tmp.rawContent(), tmp.length());
937  no_urlescape = 1;
938  } else
939  p = "[no request]";
940  break;
941  }
942  if (request) {
943  mb.appendf(SQUIDSBUFPH " " SQUIDSBUFPH " %s/%d.%d\n",
948  request->header.packInto(&mb, true); //hide authorization data
949  } else if (request_hdrs) {
950  p = request_hdrs;
951  } else {
952  p = "[no request]";
953  }
954  break;
955 
956  case 's':
957  /* for backward compat we make %s show the full URL. Drop this in some future release. */
958  if (building_deny_info_url) {
959  if (request) {
960  const SBuf &tmp = request->effectiveRequestUri();
961  mb.append(tmp.rawContent(), tmp.length());
962  } else
963  p = url;
964  debugs(0, DBG_CRITICAL, "WARNING: deny_info now accepts coded tags. Use %u to get the full URL instead of %s");
965  } else
967  break;
968 
969  case 'S':
970  if (building_deny_info_url) {
972  break;
973  }
974  /* signature may contain %-escapes, recursion */
975  if (page_id != ERR_SQUID_SIGNATURE) {
976  const int saved_id = page_id;
978  MemBuf *sign_mb = BuildContent();
979  mb.append(sign_mb->content(), sign_mb->contentSize());
980  sign_mb->clean();
981  delete sign_mb;
982  page_id = saved_id;
983  do_quote = 0;
984  } else {
985  /* wow, somebody put %S into ERR_SIGNATURE, stop recursion */
986  p = "[%S]";
987  }
988  break;
989 
990  case 't':
992  break;
993 
994  case 'T':
995  mb.appendf("%s", mkrfc1123(squid_curtime));
996  break;
997 
998  case 'U':
999  /* Using the fake-https version of absolute-URI so error pages see https:// */
1000  /* even when the url-path cannot be shown as more than '*' */
1001  if (request)
1003  else if (url)
1004  p = url;
1005  else if (!building_deny_info_url)
1006  p = "[no URL]";
1007  break;
1008 
1009  case 'u':
1010  if (request) {
1011  const SBuf &tmp = request->effectiveRequestUri();
1012  mb.append(tmp.rawContent(), tmp.length());
1013  } else if (url)
1014  p = url;
1015  else if (!building_deny_info_url)
1016  p = "[no URL]";
1017  break;
1018 
1019  case 'w':
1020  if (Config.adminEmail)
1021  mb.appendf("%s", Config.adminEmail);
1022  else if (!building_deny_info_url)
1023  p = "[unknown]";
1024  break;
1025 
1026  case 'W':
1027  if (building_deny_info_url) break;
1029  Dump(&mb);
1030  no_urlescape = 1;
1031  break;
1032 
1033  case 'x':
1034 #if USE_OPENSSL
1035  if (detail)
1036  mb.appendf("%s", detail->errorName());
1037  else
1038 #endif
1039  if (!building_deny_info_url)
1040  p = "[Unknown Error Code]";
1041  break;
1042 
1043  case 'z':
1044  if (building_deny_info_url) break;
1045  if (dnsError.size() > 0)
1046  p = dnsError.termedBuf();
1047  else if (ftp.cwd_msg)
1048  p = ftp.cwd_msg;
1049  else
1050  p = "[unknown]";
1051  break;
1052 
1053  case 'Z':
1054  if (building_deny_info_url) break;
1055  if (err_msg)
1056  p = err_msg;
1057  else
1058  p = "[unknown]";
1059  break;
1060 
1061  case '%':
1062  p = "%";
1063  break;
1064 
1065  default:
1066  mb.appendf("%%%c", token);
1067  do_quote = 0;
1068  break;
1069  }
1070 
1071  if (!p)
1072  p = mb.buf; /* do not use mb after this assignment! */
1073 
1074  assert(p);
1075 
1076  debugs(4, 3, "errorConvert: %%" << token << " --> '" << p << "'" );
1077 
1078  if (do_quote)
1079  p = html_quote(p);
1080 
1081  if (building_deny_info_url && !no_urlescape)
1082  p = rfc1738_escape_part(p);
1083 
1084  return p;
1085 }
1086 
1087 void
1088 ErrorState::DenyInfoLocation(const char *name, HttpRequest *, MemBuf &result)
1089 {
1090  char const *m = name;
1091  char const *p = m;
1092  char const *t;
1093 
1094  if (m[0] == '3')
1095  m += 4; // skip "3xx:"
1096 
1097  while ((p = strchr(m, '%'))) {
1098  result.append(m, p - m); /* copy */
1099  t = Convert(*++p, true, true); /* convert */
1100  result.appendf("%s", t); /* copy */
1101  m = p + 1; /* advance */
1102  }
1103 
1104  if (*m)
1105  result.appendf("%s", m); /* copy tail */
1106 
1107  assert((size_t)result.contentSize() == strlen(result.content()));
1108 }
1109 
1110 HttpReply *
1112 {
1113  HttpReply *rep = new HttpReply;
1114  const char *name = errorPageName(page_id);
1115  /* no LMT for error pages; error pages expire immediately */
1116 
1117  if (name[0] == '3' || (name[0] != '2' && name[0] != '4' && name[0] != '5' && strchr(name, ':'))) {
1118  /* Redirection */
1120  // Use configured 3xx reply status if set.
1121  if (name[0] == '3')
1122  status = httpStatus;
1123  else {
1124  // Use 307 for HTTP/1.1 non-GET/HEAD requests.
1126  status = Http::scTemporaryRedirect;
1127  }
1128 
1129  rep->setHeaders(status, NULL, "text/html;charset=utf-8", 0, 0, -1);
1130 
1131  if (request) {
1132  MemBuf redirect_location;
1133  redirect_location.init();
1134  DenyInfoLocation(name, request.getRaw(), redirect_location);
1135  httpHeaderPutStrf(&rep->header, Http::HdrType::LOCATION, "%s", redirect_location.content() );
1136  }
1137 
1138  httpHeaderPutStrf(&rep->header, Http::HdrType::X_SQUID_ERROR, "%d %s", httpStatus, "Access Denied");
1139  } else {
1140  MemBuf *content = BuildContent();
1141  rep->setHeaders(httpStatus, NULL, "text/html;charset=utf-8", content->contentSize(), 0, -1);
1142  /*
1143  * include some information for downstream caches. Implicit
1144  * replaceable content. This isn't quite sufficient. xerrno is not
1145  * necessarily meaningful to another system, so we really should
1146  * expand it. Additionally, we should identify ourselves. Someone
1147  * might want to know. Someone _will_ want to know OTOH, the first
1148  * X-CACHE-MISS entry should tell us who.
1149  */
1151 
1152 #if USE_ERR_LOCALES
1153  /*
1154  * If error page auto-negotiate is enabled in any way, send the Vary.
1155  * RFC 2616 section 13.6 and 14.44 says MAY and SHOULD do this.
1156  * We have even better reasons though:
1157  * see http://wiki.squid-cache.org/KnowledgeBase/VaryNotCaching
1158  */
1159  if (!Config.errorDirectory) {
1160  /* We 'negotiated' this ONLY from the Accept-Language. */
1162  rep->header.putStr(Http::HdrType::VARY, "Accept-Language");
1163  }
1164 
1165  /* add the Content-Language header according to RFC section 14.12 */
1166  if (err_language) {
1168  } else
1169 #endif /* USE_ERROR_LOCALES */
1170  {
1171  /* default templates are in English */
1172  /* language is known unless error_directory override used */
1173  if (!Config.errorDirectory)
1175  }
1176 
1177  rep->body.setMb(content);
1178  /* do not memBufClean() or delete the content, it was absorbed by httpBody */
1179  }
1180 
1181  // Make sure error codes get back to the client side for logging and
1182  // error tracking.
1183  if (request) {
1184  int edc = ERR_DETAIL_NONE; // error detail code
1185 #if USE_OPENSSL
1186  if (detail)
1187  edc = detail->errorNo();
1188  else
1189 #endif
1190  if (detailCode)
1191  edc = detailCode;
1192  else
1193  edc = xerrno;
1194  request->detailError(type, edc);
1195  }
1196 
1197  return rep;
1198 }
1199 
1200 MemBuf *
1202 {
1203  const char *m = NULL;
1204 
1205  assert(page_id > ERR_NONE && page_id < error_page_count);
1206 
1207 #if USE_ERR_LOCALES
1208  ErrorPageFile *localeTmpl = NULL;
1209 
1214  if (!Config.errorDirectory && page_id < ERR_MAX) {
1217 
1218  localeTmpl = new ErrorPageFile(err_type_str[page_id], static_cast<err_type>(page_id));
1219  if (localeTmpl->loadFor(request.getRaw())) {
1220  m = localeTmpl->text();
1221  assert(localeTmpl->language());
1222  err_language = xstrdup(localeTmpl->language());
1223  }
1224  }
1225 #endif /* USE_ERR_LOCALES */
1226 
1231  if (!m) {
1232  m = error_text[page_id];
1233 #if USE_ERR_LOCALES
1234  if (!Config.errorDirectory)
1236 #endif
1237  debugs(4, 2, HERE << "No existing error page language negotiated for " << errorPageName(page_id) << ". Using default error file.");
1238  }
1239 
1240  MemBuf *result = ConvertText(m, true);
1241 #if USE_ERR_LOCALES
1242  if (localeTmpl)
1243  delete localeTmpl;
1244 #endif
1245  return result;
1246 }
1247 
1248 MemBuf *ErrorState::ConvertText(const char *text, bool allowRecursion)
1249 {
1250  MemBuf *content = new MemBuf;
1251  const char *p;
1252  const char *m = text;
1253  assert(m);
1254  content->init();
1255 
1256  while ((p = strchr(m, '%'))) {
1257  content->append(m, p - m); /* copy */
1258  const char *t = Convert(*++p, false, allowRecursion); /* convert */
1259  content->appendf("%s", t); /* copy */
1260  m = p + 1; /* advance */
1261  }
1262 
1263  if (*m)
1264  content->appendf("%s", m); /* copy tail */
1265 
1266  content->terminate();
1267 
1268  assert((size_t)content->contentSize() == strlen(content->content()));
1269 
1270  return content;
1271 }
1272 
int delById(Http::HdrType id)
Definition: HttpHeader.cc:681
HierarchyLogEntry hier
Definition: HttpRequest.h:149
AnyP::ProtocolVersion ProtocolVersion(unsigned int aMajor, unsigned int aMinor)
HTTP version label information.
MemBuf textBuf
A buffer to store the error page.
Definition: errorpage.cc:139
#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
Http::StatusCode page_redirect
Definition: errorpage.cc:66
int emailErrData
Definition: SquidConfig.h:323
const char * mkrfc1123(time_t)
Definition: rfc1123.c:202
bool loaded() const
return true if the data loaded from disk without any problem
Definition: errorpage.h:250
virtual void append(const char *c, int sz)
Definition: MemBuf.cc:216
static void errorDynamicPageInfoDestroy(ErrorDynamicPageInfo *info)
Definition: errorpage.cc:499
int type
Definition: errorpage.cc:78
void path(const char *p)
Definition: Uri.h:86
Definition: SBuf.h:86
SBuf image() const
Definition: UriScheme.h:50
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:547
void self_destruct(void)
Definition: cache_cf.cc:257
HttpRequestMethod method
Definition: HttpRequest.h:106
String errLanguage
The error language of the template.
Definition: errorpage.h:291
struct _request * request(char *urlin)
Definition: tcp-banger2.c:291
char * adminEmail
Definition: SquidConfig.h:186
int i
Definition: membanger.c:49
#define xstrdup
int page_id
Definition: errorpage.h:141
#define MAXPATHLEN
Definition: stdio.h:62
ERCB * callback
Definition: errorpage.h:156
#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:148
int file_open(const char *path, int mode)
Definition: fs_io.cc:46
MemBuf * ConvertText(const char *text, bool allowRecursion)
Definition: errorpage.cc:1248
static std::vector< ErrorDynamicPageInfo * > ErrorDynamicPages
Definition: errorpage.cc:100
static struct @59 error_hard_text[]
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:145
char * p
Definition: membanger.c:43
char * err_msg
Definition: errorpage.h:168
int conn
the current server connection FD
Definition: Transport.cc:26
static MemBuf error_stylesheet
Definition: errorpage.cc:114
const char * getMyHostname(void)
Definition: tools.cc:412
void * callback_data
Definition: errorpage.h:157
size_type size() const
Definition: SquidString.h:72
bool wasLoaded
True if the template data read from disk without any problem.
Definition: errorpage.h:290
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:608
int detailCode
Definition: errorpage.h:175
bool silent
Whether to print error messages on cache.log file or not. It is user defined.
Definition: errorpage.h:277
err_type templateCode
The internal code for this template.
Definition: errorpage.h:293
void init(mb_size_t szInit, mb_size_t szMax)
Definition: MemBuf.cc:96
bool tryLoadTemplate(const char *lang)
Definition: errorpage.cc:294
char * errorStylesheet
Definition: SquidConfig.h:433
void httpHeaderPutStrf(HttpHeader *hdr, Http::HdrType id, const char *fmt,...)
String extacl_message
Definition: HttpRequest.h:177
char * errorDirectory
Definition: SquidConfig.h:428
void errorClean(void)
Definition: errorpage.cc:215
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
size_type length() const
Returns the number of bytes stored in SBuf.
Definition: SBuf.h:404
StatusCode
Definition: StatusCode.h:20
bool isEmpty() const
Definition: Store.h:60
MemBuf * BuildContent(void)
Definition: errorpage.cc:1201
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
static ErrorDynamicPageInfo * errorDynamicPageInfoCreate(int id, const char *page_name)
Definition: errorpage.cc:455
err_type & operator++(err_type &anErr)
Definition: errorpage.cc:143
void reset()
Definition: MemBuf.cc:132
Ip::Address client_addr
Definition: HttpRequest.h:141
#define DEFAULT_SQUID_ERROR_DIR
Definition: errorpage.cc:54
String substr(size_type from, size_type to) const
Definition: String.cc:223
char const * termedBuf() const
Definition: SquidString.h:91
ErrorState()=delete
String getList(Http::HdrType id) const
Definition: HttpHeader.cc:828
const char * errorPageName(int pageId)
error ID to string
Definition: errorpage.cc:540
const SBuf & effectiveRequestUri() const
RFC 7230 section 5.5 - Effective Request URI.
Definition: HttpRequest.cc:687
const SBuf & UrlWith2f(HttpRequest *)
Definition: FtpGateway.cc:2642
AnyP::Uri url
the request URI
Definition: HttpRequest.h:107
void * addr
Definition: membanger.c:46
TemplateFile(const char *name, const err_type code)
Definition: errorpage.cc:251
AnyP::UriScheme const & getScheme() const
Definition: Uri.h:67
const String & toString() const
An error detail string to embed in squid error pages.
Definition: ErrorDetail.cc:634
Http::StatusCode httpStatus
Definition: errorpage.h:143
uint16_t flags
Definition: Store.h:208
err_type errorReservePageId(const char *page_name)
Definition: errorpage.cc:524
void wordlistCat(const wordlist *w, MemBuf *mb)
Definition: wordlist.cc:35
void host(const char *src)
Definition: Uri.cc:47
static const char * errorFindHardText(err_type type)
Definition: errorpage.cc:240
MemObject * mem_obj
Definition: Store.h:197
static int errorPageId(const char *page_name)
Definition: errorpage.cc:508
const char * errorName() const
The error name to embed in squid error pages.
Definition: ErrorDetail.h:51
struct ErrorState::@60 ftp
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
struct SquidConfig::@112 onoff
char const * denyMessage(char const *const default_message=NULL) const
Definition: UserRequest.cc:127
mb_size_t contentSize() const
available data size
Definition: MemBuf.h:47
Flag
Definition: Flag.h:15
bool loadDefault()
Definition: errorpage.cc:257
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
static ErrorState * NewForwarding(err_type, HttpRequestPointer &)
Creates a general request forwarding error with the right http_status.
Definition: errorpage.cc:552
char * buf
Definition: MemBuf.h:134
ErrorPageFile(const char *name, const err_type code)
Definition: errorpage.cc:126
RequestFlags flags
Definition: HttpRequest.h:133
const SBuf & image() const
void useRequest(HttpRequest *aRequest)
Definition: ErrorDetail.h:49
store_status_t store_status
Definition: Store.h:220
#define MYNAME
Definition: Debug.h:166
const char * text()
The template text data read from disk.
Definition: errorpage.cc:129
err_type type
Definition: errorpage.h:140
Ip::Address remote
Definition: Connection.h:138
void putStr(Http::HdrType id, const char *str)
Definition: HttpHeader.cc:1072
#define FD_READ_METHOD(fd, buf, len)
Definition: fde.h:161
String dnsError
DNS lookup error message.
Definition: errorpage.h:151
HttpBody body
Definition: HttpReply.h:62
static IOCB errorSendComplete
Definition: errorpage.cc:119
const char * external_acl_message
const Ip::Address * FindListeningPortAddress(const HttpRequest *callerRequest, const AccessLogEntry *ale)
Definition: HttpRequest.cc:785
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:456
const char * FormatHttpd(time_t t)
Definition: stub_time.cc:25
char const * username() const
Definition: UserRequest.cc:32
HttpRequestPointer request
Definition: errorpage.h:147
static char ** error_text
Definition: errorpage.cc:108
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
Definition: Packable.h:61
void setMb(MemBuf *)
Definition: HttpBody.cc:31
Definition: MemBuf.h:23
bool strHdrAcptLangGetItem(const String &hdr, char *lang, int langLen, size_t &pos)
Definition: errorpage.cc:360
Auth::UserRequest::Pointer auth_user_request
Definition: HttpRequest.h:119
char * errorDefaultLanguage
Definition: SquidConfig.h:430
void errorAppendEntry(StoreEntry *entry, ErrorState *err)
Definition: errorpage.cc:575
void packInto(Packable *p, bool mask_sensitive_info=false) const
Definition: HttpHeader.cc:554
Security::ErrorCode errorNo() const
The error no.
Definition: ErrorDetail.h:53
int Dump(MemBuf *mb)
Definition: errorpage.cc:669
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
char * errHtmlText
Definition: SquidConfig.h:224
char * request_hdrs
Definition: errorpage.h:167
bool loadFor(const HttpRequest *request)
Definition: errorpage.cc:414
HttpReply * BuildHttpReply(void)
Definition: errorpage.cc:1111
CharacterSet operator-(CharacterSet lhs, const CharacterSet &rhs)
void storeErrorResponse(HttpReply *reply)
Store a prepared error response. MemObject locks the reply object.
Definition: store.cc:1765
#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:275
const char * Convert(char token, bool building_deny_info_url, bool allowRecursion)
Definition: errorpage.cc:739
static const int error_hard_text_count
Definition: errorpage.cc:105
void errorInitialize(void)
Definition: errorpage.cc:157
unsigned int minor
minor version number
int xerrno
Definition: errorpage.h:149
#define rfc1738_escape_part(x)
Definition: rfc1738.h:55
int errorLogMissingLanguages
Definition: SquidConfig.h:431
virtual bool parse(const char *buf, int len, bool)
stores the data read from disk to a local buffer
Definition: errorpage.cc:133
virtual bool parse(const char *buf, int len, bool eof)=0
Used to parse (if parsing required) the template data .
char * toStr(char *buf, const unsigned int blen, int force=AF_UNSPEC) const
Definition: Address.cc:795
Ip::Address src_addr
Definition: errorpage.h:154
#define SQUIDSBUFPH
Definition: SBuf.h:31
static int error_page_count
Definition: errorpage.cc:111
char * redirect_url
Definition: errorpage.h:155
ProtocolType protocol
which protocol this version is for
const char * rawContent() const
Definition: SBuf.cc:519
Ssl::ErrorDetail * detail
Definition: errorpage.h:171
void file_close(int fd)
Definition: fs_io.cc:76
#define SQUIDSBUFPRINT(s)
Definition: SBuf.h:32
char const * visible_appname_string
#define xtolower(x)
Definition: xis.h:19
#define EBIT_TEST(flag, bit)
Definition: defines.h:107
C * getRaw() const
Definition: RefCount.h:74
class SquidConfig Config
Definition: SquidConfig.cc:12
#define NULL
Definition: types.h:166
const char * text
Definition: errorpage.cc:79
bool needValidation
Definition: RequestFlags.h:48
void DenyInfoLocation(const char *name, HttpRequest *request, MemBuf &result)
Definition: errorpage.cc:1088
int size
Definition: ModDevPoll.cc:77
String templateName
The name of the template.
Definition: errorpage.h:292
#define false
Definition: GnuRegex.c:233
bool loadFromFile(const char *path)
Definition: errorpage.cc:319
void Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE *free_func)
Definition: Write.cc:35
err_type
Definition: err_type.h:12
char * err_language
Definition: errorpage.h:142
void terminate()
Definition: MemBuf.cc:250

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors