commit d6795e9fa6cc029fe5e47ccc827abe3a498a7e71 from: Omar Polo via: Thomas Adam date: Fri Dec 30 14:58:03 2022 UTC gotwebd: add an RSS feed for the tags ok tracey@ commit - 3191e25687ad12e5d81efb8827a7bddee0ba0465 commit + d6795e9fa6cc029fe5e47ccc827abe3a498a7e71 blob - 678acf36a49b4d793e83499935473a2a12f9ebd5 blob + bb5fdc03540ccfbca6182ba7a6cee7837c03e68a --- gotwebd/fcgi.c +++ gotwebd/fcgi.c @@ -278,6 +278,10 @@ fcgi_parse_params(uint8_t *buf, uint16_t n, struct req memcpy(c->server_name, val, val_len); c->server_name[val_len] = '\0'; } + + if (name_len == 5 && + strncmp(buf, "HTTPS", 5) == 0) + c->https = 1; buf += name_len + val_len; n -= name_len - val_len; blob - 720ddf7a23a10f5f33bb11b3c77f9932477b30f5 blob + 40e8ef26d1b28b601ac2a1af3b4f766a63e48ece --- gotwebd/got_operations.c +++ gotwebd/got_operations.c @@ -572,7 +572,7 @@ got_get_repo_tags(struct request *c, int limit) repo_dir->name) == -1) return got_error_from_errno("asprintf"); - if (qs->commit == NULL && qs->action == TAGS) { + if (qs->commit == NULL && (qs->action == TAGS || qs->action == RSS)) { error = got_ref_open(&ref, repo, qs->headref, 0); if (error) goto err; blob - c142c6086c544ad69c9b72a50fe058746924751c blob + 496645105ab3ccefd1837eaa9e57b785168829b2 --- gotwebd/gotweb.c +++ gotwebd/gotweb.c @@ -49,6 +49,7 @@ #include "proc.h" #include "gotwebd.h" +#include "tmpl.h" static const struct querystring_keys querystring_keys[] = { { "action", ACTION }, @@ -73,6 +74,7 @@ static const struct action_keys action_keys[] = { { "tag", TAG }, { "tags", TAGS }, { "tree", TREE }, + { "rss", RSS }, }; static const struct got_error *gotweb_init_querystring(struct querystring **); @@ -169,10 +171,28 @@ gotweb_process_request(struct request *c) if (error) goto done; error = got_output_file_blob(c); + if (error) { + log_warnx("%s: %s", __func__, error->msg); + goto err; + } + goto done; + } + + if (qs->action == RSS) { + error = gotweb_render_content_type(c, + "application/rss+xml;charset=utf-8"); + if (error) { + log_warnx("%s: %s", __func__, error->msg); + goto err; + } + + error = got_get_repo_tags(c, D_MAXSLCOMMDISP); if (error) { log_warnx("%s: %s", __func__, error->msg); goto err; } + if (gotweb_render_rss(c->tp) == -1) + goto err; goto done; } @@ -1623,6 +1643,8 @@ gotweb_action_name(int action) return "tags"; case TREE: return "tree"; + case RSS: + return "rss"; default: return NULL; } @@ -1721,6 +1743,21 @@ gotweb_render_url(struct request *c, struct gotweb_url } int +gotweb_render_absolute_url(struct request *c, struct gotweb_url *url) +{ + struct template *tp = c->tp; + const char *proto = c->https ? "https" : "http"; + + if (fcgi_puts(tp, proto) == -1 || + fcgi_puts(tp, "://") == -1 || + tp_htmlescape(tp, c->server_name) == -1 || + tp_htmlescape(tp, c->document_uri) == -1) + return -1; + + return gotweb_render_url(c, url); +} + +int gotweb_link(struct request *c, struct gotweb_url *url, const char *fmt, ...) { va_list ap; @@ -2003,7 +2040,8 @@ gotweb_get_time_str(char **repo_age, time_t committer_ const char *hours = "hours ago", *minutes = "minutes ago"; const char *seconds = "seconds ago", *now = "right now"; char *s; - char datebuf[29]; + char datebuf[64]; + size_t r; *repo_age = NULL; @@ -2055,6 +2093,19 @@ gotweb_get_time_str(char **repo_age, time_t committer_ if (asprintf(repo_age, "%s UTC", datebuf) == -1) return got_error_from_errno("asprintf"); break; + case TM_RFC822: + if (gmtime_r(&committer_time, &tm) == NULL) + return got_error_from_errno("gmtime_r"); + + r = strftime(datebuf, sizeof(datebuf), + "%a, %d %b %Y %H:%M:%S GMT", &tm); + if (r == 0) + return got_error(GOT_ERR_NO_SPACE); + + *repo_age = strdup(datebuf); + if (*repo_age == NULL) + return got_error_from_errno("asprintf"); + break; } return NULL; } blob - 38161394053fe7a7aca451c50b25e97bb1f80898 blob + c54fe3683dc1d915d6d3fa880753b93adc5252e5 --- gotwebd/gotwebd.h +++ gotwebd/gotwebd.h @@ -226,6 +226,7 @@ struct request { char http_host[GOTWEBD_MAXTEXT]; char document_uri[MAX_DOCUMENT_URI]; char server_name[MAX_SERVER_NAME]; + int https; uint8_t request_started; }; @@ -412,12 +413,14 @@ enum query_actions { TAG, TAGS, TREE, + RSS, ACTIONS__MAX, }; enum gotweb_ref_tm { TM_DIFF, TM_LONG, + TM_RFC822, }; extern struct gotwebd *gotwebd_env; @@ -441,6 +444,7 @@ const struct got_error *gotweb_init_transport(struct t const struct got_error *gotweb_escape_html(char **, const char *); const char *gotweb_action_name(int); int gotweb_render_url(struct request *, struct gotweb_url *); +int gotweb_render_absolute_url(struct request *, struct gotweb_url *); int gotweb_link(struct request *, struct gotweb_url *, const char *, ...) __attribute__((__format__(printf, 3, 4))) __attribute__((__nonnull__(3))); @@ -457,6 +461,7 @@ int gotweb_render_repo_fragment(struct template *, str int gotweb_render_briefs(struct template *); int gotweb_render_navs(struct template *); int gotweb_render_commits(struct template *); +int gotweb_render_rss(struct template *); /* parse.y */ int parse_config(const char *, struct gotwebd *); blob - a822e44c28412ddbf85071a448bc1fca3266812d blob + d694fb2afcffcc2b7f3319fcff1c1f49c6545ed5 --- gotwebd/pages.tmpl +++ gotwebd/pages.tmpl @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -30,6 +31,9 @@ #include "gotwebd.h" #include "tmpl.h" +static inline int rss_tag_item(struct template *, struct repo_tag *); +static inline int rss_author(struct template *, char *); + static int gotweb_render_age(struct template *tp, time_t time, int ref_tm) { @@ -179,6 +183,11 @@ gotweb_render_age(struct template *tp, time_t time, in .index_page = -1, .page = -1, .path = repo_dir->name, + }, rss = { + .action = RSS, + .index_page = -1, + .page = -1, + .path = repo_dir->name, }; !}
@@ -211,6 +220,8 @@ gotweb_render_age(struct template *tp, time_t time, in tags {{ " | " }} tree + {{ " | " }} + rss
@@ -388,4 +399,99 @@ gotweb_render_age(struct template *tp, time_t time, in {{ render gotweb_render_navs(tp) }} {{ end }} +{{ end }} + +{{ define gotweb_render_rss(struct template *tp) }} +{! + struct request *c = tp->tp_arg; + struct server *srv = c->srv; + struct transport *t = c->t; + struct repo_dir *repo_dir = t->repo_dir; + struct repo_tag *rt; + struct gotweb_url summary = { + .action = SUMMARY, + .index_page = -1, + .page = -1, + .path = repo_dir->name, + }; +!} + + + + Tags of {{ repo_dir->name }} + + + + {{ if srv->show_repo_description }} + {{ repo_dir->description }} + {{ end }} + {{ tailq-foreach rt &t->repo_tags entry }} + {{ render rss_tag_item(tp, rt) }} + {{ end }} + + +{{ end }} + +{{ define rss_tag_item(struct template *tp, struct repo_tag *rt) }} +{! + struct request *c = tp->tp_arg; + struct transport *t = c->t; + struct repo_dir *repo_dir = t->repo_dir; + char *tag_name = rt->tag_name; + struct gotweb_url tag = { + .action = TAG, + .index_page = -1, + .page = -1, + .path = repo_dir->name, + .commit = rt->commit_id, + }; + + if (strncmp(tag_name, "refs/tags/", 10) == 0) + tag_name += 10; +!} + + {{ repo_dir->name }} {{" "}} {{ tag_name }} + + + + + {{ rt->tag_commit }}]]> + + {{ render rss_author(tp, rt->tagger) }} + {{ rt->commit_id }} + + {{ render gotweb_render_age(tp, rt->tagger_time, TM_RFC822) }} + + {{ end }} + +{{ define rss_author(struct template *tp, char *author) }} +{! + char *t, *mail; + + /* what to do if the author name contains a paren? */ + if (strchr(author, '(') != NULL || strchr(author, ')') != NULL) + return 0; + + t = strchr(author, '<'); + if (t == NULL) + return 0; + *t = '\0'; + mail = t+1; + + while (isspace((unsigned char)*--t)) + *t = '\0'; + + t = strchr(mail, '>'); + if (t == NULL) + return 0; + *t = '\0'; +!} + + {{ mail }} {{" "}} ({{ author }}) + +{{ end }}