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 */
34 static void mimeFreeMemory(void);
35 static const SBuf mimeGetIcon(const char *fn);
36 
37 class MimeIcon : public StoreClient
38 {
40 
41 public:
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 
52 private:
54  char *url_;
55 };
56 
57 class MimeEntry
58 {
60 
61 public:
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 
82 
83 static MimeEntry *
84 mimeGetEntry(const char *fn, int skip_encodings)
85 {
86  MimeEntry *m;
87  char *t;
88  char *name = xstrdup(fn);
89 
90  do {
91  t = NULL;
92 
93  for (m = MimeTable; m; m = m->next) {
94  if (regexec(&m->compiled_pattern, name, 0, 0, 0) == 0)
95  break;
96  }
97 
98  if (!skip_encodings)
99  (void) 0;
100  else if (m == NULL)
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 = NULL;
113  }
114  }
115  } while (t);
116 
117  xfree(name);
118  return m;
119 }
120 
121 MimeIcon::MimeIcon(const char *aName) :
122  url_(nullptr)
123 {
124  setName(aName);
125 }
126 
128 {
129  xfree(url_);
130 }
131 
132 void
133 MimeIcon::setName(char const *aString)
134 {
135  xfree(url_);
136  icon_ = aString;
137  url_ = xstrdup(internalLocalUri("/squid-internal-static/icons/", icon_));
138 }
139 
140 SBuf
142 {
143  return icon_;
144 }
145 
146 const SBuf
147 mimeGetIcon(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 
157 const char *
158 mimeGetIconURL(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 
176 const char *
177 mimeGetContentType(const char *fn)
178 {
179  MimeEntry *m = mimeGetEntry(fn, 1);
180 
181  if (m == NULL)
182  return NULL;
183 
184  if (!strcmp(m->content_type, dash_str))
185  return NULL;
186 
187  return m->content_type;
188 }
189 
190 const char *
191 mimeGetContentEncoding(const char *fn)
192 {
193  MimeEntry *m = mimeGetEntry(fn, 0);
194 
195  if (m == NULL)
196  return NULL;
197 
198  if (!strcmp(m->content_encoding, dash_str))
199  return NULL;
200 
201  return m->content_encoding;
202 }
203 
204 char
205 mimeGetTransferMode(const char *fn)
206 {
207  MimeEntry *m = mimeGetEntry(fn, 0);
208  return m ? m->transfer_mode : 'I';
209 }
210 
211 bool
212 mimeGetDownloadOption(const char *fn)
213 {
214  MimeEntry *m = mimeGetEntry(fn, 1);
215  return m ? m->download_option : 0;
216 }
217 
218 bool
219 mimeGetViewOption(const char *fn)
220 {
221  MimeEntry *m = mimeGetEntry(fn, 0);
222  return m != 0 ? 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  */
230 void
231 mimeInit(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 == NULL)
250  return;
251 
252  if ((fp = fopen(filename, "r")) == NULL) {
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 
262  mimeFreeMemory();
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)) == NULL) {
280  debugs(25, DBG_IMPORTANT, "ERROR: mimeInit: parse failure: '" << buf << "'");
281  continue;
282  }
283 
284  if ((type = strtok(NULL, w_space)) == NULL) {
285  debugs(25, DBG_IMPORTANT, "ERROR: mimeInit: parse failure: '" << buf << "'");
286  continue;
287  }
288 
289  if ((icon = strtok(NULL, w_space)) == NULL) {
290  debugs(25, DBG_IMPORTANT, "ERROR: mimeInit: parse failure: '" << buf << "'");
291  continue;
292  }
293 
294  if ((encoding = strtok(NULL, w_space)) == NULL) {
295  debugs(25, DBG_IMPORTANT, "ERROR: mimeInit: parse failure: '" << buf << "'");
296  continue;
297  }
298 
299  if ((mode = strtok(NULL, w_space)) == NULL) {
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(NULL, w_space)) != NULL) {
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 != NULL; m = m->next)
334  m->theIcon.load();
335  debugs(25, Important(28), "Finished loading MIME types and icons.");
336 }
337 
338 void
340 {
341  MimeEntry *m;
342 
343  while ((m = MimeTable)) {
344  MimeTable = m->next;
345  delete m;
346  }
347 
349 }
350 
351 void
353 {
354  const char *type = mimeGetContentType(icon_.c_str());
355 
356  if (type == NULL)
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, NULL, NULL, 0, -1, -1);
416  else
417  reply->setHeaders(status, NULL, 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 
441 void
443 {
444  // Unreachable: We never mayInitiateCollapsing() or startCollapsingOn().
445  assert(false);
446 }
447 
449 {
450  xfree(pattern);
454 }
455 
456 MimeEntry::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(NULL)
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 
void fatal(const char *message)
Definition: fatal.cc:28
const char * xstrerr(int error)
Definition: xstrerror.cc:83
virtual LogTags * loggingTags() const
Definition: mime.cc:49
MEMPROXY_CLASS(MimeIcon)
virtual void buffer()
Definition: store.cc:1579
#define DBG_CRITICAL
Definition: Stream.h:40
#define BUFSIZ
Definition: defines.h:20
HttpHeader header
Definition: Message.h:75
MimeIcon theIcon
Definition: mime.cc:76
#define EBIT_SET(flag, bit)
Definition: defines.h:67
bool isEmpty() const
Definition: SBuf.h:424
virtual void flush()
Definition: store.cc:1590
MemObject * mem_obj
Definition: Store.h:219
regex_t compiled_pattern
Definition: mime.cc:70
void regfree(regex_t *preg)
Definition: GnuRegex.c:4280
static const SBuf mimeGetIcon(const char *fn)
Definition: mime.cc:147
#define O_TEXT
Definition: defines.h:140
void lock(const char *context)
Definition: store.cc:420
SBuf icon_
Definition: mime.cc:53
char * url_
Definition: mime.cc:54
Definition: SBuf.h:87
#define xstrdup
bool setPublicKey(const KeyScope keyScope=ksDefault)
Definition: store.cc:550
int type
Definition: errorpage.cc:152
C * getRaw() const
Definition: RefCount.h:80
const char * content_type
Definition: mime.cc:71
uint16_t flags
Definition: Store.h:230
#define REG_ICASE
Definition: GnuRegex.h:230
char * xstrncpy(char *dst, const char *src, size_t n)
Definition: xstring.cc:37
MimeEntry * next
Definition: mime.cc:77
void replaceHttpReply(const HttpReplyPointer &, const bool andStartWriting=true)
Definition: store.cc:1683
StatusCode
Definition: StatusCode.h:20
void file_close(int fd)
Definition: fs_io.cc:73
virtual void fillChecklist(ACLFilledChecklist &) const
configure the given checklist (to reflect the current transaction state)
Definition: mime.cc:442
#define w_space
void clear()
Definition: SBuf.cc:175
static MimeEntry * mimeGetEntry(const char *fn, int skip_encodings)
Definition: mime.cc:84
static void mimeFreeMemory(void)
Definition: mime.cc:339
Definition: mime.cc:38
a storeGetPublic*() caller
Definition: StoreClient.h:26
#define O_BINARY
Definition: defines.h:143
#define NULL
Definition: types.h:166
#define REG_EXTENDED
Definition: GnuRegex.h:226
void maxAge(int32_t v)
Definition: HttpHdrCc.h:123
#define SQUIDSBUFPRINT(s)
Definition: SBuf.h:32
void mimeInit(char *filename)
Definition: mime.cc:231
void load()
Definition: mime.cc:352
static MimeEntry * MimeTable
Definition: mime.cc:80
int use_short_names
Definition: SquidConfig.h:433
const char * dash_str
#define assert(EX)
Definition: assert.h:19
~MimeIcon()
Definition: mime.cc:127
HttpHdrCc * cache_control
Definition: Message.h:77
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
@ ENTRY_SPECIAL
Definition: enums.h:84
const char * pattern
Definition: mime.cc:69
const char * c_str()
Definition: SBuf.cc:516
const char * null_string
SBuf & append(const SBuf &S)
Definition: SBuf.cc:185
#define xfree
void putCc(const HttpHdrCc *cc)
Definition: HttpHeader.cc:1068
int regexec(regex_t *preg, const char *string, size_t nmatch, pmatch, int eflags) const
Definition: GnuRegex.c:4188
bool mimeGetViewOption(const char *fn)
Definition: mime.cc:219
int FD_READ_METHOD(int fd, char *buf, int len)
Definition: fde.h:194
void complete()
Definition: store.cc:1006
MEMPROXY_CLASS(MimeEntry)
SBuf getName() const
Definition: mime.cc:141
const char * mimeGetContentType(const char *fn)
Definition: mime.cc:177
int cmp(const SBuf &S, const size_type n) const
shorthand version for compare()
Definition: SBuf.h:268
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
bool timestampsSet()
Definition: store.cc:1371
@ scNoContent
Definition: StatusCode.h:30
MimeIcon(const char *aName)
Definition: mime.cc:121
~MimeEntry()
Definition: mime.cc:448
static HttpRequest * FromUrlXXX(const char *url, const MasterXaction::Pointer &, const HttpRequestMethod &method=Http::METHOD_GET)
Definition: HttpRequest.cc:529
const char * mimeGetContentEncoding(const char *fn)
Definition: mime.cc:191
#define Important(id)
Definition: Messages.h:91
#define DBG_IMPORTANT
Definition: Stream.h:41
StoreEntry * storeGetPublic(const char *uri, const HttpRequestMethod &method)
Definition: store.cc:479
void setName(char const *)
Definition: mime.cc:133
const char * content_encoding
Definition: mime.cc:72
struct SquidConfig::@113 icons
StoreEntry * storeCreatePureEntry(const char *url, const char *log_url, const HttpRequestMethod &method)
Definition: store.cc:716
virtual void append(char const *, int)
Appends a c-string to existing packed data.
Definition: store.cc:778
static MimeEntry ** MimeTableTail
Definition: mime.cc:81
bool view_option
Definition: mime.cc:74
const char * mimeGetIconURL(const char *fn)
Definition: mime.cc:158
void setHeaders(Http::StatusCode status, const char *reason, const char *ctype, int64_t clen, time_t lmt, time_t expires)
Definition: HttpReply.cc:167
#define MAXPATHLEN
Definition: stdio.h:62
int file_open(const char *path, int mode)
Definition: fs_io.cc:45
static struct stat sb
Definition: squidclient.cc:71
@ scOkay
Definition: StatusCode.h:26
bool mimeGetDownloadOption(const char *fn)
Definition: mime.cc:212
@ METHOD_GET
Definition: MethodType.h:25
char * internalLocalUri(const char *dir, const SBuf &name)
Definition: internal.cc:130
bool download_option
Definition: mime.cc:75
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:196
HttpRequestPointer request
Definition: MemObject.h:188
char transfer_mode
Definition: mime.cc:73
#define SQUIDSBUFPH
Definition: SBuf.h:31
char mimeGetTransferMode(const char *fn)
Definition: mime.cc:205
char * directory
Definition: SquidConfig.h:432
class SquidConfig Config
Definition: SquidConfig.cc:12
#define REG_NOSUB
Definition: GnuRegex.h:239
int regcomp(regex_t *preg, const char *pattern, int cflags)
Definition: GnuRegex.c:4117

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors