neocgit

a more 'modern' version of cgit
Log | Files | Refs | Submodules | README | LICENSE | git clone https://git.ne02ptzero.me/git/neocgit

ui-plain.c (5157B)


      1 /* ui-plain.c: functions for output of plain blobs by path
      2  *
      3  * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
      4  *
      5  * Licensed under GNU General Public License v2
      6  *   (see COPYING for full license text)
      7  */
      8 
      9 #include "cgit.h"
     10 #include "ui-plain.h"
     11 #include "html.h"
     12 #include "ui-shared.h"
     13 
     14 struct walk_tree_context {
     15 	int match_baselen;
     16 	int match;
     17 };
     18 
     19 static int print_object(const struct object_id *oid, const char *path)
     20 {
     21 	enum object_type type;
     22 	char *buf, *mimetype;
     23 	unsigned long size;
     24 
     25 	type = oid_object_info(the_repository, oid, &size);
     26 	if (type == OBJ_BAD) {
     27 		cgit_print_error_page(404, "Not found", "Not found");
     28 		return 0;
     29 	}
     30 
     31 	buf = read_object_file(oid, &type, &size);
     32 	if (!buf) {
     33 		cgit_print_error_page(404, "Not found", "Not found");
     34 		return 0;
     35 	}
     36 
     37 	mimetype = get_mimetype_for_filename(path);
     38 	ctx.page.mimetype = mimetype;
     39 
     40 	if (!ctx.repo->enable_html_serving) {
     41 		html("X-Content-Type-Options: nosniff\n");
     42 		html("Content-Security-Policy: default-src 'none'\n");
     43 		if (mimetype) {
     44 			/* Built-in white list allows PDF and everything that isn't text/ and application/ */
     45 			if ((!strncmp(mimetype, "text/", 5) || !strncmp(mimetype, "application/", 12)) && strcmp(mimetype, "application/pdf"))
     46 				ctx.page.mimetype = NULL;
     47 		}
     48 	}
     49 
     50 	if (!ctx.page.mimetype) {
     51 		if (buffer_is_binary(buf, size)) {
     52 			ctx.page.mimetype = "application/octet-stream";
     53 			ctx.page.charset = NULL;
     54 		} else {
     55 			ctx.page.mimetype = "text/plain";
     56 		}
     57 	}
     58 	ctx.page.filename = path;
     59 	ctx.page.size = size;
     60 	ctx.page.etag = oid_to_hex(oid);
     61 	cgit_print_http_headers();
     62 	html_raw(buf, size);
     63 	free(mimetype);
     64 	free(buf);
     65 	return 1;
     66 }
     67 
     68 static char *buildpath(const char *base, int baselen, const char *path)
     69 {
     70 	if (path[0])
     71 		return fmtalloc("%.*s%s/", baselen, base, path);
     72 	else
     73 		return fmtalloc("%.*s/", baselen, base);
     74 }
     75 
     76 static void print_dir(const struct object_id *oid, const char *base,
     77 		      int baselen, const char *path)
     78 {
     79 	char *fullpath, *slash;
     80 	size_t len;
     81 
     82 	fullpath = buildpath(base, baselen, path);
     83 	slash = (fullpath[0] == '/' ? "" : "/");
     84 	ctx.page.etag = oid_to_hex(oid);
     85 	cgit_print_http_headers();
     86 	htmlf("<html><head><title>%s", slash);
     87 	html_txt(fullpath);
     88 	htmlf("</title></head>\n<body>\n<h2>%s", slash);
     89 	html_txt(fullpath);
     90 	html("</h2>\n<ul>\n");
     91 	len = strlen(fullpath);
     92 	if (len > 1) {
     93 		fullpath[len - 1] = 0;
     94 		slash = strrchr(fullpath, '/');
     95 		if (slash)
     96 			*(slash + 1) = 0;
     97 		else {
     98 			free(fullpath);
     99 			fullpath = NULL;
    100 		}
    101 		html("<li>");
    102 		cgit_plain_link("../", NULL, NULL, ctx.qry.head, ctx.qry.sha1,
    103 				fullpath);
    104 		html("</li>\n");
    105 	}
    106 	free(fullpath);
    107 }
    108 
    109 static void print_dir_entry(const struct object_id *oid, const char *base,
    110 			    int baselen, const char *path, unsigned mode)
    111 {
    112 	char *fullpath;
    113 
    114 	fullpath = buildpath(base, baselen, path);
    115 	if (!S_ISDIR(mode) && !S_ISGITLINK(mode))
    116 		fullpath[strlen(fullpath) - 1] = 0;
    117 	html("  <li>");
    118 	if (S_ISGITLINK(mode)) {
    119 		cgit_submodule_link(NULL, fullpath, oid_to_hex(oid));
    120 	} else
    121 		cgit_plain_link(path, NULL, NULL, ctx.qry.head, ctx.qry.sha1,
    122 				fullpath);
    123 	html("</li>\n");
    124 	free(fullpath);
    125 }
    126 
    127 static void print_dir_tail(void)
    128 {
    129 	html(" </ul>\n</body></html>\n");
    130 }
    131 
    132 static int walk_tree(const struct object_id *oid, struct strbuf *base,
    133 		const char *pathname, unsigned mode, int stage, void *cbdata)
    134 {
    135 	struct walk_tree_context *walk_tree_ctx = cbdata;
    136 
    137 	if (base->len == walk_tree_ctx->match_baselen) {
    138 		if (S_ISREG(mode) || S_ISLNK(mode)) {
    139 			if (print_object(oid, pathname))
    140 				walk_tree_ctx->match = 1;
    141 		} else if (S_ISDIR(mode)) {
    142 			print_dir(oid, base->buf, base->len, pathname);
    143 			walk_tree_ctx->match = 2;
    144 			return READ_TREE_RECURSIVE;
    145 		}
    146 	} else if (base->len < INT_MAX && (int)base->len > walk_tree_ctx->match_baselen) {
    147 		print_dir_entry(oid, base->buf, base->len, pathname, mode);
    148 		walk_tree_ctx->match = 2;
    149 	} else if (S_ISDIR(mode)) {
    150 		return READ_TREE_RECURSIVE;
    151 	}
    152 
    153 	return 0;
    154 }
    155 
    156 static int basedir_len(const char *path)
    157 {
    158 	char *p = strrchr(path, '/');
    159 	if (p)
    160 		return p - path + 1;
    161 	return 0;
    162 }
    163 
    164 void cgit_print_plain(void)
    165 {
    166 	const char *rev = ctx.qry.sha1;
    167 	struct object_id oid;
    168 	struct commit *commit;
    169 	struct pathspec_item path_items = {
    170 		.match = ctx.qry.path,
    171 		.len = ctx.qry.path ? strlen(ctx.qry.path) : 0
    172 	};
    173 	struct pathspec paths = {
    174 		.nr = 1,
    175 		.items = &path_items
    176 	};
    177 	struct walk_tree_context walk_tree_ctx = {
    178 		.match = 0
    179 	};
    180 
    181 	if (!rev)
    182 		rev = ctx.qry.head;
    183 
    184 	if (get_oid(rev, &oid)) {
    185 		cgit_print_error_page(404, "Not found", "Not found");
    186 		return;
    187 	}
    188 	commit = lookup_commit_reference(&oid);
    189 	if (!commit || parse_commit(commit)) {
    190 		cgit_print_error_page(404, "Not found", "Not found");
    191 		return;
    192 	}
    193 	if (!path_items.match) {
    194 		path_items.match = "";
    195 		walk_tree_ctx.match_baselen = -1;
    196 		print_dir(&commit->maybe_tree->object.oid, "", 0, "");
    197 		walk_tree_ctx.match = 2;
    198 	}
    199 	else
    200 		walk_tree_ctx.match_baselen = basedir_len(path_items.match);
    201 	read_tree_recursive(commit->maybe_tree, "", 0, 0, &paths, walk_tree, &walk_tree_ctx);
    202 	if (!walk_tree_ctx.match)
    203 		cgit_print_error_page(404, "Not found", "Not found");
    204 	else if (walk_tree_ctx.match == 2)
    205 		print_dir_tail();
    206 }