]> git.ipfire.org Git - thirdparty/squid.git/blob - src/ssl/ErrorDetailManager.cc
4bfe6e5e623af564d9a6078079757d0404b95a47
[thirdparty/squid.git] / src / ssl / ErrorDetailManager.cc
1 #include "squid.h"
2 #include "ErrorDetail.h"
3 #include "errorpage.h"
4 #include "ErrorDetailManager.h"
5
6 void Ssl::errorDetailInitialize()
7 {
8 Ssl::ErrorDetailsManager::GetInstance();
9 }
10
11 void Ssl::errorDetailClean()
12 {
13 Ssl::ErrorDetailsManager::Shutdown();
14 }
15
16 namespace Ssl
17 {
18
19 /// manages error detail templates
20 class ErrorDetailFile : public TemplateFile
21 {
22 public:
23 explicit ErrorDetailFile(ErrorDetailsList::Pointer const details): TemplateFile("error-details.txt") {
24 buf.init();
25 theDetails = details;
26 }
27
28 private:
29 MemBuf buf;
30 ErrorDetailsList::Pointer theDetails;
31 virtual bool parse(const char *buf, int len, bool eof);
32 };
33 }// namespace Ssl
34
35 /******************/
36 bool
37 Ssl::ErrorDetailsList::getRecord(Ssl::ssl_error_t value, ErrorDetailEntry &entry)
38 {
39 const ErrorDetails::const_iterator it = theList.find(value);
40 if (it != theList.end()) {
41 entry.error_no = it->second.error_no;
42 entry.name = it->second.name;
43 entry.detail = it->second.detail;
44 entry.descr = it->second.descr;
45 return true;
46 }
47 return false;
48 }
49
50 const char *
51 Ssl::ErrorDetailsList::getErrorDescr(Ssl::ssl_error_t value)
52 {
53 const ErrorDetails::const_iterator it = theList.find(value);
54 if (it != theList.end()) {
55 return it->second.descr.termedBuf();
56 }
57
58 return NULL;
59 }
60
61 const char *
62 Ssl::ErrorDetailsList::getErrorDetail(Ssl::ssl_error_t value)
63 {
64 const ErrorDetails::const_iterator it = theList.find(value);
65 if (it != theList.end()) {
66 return it->second.detail.termedBuf();
67 }
68
69 return NULL;
70 }
71
72 Ssl::ErrorDetailsManager *Ssl::ErrorDetailsManager::TheDetailsManager = NULL;
73
74 Ssl::ErrorDetailsManager &Ssl::ErrorDetailsManager::GetInstance()
75 {
76 if (!TheDetailsManager)
77 TheDetailsManager = new Ssl::ErrorDetailsManager;
78
79 assert(TheDetailsManager);
80 return *TheDetailsManager;
81 }
82
83 void Ssl::ErrorDetailsManager::Shutdown()
84 {
85 delete TheDetailsManager;
86 TheDetailsManager = NULL;
87 }
88
89
90 Ssl::ErrorDetailsManager::ErrorDetailsManager()
91 {
92 theDefaultErrorDetails = new ErrorDetailsList();
93 ErrorDetailFile detailTmpl(theDefaultErrorDetails);
94 detailTmpl.loadDefault();
95 }
96
97 Ssl::ErrorDetailsList::Pointer Ssl::ErrorDetailsManager::getCachedDetails(const char *lang)
98 {
99 Cache::iterator it;
100 it = cache.find(lang);
101 if (it != cache.end()) {
102 debugs(83, 8, HERE << "Found template details in cache for language: " << lang);
103 return it->second;
104 }
105
106 return NULL;
107 }
108
109 void Ssl::ErrorDetailsManager::cacheDetails(ErrorDetailsList::Pointer &errorDetails)
110 {
111 const char *lang = errorDetails->errLanguage.termedBuf();
112 assert(lang);
113 if (cache.find(lang) == cache.end())
114 cache[lang] = errorDetails;
115 }
116
117 bool
118 Ssl::ErrorDetailsManager::getErrorDetail(Ssl::ssl_error_t value, HttpRequest *request, ErrorDetailEntry &entry)
119 {
120 #if USE_ERR_LOCALES
121 String hdr;
122 if (request && request->header.getList(HDR_ACCEPT_LANGUAGE, &hdr)) {
123 ErrorDetailsList::Pointer errDetails = NULL;
124 //Try to retrieve from cache
125 size_t pos = 0;
126 char lang[256];
127 // Get the first ellement of the Accept-Language header
128 strHdrAcptLangGetItem(hdr, lang, 256, pos);
129 errDetails = getCachedDetails(lang); // search in cache
130
131 if (!errDetails) { // Else try to load from disk
132 debugs(83, 8, HERE << "Creating new ErrDetailList to read from disk");
133 errDetails = new ErrorDetailsList();
134 ErrorDetailFile detailTmpl(errDetails);
135 if (detailTmpl.loadFor(request)) {
136 if (detailTmpl.language()) {
137 debugs(83, 8, HERE << "Found details on disk for language " << detailTmpl.language());
138 errDetails->errLanguage = detailTmpl.language();
139 cacheDetails(errDetails);
140 }
141 }
142 }
143
144 if (errDetails != NULL && errDetails->getRecord(value, entry))
145 return true;
146 }
147 #endif
148
149 // else try the default
150 if (theDefaultErrorDetails->getRecord(value, entry)) {
151 debugs(83, 8, HERE << "Found default details record for error: " << GetErrorName(value));
152 return true;
153 }
154
155 return false;
156 }
157
158 const char *
159 Ssl::ErrorDetailsManager::getDefaultErrorDescr(Ssl::ssl_error_t value)
160 {
161 return theDefaultErrorDetails->getErrorDescr(value);
162 }
163
164 const char *
165 Ssl::ErrorDetailsManager::getDefaultErrorDetail(Ssl::ssl_error_t value)
166 {
167 return theDefaultErrorDetails->getErrorDetail(value);
168 }
169
170 // Use HttpHeaders parser to parse error-details.txt files
171 class DetailEntryParser: public HttpHeader
172 {
173 public:
174 DetailEntryParser():HttpHeader(hoErrorDetail) {}
175 };
176
177 //The end of an error detrail entry is a double "\n". The headersEnd
178 // functions can detect it
179 inline size_t detailEntryEnd(const char *s, size_t len) {return headersEnd(s, len);}
180
181 bool
182 Ssl::ErrorDetailFile::parse(const char *buffer, int len, bool eof)
183 {
184 if (!theDetails)
185 return false;
186
187 if (len) {
188 buf.append(buffer, len);
189 }
190
191 if (eof)
192 buf.append("\n\n", 1);
193
194 while (size_t size = detailEntryEnd(buf.content(), buf.contentSize())) {
195 const char *e = buf.content() + size;
196
197 //ignore spaces, new lines and comment lines (starting with #) at the beggining
198 const char *s;
199 for (s = buf.content(); (*s == '\n' || *s == ' ' || *s == '\t' || *s == '#') && s < e; s++) {
200 if (*s == '#')
201 while (s<e && *s != '\n') s++; // skip untill the end of line
202 }
203
204 if ( s != e) {
205 DetailEntryParser parser;
206 if (!parser.parse(s, e)) {
207 debugs(83, DBG_IMPORTANT, HERE <<
208 "WARNING! parse error on:" << s);
209 return false;
210 }
211
212 const char *errorName = parser.getByName("name").termedBuf();
213 if (!errorName) {
214 debugs(83, DBG_IMPORTANT, HERE <<
215 "WARNING! invalid or no error detail name on:" << s);
216 return false;
217 }
218
219 Ssl::ssl_error_t ssl_error = Ssl::GetErrorCode(errorName);
220 if (ssl_error == SSL_ERROR_NONE) {
221 debugs(83, DBG_IMPORTANT, HERE <<
222 "WARNING! invalid error detail name: " << errorName);
223 return false;
224 }
225
226 if (theDetails->getErrorDetail(ssl_error)) {
227 debugs(83, DBG_IMPORTANT, HERE <<
228 "WARNING! duplicate entry: " << errorName);
229 return false;
230 }
231
232 ErrorDetailEntry &entry = theDetails->theList[ssl_error];
233 entry.error_no = ssl_error;
234 entry.name = errorName;
235 String tmp = parser.getByName("detail");
236 httpHeaderParseQuotedString(tmp.termedBuf(), tmp.size(), &entry.detail);
237 tmp = parser.getByName("descr");
238 httpHeaderParseQuotedString(tmp.termedBuf(), tmp.size(), &entry.descr);
239 bool parseOK = entry.descr.defined() && entry.detail.defined();
240
241 if (!parseOK) {
242 debugs(83, DBG_IMPORTANT, HERE <<
243 "WARNING! missing imporant field for detail error: " << errorName);
244 return false;
245 }
246 }// else {only spaces and black lines; just ignore}
247
248 buf.consume(size);
249 }
250 debugs(83, 9, HERE << " Remain size: " << buf.contentSize() << " Content: " << buf.content());
251 return true;
252 }