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