]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/mime.cc
3 * $Id: mime.cc,v 1.132 2007/08/13 17:20:51 hno Exp $
5 * DEBUG: section 25 MIME Parsing
6 * AUTHOR: Harvest Derived
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
38 #include "StoreClient.h"
39 #include "HttpReply.h"
40 #include "HttpRequest.h"
41 #include "MemObject.h"
45 #define GET_HDR_SZ 1024
47 class MimeIcon
: public StoreClient
52 void setName (char const *);
53 char const * getName () const;
56 void created (StoreEntry
*newEntry
);
67 void *operator new (size_t byteCount
);
68 void operator delete (void *address
);
71 regex_t compiled_pattern
;
74 char *content_encoding
;
77 unsigned int view_option
:
80 unsigned int download_option
:
86 static mimeEntry
*MimeTable
= NULL
;
87 static mimeEntry
**MimeTableTail
= &MimeTable
;
90 mimeEntry::operator new (size_t byteCount
)
92 return xcalloc(1, byteCount
);
96 mimeEntry::operator delete (void *address
)
101 /* returns a pointer to a field-value of the first matching field-name */
103 mime_get_header(const char *mime
, const char *name
)
105 return mime_get_header_field(mime
, name
, NULL
);
109 * returns a pointer to a field-value of the first matching field-name where
110 * field-value matches prefix if any
113 mime_get_header_field(const char *mime
, const char *name
, const char *prefix
)
115 LOCAL_ARRAY(char, header
, GET_HDR_SZ
);
116 const char *p
= NULL
;
119 const int namelen
= name
? strlen(name
) : 0;
120 const int preflen
= prefix
? strlen(prefix
) : 0;
126 assert(NULL
!= name
);
128 debugs(25, 5, "mime_get_header: looking for '" << name
<< "'");
130 for (p
= mime
; *p
; p
+= strcspn(p
, "\n\r")) {
131 if (strcmp(p
, "\r\n\r\n") == 0 || strcmp(p
, "\n\n") == 0)
137 if (strncasecmp(p
, name
, namelen
))
140 if (!xisspace(p
[namelen
]) && p
[namelen
] != ':')
143 l
= strcspn(p
, "\n\r") + 1;
148 xstrncpy(header
, p
, l
);
150 debugs(25, 5, "mime_get_header: checking '" << header
<< "'");
163 /* we could process list entries here if we had strcasestr(). */
164 /* make sure we did not match a part of another field-value */
165 got
= !strncasecmp(q
, prefix
, preflen
) && !xisalpha(q
[preflen
]);
169 debugs(25, 5, "mime_get_header: returning '" << q
<< "'");
178 headersEnd(const char *mime
, size_t l
)
183 PROF_start(headersEnd
);
185 while (e
< l
&& state
< 3) {
198 else if ('\n' == mime
[e
])
219 PROF_stop(headersEnd
);
228 mimeGetEntry(const char *fn
, int skip_encodings
)
232 char *name
= xstrdup(fn
);
236 for (m
= MimeTable
; m
; m
= m
->next
) {
237 if (regexec(&m
->compiled_pattern
, name
, 0, 0, 0) == 0)
245 else if (strcmp(m
->content_type
, dash_str
))
247 else if (!strcmp(m
->content_encoding
, dash_str
))
250 /* Assume we matched /\.\w$/ and cut off the last extension */
252 if ((t
= strrchr(name
, '.'))) {
257 /* What? A encoding without a extension? */
265 MimeIcon::MimeIcon () : icon (NULL
), url (NULL
)
269 MimeIcon::setName (char const *aString
)
273 icon
= xstrdup (aString
);
274 url
= xstrdup (internalLocalUri("/squid-internal-static/icons/", icon
));
278 MimeIcon::getName () const
292 mimeGetIcon(const char *fn
)
294 mimeEntry
*m
= mimeGetEntry(fn
, 1);
299 if (!strcmp(m
->theIcon
.getName(), dash_str
))
302 return m
->theIcon
.getName();
306 mimeGetIconURL(const char *fn
)
308 char const *icon
= mimeGetIcon(fn
);
313 if (Config
.icons
.use_short_names
) {
316 mb
.Printf("/squid-internal-static/icons/%s", icon
);
319 return internalLocalUri("/squid-internal-static/icons/", icon
);
324 mimeGetContentType(const char *fn
)
326 mimeEntry
*m
= mimeGetEntry(fn
, 1);
331 if (!strcmp(m
->content_type
, dash_str
))
334 return m
->content_type
;
338 mimeGetContentEncoding(const char *fn
)
340 mimeEntry
*m
= mimeGetEntry(fn
, 0);
345 if (!strcmp(m
->content_encoding
, dash_str
))
348 return m
->content_encoding
;
352 mimeGetTransferMode(const char *fn
)
354 mimeEntry
*m
= mimeGetEntry(fn
, 0);
355 return m
? m
->transfer_mode
: 'I';
359 mimeGetDownloadOption(const char *fn
)
361 mimeEntry
*m
= mimeGetEntry(fn
, 1);
362 return m
? m
->download_option
: 0;
366 mimeGetViewOption(const char *fn
)
368 mimeEntry
*m
= mimeGetEntry(fn
, 0);
369 return m
? m
->view_option
: 0;
372 /* Initializes/reloads the mime table
373 * Note: Due to Solaris STDIO problems the caller should NOT
374 * call mimeFreeMemory on reconfigure. This way, if STDIO
375 * fails we at least have the old copy loaded.
378 mimeInit(char *filename
)
382 char chopbuf
[BUFSIZ
];
394 int re_flags
= REG_EXTENDED
| REG_NOSUB
| REG_ICASE
;
396 if (filename
== NULL
)
399 if ((fp
= fopen(filename
, "r")) == NULL
) {
400 debugs(25, 1, "mimeInit: " << filename
<< ": " << xstrerror());
405 setmode(fileno(fp
), O_TEXT
);
411 while (fgets(buf
, BUFSIZ
, fp
)) {
412 if ((t
= strchr(buf
, '#')))
415 if ((t
= strchr(buf
, '\r')))
418 if ((t
= strchr(buf
, '\n')))
424 xstrncpy(chopbuf
, buf
, BUFSIZ
);
426 if ((pattern
= strtok(chopbuf
, w_space
)) == NULL
) {
427 debugs(25, 1, "mimeInit: parse error: '" << buf
<< "'");
431 if ((type
= strtok(NULL
, w_space
)) == NULL
) {
432 debugs(25, 1, "mimeInit: parse error: '" << buf
<< "'");
436 if ((icon
= strtok(NULL
, w_space
)) == NULL
) {
437 debugs(25, 1, "mimeInit: parse error: '" << buf
<< "'");
441 if ((encoding
= strtok(NULL
, w_space
)) == NULL
) {
442 debugs(25, 1, "mimeInit: parse error: '" << buf
<< "'");
446 if ((mode
= strtok(NULL
, w_space
)) == NULL
) {
447 debugs(25, 1, "mimeInit: parse error: '" << buf
<< "'");
454 while ((option
= strtok(NULL
, w_space
)) != NULL
) {
455 if (!strcmp(option
, "+download"))
457 else if (!strcmp(option
, "+view"))
460 debugs(25, 1, "mimeInit: unknown option: '" << buf
<< "' (" << option
<< ")");
463 if (regcomp(&re
, pattern
, re_flags
) != 0) {
464 debugs(25, 1, "mimeInit: regcomp error: '" << buf
<< "'");
469 m
->pattern
= xstrdup(pattern
);
470 m
->content_type
= xstrdup(type
);
471 m
->theIcon
.setName(icon
);
472 m
->content_encoding
= xstrdup(encoding
);
473 m
->compiled_pattern
= re
;
475 if (!strcasecmp(mode
, "ascii"))
476 m
->transfer_mode
= 'A';
477 else if (!strcasecmp(mode
, "text"))
478 m
->transfer_mode
= 'A';
480 m
->transfer_mode
= 'I';
482 m
->view_option
= view_option
;
484 m
->download_option
= download_option
;
488 MimeTableTail
= &m
->next
;
490 debugs(25, 5, "mimeInit: added '" << buf
<< "'");
495 * Create Icon StoreEntry's
498 for (m
= MimeTable
; m
!= NULL
; m
= m
->next
)
501 debugs(25, 1, "Loaded Icons.");
509 while ((m
= MimeTable
)) {
511 safe_free(m
->pattern
);
512 safe_free(m
->content_type
);
514 safe_free(m
->content_encoding
);
515 regfree(&m
->compiled_pattern
);
519 MimeTableTail
= &MimeTable
;
525 const char *type
= mimeGetContentType(icon
);
528 fatal("Unknown icon format while reading mime.conf\n");
530 StoreEntry::getPublic(this, url
, METHOD_GET
);
534 MimeIcon::created (StoreEntry
*newEntry
)
536 /* is already in the store, do nothing */
538 if (!newEntry
->isNull())
549 LOCAL_ARRAY(char, path
, MAXPATHLEN
);
553 snprintf(path
, MAXPATHLEN
, "%s/%s", Config
.icons
.directory
, icon
);
555 fd
= file_open(path
, O_RDONLY
| O_BINARY
);
558 debugs(25, 0, "mimeLoadIconFile: " << path
<< ": " << xstrerror());
562 if (fstat(fd
, &sb
) < 0) {
563 debugs(25, 0, "mimeLoadIconFile: FD " << fd
<< ": fstat: " << xstrerror());
569 StoreEntry
*e
= storeCreateEntry(url
,
574 EBIT_SET(e
->flags
, ENTRY_SPECIAL
);
577 HttpRequest
*r
= HttpRequest::CreateFromUrl(url
);
580 fatal("mimeLoadIcon: cannot parse internal URL");
582 e
->mem_obj
->request
= HTTPMSGLOCK(r
);
584 HttpReply
*reply
= new HttpReply
;
586 HttpVersion
version(1, 0);
588 reply
->setHeaders(version
, HTTP_OK
, NULL
,
589 mimeGetContentType(icon
), sb
.st_size
, sb
.st_mtime
, -1);
591 reply
->cache_control
= httpHdrCcCreate();
593 httpHdrCcSetMaxAge(reply
->cache_control
, 86400);
595 reply
->header
.putCc(reply
->cache_control
);
597 e
->replaceHttpReply(reply
);
599 /* read the file into the buffer and append it to store */
600 buf
= (char *)memAllocate(MEM_4K_BUF
);
602 while ((n
= FD_READ_METHOD(fd
, buf
, 4096)) > 0)
613 debugs(25, 3, "Loaded icon " << url
);
617 memFree(buf
, MEM_4K_BUF
);