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