]> git.ipfire.org Git - thirdparty/squid.git/blame - src/errorpage.cc
comments
[thirdparty/squid.git] / src / errorpage.cc
CommitLineData
4a9a952e 1
30a4f2a8 2/*
ea3a2a69 3 * $Id: errorpage.cc,v 1.87 1997/10/26 02:35:30 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
44a47c6e 32#include "squid.h"
1e74c110 33
9b312a19 34const char *err_string[] =
1e74c110 35{
9b312a19 36 "ERR_NONE",
37 "ERR_READ_TIMEOUT",
38 "ERR_LIFETIME_EXP",
9b312a19 39 "ERR_READ_ERROR",
40 "ERR_WRITE_ERROR",
41 "ERR_CLIENT_ABORT",
42 "ERR_CONNECT_FAIL",
43 "ERR_INVALID_REQ",
44 "ERR_UNSUP_REQ",
45 "ERR_INVALID_URL",
46 "ERR_SOCKET_FAILURE",
47 "ERR_DNS_FAIL",
9b312a19 48 "ERR_CANNOT_FORWARD",
49 "ERR_NO_RELAY",
9b312a19 50 "ERR_ZERO_SIZE_OBJECT",
51 "ERR_FTP_DISABLED",
9b312a19 52 "ERR_ACCESS_DENIED",
53 "ERR_MAX"
1e74c110 54};
55
9b312a19 56static char *error_text[ERR_MAX];
57
f5b8bbc4 58static void errorStateFree(ErrorState * err);
59static char *errorConvert(char token, ErrorState * err);
60static char *errorBuildBuf(ErrorState * err, int *len);
9b312a19 61static CWCB errorSendComplete;
1e74c110 62
b8d8561b 63void
0673c0ba 64errorInitialize(void)
fa966b74 65{
9b312a19 66 err_type i;
67 int fd;
68 char path[MAXPATHLEN];
69 struct stat sb;
70 assert(sizeof(err_string) == (ERR_MAX + 1) * 4);
71 for (i = ERR_NONE + 1; i < ERR_MAX; i++) {
72 snprintf(path, MAXPATHLEN, "%s/%s",
73 Config.errorDirectory, err_string[i]);
74 fd = file_open(path, O_RDONLY, NULL, NULL);
75 if (fd < 0) {
76 debug(4, 0) ("errorInitialize: %s: %s\n", path, xstrerror());
77 fatal("Failed to open error text file");
78 }
79 if (fstat(fd, &sb) < 0)
80 fatal_dump("stat() failed on error text file");
81 safe_free(error_text[i]);
f787fb1e 82 error_text[i] = xcalloc(sb.st_size + 1, 1);
9b312a19 83 if (read(fd, error_text[i], sb.st_size) != sb.st_size)
84 fatal_dump("failed to fully read error text file");
85 file_close(fd);
1e74c110 86 }
6eb42cae 87}
88
9b312a19 89static void
90errorStateFree(ErrorState * err)
6eb42cae 91{
9b312a19 92 requestUnlink(err->request);
93 safe_free(err->redirect_url);
94 safe_free(err->url);
95 cbdataFree(err);
1e74c110 96}
8213067d 97
2658f489 98#define CVT_BUF_SZ 512
9b312a19 99static char *
100errorConvert(char token, ErrorState * err)
8213067d 101{
9b312a19 102 char *p = NULL;
2658f489 103 request_t *r = err->request;
104 static char buf[CVT_BUF_SZ];
9b312a19 105 switch (token) {
106 case 'U':
2658f489 107 p = r ? urlCanonicalClean(r) : err->url;
9b312a19 108 break;
2658f489 109 case 'H':
110 p = r ? r->host : "[unknown host]";
111 break;
112 case 'p':
113 if (r) {
437e2060 114 snprintf(buf, CVT_BUF_SZ, "%d", (int) r->port);
115 p = buf;
2658f489 116 } else {
437e2060 117 p = "[unknown port]";
2658f489 118 }
119 break;
120 case 'P':
121 p = r ? (char *) ProtocolStr[r->protocol] : "[unkown protocol]";
122 break;
123 case 'M':
124 p = r ? (char *) RequestMethodStr[r->method] : "[unkown method]";
125 break;
126 case 'z':
f787fb1e 127 if (err->dnsserver_msg)
128 p = err->dnsserver_msg;
129 else
130 p = "UNKNOWN\n";
2658f489 131 break;
042461c3 132 case 'e':
c45ed9ad 133 snprintf(buf, CVT_BUF_SZ, "%d", err->xerrno);
56878878 134 p = buf;
042461c3 135 break;
136 case 'E':
c45ed9ad 137 snprintf(buf, CVT_BUF_SZ, "(%d) %s", err->xerrno, strerror(err->xerrno));
ceab4c00 138 p = buf;
03d7b07f 139 break;
140 case 'w':
ceab4c00 141 if (Config.adminEmail) {
142 snprintf(buf, CVT_BUF_SZ, "%s", Config.adminEmail);
143 p = buf;
144 } else
145 p = "UNKNOWN";
03d7b07f 146 break;
147 case 'h':
148 snprintf(buf, CVT_BUF_SZ, "%s", getMyHostname());
ceab4c00 149 p = buf;
042461c3 150 break;
f6aa1a5c 151 case 't':
f787fb1e 152 xstrncpy(buf, mkhttpdlogtime(&squid_curtime), 128);
153 p = buf;
154 break;
155 case 'L':
f8291f8f 156 if (Config.errHtmlText) {
157 snprintf(buf, CVT_BUF_SZ, "%s", Config.errHtmlText);
158 p = buf;
159 } else
160 p = "[not available]";
f787fb1e 161 break;
162 case 'i':
163 snprintf(buf, CVT_BUF_SZ, "%s", inet_ntoa(err->src_addr));
164 p = buf;
f6aa1a5c 165 break;
f787fb1e 166 case 'I':
167 if (err->host) {
168 snprintf(buf, CVT_BUF_SZ, "%s", err->host);
169 p = buf;
170 } else
171 p = "unknown\n";
172 break;
f8291f8f 173 case 'T':
174 snprintf(buf, CVT_BUF_SZ, "%s", mkrfc1123(squid_curtime));
175 p = buf;
176 break;
2658f489 177/*
f6aa1a5c 178 * e - errno x
56878878 179 * E - strerror() x
f787fb1e 180 * t - local time x
f8291f8f 181 * T - UTC x
437e2060 182 * c - Squid error code
f8291f8f 183 * I - server IP address x
184 * i - client IP address x
185 * L - HREF link for more info/contact x
56878878 186 * w - cachemgr email address x
187 * h - cache hostname x
437e2060 188 * d - seconds elapsed since request received
56878878 189 * p - URL port # x
437e2060 190 */
9b312a19 191 default:
192 p = "%UNKNOWN%";
193 break;
194 }
195 if (p == NULL)
196 p = "<NULL>";
e102ebda 197 debug(4, 3) ("errorConvert: %%%c --> '%s'\n", token, p);
9b312a19 198 return p;
8213067d 199}
e381a13d 200
9b312a19 201static char *
202errorBuildBuf(ErrorState * err, int *len)
e381a13d 203{
9b312a19 204 LOCAL_ARRAY(char, buf, ERROR_BUF_SZ);
205 LOCAL_ARRAY(char, content, ERROR_BUF_SZ);
206 char *hdr;
207 int clen;
208 int tlen;
209 char *m;
b8b780a4 210 char *mx;
9b312a19 211 char *p;
212 char *t;
213 assert(err != NULL);
214 assert(err->type > ERR_NONE && err->type < ERR_MAX);
b8b780a4 215 mx = m = xstrdup(error_text[err->type]);
9b312a19 216 clen = 0;
217 while ((p = strchr(m, '%'))) {
218 *p = '\0'; /* terminate */
219 xstrncpy(content + clen, m, ERROR_BUF_SZ - clen); /* copy */
220 clen += (p - m); /* advance */
221 if (clen >= ERROR_BUF_SZ)
222 break;
223 p++;
224 m = p + 1;
225 t = errorConvert(*p, err); /* convert */
226 xstrncpy(content + clen, t, ERROR_BUF_SZ - clen); /* copy */
227 clen += strlen(t); /* advance */
228 if (clen >= ERROR_BUF_SZ)
229 break;
230 }
231 if (clen < ERROR_BUF_SZ && m != NULL) {
232 xstrncpy(content + clen, m, ERROR_BUF_SZ - clen);
233 clen += strlen(m);
234 }
235 if (clen >= ERROR_BUF_SZ) {
236 clen = ERROR_BUF_SZ - 1;
237 *(content + clen) = '\0';
238 }
239 assert(clen == strlen(content));
240 hdr = httpReplyHeader((double) 1.0,
241 err->http_status,
b8d8561b 242 "text/html",
9b312a19 243 clen,
437e2060 244 0, /* no LMT for error pages */
9b312a19 245 squid_curtime);
246 tlen = snprintf(buf, ERROR_BUF_SZ, "%s\r\n%s", hdr, content);
247 if (len)
248 *len = tlen;
b8b780a4 249 xfree(mx);
9b312a19 250 return buf;
e381a13d 251}
e81957b7 252
9b312a19 253void
254errorSend(int fd, ErrorState * err)
e81957b7 255{
9b312a19 256 char *buf;
257 int len;
6a54c60e 258 debug(4, 3) ("errorSend: FD %d, err=%p\n", fd, err);
9b312a19 259 assert(fd >= 0);
260 buf = errorBuildBuf(err, &len);
261 cbdataAdd(err);
262 cbdataLock(err);
263 comm_write(fd, xstrdup(buf), len, errorSendComplete, err, xfree);
e81957b7 264}
0a21bd84 265
266void
b716a8ad 267errorAppendEntry(StoreEntry * entry, ErrorState * err)
9b312a19 268{
269 char *buf;
e3f80962 270 MemObject *mem = entry->mem_obj;
9b312a19 271 int len;
272 assert(entry->store_status == STORE_PENDING);
273 buf = errorBuildBuf(err, &len);
274 storeAppend(entry, buf, len);
e3f80962 275 if (mem)
276 mem->reply->code = err->http_status;
9b312a19 277}
278
4f3190fe 279/* If there is a callback, the callback is responsible to close
280 * the FD, otherwise we do it ourseves. */
9b312a19 281static void
282errorSendComplete(int fd, char *buf, int size, int errflag, void *data)
0a21bd84 283{
9b312a19 284 ErrorState *err = data;
6a54c60e 285 debug(4, 3) ("errorSendComplete: FD %d, size=%d\n", fd, size);
ea3a2a69 286 if (errflag != COMM_ERR_CLOSING) {
287 if (err->callback)
288 err->callback(fd, err->callback_data, size);
289 else
290 comm_close(fd);
291 }
9b312a19 292 cbdataUnlock(err);
293 errorStateFree(err);
0a21bd84 294}