From e5da4bca54574522b28f88cab0dc8ebad9e35a73 Mon Sep 17 00:00:00 2001 From: Lars Hjemli Date: Wed, 6 Aug 2008 10:53:50 +0200 Subject: [PATCH 1/3] Implement plain view This implements a way to access plain blobs by path (similar to the tree view) instead of by sha1. Signed-off-by: Lars Hjemli --- Makefile | 1 + cgit.c | 1 + cgit.h | 1 + cmd.c | 7 +++++ html.c | 5 ++++ html.h | 1 + ui-plain.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++ ui-plain.h | 6 ++++ ui-shared.c | 2 ++ 9 files changed, 106 insertions(+) create mode 100644 ui-plain.c create mode 100644 ui-plain.h diff --git a/Makefile b/Makefile index 78aad10..a305894 100644 --- a/Makefile +++ b/Makefile @@ -61,6 +61,7 @@ OBJECTS += ui-commit.o OBJECTS += ui-diff.o OBJECTS += ui-log.o OBJECTS += ui-patch.o +OBJECTS += ui-plain.o OBJECTS += ui-refs.o OBJECTS += ui-repolist.o OBJECTS += ui-shared.o diff --git a/cgit.c b/cgit.c index f49fffa..497337b 100644 --- a/cgit.c +++ b/cgit.c @@ -187,6 +187,7 @@ static void prepare_context(struct cgit_context *ctx) ctx->page.mimetype = "text/html"; ctx->page.charset = PAGE_ENCODING; ctx->page.filename = NULL; + ctx->page.size = 0; ctx->page.modified = time(NULL); ctx->page.expires = ctx->page.modified; } diff --git a/cgit.h b/cgit.h index b01fa31..e2af0c2 100644 --- a/cgit.h +++ b/cgit.h @@ -165,6 +165,7 @@ struct cgit_config { struct cgit_page { time_t modified; time_t expires; + size_t size; char *mimetype; char *charset; char *filename; diff --git a/cmd.c b/cmd.c index 03e165c..2b34189 100644 --- a/cmd.c +++ b/cmd.c @@ -16,6 +16,7 @@ #include "ui-diff.h" #include "ui-log.h" #include "ui-patch.h" +#include "ui-plain.h" #include "ui-refs.h" #include "ui-repolist.h" #include "ui-snapshot.h" @@ -85,6 +86,11 @@ static void patch_fn(struct cgit_context *ctx) cgit_print_patch(ctx->qry.sha1); } +static void plain_fn(struct cgit_context *ctx) +{ + cgit_print_plain(ctx); +} + static void refs_fn(struct cgit_context *ctx) { cgit_print_refs(); @@ -128,6 +134,7 @@ struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx) def_cmd(ls_cache, 0, 0), def_cmd(objects, 1, 0), def_cmd(patch, 1, 0), + def_cmd(plain, 1, 0), def_cmd(refs, 1, 1), def_cmd(repolist, 0, 0), def_cmd(snapshot, 1, 0), diff --git a/html.c b/html.c index 1237076..83fc7a9 100644 --- a/html.c +++ b/html.c @@ -35,6 +35,11 @@ char *fmt(const char *format, ...) return buf[bufidx]; } +void html_raw(const char *data, size_t size) +{ + write(htmlfd, data, size); +} + void html(const char *txt) { write(htmlfd, txt, strlen(txt)); diff --git a/html.h b/html.h index 2bde28d..49462a2 100644 --- a/html.h +++ b/html.h @@ -3,6 +3,7 @@ extern int htmlfd; +extern void html_raw(const char *txt, size_t size); extern void html(const char *txt); extern void htmlf(const char *format,...); extern void html_status(int code, int more_headers); diff --git a/ui-plain.c b/ui-plain.c new file mode 100644 index 0000000..28deae5 --- /dev/null +++ b/ui-plain.c @@ -0,0 +1,82 @@ +/* ui-plain.c: functions for output of plain blobs by path + * + * Copyright (C) 2008 Lars Hjemli + * + * Licensed under GNU General Public License v2 + * (see COPYING for full license text) + */ + +#include "cgit.h" +#include "html.h" +#include "ui-shared.h" + +char *curr_rev; +char *match_path; +int match; + +static void print_object(const unsigned char *sha1, const char *path) +{ + enum object_type type; + char *buf; + size_t size; + + type = sha1_object_info(sha1, &size); + if (type == OBJ_BAD) { + html_status(404, 0); + return; + } + + buf = read_sha1_file(sha1, &type, &size); + if (!buf) { + html_status(404, 0); + return; + } + ctx.page.mimetype = "text/plain"; + ctx.page.filename = fmt("%s", path); + ctx.page.size = size; + cgit_print_http_headers(&ctx); + html_raw(buf, size); + match = 1; +} + +static int walk_tree(const unsigned char *sha1, const char *base, int baselen, + const char *pathname, unsigned mode, int stage, + void *cbdata) +{ + fprintf(stderr, "[cgit] walk_tree.pathname=%s", pathname); + + if (!pathname || strcmp(match_path, pathname)) + return READ_TREE_RECURSIVE; + + if (S_ISREG(mode)) + print_object(sha1, pathname); + + return 0; +} + +void cgit_print_plain(struct cgit_context *ctx) +{ + const char *rev = ctx->qry.sha1; + unsigned char sha1[20]; + struct commit *commit; + const char *paths[] = {ctx->qry.path, NULL}; + + if (!rev) + rev = ctx->qry.head; + + curr_rev = xstrdup(rev); + if (get_sha1(rev, sha1)) { + html_status(404, 0); + return; + } + commit = lookup_commit_reference(sha1); + if (!commit || parse_commit(commit)) { + html_status(404, 0); + return; + } + match_path = ctx->qry.path; + fprintf(stderr, "[cgit] match_path=%s", match_path); + read_tree_recursive(commit->tree, NULL, 0, 0, paths, walk_tree, NULL); + if (!match) + html_status(404, 0); +} diff --git a/ui-plain.h b/ui-plain.h new file mode 100644 index 0000000..4373118 --- /dev/null +++ b/ui-plain.h @@ -0,0 +1,6 @@ +#ifndef UI_PLAIN_H +#define UI_PLAIN_H + +extern void cgit_print_plain(struct cgit_context *ctx); + +#endif /* UI_PLAIN_H */ diff --git a/ui-shared.c b/ui-shared.c index 197ee37..4408969 100644 --- a/ui-shared.c +++ b/ui-shared.c @@ -418,6 +418,8 @@ void cgit_print_http_headers(struct cgit_context *ctx) ctx->page.charset); else if (ctx->page.mimetype) htmlf("Content-Type: %s\n", ctx->page.mimetype); + if (ctx->page.size) + htmlf("Content-Length: %ld\n", ctx->page.size); if (ctx->page.filename) htmlf("Content-Disposition: inline; filename=\"%s\"\n", ctx->page.filename); From 65b7b876aaaf50fc15060533359d6561f4f1819a Mon Sep 17 00:00:00 2001 From: Lars Hjemli Date: Wed, 6 Aug 2008 11:07:13 +0200 Subject: [PATCH 2/3] ui-tree: link to plain view instead of blob view The urls for plain view makes it possible to download blobs without knowing their SHA1, but the function needs to be promoted and the link from tree view seems like a perfect fit. PS: Although hidden, the blob view still is nice for direct blob access so there's no point in removing it. Signed-off-by: Lars Hjemli --- ui-shared.c | 6 ++++++ ui-shared.h | 2 ++ ui-tree.c | 8 ++++---- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/ui-shared.c b/ui-shared.c index 4408969..a2e0dd2 100644 --- a/ui-shared.c +++ b/ui-shared.c @@ -243,6 +243,12 @@ void cgit_tree_link(char *name, char *title, char *class, char *head, reporevlink("tree", name, title, class, head, rev, path); } +void cgit_plain_link(char *name, char *title, char *class, char *head, + char *rev, char *path) +{ + reporevlink("plain", name, title, class, head, rev, path); +} + void cgit_log_link(char *name, char *title, char *class, char *head, char *rev, char *path, int ofs, char *grep, char *pattern) { diff --git a/ui-shared.h b/ui-shared.h index 07da4b4..c5ce056 100644 --- a/ui-shared.h +++ b/ui-shared.h @@ -11,6 +11,8 @@ extern void cgit_index_link(char *name, char *title, char *class, char *pattern, int ofs); extern void cgit_tree_link(char *name, char *title, char *class, char *head, char *rev, char *path); +extern void cgit_plain_link(char *name, char *title, char *class, char *head, + char *rev, char *path); extern void cgit_log_link(char *name, char *title, char *class, char *head, char *rev, char *path, int ofs, char *grep, char *pattern); diff --git a/ui-tree.c b/ui-tree.c index 9a837e2..79332fc 100644 --- a/ui-tree.c +++ b/ui-tree.c @@ -35,10 +35,10 @@ static void print_object(const unsigned char *sha1, char *path) return; } - html(" blob: %s",sha1_to_hex(sha1)); + html(" ("); + cgit_plain_link("plain", NULL, NULL, ctx.qry.head, + curr_rev, path); + htmlf(")
blob: %s", sha1_to_hex(sha1)); html("\n"); idx = 0; From 885096c189574b1cf2e0897cc05aadd7b092a677 Mon Sep 17 00:00:00 2001 From: Lars Hjemli Date: Wed, 6 Aug 2008 22:57:44 +0200 Subject: [PATCH 3/3] Supply status description to html_status() Signed-off-by: Lars Hjemli --- html.c | 4 ++-- html.h | 2 +- ui-clone.c | 10 ++++------ ui-plain.c | 10 +++++----- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/html.c b/html.c index 83fc7a9..36e9a2f 100644 --- a/html.c +++ b/html.c @@ -56,9 +56,9 @@ void htmlf(const char *format, ...) html(buf); } -void html_status(int code, int more_headers) +void html_status(int code, const char *msg, int more_headers) { - htmlf("Status: %d\n", code); + htmlf("Status: %d %s\n", code, msg); if (!more_headers) html("\n"); } diff --git a/html.h b/html.h index 49462a2..3c32935 100644 --- a/html.h +++ b/html.h @@ -6,7 +6,7 @@ extern int htmlfd; extern void html_raw(const char *txt, size_t size); extern void html(const char *txt); extern void htmlf(const char *format,...); -extern void html_status(int code, int more_headers); +extern void html_status(int code, const char *msg, int more_headers); extern void html_txt(char *txt); extern void html_ntxt(int len, char *txt); extern void html_attr(char *txt); diff --git a/ui-clone.c b/ui-clone.c index 3a037ad..81e7a4e 100644 --- a/ui-clone.c +++ b/ui-clone.c @@ -48,20 +48,18 @@ static void print_pack_info(struct cgit_context *ctx) static void send_file(struct cgit_context *ctx, char *path) { struct stat st; - int err; if (stat(path, &st)) { switch (errno) { case ENOENT: - err = 404; + html_status(404, "Not found", 0); break; case EACCES: - err = 403; + html_status(403, "Forbidden", 0); break; default: - err = 400; + html_status(400, "Bad request", 0); } - html_status(err, 0); return; } ctx->page.mimetype = "application/octet-stream"; @@ -86,7 +84,7 @@ void cgit_clone_info(struct cgit_context *ctx) void cgit_clone_objects(struct cgit_context *ctx) { if (!ctx->qry.path) { - html_status(400, 0); + html_status(400, "Bad request", 0); return; } diff --git a/ui-plain.c b/ui-plain.c index 28deae5..35888a0 100644 --- a/ui-plain.c +++ b/ui-plain.c @@ -22,13 +22,13 @@ static void print_object(const unsigned char *sha1, const char *path) type = sha1_object_info(sha1, &size); if (type == OBJ_BAD) { - html_status(404, 0); + html_status(404, "Not found", 0); return; } buf = read_sha1_file(sha1, &type, &size); if (!buf) { - html_status(404, 0); + html_status(404, "Not found", 0); return; } ctx.page.mimetype = "text/plain"; @@ -66,17 +66,17 @@ void cgit_print_plain(struct cgit_context *ctx) curr_rev = xstrdup(rev); if (get_sha1(rev, sha1)) { - html_status(404, 0); + html_status(404, "Not found", 0); return; } commit = lookup_commit_reference(sha1); if (!commit || parse_commit(commit)) { - html_status(404, 0); + html_status(404, "Not found", 0); return; } match_path = ctx->qry.path; fprintf(stderr, "[cgit] match_path=%s", match_path); read_tree_recursive(commit->tree, NULL, 0, 0, paths, walk_tree, NULL); if (!match) - html_status(404, 0); + html_status(404, "Not found", 0); }