ErrorDetailManager.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2022 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 #include "squid.h"
10 #include "base/Raw.h"
11 #include "ErrorDetail.h"
12 #include "ErrorDetailManager.h"
13 #include "errorpage.h"
15 #include "mime_header.h"
16 
18 {
20 }
21 
23 {
25 }
26 
27 namespace Ssl
28 {
29 
32 {
33 public:
34  explicit ErrorDetailFile(ErrorDetailsList::Pointer const details): TemplateFile("error-details.txt", ERR_NONE) {
35  theDetails = details;
36  }
37 
38 private:
40  virtual bool parse() override;
41 };
42 }// namespace Ssl
43 
44 /******************/
45 bool
47 {
48  const ErrorDetails::const_iterator it = theList.find(value);
49  if (it != theList.end()) {
50  entry.error_no = it->second.error_no;
51  entry.name = it->second.name;
52  entry.detail = it->second.detail;
53  entry.descr = it->second.descr;
54  return true;
55  }
56  return false;
57 }
58 
59 const char *
61 {
62  const ErrorDetails::const_iterator it = theList.find(value);
63  if (it != theList.end()) {
64  return it->second.descr.termedBuf();
65  }
66 
67  return NULL;
68 }
69 
70 const char *
72 {
73  const ErrorDetails::const_iterator it = theList.find(value);
74  if (it != theList.end()) {
75  return it->second.detail.termedBuf();
76  }
77 
78  return NULL;
79 }
80 
82 
84 {
85  if (!TheDetailsManager)
86  TheDetailsManager = new Ssl::ErrorDetailsManager;
87 
88  assert(TheDetailsManager);
89  return *TheDetailsManager;
90 }
91 
93 {
94  delete TheDetailsManager;
95  TheDetailsManager = NULL;
96 }
97 
99 {
100  theDefaultErrorDetails = new ErrorDetailsList();
101  ErrorDetailFile detailTmpl(theDefaultErrorDetails);
102  detailTmpl.loadDefault();
103 }
104 
106 {
107  Cache::iterator it;
108  it = cache.find(lang);
109  if (it != cache.end()) {
110  debugs(83, 8, "Found template details in cache for language: " << lang);
111  return it->second;
112  }
113 
114  return NULL;
115 }
116 
118 {
119  const char *lang = errorDetails->errLanguage.termedBuf();
120  assert(lang);
121  if (cache.find(lang) == cache.end())
122  cache[lang] = errorDetails;
123 }
124 
125 bool
127 {
128 #if USE_ERR_LOCALES
129  String hdr;
130  if (request != NULL && request->header.getList(Http::HdrType::ACCEPT_LANGUAGE, &hdr)) {
131  ErrorDetailsList::Pointer errDetails = NULL;
132  //Try to retrieve from cache
133  size_t pos = 0;
134  char lang[256];
135  // Get the first ellement of the Accept-Language header
136  strHdrAcptLangGetItem(hdr, lang, 256, pos);
137  errDetails = getCachedDetails(lang); // search in cache
138 
139  if (!errDetails) { // Else try to load from disk
140  debugs(83, 8, "Creating new ErrDetailList to read from disk");
141  errDetails = new ErrorDetailsList();
142  ErrorDetailFile detailTmpl(errDetails);
143  if (detailTmpl.loadFor(request.getRaw())) {
144  if (detailTmpl.language()) {
145  debugs(83, 8, "Found details on disk for language " << detailTmpl.language());
146  errDetails->errLanguage = detailTmpl.language();
147  cacheDetails(errDetails);
148  }
149  }
150  }
151 
152  if (errDetails != NULL && errDetails->getRecord(value, entry))
153  return true;
154  }
155 #else
156  (void)request;
157 #endif
158 
159  // else try the default
160  if (theDefaultErrorDetails->getRecord(value, entry)) {
161  debugs(83, 8, "Found default details record for error: " << GetErrorName(value));
162  return true;
163  }
164 
165  return false;
166 }
167 
168 const char *
170 {
171  return theDefaultErrorDetails->getErrorDescr(value);
172 }
173 
174 const char *
176 {
177  return theDefaultErrorDetails->getErrorDetail(value);
178 }
179 
180 // Use HttpHeaders parser to parse error-details.txt files
182 {
183 public:
185 };
186 
187 //The end of an error detrail entry is a double "\n". The headersEnd
188 // functions can detect it
189 inline size_t detailEntryEnd(const char *s, size_t len) {return headersEnd(s, len);}
190 
191 bool
193 {
194  if (!theDetails)
195  return false;
196 
197  auto buf = template_;
198  buf.append("\n\n"); // ensure detailEntryEnd() finds the last entry
199 
200  while (const auto size = detailEntryEnd(buf.rawContent(), buf.length())) {
201  auto *s = buf.c_str();
202  const auto e = s + size;
203 
204  //ignore spaces, new lines and comment lines (starting with #) at the beginning
205  for (; (*s == '\n' || *s == ' ' || *s == '\t' || *s == '#') && s < e; ++s) {
206  if (*s == '#')
207  while (s<e && *s != '\n')
208  ++s; // skip until the end of line
209  }
210 
211  if ( s != e) {
212  DetailEntryParser parser;
213  Http::ContentLengthInterpreter interpreter;
214  // no applyStatusCodeRules() -- error templates lack HTTP status code
215  if (!parser.parse(s, e - s, interpreter)) {
216  debugs(83, DBG_IMPORTANT, "WARNING: parse error on:" << s);
217  return false;
218  }
219 
220  const String errorName = parser.getByName("name");
221  if (!errorName.size()) {
222  debugs(83, DBG_IMPORTANT, "WARNING: invalid or no error detail name on:" << s);
223  return false;
224  }
225 
226  Security::ErrorCode ssl_error = Ssl::GetErrorCode(errorName.termedBuf());
227  if (ssl_error != SSL_ERROR_NONE) {
228 
229  if (theDetails->getErrorDetail(ssl_error)) {
230  debugs(83, DBG_IMPORTANT, "WARNING: duplicate entry: " << errorName);
231  return false;
232  }
233 
234  ErrorDetailEntry &entry = theDetails->theList[ssl_error];
235  entry.error_no = ssl_error;
236  entry.name = errorName;
237  String tmp = parser.getByName("detail");
238  const int detailsParseOk = httpHeaderParseQuotedString(tmp.termedBuf(), tmp.size(), &entry.detail);
239  tmp = parser.getByName("descr");
240  const int descrParseOk = httpHeaderParseQuotedString(tmp.termedBuf(), tmp.size(), &entry.descr);
241  // TODO: Validate "descr" and "detail" field values.
242 
243  if (!detailsParseOk || !descrParseOk) {
244  debugs(83, DBG_IMPORTANT, "WARNING: missing important field for detail error: " << errorName);
245  return false;
246  }
247 
248  } else if (!Ssl::ErrorIsOptional(errorName.termedBuf())) {
249  debugs(83, DBG_IMPORTANT, "WARNING: invalid error detail name: " << errorName);
250  return false;
251  }
252 
253  }// else {only spaces and black lines; just ignore}
254 
255  buf.consume(size);
256  }
257  debugs(83, 9, Raw("unparsed data", buf.rawContent(), buf.length()));
258  return true;
259 }
260 
size_t detailEntryEnd(const char *s, size_t len)
int ErrorCode
Squid-defined error code (<0), an error code returned by X.509 API, or zero.
Definition: forward.h:110
ErrorDetails theList
The list of error details entries.
const char * getErrorDetail(Security::ErrorCode value)
an error details for an error if exist in list.
String descr
short error description (for use in debug messages or error pages)
Security::ErrorCode error_no
TLS error;.
virtual bool parse() override
post-process the loaded template
const char * GetErrorName(const Security::ErrorCode code, const bool prefixRawCode=false)
Definition: ErrorDetail.h:36
ErrorDetailsList::Pointer theDetails
int parse(const char *header_start, size_t len, Http::ContentLengthInterpreter &interpreter)
Definition: HttpHeader.cc:378
@ ERR_NONE
Definition: forward.h:15
ErrorDetailFile(ErrorDetailsList::Pointer const details)
static ErrorDetailsManager * TheDetailsManager
An instance of ErrorDetailsManager to be used by squid (ssl/ErrorDetails.*)
void errorDetailInitialize()
Definition: Raw.h:21
void loadDefault()
Definition: errorpage.cc:357
int size
Definition: ModDevPoll.cc:75
#define NULL
Definition: types.h:166
String name
a name for the error
void errorDetailClean()
@ ACCEPT_LANGUAGE
const char * getDefaultErrorDescr(Security::ErrorCode value)
the default error description for a given error
int httpHeaderParseQuotedString(const char *start, const int len, String *val)
bool strHdrAcptLangGetItem(const String &hdr, char *lang, int langLen, size_t &pos)
Definition: errorpage.cc:466
bool getErrorDetail(Security::ErrorCode value, const HttpRequest::Pointer &request, ErrorDetailEntry &entry)
Definition: Xaction.cc:48
String detail
for error page D macro expansion; may contain macros
#define assert(EX)
Definition: assert.h:19
char const * termedBuf() const
Definition: SquidString.h:92
const char * getErrorDescr(Security::ErrorCode value)
an error description for an error if exist in list.
Security::ErrorCode GetErrorCode(const char *name)
The Security::ErrorCode code of the error described by "name".
Definition: ErrorDetail.h:28
static void Shutdown()
reset the ErrorDetailsManager instance
@ hoErrorDetail
Definition: HttpHeader.h:39
static ErrorDetailsManager & GetInstance()
Instance class.
const char * language()
The language used for the template.
Definition: errorpage.h:312
String getByName(const SBuf &name) const
Definition: HttpHeader.cc:902
bool getRecord(Security::ErrorCode value, ErrorDetailEntry &entry)
manages error detail templates
ErrorDetailsList::Pointer getCachedDetails(const char *lang)
Return cached error details list for a given language if exist.
size_type size() const
Definition: SquidString.h:73
bool loadFor(const HttpRequest *request)
Definition: errorpage.cc:520
#define DBG_IMPORTANT
Definition: Stream.h:41
void cacheDetails(ErrorDetailsList::Pointer &errorDetails)
cache the given error details list.
const char * getDefaultErrorDetail(Security::ErrorCode value)
the default error details for a given error
String errLanguage
The language of the error-details.txt template, if any.
bool ErrorIsOptional(const char *name)
Definition: ErrorDetail.cc:148
size_t headersEnd(const char *mime, size_t l, bool &containsObsFold)
Definition: mime_header.cc:17
struct _request * request(char *urlin)
Definition: tcp-banger2.c:291
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:196

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors