]>
Commit | Line | Data |
---|---|---|
4a9a952e | 1 | |
30a4f2a8 | 2 | /* |
59ea0962 | 3 | * $Id: errorpage.cc,v 1.80 1997/10/21 03:33:41 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 | ||
58 | static void errorStateFree _PARAMS((ErrorState * err)); | |
59 | static char *errorConvert _PARAMS((char token, ErrorState * err)); | |
60 | static char *errorBuildBuf _PARAMS((ErrorState * err, int *len)); | |
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]); | |
59ea0962 | 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': | |
127 | p = err->dnsserver_msg; | |
128 | break; | |
042461c3 | 129 | case 'e': |
130 | snprintf(buf, CVT_BUF_SZ, "%d", err->errno); | |
56878878 | 131 | p = buf; |
042461c3 | 132 | break; |
133 | case 'E': | |
8350fe9b | 134 | snprintf(buf, CVT_BUF_SZ, "(%d) %s", err->errno, strerror(err->errno)); |
ceab4c00 | 135 | p = buf; |
03d7b07f | 136 | break; |
137 | case 'w': | |
ceab4c00 | 138 | if (Config.adminEmail) { |
139 | snprintf(buf, CVT_BUF_SZ, "%s", Config.adminEmail); | |
140 | p = buf; | |
141 | } else | |
142 | p = "UNKNOWN"; | |
03d7b07f | 143 | break; |
144 | case 'h': | |
145 | snprintf(buf, CVT_BUF_SZ, "%s", getMyHostname()); | |
ceab4c00 | 146 | p = buf; |
042461c3 | 147 | break; |
2658f489 | 148 | /* |
56878878 | 149 | * e - errno x |
150 | * E - strerror() x | |
437e2060 | 151 | * t - local time |
152 | * T - UTC | |
153 | * c - Squid error code | |
154 | * I - server IP address | |
155 | * i - client IP address | |
156 | * L - HREF link for more info/contact | |
56878878 | 157 | * w - cachemgr email address x |
158 | * h - cache hostname x | |
437e2060 | 159 | * d - seconds elapsed since request received |
56878878 | 160 | * p - URL port # x |
437e2060 | 161 | */ |
9b312a19 | 162 | default: |
163 | p = "%UNKNOWN%"; | |
164 | break; | |
165 | } | |
166 | if (p == NULL) | |
167 | p = "<NULL>"; | |
e102ebda | 168 | debug(4, 3) ("errorConvert: %%%c --> '%s'\n", token, p); |
9b312a19 | 169 | return p; |
8213067d | 170 | } |
e381a13d | 171 | |
9b312a19 | 172 | static char * |
173 | errorBuildBuf(ErrorState * err, int *len) | |
e381a13d | 174 | { |
9b312a19 | 175 | LOCAL_ARRAY(char, buf, ERROR_BUF_SZ); |
176 | LOCAL_ARRAY(char, content, ERROR_BUF_SZ); | |
177 | char *hdr; | |
178 | int clen; | |
179 | int tlen; | |
180 | char *m; | |
b8b780a4 | 181 | char *mx; |
9b312a19 | 182 | char *p; |
183 | char *t; | |
184 | assert(err != NULL); | |
185 | assert(err->type > ERR_NONE && err->type < ERR_MAX); | |
b8b780a4 | 186 | mx = m = xstrdup(error_text[err->type]); |
9b312a19 | 187 | clen = 0; |
188 | while ((p = strchr(m, '%'))) { | |
189 | *p = '\0'; /* terminate */ | |
190 | xstrncpy(content + clen, m, ERROR_BUF_SZ - clen); /* copy */ | |
191 | clen += (p - m); /* advance */ | |
192 | if (clen >= ERROR_BUF_SZ) | |
193 | break; | |
194 | p++; | |
195 | m = p + 1; | |
196 | t = errorConvert(*p, err); /* convert */ | |
197 | xstrncpy(content + clen, t, ERROR_BUF_SZ - clen); /* copy */ | |
198 | clen += strlen(t); /* advance */ | |
199 | if (clen >= ERROR_BUF_SZ) | |
200 | break; | |
201 | } | |
202 | if (clen < ERROR_BUF_SZ && m != NULL) { | |
203 | xstrncpy(content + clen, m, ERROR_BUF_SZ - clen); | |
204 | clen += strlen(m); | |
205 | } | |
206 | if (clen >= ERROR_BUF_SZ) { | |
207 | clen = ERROR_BUF_SZ - 1; | |
208 | *(content + clen) = '\0'; | |
209 | } | |
210 | assert(clen == strlen(content)); | |
211 | hdr = httpReplyHeader((double) 1.0, | |
212 | err->http_status, | |
b8d8561b | 213 | "text/html", |
9b312a19 | 214 | clen, |
437e2060 | 215 | 0, /* no LMT for error pages */ |
9b312a19 | 216 | squid_curtime); |
217 | tlen = snprintf(buf, ERROR_BUF_SZ, "%s\r\n%s", hdr, content); | |
218 | if (len) | |
219 | *len = tlen; | |
b8b780a4 | 220 | xfree(mx); |
9b312a19 | 221 | return buf; |
e381a13d | 222 | } |
e81957b7 | 223 | |
9b312a19 | 224 | void |
225 | errorSend(int fd, ErrorState * err) | |
e81957b7 | 226 | { |
9b312a19 | 227 | char *buf; |
228 | int len; | |
6a54c60e | 229 | debug(4, 3) ("errorSend: FD %d, err=%p\n", fd, err); |
9b312a19 | 230 | assert(fd >= 0); |
231 | buf = errorBuildBuf(err, &len); | |
232 | cbdataAdd(err); | |
233 | cbdataLock(err); | |
234 | comm_write(fd, xstrdup(buf), len, errorSendComplete, err, xfree); | |
e81957b7 | 235 | } |
0a21bd84 | 236 | |
237 | void | |
b716a8ad | 238 | errorAppendEntry(StoreEntry * entry, ErrorState * err) |
9b312a19 | 239 | { |
240 | char *buf; | |
e3f80962 | 241 | MemObject *mem = entry->mem_obj; |
9b312a19 | 242 | int len; |
243 | assert(entry->store_status == STORE_PENDING); | |
244 | buf = errorBuildBuf(err, &len); | |
245 | storeAppend(entry, buf, len); | |
e3f80962 | 246 | if (mem) |
247 | mem->reply->code = err->http_status; | |
9b312a19 | 248 | } |
249 | ||
250 | static void | |
251 | errorSendComplete(int fd, char *buf, int size, int errflag, void *data) | |
0a21bd84 | 252 | { |
9b312a19 | 253 | ErrorState *err = data; |
6a54c60e | 254 | debug(4, 3) ("errorSendComplete: FD %d, size=%d\n", fd, size); |
9b312a19 | 255 | if (err->callback) |
256 | err->callback(fd, err->callback_data, size); | |
257 | cbdataUnlock(err); | |
258 | errorStateFree(err); | |
1b9cbc64 | 259 | comm_close(fd); |
0a21bd84 | 260 | } |