mime.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2022 The Squid Software Foundation and contributors
3 *
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.
7 */
8
9/* DEBUG: section 25 MIME Parsing and Internal Icons */
10
11#include "squid.h"
12#include "debug/Messages.h"
13#include "fde.h"
14#include "fs_io.h"
15#include "globals.h"
16#include "HttpHdrCc.h"
17#include "HttpReply.h"
18#include "HttpRequest.h"
19#include "internal.h"
20#include "MemBuf.h"
21#include "MemObject.h"
22#include "mime.h"
23#include "SquidConfig.h"
24#include "Store.h"
25#include "StoreClient.h"
26
27#include <array>
28
29#if HAVE_SYS_STAT_H
30#include <sys/stat.h>
31#endif
32
33/* forward declarations */
34static void mimeFreeMemory(void);
35static const SBuf mimeGetIcon(const char *fn);
36
37class MimeIcon : public StoreClient
38{
40
41public:
42 explicit MimeIcon(const char *aName);
43 ~MimeIcon();
44 void setName(char const *);
45 SBuf getName() const;
46 void load();
47
48 /* StoreClient API */
49 virtual LogTags *loggingTags() const { return nullptr; } // no access logging/ACLs
50 virtual void fillChecklist(ACLFilledChecklist &) const;
51
52private:
54 char *url_;
55};
56
58{
60
61public:
62 explicit MimeEntry(const char *aPattern, const regex_t &compiledPattern,
63 const char *aContentType,
64 const char *aContentEncoding, const char *aTransferMode,
65 bool optionViewEnable, bool optionDownloadEnable,
66 const char *anIconName);
67 ~MimeEntry();
68
69 const char *pattern;
71 const char *content_type;
72 const char *content_encoding;
78};
79
80static MimeEntry *MimeTable = nullptr;
82
83static MimeEntry *
84mimeGetEntry(const char *fn, int skip_encodings)
85{
86 MimeEntry *m;
87 char *t;
88 char *name = xstrdup(fn);
89
90 do {
91 t = nullptr;
92
93 for (m = MimeTable; m; m = m->next) {
94 if (regexec(&m->compiled_pattern, name, 0, nullptr, 0) == 0)
95 break;
96 }
97
98 if (!skip_encodings)
99 (void) 0;
100 else if (m == nullptr)
101 (void) 0;
102 else if (strcmp(m->content_type, dash_str))
103 (void) 0;
104 else if (!strcmp(m->content_encoding, dash_str))
105 (void) 0;
106 else {
107 /* Assume we matched /\.\w$/ and cut off the last extension */
108 if ((t = strrchr(name, '.'))) {
109 *t = '\0';
110 } else {
111 /* What? A encoding without a extension? */
112 m = nullptr;
113 }
114 }
115 } while (t);
116
117 xfree(name);
118 return m;
119}
120
121MimeIcon::MimeIcon(const char *aName) :
122 url_(nullptr)
123{
124 setName(aName);
125}
126
128{
129 xfree(url_);
130}
131
132void
133MimeIcon::setName(char const *aString)
134{
135 xfree(url_);
136 icon_ = aString;
137 url_ = xstrdup(internalLocalUri("/squid-internal-static/icons/", icon_));
138}
139
140SBuf
142{
143 return icon_;
144}
145
146const SBuf
147mimeGetIcon(const char *fn)
148{
149 MimeEntry *m = mimeGetEntry(fn, 1);
150
151 if (!m || !m->theIcon.getName().cmp(dash_str))
152 return SBuf();
153
154 return m->theIcon.getName();
155}
156
157const char *
158mimeGetIconURL(const char *fn)
159{
160 SBuf icon(mimeGetIcon(fn));
161
162 if (icon.isEmpty())
163 return null_string;
164
166 static SBuf mb;
167 mb.clear();
168 mb.append("/squid-internal-static/icons/");
169 mb.append(icon);
170 return mb.c_str();
171 } else {
172 return internalLocalUri("/squid-internal-static/icons/", icon);
173 }
174}
175
176const char *
177mimeGetContentType(const char *fn)
178{
179 MimeEntry *m = mimeGetEntry(fn, 1);
180
181 if (m == nullptr)
182 return nullptr;
183
184 if (!strcmp(m->content_type, dash_str))
185 return nullptr;
186
187 return m->content_type;
188}
189
190const char *
192{
193 MimeEntry *m = mimeGetEntry(fn, 0);
194
195 if (m == nullptr)
196 return nullptr;
197
198 if (!strcmp(m->content_encoding, dash_str))
199 return nullptr;
200
201 return m->content_encoding;
202}
203
204char
205mimeGetTransferMode(const char *fn)
206{
207 MimeEntry *m = mimeGetEntry(fn, 0);
208 return m ? m->transfer_mode : 'I';
209}
210
211bool
213{
214 MimeEntry *m = mimeGetEntry(fn, 1);
215 return m ? m->download_option : 0;
216}
217
218bool
219mimeGetViewOption(const char *fn)
220{
221 MimeEntry *m = mimeGetEntry(fn, 0);
222 return m != nullptr ? m->view_option : false;
223}
224
225/* Initializes/reloads the mime table
226 * Note: Due to Solaris STDIO problems the caller should NOT
227 * call mimeFreeMemory on reconfigure. This way, if STDIO
228 * fails we at least have the old copy loaded.
229 */
230void
231mimeInit(char *filename)
232{
233 FILE *fp;
234 char buf[BUFSIZ];
235 char chopbuf[BUFSIZ];
236 char *t;
237 char *pattern;
238 char *icon;
239 char *type;
240 char *encoding;
241 char *mode;
242 char *option;
243 int view_option;
244 int download_option;
245 regex_t re;
246 MimeEntry *m;
247 int re_flags = REG_EXTENDED | REG_NOSUB | REG_ICASE;
248
249 if (filename == nullptr)
250 return;
251
252 if ((fp = fopen(filename, "r")) == nullptr) {
253 int xerrno = errno;
254 debugs(25, DBG_IMPORTANT, "mimeInit: " << filename << ": " << xstrerr(xerrno));
255 return;
256 }
257
258#if _SQUID_WINDOWS_
259 setmode(fileno(fp), O_TEXT);
260#endif
261
263
264 while (fgets(buf, BUFSIZ, fp)) {
265 if ((t = strchr(buf, '#')))
266 *t = '\0';
267
268 if ((t = strchr(buf, '\r')))
269 *t = '\0';
270
271 if ((t = strchr(buf, '\n')))
272 *t = '\0';
273
274 if (buf[0] == '\0')
275 continue;
276
277 xstrncpy(chopbuf, buf, BUFSIZ);
278
279 if ((pattern = strtok(chopbuf, w_space)) == nullptr) {
280 debugs(25, DBG_IMPORTANT, "ERROR: mimeInit: parse failure: '" << buf << "'");
281 continue;
282 }
283
284 if ((type = strtok(nullptr, w_space)) == nullptr) {
285 debugs(25, DBG_IMPORTANT, "ERROR: mimeInit: parse failure: '" << buf << "'");
286 continue;
287 }
288
289 if ((icon = strtok(nullptr, w_space)) == nullptr) {
290 debugs(25, DBG_IMPORTANT, "ERROR: mimeInit: parse failure: '" << buf << "'");
291 continue;
292 }
293
294 if ((encoding = strtok(nullptr, w_space)) == nullptr) {
295 debugs(25, DBG_IMPORTANT, "ERROR: mimeInit: parse failure: '" << buf << "'");
296 continue;
297 }
298
299 if ((mode = strtok(nullptr, w_space)) == nullptr) {
300 debugs(25, DBG_IMPORTANT, "ERROR: mimeInit: parse failure: '" << buf << "'");
301 continue;
302 }
303
304 download_option = 0;
305 view_option = 0;
306
307 while ((option = strtok(nullptr, w_space)) != nullptr) {
308 if (!strcmp(option, "+download"))
309 download_option = 1;
310 else if (!strcmp(option, "+view"))
311 view_option = 1;
312 else
313 debugs(25, DBG_IMPORTANT, "ERROR: mimeInit: unknown option: '" << buf << "' (" << option << ")");
314 }
315
316 if (regcomp(&re, pattern, re_flags) != 0) {
317 debugs(25, DBG_IMPORTANT, "ERROR: mimeInit: regcomp failure: '" << buf << "'");
318 continue;
319 }
320
321 m = new MimeEntry(pattern,re,type,encoding,mode,view_option,
322 download_option,icon);
323
324 *MimeTableTail = m;
325
326 MimeTableTail = &m->next;
327
328 debugs(25, 5, "mimeInit: added '" << buf << "'");
329 }
330
331 fclose(fp);
332
333 for (m = MimeTable; m != nullptr; m = m->next)
334 m->theIcon.load();
335 debugs(25, Important(28), "Finished loading MIME types and icons.");
336}
337
338void
340{
341 MimeEntry *m;
342
343 while ((m = MimeTable)) {
344 MimeTable = m->next;
345 delete m;
346 }
347
349}
350
351void
353{
354 const char *type = mimeGetContentType(icon_.c_str());
355
356 if (type == nullptr)
357 fatal("Unknown icon format while reading mime.conf\n");
358
359 if (const auto e = storeGetPublic(url_, Http::METHOD_GET)) {
360 // do not overwrite an already stored icon
361 e->abandon(__FUNCTION__);
362 return;
363 }
364
365 // XXX: if a 204 is cached due to earlier load 'failure' we should try to reload.
366
367 // default is a 200 object with image data.
368 // set to the backup value of 204 on image loading errors
370
371 static char path[MAXPATHLEN];
372 *path = 0;
373 if (snprintf(path, sizeof(path)-1, "%s/" SQUIDSBUFPH, Config.icons.directory, SQUIDSBUFPRINT(icon_)) < 0) {
374 debugs(25, DBG_CRITICAL, "ERROR: icon file '" << Config.icons.directory << "/" << icon_ << "' path is longer than " << MAXPATHLEN << " bytes");
375 status = Http::scNoContent;
376 }
377
378 int fd = -1;
379 errno = 0;
380 if (status == Http::scOkay && (fd = file_open(path, O_RDONLY | O_BINARY)) < 0) {
381 int xerrno = errno;
382 debugs(25, DBG_CRITICAL, "ERROR: opening icon file " << path << ": " << xstrerr(xerrno));
383 status = Http::scNoContent;
384 }
385
386 struct stat sb;
387 errno = 0;
388 if (status == Http::scOkay && fstat(fd, &sb) < 0) {
389 int xerrno = errno;
390 debugs(25, DBG_CRITICAL, "ERROR: opening icon file " << path << " FD " << fd << ", fstat error " << xstrerr(xerrno));
391 file_close(fd);
392 status = Http::scNoContent;
393 }
394
396 e->lock("MimeIcon::created");
398 const auto madePublic = e->setPublicKey();
399 assert(madePublic); // nothing can block ENTRY_SPECIAL from becoming public
400
401 /* fill `e` with a canned 2xx response object */
402
403 const auto mx = MasterXaction::MakePortless<XactionInitiator::initIcon>();
405 if (!r)
406 fatalf("mimeLoadIcon: cannot parse internal URL: %s", url_);
407
408 e->buffer();
409
410 e->mem_obj->request = r;
411
412 HttpReplyPointer reply(new HttpReply);
413
414 if (status == Http::scNoContent)
415 reply->setHeaders(status, nullptr, nullptr, 0, -1, -1);
416 else
417 reply->setHeaders(status, nullptr, mimeGetContentType(icon_.c_str()), sb.st_size, sb.st_mtime, -1);
418 reply->cache_control = new HttpHdrCc();
419 reply->cache_control->maxAge(86400);
420 reply->header.putCc(reply->cache_control);
421 e->replaceHttpReply(reply.getRaw());
422
423 if (status == Http::scOkay) {
424 /* read the file into the buffer and append it to store */
425 int n;
426 std::array<char, 4096> buf;
427 while ((n = FD_READ_METHOD(fd, buf.data(), buf.size())) > 0)
428 e->append(buf.data(), n);
429
430 file_close(fd);
431 }
432
433 e->flush();
434 e->complete();
435 e->timestampsSet();
436 // MimeIcons are only loaded once, prevent accidental destruction
437 // e->unlock("MimeIcon::created");
438 debugs(25, 3, "Loaded icon " << url_);
439}
440
441void
443{
444 // Unreachable: We never mayInitiateCollapsing() or startCollapsingOn().
445 assert(false);
446}
447
449{
450 xfree(pattern);
454}
455
456MimeEntry::MimeEntry(const char *aPattern, const regex_t &compiledPattern,
457 const char *aContentType, const char *aContentEncoding,
458 const char *aTransferMode, bool optionViewEnable,
459 bool optionDownloadEnable, const char *anIconName) :
460 pattern(xstrdup(aPattern)),
461 compiled_pattern(compiledPattern),
462 content_type(xstrdup(aContentType)),
463 content_encoding(xstrdup(aContentEncoding)),
464 view_option(optionViewEnable),
465 download_option(optionDownloadEnable),
466 theIcon(anIconName), next(nullptr)
467{
468 if (!strcasecmp(aTransferMode, "ascii"))
469 transfer_mode = 'A';
470 else if (!strcasecmp(aTransferMode, "text"))
471 transfer_mode = 'A';
472 else
473 transfer_mode = 'I';
474}
475
int regexec(regex_t *preg, const char *string, size_t nmatch, pmatch, int eflags) const
Definition: GnuRegex.c:4195
int regcomp(regex_t *preg, const char *pattern, int cflags)
Definition: GnuRegex.c:4124
void regfree(regex_t *preg)
Definition: GnuRegex.c:4287
#define REG_ICASE
Definition: GnuRegex.h:230
#define REG_EXTENDED
Definition: GnuRegex.h:226
#define REG_NOSUB
Definition: GnuRegex.h:239
#define SQUIDSBUFPH
Definition: SBuf.h:31
#define SQUIDSBUFPRINT(s)
Definition: SBuf.h:32
class SquidConfig Config
Definition: SquidConfig.cc:12
#define assert(EX)
Definition: assert.h:19
void maxAge(int32_t v)
Definition: HttpHdrCc.h:123
void putCc(const HttpHdrCc *cc)
Definition: HttpHeader.cc:1044
void setHeaders(Http::StatusCode status, const char *reason, const char *ctype, int64_t clen, time_t lmt, time_t expires)
Definition: HttpReply.cc:167
static HttpRequest * FromUrlXXX(const char *url, const MasterXaction::Pointer &, const HttpRequestMethod &method=Http::METHOD_GET)
Definition: HttpRequest.cc:528
HttpHeader header
Definition: Message.h:74
HttpHdrCc * cache_control
Definition: Message.h:76
HttpRequestPointer request
Definition: MemObject.h:188
MimeEntry(const char *aPattern, const regex_t &compiledPattern, const char *aContentType, const char *aContentEncoding, const char *aTransferMode, bool optionViewEnable, bool optionDownloadEnable, const char *anIconName)
Definition: mime.cc:456
const char * content_type
Definition: mime.cc:71
MimeEntry * next
Definition: mime.cc:77
const char * pattern
Definition: mime.cc:69
MimeIcon theIcon
Definition: mime.cc:76
bool download_option
Definition: mime.cc:75
MEMPROXY_CLASS(MimeEntry)
regex_t compiled_pattern
Definition: mime.cc:70
bool view_option
Definition: mime.cc:74
~MimeEntry()
Definition: mime.cc:448
const char * content_encoding
Definition: mime.cc:72
char transfer_mode
Definition: mime.cc:73
Definition: mime.cc:38
void load()
Definition: mime.cc:352
MimeIcon(const char *aName)
Definition: mime.cc:121
void setName(char const *)
Definition: mime.cc:133
~MimeIcon()
Definition: mime.cc:127
char * url_
Definition: mime.cc:54
virtual void fillChecklist(ACLFilledChecklist &) const
configure the given checklist (to reflect the current transaction state)
Definition: mime.cc:442
MEMPROXY_CLASS(MimeIcon)
SBuf icon_
Definition: mime.cc:53
SBuf getName() const
Definition: mime.cc:141
virtual LogTags * loggingTags() const
Definition: mime.cc:49
C * getRaw() const
Definition: RefCount.h:80
Definition: SBuf.h:94
const char * c_str()
Definition: SBuf.cc:516
int cmp(const SBuf &S, const size_type n) const
shorthand version for compare()
Definition: SBuf.h:275
bool isEmpty() const
Definition: SBuf.h:431
SBuf & append(const SBuf &S)
Definition: SBuf.cc:185
void clear()
Definition: SBuf.cc:175
int use_short_names
Definition: SquidConfig.h:425
struct SquidConfig::@114 icons
char * directory
Definition: SquidConfig.h:424
a storeGetPublic*() caller
Definition: StoreClient.h:27
uint16_t flags
Definition: Store.h:232
virtual void buffer()
Definition: store.cc:1568
virtual void flush()
Definition: store.cc:1579
void complete()
Definition: store.cc:1004
virtual void append(char const *, int)
Appends a c-string to existing packed data.
Definition: store.cc:776
void lock(const char *context)
Definition: store.cc:418
bool timestampsSet()
Definition: store.cc:1360
void replaceHttpReply(const HttpReplyPointer &, const bool andStartWriting=true)
Definition: store.cc:1672
MemObject * mem_obj
Definition: Store.h:221
bool setPublicKey(const KeyScope keyScope=ksDefault)
Definition: store.cc:548
#define w_space
#define Important(id)
Definition: Messages.h:91
#define DBG_IMPORTANT
Definition: Stream.h:41
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:196
#define DBG_CRITICAL
Definition: Stream.h:40
#define O_BINARY
Definition: defines.h:136
#define EBIT_SET(flag, bit)
Definition: defines.h:67
#define BUFSIZ
Definition: defines.h:20
#define O_TEXT
Definition: defines.h:133
@ ENTRY_SPECIAL
Definition: enums.h:84
int type
Definition: errorpage.cc:152
void fatal(const char *message)
Definition: fatal.cc:28
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
int FD_READ_METHOD(int fd, char *buf, int len)
Definition: fde.h:194
int file_open(const char *path, int mode)
Definition: fs_io.cc:45
void file_close(int fd)
Definition: fs_io.cc:73
const char * dash_str
const char * null_string
char * internalLocalUri(const char *dir, const SBuf &name)
Definition: internal.cc:130
static void mimeFreeMemory(void)
Definition: mime.cc:339
const char * mimeGetIconURL(const char *fn)
Definition: mime.cc:158
static MimeEntry * MimeTable
Definition: mime.cc:80
static MimeEntry ** MimeTableTail
Definition: mime.cc:81
static const SBuf mimeGetIcon(const char *fn)
Definition: mime.cc:147
const char * mimeGetContentEncoding(const char *fn)
Definition: mime.cc:191
static MimeEntry * mimeGetEntry(const char *fn, int skip_encodings)
Definition: mime.cc:84
char mimeGetTransferMode(const char *fn)
Definition: mime.cc:205
void mimeInit(char *filename)
Definition: mime.cc:231
bool mimeGetViewOption(const char *fn)
Definition: mime.cc:219
const char * mimeGetContentType(const char *fn)
Definition: mime.cc:177
bool mimeGetDownloadOption(const char *fn)
Definition: mime.cc:212
StatusCode
Definition: StatusCode.h:20
@ scOkay
Definition: StatusCode.h:26
@ scNoContent
Definition: StatusCode.h:30
@ METHOD_GET
Definition: MethodType.h:25
#define xfree
#define xstrdup
static struct stat sb
Definition: squidclient.cc:71
#define MAXPATHLEN
Definition: stdio.h:62
StoreEntry * storeGetPublic(const char *uri, const HttpRequestMethod &method)
Definition: store.cc:477
StoreEntry * storeCreatePureEntry(const char *url, const char *log_url, const HttpRequestMethod &method)
Definition: store.cc:714
const char * xstrerr(int error)
Definition: xstrerror.cc:83
char * xstrncpy(char *dst, const char *src, size_t n)
Definition: xstring.cc:37

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors