]> git.ipfire.org Git - thirdparty/squid.git/blame - src/mime.cc
SSL->HTTP gatewaying support by Benno Rice
[thirdparty/squid.git] / src / mime.cc
CommitLineData
067bea91 1
30a4f2a8 2/*
1f7c9178 3 * $Id: mime.cc,v 1.100 2001/04/14 00:03:23 hno Exp $
30a4f2a8 4 *
5 * DEBUG: section 25 MIME Parsing
6 * AUTHOR: Harvest Derived
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 9 * ----------------------------------------------------------
30a4f2a8 10 *
2b6662ba 11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
30a4f2a8 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
cbdec147 32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 33 *
6eb42cae 34 */
ed43818f 35
44a47c6e 36#include "squid.h"
090089c4 37
09610784 38#define GET_HDR_SZ 1024
39
812ed90c 40typedef struct _mime_entry {
41 char *pattern;
42 regex_t compiled_pattern;
43 char *icon;
44 char *content_type;
45 char *content_encoding;
46 char transfer_mode;
0cdcddb9 47 unsigned int view_option:1, download_option:1;
812ed90c 48 struct _mime_entry *next;
49} mimeEntry;
50
51static mimeEntry *MimeTable = NULL;
00fa6528 52static mimeEntry **MimeTableTail = &MimeTable;
812ed90c 53
f5b8bbc4 54static void mimeLoadIconFile(const char *icon);
365cb147 55
4e41e277 56/* returns a pointer to a field-value of the first matching field-name */
b8d8561b 57char *
0ee4272b 58mime_get_header(const char *mime, const char *name)
4e41e277 59{
60 return mime_get_header_field(mime, name, NULL);
61}
62
63/*
64 * returns a pointer to a field-value of the first matching field-name where
65 * field-value matches prefix if any
66 */
67char *
68mime_get_header_field(const char *mime, const char *name, const char *prefix)
7f2e38dc 69{
95d659f0 70 LOCAL_ARRAY(char, header, GET_HDR_SZ);
0ee4272b 71 const char *p = NULL;
6eb42cae 72 char *q = NULL;
7f2e38dc 73 char got = 0;
4e41e277 74 const int namelen = name ? strlen(name) : 0;
75 const int preflen = prefix ? strlen(prefix) : 0;
e274cdf3 76 int l;
7f2e38dc 77
18c36ffc 78 if (NULL == mime)
09610784 79 return NULL;
18c36ffc 80 assert(NULL != name);
09610784 81
a3d5953d 82 debug(25, 5) ("mime_get_header: looking for '%s'\n", name);
6eb42cae 83
7f2e38dc 84 for (p = mime; *p; p += strcspn(p, "\n\r")) {
85 if (strcmp(p, "\r\n\r\n") == 0 || strcmp(p, "\n\n") == 0)
86 return NULL;
b6a2f15e 87 while (xisspace(*p))
7f2e38dc 88 p++;
6eb42cae 89 if (strncasecmp(p, name, namelen))
90 continue;
b6a2f15e 91 if (!xisspace(p[namelen]) && p[namelen] != ':')
6eb42cae 92 continue;
e274cdf3 93 l = strcspn(p, "\n\r") + 1;
94 if (l > GET_HDR_SZ)
b785f8ca 95 l = GET_HDR_SZ;
e274cdf3 96 xstrncpy(header, p, l);
a3d5953d 97 debug(25, 5) ("mime_get_header: checking '%s'\n", header);
6eb42cae 98 q = header;
99 q += namelen;
100 if (*q == ':')
101 q++, got = 1;
b6a2f15e 102 while (xisspace(*q))
6eb42cae 103 q++, got = 1;
4e41e277 104 if (got && prefix) {
105 /* we could process list entries here if we had strcasestr(). */
106 /* make sure we did not match a part of another field-value */
b6a2f15e 107 got = !strncasecmp(q, prefix, preflen) && !xisalpha(q[preflen]);
4e41e277 108 }
6eb42cae 109 if (got) {
a3d5953d 110 debug(25, 5) ("mime_get_header: returning '%s'\n", q);
6eb42cae 111 return q;
7f2e38dc 112 }
113 }
114 return NULL;
115}
116
2334c194 117size_t
118headersEnd(const char *mime, size_t l)
119{
120 size_t e = 0;
121 int state = 0;
122 while (e < l && state < 3) {
1afe05c5 123 switch (state) {
124 case 0:
125 if ('\n' == mime[e])
126 state = 1;
127 break;
128 case 1:
129 if ('\r' == mime[e])
130 state = 2;
131 else if ('\n' == mime[e])
132 state = 3;
133 else
134 state = 0;
135 break;
136 case 2:
6123e071 137 if ('\r' == mime[e]) /* ignore repeated CR */
138 (void) 0;
139 else if ('\n' == mime[e])
1afe05c5 140 state = 3;
141 else
142 state = 0;
143 break;
144 default:
145 break;
146 }
147 e++;
2334c194 148 }
149 if (3 == state)
1afe05c5 150 return e;
2334c194 151 return 0;
152}
30a4f2a8 153
63259c34 154const char *
155mime_get_auth(const char *hdr, const char *auth_scheme, const char **auth_field)
156{
157 char *auth_hdr;
158 char *t;
2ac76861 159 if (auth_field)
160 *auth_field = NULL;
63259c34 161 if (hdr == NULL)
162 return NULL;
163 if ((auth_hdr = mime_get_header(hdr, "Authorization")) == NULL)
164 return NULL;
2ac76861 165 if (auth_field)
166 *auth_field = auth_hdr;
63259c34 167 if ((t = strtok(auth_hdr, " \t")) == NULL)
168 return NULL;
169 if (strcasecmp(t, auth_scheme) != 0)
170 return NULL;
171 if ((t = strtok(NULL, " \t")) == NULL)
172 return NULL;
173 return base64_decode(t);
174}
175
2a1ca944 176static mimeEntry *
177mimeGetEntry(const char *fn, int skip_encodings)
812ed90c 178{
179 mimeEntry *m;
2a1ca944 180 char *t;
181 char *name = xstrdup(fn);
0cdcddb9 182 try_again:
812ed90c 183 for (m = MimeTable; m; m = m->next) {
2a1ca944 184 if (regexec(&m->compiled_pattern, name, 0, 0, 0) == 0)
812ed90c 185 break;
186 }
5248dfb8 187 if (!skip_encodings)
188 (void) 0;
189 else if (m == NULL)
190 (void) 0;
191 else if (strcmp(m->content_type, dash_str))
192 (void) 0;
193 else if (!strcmp(m->content_encoding, dash_str))
194 (void) 0;
195 else {
2a1ca944 196 /* Assume we matched /\.\w$/ and cut off the last extension */
197 if ((t = strrchr(name, '.'))) {
198 *t = '\0';
199 goto try_again;
200 }
201 /* What? A encoding without a extension? */
0cdcddb9 202 m = NULL;
2a1ca944 203 }
204 xfree(name);
205 return m;
206}
207
208char *
209mimeGetIcon(const char *fn)
210{
211 mimeEntry *m = mimeGetEntry(fn, 1);
812ed90c 212 if (m == NULL)
213 return NULL;
214 if (!strcmp(m->icon, dash_str))
215 return NULL;
216 return m->icon;
217}
218
d20b1cd0 219const char *
4162ee3b 220mimeGetIconURL(const char *fn)
221{
222 char *icon = mimeGetIcon(fn);
4162ee3b 223 if (icon == NULL)
d20b1cd0 224 return null_string;
1da5651f 225 return internalLocalUri("/squid-internal-static/icons/", icon);
4162ee3b 226}
227
812ed90c 228char *
229mimeGetContentType(const char *fn)
230{
2a1ca944 231 mimeEntry *m = mimeGetEntry(fn, 1);
812ed90c 232 if (m == NULL)
233 return NULL;
234 if (!strcmp(m->content_type, dash_str))
235 return NULL;
236 return m->content_type;
237}
238
239char *
240mimeGetContentEncoding(const char *fn)
241{
2a1ca944 242 mimeEntry *m = mimeGetEntry(fn, 0);
812ed90c 243 if (m == NULL)
244 return NULL;
245 if (!strcmp(m->content_encoding, dash_str))
246 return NULL;
247 return m->content_encoding;
248}
249
250char
251mimeGetTransferMode(const char *fn)
252{
2a1ca944 253 mimeEntry *m = mimeGetEntry(fn, 0);
812ed90c 254 return m ? m->transfer_mode : 'I';
255}
256
2a1ca944 257int
258mimeGetDownloadOption(const char *fn)
259{
260 mimeEntry *m = mimeGetEntry(fn, 1);
261 return m ? m->download_option : 0;
262}
263
264int
265mimeGetViewOption(const char *fn)
266{
267 mimeEntry *m = mimeGetEntry(fn, 0);
268 return m ? m->view_option : 0;
269}
270
00fa6528 271/* Initializes/reloads the mime table
272 * Note: Due to Solaris STDIO problems the caller should NOT
273 * call mimeFreeMemory on reconfigure. This way, if STDIO
274 * fails we at least have the old copy loaded.
275 */
812ed90c 276void
277mimeInit(char *filename)
278{
279 FILE *fp;
280 char buf[BUFSIZ];
281 char chopbuf[BUFSIZ];
282 char *t;
283 char *pattern;
284 char *icon;
285 char *type;
286 char *encoding;
287 char *mode;
2a1ca944 288 char *option;
289 int view_option;
290 int download_option;
812ed90c 291 regex_t re;
292 mimeEntry *m;
293 int re_flags = REG_EXTENDED | REG_NOSUB | REG_ICASE;
294 if (filename == NULL)
295 return;
296 if ((fp = fopen(filename, "r")) == NULL) {
a3d5953d 297 debug(50, 1) ("mimeInit: %s: %s\n", filename, xstrerror());
812ed90c 298 return;
299 }
c4aefe96 300#if defined (_SQUID_CYGWIN_)
301 setmode(fileno(fp), O_TEXT);
302#endif
00fa6528 303 mimeFreeMemory();
812ed90c 304 while (fgets(buf, BUFSIZ, fp)) {
305 if ((t = strchr(buf, '#')))
306 *t = '\0';
76f87348 307 if ((t = strchr(buf, '\r')))
308 *t = '\0';
309 if ((t = strchr(buf, '\n')))
310 *t = '\0';
812ed90c 311 if (buf[0] == '\0')
312 continue;
313 xstrncpy(chopbuf, buf, BUFSIZ);
314 if ((pattern = strtok(chopbuf, w_space)) == NULL) {
a3d5953d 315 debug(25, 1) ("mimeInit: parse error: '%s'\n", buf);
812ed90c 316 continue;
317 }
318 if ((type = strtok(NULL, w_space)) == NULL) {
a3d5953d 319 debug(25, 1) ("mimeInit: parse error: '%s'\n", buf);
812ed90c 320 continue;
321 }
322 if ((icon = strtok(NULL, w_space)) == NULL) {
a3d5953d 323 debug(25, 1) ("mimeInit: parse error: '%s'\n", buf);
812ed90c 324 continue;
325 }
326 if ((encoding = strtok(NULL, w_space)) == NULL) {
a3d5953d 327 debug(25, 1) ("mimeInit: parse error: '%s'\n", buf);
812ed90c 328 continue;
329 }
330 if ((mode = strtok(NULL, w_space)) == NULL) {
a3d5953d 331 debug(25, 1) ("mimeInit: parse error: '%s'\n", buf);
812ed90c 332 continue;
333 }
0cdcddb9 334 download_option = 0;
335 view_option = 0;
2a1ca944 336 while ((option = strtok(NULL, w_space)) != NULL) {
0cdcddb9 337 if (!strcmp(option, "+download"))
2a1ca944 338 download_option = 1;
0cdcddb9 339 else if (!strcmp(option, "+view"))
2a1ca944 340 view_option = 1;
0cdcddb9 341 else
2a1ca944 342 debug(25, 1) ("mimeInit: unknown option: '%s' (%s)\n", buf, option);
343 }
812ed90c 344 if (regcomp(&re, pattern, re_flags) != 0) {
a3d5953d 345 debug(25, 1) ("mimeInit: regcomp error: '%s'\n", buf);
812ed90c 346 continue;
347 }
348 m = xcalloc(1, sizeof(mimeEntry));
349 m->pattern = xstrdup(pattern);
350 m->content_type = xstrdup(type);
351 m->icon = xstrdup(icon);
352 m->content_encoding = xstrdup(encoding);
353 m->compiled_pattern = re;
354 if (!strcasecmp(mode, "ascii"))
355 m->transfer_mode = 'A';
356 else if (!strcasecmp(mode, "text"))
357 m->transfer_mode = 'A';
358 else
359 m->transfer_mode = 'I';
2a1ca944 360 m->view_option = view_option;
361 m->download_option = download_option;
812ed90c 362 *MimeTableTail = m;
363 MimeTableTail = &m->next;
4cd746ee 364 debug(25, 5) ("mimeInit: added '%s'\n", buf);
812ed90c 365 }
337d4867 366 fclose(fp);
8ca66e48 367 /*
368 * Create Icon StoreEntry's
369 */
370 for (m = MimeTable; m != NULL; m = m->next)
371 mimeLoadIconFile(m->icon);
f53b06f9 372 debug(25, 1) ("Loaded Icons.\n");
812ed90c 373}
365cb147 374
c68e9c6b 375void
376mimeFreeMemory(void)
377{
378 mimeEntry *m;
379 while ((m = MimeTable)) {
380 MimeTable = m->next;
381 safe_free(m->pattern);
382 safe_free(m->content_type);
383 safe_free(m->icon);
384 safe_free(m->content_encoding);
385 regfree(&m->compiled_pattern);
386 safe_free(m);
387 }
388 MimeTableTail = &MimeTable;
389}
390
365cb147 391static void
392mimeLoadIconFile(const char *icon)
393{
f9e5a344 394 int fd;
395 int n;
92695e5e 396 request_flags flags;
f9e5a344 397 struct stat sb;
398 StoreEntry *e;
399 LOCAL_ARRAY(char, path, MAXPATHLEN);
400 LOCAL_ARRAY(char, url, MAX_URL);
401 char *buf;
4cd746ee 402 const char *type = mimeGetContentType(icon);
b6a2f15e 403 HttpReply *reply;
ccf44862 404 http_version_t version;
4cd746ee 405 if (type == NULL)
406 fatal("Unknown icon format while reading mime.conf\n");
1da5651f 407 buf = internalLocalUri("/squid-internal-static/icons/", icon);
408 xstrncpy(url, buf, MAX_URL);
08e5d64f 409 if (storeGetPublic(url, METHOD_GET))
f9e5a344 410 return;
411 snprintf(path, MAXPATHLEN, "%s/%s", Config.icons.directory, icon);
c4aefe96 412 fd = file_open(path, O_RDONLY | O_BINARY);
f9e5a344 413 if (fd < 0) {
414 debug(25, 0) ("mimeLoadIconFile: %s: %s\n", path, xstrerror());
415 return;
416 }
417 if (fstat(fd, &sb) < 0) {
418 debug(50, 0) ("mimeLoadIconFile: FD %d: fstat: %s\n", fd, xstrerror());
419 return;
420 }
92695e5e 421 flags = null_request_flags;
422 flags.cachable = 1;
f9e5a344 423 e = storeCreateEntry(url,
424 url,
c998d7c8 425 flags,
f9e5a344 426 METHOD_GET);
427 assert(e != NULL);
4d19abd1 428 storeSetPublicKey(e);
a9f31179 429 storeBuffer(e);
f9e5a344 430 e->mem_obj->request = requestLink(urlParse(METHOD_GET, url));
b6a2f15e 431 httpReplyReset(reply = e->mem_obj->reply);
bffee5af 432 httpBuildVersion(&version, 1, 0);
ccf44862 433 httpReplySetHeaders(reply, version, HTTP_OK, NULL,
b6a2f15e 434 type, (int) sb.st_size, sb.st_mtime, -1);
435 reply->cache_control = httpHdrCcCreate();
436 httpHdrCcSetMaxAge(reply->cache_control, 86400);
437 httpHeaderPutCc(&reply->header, reply->cache_control);
438 httpReplySwapOut(reply, e);
22c59550 439 reply->hdr_sz = e->mem_obj->inmem_hi; /* yuk */
cb69b4c7 440 /* read the file into the buffer and append it to store */
7021844c 441 buf = memAllocate(MEM_4K_BUF);
1f7c9178 442 while ((n = FD_READ_METHOD(fd, buf, 4096)) > 0)
f9e5a344 443 storeAppend(e, buf, n);
444 file_close(fd);
a9f31179 445 EBIT_SET(e->flags, ENTRY_SPECIAL);
446 storeBufferFlush(e);
f9e5a344 447 storeComplete(e);
448 storeTimestampsSet(e);
f53b06f9 449 debug(25, 3) ("Loaded icon %s\n", url);
78f1250a 450 storeUnlockObject(e);
db1cd23c 451 memFree(buf, MEM_4K_BUF);
365cb147 452}