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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors