cgit

commit c4d46c7035d07070ac1ebf0c0b44df927358687f

Author: Lars Hjemli <hjemli@gmail.com>

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>

 cgit.c | 11 +++++++++++
 cgit.h | 2 ++
 cgitrc.5.txt | 17 +++++++++++++++++
 ui-plain.c | 20 +++++++++++++++-----


diff --git a/cgit.c b/cgit.c
index 2039ab1de53699b6d29a23f1409461386589a227..4f414c333437a67106c327c7fddbefa964d400c7 100644
--- a/cgit.c
+++ b/cgit.c
@@ -17,6 +17,14 @@ #include "scan-tree.h"
 
 const char *cgit_version = CGIT_VERSION;
 
+void add_mimetype(const char *name, const char *value)
+{
+	struct string_list_item *item;
+
+	item = string_list_insert(xstrdup(name), &ctx.cfg.mimetypes);
+	item->util = xstrdup(value);
+}
+
 void config_cb(const char *name, const char *value)
 {
 	if (!strcmp(name, "root-title"))
@@ -101,6 +109,8 @@ 	else if (!strcmp(name, "clone-prefix"))
 		ctx.cfg.clone_prefix = xstrdup(value);
 	else if (!strcmp(name, "local-time"))
 		ctx.cfg.local_time = atoi(value);
+	else if (!prefixcmp(name, "mimetype."))
+		add_mimetype(name + 9, value);
 	else if (!strcmp(name, "repo.group"))
 		ctx.cfg.repo_group = xstrdup(value);
 	else if (!strcmp(name, "repo.url"))
@@ -213,6 +223,7 @@ 	ctx->page.size = 0;
 	ctx->page.modified = time(NULL);
 	ctx->page.expires = ctx->page.modified;
 	ctx->page.etag = NULL;
+	memset(&ctx->cfg.mimetypes, 0, sizeof(struct string_list));
 }
 
 struct refmatch {




diff --git a/cgit.h b/cgit.h
index 8c64efeaa6e7f5698751e202b64765280e3985cf..9259f33d60e0d21f6dc61e50e39e094ac43d8a9f 100644
--- a/cgit.h
+++ b/cgit.h
@@ -15,6 +15,7 @@ #include 
 #include <revision.h>
 #include <log-tree.h>
 #include <archive.h>
+#include <string-list.h>
 #include <xdiff-interface.h>
 #include <xdiff/xdiff.h>
 #include <utf8.h>
@@ -174,6 +175,7 @@ 	int snapshots;
 	int summary_branches;
 	int summary_log;
 	int summary_tags;
+	struct string_list mimetypes;
 };
 
 struct cgit_page {




diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index a207fe07aadb9eb2863b1c47165e804772a12e5b..7256ec0d0fa1a0f6baad63cde084102190cfbce9 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -147,6 +147,10 @@ 	Set the default maximum statistics period. Valid values are "week",
 	"month", "quarter" and "year". If unspecified, statistics are
 	disabled. Default value: none. See also: "repo.max-stats".
 
+mimetype.<ext>::
+	Set the mimetype for the specified filename extension. This is used
+	by the `plain` command when returning blob content.
+
 module-link::
 	Text which will be used as the formatstring for a hyperlink when a
 	submodule is printed in a directory listing. The arguments for the
@@ -322,6 +326,19 @@
 
 # Allow download of tar.gz, tar.bz2 and zip-files
 snapshots=tar.gz tar.bz2 zip
+
+
+##
+## List of common mimetypes
+##
+
+mimetype.git=image/git
+mimetype.html=text/html
+mimetype.jpg=image/jpeg
+mimetype.jpeg=image/jpeg
+mimetype.pdf=application/pdf
+mimetype.png=image/png
+mimetype.svg=image/svg+xml
 
 
 ##




diff --git a/ui-plain.c b/ui-plain.c
index 93a3a05ac50f7a43b3c50529a011f0c9fdbf547c..27c6daec7f1dc71bfd7b8b74c8179467a5d39224 100644
--- a/ui-plain.c
+++ b/ui-plain.c
@@ -17,8 +17,9 @@
 static void print_object(const unsigned char *sha1, const char *path)
 {
 	enum object_type type;
-	char *buf;
+	char *buf, *ext;
 	unsigned long size;
+	struct string_list_item *mime;
 
 	type = sha1_object_info(sha1, &size);
 	if (type == OBJ_BAD) {
@@ -31,10 +32,19 @@ 	if (!buf) {
 		html_status(404, "Not found", 0);
 		return;
 	}
-	if (buffer_is_binary(buf, size))
-		ctx.page.mimetype = "application/octet-stream";
-	else
-		ctx.page.mimetype = "text/plain";
+	ctx.page.mimetype = NULL;
+	ext = strrchr(path, '.');
+	if (ext && *(++ext)) {
+		mime = string_list_lookup(ext, &ctx.cfg.mimetypes);
+		if (mime)
+			ctx.page.mimetype = (char *)mime->util;
+	}
+	if (!ctx.page.mimetype) {
+		if (buffer_is_binary(buf, size))
+			ctx.page.mimetype = "application/octet-stream";
+		else
+			ctx.page.mimetype = "text/plain";
+	}
 	ctx.page.filename = fmt("%s", path);
 	ctx.page.size = size;
 	ctx.page.etag = sha1_to_hex(sha1);