Diff options
Diffstat (limited to '')
-rw-r--r--source/ui-plain.c92
1 file changed, 65 insertions, 27 deletions
diff --git a/source/ui-plain.c b/source/ui-plain.c
index 57e4699..43bdb22 100644
--- a/source/ui-plain.c
+++ b/source/ui-plain.c
@@ -42,6 +42,55 @@ static int is_unsafe_type(const char *mimetype)
strcmp(mimetype, "application/pdf");
}
+static char *get_mimetype_for_filename(const char *filename)
+{
+ const char *ext;
+ char *type, line[1024];
+ struct string_list fields = STRING_LIST_INIT_NODUP;
+ size_t i;
+ FILE *file;
+ struct string_list_item *entry;
+
+ if (!filename)
+ return NULL;
+
+ ext = strrchr(filename, '.');
+ if (!ext)
+ return NULL;
+ ++ext;
+ if (!ext[0])
+ return NULL;
+ entry = string_list_lookup(&ctx.cfg.mimetypes, ext);
+ if (entry)
+ return xstrdup(entry->util);
+
+ if (!ctx.cfg.mimetype_file)
+ return NULL;
+ file = fopen(ctx.cfg.mimetype_file, "r");
+ if (!file)
+ return NULL;
+ while (fgets(line, sizeof(line), file)) {
+ // A line of a mime.types file is one type followed by every
+ // extension that maps to it.
+ string_list_split_in_place(&fields, line, " \t\r\n", -1);
+ string_list_remove_empty_items(&fields, 0);
+ if (!fields.nr || fields.items[0].string[0] == '#') {
+ string_list_clear(&fields, 0);
+ continue;
+ }
+ type = fields.items[0].string;
+ for (i = 1; i < fields.nr; i++) {
+ if (!strcasecmp(ext, fields.items[i].string)) {
+ fclose(file);
+ return xstrdup(type);
+ }
+ }
+ string_list_clear(&fields, 0);
+ }
+ fclose(file);
+ return NULL;
+}
+
/*
* Writes the response for the object, error pages included, so the walk
* does not go on to report the path as missing.
@@ -69,7 +118,7 @@ static void print_object(const struct object_id *oid, const char *path)
return;
}
- mimetype = cgit_get_mimetype_for_filename(path);
+ mimetype = get_mimetype_for_filename(path);
ctx.page.mimetype = mimetype;
if (!ctx.repo->enable_html_serving) {
@@ -93,9 +142,9 @@ static void print_object(const struct object_id *oid, const char *path)
static char *build_path(const char *base, int baselen, const char *path)
{
if (path[0])
- return cgit_fmtalloc("%.*s%s/", baselen, base, path);
+ return xstrfmt("%.*s%s/", baselen, base, path);
else
- return cgit_fmtalloc("%.*s/", baselen, base);
+ return xstrfmt("%.*s/", baselen, base);
}
static void print_dir(const char *base, int baselen, const char *path)
@@ -159,20 +208,17 @@ static void print_dir_tail(void)
html("</ul>\n</body>\n</html>\n");
}
-/*
- * read_tree reads the return value as a direction rather than a status, so
- * READ_TREE_RECURSIVE means step into this entry and zero means step over it.
- */
static int walk_tree(const struct object_id *oid, struct strbuf *base,
const char *pathname, unsigned mode, void *context)
{
struct walk_tree_context *walk = context;
- // A tree can hold two entries of one name, and only the first answers:
- // a second response would follow the first in the same body.
- if (walk->response != RESPONSE_NONE && walk->dir_len >= 0 && base->len == (size_t)walk->dir_len)
- return 0;
if (walk->dir_len >= 0 && base->len == (size_t)walk->dir_len) {
+ // A tree can hold two entries of one name, and only the first
+ // answers: a second response would follow the first in the same
+ // body.
+ if (walk->response != RESPONSE_NONE)
+ return 0;
if (S_ISREG(mode) || S_ISLNK(mode)) {
print_object(oid, pathname);
walk->response = RESPONSE_BLOB;
@@ -205,19 +251,8 @@ void cgit_print_plain(void)
const char *rev = ctx.qry.oid;
struct object_id oid;
struct commit *commit;
- int path_len = ctx.qry.path ? strlen(ctx.qry.path) : 0;
- // nowildcard_len matches len so git treats the path as literal. As a
- // glob, every entry a pattern like * matches would be answered with
- // its own HTTP headers inside the body of the first.
- struct pathspec_item path_items = {
- .match = ctx.qry.path,
- .len = path_len,
- .nowildcard_len = path_len
- };
- struct pathspec paths = {
- .nr = 1,
- .items = &path_items
- };
+ struct pathspec_item path_item;
+ struct pathspec paths = { 0 };
struct walk_tree_context walk = {
.response = RESPONSE_NONE
};
@@ -234,15 +269,18 @@ void cgit_print_plain(void)
cgit_print_error_page(404, "Not Found", "Not found");
return;
}
- if (!path_items.match) {
+ // The path is taken literally, since as a glob every entry a pattern
+ // like * matches would be answered with its own HTTP headers inside
+ // the body of the first.
+ cgit_literal_pathspec(&paths, &path_item, ctx.qry.path);
+ if (!ctx.qry.path) {
// The walk is never handed an entry for the top of the tree
// itself, so the listing it would have opened is opened here.
- paths.nr = 0;
walk.dir_len = -1;
print_dir("", 0, "");
walk.response = RESPONSE_LISTING;
} else {
- walk.dir_len = dir_prefix_len(path_items.match);
+ walk.dir_len = dir_prefix_len(ctx.qry.path);
}
read_tree(the_repository, repo_get_commit_tree(the_repository, commit), &paths, walk_tree, &walk);
if (walk.response == RESPONSE_NONE)