c699866699
By specifying the "url" query parameter multiple times it is possible to end up with ctx.qry.vpath set while ctx.repo is null, which triggers an invalid code path from cgit_print_pageheader() while printing path crumbs, resulting in a null dereference. The previous patch fixed this segfault, but it makes no sense for us to clear ctx.repo while leaving ctx.qry.path set to the previous value, so let's just clear it here so that the last "url" parameter given takes full effect rather than partially overriding the effect of the previous value. Signed-off-by: John Keeping <john@keeping.me.uk>
227 строки
4.6 KiB
C
227 строки
4.6 KiB
C
/* parsing.c: parsing of config files
|
|
*
|
|
* Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
|
|
*
|
|
* Licensed under GNU General Public License v2
|
|
* (see COPYING for full license text)
|
|
*/
|
|
|
|
#include "cgit.h"
|
|
|
|
/*
|
|
* url syntax: [repo ['/' cmd [ '/' path]]]
|
|
* repo: any valid repo url, may contain '/'
|
|
* cmd: log | commit | diff | tree | view | blob | snapshot
|
|
* path: any valid path, may contain '/'
|
|
*
|
|
*/
|
|
void cgit_parse_url(const char *url)
|
|
{
|
|
char *c, *cmd, *p;
|
|
struct cgit_repo *repo;
|
|
|
|
ctx.repo = NULL;
|
|
ctx.qry.page = NULL;
|
|
if (!url || url[0] == '\0')
|
|
return;
|
|
|
|
ctx.repo = cgit_get_repoinfo(url);
|
|
if (ctx.repo) {
|
|
ctx.qry.repo = ctx.repo->url;
|
|
return;
|
|
}
|
|
|
|
cmd = NULL;
|
|
c = strchr(url, '/');
|
|
while (c) {
|
|
c[0] = '\0';
|
|
repo = cgit_get_repoinfo(url);
|
|
if (repo) {
|
|
ctx.repo = repo;
|
|
cmd = c;
|
|
}
|
|
c[0] = '/';
|
|
c = strchr(c + 1, '/');
|
|
}
|
|
|
|
if (ctx.repo) {
|
|
ctx.qry.repo = ctx.repo->url;
|
|
p = strchr(cmd + 1, '/');
|
|
if (p) {
|
|
p[0] = '\0';
|
|
if (p[1])
|
|
ctx.qry.path = trim_end(p + 1, '/');
|
|
}
|
|
if (cmd[1])
|
|
ctx.qry.page = xstrdup(cmd + 1);
|
|
}
|
|
}
|
|
|
|
static char *substr(const char *head, const char *tail)
|
|
{
|
|
char *buf;
|
|
|
|
if (tail < head)
|
|
return xstrdup("");
|
|
buf = xmalloc(tail - head + 1);
|
|
strncpy(buf, head, tail - head);
|
|
buf[tail - head] = '\0';
|
|
return buf;
|
|
}
|
|
|
|
static void parse_user(const char *t, char **name, char **email, unsigned long *date, int *tz)
|
|
{
|
|
struct ident_split ident;
|
|
unsigned email_len;
|
|
|
|
if (!split_ident_line(&ident, t, strchrnul(t, '\n') - t)) {
|
|
*name = substr(ident.name_begin, ident.name_end);
|
|
|
|
email_len = ident.mail_end - ident.mail_begin;
|
|
*email = xmalloc(strlen("<") + email_len + strlen(">") + 1);
|
|
sprintf(*email, "<%.*s>", email_len, ident.mail_begin);
|
|
|
|
if (ident.date_begin)
|
|
*date = strtoul(ident.date_begin, NULL, 10);
|
|
if (ident.tz_begin)
|
|
*tz = atoi(ident.tz_begin);
|
|
}
|
|
}
|
|
|
|
#ifdef NO_ICONV
|
|
#define reencode(a, b, c)
|
|
#else
|
|
static const char *reencode(char **txt, const char *src_enc, const char *dst_enc)
|
|
{
|
|
char *tmp;
|
|
|
|
if (!txt)
|
|
return NULL;
|
|
|
|
if (!*txt || !src_enc || !dst_enc)
|
|
return *txt;
|
|
|
|
/* no encoding needed if src_enc equals dst_enc */
|
|
if (!strcasecmp(src_enc, dst_enc))
|
|
return *txt;
|
|
|
|
tmp = reencode_string(*txt, dst_enc, src_enc);
|
|
if (tmp) {
|
|
free(*txt);
|
|
*txt = tmp;
|
|
}
|
|
return *txt;
|
|
}
|
|
#endif
|
|
|
|
static const char *next_header_line(const char *p)
|
|
{
|
|
p = strchr(p, '\n');
|
|
if (!p)
|
|
return NULL;
|
|
return p + 1;
|
|
}
|
|
|
|
static int end_of_header(const char *p)
|
|
{
|
|
return !p || (*p == '\n');
|
|
}
|
|
|
|
struct commitinfo *cgit_parse_commit(struct commit *commit)
|
|
{
|
|
const int sha1hex_len = 40;
|
|
struct commitinfo *ret;
|
|
const char *p = get_cached_commit_buffer(commit, NULL);
|
|
const char *t;
|
|
|
|
ret = xcalloc(1, sizeof(struct commitinfo));
|
|
ret->commit = commit;
|
|
|
|
if (!p)
|
|
return ret;
|
|
|
|
if (!skip_prefix(p, "tree ", &p))
|
|
die("Bad commit: %s", oid_to_hex(&commit->object.oid));
|
|
p += sha1hex_len + 1;
|
|
|
|
while (skip_prefix(p, "parent ", &p))
|
|
p += sha1hex_len + 1;
|
|
|
|
if (p && skip_prefix(p, "author ", &p)) {
|
|
parse_user(p, &ret->author, &ret->author_email,
|
|
&ret->author_date, &ret->author_tz);
|
|
p = next_header_line(p);
|
|
}
|
|
|
|
if (p && skip_prefix(p, "committer ", &p)) {
|
|
parse_user(p, &ret->committer, &ret->committer_email,
|
|
&ret->committer_date, &ret->committer_tz);
|
|
p = next_header_line(p);
|
|
}
|
|
|
|
if (p && skip_prefix(p, "encoding ", &p)) {
|
|
t = strchr(p, '\n');
|
|
if (t) {
|
|
ret->msg_encoding = substr(p, t + 1);
|
|
p = t + 1;
|
|
}
|
|
}
|
|
|
|
if (!ret->msg_encoding)
|
|
ret->msg_encoding = xstrdup("UTF-8");
|
|
|
|
while (!end_of_header(p))
|
|
p = next_header_line(p);
|
|
while (p && *p == '\n')
|
|
p++;
|
|
if (!p)
|
|
return ret;
|
|
|
|
t = strchrnul(p, '\n');
|
|
ret->subject = substr(p, t);
|
|
while (*t == '\n')
|
|
t++;
|
|
ret->msg = xstrdup(t);
|
|
|
|
reencode(&ret->author, ret->msg_encoding, PAGE_ENCODING);
|
|
reencode(&ret->author_email, ret->msg_encoding, PAGE_ENCODING);
|
|
reencode(&ret->committer, ret->msg_encoding, PAGE_ENCODING);
|
|
reencode(&ret->committer_email, ret->msg_encoding, PAGE_ENCODING);
|
|
reencode(&ret->subject, ret->msg_encoding, PAGE_ENCODING);
|
|
reencode(&ret->msg, ret->msg_encoding, PAGE_ENCODING);
|
|
|
|
return ret;
|
|
}
|
|
|
|
struct taginfo *cgit_parse_tag(struct tag *tag)
|
|
{
|
|
void *data;
|
|
enum object_type type;
|
|
unsigned long size;
|
|
const char *p;
|
|
struct taginfo *ret = NULL;
|
|
|
|
data = read_sha1_file(tag->object.oid.hash, &type, &size);
|
|
if (!data || type != OBJ_TAG)
|
|
goto cleanup;
|
|
|
|
ret = xcalloc(1, sizeof(struct taginfo));
|
|
|
|
for (p = data; !end_of_header(p); p = next_header_line(p)) {
|
|
if (skip_prefix(p, "tagger ", &p)) {
|
|
parse_user(p, &ret->tagger, &ret->tagger_email,
|
|
&ret->tagger_date, &ret->tagger_tz);
|
|
}
|
|
}
|
|
|
|
while (p && *p == '\n')
|
|
p++;
|
|
|
|
if (p && *p)
|
|
ret->msg = xstrdup(p);
|
|
|
|
cleanup:
|
|
free(data);
|
|
return ret;
|
|
}
|