]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/mime.cc
2 * Copyright (C) 1996-2016 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 "base/RegexPattern.h"
16 #include "HttpHdrCc.h"
17 #include "HttpReply.h"
18 #include "HttpRequest.h"
21 #include "MemObject.h"
23 #include "RequestFlags.h"
24 #include "SquidConfig.h"
26 #include "StoreClient.h"
34 /* forward declarations */
35 static void mimeFreeMemory(void);
36 static const SBuf
mimeGetIcon(const char *fn
);
38 class MimeIcon
: public StoreClient
40 MEMPROXY_CLASS(MimeIcon
);
43 explicit MimeIcon(const char *aName
);
45 void setName(char const *);
50 virtual void created(StoreEntry
*);
59 MEMPROXY_CLASS(MimeEntry
);
62 MimeEntry(const char *aPattern
, const decltype(RegexPattern::flags
) &reFlags
,
63 const char *aContentType
,
64 const char *aContentEncoding
, const char *aTransferMode
,
65 bool optionViewEnable
, bool optionDownloadEnable
,
66 const char *anIconName
);
67 MimeEntry(const MimeEntry
&) = delete;
68 MimeEntry(const MimeEntry
&&) = delete;
72 const char *content_type
;
73 const char *content_encoding
;
81 static MimeEntry
*MimeTable
= NULL
;
82 static MimeEntry
**MimeTableTail
= &MimeTable
;
85 mimeGetEntry(const char *fn
, int skip_encodings
)
89 char *name
= xstrdup(fn
);
94 for (m
= MimeTable
; m
; m
= m
->next
) {
95 if (m
->pattern
.match(name
))
103 else if (strcmp(m
->content_type
, dash_str
))
105 else if (!strcmp(m
->content_encoding
, dash_str
))
108 /* Assume we matched /\.\w$/ and cut off the last extension */
109 if ((t
= strrchr(name
, '.'))) {
112 /* What? A encoding without a extension? */
122 MimeIcon::MimeIcon(const char *aName
) :
128 MimeIcon::~MimeIcon()
134 MimeIcon::setName(char const *aString
)
138 url_
= xstrdup(internalLocalUri("/squid-internal-static/icons/", icon_
));
142 MimeIcon::getName() const
148 mimeGetIcon(const char *fn
)
150 MimeEntry
*m
= mimeGetEntry(fn
, 1);
152 if (!m
|| !m
->theIcon
.getName().cmp(dash_str
))
155 return m
->theIcon
.getName();
159 mimeGetIconURL(const char *fn
)
161 SBuf
icon(mimeGetIcon(fn
));
166 if (Config
.icons
.use_short_names
) {
169 mb
.append("/squid-internal-static/icons/");
173 return internalLocalUri("/squid-internal-static/icons/", icon
);
178 mimeGetContentType(const char *fn
)
180 MimeEntry
*m
= mimeGetEntry(fn
, 1);
185 if (!strcmp(m
->content_type
, dash_str
))
188 return m
->content_type
;
192 mimeGetContentEncoding(const char *fn
)
194 MimeEntry
*m
= mimeGetEntry(fn
, 0);
199 if (!strcmp(m
->content_encoding
, dash_str
))
202 return m
->content_encoding
;
206 mimeGetTransferMode(const char *fn
)
208 MimeEntry
*m
= mimeGetEntry(fn
, 0);
209 return m
? m
->transfer_mode
: 'I';
213 mimeGetDownloadOption(const char *fn
)
215 MimeEntry
*m
= mimeGetEntry(fn
, 1);
216 return m
? m
->download_option
: 0;
220 mimeGetViewOption(const char *fn
)
222 MimeEntry
*m
= mimeGetEntry(fn
, 0);
223 return m
!= 0 ? m
->view_option
: false;
226 /* Initializes/reloads the mime table
227 * Note: Due to Solaris STDIO problems the caller should NOT
228 * call mimeFreeMemory on reconfigure. This way, if STDIO
229 * fails we at least have the old copy loaded.
232 mimeInit(char *filename
)
236 char chopbuf
[BUFSIZ
];
247 if (filename
== NULL
)
250 if ((fp
= fopen(filename
, "r")) == NULL
) {
252 debugs(25, DBG_IMPORTANT
, "mimeInit: " << filename
<< ": " << xstrerr(xerrno
));
257 setmode(fileno(fp
), O_TEXT
);
262 const auto re_flags
= std::regex::extended
| std::regex::nosubs
| std::regex::icase
;
264 while (fgets(buf
, BUFSIZ
, fp
)) {
265 if ((t
= strchr(buf
, '#')))
268 if ((t
= strchr(buf
, '\r')))
271 if ((t
= strchr(buf
, '\n')))
277 xstrncpy(chopbuf
, buf
, BUFSIZ
);
280 if ((pattern
= strtok(chopbuf
, w_space
)) == NULL
) {
281 debugs(25, DBG_IMPORTANT
, "mimeInit: parse error: '" << buf
<< "'");
285 if ((type
= strtok(NULL
, w_space
)) == NULL
) {
286 debugs(25, DBG_IMPORTANT
, "mimeInit: parse error: '" << buf
<< "'");
290 if ((icon
= strtok(NULL
, w_space
)) == NULL
) {
291 debugs(25, DBG_IMPORTANT
, "mimeInit: parse error: '" << buf
<< "'");
295 if ((encoding
= strtok(NULL
, w_space
)) == NULL
) {
296 debugs(25, DBG_IMPORTANT
, "mimeInit: parse error: '" << buf
<< "'");
300 if ((mode
= strtok(NULL
, w_space
)) == NULL
) {
301 debugs(25, DBG_IMPORTANT
, "mimeInit: parse error: '" << buf
<< "'");
308 while ((option
= strtok(NULL
, w_space
)) != NULL
) {
309 if (!strcmp(option
, "+download"))
311 else if (!strcmp(option
, "+view"))
314 debugs(25, DBG_IMPORTANT
, "mimeInit: unknown option: '" << buf
<< "' (" << option
<< ")");
318 m
= new MimeEntry(pattern
, re_flags
, type
, encoding
, mode
, view_option
, download_option
, icon
);
320 } catch (std::regex_error
&e
) {
321 debugs(25, DBG_IMPORTANT
, "mimeInit: invalid regular expression: '" << buf
<< "'");
327 MimeTableTail
= &m
->next
;
329 debugs(25, 5, "mimeInit: added '" << buf
<< "'");
334 for (m
= MimeTable
; m
!= NULL
; m
= m
->next
)
336 debugs(25, DBG_IMPORTANT
, "Finished loading MIME types and icons.");
344 while ((m
= MimeTable
)) {
349 MimeTableTail
= &MimeTable
;
355 const char *type
= mimeGetContentType(icon_
.c_str());
358 fatal("Unknown icon format while reading mime.conf\n");
360 StoreEntry::getPublic(this, url_
, Http::METHOD_GET
);
364 MimeIcon::created(StoreEntry
*newEntry
)
366 /* if the icon is already in the store, do nothing */
367 if (!newEntry
->isNull())
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 // fill newEntry with a canned 2xx response object
401 flags
.cachable
= true;
402 StoreEntry
*e
= storeCreateEntry(url_
,url_
,flags
,Http::METHOD_GET
);
404 EBIT_SET(e
->flags
, ENTRY_SPECIAL
);
407 HttpRequest
*r
= HttpRequest::CreateFromUrl(url_
);
410 fatalf("mimeLoadIcon: cannot parse internal URL: %s", url_
);
412 e
->mem_obj
->request
= r
;
413 HTTPMSGLOCK(e
->mem_obj
->request
);
415 HttpReply
*reply
= new HttpReply
;
417 if (status
== Http::scNoContent
)
418 reply
->setHeaders(status
, NULL
, NULL
, 0, -1, -1);
420 reply
->setHeaders(status
, NULL
, mimeGetContentType(icon_
.c_str()), sb
.st_size
, sb
.st_mtime
, -1);
421 reply
->cache_control
= new HttpHdrCc();
422 reply
->cache_control
->maxAge(86400);
423 reply
->header
.putCc(reply
->cache_control
);
424 e
->replaceHttpReply(reply
);
426 if (status
== Http::scOkay
) {
427 /* read the file into the buffer and append it to store */
429 std::array
<char, 4096> buf
;
430 while ((n
= FD_READ_METHOD(fd
, buf
.data(), buf
.size())) > 0)
431 e
->append(buf
.data(), n
);
439 e
->unlock("MimeIcon::created");
440 debugs(25, 3, "Loaded icon " << url_
);
443 MimeEntry::~MimeEntry()
446 xfree(content_encoding
);
449 MimeEntry::MimeEntry(const char *aPattern
, const decltype(RegexPattern::flags
) &reFlags
,
450 const char *aContentType
, const char *aContentEncoding
,
451 const char *aTransferMode
, bool optionViewEnable
,
452 bool optionDownloadEnable
, const char *anIconName
) :
453 pattern(reFlags
, aPattern
),
454 content_type(xstrdup(aContentType
)),
455 content_encoding(xstrdup(aContentEncoding
)),
456 view_option(optionViewEnable
),
457 download_option(optionDownloadEnable
),
461 if (!strcasecmp(aTransferMode
, "ascii"))
463 else if (!strcasecmp(aTransferMode
, "text"))