]> git.ipfire.org Git - thirdparty/squid.git/blame - src/mime.cc
Boilerplate: update copyright blurbs on src/
[thirdparty/squid.git] / src / mime.cc
CommitLineData
30a4f2a8 1/*
bbc27441 2 * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
e25c139f 3 *
bbc27441
AJ
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
6eb42cae 7 */
ed43818f 8
bbc27441
AJ
9/* DEBUG: section 25 MIME Parsing and Internal Icons */
10
582c2af2 11#include "squid.h"
438b04d4 12#include "disk.h"
582c2af2
FC
13#include "fde.h"
14#include "globals.h"
7ebe76de 15#include "HttpHdrCc.h"
528b2c61 16#include "HttpReply.h"
17#include "HttpRequest.h"
308e60be 18#include "internal.h"
8a89c28f 19#include "Mem.h"
0eb49b6d 20#include "MemBuf.h"
582c2af2 21#include "MemObject.h"
b65ce00c 22#include "mime.h"
f206b652 23#include "RequestFlags.h"
4d5904f7 24#include "SquidConfig.h"
582c2af2
FC
25#include "Store.h"
26#include "StoreClient.h"
27
28#if HAVE_SYS_STAT_H
29#include <sys/stat.h>
30#endif
090089c4 31
09610784 32#define GET_HDR_SZ 1024
33
b65ce00c
FC
34/* forward declarations */
35static void mimeFreeMemory(void);
36static char const *mimeGetIcon(const char *fn);
37
62e76326 38class MimeIcon : public StoreClient
39{
62e76326 40public:
cbb7a719 41 explicit MimeIcon(const char *aName);
d8aa42dc
FC
42 ~MimeIcon();
43 void setName(char const *);
44 char const * getName() const;
e6ccf245 45 void load();
d8aa42dc 46 void created(StoreEntry *newEntry);
857f9f58 47 MEMPROXY_CLASS(MimeIcon);
62e76326 48
e6ccf245 49private:
857f9f58
FC
50 const char *icon_;
51 char *url_;
e6ccf245 52};
857f9f58 53MEMPROXY_CLASS_INLINE(MimeIcon);
e6ccf245 54
d8aa42dc 55class MimeEntry
62e76326 56{
e6ccf245 57public:
cbb7a719 58 explicit MimeEntry(const char *aPattern, const regex_t &compiledPattern,
8f52a1c0
A
59 const char *aContentType,
60 const char *aContentEncoding, const char *aTransferMode,
61 bool optionViewEnable, bool optionDownloadEnable,
62 const char *anIconName);
d8aa42dc 63 ~MimeEntry();
857f9f58 64 MEMPROXY_CLASS(MimeEntry);
2cac2cc9
FC
65
66 const char *pattern;
812ed90c 67 regex_t compiled_pattern;
2cac2cc9
FC
68 const char *content_type;
69 const char *content_encoding;
812ed90c 70 char transfer_mode;
2cac2cc9
FC
71 bool view_option;
72 bool download_option;
e6ccf245 73 MimeIcon theIcon;
857f9f58 74 MimeEntry *next;
e6ccf245 75};
857f9f58 76MEMPROXY_CLASS_INLINE(MimeEntry);
812ed90c 77
d8aa42dc
FC
78static MimeEntry *MimeTable = NULL;
79static MimeEntry **MimeTableTail = &MimeTable;
365cb147 80
d8aa42dc 81static MimeEntry *
2a1ca944 82mimeGetEntry(const char *fn, int skip_encodings)
812ed90c 83{
d8aa42dc 84 MimeEntry *m;
7c06ad5f 85 char *t;
2a1ca944 86 char *name = xstrdup(fn);
62e76326 87
0a297316 88 do {
7c06ad5f 89 t = NULL;
62e76326 90
0a297316
AJ
91 for (m = MimeTable; m; m = m->next) {
92 if (regexec(&m->compiled_pattern, name, 0, 0, 0) == 0)
93 break;
62e76326 94 }
95
0a297316
AJ
96 if (!skip_encodings)
97 (void) 0;
98 else if (m == NULL)
99 (void) 0;
100 else if (strcmp(m->content_type, dash_str))
101 (void) 0;
102 else if (!strcmp(m->content_encoding, dash_str))
103 (void) 0;
104 else {
105 /* Assume we matched /\.\w$/ and cut off the last extension */
106 if ((t = strrchr(name, '.'))) {
107 *t = '\0';
9e008dda 108 } else {
0a297316
AJ
109 /* What? A encoding without a extension? */
110 m = NULL;
111 }
112 }
9e008dda 113 } while (t);
62e76326 114
2a1ca944 115 xfree(name);
116 return m;
117}
118
d8aa42dc 119MimeIcon::MimeIcon(const char *aName) :
8f52a1c0 120 icon_(xstrdup(aName))
29bf4910 121{
857f9f58 122 url_ = xstrdup(internalLocalUri("/squid-internal-static/icons/", icon_));
29bf4910
CT
123}
124
f0229765 125MimeIcon::~MimeIcon()
e6ccf245 126{
3f4abadf
AJ
127 xfree(icon_);
128 xfree(url_);
e6ccf245 129}
130
e6ccf245 131void
f0229765 132MimeIcon::setName(char const *aString)
e6ccf245 133{
3f4abadf
AJ
134 xfree(icon_);
135 xfree(url_);
136 icon_ = xstrdup(aString);
137 url_ = xstrdup(internalLocalUri("/squid-internal-static/icons/", icon_));
e6ccf245 138}
139
e6ccf245 140char const *
f0229765 141MimeIcon::getName() const
e6ccf245 142{
857f9f58 143 return icon_;
e6ccf245 144}
145
e6ccf245 146char const *
2a1ca944 147mimeGetIcon(const char *fn)
148{
d8aa42dc 149 MimeEntry *m = mimeGetEntry(fn, 1);
62e76326 150
812ed90c 151 if (m == NULL)
62e76326 152 return NULL;
153
e6ccf245 154 if (!strcmp(m->theIcon.getName(), dash_str))
62e76326 155 return NULL;
156
e6ccf245 157 return m->theIcon.getName();
812ed90c 158}
159
d20b1cd0 160const char *
4162ee3b 161mimeGetIconURL(const char *fn)
162{
e6ccf245 163 char const *icon = mimeGetIcon(fn);
62e76326 164
4162ee3b 165 if (icon == NULL)
62e76326 166 return null_string;
167
e72a0ec0 168 if (Config.icons.use_short_names) {
032785bf 169 static MemBuf mb;
2fe7eff9 170 mb.reset();
171 mb.Printf("/squid-internal-static/icons/%s", icon);
032785bf 172 return mb.content();
e72a0ec0 173 } else {
174 return internalLocalUri("/squid-internal-static/icons/", icon);
175 }
4162ee3b 176}
177
2cac2cc9 178const char *
812ed90c 179mimeGetContentType(const char *fn)
180{
d8aa42dc 181 MimeEntry *m = mimeGetEntry(fn, 1);
62e76326 182
812ed90c 183 if (m == NULL)
62e76326 184 return NULL;
185
812ed90c 186 if (!strcmp(m->content_type, dash_str))
62e76326 187 return NULL;
188
812ed90c 189 return m->content_type;
190}
191
2cac2cc9 192const char *
812ed90c 193mimeGetContentEncoding(const char *fn)
194{
d8aa42dc 195 MimeEntry *m = mimeGetEntry(fn, 0);
62e76326 196
812ed90c 197 if (m == NULL)
62e76326 198 return NULL;
199
812ed90c 200 if (!strcmp(m->content_encoding, dash_str))
62e76326 201 return NULL;
202
812ed90c 203 return m->content_encoding;
204}
205
206char
207mimeGetTransferMode(const char *fn)
208{
d8aa42dc 209 MimeEntry *m = mimeGetEntry(fn, 0);
812ed90c 210 return m ? m->transfer_mode : 'I';
211}
212
2cac2cc9 213bool
2a1ca944 214mimeGetDownloadOption(const char *fn)
215{
d8aa42dc 216 MimeEntry *m = mimeGetEntry(fn, 1);
2a1ca944 217 return m ? m->download_option : 0;
218}
219
2cac2cc9 220bool
2a1ca944 221mimeGetViewOption(const char *fn)
222{
d8aa42dc 223 MimeEntry *m = mimeGetEntry(fn, 0);
2cac2cc9 224 return m != 0 ? m->view_option : false;
2a1ca944 225}
226
00fa6528 227/* Initializes/reloads the mime table
228 * Note: Due to Solaris STDIO problems the caller should NOT
229 * call mimeFreeMemory on reconfigure. This way, if STDIO
230 * fails we at least have the old copy loaded.
231 */
812ed90c 232void
233mimeInit(char *filename)
234{
235 FILE *fp;
236 char buf[BUFSIZ];
237 char chopbuf[BUFSIZ];
238 char *t;
239 char *pattern;
240 char *icon;
241 char *type;
242 char *encoding;
243 char *mode;
2a1ca944 244 char *option;
245 int view_option;
246 int download_option;
812ed90c 247 regex_t re;
d8aa42dc 248 MimeEntry *m;
812ed90c 249 int re_flags = REG_EXTENDED | REG_NOSUB | REG_ICASE;
62e76326 250
812ed90c 251 if (filename == NULL)
62e76326 252 return;
253
812ed90c 254 if ((fp = fopen(filename, "r")) == NULL) {
e0236918 255 debugs(25, DBG_IMPORTANT, "mimeInit: " << filename << ": " << xstrerror());
62e76326 256 return;
812ed90c 257 }
62e76326 258
be266cb2 259#if _SQUID_WINDOWS_
c4aefe96 260 setmode(fileno(fp), O_TEXT);
261#endif
62e76326 262
00fa6528 263 mimeFreeMemory();
62e76326 264
812ed90c 265 while (fgets(buf, BUFSIZ, fp)) {
62e76326 266 if ((t = strchr(buf, '#')))
267 *t = '\0';
268
269 if ((t = strchr(buf, '\r')))
270 *t = '\0';
271
272 if ((t = strchr(buf, '\n')))
273 *t = '\0';
274
275 if (buf[0] == '\0')
276 continue;
277
278 xstrncpy(chopbuf, buf, BUFSIZ);
279
280 if ((pattern = strtok(chopbuf, w_space)) == NULL) {
e0236918 281 debugs(25, DBG_IMPORTANT, "mimeInit: parse error: '" << buf << "'");
62e76326 282 continue;
283 }
284
285 if ((type = strtok(NULL, w_space)) == NULL) {
e0236918 286 debugs(25, DBG_IMPORTANT, "mimeInit: parse error: '" << buf << "'");
62e76326 287 continue;
288 }
289
290 if ((icon = strtok(NULL, w_space)) == NULL) {
e0236918 291 debugs(25, DBG_IMPORTANT, "mimeInit: parse error: '" << buf << "'");
62e76326 292 continue;
293 }
294
295 if ((encoding = strtok(NULL, w_space)) == NULL) {
e0236918 296 debugs(25, DBG_IMPORTANT, "mimeInit: parse error: '" << buf << "'");
62e76326 297 continue;
298 }
299
300 if ((mode = strtok(NULL, w_space)) == NULL) {
e0236918 301 debugs(25, DBG_IMPORTANT, "mimeInit: parse error: '" << buf << "'");
62e76326 302 continue;
303 }
304
305 download_option = 0;
306 view_option = 0;
307
308 while ((option = strtok(NULL, w_space)) != NULL) {
309 if (!strcmp(option, "+download"))
310 download_option = 1;
311 else if (!strcmp(option, "+view"))
312 view_option = 1;
313 else
e0236918 314 debugs(25, DBG_IMPORTANT, "mimeInit: unknown option: '" << buf << "' (" << option << ")");
62e76326 315 }
316
317 if (regcomp(&re, pattern, re_flags) != 0) {
e0236918 318 debugs(25, DBG_IMPORTANT, "mimeInit: regcomp error: '" << buf << "'");
62e76326 319 continue;
320 }
321
d8aa42dc 322 m = new MimeEntry(pattern,re,type,encoding,mode,view_option,
8f52a1c0 323 download_option,icon);
62e76326 324
325 *MimeTableTail = m;
326
327 MimeTableTail = &m->next;
328
bf8fe701 329 debugs(25, 5, "mimeInit: added '" << buf << "'");
812ed90c 330 }
62e76326 331
337d4867 332 fclose(fp);
62e76326 333
8ca66e48 334 for (m = MimeTable; m != NULL; m = m->next)
62e76326 335 m->theIcon.load();
2cac2cc9 336 debugs(25, DBG_IMPORTANT, "Finished loading MIME types and icons.");
812ed90c 337}
365cb147 338
c68e9c6b 339void
340mimeFreeMemory(void)
341{
d8aa42dc 342 MimeEntry *m;
62e76326 343
c68e9c6b 344 while ((m = MimeTable)) {
62e76326 345 MimeTable = m->next;
62e76326 346 delete m;
c68e9c6b 347 }
62e76326 348
c68e9c6b 349 MimeTableTail = &MimeTable;
350}
351
e6ccf245 352void
353MimeIcon::load()
354{
857f9f58 355 const char *type = mimeGetContentType(icon_);
62e76326 356
e6ccf245 357 if (type == NULL)
62e76326 358 fatal("Unknown icon format while reading mime.conf\n");
359
857f9f58 360 StoreEntry::getPublic(this, url_, Http::METHOD_GET);
e6ccf245 361}
362
363void
364MimeIcon::created (StoreEntry *newEntry)
365cb147 365{
100f7d8b 366 /* if the icon is already in the store, do nothing */
e6ccf245 367 if (!newEntry->isNull())
62e76326 368 return;
369
f9e5a344 370 int fd;
371 int n;
f206b652 372 RequestFlags flags;
f9e5a344 373 struct stat sb;
f9e5a344 374 LOCAL_ARRAY(char, path, MAXPATHLEN);
f9e5a344 375 char *buf;
62e76326 376
857f9f58 377 snprintf(path, MAXPATHLEN, "%s/%s", Config.icons.directory, icon_);
62e76326 378
c4aefe96 379 fd = file_open(path, O_RDONLY | O_BINARY);
f9e5a344 380 if (fd < 0) {
857f9f58 381 debugs(25, DBG_CRITICAL, "Problem opening icon file " << path << ": " << xstrerror());
62e76326 382 return;
f9e5a344 383 }
384 if (fstat(fd, &sb) < 0) {
857f9f58 385 debugs(25, DBG_CRITICAL, "Problem opening icon file. Fd: " << fd << ", fstat error " << xstrerror());
62e76326 386 file_close(fd);
387 return;
f9e5a344 388 }
62e76326 389
e857372a 390 flags.cachable = true;
857f9f58 391 StoreEntry *e = storeCreateEntry(url_,url_,flags,Http::METHOD_GET);
f9e5a344 392 assert(e != NULL);
1c85378b 393 EBIT_SET(e->flags, ENTRY_SPECIAL);
d88e3c49 394 e->setPublicKey();
3900307b 395 e->buffer();
857f9f58 396 HttpRequest *r = HttpRequest::CreateFromUrl(url_);
62e76326 397
96a7422a 398 if (NULL == r)
62e76326 399 fatal("mimeLoadIcon: cannot parse internal URL");
400
b248c2a3
AJ
401 e->mem_obj->request = r;
402 HTTPMSGLOCK(e->mem_obj->request);
62e76326 403
06a5ae20 404 HttpReply *reply = new HttpReply;
62e76326 405
955394ce 406 reply->setHeaders(Http::scOkay, NULL, mimeGetContentType(icon_), sb.st_size, sb.st_mtime, -1);
a4a03b37 407 reply->cache_control = new HttpHdrCc();
cf7c2e94 408 reply->cache_control->maxAge(86400);
a9925b40 409 reply->header.putCc(reply->cache_control);
db237875 410 e->replaceHttpReply(reply);
62e76326 411
cb69b4c7 412 /* read the file into the buffer and append it to store */
e6ccf245 413 buf = (char *)memAllocate(MEM_4K_BUF);
1f7c9178 414 while ((n = FD_READ_METHOD(fd, buf, 4096)) > 0)
3900307b 415 e->append(buf, n);
62e76326 416
f9e5a344 417 file_close(fd);
3900307b 418 e->flush();
528b2c61 419 e->complete();
3900307b 420 e->timestampsSet();
acc5dc4c 421 e->unlock("MimeIcon::created");
db1cd23c 422 memFree(buf, MEM_4K_BUF);
857f9f58 423 debugs(25, 3, "Loaded icon " << url_);
365cb147 424}
d8aa42dc 425
857f9f58
FC
426MimeEntry::~MimeEntry()
427{
3f4abadf
AJ
428 xfree(pattern);
429 xfree(content_type);
430 xfree(content_encoding);
d8aa42dc
FC
431 regfree(&compiled_pattern);
432}
f0229765
FC
433
434MimeEntry::MimeEntry(const char *aPattern, const regex_t &compiledPattern,
8f52a1c0
A
435 const char *aContentType, const char *aContentEncoding,
436 const char *aTransferMode, bool optionViewEnable,
437 bool optionDownloadEnable, const char *anIconName) :
438 pattern(xstrdup(aPattern)),
439 compiled_pattern(compiledPattern),
440 content_type(xstrdup(aContentType)),
441 content_encoding(xstrdup(aContentEncoding)),
442 view_option(optionViewEnable),
443 download_option(optionViewEnable),
444 theIcon(anIconName), next(NULL)
f0229765
FC
445{
446 if (!strcasecmp(aTransferMode, "ascii"))
447 transfer_mode = 'A';
448 else if (!strcasecmp(aTransferMode, "text"))
449 transfer_mode = 'A';
450 else
451 transfer_mode = 'I';
365cb147 452}