]>
Commit | Line | Data |
---|---|---|
02259ff8 CT |
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 | public: | |
22 | explicit ErrorDetailFile(ErrorDetailsList::Pointer const details): TemplateFile("error-details.txt") { | |
23 | buf.init(); theDetails = details; | |
24 | } | |
25 | ||
26 | private: | |
27 | MemBuf buf; | |
28 | ErrorDetailsList::Pointer theDetails; | |
29 | virtual bool parse(const char *buf, int len, bool eof); | |
30 | }; | |
31 | }// namespace Ssl | |
32 | ||
33 | /******************/ | |
34 | bool | |
35 | Ssl::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 | ||
48 | const char * | |
49 | Ssl::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 | ||
59 | const char * | |
60 | Ssl::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 | ||
70 | Ssl::ErrorDetailsManager *Ssl::ErrorDetailsManager::TheDetailsManager = NULL; | |
71 | ||
72 | Ssl::ErrorDetailsManager &Ssl::ErrorDetailsManager::GetInstance() | |
73 | { | |
74 | if (!TheDetailsManager) | |
75 | TheDetailsManager = new Ssl::ErrorDetailsManager; | |
76 | ||
77 | assert(TheDetailsManager); | |
78 | return *TheDetailsManager; | |
79 | } | |
80 | ||
81 | void Ssl::ErrorDetailsManager::Shutdown() | |
82 | { | |
83 | delete TheDetailsManager; | |
84 | TheDetailsManager = NULL; | |
85 | } | |
86 | ||
87 | ||
88 | Ssl::ErrorDetailsManager::ErrorDetailsManager() | |
89 | { | |
90 | theDefaultErrorDetails = new ErrorDetailsList(); | |
91 | ErrorDetailFile detailTmpl(theDefaultErrorDetails); | |
92 | detailTmpl.loadDefault(); | |
93 | } | |
94 | ||
95 | Ssl::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 | ||
107 | void 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 | ||
115 | bool | |
116 | Ssl::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 | ||
156 | const char * | |
157 | Ssl::ErrorDetailsManager::getDefaultErrorDescr(Ssl::ssl_error_t value) | |
158 | { | |
159 | return theDefaultErrorDetails->getErrorDescr(value); | |
160 | } | |
161 | ||
162 | const char * | |
163 | Ssl::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 | |
169 | class DetailEntryParser: public HttpHeader { | |
170 | public: | |
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 | |
176 | inline size_t detailEntryEnd(const char *s, size_t len) {return headersEnd(s, len);} | |
177 | ||
178 | bool | |
179 | Ssl::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 | } |