]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/mime.cc
99307d98f85035515c71a21f8479e312bd28df3c
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
:1;
78 unsigned int download_option
:1;
84 static mimeEntry
*MimeTable
= NULL
;
85 static mimeEntry
**MimeTableTail
= &MimeTable
;
88 mimeEntry::operator new (size_t byteCount
)
90 return xcalloc(1, byteCount
);
94 mimeEntry::operator delete (void *address
)
99 /* returns a pointer to a field-value of the first matching field-name */
101 mime_get_header(const char *mime
, const char *name
)
103 return mime_get_header_field(mime
, name
, NULL
);
107 * returns a pointer to a field-value of the first matching field-name where
108 * field-value matches prefix if any
111 mime_get_header_field(const char *mime
, const char *name
, const char *prefix
)
113 LOCAL_ARRAY(char, header
, GET_HDR_SZ
);
114 const char *p
= NULL
;
117 const int namelen
= name
? strlen(name
) : 0;
118 const int preflen
= prefix
? strlen(prefix
) : 0;
124 assert(NULL
!= name
);
126 debugs(25, 5, "mime_get_header: looking for '" << name
<< "'");
128 for (p
= mime
; *p
; p
+= strcspn(p
, "\n\r")) {
129 if (strcmp(p
, "\r\n\r\n") == 0 || strcmp(p
, "\n\n") == 0)
135 if (strncasecmp(p
, name
, namelen
))
138 if (!xisspace(p
[namelen
]) && p
[namelen
] != ':')
141 l
= strcspn(p
, "\n\r") + 1;
146 xstrncpy(header
, p
, l
);
148 debugs(25, 5, "mime_get_header: checking '" << header
<< "'");
161 /* we could process list entries here if we had strcasestr(). */
162 /* make sure we did not match a part of another field-value */
163 got
= !strncasecmp(q
, prefix
, preflen
) && !xisalpha(q
[preflen
]);
167 debugs(25, 5, "mime_get_header: returning '" << q
<< "'");
176 headersEnd(const char *mime
, size_t l
)
181 PROF_start(headersEnd
);
183 while (e
< l
&& state
< 3) {
196 else if ('\n' == mime
[e
])
217 PROF_stop(headersEnd
);
226 mimeGetEntry(const char *fn
, int skip_encodings
)
230 char *name
= xstrdup(fn
);
234 for (m
= MimeTable
; m
; m
= m
->next
) {
235 if (regexec(&m
->compiled_pattern
, name
, 0, 0, 0) == 0)
243 else if (strcmp(m
->content_type
, dash_str
))
245 else if (!strcmp(m
->content_encoding
, dash_str
))
248 /* Assume we matched /\.\w$/ and cut off the last extension */
249 if ((t
= strrchr(name
, '.'))) {
252 /* What? A encoding without a extension? */
262 MimeIcon::MimeIcon () : icon (NULL
), url (NULL
)
266 MimeIcon::setName (char const *aString
)
270 icon
= xstrdup (aString
);
271 url
= xstrdup (internalLocalUri("/squid-internal-static/icons/", icon
));
275 MimeIcon::getName () const
289 mimeGetIcon(const char *fn
)
291 mimeEntry
*m
= mimeGetEntry(fn
, 1);
296 if (!strcmp(m
->theIcon
.getName(), dash_str
))
299 return m
->theIcon
.getName();
303 mimeGetIconURL(const char *fn
)
305 char const *icon
= mimeGetIcon(fn
);
310 if (Config
.icons
.use_short_names
) {
313 mb
.Printf("/squid-internal-static/icons/%s", icon
);
316 return internalLocalUri("/squid-internal-static/icons/", icon
);
321 mimeGetContentType(const char *fn
)
323 mimeEntry
*m
= mimeGetEntry(fn
, 1);
328 if (!strcmp(m
->content_type
, dash_str
))
331 return m
->content_type
;
335 mimeGetContentEncoding(const char *fn
)
337 mimeEntry
*m
= mimeGetEntry(fn
, 0);
342 if (!strcmp(m
->content_encoding
, dash_str
))
345 return m
->content_encoding
;
349 mimeGetTransferMode(const char *fn
)
351 mimeEntry
*m
= mimeGetEntry(fn
, 0);
352 return m
? m
->transfer_mode
: 'I';
356 mimeGetDownloadOption(const char *fn
)
358 mimeEntry
*m
= mimeGetEntry(fn
, 1);
359 return m
? m
->download_option
: 0;
363 mimeGetViewOption(const char *fn
)
365 mimeEntry
*m
= mimeGetEntry(fn
, 0);
366 return m
? m
->view_option
: 0;
369 /* Initializes/reloads the mime table
370 * Note: Due to Solaris STDIO problems the caller should NOT
371 * call mimeFreeMemory on reconfigure. This way, if STDIO
372 * fails we at least have the old copy loaded.
375 mimeInit(char *filename
)
379 char chopbuf
[BUFSIZ
];
391 int re_flags
= REG_EXTENDED
| REG_NOSUB
| REG_ICASE
;
393 if (filename
== NULL
)
396 if ((fp
= fopen(filename
, "r")) == NULL
) {
397 debugs(25, 1, "mimeInit: " << filename
<< ": " << xstrerror());
402 setmode(fileno(fp
), O_TEXT
);
408 while (fgets(buf
, BUFSIZ
, fp
)) {
409 if ((t
= strchr(buf
, '#')))
412 if ((t
= strchr(buf
, '\r')))
415 if ((t
= strchr(buf
, '\n')))
421 xstrncpy(chopbuf
, buf
, BUFSIZ
);
423 if ((pattern
= strtok(chopbuf
, w_space
)) == NULL
) {
424 debugs(25, 1, "mimeInit: parse error: '" << buf
<< "'");
428 if ((type
= strtok(NULL
, w_space
)) == NULL
) {
429 debugs(25, 1, "mimeInit: parse error: '" << buf
<< "'");
433 if ((icon
= strtok(NULL
, w_space
)) == NULL
) {
434 debugs(25, 1, "mimeInit: parse error: '" << buf
<< "'");
438 if ((encoding
= strtok(NULL
, w_space
)) == NULL
) {
439 debugs(25, 1, "mimeInit: parse error: '" << buf
<< "'");
443 if ((mode
= strtok(NULL
, w_space
)) == NULL
) {
444 debugs(25, 1, "mimeInit: parse error: '" << buf
<< "'");
451 while ((option
= strtok(NULL
, w_space
)) != NULL
) {
452 if (!strcmp(option
, "+download"))
454 else if (!strcmp(option
, "+view"))
457 debugs(25, 1, "mimeInit: unknown option: '" << buf
<< "' (" << option
<< ")");
460 if (regcomp(&re
, pattern
, re_flags
) != 0) {
461 debugs(25, 1, "mimeInit: regcomp error: '" << buf
<< "'");
466 m
->pattern
= xstrdup(pattern
);
467 m
->content_type
= xstrdup(type
);
468 m
->theIcon
.setName(icon
);
469 m
->content_encoding
= xstrdup(encoding
);
470 m
->compiled_pattern
= re
;
472 if (!strcasecmp(mode
, "ascii"))
473 m
->transfer_mode
= 'A';
474 else if (!strcasecmp(mode
, "text"))
475 m
->transfer_mode
= 'A';
477 m
->transfer_mode
= 'I';
479 m
->view_option
= view_option
;
481 m
->download_option
= download_option
;
485 MimeTableTail
= &m
->next
;
487 debugs(25, 5, "mimeInit: added '" << buf
<< "'");
492 * Create Icon StoreEntry's
495 for (m
= MimeTable
; m
!= NULL
; m
= m
->next
)
498 debugs(25, 1, "Loaded Icons.");
506 while ((m
= MimeTable
)) {
508 safe_free(m
->pattern
);
509 safe_free(m
->content_type
);
511 safe_free(m
->content_encoding
);
512 regfree(&m
->compiled_pattern
);
516 MimeTableTail
= &MimeTable
;
522 const char *type
= mimeGetContentType(icon
);
525 fatal("Unknown icon format while reading mime.conf\n");
527 StoreEntry::getPublic(this, url
, METHOD_GET
);
531 MimeIcon::created (StoreEntry
*newEntry
)
533 /* is already in the store, do nothing */
535 if (!newEntry
->isNull())
546 LOCAL_ARRAY(char, path
, MAXPATHLEN
);
550 snprintf(path
, MAXPATHLEN
, "%s/%s", Config
.icons
.directory
, icon
);
552 fd
= file_open(path
, O_RDONLY
| O_BINARY
);
555 debugs(25, 0, "mimeLoadIconFile: " << path
<< ": " << xstrerror());
559 if (fstat(fd
, &sb
) < 0) {
560 debugs(25, 0, "mimeLoadIconFile: FD " << fd
<< ": fstat: " << xstrerror());
566 StoreEntry
*e
= storeCreateEntry(url
,
571 EBIT_SET(e
->flags
, ENTRY_SPECIAL
);
574 HttpRequest
*r
= HttpRequest::CreateFromUrl(url
);
577 fatal("mimeLoadIcon: cannot parse internal URL");
579 e
->mem_obj
->request
= HTTPMSGLOCK(r
);
581 HttpReply
*reply
= new HttpReply
;
583 HttpVersion
version(1, 0);
585 reply
->setHeaders(version
, HTTP_OK
, NULL
,
586 mimeGetContentType(icon
), sb
.st_size
, sb
.st_mtime
, -1);
588 reply
->cache_control
= httpHdrCcCreate();
590 httpHdrCcSetMaxAge(reply
->cache_control
, 86400);
592 reply
->header
.putCc(reply
->cache_control
);
594 e
->replaceHttpReply(reply
);
596 /* read the file into the buffer and append it to store */
597 buf
= (char *)memAllocate(MEM_4K_BUF
);
599 while ((n
= FD_READ_METHOD(fd
, buf
, 4096)) > 0)
610 debugs(25, 3, "Loaded icon " << url
);
614 memFree(buf
, MEM_4K_BUF
);