Blame


1 8a35f56c 2022-07-16 thomas /*
2 8a35f56c 2022-07-16 thomas * Copyright (c) 2016, 2019, 2020-2022 Tracey Emery <tracey@traceyemery.net>
3 8a35f56c 2022-07-16 thomas * Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
4 2ac684a4 2022-09-03 thomas * Copyright (c) 2014 Reyk Floeter <reyk@openbsd.org>
5 8a35f56c 2022-07-16 thomas * Copyright (c) 2013 David Gwynne <dlg@openbsd.org>
6 8a35f56c 2022-07-16 thomas * Copyright (c) 2013 Florian Obser <florian@openbsd.org>
7 8a35f56c 2022-07-16 thomas *
8 8a35f56c 2022-07-16 thomas * Permission to use, copy, modify, and distribute this software for any
9 8a35f56c 2022-07-16 thomas * purpose with or without fee is hereby granted, provided that the above
10 8a35f56c 2022-07-16 thomas * copyright notice and this permission notice appear in all copies.
11 8a35f56c 2022-07-16 thomas *
12 8a35f56c 2022-07-16 thomas * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 8a35f56c 2022-07-16 thomas * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 8a35f56c 2022-07-16 thomas * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 8a35f56c 2022-07-16 thomas * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 8a35f56c 2022-07-16 thomas * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 8a35f56c 2022-07-16 thomas * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 8a35f56c 2022-07-16 thomas * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 8a35f56c 2022-07-16 thomas */
20 8a35f56c 2022-07-16 thomas
21 8a35f56c 2022-07-16 thomas #include <net/if.h>
22 8a35f56c 2022-07-16 thomas #include <netinet/in.h>
23 3e12c168 2022-07-16 thomas #include <sys/queue.h>
24 8a35f56c 2022-07-16 thomas #include <sys/stat.h>
25 8a35f56c 2022-07-16 thomas #include <sys/types.h>
26 8a35f56c 2022-07-16 thomas
27 2ac684a4 2022-09-03 thomas #include <ctype.h>
28 8a35f56c 2022-07-16 thomas #include <dirent.h>
29 8a35f56c 2022-07-16 thomas #include <errno.h>
30 8a35f56c 2022-07-16 thomas #include <event.h>
31 4606e6d4 2022-11-23 thomas #include <fcntl.h>
32 4606e6d4 2022-11-23 thomas #include <imsg.h>
33 8a35f56c 2022-07-16 thomas #include <stdio.h>
34 8a35f56c 2022-07-16 thomas #include <stdlib.h>
35 8a35f56c 2022-07-16 thomas #include <string.h>
36 8a35f56c 2022-07-16 thomas #include <unistd.h>
37 8a35f56c 2022-07-16 thomas
38 8a35f56c 2022-07-16 thomas #include "got_error.h"
39 8a35f56c 2022-07-16 thomas #include "got_object.h"
40 8a35f56c 2022-07-16 thomas #include "got_reference.h"
41 8a35f56c 2022-07-16 thomas #include "got_repository.h"
42 8a35f56c 2022-07-16 thomas #include "got_path.h"
43 8a35f56c 2022-07-16 thomas #include "got_cancel.h"
44 8a35f56c 2022-07-16 thomas #include "got_worktree.h"
45 8a35f56c 2022-07-16 thomas #include "got_diff.h"
46 8a35f56c 2022-07-16 thomas #include "got_commit_graph.h"
47 8a35f56c 2022-07-16 thomas #include "got_blame.h"
48 8a35f56c 2022-07-16 thomas #include "got_privsep.h"
49 8a35f56c 2022-07-16 thomas
50 8a35f56c 2022-07-16 thomas #include "proc.h"
51 8a35f56c 2022-07-16 thomas #include "gotwebd.h"
52 ff36aeea 2022-07-16 thomas
53 8a35f56c 2022-07-16 thomas static const struct querystring_keys querystring_keys[] = {
54 8a35f56c 2022-07-16 thomas { "action", ACTION },
55 8a35f56c 2022-07-16 thomas { "commit", COMMIT },
56 8a35f56c 2022-07-16 thomas { "file", RFILE },
57 8a35f56c 2022-07-16 thomas { "folder", FOLDER },
58 8a35f56c 2022-07-16 thomas { "headref", HEADREF },
59 8a35f56c 2022-07-16 thomas { "index_page", INDEX_PAGE },
60 8a35f56c 2022-07-16 thomas { "path", PATH },
61 8a35f56c 2022-07-16 thomas { "page", PAGE },
62 8a35f56c 2022-07-16 thomas };
63 8a35f56c 2022-07-16 thomas
64 8a35f56c 2022-07-16 thomas static const struct action_keys action_keys[] = {
65 8a35f56c 2022-07-16 thomas { "blame", BLAME },
66 8a35f56c 2022-07-16 thomas { "blob", BLOB },
67 8a35f56c 2022-07-16 thomas { "briefs", BRIEFS },
68 8a35f56c 2022-07-16 thomas { "commits", COMMITS },
69 8a35f56c 2022-07-16 thomas { "diff", DIFF },
70 8a35f56c 2022-07-16 thomas { "error", ERR },
71 8a35f56c 2022-07-16 thomas { "index", INDEX },
72 8a35f56c 2022-07-16 thomas { "summary", SUMMARY },
73 8a35f56c 2022-07-16 thomas { "tag", TAG },
74 8a35f56c 2022-07-16 thomas { "tags", TAGS },
75 8a35f56c 2022-07-16 thomas { "tree", TREE },
76 8a35f56c 2022-07-16 thomas };
77 8a35f56c 2022-07-16 thomas
78 8a35f56c 2022-07-16 thomas static const struct got_error *gotweb_init_querystring(struct querystring **);
79 8a35f56c 2022-07-16 thomas static const struct got_error *gotweb_parse_querystring(struct querystring **,
80 8a35f56c 2022-07-16 thomas char *);
81 8a35f56c 2022-07-16 thomas static const struct got_error *gotweb_assign_querystring(struct querystring **,
82 8a35f56c 2022-07-16 thomas char *, char *);
83 8a35f56c 2022-07-16 thomas static const struct got_error *gotweb_render_index(struct request *);
84 8a35f56c 2022-07-16 thomas static const struct got_error *gotweb_init_repo_dir(struct repo_dir **,
85 8a35f56c 2022-07-16 thomas const char *);
86 8a35f56c 2022-07-16 thomas static const struct got_error *gotweb_load_got_path(struct request *c,
87 8a35f56c 2022-07-16 thomas struct repo_dir *);
88 8a35f56c 2022-07-16 thomas static const struct got_error *gotweb_get_repo_description(char **,
89 4606e6d4 2022-11-23 thomas struct server *, const char *, int);
90 8a35f56c 2022-07-16 thomas static const struct got_error *gotweb_get_clone_url(char **, struct server *,
91 4606e6d4 2022-11-23 thomas const char *, int);
92 8a35f56c 2022-07-16 thomas static const struct got_error *gotweb_render_blame(struct request *);
93 8a35f56c 2022-07-16 thomas static const struct got_error *gotweb_render_commits(struct request *);
94 8a35f56c 2022-07-16 thomas static const struct got_error *gotweb_render_diff(struct request *);
95 8a35f56c 2022-07-16 thomas static const struct got_error *gotweb_render_summary(struct request *);
96 8a35f56c 2022-07-16 thomas static const struct got_error *gotweb_render_tag(struct request *);
97 8a35f56c 2022-07-16 thomas static const struct got_error *gotweb_render_tags(struct request *);
98 8a35f56c 2022-07-16 thomas static const struct got_error *gotweb_render_tree(struct request *);
99 8a35f56c 2022-07-16 thomas static const struct got_error *gotweb_render_branches(struct request *);
100 8a35f56c 2022-07-16 thomas
101 e7e5fa49 2022-12-30 thomas const struct got_error *gotweb_render_navs(struct request *);
102 e7e5fa49 2022-12-30 thomas
103 8a35f56c 2022-07-16 thomas static void gotweb_free_querystring(struct querystring *);
104 8a35f56c 2022-07-16 thomas static void gotweb_free_repo_dir(struct repo_dir *);
105 8a35f56c 2022-07-16 thomas
106 3f0158b4 2022-08-30 thomas struct server *gotweb_get_server(uint8_t *, uint8_t *);
107 8a35f56c 2022-07-16 thomas
108 8a35f56c 2022-07-16 thomas void
109 8a35f56c 2022-07-16 thomas gotweb_process_request(struct request *c)
110 8a35f56c 2022-07-16 thomas {
111 8a35f56c 2022-07-16 thomas const struct got_error *error = NULL, *error2 = NULL;
112 8a35f56c 2022-07-16 thomas struct server *srv = NULL;
113 8a35f56c 2022-07-16 thomas struct querystring *qs = NULL;
114 8a35f56c 2022-07-16 thomas struct repo_dir *repo_dir = NULL;
115 8a35f56c 2022-07-16 thomas uint8_t err[] = "gotwebd experienced an error: ";
116 79393471 2022-08-27 thomas int r, html = 0;
117 8a35f56c 2022-07-16 thomas
118 8a35f56c 2022-07-16 thomas /* init the transport */
119 8a35f56c 2022-07-16 thomas error = gotweb_init_transport(&c->t);
120 8a35f56c 2022-07-16 thomas if (error) {
121 8a35f56c 2022-07-16 thomas log_warnx("%s: %s", __func__, error->msg);
122 46aeda9a 2022-08-27 thomas return;
123 8a35f56c 2022-07-16 thomas }
124 8a35f56c 2022-07-16 thomas /* don't process any further if client disconnected */
125 8a35f56c 2022-07-16 thomas if (c->sock->client_status == CLIENT_DISCONNECT)
126 8a35f56c 2022-07-16 thomas return;
127 8a35f56c 2022-07-16 thomas /* get the gotwebd server */
128 3f0158b4 2022-08-30 thomas srv = gotweb_get_server(c->server_name, c->http_host);
129 8a35f56c 2022-07-16 thomas if (srv == NULL) {
130 8a35f56c 2022-07-16 thomas log_warnx("%s: error server is NULL", __func__);
131 8a35f56c 2022-07-16 thomas goto err;
132 8a35f56c 2022-07-16 thomas }
133 8a35f56c 2022-07-16 thomas c->srv = srv;
134 8a35f56c 2022-07-16 thomas /* parse our querystring */
135 8a35f56c 2022-07-16 thomas error = gotweb_init_querystring(&qs);
136 8a35f56c 2022-07-16 thomas if (error) {
137 8a35f56c 2022-07-16 thomas log_warnx("%s: %s", __func__, error->msg);
138 8a35f56c 2022-07-16 thomas goto err;
139 8a35f56c 2022-07-16 thomas }
140 8a35f56c 2022-07-16 thomas c->t->qs = qs;
141 8a35f56c 2022-07-16 thomas error = gotweb_parse_querystring(&qs, c->querystring);
142 8a35f56c 2022-07-16 thomas if (error) {
143 8a35f56c 2022-07-16 thomas log_warnx("%s: %s", __func__, error->msg);
144 8a35f56c 2022-07-16 thomas goto err;
145 8a35f56c 2022-07-16 thomas }
146 8a35f56c 2022-07-16 thomas
147 8a35f56c 2022-07-16 thomas /*
148 8a35f56c 2022-07-16 thomas * certain actions require a commit id in the querystring. this stops
149 8a35f56c 2022-07-16 thomas * bad actors from exploiting this by manually manipulating the
150 8a35f56c 2022-07-16 thomas * querystring.
151 8a35f56c 2022-07-16 thomas */
152 8a35f56c 2022-07-16 thomas
153 8a35f56c 2022-07-16 thomas if (qs->commit == NULL && (qs->action == BLAME || qs->action == BLOB ||
154 8a35f56c 2022-07-16 thomas qs->action == DIFF)) {
155 8a35f56c 2022-07-16 thomas error2 = got_error(GOT_ERR_QUERYSTRING);
156 8a35f56c 2022-07-16 thomas goto render;
157 8a35f56c 2022-07-16 thomas }
158 8a35f56c 2022-07-16 thomas
159 8a35f56c 2022-07-16 thomas if (qs->action != INDEX) {
160 8a35f56c 2022-07-16 thomas error = gotweb_init_repo_dir(&repo_dir, qs->path);
161 8a35f56c 2022-07-16 thomas if (error)
162 8a35f56c 2022-07-16 thomas goto done;
163 8a35f56c 2022-07-16 thomas error = gotweb_load_got_path(c, repo_dir);
164 8a35f56c 2022-07-16 thomas c->t->repo_dir = repo_dir;
165 8a35f56c 2022-07-16 thomas if (error && error->code != GOT_ERR_LONELY_PACKIDX)
166 8a35f56c 2022-07-16 thomas goto err;
167 8a35f56c 2022-07-16 thomas }
168 8a35f56c 2022-07-16 thomas
169 8a35f56c 2022-07-16 thomas /* render top of page */
170 8a35f56c 2022-07-16 thomas if (qs != NULL && qs->action == BLOB) {
171 8a35f56c 2022-07-16 thomas error = got_get_repo_commits(c, 1);
172 8a35f56c 2022-07-16 thomas if (error)
173 8a35f56c 2022-07-16 thomas goto done;
174 8a35f56c 2022-07-16 thomas error = got_output_file_blob(c);
175 8a35f56c 2022-07-16 thomas if (error) {
176 8a35f56c 2022-07-16 thomas log_warnx("%s: %s", __func__, error->msg);
177 8a35f56c 2022-07-16 thomas goto err;
178 8a35f56c 2022-07-16 thomas }
179 8a35f56c 2022-07-16 thomas goto done;
180 43a44bce 2022-12-04 thomas }
181 43a44bce 2022-12-04 thomas
182 43a44bce 2022-12-04 thomas render:
183 43a44bce 2022-12-04 thomas error = gotweb_render_content_type(c, "text/html");
184 43a44bce 2022-12-04 thomas if (error) {
185 43a44bce 2022-12-04 thomas log_warnx("%s: %s", __func__, error->msg);
186 43a44bce 2022-12-04 thomas goto err;
187 8a35f56c 2022-07-16 thomas }
188 43a44bce 2022-12-04 thomas html = 1;
189 8a35f56c 2022-07-16 thomas
190 e7e5fa49 2022-12-30 thomas if (gotweb_render_header(c->tp) == -1)
191 8a35f56c 2022-07-16 thomas goto err;
192 8a35f56c 2022-07-16 thomas
193 8a35f56c 2022-07-16 thomas if (error2) {
194 8a35f56c 2022-07-16 thomas error = error2;
195 8a35f56c 2022-07-16 thomas goto err;
196 8a35f56c 2022-07-16 thomas }
197 8a35f56c 2022-07-16 thomas
198 8a35f56c 2022-07-16 thomas switch(qs->action) {
199 8a35f56c 2022-07-16 thomas case BLAME:
200 8a35f56c 2022-07-16 thomas error = gotweb_render_blame(c);
201 8a35f56c 2022-07-16 thomas if (error) {
202 8a35f56c 2022-07-16 thomas log_warnx("%s: %s", __func__, error->msg);
203 8a35f56c 2022-07-16 thomas goto err;
204 8a35f56c 2022-07-16 thomas }
205 8a35f56c 2022-07-16 thomas break;
206 8a35f56c 2022-07-16 thomas case BRIEFS:
207 e7e5fa49 2022-12-30 thomas if (gotweb_render_briefs(c->tp) == -1)
208 8a35f56c 2022-07-16 thomas goto err;
209 8a35f56c 2022-07-16 thomas break;
210 8a35f56c 2022-07-16 thomas case COMMITS:
211 8a35f56c 2022-07-16 thomas error = gotweb_render_commits(c);
212 8a35f56c 2022-07-16 thomas if (error) {
213 8a35f56c 2022-07-16 thomas log_warnx("%s: %s", __func__, error->msg);
214 8a35f56c 2022-07-16 thomas goto err;
215 8a35f56c 2022-07-16 thomas }
216 8a35f56c 2022-07-16 thomas break;
217 8a35f56c 2022-07-16 thomas case DIFF:
218 8a35f56c 2022-07-16 thomas error = gotweb_render_diff(c);
219 8a35f56c 2022-07-16 thomas if (error) {
220 8a35f56c 2022-07-16 thomas log_warnx("%s: %s", __func__, error->msg);
221 8a35f56c 2022-07-16 thomas goto err;
222 8a35f56c 2022-07-16 thomas }
223 8a35f56c 2022-07-16 thomas break;
224 8a35f56c 2022-07-16 thomas case INDEX:
225 8a35f56c 2022-07-16 thomas error = gotweb_render_index(c);
226 8a35f56c 2022-07-16 thomas if (error) {
227 8a35f56c 2022-07-16 thomas log_warnx("%s: %s", __func__, error->msg);
228 8a35f56c 2022-07-16 thomas goto err;
229 8a35f56c 2022-07-16 thomas }
230 8a35f56c 2022-07-16 thomas break;
231 8a35f56c 2022-07-16 thomas case SUMMARY:
232 8a35f56c 2022-07-16 thomas error = gotweb_render_summary(c);
233 8a35f56c 2022-07-16 thomas if (error) {
234 8a35f56c 2022-07-16 thomas log_warnx("%s: %s", __func__, error->msg);
235 8a35f56c 2022-07-16 thomas goto err;
236 8a35f56c 2022-07-16 thomas }
237 8a35f56c 2022-07-16 thomas break;
238 8a35f56c 2022-07-16 thomas case TAG:
239 8a35f56c 2022-07-16 thomas error = gotweb_render_tag(c);
240 8a35f56c 2022-07-16 thomas if (error) {
241 8a35f56c 2022-07-16 thomas log_warnx("%s: %s", __func__, error->msg);
242 8a35f56c 2022-07-16 thomas goto err;
243 8a35f56c 2022-07-16 thomas }
244 8a35f56c 2022-07-16 thomas break;
245 8a35f56c 2022-07-16 thomas case TAGS:
246 8a35f56c 2022-07-16 thomas error = gotweb_render_tags(c);
247 8a35f56c 2022-07-16 thomas if (error) {
248 8a35f56c 2022-07-16 thomas log_warnx("%s: %s", __func__, error->msg);
249 8a35f56c 2022-07-16 thomas goto err;
250 8a35f56c 2022-07-16 thomas }
251 8a35f56c 2022-07-16 thomas break;
252 8a35f56c 2022-07-16 thomas case TREE:
253 8a35f56c 2022-07-16 thomas error = gotweb_render_tree(c);
254 8a35f56c 2022-07-16 thomas if (error) {
255 8a35f56c 2022-07-16 thomas log_warnx("%s: %s", __func__, error->msg);
256 8a35f56c 2022-07-16 thomas goto err;
257 8a35f56c 2022-07-16 thomas }
258 8a35f56c 2022-07-16 thomas break;
259 8a35f56c 2022-07-16 thomas case ERR:
260 8a35f56c 2022-07-16 thomas default:
261 79393471 2022-08-27 thomas r = fcgi_printf(c, "<div id='err_content'>%s</div>\n",
262 79393471 2022-08-27 thomas "Erorr: Bad Querystring");
263 79393471 2022-08-27 thomas if (r == -1)
264 8a35f56c 2022-07-16 thomas goto err;
265 8a35f56c 2022-07-16 thomas break;
266 8a35f56c 2022-07-16 thomas }
267 8a35f56c 2022-07-16 thomas
268 8a35f56c 2022-07-16 thomas goto done;
269 8a35f56c 2022-07-16 thomas err:
270 79393471 2022-08-27 thomas if (html && fcgi_printf(c, "<div id='err_content'>") == -1)
271 8a35f56c 2022-07-16 thomas return;
272 a5f25a12 2022-10-31 thomas if (fcgi_printf(c, "\n%s", err) == -1)
273 8a35f56c 2022-07-16 thomas return;
274 8a35f56c 2022-07-16 thomas if (error) {
275 79393471 2022-08-27 thomas if (fcgi_printf(c, "%s", error->msg) == -1)
276 8a35f56c 2022-07-16 thomas return;
277 8a35f56c 2022-07-16 thomas } else {
278 79393471 2022-08-27 thomas if (fcgi_printf(c, "see daemon logs for details") == -1)
279 8a35f56c 2022-07-16 thomas return;
280 8a35f56c 2022-07-16 thomas }
281 79393471 2022-08-27 thomas if (html && fcgi_printf(c, "</div>\n") == -1)
282 8a35f56c 2022-07-16 thomas return;
283 8a35f56c 2022-07-16 thomas done:
284 8a35f56c 2022-07-16 thomas if (html && srv != NULL)
285 e7e5fa49 2022-12-30 thomas gotweb_render_footer(c->tp);
286 8a35f56c 2022-07-16 thomas }
287 8a35f56c 2022-07-16 thomas
288 8a35f56c 2022-07-16 thomas struct server *
289 3f0158b4 2022-08-30 thomas gotweb_get_server(uint8_t *server_name, uint8_t *subdomain)
290 8a35f56c 2022-07-16 thomas {
291 8a35f56c 2022-07-16 thomas struct server *srv = NULL;
292 8a35f56c 2022-07-16 thomas
293 3f0158b4 2022-08-30 thomas /* check against the server name first */
294 8a35f56c 2022-07-16 thomas if (strlen(server_name) > 0)
295 90d63d47 2022-08-16 thomas TAILQ_FOREACH(srv, &gotwebd_env->servers, entry)
296 8a35f56c 2022-07-16 thomas if (strcmp(srv->name, server_name) == 0)
297 8a35f56c 2022-07-16 thomas goto done;
298 8a35f56c 2022-07-16 thomas
299 3f0158b4 2022-08-30 thomas /* check against subdomain second */
300 8a35f56c 2022-07-16 thomas if (strlen(subdomain) > 0)
301 90d63d47 2022-08-16 thomas TAILQ_FOREACH(srv, &gotwebd_env->servers, entry)
302 8a35f56c 2022-07-16 thomas if (strcmp(srv->name, subdomain) == 0)
303 8a35f56c 2022-07-16 thomas goto done;
304 8a35f56c 2022-07-16 thomas
305 8a35f56c 2022-07-16 thomas /* if those fail, send first server */
306 90d63d47 2022-08-16 thomas TAILQ_FOREACH(srv, &gotwebd_env->servers, entry)
307 8a35f56c 2022-07-16 thomas if (srv != NULL)
308 8a35f56c 2022-07-16 thomas break;
309 8a35f56c 2022-07-16 thomas done:
310 8a35f56c 2022-07-16 thomas return srv;
311 8a35f56c 2022-07-16 thomas };
312 8a35f56c 2022-07-16 thomas
313 8a35f56c 2022-07-16 thomas const struct got_error *
314 8a35f56c 2022-07-16 thomas gotweb_init_transport(struct transport **t)
315 8a35f56c 2022-07-16 thomas {
316 8a35f56c 2022-07-16 thomas const struct got_error *error = NULL;
317 8a35f56c 2022-07-16 thomas
318 8a35f56c 2022-07-16 thomas *t = calloc(1, sizeof(**t));
319 8a35f56c 2022-07-16 thomas if (*t == NULL)
320 8a35f56c 2022-07-16 thomas return got_error_from_errno2("%s: calloc", __func__);
321 8a35f56c 2022-07-16 thomas
322 8a35f56c 2022-07-16 thomas TAILQ_INIT(&(*t)->repo_commits);
323 8a35f56c 2022-07-16 thomas TAILQ_INIT(&(*t)->repo_tags);
324 8a35f56c 2022-07-16 thomas
325 8a35f56c 2022-07-16 thomas (*t)->repo = NULL;
326 8a35f56c 2022-07-16 thomas (*t)->repo_dir = NULL;
327 8a35f56c 2022-07-16 thomas (*t)->qs = NULL;
328 8a35f56c 2022-07-16 thomas (*t)->next_id = NULL;
329 8a35f56c 2022-07-16 thomas (*t)->prev_id = NULL;
330 8a35f56c 2022-07-16 thomas (*t)->next_disp = 0;
331 8a35f56c 2022-07-16 thomas (*t)->prev_disp = 0;
332 8a35f56c 2022-07-16 thomas
333 8a35f56c 2022-07-16 thomas return error;
334 8a35f56c 2022-07-16 thomas }
335 8a35f56c 2022-07-16 thomas
336 8a35f56c 2022-07-16 thomas static const struct got_error *
337 8a35f56c 2022-07-16 thomas gotweb_init_querystring(struct querystring **qs)
338 8a35f56c 2022-07-16 thomas {
339 8a35f56c 2022-07-16 thomas const struct got_error *error = NULL;
340 8a35f56c 2022-07-16 thomas
341 8a35f56c 2022-07-16 thomas *qs = calloc(1, sizeof(**qs));
342 8a35f56c 2022-07-16 thomas if (*qs == NULL)
343 8a35f56c 2022-07-16 thomas return got_error_from_errno2("%s: calloc", __func__);
344 8a35f56c 2022-07-16 thomas
345 8a35f56c 2022-07-16 thomas (*qs)->headref = strdup("HEAD");
346 8a35f56c 2022-07-16 thomas if ((*qs)->headref == NULL) {
347 84630254 2022-09-02 thomas free(*qs);
348 84630254 2022-09-02 thomas *qs = NULL;
349 8a35f56c 2022-07-16 thomas return got_error_from_errno2("%s: strdup", __func__);
350 8a35f56c 2022-07-16 thomas }
351 84630254 2022-09-02 thomas
352 84630254 2022-09-02 thomas (*qs)->action = INDEX;
353 84630254 2022-09-02 thomas (*qs)->commit = NULL;
354 84630254 2022-09-02 thomas (*qs)->file = NULL;
355 84630254 2022-09-02 thomas (*qs)->folder = NULL;
356 8a35f56c 2022-07-16 thomas (*qs)->index_page = 0;
357 8a35f56c 2022-07-16 thomas (*qs)->index_page_str = NULL;
358 8a35f56c 2022-07-16 thomas (*qs)->path = NULL;
359 8a35f56c 2022-07-16 thomas
360 8a35f56c 2022-07-16 thomas return error;
361 8a35f56c 2022-07-16 thomas }
362 8a35f56c 2022-07-16 thomas
363 8a35f56c 2022-07-16 thomas static const struct got_error *
364 8a35f56c 2022-07-16 thomas gotweb_parse_querystring(struct querystring **qs, char *qst)
365 8a35f56c 2022-07-16 thomas {
366 8a35f56c 2022-07-16 thomas const struct got_error *error = NULL;
367 8a35f56c 2022-07-16 thomas char *tok1 = NULL, *tok1_pair = NULL, *tok1_end = NULL;
368 8a35f56c 2022-07-16 thomas char *tok2 = NULL, *tok2_pair = NULL, *tok2_end = NULL;
369 8a35f56c 2022-07-16 thomas
370 8a35f56c 2022-07-16 thomas if (qst == NULL)
371 8a35f56c 2022-07-16 thomas return error;
372 8a35f56c 2022-07-16 thomas
373 8a35f56c 2022-07-16 thomas tok1 = strdup(qst);
374 8a35f56c 2022-07-16 thomas if (tok1 == NULL)
375 8a35f56c 2022-07-16 thomas return got_error_from_errno2("%s: strdup", __func__);
376 8a35f56c 2022-07-16 thomas
377 8a35f56c 2022-07-16 thomas tok1_pair = tok1;
378 8a35f56c 2022-07-16 thomas tok1_end = tok1;
379 8a35f56c 2022-07-16 thomas
380 8a35f56c 2022-07-16 thomas while (tok1_pair != NULL) {
381 8a35f56c 2022-07-16 thomas strsep(&tok1_end, "&");
382 8a35f56c 2022-07-16 thomas
383 8a35f56c 2022-07-16 thomas tok2 = strdup(tok1_pair);
384 8a35f56c 2022-07-16 thomas if (tok2 == NULL) {
385 8a35f56c 2022-07-16 thomas free(tok1);
386 8a35f56c 2022-07-16 thomas return got_error_from_errno2("%s: strdup", __func__);
387 8a35f56c 2022-07-16 thomas }
388 8a35f56c 2022-07-16 thomas
389 8a35f56c 2022-07-16 thomas tok2_pair = tok2;
390 8a35f56c 2022-07-16 thomas tok2_end = tok2;
391 8a35f56c 2022-07-16 thomas
392 8a35f56c 2022-07-16 thomas while (tok2_pair != NULL) {
393 8a35f56c 2022-07-16 thomas strsep(&tok2_end, "=");
394 8a35f56c 2022-07-16 thomas if (tok2_end) {
395 8a35f56c 2022-07-16 thomas error = gotweb_assign_querystring(qs, tok2_pair,
396 8a35f56c 2022-07-16 thomas tok2_end);
397 8a35f56c 2022-07-16 thomas if (error)
398 8a35f56c 2022-07-16 thomas goto err;
399 8a35f56c 2022-07-16 thomas }
400 8a35f56c 2022-07-16 thomas tok2_pair = tok2_end;
401 8a35f56c 2022-07-16 thomas }
402 8a35f56c 2022-07-16 thomas free(tok2);
403 8a35f56c 2022-07-16 thomas tok1_pair = tok1_end;
404 8a35f56c 2022-07-16 thomas }
405 8a35f56c 2022-07-16 thomas free(tok1);
406 8a35f56c 2022-07-16 thomas return error;
407 8a35f56c 2022-07-16 thomas err:
408 8a35f56c 2022-07-16 thomas free(tok2);
409 8a35f56c 2022-07-16 thomas free(tok1);
410 8a35f56c 2022-07-16 thomas return error;
411 8a35f56c 2022-07-16 thomas }
412 8a35f56c 2022-07-16 thomas
413 2ac684a4 2022-09-03 thomas /*
414 2ac684a4 2022-09-03 thomas * Adapted from usr.sbin/httpd/httpd.c url_decode.
415 2ac684a4 2022-09-03 thomas */
416 8a35f56c 2022-07-16 thomas static const struct got_error *
417 2ac684a4 2022-09-03 thomas gotweb_urldecode(char *url)
418 2ac684a4 2022-09-03 thomas {
419 2ac684a4 2022-09-03 thomas char *p, *q;
420 2ac684a4 2022-09-03 thomas char hex[3];
421 2ac684a4 2022-09-03 thomas unsigned long x;
422 2ac684a4 2022-09-03 thomas
423 2ac684a4 2022-09-03 thomas hex[2] = '\0';
424 2ac684a4 2022-09-03 thomas p = q = url;
425 2ac684a4 2022-09-03 thomas
426 2ac684a4 2022-09-03 thomas while (*p != '\0') {
427 2ac684a4 2022-09-03 thomas switch (*p) {
428 2ac684a4 2022-09-03 thomas case '%':
429 2ac684a4 2022-09-03 thomas /* Encoding character is followed by two hex chars */
430 2ac684a4 2022-09-03 thomas if (!isxdigit((unsigned char)p[1]) ||
431 2ac684a4 2022-09-03 thomas !isxdigit((unsigned char)p[2]) ||
432 2ac684a4 2022-09-03 thomas (p[1] == '0' && p[2] == '0'))
433 2ac684a4 2022-09-03 thomas return got_error(GOT_ERR_BAD_QUERYSTRING);
434 2ac684a4 2022-09-03 thomas
435 2ac684a4 2022-09-03 thomas hex[0] = p[1];
436 2ac684a4 2022-09-03 thomas hex[1] = p[2];
437 2ac684a4 2022-09-03 thomas
438 2ac684a4 2022-09-03 thomas /*
439 2ac684a4 2022-09-03 thomas * We don't have to validate "hex" because it is
440 2ac684a4 2022-09-03 thomas * guaranteed to include two hex chars followed by nul.
441 2ac684a4 2022-09-03 thomas */
442 2ac684a4 2022-09-03 thomas x = strtoul(hex, NULL, 16);
443 2ac684a4 2022-09-03 thomas *q = (char)x;
444 2ac684a4 2022-09-03 thomas p += 2;
445 2ac684a4 2022-09-03 thomas break;
446 2ac684a4 2022-09-03 thomas default:
447 2ac684a4 2022-09-03 thomas *q = *p;
448 2ac684a4 2022-09-03 thomas break;
449 2ac684a4 2022-09-03 thomas }
450 2ac684a4 2022-09-03 thomas p++;
451 2ac684a4 2022-09-03 thomas q++;
452 2ac684a4 2022-09-03 thomas }
453 2ac684a4 2022-09-03 thomas *q = '\0';
454 2ac684a4 2022-09-03 thomas
455 2ac684a4 2022-09-03 thomas return NULL;
456 2ac684a4 2022-09-03 thomas }
457 2ac684a4 2022-09-03 thomas
458 2ac684a4 2022-09-03 thomas static const struct got_error *
459 8a35f56c 2022-07-16 thomas gotweb_assign_querystring(struct querystring **qs, char *key, char *value)
460 8a35f56c 2022-07-16 thomas {
461 8a35f56c 2022-07-16 thomas const struct got_error *error = NULL;
462 8a35f56c 2022-07-16 thomas const char *errstr;
463 8a35f56c 2022-07-16 thomas int a_cnt, el_cnt;
464 8a35f56c 2022-07-16 thomas
465 2ac684a4 2022-09-03 thomas error = gotweb_urldecode(value);
466 2ac684a4 2022-09-03 thomas if (error)
467 2ac684a4 2022-09-03 thomas return error;
468 2ac684a4 2022-09-03 thomas
469 8a35f56c 2022-07-16 thomas for (el_cnt = 0; el_cnt < QSELEM__MAX; el_cnt++) {
470 8a35f56c 2022-07-16 thomas if (strcmp(key, querystring_keys[el_cnt].name) != 0)
471 8a35f56c 2022-07-16 thomas continue;
472 8a35f56c 2022-07-16 thomas
473 8a35f56c 2022-07-16 thomas switch (querystring_keys[el_cnt].element) {
474 8a35f56c 2022-07-16 thomas case ACTION:
475 8a35f56c 2022-07-16 thomas for (a_cnt = 0; a_cnt < ACTIONS__MAX; a_cnt++) {
476 8a35f56c 2022-07-16 thomas if (strcmp(value, action_keys[a_cnt].name) != 0)
477 8a35f56c 2022-07-16 thomas continue;
478 8a35f56c 2022-07-16 thomas else if (strcmp(value,
479 8a35f56c 2022-07-16 thomas action_keys[a_cnt].name) == 0){
480 8a35f56c 2022-07-16 thomas (*qs)->action =
481 8a35f56c 2022-07-16 thomas action_keys[a_cnt].action;
482 8a35f56c 2022-07-16 thomas goto qa_found;
483 8a35f56c 2022-07-16 thomas }
484 8a35f56c 2022-07-16 thomas }
485 8a35f56c 2022-07-16 thomas (*qs)->action = ERR;
486 8a35f56c 2022-07-16 thomas qa_found:
487 8a35f56c 2022-07-16 thomas break;
488 8a35f56c 2022-07-16 thomas case COMMIT:
489 8a35f56c 2022-07-16 thomas (*qs)->commit = strdup(value);
490 8a35f56c 2022-07-16 thomas if ((*qs)->commit == NULL) {
491 8a35f56c 2022-07-16 thomas error = got_error_from_errno2("%s: strdup",
492 8a35f56c 2022-07-16 thomas __func__);
493 8a35f56c 2022-07-16 thomas goto done;
494 8a35f56c 2022-07-16 thomas }
495 8a35f56c 2022-07-16 thomas break;
496 8a35f56c 2022-07-16 thomas case RFILE:
497 8a35f56c 2022-07-16 thomas (*qs)->file = strdup(value);
498 8a35f56c 2022-07-16 thomas if ((*qs)->file == NULL) {
499 8a35f56c 2022-07-16 thomas error = got_error_from_errno2("%s: strdup",
500 8a35f56c 2022-07-16 thomas __func__);
501 8a35f56c 2022-07-16 thomas goto done;
502 8a35f56c 2022-07-16 thomas }
503 8a35f56c 2022-07-16 thomas break;
504 8a35f56c 2022-07-16 thomas case FOLDER:
505 8a35f56c 2022-07-16 thomas (*qs)->folder = strdup(value);
506 8a35f56c 2022-07-16 thomas if ((*qs)->folder == NULL) {
507 8a35f56c 2022-07-16 thomas error = got_error_from_errno2("%s: strdup",
508 8a35f56c 2022-07-16 thomas __func__);
509 8a35f56c 2022-07-16 thomas goto done;
510 8a35f56c 2022-07-16 thomas }
511 8a35f56c 2022-07-16 thomas break;
512 8a35f56c 2022-07-16 thomas case HEADREF:
513 b0764984 2022-09-02 thomas free((*qs)->headref);
514 8a35f56c 2022-07-16 thomas (*qs)->headref = strdup(value);
515 8a35f56c 2022-07-16 thomas if ((*qs)->headref == NULL) {
516 8a35f56c 2022-07-16 thomas error = got_error_from_errno2("%s: strdup",
517 8a35f56c 2022-07-16 thomas __func__);
518 8a35f56c 2022-07-16 thomas goto done;
519 8a35f56c 2022-07-16 thomas }
520 8a35f56c 2022-07-16 thomas break;
521 8a35f56c 2022-07-16 thomas case INDEX_PAGE:
522 8a35f56c 2022-07-16 thomas if (strlen(value) == 0)
523 8a35f56c 2022-07-16 thomas break;
524 8a35f56c 2022-07-16 thomas (*qs)->index_page_str = strdup(value);
525 8a35f56c 2022-07-16 thomas if ((*qs)->index_page_str == NULL) {
526 8a35f56c 2022-07-16 thomas error = got_error_from_errno2("%s: strdup",
527 8a35f56c 2022-07-16 thomas __func__);
528 8a35f56c 2022-07-16 thomas goto done;
529 8a35f56c 2022-07-16 thomas }
530 8a35f56c 2022-07-16 thomas (*qs)->index_page = strtonum(value, INT64_MIN,
531 8a35f56c 2022-07-16 thomas INT64_MAX, &errstr);
532 8a35f56c 2022-07-16 thomas if (errstr) {
533 8a35f56c 2022-07-16 thomas error = got_error_from_errno3("%s: strtonum %s",
534 8a35f56c 2022-07-16 thomas __func__, errstr);
535 8a35f56c 2022-07-16 thomas goto done;
536 8a35f56c 2022-07-16 thomas }
537 8a35f56c 2022-07-16 thomas if ((*qs)->index_page < 0) {
538 8a35f56c 2022-07-16 thomas (*qs)->index_page = 0;
539 8a35f56c 2022-07-16 thomas sprintf((*qs)->index_page_str, "%d", 0);
540 8a35f56c 2022-07-16 thomas }
541 8a35f56c 2022-07-16 thomas break;
542 8a35f56c 2022-07-16 thomas case PATH:
543 8a35f56c 2022-07-16 thomas (*qs)->path = strdup(value);
544 8a35f56c 2022-07-16 thomas if ((*qs)->path == NULL) {
545 8a35f56c 2022-07-16 thomas error = got_error_from_errno2("%s: strdup",
546 8a35f56c 2022-07-16 thomas __func__);
547 8a35f56c 2022-07-16 thomas goto done;
548 8a35f56c 2022-07-16 thomas }
549 8a35f56c 2022-07-16 thomas break;
550 8a35f56c 2022-07-16 thomas case PAGE:
551 8a35f56c 2022-07-16 thomas if (strlen(value) == 0)
552 8a35f56c 2022-07-16 thomas break;
553 8a35f56c 2022-07-16 thomas (*qs)->page_str = strdup(value);
554 8a35f56c 2022-07-16 thomas if ((*qs)->page_str == NULL) {
555 8a35f56c 2022-07-16 thomas error = got_error_from_errno2("%s: strdup",
556 8a35f56c 2022-07-16 thomas __func__);
557 8a35f56c 2022-07-16 thomas goto done;
558 8a35f56c 2022-07-16 thomas }
559 8a35f56c 2022-07-16 thomas (*qs)->page = strtonum(value, INT64_MIN,
560 8a35f56c 2022-07-16 thomas INT64_MAX, &errstr);
561 8a35f56c 2022-07-16 thomas if (errstr) {
562 8a35f56c 2022-07-16 thomas error = got_error_from_errno3("%s: strtonum %s",
563 8a35f56c 2022-07-16 thomas __func__, errstr);
564 8a35f56c 2022-07-16 thomas goto done;
565 8a35f56c 2022-07-16 thomas }
566 8a35f56c 2022-07-16 thomas if ((*qs)->page < 0) {
567 8a35f56c 2022-07-16 thomas (*qs)->page = 0;
568 8a35f56c 2022-07-16 thomas sprintf((*qs)->page_str, "%d", 0);
569 8a35f56c 2022-07-16 thomas }
570 8a35f56c 2022-07-16 thomas break;
571 8a35f56c 2022-07-16 thomas default:
572 8a35f56c 2022-07-16 thomas break;
573 8a35f56c 2022-07-16 thomas }
574 8a35f56c 2022-07-16 thomas }
575 8a35f56c 2022-07-16 thomas done:
576 8a35f56c 2022-07-16 thomas return error;
577 8a35f56c 2022-07-16 thomas }
578 8a35f56c 2022-07-16 thomas
579 8a35f56c 2022-07-16 thomas void
580 8a35f56c 2022-07-16 thomas gotweb_free_repo_tag(struct repo_tag *rt)
581 8a35f56c 2022-07-16 thomas {
582 8a35f56c 2022-07-16 thomas if (rt != NULL) {
583 8a35f56c 2022-07-16 thomas free(rt->commit_id);
584 217813df 2022-09-02 thomas free(rt->tag_name);
585 217813df 2022-09-02 thomas free(rt->tag_commit);
586 217813df 2022-09-02 thomas free(rt->commit_msg);
587 8a35f56c 2022-07-16 thomas free(rt->tagger);
588 8a35f56c 2022-07-16 thomas }
589 8a35f56c 2022-07-16 thomas free(rt);
590 8a35f56c 2022-07-16 thomas }
591 8a35f56c 2022-07-16 thomas
592 8a35f56c 2022-07-16 thomas void
593 8a35f56c 2022-07-16 thomas gotweb_free_repo_commit(struct repo_commit *rc)
594 8a35f56c 2022-07-16 thomas {
595 8a35f56c 2022-07-16 thomas if (rc != NULL) {
596 8a35f56c 2022-07-16 thomas free(rc->path);
597 8a35f56c 2022-07-16 thomas free(rc->refs_str);
598 8a35f56c 2022-07-16 thomas free(rc->commit_id);
599 8a35f56c 2022-07-16 thomas free(rc->parent_id);
600 8a35f56c 2022-07-16 thomas free(rc->tree_id);
601 8a35f56c 2022-07-16 thomas free(rc->author);
602 8a35f56c 2022-07-16 thomas free(rc->committer);
603 8a35f56c 2022-07-16 thomas free(rc->commit_msg);
604 8a35f56c 2022-07-16 thomas }
605 8a35f56c 2022-07-16 thomas free(rc);
606 8a35f56c 2022-07-16 thomas }
607 8a35f56c 2022-07-16 thomas
608 8a35f56c 2022-07-16 thomas static void
609 8a35f56c 2022-07-16 thomas gotweb_free_querystring(struct querystring *qs)
610 8a35f56c 2022-07-16 thomas {
611 8a35f56c 2022-07-16 thomas if (qs != NULL) {
612 8a35f56c 2022-07-16 thomas free(qs->commit);
613 8a35f56c 2022-07-16 thomas free(qs->file);
614 8a35f56c 2022-07-16 thomas free(qs->folder);
615 8a35f56c 2022-07-16 thomas free(qs->headref);
616 8a35f56c 2022-07-16 thomas free(qs->index_page_str);
617 8a35f56c 2022-07-16 thomas free(qs->path);
618 8a35f56c 2022-07-16 thomas free(qs->page_str);
619 8a35f56c 2022-07-16 thomas }
620 8a35f56c 2022-07-16 thomas free(qs);
621 8a35f56c 2022-07-16 thomas }
622 8a35f56c 2022-07-16 thomas
623 8a35f56c 2022-07-16 thomas static void
624 8a35f56c 2022-07-16 thomas gotweb_free_repo_dir(struct repo_dir *repo_dir)
625 8a35f56c 2022-07-16 thomas {
626 8a35f56c 2022-07-16 thomas if (repo_dir != NULL) {
627 8a35f56c 2022-07-16 thomas free(repo_dir->name);
628 8a35f56c 2022-07-16 thomas free(repo_dir->owner);
629 8a35f56c 2022-07-16 thomas free(repo_dir->description);
630 8a35f56c 2022-07-16 thomas free(repo_dir->url);
631 8a35f56c 2022-07-16 thomas free(repo_dir->age);
632 8a35f56c 2022-07-16 thomas free(repo_dir->path);
633 8a35f56c 2022-07-16 thomas }
634 8a35f56c 2022-07-16 thomas free(repo_dir);
635 8a35f56c 2022-07-16 thomas }
636 8a35f56c 2022-07-16 thomas
637 8a35f56c 2022-07-16 thomas void
638 8a35f56c 2022-07-16 thomas gotweb_free_transport(struct transport *t)
639 8a35f56c 2022-07-16 thomas {
640 8a35f56c 2022-07-16 thomas struct repo_commit *rc = NULL, *trc = NULL;
641 8a35f56c 2022-07-16 thomas struct repo_tag *rt = NULL, *trt = NULL;
642 8a35f56c 2022-07-16 thomas
643 8a35f56c 2022-07-16 thomas TAILQ_FOREACH_SAFE(rc, &t->repo_commits, entry, trc) {
644 8a35f56c 2022-07-16 thomas TAILQ_REMOVE(&t->repo_commits, rc, entry);
645 8a35f56c 2022-07-16 thomas gotweb_free_repo_commit(rc);
646 8a35f56c 2022-07-16 thomas }
647 8a35f56c 2022-07-16 thomas TAILQ_FOREACH_SAFE(rt, &t->repo_tags, entry, trt) {
648 8a35f56c 2022-07-16 thomas TAILQ_REMOVE(&t->repo_tags, rt, entry);
649 8a35f56c 2022-07-16 thomas gotweb_free_repo_tag(rt);
650 8a35f56c 2022-07-16 thomas }
651 8a35f56c 2022-07-16 thomas gotweb_free_repo_dir(t->repo_dir);
652 8a35f56c 2022-07-16 thomas gotweb_free_querystring(t->qs);
653 6b42af1e 2022-09-02 thomas free(t->next_id);
654 6b42af1e 2022-09-02 thomas free(t->prev_id);
655 8a35f56c 2022-07-16 thomas free(t);
656 8a35f56c 2022-07-16 thomas }
657 8a35f56c 2022-07-16 thomas
658 8a35f56c 2022-07-16 thomas const struct got_error *
659 8a35f56c 2022-07-16 thomas gotweb_render_content_type(struct request *c, const uint8_t *type)
660 8a35f56c 2022-07-16 thomas {
661 0b75e088 2022-08-27 thomas const char *csp = "default-src 'self'; script-src 'none'; "
662 0b75e088 2022-08-27 thomas "object-src 'none';";
663 0b75e088 2022-08-27 thomas
664 0b75e088 2022-08-27 thomas fcgi_printf(c,
665 0b75e088 2022-08-27 thomas "Content-Security-Policy: %s\r\n"
666 0b75e088 2022-08-27 thomas "Content-Type: %s\r\n\r\n",
667 0b75e088 2022-08-27 thomas csp, type);
668 79393471 2022-08-27 thomas return NULL;
669 8a35f56c 2022-07-16 thomas }
670 8a35f56c 2022-07-16 thomas
671 8a35f56c 2022-07-16 thomas const struct got_error *
672 8a35f56c 2022-07-16 thomas gotweb_render_content_type_file(struct request *c, const uint8_t *type,
673 8a35f56c 2022-07-16 thomas char *file)
674 8a35f56c 2022-07-16 thomas {
675 79393471 2022-08-27 thomas fcgi_printf(c, "Content-type: %s\r\n"
676 8a35f56c 2022-07-16 thomas "Content-disposition: attachment; filename=%s\r\n\r\n",
677 79393471 2022-08-27 thomas type, file);
678 79393471 2022-08-27 thomas return NULL;
679 8a35f56c 2022-07-16 thomas }
680 8a35f56c 2022-07-16 thomas
681 e7e5fa49 2022-12-30 thomas const struct got_error *
682 8a35f56c 2022-07-16 thomas gotweb_render_navs(struct request *c)
683 8a35f56c 2022-07-16 thomas {
684 8a35f56c 2022-07-16 thomas const struct got_error *error = NULL;
685 8a35f56c 2022-07-16 thomas struct transport *t = c->t;
686 8a35f56c 2022-07-16 thomas struct querystring *qs = t->qs;
687 8a35f56c 2022-07-16 thomas struct server *srv = c->srv;
688 55144267 2022-09-07 thomas int r;
689 8a35f56c 2022-07-16 thomas
690 79393471 2022-08-27 thomas r = fcgi_printf(c, "<div id='np_wrapper'>\n<div id='nav_prev'>\n");
691 79393471 2022-08-27 thomas if (r == -1)
692 8a35f56c 2022-07-16 thomas goto done;
693 8a35f56c 2022-07-16 thomas
694 8a35f56c 2022-07-16 thomas switch(qs->action) {
695 8a35f56c 2022-07-16 thomas case INDEX:
696 8a35f56c 2022-07-16 thomas if (qs->index_page > 0) {
697 55144267 2022-09-07 thomas struct gotweb_url url = {
698 55144267 2022-09-07 thomas .action = -1,
699 55144267 2022-09-07 thomas .index_page = qs->index_page - 1,
700 55144267 2022-09-07 thomas .page = -1,
701 55144267 2022-09-07 thomas };
702 55144267 2022-09-07 thomas
703 55144267 2022-09-07 thomas r = gotweb_link(c, &url, "Previous");
704 8a35f56c 2022-07-16 thomas }
705 8a35f56c 2022-07-16 thomas break;
706 8a35f56c 2022-07-16 thomas case BRIEFS:
707 8a35f56c 2022-07-16 thomas if (t->prev_id && qs->commit != NULL &&
708 8a35f56c 2022-07-16 thomas strcmp(qs->commit, t->prev_id) != 0) {
709 55144267 2022-09-07 thomas struct gotweb_url url = {
710 55144267 2022-09-07 thomas .action = BRIEFS,
711 55144267 2022-09-07 thomas .index_page = -1,
712 55144267 2022-09-07 thomas .page = qs->page - 1,
713 55144267 2022-09-07 thomas .path = qs->path,
714 55144267 2022-09-07 thomas .commit = t->prev_id,
715 55144267 2022-09-07 thomas .headref = qs->headref,
716 55144267 2022-09-07 thomas };
717 55144267 2022-09-07 thomas
718 55144267 2022-09-07 thomas r = gotweb_link(c, &url, "Previous");
719 8a35f56c 2022-07-16 thomas }
720 8a35f56c 2022-07-16 thomas break;
721 8a35f56c 2022-07-16 thomas case COMMITS:
722 8a35f56c 2022-07-16 thomas if (t->prev_id && qs->commit != NULL &&
723 8a35f56c 2022-07-16 thomas strcmp(qs->commit, t->prev_id) != 0) {
724 55144267 2022-09-07 thomas struct gotweb_url url = {
725 55144267 2022-09-07 thomas .action = COMMIT,
726 55144267 2022-09-07 thomas .index_page = -1,
727 55144267 2022-09-07 thomas .page = qs->page - 1,
728 55144267 2022-09-07 thomas .path = qs->path,
729 55144267 2022-09-07 thomas .commit = t->prev_id,
730 55144267 2022-09-07 thomas .headref = qs->headref,
731 55144267 2022-09-07 thomas .folder = qs->folder,
732 55144267 2022-09-07 thomas .file = qs->file,
733 55144267 2022-09-07 thomas };
734 55144267 2022-09-07 thomas
735 55144267 2022-09-07 thomas r = gotweb_link(c, &url, "Previous");
736 8a35f56c 2022-07-16 thomas }
737 8a35f56c 2022-07-16 thomas break;
738 8a35f56c 2022-07-16 thomas case TAGS:
739 8a35f56c 2022-07-16 thomas if (t->prev_id && qs->commit != NULL &&
740 8a35f56c 2022-07-16 thomas strcmp(qs->commit, t->prev_id) != 0) {
741 55144267 2022-09-07 thomas struct gotweb_url url = {
742 55144267 2022-09-07 thomas .action = TAGS,
743 55144267 2022-09-07 thomas .index_page = -1,
744 55144267 2022-09-07 thomas .page = qs->page - 1,
745 55144267 2022-09-07 thomas .path = qs->path,
746 55144267 2022-09-07 thomas .commit = t->prev_id,
747 55144267 2022-09-07 thomas .headref = qs->headref,
748 55144267 2022-09-07 thomas };
749 55144267 2022-09-07 thomas
750 55144267 2022-09-07 thomas r = gotweb_link(c, &url, "Previous");
751 8a35f56c 2022-07-16 thomas }
752 8a35f56c 2022-07-16 thomas break;
753 8a35f56c 2022-07-16 thomas }
754 8a35f56c 2022-07-16 thomas
755 55144267 2022-09-07 thomas if (r == -1)
756 55144267 2022-09-07 thomas goto done;
757 79393471 2022-08-27 thomas
758 79393471 2022-08-27 thomas r = fcgi_printf(c, "</div>\n" /* #nav_prev */
759 79393471 2022-08-27 thomas "<div id='nav_next'>");
760 79393471 2022-08-27 thomas if (r == -1)
761 8a35f56c 2022-07-16 thomas goto done;
762 8a35f56c 2022-07-16 thomas
763 8a35f56c 2022-07-16 thomas switch(qs->action) {
764 8a35f56c 2022-07-16 thomas case INDEX:
765 8a35f56c 2022-07-16 thomas if (t->next_disp == srv->max_repos_display &&
766 8a35f56c 2022-07-16 thomas t->repos_total != (qs->index_page + 1) *
767 8a35f56c 2022-07-16 thomas srv->max_repos_display) {
768 55144267 2022-09-07 thomas struct gotweb_url url = {
769 55144267 2022-09-07 thomas .action = -1,
770 55144267 2022-09-07 thomas .index_page = qs->index_page + 1,
771 55144267 2022-09-07 thomas .page = -1,
772 55144267 2022-09-07 thomas };
773 55144267 2022-09-07 thomas
774 55144267 2022-09-07 thomas r = gotweb_link(c, &url, "Next");
775 8a35f56c 2022-07-16 thomas }
776 8a35f56c 2022-07-16 thomas break;
777 8a35f56c 2022-07-16 thomas case BRIEFS:
778 8a35f56c 2022-07-16 thomas if (t->next_id) {
779 55144267 2022-09-07 thomas struct gotweb_url url = {
780 55144267 2022-09-07 thomas .action = BRIEFS,
781 55144267 2022-09-07 thomas .index_page = -1,
782 55144267 2022-09-07 thomas .page = qs->page + 1,
783 55144267 2022-09-07 thomas .path = qs->path,
784 55144267 2022-09-07 thomas .commit = t->next_id,
785 55144267 2022-09-07 thomas .headref = qs->headref,
786 55144267 2022-09-07 thomas };
787 55144267 2022-09-07 thomas
788 55144267 2022-09-07 thomas r = gotweb_link(c, &url, "Next");
789 8a35f56c 2022-07-16 thomas }
790 8a35f56c 2022-07-16 thomas break;
791 8a35f56c 2022-07-16 thomas case COMMITS:
792 8a35f56c 2022-07-16 thomas if (t->next_id) {
793 55144267 2022-09-07 thomas struct gotweb_url url = {
794 55144267 2022-09-07 thomas .action = COMMIT,
795 55144267 2022-09-07 thomas .index_page = -1,
796 55144267 2022-09-07 thomas .page = qs->page + 1,
797 55144267 2022-09-07 thomas .path = qs->path,
798 55144267 2022-09-07 thomas .commit = t->next_id,
799 55144267 2022-09-07 thomas .headref = qs->headref,
800 55144267 2022-09-07 thomas .folder = qs->folder,
801 55144267 2022-09-07 thomas .file = qs->file,
802 55144267 2022-09-07 thomas };
803 55144267 2022-09-07 thomas
804 55144267 2022-09-07 thomas r = gotweb_link(c, &url, "Next");
805 8a35f56c 2022-07-16 thomas }
806 8a35f56c 2022-07-16 thomas break;
807 8a35f56c 2022-07-16 thomas case TAGS:
808 8a35f56c 2022-07-16 thomas if (t->next_id) {
809 55144267 2022-09-07 thomas struct gotweb_url url = {
810 55144267 2022-09-07 thomas .action = TAGS,
811 55144267 2022-09-07 thomas .index_page = -1,
812 55144267 2022-09-07 thomas .page = qs->page + 1,
813 55144267 2022-09-07 thomas .path = qs->path,
814 55144267 2022-09-07 thomas .commit = t->next_id,
815 55144267 2022-09-07 thomas .headref = qs->headref,
816 55144267 2022-09-07 thomas };
817 55144267 2022-09-07 thomas
818 55144267 2022-09-07 thomas r = gotweb_link(c, &url, "Next");
819 8a35f56c 2022-07-16 thomas }
820 8a35f56c 2022-07-16 thomas break;
821 8a35f56c 2022-07-16 thomas }
822 55144267 2022-09-07 thomas if (r == -1)
823 55144267 2022-09-07 thomas goto done;
824 55144267 2022-09-07 thomas
825 79393471 2022-08-27 thomas fcgi_printf(c, "</div>\n"); /* #nav_next */
826 79393471 2022-08-27 thomas fcgi_printf(c, "</div>\n"); /* #np_wrapper */
827 8a35f56c 2022-07-16 thomas done:
828 8a35f56c 2022-07-16 thomas free(t->next_id);
829 8a35f56c 2022-07-16 thomas t->next_id = NULL;
830 8a35f56c 2022-07-16 thomas free(t->prev_id);
831 8a35f56c 2022-07-16 thomas t->prev_id = NULL;
832 8a35f56c 2022-07-16 thomas return error;
833 8a35f56c 2022-07-16 thomas }
834 8a35f56c 2022-07-16 thomas
835 8a35f56c 2022-07-16 thomas static const struct got_error *
836 8a35f56c 2022-07-16 thomas gotweb_render_index(struct request *c)
837 8a35f56c 2022-07-16 thomas {
838 8a35f56c 2022-07-16 thomas const struct got_error *error = NULL;
839 8a35f56c 2022-07-16 thomas struct server *srv = c->srv;
840 8a35f56c 2022-07-16 thomas struct transport *t = c->t;
841 8a35f56c 2022-07-16 thomas struct querystring *qs = t->qs;
842 8a35f56c 2022-07-16 thomas struct repo_dir *repo_dir = NULL;
843 8a35f56c 2022-07-16 thomas DIR *d;
844 f530ab0e 2022-09-02 thomas struct dirent **sd_dent = NULL;
845 8a35f56c 2022-07-16 thomas unsigned int d_cnt, d_i, d_disp = 0;
846 24240f6a 2022-11-23 thomas unsigned int d_skipped = 0;
847 e7e5fa49 2022-12-30 thomas int type;
848 8a35f56c 2022-07-16 thomas
849 8a35f56c 2022-07-16 thomas d = opendir(srv->repos_path);
850 8a35f56c 2022-07-16 thomas if (d == NULL) {
851 8a35f56c 2022-07-16 thomas error = got_error_from_errno2("opendir", srv->repos_path);
852 8a35f56c 2022-07-16 thomas return error;
853 8a35f56c 2022-07-16 thomas }
854 8a35f56c 2022-07-16 thomas
855 8a35f56c 2022-07-16 thomas d_cnt = scandir(srv->repos_path, &sd_dent, NULL, alphasort);
856 8a35f56c 2022-07-16 thomas if (d_cnt == -1) {
857 f530ab0e 2022-09-02 thomas sd_dent = NULL;
858 8a35f56c 2022-07-16 thomas error = got_error_from_errno2("scandir", srv->repos_path);
859 8a35f56c 2022-07-16 thomas goto done;
860 8a35f56c 2022-07-16 thomas }
861 8a35f56c 2022-07-16 thomas
862 e7e5fa49 2022-12-30 thomas if (gotweb_render_repo_table_hdr(c->tp) == -1)
863 8a35f56c 2022-07-16 thomas goto done;
864 79393471 2022-08-27 thomas
865 8a35f56c 2022-07-16 thomas for (d_i = 0; d_i < d_cnt; d_i++) {
866 57e88d7c 2022-11-23 thomas if (srv->max_repos > 0 && t->prev_disp == srv->max_repos)
867 57e88d7c 2022-11-23 thomas break;
868 8a35f56c 2022-07-16 thomas
869 8a35f56c 2022-07-16 thomas if (strcmp(sd_dent[d_i]->d_name, ".") == 0 ||
870 24240f6a 2022-11-23 thomas strcmp(sd_dent[d_i]->d_name, "..") == 0) {
871 24240f6a 2022-11-23 thomas d_skipped++;
872 24240f6a 2022-11-23 thomas continue;
873 24240f6a 2022-11-23 thomas }
874 24240f6a 2022-11-23 thomas
875 24240f6a 2022-11-23 thomas error = got_path_dirent_type(&type, srv->repos_path,
876 24240f6a 2022-11-23 thomas sd_dent[d_i]);
877 24240f6a 2022-11-23 thomas if (error)
878 24240f6a 2022-11-23 thomas goto done;
879 24240f6a 2022-11-23 thomas if (type != DT_DIR) {
880 24240f6a 2022-11-23 thomas d_skipped++;
881 8a35f56c 2022-07-16 thomas continue;
882 24240f6a 2022-11-23 thomas }
883 8a35f56c 2022-07-16 thomas
884 8a35f56c 2022-07-16 thomas if (qs->index_page > 0 && (qs->index_page *
885 8a35f56c 2022-07-16 thomas srv->max_repos_display) > t->prev_disp) {
886 8a35f56c 2022-07-16 thomas t->prev_disp++;
887 8a35f56c 2022-07-16 thomas continue;
888 8a35f56c 2022-07-16 thomas }
889 8a35f56c 2022-07-16 thomas
890 8a35f56c 2022-07-16 thomas error = gotweb_init_repo_dir(&repo_dir, sd_dent[d_i]->d_name);
891 8a35f56c 2022-07-16 thomas if (error)
892 8a35f56c 2022-07-16 thomas goto done;
893 8a35f56c 2022-07-16 thomas
894 8a35f56c 2022-07-16 thomas error = gotweb_load_got_path(c, repo_dir);
895 8a35f56c 2022-07-16 thomas if (error && error->code == GOT_ERR_NOT_GIT_REPO) {
896 8a35f56c 2022-07-16 thomas error = NULL;
897 8a35f56c 2022-07-16 thomas gotweb_free_repo_dir(repo_dir);
898 8a35f56c 2022-07-16 thomas repo_dir = NULL;
899 24240f6a 2022-11-23 thomas d_skipped++;
900 8a35f56c 2022-07-16 thomas continue;
901 8a35f56c 2022-07-16 thomas }
902 24240f6a 2022-11-23 thomas if (error && error->code != GOT_ERR_LONELY_PACKIDX)
903 24240f6a 2022-11-23 thomas goto done;
904 24240f6a 2022-11-23 thomas
905 8a35f56c 2022-07-16 thomas d_disp++;
906 8a35f56c 2022-07-16 thomas t->prev_disp++;
907 8a35f56c 2022-07-16 thomas
908 e7e5fa49 2022-12-30 thomas if (gotweb_render_repo_fragment(c->tp, repo_dir) == -1)
909 55144267 2022-09-07 thomas goto done;
910 55144267 2022-09-07 thomas
911 8a35f56c 2022-07-16 thomas gotweb_free_repo_dir(repo_dir);
912 8a35f56c 2022-07-16 thomas repo_dir = NULL;
913 8a35f56c 2022-07-16 thomas t->next_disp++;
914 8a35f56c 2022-07-16 thomas if (d_disp == srv->max_repos_display)
915 8a35f56c 2022-07-16 thomas break;
916 8a35f56c 2022-07-16 thomas }
917 24240f6a 2022-11-23 thomas t->repos_total = d_cnt - d_skipped;
918 24240f6a 2022-11-23 thomas
919 8a35f56c 2022-07-16 thomas if (srv->max_repos_display == 0)
920 79393471 2022-08-27 thomas goto done;
921 8a35f56c 2022-07-16 thomas if (srv->max_repos > 0 && srv->max_repos < srv->max_repos_display)
922 79393471 2022-08-27 thomas goto done;
923 8a35f56c 2022-07-16 thomas if (t->repos_total <= srv->max_repos ||
924 8a35f56c 2022-07-16 thomas t->repos_total <= srv->max_repos_display)
925 79393471 2022-08-27 thomas goto done;
926 8a35f56c 2022-07-16 thomas
927 8a35f56c 2022-07-16 thomas error = gotweb_render_navs(c);
928 8a35f56c 2022-07-16 thomas if (error)
929 8a35f56c 2022-07-16 thomas goto done;
930 8a35f56c 2022-07-16 thomas done:
931 f530ab0e 2022-09-02 thomas if (sd_dent) {
932 f530ab0e 2022-09-02 thomas for (d_i = 0; d_i < d_cnt; d_i++)
933 f530ab0e 2022-09-02 thomas free(sd_dent[d_i]);
934 f530ab0e 2022-09-02 thomas free(sd_dent);
935 f530ab0e 2022-09-02 thomas }
936 8a35f56c 2022-07-16 thomas if (d != NULL && closedir(d) == EOF && error == NULL)
937 8a35f56c 2022-07-16 thomas error = got_error_from_errno("closedir");
938 8a35f56c 2022-07-16 thomas return error;
939 8a35f56c 2022-07-16 thomas }
940 8a35f56c 2022-07-16 thomas
941 8a35f56c 2022-07-16 thomas static const struct got_error *
942 8a35f56c 2022-07-16 thomas gotweb_render_blame(struct request *c)
943 8a35f56c 2022-07-16 thomas {
944 8a35f56c 2022-07-16 thomas const struct got_error *error = NULL;
945 8a35f56c 2022-07-16 thomas struct transport *t = c->t;
946 8a35f56c 2022-07-16 thomas struct repo_commit *rc = NULL;
947 255f4022 2022-08-27 thomas char *age = NULL, *msg = NULL;
948 79393471 2022-08-27 thomas int r;
949 8a35f56c 2022-07-16 thomas
950 8a35f56c 2022-07-16 thomas error = got_get_repo_commits(c, 1);
951 8a35f56c 2022-07-16 thomas if (error)
952 8a35f56c 2022-07-16 thomas return error;
953 8a35f56c 2022-07-16 thomas
954 8a35f56c 2022-07-16 thomas rc = TAILQ_FIRST(&t->repo_commits);
955 8a35f56c 2022-07-16 thomas
956 8a35f56c 2022-07-16 thomas error = gotweb_get_time_str(&age, rc->committer_time, TM_LONG);
957 255f4022 2022-08-27 thomas if (error)
958 255f4022 2022-08-27 thomas goto done;
959 255f4022 2022-08-27 thomas error = gotweb_escape_html(&msg, rc->commit_msg);
960 8a35f56c 2022-07-16 thomas if (error)
961 8a35f56c 2022-07-16 thomas goto done;
962 8a35f56c 2022-07-16 thomas
963 79393471 2022-08-27 thomas r = fcgi_printf(c, "<div id='blame_title_wrapper'>\n"
964 79393471 2022-08-27 thomas "<div id='blame_title'>Blame</div>\n"
965 79393471 2022-08-27 thomas "</div>\n" /* #blame_title_wrapper */
966 79393471 2022-08-27 thomas "<div id='blame_content'>\n"
967 79393471 2022-08-27 thomas "<div id='blame_header_wrapper'>\n"
968 79393471 2022-08-27 thomas "<div id='blame_header'>\n"
969 79393471 2022-08-27 thomas "<div class='header_age_title'>Date:</div>\n"
970 79393471 2022-08-27 thomas "<div class='header_age'>%s</div>\n"
971 79393471 2022-08-27 thomas "<div id='header_commit_msg_title'>Message:</div>\n"
972 79393471 2022-08-27 thomas "<div id='header_commit_msg'>%s</div>\n"
973 79393471 2022-08-27 thomas "</div>\n" /* #blame_header */
974 79393471 2022-08-27 thomas "</div>\n" /* #blame_header_wrapper */
975 79393471 2022-08-27 thomas "<div class='dotted_line'></div>\n"
976 79393471 2022-08-27 thomas "<div id='blame'>\n",
977 2ad628aa 2022-08-31 thomas age,
978 255f4022 2022-08-27 thomas msg);
979 79393471 2022-08-27 thomas if (r == -1)
980 8a35f56c 2022-07-16 thomas goto done;
981 8a35f56c 2022-07-16 thomas
982 8a35f56c 2022-07-16 thomas error = got_output_file_blame(c);
983 8a35f56c 2022-07-16 thomas if (error)
984 8a35f56c 2022-07-16 thomas goto done;
985 8a35f56c 2022-07-16 thomas
986 79393471 2022-08-27 thomas fcgi_printf(c, "</div>\n" /* #blame */
987 79393471 2022-08-27 thomas "</div>\n"); /* #blame_content */
988 8a35f56c 2022-07-16 thomas done:
989 8a35f56c 2022-07-16 thomas free(age);
990 255f4022 2022-08-27 thomas free(msg);
991 8a35f56c 2022-07-16 thomas return error;
992 8a35f56c 2022-07-16 thomas }
993 8a35f56c 2022-07-16 thomas
994 8a35f56c 2022-07-16 thomas static const struct got_error *
995 8a35f56c 2022-07-16 thomas gotweb_render_commits(struct request *c)
996 8a35f56c 2022-07-16 thomas {
997 8a35f56c 2022-07-16 thomas const struct got_error *error = NULL;
998 8a35f56c 2022-07-16 thomas struct repo_commit *rc = NULL;
999 8a35f56c 2022-07-16 thomas struct server *srv = c->srv;
1000 8a35f56c 2022-07-16 thomas struct transport *t = c->t;
1001 8a35f56c 2022-07-16 thomas struct repo_dir *repo_dir = t->repo_dir;
1002 255f4022 2022-08-27 thomas char *age = NULL, *author = NULL, *msg = NULL;
1003 79393471 2022-08-27 thomas int r;
1004 8a35f56c 2022-07-16 thomas
1005 79393471 2022-08-27 thomas r = fcgi_printf(c, "<div class='commits_title_wrapper'>\n"
1006 79393471 2022-08-27 thomas "<div class='commits_title'>Commits</div>\n"
1007 79393471 2022-08-27 thomas "</div>\n" /* .commits_title_wrapper */
1008 79393471 2022-08-27 thomas "<div class='commits_content'>\n");
1009 79393471 2022-08-27 thomas if (r == -1)
1010 8a35f56c 2022-07-16 thomas goto done;
1011 8a35f56c 2022-07-16 thomas
1012 8a35f56c 2022-07-16 thomas error = got_get_repo_commits(c, srv->max_commits_display);
1013 8a35f56c 2022-07-16 thomas if (error)
1014 8a35f56c 2022-07-16 thomas goto done;
1015 8a35f56c 2022-07-16 thomas
1016 8a35f56c 2022-07-16 thomas TAILQ_FOREACH(rc, &t->repo_commits, entry) {
1017 8a35f56c 2022-07-16 thomas error = gotweb_get_time_str(&age, rc->committer_time, TM_LONG);
1018 8a35f56c 2022-07-16 thomas if (error)
1019 8a35f56c 2022-07-16 thomas goto done;
1020 8a35f56c 2022-07-16 thomas error = gotweb_escape_html(&author, rc->author);
1021 8a35f56c 2022-07-16 thomas if (error)
1022 8a35f56c 2022-07-16 thomas goto done;
1023 255f4022 2022-08-27 thomas error = gotweb_escape_html(&msg, rc->commit_msg);
1024 255f4022 2022-08-27 thomas if (error)
1025 255f4022 2022-08-27 thomas goto done;
1026 8a35f56c 2022-07-16 thomas
1027 79393471 2022-08-27 thomas r = fcgi_printf(c, "<div class='commits_header_wrapper'>\n"
1028 79393471 2022-08-27 thomas "<div class='commits_header'>\n"
1029 79393471 2022-08-27 thomas "<div class='header_commit_title'>Commit:</div>\n"
1030 79393471 2022-08-27 thomas "<div class='header_commit'>%s</div>\n"
1031 79393471 2022-08-27 thomas "<div class='header_author_title'>Author:</div>\n"
1032 79393471 2022-08-27 thomas "<div class='header_author'>%s</div>\n"
1033 79393471 2022-08-27 thomas "<div class='header_age_title'>Date:</div>\n"
1034 79393471 2022-08-27 thomas "<div class='header_age'>%s</div>\n"
1035 79393471 2022-08-27 thomas "</div>\n" /* .commits_header */
1036 79393471 2022-08-27 thomas "</div>\n" /* .commits_header_wrapper */
1037 79393471 2022-08-27 thomas "<div class='dotted_line'></div>\n"
1038 79393471 2022-08-27 thomas "<div class='commit'>\n%s</div>\n",
1039 79393471 2022-08-27 thomas rc->commit_id,
1040 255f4022 2022-08-27 thomas author,
1041 2ad628aa 2022-08-31 thomas age,
1042 255f4022 2022-08-27 thomas msg);
1043 79393471 2022-08-27 thomas if (r == -1)
1044 8a35f56c 2022-07-16 thomas goto done;
1045 8a35f56c 2022-07-16 thomas
1046 55144267 2022-09-07 thomas if (fcgi_printf(c, "<div class='navs_wrapper'>\n"
1047 55144267 2022-09-07 thomas "<div class='navs'>") == -1)
1048 55144267 2022-09-07 thomas goto done;
1049 55144267 2022-09-07 thomas
1050 55144267 2022-09-07 thomas r = gotweb_link(c, &(struct gotweb_url){
1051 55144267 2022-09-07 thomas .action = DIFF,
1052 55144267 2022-09-07 thomas .index_page = -1,
1053 55144267 2022-09-07 thomas .page = -1,
1054 55144267 2022-09-07 thomas .path = repo_dir->name,
1055 55144267 2022-09-07 thomas .commit = rc->commit_id,
1056 55144267 2022-09-07 thomas }, "diff");
1057 1510f72d 2022-09-02 thomas if (r == -1)
1058 1510f72d 2022-09-02 thomas goto done;
1059 8a35f56c 2022-07-16 thomas
1060 55144267 2022-09-07 thomas if (fcgi_printf(c, " | ") == -1)
1061 55144267 2022-09-07 thomas goto done;
1062 55144267 2022-09-07 thomas
1063 55144267 2022-09-07 thomas r = gotweb_link(c, &(struct gotweb_url){
1064 55144267 2022-09-07 thomas .action = TREE,
1065 55144267 2022-09-07 thomas .index_page = -1,
1066 55144267 2022-09-07 thomas .page = -1,
1067 55144267 2022-09-07 thomas .path = repo_dir->name,
1068 55144267 2022-09-07 thomas .commit = rc->commit_id,
1069 55144267 2022-09-07 thomas }, "tree");
1070 55144267 2022-09-07 thomas if (r == -1)
1071 55144267 2022-09-07 thomas goto done;
1072 55144267 2022-09-07 thomas
1073 55144267 2022-09-07 thomas if (fcgi_printf(c, "</div>\n" /* .navs */
1074 55144267 2022-09-07 thomas "</div>\n" /* .navs_wrapper */
1075 55144267 2022-09-07 thomas "<div class='dotted_line'></div>\n") == -1)
1076 55144267 2022-09-07 thomas goto done;
1077 55144267 2022-09-07 thomas
1078 8a35f56c 2022-07-16 thomas free(age);
1079 8a35f56c 2022-07-16 thomas age = NULL;
1080 8a35f56c 2022-07-16 thomas free(author);
1081 8a35f56c 2022-07-16 thomas author = NULL;
1082 255f4022 2022-08-27 thomas free(msg);
1083 255f4022 2022-08-27 thomas msg = NULL;
1084 8a35f56c 2022-07-16 thomas }
1085 8a35f56c 2022-07-16 thomas
1086 8a35f56c 2022-07-16 thomas if (t->next_id || t->prev_id) {
1087 8a35f56c 2022-07-16 thomas error = gotweb_render_navs(c);
1088 8a35f56c 2022-07-16 thomas if (error)
1089 8a35f56c 2022-07-16 thomas goto done;
1090 8a35f56c 2022-07-16 thomas }
1091 79393471 2022-08-27 thomas fcgi_printf(c, "</div>\n"); /* .commits_content */
1092 8a35f56c 2022-07-16 thomas done:
1093 8a35f56c 2022-07-16 thomas free(age);
1094 255f4022 2022-08-27 thomas free(author);
1095 255f4022 2022-08-27 thomas free(msg);
1096 8a35f56c 2022-07-16 thomas return error;
1097 8a35f56c 2022-07-16 thomas }
1098 8a35f56c 2022-07-16 thomas
1099 8a35f56c 2022-07-16 thomas static const struct got_error *
1100 8a35f56c 2022-07-16 thomas gotweb_render_branches(struct request *c)
1101 8a35f56c 2022-07-16 thomas {
1102 8a35f56c 2022-07-16 thomas const struct got_error *error = NULL;
1103 8a35f56c 2022-07-16 thomas struct got_reflist_head refs;
1104 8a35f56c 2022-07-16 thomas struct got_reflist_entry *re;
1105 8a35f56c 2022-07-16 thomas struct transport *t = c->t;
1106 8a35f56c 2022-07-16 thomas struct querystring *qs = t->qs;
1107 8a35f56c 2022-07-16 thomas struct got_repository *repo = t->repo;
1108 55144267 2022-09-07 thomas char *escaped_refname = NULL;
1109 8a35f56c 2022-07-16 thomas char *age = NULL;
1110 79393471 2022-08-27 thomas int r;
1111 8a35f56c 2022-07-16 thomas
1112 8a35f56c 2022-07-16 thomas TAILQ_INIT(&refs);
1113 8a35f56c 2022-07-16 thomas
1114 8a35f56c 2022-07-16 thomas error = got_ref_list(&refs, repo, "refs/heads",
1115 8a35f56c 2022-07-16 thomas got_ref_cmp_by_name, NULL);
1116 8a35f56c 2022-07-16 thomas if (error)
1117 8a35f56c 2022-07-16 thomas goto done;
1118 8a35f56c 2022-07-16 thomas
1119 79393471 2022-08-27 thomas r = fcgi_printf(c, "<div id='branches_title_wrapper'>\n"
1120 79393471 2022-08-27 thomas "<div id='branches_title'>Branches</div>\n"
1121 79393471 2022-08-27 thomas "</div>\n" /* #branches_title_wrapper */
1122 79393471 2022-08-27 thomas "<div id='branches_content'>\n");
1123 79393471 2022-08-27 thomas if (r == -1)
1124 8a35f56c 2022-07-16 thomas goto done;
1125 8a35f56c 2022-07-16 thomas
1126 8a35f56c 2022-07-16 thomas TAILQ_FOREACH(re, &refs, entry) {
1127 255f4022 2022-08-27 thomas const char *refname = NULL;
1128 8a35f56c 2022-07-16 thomas
1129 8a35f56c 2022-07-16 thomas if (got_ref_is_symbolic(re->ref))
1130 8a35f56c 2022-07-16 thomas continue;
1131 8a35f56c 2022-07-16 thomas
1132 255f4022 2022-08-27 thomas refname = got_ref_get_name(re->ref);
1133 8a35f56c 2022-07-16 thomas if (refname == NULL) {
1134 8a35f56c 2022-07-16 thomas error = got_error_from_errno("strdup");
1135 8a35f56c 2022-07-16 thomas goto done;
1136 8a35f56c 2022-07-16 thomas }
1137 8a35f56c 2022-07-16 thomas if (strncmp(refname, "refs/heads/", 11) != 0)
1138 8a35f56c 2022-07-16 thomas continue;
1139 8a35f56c 2022-07-16 thomas
1140 6c7f10f7 2022-11-23 thomas error = got_get_repo_age(&age, c, refname, TM_DIFF);
1141 8a35f56c 2022-07-16 thomas if (error)
1142 8a35f56c 2022-07-16 thomas goto done;
1143 8a35f56c 2022-07-16 thomas
1144 8a35f56c 2022-07-16 thomas if (strncmp(refname, "refs/heads/", 11) == 0)
1145 8a35f56c 2022-07-16 thomas refname += 11;
1146 255f4022 2022-08-27 thomas error = gotweb_escape_html(&escaped_refname, refname);
1147 255f4022 2022-08-27 thomas if (error)
1148 255f4022 2022-08-27 thomas goto done;
1149 8a35f56c 2022-07-16 thomas
1150 79393471 2022-08-27 thomas r = fcgi_printf(c, "<div class='branches_wrapper'>\n"
1151 79393471 2022-08-27 thomas "<div class='branches_age'>%s</div>\n"
1152 79393471 2022-08-27 thomas "<div class='branches_space'>&nbsp;</div>\n"
1153 55144267 2022-09-07 thomas "<div class='branch'>", age);
1154 55144267 2022-09-07 thomas if (r == -1)
1155 55144267 2022-09-07 thomas goto done;
1156 55144267 2022-09-07 thomas
1157 55144267 2022-09-07 thomas r = gotweb_link(c, &(struct gotweb_url){
1158 55144267 2022-09-07 thomas .action = SUMMARY,
1159 55144267 2022-09-07 thomas .index_page = -1,
1160 55144267 2022-09-07 thomas .page = -1,
1161 55144267 2022-09-07 thomas .path = qs->path,
1162 55144267 2022-09-07 thomas .headref = refname,
1163 55144267 2022-09-07 thomas }, "%s", escaped_refname);
1164 55144267 2022-09-07 thomas if (r == -1)
1165 55144267 2022-09-07 thomas goto done;
1166 55144267 2022-09-07 thomas
1167 55144267 2022-09-07 thomas if (fcgi_printf(c, "</div>\n" /* .branch */
1168 79393471 2022-08-27 thomas "<div class='navs_wrapper'>\n"
1169 55144267 2022-09-07 thomas "<div class='navs'>") == -1)
1170 55144267 2022-09-07 thomas goto done;
1171 55144267 2022-09-07 thomas
1172 55144267 2022-09-07 thomas r = gotweb_link(c, &(struct gotweb_url){
1173 55144267 2022-09-07 thomas .action = SUMMARY,
1174 55144267 2022-09-07 thomas .index_page = -1,
1175 55144267 2022-09-07 thomas .page = -1,
1176 55144267 2022-09-07 thomas .path = qs->path,
1177 55144267 2022-09-07 thomas .headref = refname,
1178 55144267 2022-09-07 thomas }, "summary");
1179 55144267 2022-09-07 thomas if (r == -1)
1180 55144267 2022-09-07 thomas goto done;
1181 55144267 2022-09-07 thomas
1182 55144267 2022-09-07 thomas if (fcgi_printf(c, " | ") == -1)
1183 55144267 2022-09-07 thomas goto done;
1184 55144267 2022-09-07 thomas
1185 55144267 2022-09-07 thomas r = gotweb_link(c, &(struct gotweb_url){
1186 55144267 2022-09-07 thomas .action = BRIEFS,
1187 55144267 2022-09-07 thomas .index_page = -1,
1188 55144267 2022-09-07 thomas .page = -1,
1189 55144267 2022-09-07 thomas .path = qs->path,
1190 55144267 2022-09-07 thomas .headref = refname,
1191 55144267 2022-09-07 thomas }, "commit briefs");
1192 55144267 2022-09-07 thomas if (r == -1)
1193 55144267 2022-09-07 thomas goto done;
1194 55144267 2022-09-07 thomas
1195 55144267 2022-09-07 thomas if (fcgi_printf(c, " | ") == -1)
1196 55144267 2022-09-07 thomas goto done;
1197 55144267 2022-09-07 thomas
1198 55144267 2022-09-07 thomas r = gotweb_link(c, &(struct gotweb_url){
1199 55144267 2022-09-07 thomas .action = COMMITS,
1200 55144267 2022-09-07 thomas .index_page = -1,
1201 55144267 2022-09-07 thomas .page = -1,
1202 55144267 2022-09-07 thomas .path = qs->path,
1203 55144267 2022-09-07 thomas .headref = refname,
1204 55144267 2022-09-07 thomas }, "commits");
1205 55144267 2022-09-07 thomas if (r == -1)
1206 55144267 2022-09-07 thomas goto done;
1207 55144267 2022-09-07 thomas
1208 55144267 2022-09-07 thomas r = fcgi_printf(c, "</div>\n" /* .navs */
1209 55144267 2022-09-07 thomas "</div>\n" /* .navs_wrapper */
1210 79393471 2022-08-27 thomas "<div class='dotted_line'></div>\n"
1211 55144267 2022-09-07 thomas "</div>\n"); /* .branches_wrapper */
1212 79393471 2022-08-27 thomas if (r == -1)
1213 8a35f56c 2022-07-16 thomas goto done;
1214 8a35f56c 2022-07-16 thomas
1215 8a35f56c 2022-07-16 thomas free(age);
1216 8a35f56c 2022-07-16 thomas age = NULL;
1217 55144267 2022-09-07 thomas free(escaped_refname);
1218 55144267 2022-09-07 thomas escaped_refname = NULL;
1219 8a35f56c 2022-07-16 thomas }
1220 79393471 2022-08-27 thomas fcgi_printf(c, "</div>\n"); /* #branches_content */
1221 8a35f56c 2022-07-16 thomas done:
1222 f95e65a1 2022-09-02 thomas free(age);
1223 55144267 2022-09-07 thomas free(escaped_refname);
1224 f95e65a1 2022-09-02 thomas got_ref_list_free(&refs);
1225 8a35f56c 2022-07-16 thomas return error;
1226 8a35f56c 2022-07-16 thomas }
1227 8a35f56c 2022-07-16 thomas
1228 8a35f56c 2022-07-16 thomas static const struct got_error *
1229 8a35f56c 2022-07-16 thomas gotweb_render_tree(struct request *c)
1230 8a35f56c 2022-07-16 thomas {
1231 8a35f56c 2022-07-16 thomas const struct got_error *error = NULL;
1232 8a35f56c 2022-07-16 thomas struct transport *t = c->t;
1233 8a35f56c 2022-07-16 thomas struct repo_commit *rc = NULL;
1234 255f4022 2022-08-27 thomas char *age = NULL, *msg = NULL;
1235 79393471 2022-08-27 thomas int r;
1236 8a35f56c 2022-07-16 thomas
1237 8a35f56c 2022-07-16 thomas error = got_get_repo_commits(c, 1);
1238 8a35f56c 2022-07-16 thomas if (error)
1239 8a35f56c 2022-07-16 thomas return error;
1240 8a35f56c 2022-07-16 thomas
1241 8a35f56c 2022-07-16 thomas rc = TAILQ_FIRST(&t->repo_commits);
1242 8a35f56c 2022-07-16 thomas
1243 8a35f56c 2022-07-16 thomas error = gotweb_get_time_str(&age, rc->committer_time, TM_LONG);
1244 8a35f56c 2022-07-16 thomas if (error)
1245 8a35f56c 2022-07-16 thomas goto done;
1246 8a35f56c 2022-07-16 thomas
1247 255f4022 2022-08-27 thomas error = gotweb_escape_html(&msg, rc->commit_msg);
1248 255f4022 2022-08-27 thomas if (error)
1249 255f4022 2022-08-27 thomas goto done;
1250 255f4022 2022-08-27 thomas
1251 79393471 2022-08-27 thomas r = fcgi_printf(c, "<div id='tree_title_wrapper'>\n"
1252 79393471 2022-08-27 thomas "<div id='tree_title'>Tree</div>\n"
1253 79393471 2022-08-27 thomas "</div>\n" /* #tree_title_wrapper */
1254 79393471 2022-08-27 thomas "<div id='tree_content'>\n"
1255 79393471 2022-08-27 thomas "<div id='tree_header_wrapper'>\n"
1256 79393471 2022-08-27 thomas "<div id='tree_header'>\n"
1257 79393471 2022-08-27 thomas "<div id='header_tree_title'>Tree:</div>\n"
1258 79393471 2022-08-27 thomas "<div id='header_tree'>%s</div>\n"
1259 79393471 2022-08-27 thomas "<div class='header_age_title'>Date:</div>\n"
1260 79393471 2022-08-27 thomas "<div class='header_age'>%s</div>\n"
1261 79393471 2022-08-27 thomas "<div id='header_commit_msg_title'>Message:</div>\n"
1262 79393471 2022-08-27 thomas "<div id='header_commit_msg'>%s</div>\n"
1263 79393471 2022-08-27 thomas "</div>\n" /* #tree_header */
1264 79393471 2022-08-27 thomas "</div>\n" /* #tree_header_wrapper */
1265 79393471 2022-08-27 thomas "<div class='dotted_line'></div>\n"
1266 79393471 2022-08-27 thomas "<div id='tree'>\n",
1267 79393471 2022-08-27 thomas rc->tree_id,
1268 2ad628aa 2022-08-31 thomas age,
1269 255f4022 2022-08-27 thomas msg);
1270 79393471 2022-08-27 thomas if (r == -1)
1271 8a35f56c 2022-07-16 thomas goto done;
1272 8a35f56c 2022-07-16 thomas
1273 8a35f56c 2022-07-16 thomas error = got_output_repo_tree(c);
1274 8a35f56c 2022-07-16 thomas if (error)
1275 8a35f56c 2022-07-16 thomas goto done;
1276 8a35f56c 2022-07-16 thomas
1277 79393471 2022-08-27 thomas fcgi_printf(c, "</div>\n"); /* #tree */
1278 79393471 2022-08-27 thomas fcgi_printf(c, "</div>\n"); /* #tree_content */
1279 8a35f56c 2022-07-16 thomas done:
1280 2ad628aa 2022-08-31 thomas free(age);
1281 255f4022 2022-08-27 thomas free(msg);
1282 8a35f56c 2022-07-16 thomas return error;
1283 8a35f56c 2022-07-16 thomas }
1284 8a35f56c 2022-07-16 thomas
1285 8a35f56c 2022-07-16 thomas static const struct got_error *
1286 8a35f56c 2022-07-16 thomas gotweb_render_diff(struct request *c)
1287 8a35f56c 2022-07-16 thomas {
1288 8a35f56c 2022-07-16 thomas const struct got_error *error = NULL;
1289 8a35f56c 2022-07-16 thomas struct transport *t = c->t;
1290 8a35f56c 2022-07-16 thomas struct repo_commit *rc = NULL;
1291 255f4022 2022-08-27 thomas char *age = NULL, *author = NULL, *msg = NULL;
1292 79393471 2022-08-27 thomas int r;
1293 8a35f56c 2022-07-16 thomas
1294 8a35f56c 2022-07-16 thomas error = got_get_repo_commits(c, 1);
1295 8a35f56c 2022-07-16 thomas if (error)
1296 8a35f56c 2022-07-16 thomas return error;
1297 8a35f56c 2022-07-16 thomas
1298 8a35f56c 2022-07-16 thomas rc = TAILQ_FIRST(&t->repo_commits);
1299 8a35f56c 2022-07-16 thomas
1300 8a35f56c 2022-07-16 thomas error = gotweb_get_time_str(&age, rc->committer_time, TM_LONG);
1301 8a35f56c 2022-07-16 thomas if (error)
1302 8a35f56c 2022-07-16 thomas goto done;
1303 8a35f56c 2022-07-16 thomas error = gotweb_escape_html(&author, rc->author);
1304 8a35f56c 2022-07-16 thomas if (error)
1305 8a35f56c 2022-07-16 thomas goto done;
1306 255f4022 2022-08-27 thomas error = gotweb_escape_html(&msg, rc->commit_msg);
1307 255f4022 2022-08-27 thomas if (error)
1308 255f4022 2022-08-27 thomas goto done;
1309 8a35f56c 2022-07-16 thomas
1310 79393471 2022-08-27 thomas r = fcgi_printf(c, "<div id='diff_title_wrapper'>\n"
1311 79393471 2022-08-27 thomas "<div id='diff_title'>Commit Diff</div>\n"
1312 79393471 2022-08-27 thomas "</div>\n" /* #diff_title_wrapper */
1313 79393471 2022-08-27 thomas "<div id='diff_content'>\n"
1314 79393471 2022-08-27 thomas "<div id='diff_header_wrapper'>\n"
1315 79393471 2022-08-27 thomas "<div id='diff_header'>\n"
1316 79393471 2022-08-27 thomas "<div id='header_diff_title'>Diff:</div>\n"
1317 79393471 2022-08-27 thomas "<div id='header_diff'>%s<br />%s</div>\n"
1318 79393471 2022-08-27 thomas "<div class='header_commit_title'>Commit:</div>\n"
1319 79393471 2022-08-27 thomas "<div class='header_commit'>%s</div>\n"
1320 79393471 2022-08-27 thomas "<div id='header_tree_title'>Tree:</div>\n"
1321 79393471 2022-08-27 thomas "<div id='header_tree'>%s</div>\n"
1322 79393471 2022-08-27 thomas "<div class='header_author_title'>Author:</div>\n"
1323 79393471 2022-08-27 thomas "<div class='header_author'>%s</div>\n"
1324 79393471 2022-08-27 thomas "<div class='header_age_title'>Date:</div>\n"
1325 79393471 2022-08-27 thomas "<div class='header_age'>%s</div>\n"
1326 79393471 2022-08-27 thomas "<div id='header_commit_msg_title'>Message:</div>\n"
1327 79393471 2022-08-27 thomas "<div id='header_commit_msg'>%s</div>\n"
1328 79393471 2022-08-27 thomas "</div>\n" /* #diff_header */
1329 79393471 2022-08-27 thomas "</div>\n" /* #diff_header_wrapper */
1330 79393471 2022-08-27 thomas "<div class='dotted_line'></div>\n"
1331 79393471 2022-08-27 thomas "<div id='diff'>\n",
1332 79393471 2022-08-27 thomas rc->parent_id, rc->commit_id,
1333 79393471 2022-08-27 thomas rc->commit_id,
1334 79393471 2022-08-27 thomas rc->tree_id,
1335 255f4022 2022-08-27 thomas author,
1336 2ad628aa 2022-08-31 thomas age,
1337 255f4022 2022-08-27 thomas msg);
1338 79393471 2022-08-27 thomas if (r == -1)
1339 8a35f56c 2022-07-16 thomas goto done;
1340 8a35f56c 2022-07-16 thomas
1341 8a35f56c 2022-07-16 thomas error = got_output_repo_diff(c);
1342 8a35f56c 2022-07-16 thomas if (error)
1343 8a35f56c 2022-07-16 thomas goto done;
1344 8a35f56c 2022-07-16 thomas
1345 79393471 2022-08-27 thomas fcgi_printf(c, "</div>\n"); /* #diff */
1346 79393471 2022-08-27 thomas fcgi_printf(c, "</div>\n"); /* #diff_content */
1347 8a35f56c 2022-07-16 thomas done:
1348 8a35f56c 2022-07-16 thomas free(age);
1349 8a35f56c 2022-07-16 thomas free(author);
1350 255f4022 2022-08-27 thomas free(msg);
1351 8a35f56c 2022-07-16 thomas return error;
1352 8a35f56c 2022-07-16 thomas }
1353 8a35f56c 2022-07-16 thomas
1354 8a35f56c 2022-07-16 thomas static const struct got_error *
1355 8a35f56c 2022-07-16 thomas gotweb_render_summary(struct request *c)
1356 8a35f56c 2022-07-16 thomas {
1357 8a35f56c 2022-07-16 thomas const struct got_error *error = NULL;
1358 8a35f56c 2022-07-16 thomas struct transport *t = c->t;
1359 8a35f56c 2022-07-16 thomas struct server *srv = c->srv;
1360 79393471 2022-08-27 thomas int r;
1361 8a35f56c 2022-07-16 thomas
1362 79393471 2022-08-27 thomas if (fcgi_printf(c, "<div id='summary_wrapper'>\n") == -1)
1363 8a35f56c 2022-07-16 thomas goto done;
1364 8a35f56c 2022-07-16 thomas
1365 79393471 2022-08-27 thomas if (srv->show_repo_description) {
1366 79393471 2022-08-27 thomas r = fcgi_printf(c,
1367 79393471 2022-08-27 thomas "<div id='description_title'>Description:</div>\n"
1368 79393471 2022-08-27 thomas "<div id='description'>%s</div>\n",
1369 ddf2e5c2 2022-08-27 thomas t->repo_dir->description ? t->repo_dir->description : "");
1370 79393471 2022-08-27 thomas if (r == -1)
1371 79393471 2022-08-27 thomas goto done;
1372 79393471 2022-08-27 thomas }
1373 8a35f56c 2022-07-16 thomas
1374 79393471 2022-08-27 thomas if (srv->show_repo_owner) {
1375 79393471 2022-08-27 thomas r = fcgi_printf(c,
1376 79393471 2022-08-27 thomas "<div id='repo_owner_title'>Owner:</div>\n"
1377 79393471 2022-08-27 thomas "<div id='repo_owner'>%s</div>\n",
1378 ddf2e5c2 2022-08-27 thomas t->repo_dir->owner ? t->repo_dir->owner : "");
1379 79393471 2022-08-27 thomas if (r == -1)
1380 79393471 2022-08-27 thomas goto done;
1381 79393471 2022-08-27 thomas }
1382 8a35f56c 2022-07-16 thomas
1383 79393471 2022-08-27 thomas if (srv->show_repo_age) {
1384 79393471 2022-08-27 thomas r = fcgi_printf(c,
1385 79393471 2022-08-27 thomas "<div id='last_change_title'>Last Change:</div>\n"
1386 79393471 2022-08-27 thomas "<div id='last_change'>%s</div>\n",
1387 79393471 2022-08-27 thomas t->repo_dir->age);
1388 79393471 2022-08-27 thomas if (r == -1)
1389 79393471 2022-08-27 thomas goto done;
1390 79393471 2022-08-27 thomas }
1391 8a35f56c 2022-07-16 thomas
1392 79393471 2022-08-27 thomas if (srv->show_repo_cloneurl) {
1393 79393471 2022-08-27 thomas r = fcgi_printf(c,
1394 79393471 2022-08-27 thomas "<div id='cloneurl_title'>Clone URL:</div>\n"
1395 79393471 2022-08-27 thomas "<div id='cloneurl'>%s</div>\n",
1396 79393471 2022-08-27 thomas t->repo_dir->url ? t->repo_dir->url : "");
1397 79393471 2022-08-27 thomas if (r == -1)
1398 79393471 2022-08-27 thomas goto done;
1399 79393471 2022-08-27 thomas }
1400 8a35f56c 2022-07-16 thomas
1401 79393471 2022-08-27 thomas r = fcgi_printf(c, "</div>\n"); /* #summary_wrapper */
1402 79393471 2022-08-27 thomas if (r == -1)
1403 8a35f56c 2022-07-16 thomas goto done;
1404 8a35f56c 2022-07-16 thomas
1405 e7e5fa49 2022-12-30 thomas if (gotweb_render_briefs(c->tp) == -1)
1406 8a35f56c 2022-07-16 thomas goto done;
1407 8a35f56c 2022-07-16 thomas
1408 8a35f56c 2022-07-16 thomas error = gotweb_render_tags(c);
1409 8a35f56c 2022-07-16 thomas if (error) {
1410 8a35f56c 2022-07-16 thomas log_warnx("%s: %s", __func__, error->msg);
1411 8a35f56c 2022-07-16 thomas goto done;
1412 8a35f56c 2022-07-16 thomas }
1413 8a35f56c 2022-07-16 thomas
1414 8a35f56c 2022-07-16 thomas error = gotweb_render_branches(c);
1415 8a35f56c 2022-07-16 thomas if (error)
1416 8a35f56c 2022-07-16 thomas log_warnx("%s: %s", __func__, error->msg);
1417 8a35f56c 2022-07-16 thomas done:
1418 8a35f56c 2022-07-16 thomas return error;
1419 8a35f56c 2022-07-16 thomas }
1420 8a35f56c 2022-07-16 thomas
1421 8a35f56c 2022-07-16 thomas static const struct got_error *
1422 8a35f56c 2022-07-16 thomas gotweb_render_tag(struct request *c)
1423 8a35f56c 2022-07-16 thomas {
1424 8a35f56c 2022-07-16 thomas const struct got_error *error = NULL;
1425 8a35f56c 2022-07-16 thomas struct repo_tag *rt = NULL;
1426 8a35f56c 2022-07-16 thomas struct transport *t = c->t;
1427 255f4022 2022-08-27 thomas char *tagname = NULL, *age = NULL, *author = NULL, *msg = NULL;
1428 8a35f56c 2022-07-16 thomas
1429 8a35f56c 2022-07-16 thomas error = got_get_repo_tags(c, 1);
1430 8a35f56c 2022-07-16 thomas if (error)
1431 8a35f56c 2022-07-16 thomas goto done;
1432 8a35f56c 2022-07-16 thomas
1433 8a35f56c 2022-07-16 thomas if (t->tag_count == 0) {
1434 8a35f56c 2022-07-16 thomas error = got_error_set_errno(GOT_ERR_BAD_OBJ_ID,
1435 8a35f56c 2022-07-16 thomas "bad commit id");
1436 8a35f56c 2022-07-16 thomas goto done;
1437 8a35f56c 2022-07-16 thomas }
1438 8a35f56c 2022-07-16 thomas
1439 8a35f56c 2022-07-16 thomas rt = TAILQ_LAST(&t->repo_tags, repo_tags_head);
1440 8a35f56c 2022-07-16 thomas
1441 8a35f56c 2022-07-16 thomas error = gotweb_get_time_str(&age, rt->tagger_time, TM_LONG);
1442 8a35f56c 2022-07-16 thomas if (error)
1443 8a35f56c 2022-07-16 thomas goto done;
1444 8a35f56c 2022-07-16 thomas error = gotweb_escape_html(&author, rt->tagger);
1445 8a35f56c 2022-07-16 thomas if (error)
1446 8a35f56c 2022-07-16 thomas goto done;
1447 255f4022 2022-08-27 thomas error = gotweb_escape_html(&msg, rt->commit_msg);
1448 255f4022 2022-08-27 thomas if (error)
1449 255f4022 2022-08-27 thomas goto done;
1450 8a35f56c 2022-07-16 thomas
1451 c8d0196f 2022-09-02 thomas tagname = rt->tag_name;
1452 c8d0196f 2022-09-02 thomas if (strncmp(tagname, "refs/", 5) == 0)
1453 c8d0196f 2022-09-02 thomas tagname += 5;
1454 c8d0196f 2022-09-02 thomas error = gotweb_escape_html(&tagname, tagname);
1455 255f4022 2022-08-27 thomas if (error)
1456 255f4022 2022-08-27 thomas goto done;
1457 8a35f56c 2022-07-16 thomas
1458 79393471 2022-08-27 thomas fcgi_printf(c, "<div id='tags_title_wrapper'>\n"
1459 79393471 2022-08-27 thomas "<div id='tags_title'>Tag</div>\n"
1460 79393471 2022-08-27 thomas "</div>\n" /* #tags_title_wrapper */
1461 79393471 2022-08-27 thomas "<div id='tags_content'>\n"
1462 79393471 2022-08-27 thomas "<div id='tag_header_wrapper'>\n"
1463 79393471 2022-08-27 thomas "<div id='tag_header'>\n"
1464 79393471 2022-08-27 thomas "<div class='header_commit_title'>Commit:</div>\n"
1465 79393471 2022-08-27 thomas "<div class='header_commit'>%s"
1466 79393471 2022-08-27 thomas " <span class='refs_str'>(%s)</span></div>\n"
1467 79393471 2022-08-27 thomas "<div class='header_author_title'>Tagger:</div>\n"
1468 79393471 2022-08-27 thomas "<div class='header_author'>%s</div>\n"
1469 79393471 2022-08-27 thomas "<div class='header_age_title'>Date:</div>\n"
1470 79393471 2022-08-27 thomas "<div class='header_age'>%s</div>\n"
1471 79393471 2022-08-27 thomas "<div id='header_commit_msg_title'>Message:</div>\n"
1472 79393471 2022-08-27 thomas "<div id='header_commit_msg'>%s</div>\n"
1473 79393471 2022-08-27 thomas "</div>\n" /* #tag_header */
1474 79393471 2022-08-27 thomas "<div class='dotted_line'></div>\n"
1475 79393471 2022-08-27 thomas "<div id='tag_commit'>\n%s</div>"
1476 80ca8b0f 2022-09-06 thomas "</div>" /* #tag_header_wrapper */
1477 80ca8b0f 2022-09-06 thomas "</div>", /* #tags_content */
1478 79393471 2022-08-27 thomas rt->commit_id,
1479 255f4022 2022-08-27 thomas tagname,
1480 255f4022 2022-08-27 thomas author,
1481 2ad628aa 2022-08-31 thomas age,
1482 255f4022 2022-08-27 thomas msg,
1483 79393471 2022-08-27 thomas rt->tag_commit);
1484 8a35f56c 2022-07-16 thomas
1485 8a35f56c 2022-07-16 thomas done:
1486 8a35f56c 2022-07-16 thomas free(age);
1487 8a35f56c 2022-07-16 thomas free(author);
1488 255f4022 2022-08-27 thomas free(msg);
1489 8a35f56c 2022-07-16 thomas return error;
1490 8a35f56c 2022-07-16 thomas }
1491 8a35f56c 2022-07-16 thomas
1492 8a35f56c 2022-07-16 thomas static const struct got_error *
1493 8a35f56c 2022-07-16 thomas gotweb_render_tags(struct request *c)
1494 8a35f56c 2022-07-16 thomas {
1495 8a35f56c 2022-07-16 thomas const struct got_error *error = NULL;
1496 8a35f56c 2022-07-16 thomas struct repo_tag *rt = NULL;
1497 8a35f56c 2022-07-16 thomas struct server *srv = c->srv;
1498 8a35f56c 2022-07-16 thomas struct transport *t = c->t;
1499 8a35f56c 2022-07-16 thomas struct querystring *qs = t->qs;
1500 8a35f56c 2022-07-16 thomas struct repo_dir *repo_dir = t->repo_dir;
1501 255f4022 2022-08-27 thomas char *age = NULL, *tagname = NULL, *msg = NULL, *newline;
1502 79393471 2022-08-27 thomas int r, commit_found = 0;
1503 8a35f56c 2022-07-16 thomas
1504 8a35f56c 2022-07-16 thomas if (qs->action == BRIEFS) {
1505 8a35f56c 2022-07-16 thomas qs->action = TAGS;
1506 8a35f56c 2022-07-16 thomas error = got_get_repo_tags(c, D_MAXSLCOMMDISP);
1507 8a35f56c 2022-07-16 thomas } else
1508 8a35f56c 2022-07-16 thomas error = got_get_repo_tags(c, srv->max_commits_display);
1509 8a35f56c 2022-07-16 thomas if (error)
1510 8a35f56c 2022-07-16 thomas goto done;
1511 8a35f56c 2022-07-16 thomas
1512 79393471 2022-08-27 thomas r = fcgi_printf(c, "<div id='tags_title_wrapper'>\n"
1513 79393471 2022-08-27 thomas "<div id='tags_title'>Tags</div>\n"
1514 79393471 2022-08-27 thomas "</div>\n" /* #tags_title_wrapper */
1515 79393471 2022-08-27 thomas "<div id='tags_content'>\n");
1516 79393471 2022-08-27 thomas if (r == -1)
1517 8a35f56c 2022-07-16 thomas goto done;
1518 8a35f56c 2022-07-16 thomas
1519 8a35f56c 2022-07-16 thomas if (t->tag_count == 0) {
1520 79393471 2022-08-27 thomas r = fcgi_printf(c, "<div id='err_content'>%s\n</div>\n",
1521 79393471 2022-08-27 thomas "This repository contains no tags");
1522 79393471 2022-08-27 thomas if (r == -1)
1523 8a35f56c 2022-07-16 thomas goto done;
1524 8a35f56c 2022-07-16 thomas }
1525 8a35f56c 2022-07-16 thomas
1526 8a35f56c 2022-07-16 thomas TAILQ_FOREACH(rt, &t->repo_tags, entry) {
1527 8a35f56c 2022-07-16 thomas if (commit_found == 0 && qs->commit != NULL) {
1528 8a35f56c 2022-07-16 thomas if (strcmp(qs->commit, rt->commit_id) != 0)
1529 8a35f56c 2022-07-16 thomas continue;
1530 8a35f56c 2022-07-16 thomas else
1531 8a35f56c 2022-07-16 thomas commit_found = 1;
1532 8a35f56c 2022-07-16 thomas }
1533 8a35f56c 2022-07-16 thomas error = gotweb_get_time_str(&age, rt->tagger_time, TM_DIFF);
1534 8a35f56c 2022-07-16 thomas if (error)
1535 8a35f56c 2022-07-16 thomas goto done;
1536 8a35f56c 2022-07-16 thomas
1537 c8d0196f 2022-09-02 thomas tagname = rt->tag_name;
1538 c8d0196f 2022-09-02 thomas if (strncmp(tagname, "refs/tags/", 10) == 0)
1539 c8d0196f 2022-09-02 thomas tagname += 10;
1540 c8d0196f 2022-09-02 thomas error = gotweb_escape_html(&tagname, tagname);
1541 255f4022 2022-08-27 thomas if (error)
1542 255f4022 2022-08-27 thomas goto done;
1543 8a35f56c 2022-07-16 thomas
1544 8a35f56c 2022-07-16 thomas if (rt->tag_commit != NULL) {
1545 8a35f56c 2022-07-16 thomas newline = strchr(rt->tag_commit, '\n');
1546 8a35f56c 2022-07-16 thomas if (newline)
1547 8a35f56c 2022-07-16 thomas *newline = '\0';
1548 255f4022 2022-08-27 thomas error = gotweb_escape_html(&msg, rt->tag_commit);
1549 255f4022 2022-08-27 thomas if (error)
1550 255f4022 2022-08-27 thomas goto done;
1551 8a35f56c 2022-07-16 thomas }
1552 8a35f56c 2022-07-16 thomas
1553 55144267 2022-09-07 thomas if (fcgi_printf(c, "<div class='tag_age'>%s</div>\n"
1554 79393471 2022-08-27 thomas "<div class='tag'>%s</div>\n"
1555 55144267 2022-09-07 thomas "<div class='tag_log'>", age, tagname) == -1)
1556 55144267 2022-09-07 thomas goto done;
1557 55144267 2022-09-07 thomas
1558 55144267 2022-09-07 thomas r = gotweb_link(c, &(struct gotweb_url){
1559 55144267 2022-09-07 thomas .action = TAG,
1560 55144267 2022-09-07 thomas .index_page = -1,
1561 55144267 2022-09-07 thomas .page = -1,
1562 55144267 2022-09-07 thomas .path = repo_dir->name,
1563 55144267 2022-09-07 thomas .commit = rt->commit_id,
1564 55144267 2022-09-07 thomas }, "%s", msg ? msg : "");
1565 55144267 2022-09-07 thomas if (r == -1)
1566 55144267 2022-09-07 thomas goto done;
1567 55144267 2022-09-07 thomas
1568 55144267 2022-09-07 thomas if (fcgi_printf(c, "</div>\n" /* .tag_log */
1569 79393471 2022-08-27 thomas "<div class='navs_wrapper'>\n"
1570 55144267 2022-09-07 thomas "<div class='navs'>") == -1)
1571 55144267 2022-09-07 thomas goto done;
1572 55144267 2022-09-07 thomas
1573 55144267 2022-09-07 thomas r = gotweb_link(c, &(struct gotweb_url){
1574 55144267 2022-09-07 thomas .action = TAG,
1575 55144267 2022-09-07 thomas .index_page = -1,
1576 55144267 2022-09-07 thomas .page = -1,
1577 55144267 2022-09-07 thomas .path = repo_dir->name,
1578 55144267 2022-09-07 thomas .commit = rt->commit_id,
1579 55144267 2022-09-07 thomas }, "tag");
1580 55144267 2022-09-07 thomas if (r == -1)
1581 55144267 2022-09-07 thomas goto done;
1582 55144267 2022-09-07 thomas
1583 55144267 2022-09-07 thomas if (fcgi_printf(c, " | ") == -1)
1584 55144267 2022-09-07 thomas goto done;
1585 55144267 2022-09-07 thomas
1586 55144267 2022-09-07 thomas r = gotweb_link(c, &(struct gotweb_url){
1587 55144267 2022-09-07 thomas .action = BRIEFS,
1588 55144267 2022-09-07 thomas .index_page = -1,
1589 55144267 2022-09-07 thomas .page = -1,
1590 55144267 2022-09-07 thomas .path = repo_dir->name,
1591 55144267 2022-09-07 thomas .commit = rt->commit_id,
1592 55144267 2022-09-07 thomas }, "commit briefs");
1593 55144267 2022-09-07 thomas if (r == -1)
1594 55144267 2022-09-07 thomas goto done;
1595 55144267 2022-09-07 thomas
1596 55144267 2022-09-07 thomas if (fcgi_printf(c, " | ") == -1)
1597 55144267 2022-09-07 thomas goto done;
1598 55144267 2022-09-07 thomas
1599 55144267 2022-09-07 thomas r = gotweb_link(c, &(struct gotweb_url){
1600 55144267 2022-09-07 thomas .action = COMMITS,
1601 55144267 2022-09-07 thomas .index_page = -1,
1602 55144267 2022-09-07 thomas .page = -1,
1603 55144267 2022-09-07 thomas .path = repo_dir->name,
1604 55144267 2022-09-07 thomas .commit = rt->commit_id,
1605 55144267 2022-09-07 thomas }, "commits");
1606 55144267 2022-09-07 thomas if (r == -1)
1607 55144267 2022-09-07 thomas goto done;
1608 55144267 2022-09-07 thomas
1609 55144267 2022-09-07 thomas r = fcgi_printf(c,
1610 79393471 2022-08-27 thomas "</div>\n" /* .navs */
1611 79393471 2022-08-27 thomas "</div>\n" /* .navs_wrapper */
1612 55144267 2022-09-07 thomas "<div class='dotted_line'></div>\n");
1613 79393471 2022-08-27 thomas if (r == -1)
1614 8a35f56c 2022-07-16 thomas goto done;
1615 8a35f56c 2022-07-16 thomas
1616 8a35f56c 2022-07-16 thomas free(age);
1617 8a35f56c 2022-07-16 thomas age = NULL;
1618 255f4022 2022-08-27 thomas free(tagname);
1619 255f4022 2022-08-27 thomas tagname = NULL;
1620 255f4022 2022-08-27 thomas free(msg);
1621 255f4022 2022-08-27 thomas msg = NULL;
1622 8a35f56c 2022-07-16 thomas }
1623 8a35f56c 2022-07-16 thomas if (t->next_id || t->prev_id) {
1624 8a35f56c 2022-07-16 thomas error = gotweb_render_navs(c);
1625 8a35f56c 2022-07-16 thomas if (error)
1626 8a35f56c 2022-07-16 thomas goto done;
1627 8a35f56c 2022-07-16 thomas }
1628 79393471 2022-08-27 thomas fcgi_printf(c, "</div>\n"); /* #tags_content */
1629 8a35f56c 2022-07-16 thomas done:
1630 8a35f56c 2022-07-16 thomas free(age);
1631 255f4022 2022-08-27 thomas free(tagname);
1632 255f4022 2022-08-27 thomas free(msg);
1633 8a35f56c 2022-07-16 thomas return error;
1634 8a35f56c 2022-07-16 thomas }
1635 8a35f56c 2022-07-16 thomas
1636 8a35f56c 2022-07-16 thomas const struct got_error *
1637 8a35f56c 2022-07-16 thomas gotweb_escape_html(char **escaped_html, const char *orig_html)
1638 8a35f56c 2022-07-16 thomas {
1639 8a35f56c 2022-07-16 thomas const struct got_error *error = NULL;
1640 8a35f56c 2022-07-16 thomas struct escape_pair {
1641 8a35f56c 2022-07-16 thomas char c;
1642 8a35f56c 2022-07-16 thomas const char *s;
1643 8a35f56c 2022-07-16 thomas } esc[] = {
1644 8a35f56c 2022-07-16 thomas { '>', "&gt;" },
1645 8a35f56c 2022-07-16 thomas { '<', "&lt;" },
1646 8a35f56c 2022-07-16 thomas { '&', "&amp;" },
1647 8a35f56c 2022-07-16 thomas { '"', "&quot;" },
1648 8a35f56c 2022-07-16 thomas { '\'', "&apos;" },
1649 8a35f56c 2022-07-16 thomas { '\n', "<br />" },
1650 8a35f56c 2022-07-16 thomas };
1651 8a35f56c 2022-07-16 thomas size_t orig_len, len;
1652 8a35f56c 2022-07-16 thomas int i, j, x;
1653 8a35f56c 2022-07-16 thomas
1654 8a35f56c 2022-07-16 thomas orig_len = strlen(orig_html);
1655 8a35f56c 2022-07-16 thomas len = orig_len;
1656 8a35f56c 2022-07-16 thomas for (i = 0; i < orig_len; i++) {
1657 8a35f56c 2022-07-16 thomas for (j = 0; j < nitems(esc); j++) {
1658 8a35f56c 2022-07-16 thomas if (orig_html[i] != esc[j].c)
1659 8a35f56c 2022-07-16 thomas continue;
1660 8a35f56c 2022-07-16 thomas len += strlen(esc[j].s) - 1 /* escaped char */;
1661 8a35f56c 2022-07-16 thomas }
1662 8a35f56c 2022-07-16 thomas }
1663 8a35f56c 2022-07-16 thomas
1664 8a35f56c 2022-07-16 thomas *escaped_html = calloc(len + 1 /* NUL */, sizeof(**escaped_html));
1665 8a35f56c 2022-07-16 thomas if (*escaped_html == NULL)
1666 8a35f56c 2022-07-16 thomas return got_error_from_errno("calloc");
1667 8a35f56c 2022-07-16 thomas
1668 8a35f56c 2022-07-16 thomas x = 0;
1669 8a35f56c 2022-07-16 thomas for (i = 0; i < orig_len; i++) {
1670 8a35f56c 2022-07-16 thomas int escaped = 0;
1671 8a35f56c 2022-07-16 thomas for (j = 0; j < nitems(esc); j++) {
1672 8a35f56c 2022-07-16 thomas if (orig_html[i] != esc[j].c)
1673 8a35f56c 2022-07-16 thomas continue;
1674 8a35f56c 2022-07-16 thomas
1675 8a35f56c 2022-07-16 thomas if (strlcat(*escaped_html, esc[j].s, len + 1)
1676 8a35f56c 2022-07-16 thomas >= len + 1) {
1677 8a35f56c 2022-07-16 thomas error = got_error(GOT_ERR_NO_SPACE);
1678 8a35f56c 2022-07-16 thomas goto done;
1679 8a35f56c 2022-07-16 thomas }
1680 8a35f56c 2022-07-16 thomas x += strlen(esc[j].s);
1681 8a35f56c 2022-07-16 thomas escaped = 1;
1682 8a35f56c 2022-07-16 thomas break;
1683 8a35f56c 2022-07-16 thomas }
1684 8a35f56c 2022-07-16 thomas if (!escaped) {
1685 8a35f56c 2022-07-16 thomas (*escaped_html)[x] = orig_html[i];
1686 8a35f56c 2022-07-16 thomas x++;
1687 8a35f56c 2022-07-16 thomas }
1688 8a35f56c 2022-07-16 thomas }
1689 8a35f56c 2022-07-16 thomas done:
1690 8a35f56c 2022-07-16 thomas if (error) {
1691 8a35f56c 2022-07-16 thomas free(*escaped_html);
1692 8a35f56c 2022-07-16 thomas *escaped_html = NULL;
1693 8a35f56c 2022-07-16 thomas } else {
1694 8a35f56c 2022-07-16 thomas (*escaped_html)[x] = '\0';
1695 8a35f56c 2022-07-16 thomas }
1696 8a35f56c 2022-07-16 thomas
1697 8a35f56c 2022-07-16 thomas return error;
1698 8a35f56c 2022-07-16 thomas }
1699 8a35f56c 2022-07-16 thomas
1700 55144267 2022-09-07 thomas static inline int
1701 55144267 2022-09-07 thomas should_urlencode(int c)
1702 55144267 2022-09-07 thomas {
1703 55144267 2022-09-07 thomas if (c <= ' ' || c >= 127)
1704 55144267 2022-09-07 thomas return 1;
1705 55144267 2022-09-07 thomas
1706 55144267 2022-09-07 thomas switch (c) {
1707 55144267 2022-09-07 thomas /* gen-delim */
1708 55144267 2022-09-07 thomas case ':':
1709 55144267 2022-09-07 thomas case '/':
1710 55144267 2022-09-07 thomas case '?':
1711 55144267 2022-09-07 thomas case '#':
1712 55144267 2022-09-07 thomas case '[':
1713 55144267 2022-09-07 thomas case ']':
1714 55144267 2022-09-07 thomas case '@':
1715 55144267 2022-09-07 thomas /* sub-delims */
1716 55144267 2022-09-07 thomas case '!':
1717 55144267 2022-09-07 thomas case '$':
1718 55144267 2022-09-07 thomas case '&':
1719 55144267 2022-09-07 thomas case '\'':
1720 55144267 2022-09-07 thomas case '(':
1721 55144267 2022-09-07 thomas case ')':
1722 55144267 2022-09-07 thomas case '*':
1723 55144267 2022-09-07 thomas case '+':
1724 55144267 2022-09-07 thomas case ',':
1725 55144267 2022-09-07 thomas case ';':
1726 55144267 2022-09-07 thomas case '=':
1727 55144267 2022-09-07 thomas return 1;
1728 55144267 2022-09-07 thomas default:
1729 55144267 2022-09-07 thomas return 0;
1730 55144267 2022-09-07 thomas }
1731 55144267 2022-09-07 thomas }
1732 55144267 2022-09-07 thomas
1733 55144267 2022-09-07 thomas static char *
1734 55144267 2022-09-07 thomas gotweb_urlencode(const char *str)
1735 55144267 2022-09-07 thomas {
1736 55144267 2022-09-07 thomas const char *s;
1737 55144267 2022-09-07 thomas char *escaped;
1738 55144267 2022-09-07 thomas size_t i, len;
1739 55144267 2022-09-07 thomas int a, b;
1740 55144267 2022-09-07 thomas
1741 55144267 2022-09-07 thomas len = 0;
1742 55144267 2022-09-07 thomas for (s = str; *s; ++s) {
1743 55144267 2022-09-07 thomas len++;
1744 55144267 2022-09-07 thomas if (should_urlencode(*s))
1745 55144267 2022-09-07 thomas len += 2;
1746 55144267 2022-09-07 thomas }
1747 55144267 2022-09-07 thomas
1748 55144267 2022-09-07 thomas escaped = calloc(1, len + 1);
1749 55144267 2022-09-07 thomas if (escaped == NULL)
1750 55144267 2022-09-07 thomas return NULL;
1751 55144267 2022-09-07 thomas
1752 55144267 2022-09-07 thomas i = 0;
1753 55144267 2022-09-07 thomas for (s = str; *s; ++s) {
1754 55144267 2022-09-07 thomas if (should_urlencode(*s)) {
1755 55144267 2022-09-07 thomas a = (*s & 0xF0) >> 4;
1756 55144267 2022-09-07 thomas b = (*s & 0x0F);
1757 55144267 2022-09-07 thomas
1758 55144267 2022-09-07 thomas escaped[i++] = '%';
1759 55144267 2022-09-07 thomas escaped[i++] = a <= 9 ? ('0' + a) : ('7' + a);
1760 55144267 2022-09-07 thomas escaped[i++] = b <= 9 ? ('0' + b) : ('7' + b);
1761 55144267 2022-09-07 thomas } else
1762 55144267 2022-09-07 thomas escaped[i++] = *s;
1763 55144267 2022-09-07 thomas }
1764 55144267 2022-09-07 thomas
1765 55144267 2022-09-07 thomas return escaped;
1766 55144267 2022-09-07 thomas }
1767 55144267 2022-09-07 thomas
1768 e7e5fa49 2022-12-30 thomas const char *
1769 e7e5fa49 2022-12-30 thomas gotweb_action_name(int action)
1770 55144267 2022-09-07 thomas {
1771 55144267 2022-09-07 thomas switch (action) {
1772 55144267 2022-09-07 thomas case BLAME:
1773 55144267 2022-09-07 thomas return "blame";
1774 55144267 2022-09-07 thomas case BLOB:
1775 55144267 2022-09-07 thomas return "blob";
1776 55144267 2022-09-07 thomas case BRIEFS:
1777 55144267 2022-09-07 thomas return "briefs";
1778 55144267 2022-09-07 thomas case COMMITS:
1779 55144267 2022-09-07 thomas return "commits";
1780 55144267 2022-09-07 thomas case DIFF:
1781 55144267 2022-09-07 thomas return "diff";
1782 55144267 2022-09-07 thomas case ERR:
1783 55144267 2022-09-07 thomas return "err";
1784 55144267 2022-09-07 thomas case INDEX:
1785 55144267 2022-09-07 thomas return "index";
1786 55144267 2022-09-07 thomas case SUMMARY:
1787 55144267 2022-09-07 thomas return "summary";
1788 55144267 2022-09-07 thomas case TAG:
1789 55144267 2022-09-07 thomas return "tag";
1790 55144267 2022-09-07 thomas case TAGS:
1791 55144267 2022-09-07 thomas return "tags";
1792 55144267 2022-09-07 thomas case TREE:
1793 55144267 2022-09-07 thomas return "tree";
1794 55144267 2022-09-07 thomas default:
1795 55144267 2022-09-07 thomas return NULL;
1796 55144267 2022-09-07 thomas }
1797 55144267 2022-09-07 thomas }
1798 55144267 2022-09-07 thomas
1799 e7e5fa49 2022-12-30 thomas int
1800 e7e5fa49 2022-12-30 thomas gotweb_render_url(struct request *c, struct gotweb_url *url)
1801 55144267 2022-09-07 thomas {
1802 55144267 2022-09-07 thomas const char *sep = "?", *action;
1803 55144267 2022-09-07 thomas char *tmp;
1804 55144267 2022-09-07 thomas int r;
1805 55144267 2022-09-07 thomas
1806 e7e5fa49 2022-12-30 thomas action = gotweb_action_name(url->action);
1807 55144267 2022-09-07 thomas if (action != NULL) {
1808 55144267 2022-09-07 thomas if (fcgi_printf(c, "?action=%s", action) == -1)
1809 55144267 2022-09-07 thomas return -1;
1810 55144267 2022-09-07 thomas sep = "&";
1811 55144267 2022-09-07 thomas }
1812 55144267 2022-09-07 thomas
1813 55144267 2022-09-07 thomas if (url->commit) {
1814 55144267 2022-09-07 thomas if (fcgi_printf(c, "%scommit=%s", sep, url->commit) == -1)
1815 55144267 2022-09-07 thomas return -1;
1816 55144267 2022-09-07 thomas sep = "&";
1817 55144267 2022-09-07 thomas }
1818 55144267 2022-09-07 thomas
1819 55144267 2022-09-07 thomas if (url->previd) {
1820 55144267 2022-09-07 thomas if (fcgi_printf(c, "%sprevid=%s", sep, url->previd) == -1)
1821 55144267 2022-09-07 thomas return -1;
1822 55144267 2022-09-07 thomas sep = "&";
1823 55144267 2022-09-07 thomas }
1824 55144267 2022-09-07 thomas
1825 55144267 2022-09-07 thomas if (url->prevset) {
1826 55144267 2022-09-07 thomas if (fcgi_printf(c, "%sprevset=%s", sep, url->prevset) == -1)
1827 55144267 2022-09-07 thomas return -1;
1828 55144267 2022-09-07 thomas sep = "&";
1829 55144267 2022-09-07 thomas }
1830 55144267 2022-09-07 thomas
1831 55144267 2022-09-07 thomas if (url->file) {
1832 55144267 2022-09-07 thomas tmp = gotweb_urlencode(url->file);
1833 55144267 2022-09-07 thomas if (tmp == NULL)
1834 55144267 2022-09-07 thomas return -1;
1835 55144267 2022-09-07 thomas r = fcgi_printf(c, "%sfile=%s", sep, tmp);
1836 55144267 2022-09-07 thomas free(tmp);
1837 55144267 2022-09-07 thomas if (r == -1)
1838 55144267 2022-09-07 thomas return -1;
1839 55144267 2022-09-07 thomas sep = "&";
1840 55144267 2022-09-07 thomas }
1841 55144267 2022-09-07 thomas
1842 55144267 2022-09-07 thomas if (url->folder) {
1843 55144267 2022-09-07 thomas tmp = gotweb_urlencode(url->folder);
1844 55144267 2022-09-07 thomas if (tmp == NULL)
1845 55144267 2022-09-07 thomas return -1;
1846 55144267 2022-09-07 thomas r = fcgi_printf(c, "%sfolder=%s", sep, tmp);
1847 55144267 2022-09-07 thomas free(tmp);
1848 55144267 2022-09-07 thomas if (r == -1)
1849 55144267 2022-09-07 thomas return -1;
1850 55144267 2022-09-07 thomas sep = "&";
1851 55144267 2022-09-07 thomas }
1852 55144267 2022-09-07 thomas
1853 55144267 2022-09-07 thomas if (url->headref) {
1854 55144267 2022-09-07 thomas tmp = gotweb_urlencode(url->headref);
1855 55144267 2022-09-07 thomas if (tmp == NULL)
1856 55144267 2022-09-07 thomas return -1;
1857 55144267 2022-09-07 thomas r = fcgi_printf(c, "%sheadref=%s", sep, url->headref);
1858 55144267 2022-09-07 thomas free(tmp);
1859 55144267 2022-09-07 thomas if (r == -1)
1860 55144267 2022-09-07 thomas return -1;
1861 55144267 2022-09-07 thomas sep = "&";
1862 55144267 2022-09-07 thomas }
1863 55144267 2022-09-07 thomas
1864 55144267 2022-09-07 thomas if (url->index_page != -1) {
1865 55144267 2022-09-07 thomas if (fcgi_printf(c, "%sindex_page=%d", sep,
1866 55144267 2022-09-07 thomas url->index_page) == -1)
1867 55144267 2022-09-07 thomas return -1;
1868 55144267 2022-09-07 thomas sep = "&";
1869 55144267 2022-09-07 thomas }
1870 55144267 2022-09-07 thomas
1871 55144267 2022-09-07 thomas if (url->path) {
1872 55144267 2022-09-07 thomas tmp = gotweb_urlencode(url->path);
1873 55144267 2022-09-07 thomas if (tmp == NULL)
1874 55144267 2022-09-07 thomas return -1;
1875 55144267 2022-09-07 thomas r = fcgi_printf(c, "%spath=%s", sep, tmp);
1876 55144267 2022-09-07 thomas free(tmp);
1877 55144267 2022-09-07 thomas if (r == -1)
1878 55144267 2022-09-07 thomas return -1;
1879 55144267 2022-09-07 thomas sep = "&";
1880 55144267 2022-09-07 thomas }
1881 55144267 2022-09-07 thomas
1882 55144267 2022-09-07 thomas if (url->page != -1) {
1883 55144267 2022-09-07 thomas if (fcgi_printf(c, "%spage=%d", sep, url->page) == -1)
1884 55144267 2022-09-07 thomas return -1;
1885 55144267 2022-09-07 thomas sep = "&";
1886 55144267 2022-09-07 thomas }
1887 55144267 2022-09-07 thomas
1888 55144267 2022-09-07 thomas return 0;
1889 55144267 2022-09-07 thomas }
1890 55144267 2022-09-07 thomas
1891 55144267 2022-09-07 thomas int
1892 55144267 2022-09-07 thomas gotweb_link(struct request *c, struct gotweb_url *url, const char *fmt, ...)
1893 55144267 2022-09-07 thomas {
1894 55144267 2022-09-07 thomas va_list ap;
1895 55144267 2022-09-07 thomas int r;
1896 55144267 2022-09-07 thomas
1897 55144267 2022-09-07 thomas if (fcgi_printf(c, "<a href='") == -1)
1898 55144267 2022-09-07 thomas return -1;
1899 55144267 2022-09-07 thomas
1900 e7e5fa49 2022-12-30 thomas if (gotweb_render_url(c, url) == -1)
1901 55144267 2022-09-07 thomas return -1;
1902 55144267 2022-09-07 thomas
1903 55144267 2022-09-07 thomas if (fcgi_printf(c, "'>") == -1)
1904 55144267 2022-09-07 thomas return -1;
1905 55144267 2022-09-07 thomas
1906 55144267 2022-09-07 thomas va_start(ap, fmt);
1907 55144267 2022-09-07 thomas r = fcgi_vprintf(c, fmt, ap);
1908 55144267 2022-09-07 thomas va_end(ap);
1909 55144267 2022-09-07 thomas if (r == -1)
1910 55144267 2022-09-07 thomas return -1;
1911 55144267 2022-09-07 thomas
1912 55144267 2022-09-07 thomas if (fcgi_printf(c, "</a>"))
1913 55144267 2022-09-07 thomas return -1;
1914 55144267 2022-09-07 thomas return 0;
1915 55144267 2022-09-07 thomas }
1916 55144267 2022-09-07 thomas
1917 55e6cffd 2022-09-01 thomas static struct got_repository *
1918 55e6cffd 2022-09-01 thomas find_cached_repo(struct server *srv, const char *path)
1919 55e6cffd 2022-09-01 thomas {
1920 55e6cffd 2022-09-01 thomas int i;
1921 55e6cffd 2022-09-01 thomas
1922 55e6cffd 2022-09-01 thomas for (i = 0; i < srv->ncached_repos; i++) {
1923 55e6cffd 2022-09-01 thomas if (strcmp(srv->cached_repos[i].path, path) == 0)
1924 55e6cffd 2022-09-01 thomas return srv->cached_repos[i].repo;
1925 55e6cffd 2022-09-01 thomas }
1926 55e6cffd 2022-09-01 thomas
1927 55e6cffd 2022-09-01 thomas return NULL;
1928 55e6cffd 2022-09-01 thomas }
1929 55e6cffd 2022-09-01 thomas
1930 8a35f56c 2022-07-16 thomas static const struct got_error *
1931 55e6cffd 2022-09-01 thomas cache_repo(struct got_repository **new, struct server *srv,
1932 55e6cffd 2022-09-01 thomas struct repo_dir *repo_dir, struct socket *sock)
1933 55e6cffd 2022-09-01 thomas {
1934 55e6cffd 2022-09-01 thomas const struct got_error *error = NULL;
1935 55e6cffd 2022-09-01 thomas struct got_repository *repo;
1936 55e6cffd 2022-09-01 thomas struct cached_repo *cr;
1937 55e6cffd 2022-09-01 thomas int evicted = 0;
1938 55e6cffd 2022-09-01 thomas
1939 a004b24a 2022-09-06 thomas if (srv->ncached_repos >= GOTWEBD_REPO_CACHESIZE) {
1940 55e6cffd 2022-09-01 thomas cr = &srv->cached_repos[srv->ncached_repos - 1];
1941 55e6cffd 2022-09-01 thomas error = got_repo_close(cr->repo);
1942 55e6cffd 2022-09-01 thomas memset(cr, 0, sizeof(*cr));
1943 55e6cffd 2022-09-01 thomas srv->ncached_repos--;
1944 55e6cffd 2022-09-01 thomas if (error)
1945 55e6cffd 2022-09-01 thomas return error;
1946 55e6cffd 2022-09-01 thomas memmove(&srv->cached_repos[1], &srv->cached_repos[0],
1947 55e6cffd 2022-09-01 thomas srv->ncached_repos * sizeof(srv->cached_repos[0]));
1948 55e6cffd 2022-09-01 thomas cr = &srv->cached_repos[0];
1949 55e6cffd 2022-09-01 thomas evicted = 1;
1950 55e6cffd 2022-09-01 thomas } else {
1951 55e6cffd 2022-09-01 thomas cr = &srv->cached_repos[srv->ncached_repos];
1952 55e6cffd 2022-09-01 thomas }
1953 55e6cffd 2022-09-01 thomas
1954 55e6cffd 2022-09-01 thomas error = got_repo_open(&repo, repo_dir->path, NULL, sock->pack_fds);
1955 55e6cffd 2022-09-01 thomas if (error) {
1956 55e6cffd 2022-09-01 thomas if (evicted) {
1957 55e6cffd 2022-09-01 thomas memmove(&srv->cached_repos[0], &srv->cached_repos[1],
1958 55e6cffd 2022-09-01 thomas srv->ncached_repos * sizeof(srv->cached_repos[0]));
1959 55e6cffd 2022-09-01 thomas }
1960 55e6cffd 2022-09-01 thomas return error;
1961 55e6cffd 2022-09-01 thomas }
1962 55e6cffd 2022-09-01 thomas
1963 55e6cffd 2022-09-01 thomas if (strlcpy(cr->path, repo_dir->path, sizeof(cr->path))
1964 55e6cffd 2022-09-01 thomas >= sizeof(cr->path)) {
1965 55e6cffd 2022-09-01 thomas if (evicted) {
1966 55e6cffd 2022-09-01 thomas memmove(&srv->cached_repos[0], &srv->cached_repos[1],
1967 55e6cffd 2022-09-01 thomas srv->ncached_repos * sizeof(srv->cached_repos[0]));
1968 55e6cffd 2022-09-01 thomas }
1969 55e6cffd 2022-09-01 thomas return got_error(GOT_ERR_NO_SPACE);
1970 55e6cffd 2022-09-01 thomas }
1971 55e6cffd 2022-09-01 thomas
1972 55e6cffd 2022-09-01 thomas cr->repo = repo;
1973 55e6cffd 2022-09-01 thomas srv->ncached_repos++;
1974 55e6cffd 2022-09-01 thomas *new = repo;
1975 55e6cffd 2022-09-01 thomas return NULL;
1976 55e6cffd 2022-09-01 thomas }
1977 55e6cffd 2022-09-01 thomas
1978 55e6cffd 2022-09-01 thomas static const struct got_error *
1979 8a35f56c 2022-07-16 thomas gotweb_load_got_path(struct request *c, struct repo_dir *repo_dir)
1980 8a35f56c 2022-07-16 thomas {
1981 8a35f56c 2022-07-16 thomas const struct got_error *error = NULL;
1982 8a35f56c 2022-07-16 thomas struct socket *sock = c->sock;
1983 8a35f56c 2022-07-16 thomas struct server *srv = c->srv;
1984 8a35f56c 2022-07-16 thomas struct transport *t = c->t;
1985 55e6cffd 2022-09-01 thomas struct got_repository *repo = NULL;
1986 8a35f56c 2022-07-16 thomas DIR *dt;
1987 8a35f56c 2022-07-16 thomas char *dir_test;
1988 8a35f56c 2022-07-16 thomas
1989 8a35f56c 2022-07-16 thomas if (asprintf(&dir_test, "%s/%s/%s", srv->repos_path, repo_dir->name,
1990 8a35f56c 2022-07-16 thomas GOTWEB_GIT_DIR) == -1)
1991 8a35f56c 2022-07-16 thomas return got_error_from_errno("asprintf");
1992 8a35f56c 2022-07-16 thomas
1993 8a35f56c 2022-07-16 thomas dt = opendir(dir_test);
1994 8a35f56c 2022-07-16 thomas if (dt == NULL) {
1995 8a35f56c 2022-07-16 thomas free(dir_test);
1996 8a35f56c 2022-07-16 thomas } else {
1997 c2d3d9a0 2022-09-01 thomas repo_dir->path = dir_test;
1998 8a35f56c 2022-07-16 thomas dir_test = NULL;
1999 c2d3d9a0 2022-09-01 thomas goto done;
2000 8a35f56c 2022-07-16 thomas }
2001 8a35f56c 2022-07-16 thomas
2002 8a35f56c 2022-07-16 thomas if (asprintf(&dir_test, "%s/%s", srv->repos_path,
2003 c2d3d9a0 2022-09-01 thomas repo_dir->name) == -1)
2004 c2d3d9a0 2022-09-01 thomas return got_error_from_errno("asprintf");
2005 8a35f56c 2022-07-16 thomas
2006 8a35f56c 2022-07-16 thomas dt = opendir(dir_test);
2007 8a35f56c 2022-07-16 thomas if (dt == NULL) {
2008 8a35f56c 2022-07-16 thomas error = got_error_path(repo_dir->name, GOT_ERR_NOT_GIT_REPO);
2009 8a35f56c 2022-07-16 thomas goto err;
2010 c2d3d9a0 2022-09-01 thomas } else {
2011 c2d3d9a0 2022-09-01 thomas repo_dir->path = dir_test;
2012 c2d3d9a0 2022-09-01 thomas dir_test = NULL;
2013 c2d3d9a0 2022-09-01 thomas }
2014 c2d3d9a0 2022-09-01 thomas
2015 8a35f56c 2022-07-16 thomas done:
2016 3991b2a5 2022-10-31 thomas if (srv->respect_exportok &&
2017 3991b2a5 2022-10-31 thomas faccessat(dirfd(dt), "git-daemon-export-ok", F_OK, 0) == -1) {
2018 3991b2a5 2022-10-31 thomas error = got_error_path(repo_dir->name, GOT_ERR_NOT_GIT_REPO);
2019 3991b2a5 2022-10-31 thomas goto err;
2020 3991b2a5 2022-10-31 thomas }
2021 3991b2a5 2022-10-31 thomas
2022 55e6cffd 2022-09-01 thomas repo = find_cached_repo(srv, repo_dir->path);
2023 55e6cffd 2022-09-01 thomas if (repo == NULL) {
2024 55e6cffd 2022-09-01 thomas error = cache_repo(&repo, srv, repo_dir, sock);
2025 55e6cffd 2022-09-01 thomas if (error)
2026 55e6cffd 2022-09-01 thomas goto err;
2027 55e6cffd 2022-09-01 thomas }
2028 55e6cffd 2022-09-01 thomas t->repo = repo;
2029 8a35f56c 2022-07-16 thomas error = gotweb_get_repo_description(&repo_dir->description, srv,
2030 4606e6d4 2022-11-23 thomas repo_dir->path, dirfd(dt));
2031 8a35f56c 2022-07-16 thomas if (error)
2032 8a35f56c 2022-07-16 thomas goto err;
2033 6c7f10f7 2022-11-23 thomas error = got_get_repo_owner(&repo_dir->owner, c);
2034 8a35f56c 2022-07-16 thomas if (error)
2035 8a35f56c 2022-07-16 thomas goto err;
2036 6c7f10f7 2022-11-23 thomas error = got_get_repo_age(&repo_dir->age, c, NULL, TM_DIFF);
2037 8a35f56c 2022-07-16 thomas if (error)
2038 8a35f56c 2022-07-16 thomas goto err;
2039 4606e6d4 2022-11-23 thomas error = gotweb_get_clone_url(&repo_dir->url, srv, repo_dir->path,
2040 4606e6d4 2022-11-23 thomas dirfd(dt));
2041 8a35f56c 2022-07-16 thomas err:
2042 8a35f56c 2022-07-16 thomas free(dir_test);
2043 c2d3d9a0 2022-09-01 thomas if (dt != NULL && closedir(dt) == EOF && error == NULL)
2044 c2d3d9a0 2022-09-01 thomas error = got_error_from_errno("closedir");
2045 8a35f56c 2022-07-16 thomas return error;
2046 8a35f56c 2022-07-16 thomas }
2047 8a35f56c 2022-07-16 thomas
2048 8a35f56c 2022-07-16 thomas static const struct got_error *
2049 8a35f56c 2022-07-16 thomas gotweb_init_repo_dir(struct repo_dir **repo_dir, const char *dir)
2050 8a35f56c 2022-07-16 thomas {
2051 8a35f56c 2022-07-16 thomas const struct got_error *error;
2052 8a35f56c 2022-07-16 thomas
2053 8a35f56c 2022-07-16 thomas *repo_dir = calloc(1, sizeof(**repo_dir));
2054 8a35f56c 2022-07-16 thomas if (*repo_dir == NULL)
2055 8a35f56c 2022-07-16 thomas return got_error_from_errno("calloc");
2056 8a35f56c 2022-07-16 thomas
2057 8a35f56c 2022-07-16 thomas if (asprintf(&(*repo_dir)->name, "%s", dir) == -1) {
2058 8a35f56c 2022-07-16 thomas error = got_error_from_errno("asprintf");
2059 8a35f56c 2022-07-16 thomas free(*repo_dir);
2060 8a35f56c 2022-07-16 thomas *repo_dir = NULL;
2061 8a35f56c 2022-07-16 thomas return error;
2062 8a35f56c 2022-07-16 thomas }
2063 8a35f56c 2022-07-16 thomas (*repo_dir)->owner = NULL;
2064 8a35f56c 2022-07-16 thomas (*repo_dir)->description = NULL;
2065 8a35f56c 2022-07-16 thomas (*repo_dir)->url = NULL;
2066 8a35f56c 2022-07-16 thomas (*repo_dir)->age = NULL;
2067 8a35f56c 2022-07-16 thomas (*repo_dir)->path = NULL;
2068 8a35f56c 2022-07-16 thomas
2069 8a35f56c 2022-07-16 thomas return NULL;
2070 8a35f56c 2022-07-16 thomas }
2071 8a35f56c 2022-07-16 thomas
2072 8a35f56c 2022-07-16 thomas static const struct got_error *
2073 4606e6d4 2022-11-23 thomas gotweb_get_repo_description(char **description, struct server *srv,
2074 4606e6d4 2022-11-23 thomas const char *dirpath, int dir)
2075 8a35f56c 2022-07-16 thomas {
2076 8a35f56c 2022-07-16 thomas const struct got_error *error = NULL;
2077 4606e6d4 2022-11-23 thomas struct stat sb;
2078 4606e6d4 2022-11-23 thomas int fd = -1;
2079 4606e6d4 2022-11-23 thomas off_t len;
2080 8a35f56c 2022-07-16 thomas
2081 8a35f56c 2022-07-16 thomas *description = NULL;
2082 8a35f56c 2022-07-16 thomas if (srv->show_repo_description == 0)
2083 8a35f56c 2022-07-16 thomas return NULL;
2084 8a35f56c 2022-07-16 thomas
2085 4606e6d4 2022-11-23 thomas fd = openat(dir, "description", O_RDONLY);
2086 4606e6d4 2022-11-23 thomas if (fd == -1) {
2087 4606e6d4 2022-11-23 thomas if (errno != ENOENT && errno != EACCES) {
2088 4606e6d4 2022-11-23 thomas error = got_error_from_errno_fmt("openat %s/%s",
2089 4606e6d4 2022-11-23 thomas dirpath, "description");
2090 4606e6d4 2022-11-23 thomas }
2091 8a35f56c 2022-07-16 thomas goto done;
2092 8a35f56c 2022-07-16 thomas }
2093 8a35f56c 2022-07-16 thomas
2094 4606e6d4 2022-11-23 thomas if (fstat(fd, &sb) == -1) {
2095 4606e6d4 2022-11-23 thomas error = got_error_from_errno_fmt("fstat %s/%s",
2096 4606e6d4 2022-11-23 thomas dirpath, "description");
2097 8a35f56c 2022-07-16 thomas goto done;
2098 8a35f56c 2022-07-16 thomas }
2099 8a35f56c 2022-07-16 thomas
2100 4606e6d4 2022-11-23 thomas len = sb.st_size;
2101 3e9a56b5 2022-12-01 thomas if (len > GOTWEBD_MAXDESCRSZ - 1)
2102 3e9a56b5 2022-12-01 thomas len = GOTWEBD_MAXDESCRSZ - 1;
2103 8a35f56c 2022-07-16 thomas
2104 8a35f56c 2022-07-16 thomas *description = calloc(len + 1, sizeof(**description));
2105 8a35f56c 2022-07-16 thomas if (*description == NULL) {
2106 8a35f56c 2022-07-16 thomas error = got_error_from_errno("calloc");
2107 8a35f56c 2022-07-16 thomas goto done;
2108 8a35f56c 2022-07-16 thomas }
2109 8a35f56c 2022-07-16 thomas
2110 4606e6d4 2022-11-23 thomas if (read(fd, *description, len) == -1)
2111 4606e6d4 2022-11-23 thomas error = got_error_from_errno("read");
2112 8a35f56c 2022-07-16 thomas done:
2113 4606e6d4 2022-11-23 thomas if (fd != -1 && close(fd) == -1 && error == NULL)
2114 4606e6d4 2022-11-23 thomas error = got_error_from_errno("close");
2115 8a35f56c 2022-07-16 thomas return error;
2116 8a35f56c 2022-07-16 thomas }
2117 8a35f56c 2022-07-16 thomas
2118 8a35f56c 2022-07-16 thomas static const struct got_error *
2119 4606e6d4 2022-11-23 thomas gotweb_get_clone_url(char **url, struct server *srv, const char *dirpath,
2120 4606e6d4 2022-11-23 thomas int dir)
2121 8a35f56c 2022-07-16 thomas {
2122 8a35f56c 2022-07-16 thomas const struct got_error *error = NULL;
2123 4606e6d4 2022-11-23 thomas struct stat sb;
2124 4606e6d4 2022-11-23 thomas int fd = -1;
2125 4606e6d4 2022-11-23 thomas off_t len;
2126 8a35f56c 2022-07-16 thomas
2127 8a35f56c 2022-07-16 thomas *url = NULL;
2128 8a35f56c 2022-07-16 thomas if (srv->show_repo_cloneurl == 0)
2129 8a35f56c 2022-07-16 thomas return NULL;
2130 8a35f56c 2022-07-16 thomas
2131 4606e6d4 2022-11-23 thomas fd = openat(dir, "cloneurl", O_RDONLY);
2132 4606e6d4 2022-11-23 thomas if (fd == -1) {
2133 4606e6d4 2022-11-23 thomas if (errno != ENOENT && errno != EACCES) {
2134 4606e6d4 2022-11-23 thomas error = got_error_from_errno_fmt("openat %s/%s",
2135 4606e6d4 2022-11-23 thomas dirpath, "cloneurl");
2136 4606e6d4 2022-11-23 thomas }
2137 8a35f56c 2022-07-16 thomas goto done;
2138 8a35f56c 2022-07-16 thomas }
2139 8a35f56c 2022-07-16 thomas
2140 4606e6d4 2022-11-23 thomas if (fstat(fd, &sb) == -1) {
2141 4606e6d4 2022-11-23 thomas error = got_error_from_errno_fmt("fstat %s/%s",
2142 4606e6d4 2022-11-23 thomas dirpath, "cloneurl");
2143 8a35f56c 2022-07-16 thomas goto done;
2144 8a35f56c 2022-07-16 thomas }
2145 8a35f56c 2022-07-16 thomas
2146 4606e6d4 2022-11-23 thomas len = sb.st_size;
2147 3e9a56b5 2022-12-01 thomas if (len > GOTWEBD_MAXCLONEURLSZ - 1)
2148 3e9a56b5 2022-12-01 thomas len = GOTWEBD_MAXCLONEURLSZ - 1;
2149 8a35f56c 2022-07-16 thomas
2150 8a35f56c 2022-07-16 thomas *url = calloc(len + 1, sizeof(**url));
2151 8a35f56c 2022-07-16 thomas if (*url == NULL) {
2152 8a35f56c 2022-07-16 thomas error = got_error_from_errno("calloc");
2153 8a35f56c 2022-07-16 thomas goto done;
2154 8a35f56c 2022-07-16 thomas }
2155 8a35f56c 2022-07-16 thomas
2156 4606e6d4 2022-11-23 thomas if (read(fd, *url, len) == -1)
2157 4606e6d4 2022-11-23 thomas error = got_error_from_errno("read");
2158 8a35f56c 2022-07-16 thomas done:
2159 4606e6d4 2022-11-23 thomas if (fd != -1 && close(fd) == -1 && error == NULL)
2160 4606e6d4 2022-11-23 thomas error = got_error_from_errno("close");
2161 8a35f56c 2022-07-16 thomas return error;
2162 8a35f56c 2022-07-16 thomas }
2163 8a35f56c 2022-07-16 thomas
2164 8a35f56c 2022-07-16 thomas const struct got_error *
2165 8a35f56c 2022-07-16 thomas gotweb_get_time_str(char **repo_age, time_t committer_time, int ref_tm)
2166 8a35f56c 2022-07-16 thomas {
2167 8a35f56c 2022-07-16 thomas struct tm tm;
2168 399ea8e4 2022-07-20 thomas long long diff_time;
2169 8a35f56c 2022-07-16 thomas const char *years = "years ago", *months = "months ago";
2170 8a35f56c 2022-07-16 thomas const char *weeks = "weeks ago", *days = "days ago";
2171 8a35f56c 2022-07-16 thomas const char *hours = "hours ago", *minutes = "minutes ago";
2172 8a35f56c 2022-07-16 thomas const char *seconds = "seconds ago", *now = "right now";
2173 8a35f56c 2022-07-16 thomas char *s;
2174 8a35f56c 2022-07-16 thomas char datebuf[29];
2175 8a35f56c 2022-07-16 thomas
2176 8a35f56c 2022-07-16 thomas *repo_age = NULL;
2177 8a35f56c 2022-07-16 thomas
2178 8a35f56c 2022-07-16 thomas switch (ref_tm) {
2179 8a35f56c 2022-07-16 thomas case TM_DIFF:
2180 8a35f56c 2022-07-16 thomas diff_time = time(NULL) - committer_time;
2181 8a35f56c 2022-07-16 thomas if (diff_time > 60 * 60 * 24 * 365 * 2) {
2182 8a35f56c 2022-07-16 thomas if (asprintf(repo_age, "%lld %s",
2183 8a35f56c 2022-07-16 thomas (diff_time / 60 / 60 / 24 / 365), years) == -1)
2184 8a35f56c 2022-07-16 thomas return got_error_from_errno("asprintf");
2185 8a35f56c 2022-07-16 thomas } else if (diff_time > 60 * 60 * 24 * (365 / 12) * 2) {
2186 8a35f56c 2022-07-16 thomas if (asprintf(repo_age, "%lld %s",
2187 8a35f56c 2022-07-16 thomas (diff_time / 60 / 60 / 24 / (365 / 12)),
2188 8a35f56c 2022-07-16 thomas months) == -1)
2189 8a35f56c 2022-07-16 thomas return got_error_from_errno("asprintf");
2190 8a35f56c 2022-07-16 thomas } else if (diff_time > 60 * 60 * 24 * 7 * 2) {
2191 8a35f56c 2022-07-16 thomas if (asprintf(repo_age, "%lld %s",
2192 8a35f56c 2022-07-16 thomas (diff_time / 60 / 60 / 24 / 7), weeks) == -1)
2193 8a35f56c 2022-07-16 thomas return got_error_from_errno("asprintf");
2194 8a35f56c 2022-07-16 thomas } else if (diff_time > 60 * 60 * 24 * 2) {
2195 8a35f56c 2022-07-16 thomas if (asprintf(repo_age, "%lld %s",
2196 8a35f56c 2022-07-16 thomas (diff_time / 60 / 60 / 24), days) == -1)
2197 8a35f56c 2022-07-16 thomas return got_error_from_errno("asprintf");
2198 8a35f56c 2022-07-16 thomas } else if (diff_time > 60 * 60 * 2) {
2199 8a35f56c 2022-07-16 thomas if (asprintf(repo_age, "%lld %s",
2200 8a35f56c 2022-07-16 thomas (diff_time / 60 / 60), hours) == -1)
2201 8a35f56c 2022-07-16 thomas return got_error_from_errno("asprintf");
2202 8a35f56c 2022-07-16 thomas } else if (diff_time > 60 * 2) {
2203 8a35f56c 2022-07-16 thomas if (asprintf(repo_age, "%lld %s", (diff_time / 60),
2204 8a35f56c 2022-07-16 thomas minutes) == -1)
2205 8a35f56c 2022-07-16 thomas return got_error_from_errno("asprintf");
2206 8a35f56c 2022-07-16 thomas } else if (diff_time > 2) {
2207 8a35f56c 2022-07-16 thomas if (asprintf(repo_age, "%lld %s", diff_time,
2208 8a35f56c 2022-07-16 thomas seconds) == -1)
2209 8a35f56c 2022-07-16 thomas return got_error_from_errno("asprintf");
2210 8a35f56c 2022-07-16 thomas } else {
2211 8a35f56c 2022-07-16 thomas if (asprintf(repo_age, "%s", now) == -1)
2212 8a35f56c 2022-07-16 thomas return got_error_from_errno("asprintf");
2213 8a35f56c 2022-07-16 thomas }
2214 8a35f56c 2022-07-16 thomas break;
2215 8a35f56c 2022-07-16 thomas case TM_LONG:
2216 8a35f56c 2022-07-16 thomas if (gmtime_r(&committer_time, &tm) == NULL)
2217 8a35f56c 2022-07-16 thomas return got_error_from_errno("gmtime_r");
2218 8a35f56c 2022-07-16 thomas
2219 8a35f56c 2022-07-16 thomas s = asctime_r(&tm, datebuf);
2220 8a35f56c 2022-07-16 thomas if (s == NULL)
2221 8a35f56c 2022-07-16 thomas return got_error_from_errno("asctime_r");
2222 8a35f56c 2022-07-16 thomas
2223 8a35f56c 2022-07-16 thomas if (asprintf(repo_age, "%s UTC", datebuf) == -1)
2224 8a35f56c 2022-07-16 thomas return got_error_from_errno("asprintf");
2225 8a35f56c 2022-07-16 thomas break;
2226 8a35f56c 2022-07-16 thomas }
2227 8a35f56c 2022-07-16 thomas return NULL;
2228 3e12c168 2022-07-16 thomas }