]>
Commit | Line | Data |
---|---|---|
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 | 34 | const 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 | 56 | static char *error_text[ERR_MAX]; |
57 | ||
f5b8bbc4 | 58 | static void errorStateFree(ErrorState * err); |
59 | static char *errorConvert(char token, ErrorState * err); | |
60 | static char *errorBuildBuf(ErrorState * err, int *len); | |
9b312a19 | 61 | static CWCB errorSendComplete; |
1e74c110 | 62 | |
b8d8561b | 63 | void |
0673c0ba | 64 | errorInitialize(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 | 89 | static void |
90 | errorStateFree(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 | 99 | static char * |
100 | errorConvert(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 | 201 | static char * |
202 | errorBuildBuf(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 | 253 | void |
254 | errorSend(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 | |
266 | void | |
b716a8ad | 267 | errorAppendEntry(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 | 281 | static void |
282 | errorSendComplete(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 | } |