2 * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
5 * "THE BEER-WARE LICENSE" (Revision 42):
6 * Sergey Lyubka wrote this file. As long as you retain this notice you
7 * can do whatever you want with this stuff. If we meet some day, and you think
8 * this stuff is worth it, you can buy me a beer in return.
13 static const struct mime_type default_mime_types[] = {
14 {"html", 4, "text/html" },
15 {"htm", 3, "text/html" },
16 {"txt", 3, "text/plain" },
17 {"css", 3, "text/css" },
18 {"ico", 3, "image/x-icon" },
19 {"gif", 3, "image/gif" },
20 {"jpg", 3, "image/jpeg" },
21 {"jpeg", 4, "image/jpeg" },
22 {"png", 3, "image/png" },
23 {"svg", 3, "image/svg+xml" },
24 {"torrent", 7, "application/x-bittorrent" },
25 {"wav", 3, "audio/x-wav" },
26 {"mp3", 3, "audio/x-mp3" },
27 {"mid", 3, "audio/mid" },
28 {"m3u", 3, "audio/x-mpegurl" },
29 {"ram", 3, "audio/x-pn-realaudio" },
30 {"ra", 2, "audio/x-pn-realaudio" },
31 {"doc", 3, "application/msword", },
32 {"exe", 3, "application/octet-stream" },
33 {"zip", 3, "application/x-zip-compressed" },
34 {"xls", 3, "application/excel" },
35 {"tgz", 3, "application/x-tar-gz" },
36 {"tar.gz", 6, "application/x-tar-gz" },
37 {"tar", 3, "application/x-tar" },
38 {"gz", 2, "application/x-gunzip" },
39 {"arj", 3, "application/x-arj-compressed" },
40 {"rar", 3, "application/x-arj-compressed" },
41 {"rtf", 3, "application/rtf" },
42 {"pdf", 3, "application/pdf" },
43 {"mpg", 3, "video/mpeg" },
44 {"mpeg", 4, "video/mpeg" },
45 {"asf", 3, "video/x-ms-asf" },
46 {"avi", 3, "video/x-msvideo" },
47 {"bmp", 3, "image/bmp" },
52 get_mime_type(struct shttpd_ctx *ctx, const char *uri, int len)
55 const struct mime_type *mt;
56 struct mime_type_link *mtl;
59 /* Firt, loop through the custom mime types if any */
60 LL_FOREACH(&ctx->mime_types, lp) {
61 mtl = LL_ENTRY(lp, struct mime_type_link, link);
62 s = uri + len - mtl->ext_len;
63 if (s > uri && s[-1] == '.' &&
64 !my_strncasecmp(mtl->ext, s, mtl->ext_len))
68 /* If no luck, try built-in mime types */
69 for (mt = default_mime_types; mt->ext != NULL; mt++) {
70 s = uri + len - mt->ext_len;
71 if (s > uri && s[-1] == '.' &&
72 !my_strncasecmp(mt->ext, s, mt->ext_len))
76 /* Oops. This extension is unknown to us. Fallback to text/plain */
77 return ("text/plain");
81 set_mime_types(struct shttpd_ctx *ctx, const char *path)
84 char line[512], ext[sizeof(line)], mime[sizeof(line)], *s;
86 if ((fp = fopen(path, "r")) == NULL)
87 elog(E_FATAL, NULL, "set_mime_types: fopen(%s): %s",
88 path, strerror(errno));
90 while (fgets(line, sizeof(line), fp) != NULL) {
91 /* Skip empty lines */
92 if (line[0] == '#' || line[0] == '\n')
94 if (sscanf(line, "%s", mime)) {
95 s = line + strlen(mime);
96 while (*s && *s != '\n' && sscanf(s, "%s", ext)) {
97 shttpd_add_mime_type(ctx, ext, mime);