]>
Commit | Line | Data |
---|---|---|
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 | |
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 | |
dc49061a A |
21 | class ErrorDetailFile : public TemplateFile |
22 | { | |
02259ff8 | 23 | public: |
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 | ||
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 | ||
02259ff8 CT |
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()) { | |
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 | ||
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 | |
b248c2a3 | 118 | Ssl::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 | ||
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 | |
dc49061a A |
171 | class DetailEntryParser: public HttpHeader |
172 | { | |
02259ff8 CT |
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; | |
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 | } |