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