author | Lars Hjemli <hjemli@gmail.com> | 2009-02-13 19:43:30 (UTC) |
---|---|---|
committer | Lars Hjemli <hjemli@gmail.com> | 2009-07-25 10:55:15 (UTC) |
commit | c4d46c7035d07070ac1ebf0c0b44df927358687f (patch) (unidiff) | |
tree | 562cf4f01afe78b92b13ad5be5dc01e07db04a66 | |
parent | 286a905842dc0bec6d21a614ec4a97c5f19d5bc4 (diff) | |
download | cgit-c4d46c7035d07070ac1ebf0c0b44df927358687f.zip cgit-c4d46c7035d07070ac1ebf0c0b44df927358687f.tar.gz cgit-c4d46c7035d07070ac1ebf0c0b44df927358687f.tar.bz2 |
Add support for mime type registration and lookup
This patch makes it possible to register mappings from filename
extension to mime type in cgitrc and use this mapping when returning
blob content in `plain` view.
The reason for adding this mapping to cgitrc (as opposed to parsing
something like /etc/mime.types) is to allow quick lookup of a limited
number of filename extensions (/etc/mime-types on my machine currently
contains over 700 entries).
NB: A nice addition to this patch would be to parse /etc/mime.types
when `plain` view is requested for a file with an extension for which
there is no mapping registered in cgitrc.
Signed-off-by: Lars Hjemli <hjemli@gmail.com>
-rw-r--r-- | cgit.c | 11 | ||||
-rw-r--r-- | cgit.h | 2 | ||||
-rw-r--r-- | cgitrc.5.txt | 17 | ||||
-rw-r--r-- | ui-plain.c | 20 |
4 files changed, 45 insertions, 5 deletions
@@ -8,24 +8,32 @@ | |||
8 | 8 | ||
9 | #include "cgit.h" | 9 | #include "cgit.h" |
10 | #include "cache.h" | 10 | #include "cache.h" |
11 | #include "cmd.h" | 11 | #include "cmd.h" |
12 | #include "configfile.h" | 12 | #include "configfile.h" |
13 | #include "html.h" | 13 | #include "html.h" |
14 | #include "ui-shared.h" | 14 | #include "ui-shared.h" |
15 | #include "ui-stats.h" | 15 | #include "ui-stats.h" |
16 | #include "scan-tree.h" | 16 | #include "scan-tree.h" |
17 | 17 | ||
18 | const char *cgit_version = CGIT_VERSION; | 18 | const char *cgit_version = CGIT_VERSION; |
19 | 19 | ||
20 | void add_mimetype(const char *name, const char *value) | ||
21 | { | ||
22 | struct string_list_item *item; | ||
23 | |||
24 | item = string_list_insert(xstrdup(name), &ctx.cfg.mimetypes); | ||
25 | item->util = xstrdup(value); | ||
26 | } | ||
27 | |||
20 | void config_cb(const char *name, const char *value) | 28 | void config_cb(const char *name, const char *value) |
21 | { | 29 | { |
22 | if (!strcmp(name, "root-title")) | 30 | if (!strcmp(name, "root-title")) |
23 | ctx.cfg.root_title = xstrdup(value); | 31 | ctx.cfg.root_title = xstrdup(value); |
24 | else if (!strcmp(name, "root-desc")) | 32 | else if (!strcmp(name, "root-desc")) |
25 | ctx.cfg.root_desc = xstrdup(value); | 33 | ctx.cfg.root_desc = xstrdup(value); |
26 | else if (!strcmp(name, "root-readme")) | 34 | else if (!strcmp(name, "root-readme")) |
27 | ctx.cfg.root_readme = xstrdup(value); | 35 | ctx.cfg.root_readme = xstrdup(value); |
28 | else if (!strcmp(name, "css")) | 36 | else if (!strcmp(name, "css")) |
29 | ctx.cfg.css = xstrdup(value); | 37 | ctx.cfg.css = xstrdup(value); |
30 | else if (!strcmp(name, "favicon")) | 38 | else if (!strcmp(name, "favicon")) |
31 | ctx.cfg.favicon = xstrdup(value); | 39 | ctx.cfg.favicon = xstrdup(value); |
@@ -92,24 +100,26 @@ void config_cb(const char *name, const char *value) | |||
92 | else if (!strcmp(name, "summary-tags")) | 100 | else if (!strcmp(name, "summary-tags")) |
93 | ctx.cfg.summary_tags = atoi(value); | 101 | ctx.cfg.summary_tags = atoi(value); |
94 | else if (!strcmp(name, "agefile")) | 102 | else if (!strcmp(name, "agefile")) |
95 | ctx.cfg.agefile = xstrdup(value); | 103 | ctx.cfg.agefile = xstrdup(value); |
96 | else if (!strcmp(name, "renamelimit")) | 104 | else if (!strcmp(name, "renamelimit")) |
97 | ctx.cfg.renamelimit = atoi(value); | 105 | ctx.cfg.renamelimit = atoi(value); |
98 | else if (!strcmp(name, "robots")) | 106 | else if (!strcmp(name, "robots")) |
99 | ctx.cfg.robots = xstrdup(value); | 107 | ctx.cfg.robots = xstrdup(value); |
100 | else if (!strcmp(name, "clone-prefix")) | 108 | else if (!strcmp(name, "clone-prefix")) |
101 | ctx.cfg.clone_prefix = xstrdup(value); | 109 | ctx.cfg.clone_prefix = xstrdup(value); |
102 | else if (!strcmp(name, "local-time")) | 110 | else if (!strcmp(name, "local-time")) |
103 | ctx.cfg.local_time = atoi(value); | 111 | ctx.cfg.local_time = atoi(value); |
112 | else if (!prefixcmp(name, "mimetype.")) | ||
113 | add_mimetype(name + 9, value); | ||
104 | else if (!strcmp(name, "repo.group")) | 114 | else if (!strcmp(name, "repo.group")) |
105 | ctx.cfg.repo_group = xstrdup(value); | 115 | ctx.cfg.repo_group = xstrdup(value); |
106 | else if (!strcmp(name, "repo.url")) | 116 | else if (!strcmp(name, "repo.url")) |
107 | ctx.repo = cgit_add_repo(value); | 117 | ctx.repo = cgit_add_repo(value); |
108 | else if (!strcmp(name, "repo.name")) | 118 | else if (!strcmp(name, "repo.name")) |
109 | ctx.repo->name = xstrdup(value); | 119 | ctx.repo->name = xstrdup(value); |
110 | else if (ctx.repo && !strcmp(name, "repo.path")) | 120 | else if (ctx.repo && !strcmp(name, "repo.path")) |
111 | ctx.repo->path = trim_end(value, '/'); | 121 | ctx.repo->path = trim_end(value, '/'); |
112 | else if (ctx.repo && !strcmp(name, "repo.clone-url")) | 122 | else if (ctx.repo && !strcmp(name, "repo.clone-url")) |
113 | ctx.repo->clone_url = xstrdup(value); | 123 | ctx.repo->clone_url = xstrdup(value); |
114 | else if (ctx.repo && !strcmp(name, "repo.desc")) | 124 | else if (ctx.repo && !strcmp(name, "repo.desc")) |
115 | ctx.repo->desc = xstrdup(value); | 125 | ctx.repo->desc = xstrdup(value); |
@@ -204,24 +214,25 @@ static void prepare_context(struct cgit_context *ctx) | |||
204 | ctx->cfg.root_desc = "a fast webinterface for the git dscm"; | 214 | ctx->cfg.root_desc = "a fast webinterface for the git dscm"; |
205 | ctx->cfg.script_name = CGIT_SCRIPT_NAME; | 215 | ctx->cfg.script_name = CGIT_SCRIPT_NAME; |
206 | ctx->cfg.summary_branches = 10; | 216 | ctx->cfg.summary_branches = 10; |
207 | ctx->cfg.summary_log = 10; | 217 | ctx->cfg.summary_log = 10; |
208 | ctx->cfg.summary_tags = 10; | 218 | ctx->cfg.summary_tags = 10; |
209 | ctx->page.mimetype = "text/html"; | 219 | ctx->page.mimetype = "text/html"; |
210 | ctx->page.charset = PAGE_ENCODING; | 220 | ctx->page.charset = PAGE_ENCODING; |
211 | ctx->page.filename = NULL; | 221 | ctx->page.filename = NULL; |
212 | ctx->page.size = 0; | 222 | ctx->page.size = 0; |
213 | ctx->page.modified = time(NULL); | 223 | ctx->page.modified = time(NULL); |
214 | ctx->page.expires = ctx->page.modified; | 224 | ctx->page.expires = ctx->page.modified; |
215 | ctx->page.etag = NULL; | 225 | ctx->page.etag = NULL; |
226 | memset(&ctx->cfg.mimetypes, 0, sizeof(struct string_list)); | ||
216 | } | 227 | } |
217 | 228 | ||
218 | struct refmatch { | 229 | struct refmatch { |
219 | char *req_ref; | 230 | char *req_ref; |
220 | char *first_ref; | 231 | char *first_ref; |
221 | int match; | 232 | int match; |
222 | }; | 233 | }; |
223 | 234 | ||
224 | int find_current_ref(const char *refname, const unsigned char *sha1, | 235 | int find_current_ref(const char *refname, const unsigned char *sha1, |
225 | int flags, void *cb_data) | 236 | int flags, void *cb_data) |
226 | { | 237 | { |
227 | struct refmatch *info; | 238 | struct refmatch *info; |
@@ -6,24 +6,25 @@ | |||
6 | #include <cache.h> | 6 | #include <cache.h> |
7 | #include <grep.h> | 7 | #include <grep.h> |
8 | #include <object.h> | 8 | #include <object.h> |
9 | #include <tree.h> | 9 | #include <tree.h> |
10 | #include <commit.h> | 10 | #include <commit.h> |
11 | #include <tag.h> | 11 | #include <tag.h> |
12 | #include <diff.h> | 12 | #include <diff.h> |
13 | #include <diffcore.h> | 13 | #include <diffcore.h> |
14 | #include <refs.h> | 14 | #include <refs.h> |
15 | #include <revision.h> | 15 | #include <revision.h> |
16 | #include <log-tree.h> | 16 | #include <log-tree.h> |
17 | #include <archive.h> | 17 | #include <archive.h> |
18 | #include <string-list.h> | ||
18 | #include <xdiff-interface.h> | 19 | #include <xdiff-interface.h> |
19 | #include <xdiff/xdiff.h> | 20 | #include <xdiff/xdiff.h> |
20 | #include <utf8.h> | 21 | #include <utf8.h> |
21 | 22 | ||
22 | 23 | ||
23 | /* | 24 | /* |
24 | * Dateformats used on misc. pages | 25 | * Dateformats used on misc. pages |
25 | */ | 26 | */ |
26 | #define FMT_LONGDATE "%Y-%m-%d %H:%M:%S (%Z)" | 27 | #define FMT_LONGDATE "%Y-%m-%d %H:%M:%S (%Z)" |
27 | #define FMT_SHORTDATE "%Y-%m-%d" | 28 | #define FMT_SHORTDATE "%Y-%m-%d" |
28 | #define FMT_ATOMDATE "%Y-%m-%dT%H:%M:%SZ" | 29 | #define FMT_ATOMDATE "%Y-%m-%dT%H:%M:%SZ" |
29 | 30 | ||
@@ -165,24 +166,25 @@ struct cgit_config { | |||
165 | int max_commit_count; | 166 | int max_commit_count; |
166 | int max_lock_attempts; | 167 | int max_lock_attempts; |
167 | int max_msg_len; | 168 | int max_msg_len; |
168 | int max_repodesc_len; | 169 | int max_repodesc_len; |
169 | int max_stats; | 170 | int max_stats; |
170 | int nocache; | 171 | int nocache; |
171 | int noheader; | 172 | int noheader; |
172 | int renamelimit; | 173 | int renamelimit; |
173 | int snapshots; | 174 | int snapshots; |
174 | int summary_branches; | 175 | int summary_branches; |
175 | int summary_log; | 176 | int summary_log; |
176 | int summary_tags; | 177 | int summary_tags; |
178 | struct string_list mimetypes; | ||
177 | }; | 179 | }; |
178 | 180 | ||
179 | struct cgit_page { | 181 | struct cgit_page { |
180 | time_t modified; | 182 | time_t modified; |
181 | time_t expires; | 183 | time_t expires; |
182 | size_t size; | 184 | size_t size; |
183 | char *mimetype; | 185 | char *mimetype; |
184 | char *charset; | 186 | char *charset; |
185 | char *filename; | 187 | char *filename; |
186 | char *etag; | 188 | char *etag; |
187 | char *title; | 189 | char *title; |
188 | int status; | 190 | int status; |
diff --git a/cgitrc.5.txt b/cgitrc.5.txt index a207fe0..7256ec0 100644 --- a/cgitrc.5.txt +++ b/cgitrc.5.txt | |||
@@ -138,24 +138,28 @@ max-repo-count:: | |||
138 | Specifies the number of entries to list per page on therepository | 138 | Specifies the number of entries to list per page on therepository |
139 | index page. Default value: "50". | 139 | index page. Default value: "50". |
140 | 140 | ||
141 | max-repodesc-length:: | 141 | max-repodesc-length:: |
142 | Specifies the maximum number of repo description characters to display | 142 | Specifies the maximum number of repo description characters to display |
143 | on the repository index page. Default value: "80". | 143 | on the repository index page. Default value: "80". |
144 | 144 | ||
145 | max-stats:: | 145 | max-stats:: |
146 | Set the default maximum statistics period. Valid values are "week", | 146 | Set the default maximum statistics period. Valid values are "week", |
147 | "month", "quarter" and "year". If unspecified, statistics are | 147 | "month", "quarter" and "year". If unspecified, statistics are |
148 | disabled. Default value: none. See also: "repo.max-stats". | 148 | disabled. Default value: none. See also: "repo.max-stats". |
149 | 149 | ||
150 | mimetype.<ext>:: | ||
151 | Set the mimetype for the specified filename extension. This is used | ||
152 | by the `plain` command when returning blob content. | ||
153 | |||
150 | module-link:: | 154 | module-link:: |
151 | Text which will be used as the formatstring for a hyperlink when a | 155 | Text which will be used as the formatstring for a hyperlink when a |
152 | submodule is printed in a directory listing. The arguments for the | 156 | submodule is printed in a directory listing. The arguments for the |
153 | formatstring are the path and SHA1 of the submodule commit. Default | 157 | formatstring are the path and SHA1 of the submodule commit. Default |
154 | value: "./?repo=%s&page=commit&id=%s" | 158 | value: "./?repo=%s&page=commit&id=%s" |
155 | 159 | ||
156 | nocache:: | 160 | nocache:: |
157 | If set to the value "1" caching will be disabled. This settings is | 161 | If set to the value "1" caching will be disabled. This settings is |
158 | deprecated, and will not be honored starting with cgit-1.0. Default | 162 | deprecated, and will not be honored starting with cgit-1.0. Default |
159 | value: "0". | 163 | value: "0". |
160 | 164 | ||
161 | noheader:: | 165 | noheader:: |
@@ -316,24 +320,37 @@ root-title=foobar.com git repositories | |||
316 | root-desc=tracking the foobar development | 320 | root-desc=tracking the foobar development |
317 | 321 | ||
318 | 322 | ||
319 | # Include some more info about foobar.com on the index page | 323 | # Include some more info about foobar.com on the index page |
320 | root-readme=/var/www/htdocs/about.html | 324 | root-readme=/var/www/htdocs/about.html |
321 | 325 | ||
322 | 326 | ||
323 | # Allow download of tar.gz, tar.bz2 and zip-files | 327 | # Allow download of tar.gz, tar.bz2 and zip-files |
324 | snapshots=tar.gz tar.bz2 zip | 328 | snapshots=tar.gz tar.bz2 zip |
325 | 329 | ||
326 | 330 | ||
327 | ## | 331 | ## |
332 | ## List of common mimetypes | ||
333 | ## | ||
334 | |||
335 | mimetype.git=image/git | ||
336 | mimetype.html=text/html | ||
337 | mimetype.jpg=image/jpeg | ||
338 | mimetype.jpeg=image/jpeg | ||
339 | mimetype.pdf=application/pdf | ||
340 | mimetype.png=image/png | ||
341 | mimetype.svg=image/svg+xml | ||
342 | |||
343 | |||
344 | ## | ||
328 | ## List of repositories. | 345 | ## List of repositories. |
329 | ## PS: Any repositories listed when repo.group is unset will not be | 346 | ## PS: Any repositories listed when repo.group is unset will not be |
330 | ## displayed under a group heading | 347 | ## displayed under a group heading |
331 | ## PPS: This list could be kept in a different file (e.g. '/etc/cgitrepos') | 348 | ## PPS: This list could be kept in a different file (e.g. '/etc/cgitrepos') |
332 | ## and included like this: | 349 | ## and included like this: |
333 | ## include=/etc/cgitrepos | 350 | ## include=/etc/cgitrepos |
334 | ## | 351 | ## |
335 | 352 | ||
336 | 353 | ||
337 | repo.url=foo | 354 | repo.url=foo |
338 | repo.path=/pub/git/foo.git | 355 | repo.path=/pub/git/foo.git |
339 | repo.desc=the master foo repository | 356 | repo.desc=the master foo repository |
@@ -8,42 +8,52 @@ | |||
8 | 8 | ||
9 | #include "cgit.h" | 9 | #include "cgit.h" |
10 | #include "html.h" | 10 | #include "html.h" |
11 | #include "ui-shared.h" | 11 | #include "ui-shared.h" |
12 | 12 | ||
13 | char *curr_rev; | 13 | char *curr_rev; |
14 | char *match_path; | 14 | char *match_path; |
15 | int match; | 15 | int match; |
16 | 16 | ||
17 | static void print_object(const unsigned char *sha1, const char *path) | 17 | static void print_object(const unsigned char *sha1, const char *path) |
18 | { | 18 | { |
19 | enum object_type type; | 19 | enum object_type type; |
20 | char *buf; | 20 | char *buf, *ext; |
21 | unsigned long size; | 21 | unsigned long size; |
22 | struct string_list_item *mime; | ||
22 | 23 | ||
23 | type = sha1_object_info(sha1, &size); | 24 | type = sha1_object_info(sha1, &size); |
24 | if (type == OBJ_BAD) { | 25 | if (type == OBJ_BAD) { |
25 | html_status(404, "Not found", 0); | 26 | html_status(404, "Not found", 0); |
26 | return; | 27 | return; |
27 | } | 28 | } |
28 | 29 | ||
29 | buf = read_sha1_file(sha1, &type, &size); | 30 | buf = read_sha1_file(sha1, &type, &size); |
30 | if (!buf) { | 31 | if (!buf) { |
31 | html_status(404, "Not found", 0); | 32 | html_status(404, "Not found", 0); |
32 | return; | 33 | return; |
33 | } | 34 | } |
34 | if (buffer_is_binary(buf, size)) | 35 | ctx.page.mimetype = NULL; |
35 | ctx.page.mimetype = "application/octet-stream"; | 36 | ext = strrchr(path, '.'); |
36 | else | 37 | if (ext && *(++ext)) { |
37 | ctx.page.mimetype = "text/plain"; | 38 | mime = string_list_lookup(ext, &ctx.cfg.mimetypes); |
39 | if (mime) | ||
40 | ctx.page.mimetype = (char *)mime->util; | ||
41 | } | ||
42 | if (!ctx.page.mimetype) { | ||
43 | if (buffer_is_binary(buf, size)) | ||
44 | ctx.page.mimetype = "application/octet-stream"; | ||
45 | else | ||
46 | ctx.page.mimetype = "text/plain"; | ||
47 | } | ||
38 | ctx.page.filename = fmt("%s", path); | 48 | ctx.page.filename = fmt("%s", path); |
39 | ctx.page.size = size; | 49 | ctx.page.size = size; |
40 | ctx.page.etag = sha1_to_hex(sha1); | 50 | ctx.page.etag = sha1_to_hex(sha1); |
41 | cgit_print_http_headers(&ctx); | 51 | cgit_print_http_headers(&ctx); |
42 | html_raw(buf, size); | 52 | html_raw(buf, size); |
43 | match = 1; | 53 | match = 1; |
44 | } | 54 | } |
45 | 55 | ||
46 | static int walk_tree(const unsigned char *sha1, const char *base, int baselen, | 56 | static int walk_tree(const unsigned char *sha1, const char *base, int baselen, |
47 | const char *pathname, unsigned mode, int stage, | 57 | const char *pathname, unsigned mode, int stage, |
48 | void *cbdata) | 58 | void *cbdata) |
49 | { | 59 | { |