]> git.ipfire.org Git - thirdparty/squid.git/blob - src/mime.cc
Enable source-formatting tools to collapse multiple whitelines in the source to one.
[thirdparty/squid.git] / src / mime.cc
1
2 /*
3 * $Id$
4 *
5 * DEBUG: section 25 MIME Parsing and Internal Icons
6 * AUTHOR: Harvest Derived
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
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.
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
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
36 #include "squid.h"
37 #include "fde.h"
38 #include "globals.h"
39 #include "HttpHdrCc.h"
40 #include "HttpReply.h"
41 #include "HttpRequest.h"
42 #include "MemBuf.h"
43 #include "MemObject.h"
44 #include "protos.h"
45 #include "Store.h"
46 #include "StoreClient.h"
47
48 #if HAVE_SYS_STAT_H
49 #include <sys/stat.h>
50 #endif
51
52 #define GET_HDR_SZ 1024
53
54 class MimeIcon : public StoreClient
55 {
56
57 public:
58 MimeIcon ();
59 ~MimeIcon ();
60 void setName (char const *);
61 char const * getName () const;
62 void _free();
63 void load();
64 void created (StoreEntry *newEntry);
65
66 private:
67 char *icon;
68 char *url;
69 };
70
71 class mimeEntry
72 {
73
74 public:
75 void *operator new (size_t byteCount);
76 void operator delete (void *address);
77
78 char *pattern;
79 regex_t compiled_pattern;
80 char *icon;
81 char *content_type;
82 char *content_encoding;
83 char transfer_mode;
84
85 unsigned int view_option:1;
86 unsigned int download_option:1;
87
88 mimeEntry *next;
89 MimeIcon theIcon;
90 };
91
92 static mimeEntry *MimeTable = NULL;
93 static mimeEntry **MimeTableTail = &MimeTable;
94
95 void *
96 mimeEntry::operator new (size_t byteCount)
97 {
98 return xcalloc(1, byteCount);
99 }
100
101 void
102 mimeEntry::operator delete (void *address)
103 {
104 safe_free (address);
105 }
106
107 static mimeEntry *
108 mimeGetEntry(const char *fn, int skip_encodings)
109 {
110 mimeEntry *m;
111 char *t;
112 char *name = xstrdup(fn);
113
114 do {
115 t = NULL;
116
117 for (m = MimeTable; m; m = m->next) {
118 if (regexec(&m->compiled_pattern, name, 0, 0, 0) == 0)
119 break;
120 }
121
122 if (!skip_encodings)
123 (void) 0;
124 else if (m == NULL)
125 (void) 0;
126 else if (strcmp(m->content_type, dash_str))
127 (void) 0;
128 else if (!strcmp(m->content_encoding, dash_str))
129 (void) 0;
130 else {
131 /* Assume we matched /\.\w$/ and cut off the last extension */
132 if ((t = strrchr(name, '.'))) {
133 *t = '\0';
134 } else {
135 /* What? A encoding without a extension? */
136 m = NULL;
137 }
138 }
139 } while (t);
140
141 xfree(name);
142 return m;
143 }
144
145 MimeIcon::MimeIcon () : icon (NULL), url (NULL)
146 {}
147
148 MimeIcon::~MimeIcon ()
149 {
150 _free();
151 }
152
153 void
154 MimeIcon::setName (char const *aString)
155 {
156 safe_free (icon);
157 safe_free (url);
158 icon = xstrdup (aString);
159 url = xstrdup (internalLocalUri("/squid-internal-static/icons/", icon));
160 }
161
162 char const *
163 MimeIcon::getName () const
164 {
165 return icon;
166 }
167
168 void
169 MimeIcon::_free()
170 {
171 safe_free (icon);
172 safe_free (url);
173 }
174
175
176 char const *
177 mimeGetIcon(const char *fn)
178 {
179 mimeEntry *m = mimeGetEntry(fn, 1);
180
181 if (m == NULL)
182 return NULL;
183
184 if (!strcmp(m->theIcon.getName(), dash_str))
185 return NULL;
186
187 return m->theIcon.getName();
188 }
189
190 const char *
191 mimeGetIconURL(const char *fn)
192 {
193 char const *icon = mimeGetIcon(fn);
194
195 if (icon == NULL)
196 return null_string;
197
198 if (Config.icons.use_short_names) {
199 static MemBuf mb;
200 mb.reset();
201 mb.Printf("/squid-internal-static/icons/%s", icon);
202 return mb.content();
203 } else {
204 return internalLocalUri("/squid-internal-static/icons/", icon);
205 }
206 }
207
208 char *
209 mimeGetContentType(const char *fn)
210 {
211 mimeEntry *m = mimeGetEntry(fn, 1);
212
213 if (m == NULL)
214 return NULL;
215
216 if (!strcmp(m->content_type, dash_str))
217 return NULL;
218
219 return m->content_type;
220 }
221
222 char *
223 mimeGetContentEncoding(const char *fn)
224 {
225 mimeEntry *m = mimeGetEntry(fn, 0);
226
227 if (m == NULL)
228 return NULL;
229
230 if (!strcmp(m->content_encoding, dash_str))
231 return NULL;
232
233 return m->content_encoding;
234 }
235
236 char
237 mimeGetTransferMode(const char *fn)
238 {
239 mimeEntry *m = mimeGetEntry(fn, 0);
240 return m ? m->transfer_mode : 'I';
241 }
242
243 int
244 mimeGetDownloadOption(const char *fn)
245 {
246 mimeEntry *m = mimeGetEntry(fn, 1);
247 return m ? m->download_option : 0;
248 }
249
250 int
251 mimeGetViewOption(const char *fn)
252 {
253 mimeEntry *m = mimeGetEntry(fn, 0);
254 return m ? m->view_option : 0;
255 }
256
257 /* Initializes/reloads the mime table
258 * Note: Due to Solaris STDIO problems the caller should NOT
259 * call mimeFreeMemory on reconfigure. This way, if STDIO
260 * fails we at least have the old copy loaded.
261 */
262 void
263 mimeInit(char *filename)
264 {
265 FILE *fp;
266 char buf[BUFSIZ];
267 char chopbuf[BUFSIZ];
268 char *t;
269 char *pattern;
270 char *icon;
271 char *type;
272 char *encoding;
273 char *mode;
274 char *option;
275 int view_option;
276 int download_option;
277 regex_t re;
278 mimeEntry *m;
279 int re_flags = REG_EXTENDED | REG_NOSUB | REG_ICASE;
280
281 if (filename == NULL)
282 return;
283
284 if ((fp = fopen(filename, "r")) == NULL) {
285 debugs(25, DBG_IMPORTANT, "mimeInit: " << filename << ": " << xstrerror());
286 return;
287 }
288
289 #if _SQUID_WINDOWS_
290 setmode(fileno(fp), O_TEXT);
291 #endif
292
293 mimeFreeMemory();
294
295 while (fgets(buf, BUFSIZ, fp)) {
296 if ((t = strchr(buf, '#')))
297 *t = '\0';
298
299 if ((t = strchr(buf, '\r')))
300 *t = '\0';
301
302 if ((t = strchr(buf, '\n')))
303 *t = '\0';
304
305 if (buf[0] == '\0')
306 continue;
307
308 xstrncpy(chopbuf, buf, BUFSIZ);
309
310 if ((pattern = strtok(chopbuf, w_space)) == NULL) {
311 debugs(25, DBG_IMPORTANT, "mimeInit: parse error: '" << buf << "'");
312 continue;
313 }
314
315 if ((type = strtok(NULL, w_space)) == NULL) {
316 debugs(25, DBG_IMPORTANT, "mimeInit: parse error: '" << buf << "'");
317 continue;
318 }
319
320 if ((icon = strtok(NULL, w_space)) == NULL) {
321 debugs(25, DBG_IMPORTANT, "mimeInit: parse error: '" << buf << "'");
322 continue;
323 }
324
325 if ((encoding = strtok(NULL, w_space)) == NULL) {
326 debugs(25, DBG_IMPORTANT, "mimeInit: parse error: '" << buf << "'");
327 continue;
328 }
329
330 if ((mode = strtok(NULL, w_space)) == NULL) {
331 debugs(25, DBG_IMPORTANT, "mimeInit: parse error: '" << buf << "'");
332 continue;
333 }
334
335 download_option = 0;
336 view_option = 0;
337
338 while ((option = strtok(NULL, w_space)) != NULL) {
339 if (!strcmp(option, "+download"))
340 download_option = 1;
341 else if (!strcmp(option, "+view"))
342 view_option = 1;
343 else
344 debugs(25, DBG_IMPORTANT, "mimeInit: unknown option: '" << buf << "' (" << option << ")");
345 }
346
347 if (regcomp(&re, pattern, re_flags) != 0) {
348 debugs(25, DBG_IMPORTANT, "mimeInit: regcomp error: '" << buf << "'");
349 continue;
350 }
351
352 m = new mimeEntry;
353 m->pattern = xstrdup(pattern);
354 m->content_type = xstrdup(type);
355 m->theIcon.setName(icon);
356 m->content_encoding = xstrdup(encoding);
357 m->compiled_pattern = re;
358
359 if (!strcasecmp(mode, "ascii"))
360 m->transfer_mode = 'A';
361 else if (!strcasecmp(mode, "text"))
362 m->transfer_mode = 'A';
363 else
364 m->transfer_mode = 'I';
365
366 m->view_option = view_option;
367
368 m->download_option = download_option;
369
370 *MimeTableTail = m;
371
372 MimeTableTail = &m->next;
373
374 debugs(25, 5, "mimeInit: added '" << buf << "'");
375 }
376
377 fclose(fp);
378 /*
379 * Create Icon StoreEntry's
380 */
381
382 for (m = MimeTable; m != NULL; m = m->next)
383 m->theIcon.load();
384
385 debugs(25, DBG_IMPORTANT, "Loaded Icons.");
386 }
387
388 void
389 mimeFreeMemory(void)
390 {
391 mimeEntry *m;
392
393 while ((m = MimeTable)) {
394 MimeTable = m->next;
395 safe_free(m->pattern);
396 safe_free(m->content_type);
397 safe_free(m->icon);
398 safe_free(m->content_encoding);
399 regfree(&m->compiled_pattern);
400 delete m;
401 }
402
403 MimeTableTail = &MimeTable;
404 }
405
406 void
407 MimeIcon::load()
408 {
409 const char *type = mimeGetContentType(icon);
410
411 if (type == NULL)
412 fatal("Unknown icon format while reading mime.conf\n");
413
414 StoreEntry::getPublic(this, url, METHOD_GET);
415 }
416
417 void
418 MimeIcon::created (StoreEntry *newEntry)
419 {
420 /* is already in the store, do nothing */
421
422 if (!newEntry->isNull())
423 return;
424
425 int fd;
426
427 int n;
428
429 request_flags flags;
430
431 struct stat sb;
432
433 LOCAL_ARRAY(char, path, MAXPATHLEN);
434
435 char *buf;
436
437 snprintf(path, MAXPATHLEN, "%s/%s", Config.icons.directory, icon);
438
439 fd = file_open(path, O_RDONLY | O_BINARY);
440
441 if (fd < 0) {
442 debugs(25, DBG_CRITICAL, "mimeLoadIconFile: " << path << ": " << xstrerror());
443 return;
444 }
445
446 if (fstat(fd, &sb) < 0) {
447 debugs(25, DBG_CRITICAL, "mimeLoadIconFile: FD " << fd << ": fstat: " << xstrerror());
448 file_close(fd);
449 return;
450 }
451
452 flags.cachable = 1;
453 StoreEntry *e = storeCreateEntry(url,
454 url,
455 flags,
456 METHOD_GET);
457 assert(e != NULL);
458 EBIT_SET(e->flags, ENTRY_SPECIAL);
459 e->setPublicKey();
460 e->buffer();
461 HttpRequest *r = HttpRequest::CreateFromUrl(url);
462
463 if (NULL == r)
464 fatal("mimeLoadIcon: cannot parse internal URL");
465
466 e->mem_obj->request = HTTPMSGLOCK(r);
467
468 HttpReply *reply = new HttpReply;
469
470 reply->setHeaders(HTTP_OK, NULL, mimeGetContentType(icon), sb.st_size, sb.st_mtime, -1);
471
472 reply->cache_control = new HttpHdrCc();
473
474 reply->cache_control->maxAge(86400);
475
476 reply->header.putCc(reply->cache_control);
477
478 e->replaceHttpReply(reply);
479
480 /* read the file into the buffer and append it to store */
481 buf = (char *)memAllocate(MEM_4K_BUF);
482
483 while ((n = FD_READ_METHOD(fd, buf, 4096)) > 0)
484 e->append(buf, n);
485
486 file_close(fd);
487
488 e->flush();
489
490 e->complete();
491
492 e->timestampsSet();
493
494 debugs(25, 3, "Loaded icon " << url);
495
496 e->unlock();
497
498 memFree(buf, MEM_4K_BUF);
499 }