]> git.ipfire.org Git - thirdparty/squid.git/blame - src/errorpage.cc
Terminated all messages with </P> for Squid signature to loook nice.
[thirdparty/squid.git] / src / errorpage.cc
CommitLineData
4a9a952e 1
30a4f2a8 2/*
cb69b4c7 3 * $Id: errorpage.cc,v 1.117 1998/02/21 00:56:54 rousskov 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/*
4e3f29eb 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)
fe40a877 37 */
38
44a47c6e 39#include "squid.h"
1e74c110 40
9b312a19 41static char *error_text[ERR_MAX];
42
cb69b4c7 43static const char *errorBuildContent(ErrorState * err, int *len);
fe40a877 44static const char *errorConvert(char token, ErrorState * err);
9b312a19 45static CWCB errorSendComplete;
1e74c110 46
fe40a877 47/*
48 * Function: errorInitialize
49 *
50 * Abstract: This function reads in the error messages formats, and stores
51 * them in error_text[];
52 *
53 * Global effects:
54 * error_text[] - is modified
55 */
b8d8561b 56void
0673c0ba 57errorInitialize(void)
fa966b74 58{
9b312a19 59 err_type i;
60 int fd;
61 char path[MAXPATHLEN];
62 struct stat sb;
9b312a19 63 for (i = ERR_NONE + 1; i < ERR_MAX; i++) {
64 snprintf(path, MAXPATHLEN, "%s/%s",
27cd7235 65 Config.errorDirectory, err_type_str[i]);
6cf028ab 66 fd = file_open(path, O_RDONLY, NULL, NULL, NULL);
9b312a19 67 if (fd < 0) {
68 debug(4, 0) ("errorInitialize: %s: %s\n", path, xstrerror());
69 fatal("Failed to open error text file");
70 }
71 if (fstat(fd, &sb) < 0)
fe40a877 72 fatal("fstat() failed on error text file");
9b312a19 73 safe_free(error_text[i]);
f787fb1e 74 error_text[i] = xcalloc(sb.st_size + 1, 1);
9b312a19 75 if (read(fd, error_text[i], sb.st_size) != sb.st_size)
fe40a877 76 fatal("failed to fully read error text file");
9b312a19 77 file_close(fd);
1e74c110 78 }
6eb42cae 79}
80
53ad48e6 81void
82errorFree(void)
83{
84 int i;
85 for (i = ERR_NONE + 1; i < ERR_MAX; i++)
86 safe_free(error_text[i]);
87}
88
fe40a877 89/*
90 * Function: errorCon
91 *
92 * Abstract: This function creates a ErrorState object.
93 */
94ErrorState *
95errorCon(err_type type, http_status status)
96{
97 ErrorState *err = xcalloc(1, sizeof(ErrorState));
98 err->type = type;
99 err->http_status = status;
100 return err;
101}
102
103/*
104 * Function: errorAppendEntry
105 *
106 * Arguments: err - This object is destroyed after use in this function.
107 *
108 * Abstract: This function generates a error page from the info contained
4e3f29eb 109 * by 'err' and then stores the text in the specified store
110 * entry. This function should only be called by ``server
111 * side routines'' which need to communicate errors to the
79e0dc20 112 * client side. It should also be called from client_side.c
113 * because we now support persistent connections, and
114 * cannot assume that we can immediately write to the socket
115 * for an error.
fe40a877 116 */
117void
118errorAppendEntry(StoreEntry * entry, ErrorState * err)
119{
cb69b4c7 120#if 0
fe40a877 121 const char *buf;
fe40a877 122 int len;
cb69b4c7 123#else
124 HttpReply *rep;
125#endif
126 MemObject *mem = entry->mem_obj;
fe40a877 127 assert(entry->store_status == STORE_PENDING);
b50179a6 128 assert(mem != NULL);
4e3f29eb 129 assert(mem->inmem_hi == 0);
cb69b4c7 130#if 0
fe40a877 131 buf = errorBuildBuf(err, &len);
132 storeAppend(entry, buf, len);
cb69b4c7 133#else
134 rep = errorBuildReply(err);
135 httpReplySwapOut(rep, entry);
136 httpReplyDestroy(rep);
137#endif
138 mem->reply->sline.status = err->http_status;
00691420 139 storeComplete(entry);
b50179a6 140 storeNegativeCache(entry);
141 storeReleaseRequest(entry);
fe40a877 142 errorStateFree(err);
fe40a877 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.
4e3f29eb 152 * The callback function errorSendComplete() is called after
153 * the page has been written to the client socket (fd).
154 * errorSendComplete() deallocates 'err'. We need to add
155 * 'err' to the cbdata because comm_write() requires it
156 * for all callback data pointers.
79e0dc20 157 *
158 * Note, normally errorSend() should only be called from
159 * routines in ssl.c and pass.c, where we don't have any
160 * StoreEntry's. In client_side.c we must allocate a StoreEntry
161 * for errors and use errorAppendEntry() to account for
162 * persistent/pipeline connections.
fe40a877 163 */
164void
165errorSend(int fd, ErrorState * err)
166{
cb69b4c7 167 HttpReply *rep;
168#if 0
169 FREE *freefunc;
170 char *buf;
fe40a877 171 int len;
cb69b4c7 172#endif
fe40a877 173 debug(4, 3) ("errorSend: FD %d, err=%p\n", fd, err);
174 assert(fd >= 0);
88aad2e5 175 /*
176 * ugh, this is how we make sure error codes get back to
177 * the client side for logging and error tracking.
178 */
179 if (err->request)
180 err->request->err_type = err->type;
cb69b4c7 181 /* moved in front of errorBuildBuf @?@ */
79a15e0a 182 EBIT_SET(err->flags, ERR_FLAG_CBDATA);
3f6c0fb2 183 cbdataAdd(err, MEM_NONE);
cb69b4c7 184#if 0
185 buf = errorBuildBuf(err, &len);
fe40a877 186 comm_write(fd, xstrdup(buf), len, errorSendComplete, err, xfree);
cb69b4c7 187#else
188 rep = errorBuildReply(err);
189 comm_write_mbuf(fd, httpReplyPack(rep), errorSendComplete, err);
190 httpReplyDestroy(rep);
191#endif
fe40a877 192}
193
194/*
195 * Function: errorSendComplete
196 *
4e3f29eb 197 * Abstract: Called by commHandleWrite() after data has been written
198 * to the client socket.
fe40a877 199 *
200 * Note: If there is a callback, the callback is responsible for
201 * closeing the FD, otherwise we do it ourseves.
202 */
203static void
79a15e0a 204errorSendComplete(int fd, char *bufnotused, size_t size, int errflag, void *data)
fe40a877 205{
206 ErrorState *err = data;
207 debug(4, 3) ("errorSendComplete: FD %d, size=%d\n", fd, size);
208 if (errflag != COMM_ERR_CLOSING) {
209 if (err->callback)
210 err->callback(fd, err->callback_data, size);
211 else
212 comm_close(fd);
213 }
214 errorStateFree(err);
fe40a877 215}
216
cb69b4c7 217void
9b312a19 218errorStateFree(ErrorState * err)
6eb42cae 219{
9b312a19 220 requestUnlink(err->request);
221 safe_free(err->redirect_url);
222 safe_free(err->url);
76a5501f 223 safe_free(err->host);
5f3c4e9a 224 safe_free(err->dnsserver_msg);
b5af8569 225 safe_free(err->request_hdrs);
79a15e0a 226 if (EBIT_TEST(err->flags, ERR_FLAG_CBDATA))
38d04788 227 cbdataFree(err);
bb0929d8 228 else
229 safe_free(err);
1e74c110 230}
8213067d 231
2658f489 232#define CVT_BUF_SZ 512
fe40a877 233
234/*
be335c22 235 * B - URL with FTP %2f hack x
fe40a877 236 * c - Squid error code
237 * d - seconds elapsed since request received
238 * e - errno x
239 * E - strerror() x
fe40a877 240 * f - FTP request line x
969c39b9 241 * F - FTP reply line x
fe40a877 242 * h - cache hostname x
969c39b9 243 * H - server host name x
fe40a877 244 * i - client IP address x
245 * I - server IP address x
246 * L - HREF link for more info/contact x
247 * M - Request Method x
248 * p - URL port # x
249 * P - Protocol x
b5af8569 250 * R - Full HTTP Request x
fe40a877 251 * t - local time x
252 * T - UTC x
969c39b9 253 * U - URL without password x
254 * u - URL without password, %2f added to path x
fe40a877 255 * w - cachemgr email address x
256 * z - dns server error message x
257 */
258
259static const char *
9b312a19 260errorConvert(char token, ErrorState * err)
8213067d 261{
2658f489 262 request_t *r = err->request;
263 static char buf[CVT_BUF_SZ];
fe40a877 264 const char *p = buf;
9b312a19 265 switch (token) {
8f872bb6 266 case 'B':
267 p = r ? ftpUrlWith2f(r) : "[no URL]";
268 break;
042461c3 269 case 'e':
c45ed9ad 270 snprintf(buf, CVT_BUF_SZ, "%d", err->xerrno);
042461c3 271 break;
272 case 'E':
23d92c64 273 if (err->xerrno)
53ad48e6 274 snprintf(buf, CVT_BUF_SZ, "(%d) %s", err->xerrno, strerror(err->xerrno));
23d92c64 275 else
0d87e358 276 snprintf(buf, CVT_BUF_SZ, "[No Error]");
03d7b07f 277 break;
fe40a877 278 case 'f':
279 /* FTP REQUEST LINE */
280 if (err->ftp.request)
281 p = err->ftp.request;
282 else
283 p = "<none>";
284 break;
285 case 'F':
286 /* FTP REPLY LINE */
287 if (err->ftp.request)
288 p = err->ftp.reply;
289 else
290 p = "<none>";
03d7b07f 291 break;
292 case 'h':
293 snprintf(buf, CVT_BUF_SZ, "%s", getMyHostname());
f787fb1e 294 break;
fe40a877 295 case 'H':
296 p = r ? r->host : "[unknown host]";
f787fb1e 297 break;
298 case 'i':
299 snprintf(buf, CVT_BUF_SZ, "%s", inet_ntoa(err->src_addr));
f6aa1a5c 300 break;
f787fb1e 301 case 'I':
302 if (err->host) {
303 snprintf(buf, CVT_BUF_SZ, "%s", err->host);
f787fb1e 304 } else
fe40a877 305 p = "[unknown]";
306 break;
307 case 'L':
308 if (Config.errHtmlText) {
309 snprintf(buf, CVT_BUF_SZ, "%s", Config.errHtmlText);
310 } else
311 p = "[not available]";
312 break;
313 case 'M':
314 p = r ? RequestMethodStr[r->method] : "[unkown method]";
315 break;
316 case 'p':
317 if (r) {
318 snprintf(buf, CVT_BUF_SZ, "%d", (int) r->port);
319 } else {
320 p = "[unknown port]";
321 }
322 break;
323 case 'P':
324 p = r ? ProtocolStr[r->protocol] : "[unkown protocol]";
325 break;
b5af8569 326 case 'R':
327 p = err->request_hdrs ? err->request_hdrs : "[no request]";
328 break;
fe40a877 329 case 't':
330 xstrncpy(buf, mkhttpdlogtime(&squid_curtime), 128);
f787fb1e 331 break;
f8291f8f 332 case 'T':
333 snprintf(buf, CVT_BUF_SZ, "%s", mkrfc1123(squid_curtime));
f8291f8f 334 break;
fe40a877 335 case 'U':
b5af8569 336 p = r ? urlCanonicalClean(r) : err->url ? err->url : "[no URL]";
b9916917 337 break;
fe40a877 338 case 'w':
339 if (Config.adminEmail) {
340 snprintf(buf, CVT_BUF_SZ, "%s", Config.adminEmail);
341 } else
342 p = "[unknown]";
343 break;
344 case 'z':
345 if (err->dnsserver_msg)
346 p = err->dnsserver_msg;
b9916917 347 else
fe40a877 348 p = "[unknown]";
b9916917 349 break;
e347f8e5 350 case '%':
351 p = "%";
352 break;
9b312a19 353 default:
354 p = "%UNKNOWN%";
355 break;
356 }
9e6aef51 357 assert(p != NULL);
e102ebda 358 debug(4, 3) ("errorConvert: %%%c --> '%s'\n", token, p);
9b312a19 359 return p;
8213067d 360}
e381a13d 361
cb69b4c7 362/* allocates and initializes an error response */
363HttpReply *
364errorBuildReply(ErrorState *err)
365{
366 int clen;
367 HttpReply *rep = httpReplyCreate();
368 const char *content = errorBuildContent(err, &clen);
369 /* no LMT for error pages; error pages expire immediately */
370 httpReplySetHeaders(rep, 1.0, err->http_status, NULL, "text/html", clen, 0, squid_curtime);
371 httpBodySet(&rep->body, content, clen+1, NULL);
372 return rep;
373}
374
fe40a877 375static const char *
cb69b4c7 376errorBuildContent(ErrorState * err, int *len)
377{
378 LOCAL_ARRAY(char, content, ERROR_BUF_SZ);
379 int clen;
380 char *m;
381 char *mx;
382 char *p;
383 const char *t;
384 assert(err != NULL);
385 assert(err->type > ERR_NONE && err->type < ERR_MAX);
386 mx = m = xstrdup(error_text[err->type]);
387 clen = 0;
388 while ((p = strchr(m, '%'))) {
389 *p = '\0'; /* terminate */
390 xstrncpy(content + clen, m, ERROR_BUF_SZ - clen); /* copy */
391 clen += (p - m); /* advance */
392 if (clen >= ERROR_BUF_SZ)
393 break;
394 p++;
395 m = p + 1;
396 t = errorConvert(*p, err); /* convert */
397 xstrncpy(content + clen, t, ERROR_BUF_SZ - clen); /* copy */
398 clen += strlen(t); /* advance */
399 if (clen >= ERROR_BUF_SZ)
400 break;
401 }
402 if (clen < ERROR_BUF_SZ && m != NULL) {
403 xstrncpy(content + clen, m, ERROR_BUF_SZ - clen);
404 clen += strlen(m);
405 }
406 if (clen >= ERROR_BUF_SZ) {
407 clen = ERROR_BUF_SZ - 1;
408 *(content + clen) = '\0';
409 }
410 assert(clen == strlen(content));
411 if (len)
412 *len = clen;
413 xfree(mx);
414 return content;
415}
416
417#if 0 /* we use httpReply instead of a buffer now */
418const char *
9b312a19 419errorBuildBuf(ErrorState * err, int *len)
e381a13d 420{
9b312a19 421 LOCAL_ARRAY(char, buf, ERROR_BUF_SZ);
422 LOCAL_ARRAY(char, content, ERROR_BUF_SZ);
423 char *hdr;
424 int clen;
425 int tlen;
426 char *m;
b8b780a4 427 char *mx;
9b312a19 428 char *p;
fe40a877 429 const char *t;
9b312a19 430 assert(err != NULL);
431 assert(err->type > ERR_NONE && err->type < ERR_MAX);
b8b780a4 432 mx = m = xstrdup(error_text[err->type]);
9b312a19 433 clen = 0;
434 while ((p = strchr(m, '%'))) {
435 *p = '\0'; /* terminate */
436 xstrncpy(content + clen, m, ERROR_BUF_SZ - clen); /* copy */
437 clen += (p - m); /* advance */
438 if (clen >= ERROR_BUF_SZ)
439 break;
440 p++;
441 m = p + 1;
442 t = errorConvert(*p, err); /* convert */
443 xstrncpy(content + clen, t, ERROR_BUF_SZ - clen); /* copy */
444 clen += strlen(t); /* advance */
445 if (clen >= ERROR_BUF_SZ)
446 break;
447 }
448 if (clen < ERROR_BUF_SZ && m != NULL) {
449 xstrncpy(content + clen, m, ERROR_BUF_SZ - clen);
450 clen += strlen(m);
451 }
452 if (clen >= ERROR_BUF_SZ) {
453 clen = ERROR_BUF_SZ - 1;
454 *(content + clen) = '\0';
455 }
456 assert(clen == strlen(content));
457 hdr = httpReplyHeader((double) 1.0,
458 err->http_status,
b8d8561b 459 "text/html",
9b312a19 460 clen,
437e2060 461 0, /* no LMT for error pages */
9b312a19 462 squid_curtime);
463 tlen = snprintf(buf, ERROR_BUF_SZ, "%s\r\n%s", hdr, content);
464 if (len)
465 *len = tlen;
b8b780a4 466 xfree(mx);
9b312a19 467 return buf;
e381a13d 468}
cb69b4c7 469#endif