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