ErrorDetailManager.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 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
27namespace Ssl
28{
29
32{
33public:
34 explicit ErrorDetailFile(ErrorDetailsList::Pointer const details): TemplateFile("error-details.txt", ERR_NONE) {
35 theDetails = details;
36 }
37
38private:
40 bool parse() override;
41};
42}// namespace Ssl
43
44/******************/
45bool
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
59const 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 nullptr;
68}
69
70const 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 nullptr;
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 = nullptr;
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 nullptr;
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
125bool
127{
128#if USE_ERR_LOCALES
129 String hdr;
130 if (request != nullptr && request->header.getList(Http::HdrType::ACCEPT_LANGUAGE, &hdr)) {
131 ErrorDetailsList::Pointer errDetails = nullptr;
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 != nullptr && 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
168const char *
170{
171 return theDefaultErrorDetails->getErrorDescr(value);
172}
173
174const char *
176{
177 return theDefaultErrorDetails->getErrorDetail(value);
178}
179
180// Use HttpHeaders parser to parse error-details.txt files
182{
183public:
185};
186
187//The end of an error detrail entry is a double "\n". The headersEnd
188// functions can detect it
189inline size_t detailEntryEnd(const char *s, size_t len) {return headersEnd(s, len);}
190
191bool
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;
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)
@ hoErrorDetail
Definition: HttpHeader.h:39
int httpHeaderParseQuotedString(const char *start, const int len, String *val)
int size
Definition: ModDevPoll.cc:75
#define assert(EX)
Definition: assert.h:17
int parse(const char *header_start, size_t len, Http::ContentLengthInterpreter &interpreter)
Definition: HttpHeader.cc:356
String getList(Http::HdrType id) const
Definition: HttpHeader.cc:820
String getByName(const SBuf &name) const
Definition: HttpHeader.cc:880
HttpHeader header
Definition: Message.h:74
Definition: Raw.h:21
C * getRaw() const
Definition: RefCount.h:80
String descr
short error description (for use in debug messages or error pages)
String detail
for error page D macro expansion; may contain macros
Security::ErrorCode error_no
TLS error;.
String name
a name for the error
manages error detail templates
ErrorDetailFile(ErrorDetailsList::Pointer const details)
ErrorDetailsList::Pointer theDetails
bool parse() override
post-process the loaded template
String errLanguage
The language of the error-details.txt template, if any.
const char * getErrorDescr(Security::ErrorCode value)
an error description for an error if exist in list.
const char * getErrorDetail(Security::ErrorCode value)
an error details for an error if exist in list.
bool getRecord(Security::ErrorCode value, ErrorDetailEntry &entry)
ErrorDetails theList
The list of error details entries.
const char * getDefaultErrorDescr(Security::ErrorCode value)
the default error description for a given error
static void Shutdown()
reset the ErrorDetailsManager instance
void cacheDetails(ErrorDetailsList::Pointer &errorDetails)
cache the given error details list.
static ErrorDetailsManager * TheDetailsManager
An instance of ErrorDetailsManager to be used by squid (ssl/ErrorDetails.*)
static ErrorDetailsManager & GetInstance()
Instance class.
const char * getDefaultErrorDetail(Security::ErrorCode value)
the default error details for a given error
ErrorDetailsList::Pointer getCachedDetails(const char *lang)
Return cached error details list for a given language if exist.
bool getErrorDetail(Security::ErrorCode value, const HttpRequest::Pointer &request, ErrorDetailEntry &entry)
char const * termedBuf() const
Definition: SquidString.h:92
size_type size() const
Definition: SquidString.h:73
void loadDefault()
Definition: errorpage.cc:356
const char * language()
The language used for the template.
Definition: errorpage.h:313
bool loadFor(const HttpRequest *request)
Definition: errorpage.cc:519
#define DBG_IMPORTANT
Definition: Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:194
@ ERR_NONE
Definition: forward.h:15
bool strHdrAcptLangGetItem(const String &hdr, char *lang, int langLen, size_t &pos)
Definition: errorpage.cc:465
size_t headersEnd(const char *mime, size_t l, bool &containsObsFold)
Definition: mime_header.cc:17
@ ACCEPT_LANGUAGE
int ErrorCode
Squid-defined error code (<0), an error code returned by X.509 API, or zero.
Definition: forward.h:128
Definition: Xaction.cc:40
void errorDetailClean()
bool ErrorIsOptional(const char *name)
Definition: ErrorDetail.cc:148
Security::ErrorCode GetErrorCode(const char *name)
The Security::ErrorCode code of the error described by "name".
Definition: ErrorDetail.h:28
void errorDetailInitialize()
const char * GetErrorName(const Security::ErrorCode code, const bool prefixRawCode=false)
Definition: ErrorDetail.h:36

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors