]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/mime.cc
95f9ba16d2577bb2a97c56a4d974dc4225da0d53
2 * Copyright (C) 1996-2022 The Squid Software Foundation and contributors
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.
9 /* DEBUG: section 25 MIME Parsing and Internal Icons */
12 #include "debug/Messages.h"
16 #include "HttpHdrCc.h"
17 #include "HttpReply.h"
18 #include "HttpRequest.h"
21 #include "MemObject.h"
23 #include "SquidConfig.h"
25 #include "StoreClient.h"
37 /* forward declarations */
38 static void mimeFreeMemory(void);
39 static const SBuf
mimeGetIcon(const char *fn
);
41 class MimeIcon
: public StoreClient
43 MEMPROXY_CLASS(MimeIcon
);
46 explicit MimeIcon(const char *aName
);
48 void setName(char const *);
53 LogTags
*loggingTags() const override
{ return nullptr; } // no access logging/ACLs
54 void fillChecklist(ACLFilledChecklist
&) const override
;
63 MEMPROXY_CLASS(MimeEntry
);
66 explicit MimeEntry(const char *aPattern
, const regex_t
&compiledPattern
,
67 const char *aContentType
,
68 const char *aContentEncoding
, const char *aTransferMode
,
69 bool optionViewEnable
, bool optionDownloadEnable
,
70 const char *anIconName
);
74 regex_t compiled_pattern
;
75 const char *content_type
;
76 const char *content_encoding
;
84 static MimeEntry
*MimeTable
= nullptr;
85 static MimeEntry
**MimeTableTail
= &MimeTable
;
88 mimeGetEntry(const char *fn
, int skip_encodings
)
92 char *name
= xstrdup(fn
);
97 for (m
= MimeTable
; m
; m
= m
->next
) {
98 if (regexec(&m
->compiled_pattern
, name
, 0, nullptr, 0) == 0)
104 else if (m
== nullptr)
106 else if (strcmp(m
->content_type
, dash_str
))
108 else if (!strcmp(m
->content_encoding
, dash_str
))
111 /* Assume we matched /\.\w$/ and cut off the last extension */
112 if ((t
= strrchr(name
, '.'))) {
115 /* What? A encoding without a extension? */
125 MimeIcon::MimeIcon(const char *aName
) :
131 MimeIcon::~MimeIcon()
137 MimeIcon::setName(char const *aString
)
141 url_
= xstrdup(internalLocalUri("/squid-internal-static/icons/", icon_
));
145 MimeIcon::getName() const
151 mimeGetIcon(const char *fn
)
153 MimeEntry
*m
= mimeGetEntry(fn
, 1);
155 if (!m
|| !m
->theIcon
.getName().cmp(dash_str
))
158 return m
->theIcon
.getName();
162 mimeGetIconURL(const char *fn
)
164 SBuf
icon(mimeGetIcon(fn
));
169 if (Config
.icons
.use_short_names
) {
172 mb
.append("/squid-internal-static/icons/");
176 return internalLocalUri("/squid-internal-static/icons/", icon
);
181 mimeGetContentType(const char *fn
)
183 MimeEntry
*m
= mimeGetEntry(fn
, 1);
188 if (!strcmp(m
->content_type
, dash_str
))
191 return m
->content_type
;
195 mimeGetContentEncoding(const char *fn
)
197 MimeEntry
*m
= mimeGetEntry(fn
, 0);
202 if (!strcmp(m
->content_encoding
, dash_str
))
205 return m
->content_encoding
;
209 mimeGetTransferMode(const char *fn
)
211 MimeEntry
*m
= mimeGetEntry(fn
, 0);
212 return m
? m
->transfer_mode
: 'I';
216 mimeGetDownloadOption(const char *fn
)
218 MimeEntry
*m
= mimeGetEntry(fn
, 1);
219 return m
? m
->download_option
: 0;
223 mimeGetViewOption(const char *fn
)
225 MimeEntry
*m
= mimeGetEntry(fn
, 0);
226 return m
!= nullptr ? m
->view_option
: false;
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.
235 mimeInit(char *filename
)
239 char chopbuf
[BUFSIZ
];
251 int re_flags
= REG_EXTENDED
| REG_NOSUB
| REG_ICASE
;
253 if (filename
== nullptr)
256 if ((fp
= fopen(filename
, "r")) == nullptr) {
258 debugs(25, DBG_IMPORTANT
, "mimeInit: " << filename
<< ": " << xstrerr(xerrno
));
263 setmode(fileno(fp
), O_TEXT
);
268 while (fgets(buf
, BUFSIZ
, fp
)) {
269 if ((t
= strchr(buf
, '#')))
272 if ((t
= strchr(buf
, '\r')))
275 if ((t
= strchr(buf
, '\n')))
281 xstrncpy(chopbuf
, buf
, BUFSIZ
);
283 if ((pattern
= strtok(chopbuf
, w_space
)) == nullptr) {
284 debugs(25, DBG_IMPORTANT
, "ERROR: mimeInit: parse failure: '" << buf
<< "'");
288 if ((type
= strtok(nullptr, w_space
)) == nullptr) {
289 debugs(25, DBG_IMPORTANT
, "ERROR: mimeInit: parse failure: '" << buf
<< "'");
293 if ((icon
= strtok(nullptr, w_space
)) == nullptr) {
294 debugs(25, DBG_IMPORTANT
, "ERROR: mimeInit: parse failure: '" << buf
<< "'");
298 if ((encoding
= strtok(nullptr, w_space
)) == nullptr) {
299 debugs(25, DBG_IMPORTANT
, "ERROR: mimeInit: parse failure: '" << buf
<< "'");
303 if ((mode
= strtok(nullptr, w_space
)) == nullptr) {
304 debugs(25, DBG_IMPORTANT
, "ERROR: mimeInit: parse failure: '" << buf
<< "'");
311 while ((option
= strtok(nullptr, w_space
)) != nullptr) {
312 if (!strcmp(option
, "+download"))
314 else if (!strcmp(option
, "+view"))
317 debugs(25, DBG_IMPORTANT
, "ERROR: mimeInit: unknown option: '" << buf
<< "' (" << option
<< ")");
320 if (regcomp(&re
, pattern
, re_flags
) != 0) {
321 debugs(25, DBG_IMPORTANT
, "ERROR: mimeInit: regcomp failure: '" << buf
<< "'");
325 m
= new MimeEntry(pattern
,re
,type
,encoding
,mode
,view_option
,
326 download_option
,icon
);
330 MimeTableTail
= &m
->next
;
332 debugs(25, 5, "mimeInit: added '" << buf
<< "'");
337 for (m
= MimeTable
; m
!= nullptr; m
= m
->next
)
339 debugs(25, Important(28), "Finished loading MIME types and icons.");
347 while ((m
= MimeTable
)) {
352 MimeTableTail
= &MimeTable
;
358 const char *type
= mimeGetContentType(icon_
.c_str());
361 fatal("Unknown icon format while reading mime.conf\n");
363 if (const auto e
= storeGetPublic(url_
, Http::METHOD_GET
)) {
364 // do not overwrite an already stored icon
365 e
->abandon(__FUNCTION__
);
369 // XXX: if a 204 is cached due to earlier load 'failure' we should try to reload.
371 // default is a 200 object with image data.
372 // set to the backup value of 204 on image loading errors
373 Http::StatusCode status
= Http::scOkay
;
375 static char path
[MAXPATHLEN
];
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
;
384 if (status
== Http::scOkay
&& (fd
= file_open(path
, O_RDONLY
| O_BINARY
)) < 0) {
386 debugs(25, DBG_CRITICAL
, "ERROR: opening icon file " << path
<< ": " << xstrerr(xerrno
));
387 status
= Http::scNoContent
;
392 if (status
== Http::scOkay
&& fstat(fd
, &sb
) < 0) {
394 debugs(25, DBG_CRITICAL
, "ERROR: opening icon file " << path
<< " FD " << fd
<< ", fstat error " << xstrerr(xerrno
));
396 status
= Http::scNoContent
;
399 StoreEntry
*e
= storeCreatePureEntry(url_
, url_
, Http::METHOD_GET
);
400 e
->lock("MimeIcon::created");
401 EBIT_SET(e
->flags
, ENTRY_SPECIAL
);
402 const auto madePublic
= e
->setPublicKey();
403 assert(madePublic
); // nothing can block ENTRY_SPECIAL from becoming public
405 /* fill `e` with a canned 2xx response object */
407 const auto mx
= MasterXaction::MakePortless
<XactionInitiator::initIcon
>();
408 HttpRequestPointer
r(HttpRequest::FromUrlXXX(url_
, mx
));
410 fatalf("mimeLoadIcon: cannot parse internal URL: %s", url_
);
414 e
->mem_obj
->request
= r
;
416 HttpReplyPointer
reply(new HttpReply
);
418 if (status
== Http::scNoContent
)
419 reply
->setHeaders(status
, nullptr, nullptr, 0, -1, -1);
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());
427 if (status
== Http::scOkay
) {
428 /* read the file into the buffer and append it to store */
430 std::array
<char, 4096> buf
;
431 while ((n
= FD_READ_METHOD(fd
, buf
.data(), buf
.size())) > 0)
432 e
->append(buf
.data(), n
);
440 // MimeIcons are only loaded once, prevent accidental destruction
441 // e->unlock("MimeIcon::created");
442 debugs(25, 3, "Loaded icon " << url_
);
446 MimeIcon::fillChecklist(ACLFilledChecklist
&) const
448 // Unreachable: We never mayInitiateCollapsing() or startCollapsingOn().
452 MimeEntry::~MimeEntry()
456 xfree(content_encoding
);
457 regfree(&compiled_pattern
);
460 MimeEntry::MimeEntry(const char *aPattern
, const regex_t
&compiledPattern
,
461 const char *aContentType
, const char *aContentEncoding
,
462 const char *aTransferMode
, bool optionViewEnable
,
463 bool optionDownloadEnable
, const char *anIconName
) :
464 pattern(xstrdup(aPattern
)),
465 compiled_pattern(compiledPattern
),
466 content_type(xstrdup(aContentType
)),
467 content_encoding(xstrdup(aContentEncoding
)),
468 view_option(optionViewEnable
),
469 download_option(optionDownloadEnable
),
470 theIcon(anIconName
), next(nullptr)
472 if (!strcasecmp(aTransferMode
, "ascii"))
474 else if (!strcasecmp(aTransferMode
, "text"))