]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ssl/ErrorDetailManager.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / ssl / ErrorDetailManager.cc
CommitLineData
582c2af2 1#include "squid.h"
02259ff8 2#include "ErrorDetail.h"
02259ff8 3#include "ErrorDetailManager.h"
602d9612 4#include "errorpage.h"
b6149797 5#include "mime_header.h"
02259ff8
CT
6
7void Ssl::errorDetailInitialize()
8{
9 Ssl::ErrorDetailsManager::GetInstance();
10}
11
12void Ssl::errorDetailClean()
13{
14 Ssl::ErrorDetailsManager::Shutdown();
15}
16
17namespace Ssl
18{
19
20/// manages error detail templates
dc49061a
A
21class ErrorDetailFile : public TemplateFile
22{
02259ff8 23public:
8ff2520a 24 explicit ErrorDetailFile(ErrorDetailsList::Pointer const details): TemplateFile("error-details.txt", ERR_NONE) {
dc49061a
A
25 buf.init();
26 theDetails = details;
02259ff8
CT
27 }
28
29private:
30 MemBuf buf;
31 ErrorDetailsList::Pointer theDetails;
32 virtual bool parse(const char *buf, int len, bool eof);
33};
34}// namespace Ssl
35
36/******************/
37bool
38Ssl::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
51const char *
52Ssl::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
62const char *
63Ssl::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
73Ssl::ErrorDetailsManager *Ssl::ErrorDetailsManager::TheDetailsManager = NULL;
74
75Ssl::ErrorDetailsManager &Ssl::ErrorDetailsManager::GetInstance()
76{
77 if (!TheDetailsManager)
78 TheDetailsManager = new Ssl::ErrorDetailsManager;
79
80 assert(TheDetailsManager);
81 return *TheDetailsManager;
82}
83
84void Ssl::ErrorDetailsManager::Shutdown()
85{
86 delete TheDetailsManager;
87 TheDetailsManager = NULL;
88}
89
02259ff8
CT
90Ssl::ErrorDetailsManager::ErrorDetailsManager()
91{
92 theDefaultErrorDetails = new ErrorDetailsList();
93 ErrorDetailFile detailTmpl(theDefaultErrorDetails);
94 detailTmpl.loadDefault();
95}
96
97Ssl::ErrorDetailsList::Pointer Ssl::ErrorDetailsManager::getCachedDetails(const char *lang)
98{
99 Cache::iterator it;
100 it = cache.find(lang);
101 if (it != cache.end()) {
dc49061a
A
102 debugs(83, 8, HERE << "Found template details in cache for language: " << lang);
103 return it->second;
02259ff8
CT
104 }
105
106 return NULL;
107}
108
109void 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
117bool
b248c2a3 118Ssl::ErrorDetailsManager::getErrorDetail(Ssl::ssl_error_t value, const HttpRequest::Pointer &request, ErrorDetailEntry &entry)
02259ff8
CT
119{
120#if USE_ERR_LOCALES
121 String hdr;
b248c2a3 122 if (request != NULL && request->header.getList(HDR_ACCEPT_LANGUAGE, &hdr)) {
02259ff8
CT
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);
b248c2a3 135 if (detailTmpl.loadFor(request.getRaw())) {
02259ff8
CT
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
158const char *
159Ssl::ErrorDetailsManager::getDefaultErrorDescr(Ssl::ssl_error_t value)
160{
161 return theDefaultErrorDetails->getErrorDescr(value);
162}
163
164const char *
165Ssl::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
dc49061a
A
171class DetailEntryParser: public HttpHeader
172{
02259ff8
CT
173public:
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
179inline size_t detailEntryEnd(const char *s, size_t len) {return headersEnd(s, len);}
180
181bool
182Ssl::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;
d7ae3534 199 for (s = buf.content(); (*s == '\n' || *s == ' ' || *s == '\t' || *s == '#') && s < e; ++s) {
dc49061a 200 if (*s == '#')
d7ae3534
FC
201 while (s<e && *s != '\n')
202 ++s; // skip untill the end of line
02259ff8
CT
203 }
204
205 if ( s != e) {
206 DetailEntryParser parser;
207 if (!parser.parse(s, e)) {
208 debugs(83, DBG_IMPORTANT, HERE <<
209 "WARNING! parse error on:" << s);
210 return false;
211 }
212
81c203c9
AR
213 const String errorName = parser.getByName("name");
214 if (!errorName.size()) {
02259ff8
CT
215 debugs(83, DBG_IMPORTANT, HERE <<
216 "WARNING! invalid or no error detail name on:" << s);
217 return false;
218 }
219
81c203c9 220 Ssl::ssl_error_t ssl_error = Ssl::GetErrorCode(errorName.termedBuf());
02259ff8
CT
221 if (ssl_error == SSL_ERROR_NONE) {
222 debugs(83, DBG_IMPORTANT, HERE <<
223 "WARNING! invalid error detail name: " << errorName);
224 return false;
225 }
226
227 if (theDetails->getErrorDetail(ssl_error)) {
228 debugs(83, DBG_IMPORTANT, HERE <<
229 "WARNING! duplicate entry: " << errorName);
230 return false;
231 }
232
233 ErrorDetailEntry &entry = theDetails->theList[ssl_error];
234 entry.error_no = ssl_error;
235 entry.name = errorName;
236 String tmp = parser.getByName("detail");
237 httpHeaderParseQuotedString(tmp.termedBuf(), tmp.size(), &entry.detail);
238 tmp = parser.getByName("descr");
239 httpHeaderParseQuotedString(tmp.termedBuf(), tmp.size(), &entry.descr);
240 bool parseOK = entry.descr.defined() && entry.detail.defined();
241
242 if (!parseOK) {
243 debugs(83, DBG_IMPORTANT, HERE <<
244 "WARNING! missing imporant field for detail error: " << errorName);
245 return false;
246 }
247 }// else {only spaces and black lines; just ignore}
248
249 buf.consume(size);
250 }
251 debugs(83, 9, HERE << " Remain size: " << buf.contentSize() << " Content: " << buf.content());
252 return true;
253}