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