]> git.ipfire.org Git - thirdparty/squid.git/blame - src/errorpage.cc
update
[thirdparty/squid.git] / src / errorpage.cc
CommitLineData
4a9a952e 1
30a4f2a8 2/*
fe40a877 3 * $Id: errorpage.cc,v 1.95 1997/10/30 02:40:58 wessels Exp $
30a4f2a8 4 *
5 * DEBUG: section 4 Error Generation
6 * AUTHOR: Duane Wessels
7 *
42c04c16 8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
30a4f2a8 9 * --------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
13 * National Laboratory for Applied Network Research and funded by
14 * the National Science Foundation.
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 *
30 */
1e74c110 31
fe40a877 32/*
33 * Abstract: These routines are used to generate error messages to be
34 * sent to clients. The error type is used to select between
35 * the various message formats. (formats are stored in the
36 * Config.errorDirectory)
37 */
38
44a47c6e 39#include "squid.h"
1e74c110 40
fe40a877 41static const char *err_string[] =
1e74c110 42{
9b312a19 43 "ERR_NONE",
44 "ERR_READ_TIMEOUT",
45 "ERR_LIFETIME_EXP",
9b312a19 46 "ERR_READ_ERROR",
47 "ERR_WRITE_ERROR",
48 "ERR_CLIENT_ABORT",
49 "ERR_CONNECT_FAIL",
50 "ERR_INVALID_REQ",
51 "ERR_UNSUP_REQ",
52 "ERR_INVALID_URL",
53 "ERR_SOCKET_FAILURE",
54 "ERR_DNS_FAIL",
9b312a19 55 "ERR_CANNOT_FORWARD",
56 "ERR_NO_RELAY",
9b312a19 57 "ERR_ZERO_SIZE_OBJECT",
58 "ERR_FTP_DISABLED",
b9916917 59 "ERR_FTP_FAILURE",
9b312a19 60 "ERR_ACCESS_DENIED",
61 "ERR_MAX"
1e74c110 62};
63
9b312a19 64static char *error_text[ERR_MAX];
65
f5b8bbc4 66static void errorStateFree(ErrorState * err);
fe40a877 67static const char *errorConvert(char token, ErrorState * err);
68static const char *errorBuildBuf(ErrorState * err, int *len);
9b312a19 69static CWCB errorSendComplete;
1e74c110 70
fe40a877 71/*
72 * Function: errorInitialize
73 *
74 * Abstract: This function reads in the error messages formats, and stores
75 * them in error_text[];
76 *
77 * Global effects:
78 * error_text[] - is modified
79 */
b8d8561b 80void
0673c0ba 81errorInitialize(void)
fa966b74 82{
9b312a19 83 err_type i;
84 int fd;
85 char path[MAXPATHLEN];
86 struct stat sb;
3d36dfc8 87 assert(sizeof(err_string) == (ERR_MAX + 1) * sizeof(char *));
9b312a19 88 for (i = ERR_NONE + 1; i < ERR_MAX; i++) {
89 snprintf(path, MAXPATHLEN, "%s/%s",
90 Config.errorDirectory, err_string[i]);
91 fd = file_open(path, O_RDONLY, NULL, NULL);
92 if (fd < 0) {
93 debug(4, 0) ("errorInitialize: %s: %s\n", path, xstrerror());
94 fatal("Failed to open error text file");
95 }
96 if (fstat(fd, &sb) < 0)
fe40a877 97 fatal("fstat() failed on error text file");
9b312a19 98 safe_free(error_text[i]);
f787fb1e 99 error_text[i] = xcalloc(sb.st_size + 1, 1);
9b312a19 100 if (read(fd, error_text[i], sb.st_size) != sb.st_size)
fe40a877 101 fatal("failed to fully read error text file");
9b312a19 102 file_close(fd);
1e74c110 103 }
6eb42cae 104}
105
fe40a877 106/*
107 * Function: errorCon
108 *
109 * Abstract: This function creates a ErrorState object.
110 */
111ErrorState *
112errorCon(err_type type, http_status status)
113{
114 ErrorState *err = xcalloc(1, sizeof(ErrorState));
115 err->type = type;
116 err->http_status = status;
117 return err;
118}
119
120/*
121 * Function: errorAppendEntry
122 *
123 * Arguments: err - This object is destroyed after use in this function.
124 *
125 * Abstract: This function generates a error page from the info contained
126 * by 'err' and then attaches it to the specified 'entry'
127 *
128 * Note: The above abstract is should be check for correctness!!!!
129 */
130void
131errorAppendEntry(StoreEntry * entry, ErrorState * err)
132{
133 const char *buf;
134 MemObject *mem = entry->mem_obj;
135 int len;
136 assert(entry->store_status == STORE_PENDING);
137 buf = errorBuildBuf(err, &len);
138 storeAppend(entry, buf, len);
139 if (mem)
140 mem->reply->code = err->http_status;
141 errorStateFree(err);
142 xfree(err);
143}
144
145/*
146 * Function: errorSend
147 *
148 * Arguments: err - This object is destroyed after use in this function.
149 *
150 * Abstract: This function generates a error page from the info contained
151 * by 'err' and then sends it to the client.
152 *
153 * Note: The callback function errorSendComplete() cleans up 'err'
154 *
155 * Note: I don't think we need to add 'err' to the callback table
156 * since the only path ends up a errorSendComplete().
157 */
158void
159errorSend(int fd, ErrorState * err)
160{
161 const char *buf;
162 int len;
163 debug(4, 3) ("errorSend: FD %d, err=%p\n", fd, err);
164 assert(fd >= 0);
165 buf = errorBuildBuf(err, &len);
166 cbdataAdd(err);
167 comm_write(fd, xstrdup(buf), len, errorSendComplete, err, xfree);
168}
169
170/*
171 * Function: errorSendComplete
172 *
173 * Abstract: This function
174 *
175 * Note: If there is a callback, the callback is responsible for
176 * closeing the FD, otherwise we do it ourseves.
177 */
178static void
179errorSendComplete(int fd, char *buf, int size, int errflag, void *data)
180{
181 ErrorState *err = data;
182 debug(4, 3) ("errorSendComplete: FD %d, size=%d\n", fd, size);
183 if (errflag != COMM_ERR_CLOSING) {
184 if (err->callback)
185 err->callback(fd, err->callback_data, size);
186 else
187 comm_close(fd);
188 }
189 errorStateFree(err);
190 cbdataFree(err);
191}
192
9b312a19 193static void
194errorStateFree(ErrorState * err)
6eb42cae 195{
9b312a19 196 requestUnlink(err->request);
197 safe_free(err->redirect_url);
198 safe_free(err->url);
76a5501f 199 safe_free(err->host);
5f3c4e9a 200 safe_free(err->dnsserver_msg);
bb0929d8 201 if (BIT_TEST(err->flags, ERR_FLAG_CBDATA))
38d04788 202 cbdataFree(err);
bb0929d8 203 else
204 safe_free(err);
1e74c110 205}
8213067d 206
2658f489 207#define CVT_BUF_SZ 512
fe40a877 208
209/*
210 * c - Squid error code
211 * d - seconds elapsed since request received
212 * e - errno x
213 * E - strerror() x
214 * F - FTP reply line x
215 * f - FTP request line x
216 * h - cache hostname x
217 * i - client IP address x
218 * I - server IP address x
219 * L - HREF link for more info/contact x
220 * M - Request Method x
221 * p - URL port # x
222 * P - Protocol x
223 * t - local time x
224 * T - UTC x
225 * w - cachemgr email address x
226 * z - dns server error message x
227 */
228
229static const char *
9b312a19 230errorConvert(char token, ErrorState * err)
8213067d 231{
2658f489 232 request_t *r = err->request;
233 static char buf[CVT_BUF_SZ];
fe40a877 234 const char *p = buf;
9b312a19 235 switch (token) {
042461c3 236 case 'e':
c45ed9ad 237 snprintf(buf, CVT_BUF_SZ, "%d", err->xerrno);
042461c3 238 break;
239 case 'E':
c45ed9ad 240 snprintf(buf, CVT_BUF_SZ, "(%d) %s", err->xerrno, strerror(err->xerrno));
03d7b07f 241 break;
fe40a877 242 case 'f':
243 /* FTP REQUEST LINE */
244 if (err->ftp.request)
245 p = err->ftp.request;
246 else
247 p = "<none>";
248 break;
249 case 'F':
250 /* FTP REPLY LINE */
251 if (err->ftp.request)
252 p = err->ftp.reply;
253 else
254 p = "<none>";
03d7b07f 255 break;
256 case 'h':
257 snprintf(buf, CVT_BUF_SZ, "%s", getMyHostname());
f787fb1e 258 break;
fe40a877 259 case 'H':
260 p = r ? r->host : "[unknown host]";
f787fb1e 261 break;
262 case 'i':
263 snprintf(buf, CVT_BUF_SZ, "%s", inet_ntoa(err->src_addr));
f6aa1a5c 264 break;
f787fb1e 265 case 'I':
266 if (err->host) {
267 snprintf(buf, CVT_BUF_SZ, "%s", err->host);
f787fb1e 268 } else
fe40a877 269 p = "[unknown]";
270 break;
271 case 'L':
272 if (Config.errHtmlText) {
273 snprintf(buf, CVT_BUF_SZ, "%s", Config.errHtmlText);
274 } else
275 p = "[not available]";
276 break;
277 case 'M':
278 p = r ? RequestMethodStr[r->method] : "[unkown method]";
279 break;
280 case 'p':
281 if (r) {
282 snprintf(buf, CVT_BUF_SZ, "%d", (int) r->port);
283 } else {
284 p = "[unknown port]";
285 }
286 break;
287 case 'P':
288 p = r ? ProtocolStr[r->protocol] : "[unkown protocol]";
289 break;
290 case 't':
291 xstrncpy(buf, mkhttpdlogtime(&squid_curtime), 128);
f787fb1e 292 break;
f8291f8f 293 case 'T':
294 snprintf(buf, CVT_BUF_SZ, "%s", mkrfc1123(squid_curtime));
f8291f8f 295 break;
fe40a877 296 case 'U':
297 p = r ? urlCanonicalClean(r) : err->url;
b9916917 298 break;
fe40a877 299 case 'w':
300 if (Config.adminEmail) {
301 snprintf(buf, CVT_BUF_SZ, "%s", Config.adminEmail);
302 } else
303 p = "[unknown]";
304 break;
305 case 'z':
306 if (err->dnsserver_msg)
307 p = err->dnsserver_msg;
b9916917 308 else
fe40a877 309 p = "[unknown]";
b9916917 310 break;
9b312a19 311 default:
312 p = "%UNKNOWN%";
313 break;
314 }
315 if (p == NULL)
316 p = "<NULL>";
e102ebda 317 debug(4, 3) ("errorConvert: %%%c --> '%s'\n", token, p);
9b312a19 318 return p;
8213067d 319}
e381a13d 320
fe40a877 321static const char *
9b312a19 322errorBuildBuf(ErrorState * err, int *len)
e381a13d 323{
9b312a19 324 LOCAL_ARRAY(char, buf, ERROR_BUF_SZ);
325 LOCAL_ARRAY(char, content, ERROR_BUF_SZ);
326 char *hdr;
327 int clen;
328 int tlen;
329 char *m;
b8b780a4 330 char *mx;
9b312a19 331 char *p;
fe40a877 332 const char *t;
9b312a19 333 assert(err != NULL);
334 assert(err->type > ERR_NONE && err->type < ERR_MAX);
b8b780a4 335 mx = m = xstrdup(error_text[err->type]);
9b312a19 336 clen = 0;
337 while ((p = strchr(m, '%'))) {
338 *p = '\0'; /* terminate */
339 xstrncpy(content + clen, m, ERROR_BUF_SZ - clen); /* copy */
340 clen += (p - m); /* advance */
341 if (clen >= ERROR_BUF_SZ)
342 break;
343 p++;
344 m = p + 1;
345 t = errorConvert(*p, err); /* convert */
346 xstrncpy(content + clen, t, ERROR_BUF_SZ - clen); /* copy */
347 clen += strlen(t); /* advance */
348 if (clen >= ERROR_BUF_SZ)
349 break;
350 }
351 if (clen < ERROR_BUF_SZ && m != NULL) {
352 xstrncpy(content + clen, m, ERROR_BUF_SZ - clen);
353 clen += strlen(m);
354 }
355 if (clen >= ERROR_BUF_SZ) {
356 clen = ERROR_BUF_SZ - 1;
357 *(content + clen) = '\0';
358 }
359 assert(clen == strlen(content));
360 hdr = httpReplyHeader((double) 1.0,
361 err->http_status,
b8d8561b 362 "text/html",
9b312a19 363 clen,
437e2060 364 0, /* no LMT for error pages */
9b312a19 365 squid_curtime);
366 tlen = snprintf(buf, ERROR_BUF_SZ, "%s\r\n%s", hdr, content);
367 if (len)
368 *len = tlen;
b8b780a4 369 xfree(mx);
9b312a19 370 return buf;
e381a13d 371}