mime.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:11k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: mime.c,v 1.84.2.3 1999/02/12 22:18:59 wessels Exp $
  3.  *
  4.  * DEBUG: section 25    MIME Parsing
  5.  * AUTHOR: Harvest Derived
  6.  *
  7.  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
  8.  * ----------------------------------------------------------
  9.  *
  10.  *  Squid is the result of efforts by numerous individuals from the
  11.  *  Internet community.  Development is led by Duane Wessels of the
  12.  *  National Laboratory for Applied Network Research and funded by the
  13.  *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
  14.  *  Duane Wessels and the University of California San Diego.  Please
  15.  *  see the COPYRIGHT file for full details.  Squid incorporates
  16.  *  software developed and/or copyrighted by other sources.  Please see
  17.  *  the CREDITS file for full details.
  18.  *
  19.  *  This program is free software; you can redistribute it and/or modify
  20.  *  it under the terms of the GNU General Public License as published by
  21.  *  the Free Software Foundation; either version 2 of the License, or
  22.  *  (at your option) any later version.
  23.  *  
  24.  *  This program is distributed in the hope that it will be useful,
  25.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  26.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27.  *  GNU General Public License for more details.
  28.  *  
  29.  *  You should have received a copy of the GNU General Public License
  30.  *  along with this program; if not, write to the Free Software
  31.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  32.  *
  33.  */
  34. #include "squid.h"
  35. #define GET_HDR_SZ 1024
  36. typedef struct _mime_entry {
  37.     char *pattern;
  38.     regex_t compiled_pattern;
  39.     char *icon;
  40.     char *content_type;
  41.     char *content_encoding;
  42.     char transfer_mode;
  43.     unsigned int view_option:1, download_option:1;
  44.     struct _mime_entry *next;
  45. } mimeEntry;
  46. static mimeEntry *MimeTable = NULL;
  47. static mimeEntry **MimeTableTail = NULL;
  48. static void mimeLoadIconFile(const char *icon);
  49. /* returns a pointer to a field-value of the first matching field-name */
  50. char *
  51. mime_get_header(const char *mime, const char *name)
  52. {
  53.     return mime_get_header_field(mime, name, NULL);
  54. }
  55. /*
  56.  * returns a pointer to a field-value of the first matching field-name where
  57.  * field-value matches prefix if any
  58.  */
  59. char *
  60. mime_get_header_field(const char *mime, const char *name, const char *prefix)
  61. {
  62.     LOCAL_ARRAY(char, header, GET_HDR_SZ);
  63.     const char *p = NULL;
  64.     char *q = NULL;
  65.     char got = 0;
  66.     const int namelen = name ? strlen(name) : 0;
  67.     const int preflen = prefix ? strlen(prefix) : 0;
  68.     int l;
  69.     if (NULL == mime)
  70. return NULL;
  71.     assert(NULL != name);
  72.     debug(25, 5) ("mime_get_header: looking for '%s'n", name);
  73.     for (p = mime; *p; p += strcspn(p, "nr")) {
  74. if (strcmp(p, "rnrn") == 0 || strcmp(p, "nn") == 0)
  75.     return NULL;
  76. while (xisspace(*p))
  77.     p++;
  78. if (strncasecmp(p, name, namelen))
  79.     continue;
  80. if (!xisspace(p[namelen]) && p[namelen] != ':')
  81.     continue;
  82. l = strcspn(p, "nr") + 1;
  83. if (l > GET_HDR_SZ)
  84.     l = GET_HDR_SZ;
  85. xstrncpy(header, p, l);
  86. debug(25, 5) ("mime_get_header: checking '%s'n", header);
  87. q = header;
  88. q += namelen;
  89. if (*q == ':')
  90.     q++, got = 1;
  91. while (xisspace(*q))
  92.     q++, got = 1;
  93. if (got && prefix) {
  94.     /* we could process list entries here if we had strcasestr(). */
  95.     /* make sure we did not match a part of another field-value */
  96.     got = !strncasecmp(q, prefix, preflen) && !xisalpha(q[preflen]);
  97. }
  98. if (got) {
  99.     debug(25, 5) ("mime_get_header: returning '%s'n", q);
  100.     return q;
  101. }
  102.     }
  103.     return NULL;
  104. }
  105. size_t
  106. headersEnd(const char *mime, size_t l)
  107. {
  108.     size_t e = 0;
  109.     int state = 0;
  110.     while (e < l && state < 3) {
  111. switch (state) {
  112. case 0:
  113.     if ('n' == mime[e])
  114. state = 1;
  115.     break;
  116. case 1:
  117.     if ('r' == mime[e])
  118. state = 2;
  119.     else if ('n' == mime[e])
  120. state = 3;
  121.     else
  122. state = 0;
  123.     break;
  124. case 2:
  125.     if ('r' == mime[e]) /* ignore repeated CR */
  126. (void) 0;
  127.     else if ('n' == mime[e])
  128. state = 3;
  129.     else
  130. state = 0;
  131.     break;
  132. default:
  133.     break;
  134. }
  135. e++;
  136.     }
  137.     if (3 == state)
  138. return e;
  139.     return 0;
  140. }
  141. const char *
  142. mime_get_auth(const char *hdr, const char *auth_scheme, const char **auth_field)
  143. {
  144.     char *auth_hdr;
  145.     char *t;
  146.     if (auth_field)
  147. *auth_field = NULL;
  148.     if (hdr == NULL)
  149. return NULL;
  150.     if ((auth_hdr = mime_get_header(hdr, "Authorization")) == NULL)
  151. return NULL;
  152.     if (auth_field)
  153. *auth_field = auth_hdr;
  154.     if ((t = strtok(auth_hdr, " t")) == NULL)
  155. return NULL;
  156.     if (strcasecmp(t, auth_scheme) != 0)
  157. return NULL;
  158.     if ((t = strtok(NULL, " t")) == NULL)
  159. return NULL;
  160.     return base64_decode(t);
  161. }
  162. static mimeEntry *
  163. mimeGetEntry(const char *fn, int skip_encodings)
  164. {
  165.     mimeEntry *m;
  166.     char *t;
  167.     char *name = xstrdup(fn);
  168.   try_again:
  169.     for (m = MimeTable; m; m = m->next) {
  170. if (regexec(&m->compiled_pattern, name, 0, 0, 0) == 0)
  171.     break;
  172.     }
  173.     if (!skip_encodings)
  174. (void) 0;
  175.     else if (m == NULL)
  176. (void) 0;
  177.     else if (strcmp(m->content_type, dash_str))
  178. (void) 0;
  179.     else if (!strcmp(m->content_encoding, dash_str))
  180. (void) 0;
  181.     else {
  182. /* Assume we matched /.w$/ and cut off the last extension */
  183. if ((t = strrchr(name, '.'))) {
  184.     *t = '';
  185.     goto try_again;
  186. }
  187. /* What? A encoding without a extension? */
  188. m = NULL;
  189.     }
  190.     xfree(name);
  191.     return m;
  192. }
  193. char *
  194. mimeGetIcon(const char *fn)
  195. {
  196.     mimeEntry *m = mimeGetEntry(fn, 1);
  197.     if (m == NULL)
  198. return NULL;
  199.     if (!strcmp(m->icon, dash_str))
  200. return NULL;
  201.     return m->icon;
  202. }
  203. char *
  204. mimeGetIconURL(const char *fn)
  205. {
  206.     char *icon = mimeGetIcon(fn);
  207.     if (icon == NULL)
  208. return NULL;
  209.     return internalLocalUri("/squid-internal-static/icons/", icon);
  210. }
  211. char *
  212. mimeGetContentType(const char *fn)
  213. {
  214.     mimeEntry *m = mimeGetEntry(fn, 1);
  215.     if (m == NULL)
  216. return NULL;
  217.     if (!strcmp(m->content_type, dash_str))
  218. return NULL;
  219.     return m->content_type;
  220. }
  221. char *
  222. mimeGetContentEncoding(const char *fn)
  223. {
  224.     mimeEntry *m = mimeGetEntry(fn, 0);
  225.     if (m == NULL)
  226. return NULL;
  227.     if (!strcmp(m->content_encoding, dash_str))
  228. return NULL;
  229.     return m->content_encoding;
  230. }
  231. char
  232. mimeGetTransferMode(const char *fn)
  233. {
  234.     mimeEntry *m = mimeGetEntry(fn, 0);
  235.     return m ? m->transfer_mode : 'I';
  236. }
  237. int
  238. mimeGetDownloadOption(const char *fn)
  239. {
  240.     mimeEntry *m = mimeGetEntry(fn, 1);
  241.     return m ? m->download_option : 0;
  242. }
  243. int
  244. mimeGetViewOption(const char *fn)
  245. {
  246.     mimeEntry *m = mimeGetEntry(fn, 0);
  247.     return m ? m->view_option : 0;
  248. }
  249. void
  250. mimeInit(char *filename)
  251. {
  252.     FILE *fp;
  253.     char buf[BUFSIZ];
  254.     char chopbuf[BUFSIZ];
  255.     char *t;
  256.     char *pattern;
  257.     char *icon;
  258.     char *type;
  259.     char *encoding;
  260.     char *mode;
  261.     char *option;
  262.     int view_option;
  263.     int download_option;
  264.     regex_t re;
  265.     mimeEntry *m;
  266.     int re_flags = REG_EXTENDED | REG_NOSUB | REG_ICASE;
  267.     if (filename == NULL)
  268. return;
  269.     if ((fp = fopen(filename, "r")) == NULL) {
  270. debug(50, 1) ("mimeInit: %s: %sn", filename, xstrerror());
  271. return;
  272.     }
  273.     if (MimeTableTail == NULL)
  274. MimeTableTail = &MimeTable;
  275.     while (fgets(buf, BUFSIZ, fp)) {
  276. if ((t = strchr(buf, '#')))
  277.     *t = '';
  278. if ((t = strchr(buf, 'r')))
  279.     *t = '';
  280. if ((t = strchr(buf, 'n')))
  281.     *t = '';
  282. if (buf[0] == '')
  283.     continue;
  284. xstrncpy(chopbuf, buf, BUFSIZ);
  285. if ((pattern = strtok(chopbuf, w_space)) == NULL) {
  286.     debug(25, 1) ("mimeInit: parse error: '%s'n", buf);
  287.     continue;
  288. }
  289. if ((type = strtok(NULL, w_space)) == NULL) {
  290.     debug(25, 1) ("mimeInit: parse error: '%s'n", buf);
  291.     continue;
  292. }
  293. if ((icon = strtok(NULL, w_space)) == NULL) {
  294.     debug(25, 1) ("mimeInit: parse error: '%s'n", buf);
  295.     continue;
  296. }
  297. if ((encoding = strtok(NULL, w_space)) == NULL) {
  298.     debug(25, 1) ("mimeInit: parse error: '%s'n", buf);
  299.     continue;
  300. }
  301. if ((mode = strtok(NULL, w_space)) == NULL) {
  302.     debug(25, 1) ("mimeInit: parse error: '%s'n", buf);
  303.     continue;
  304. }
  305. download_option = 0;
  306. view_option = 0;
  307. while ((option = strtok(NULL, w_space)) != NULL) {
  308.     if (!strcmp(option, "+download"))
  309. download_option = 1;
  310.     else if (!strcmp(option, "+view"))
  311. view_option = 1;
  312.     else
  313. debug(25, 1) ("mimeInit: unknown option: '%s' (%s)n", buf, option);
  314. }
  315. if (regcomp(&re, pattern, re_flags) != 0) {
  316.     debug(25, 1) ("mimeInit: regcomp error: '%s'n", buf);
  317.     continue;
  318. }
  319. m = xcalloc(1, sizeof(mimeEntry));
  320. m->pattern = xstrdup(pattern);
  321. m->content_type = xstrdup(type);
  322. m->icon = xstrdup(icon);
  323. m->content_encoding = xstrdup(encoding);
  324. m->compiled_pattern = re;
  325. if (!strcasecmp(mode, "ascii"))
  326.     m->transfer_mode = 'A';
  327. else if (!strcasecmp(mode, "text"))
  328.     m->transfer_mode = 'A';
  329. else
  330.     m->transfer_mode = 'I';
  331. m->view_option = view_option;
  332. m->download_option = download_option;
  333. *MimeTableTail = m;
  334. MimeTableTail = &m->next;
  335. debug(25, 5) ("mimeInit: added '%s'n", buf);
  336.     }
  337.     fclose(fp);
  338.     /*
  339.      * Create Icon StoreEntry's
  340.      */
  341.     for (m = MimeTable; m != NULL; m = m->next)
  342. mimeLoadIconFile(m->icon);
  343.     debug(25, 1) ("Loaded Icons.n");
  344. }
  345. void
  346. mimeFreeMemory(void)
  347. {
  348.     mimeEntry *m;
  349.     while ((m = MimeTable)) {
  350. MimeTable = m->next;
  351. safe_free(m->pattern);
  352. safe_free(m->content_type);
  353. safe_free(m->icon);
  354. safe_free(m->content_encoding);
  355. regfree(&m->compiled_pattern);
  356. safe_free(m);
  357.     }
  358.     MimeTableTail = &MimeTable;
  359. }
  360. static void
  361. mimeLoadIconFile(const char *icon)
  362. {
  363.     int fd;
  364.     int n;
  365.     request_flags flags;
  366.     struct stat sb;
  367.     StoreEntry *e;
  368.     LOCAL_ARRAY(char, path, MAXPATHLEN);
  369.     LOCAL_ARRAY(char, url, MAX_URL);
  370.     char *buf;
  371.     const char *type = mimeGetContentType(icon);
  372.     HttpReply *reply;
  373.     if (type == NULL)
  374. fatal("Unknown icon format while reading mime.confn");
  375.     buf = internalLocalUri("/squid-internal-static/icons/", icon);
  376.     xstrncpy(url, buf, MAX_URL);
  377.     if (storeGetPublic(url, METHOD_GET))
  378. return;
  379.     snprintf(path, MAXPATHLEN, "%s/%s", Config.icons.directory, icon);
  380.     fd = file_open(path, O_RDONLY, NULL, NULL, NULL);
  381.     if (fd < 0) {
  382. debug(25, 0) ("mimeLoadIconFile: %s: %sn", path, xstrerror());
  383. return;
  384.     }
  385.     if (fstat(fd, &sb) < 0) {
  386. debug(50, 0) ("mimeLoadIconFile: FD %d: fstat: %sn", fd, xstrerror());
  387. return;
  388.     }
  389.     flags = null_request_flags;
  390.     flags.cachable = 1;
  391.     e = storeCreateEntry(url,
  392. url,
  393. flags,
  394. METHOD_GET);
  395.     assert(e != NULL);
  396.     storeSetPublicKey(e);
  397.     e->mem_obj->request = requestLink(urlParse(METHOD_GET, url));
  398.     httpReplyReset(reply = e->mem_obj->reply);
  399.     httpReplySetHeaders(reply, 1.0, HTTP_OK, NULL,
  400. type, (int) sb.st_size, sb.st_mtime, -1);
  401.     reply->cache_control = httpHdrCcCreate();
  402.     httpHdrCcSetMaxAge(reply->cache_control, 86400);
  403.     httpHeaderPutCc(&reply->header, reply->cache_control);
  404.     httpReplySwapOut(reply, e);
  405.     /* read the file into the buffer and append it to store */
  406.     buf = memAllocate(MEM_4K_BUF);
  407.     while ((n = read(fd, buf, 4096)) > 0)
  408. storeAppend(e, buf, n);
  409.     file_close(fd);
  410.     storeComplete(e);
  411.     storeTimestampsSet(e);
  412.     EBIT_SET(e->flags, ENTRY_SPECIAL);
  413.     debug(25, 3) ("Loaded icon %sn", url);
  414.     storeUnlockObject(e);
  415.     memFree(buf, MEM_4K_BUF);
  416. }