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