summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (show whitespace changes)
-rw-r--r--Makefile4
-rw-r--r--cgit.c5
-rw-r--r--html.c2
-rw-r--r--ui-shared.c2
4 files changed, 7 insertions, 6 deletions
diff --git a/Makefile b/Makefile
index a988751..14b4df4 100644
--- a/Makefile
+++ b/Makefile
@@ -1,49 +1,49 @@
1CGIT_VERSION = v0.8.3.4 1CGIT_VERSION = v0.8.3.5
2CGIT_SCRIPT_NAME = cgit.cgi 2CGIT_SCRIPT_NAME = cgit.cgi
3CGIT_SCRIPT_PATH = /var/www/htdocs/cgit 3CGIT_SCRIPT_PATH = /var/www/htdocs/cgit
4CGIT_DATA_PATH = $(CGIT_SCRIPT_PATH) 4CGIT_DATA_PATH = $(CGIT_SCRIPT_PATH)
5CGIT_CONFIG = /etc/cgitrc 5CGIT_CONFIG = /etc/cgitrc
6CACHE_ROOT = /var/cache/cgit 6CACHE_ROOT = /var/cache/cgit
7prefix = /usr 7prefix = /usr
8libdir = $(prefix)/lib 8libdir = $(prefix)/lib
9filterdir = $(libdir)/cgit/filters 9filterdir = $(libdir)/cgit/filters
10docdir = $(prefix)/share/doc/cgit 10docdir = $(prefix)/share/doc/cgit
11htmldir = $(docdir) 11htmldir = $(docdir)
12pdfdir = $(docdir) 12pdfdir = $(docdir)
13mandir = $(prefix)/share/man 13mandir = $(prefix)/share/man
14SHA1_HEADER = <openssl/sha.h> 14SHA1_HEADER = <openssl/sha.h>
15GIT_VER = 1.7.4 15GIT_VER = 1.7.4
16GIT_URL = http://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.bz2 16GIT_URL = http://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.bz2
17INSTALL = install 17INSTALL = install
18MAN5_TXT = $(wildcard *.5.txt) 18MAN5_TXT = $(wildcard *.5.txt)
19MAN_TXT = $(MAN5_TXT) 19MAN_TXT = $(MAN5_TXT)
20DOC_MAN5 = $(patsubst %.txt,%,$(MAN5_TXT)) 20DOC_MAN5 = $(patsubst %.txt,%,$(MAN5_TXT))
21DOC_HTML = $(patsubst %.txt,%.html,$(MAN_TXT)) 21DOC_HTML = $(patsubst %.txt,%.html,$(MAN_TXT))
22DOC_PDF = $(patsubst %.txt,%.pdf,$(MAN_TXT)) 22DOC_PDF = $(patsubst %.txt,%.pdf,$(MAN_TXT))
23 23
24# Define NO_STRCASESTR if you don't have strcasestr. 24# Define NO_STRCASESTR if you don't have strcasestr.
25# 25#
26# Define NO_OPENSSL to disable linking with OpenSSL and use bundled SHA1 26# Define NO_OPENSSL to disable linking with OpenSSL and use bundled SHA1
27# implementation (slower). 27# implementation (slower).
28# 28#
29# Define NEEDS_LIBICONV if linking with libc is not enough (eg. Darwin). 29# Define NEEDS_LIBICONV if linking with libc is not enough (eg. Darwin).
30# 30#
31# Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.) 31# Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.)
32# do not support the 'size specifiers' introduced by C99, namely ll, hh, 32# do not support the 'size specifiers' introduced by C99, namely ll, hh,
33# j, z, t. (representing long long int, char, intmax_t, size_t, ptrdiff_t). 33# j, z, t. (representing long long int, char, intmax_t, size_t, ptrdiff_t).
34# some C compilers supported these specifiers prior to C99 as an extension. 34# some C compilers supported these specifiers prior to C99 as an extension.
35# 35#
36 36
37#-include config.mak 37#-include config.mak
38 38
39# 39#
40# Platform specific tweaks 40# Platform specific tweaks
41# 41#
42 42
43uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') 43uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
44uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not') 44uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not')
45uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not') 45uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not')
46 46
47ifeq ($(uname_O),Cygwin) 47ifeq ($(uname_O),Cygwin)
48 NO_STRCASESTR = YesPlease 48 NO_STRCASESTR = YesPlease
49 NEEDS_LIBICONV = YesPlease 49 NEEDS_LIBICONV = YesPlease
@@ -196,49 +196,49 @@ install-html: doc-html
196install-pdf: doc-pdf 196install-pdf: doc-pdf
197 $(INSTALL) -m 0755 -d $(DESTDIR)$(pdfdir) 197 $(INSTALL) -m 0755 -d $(DESTDIR)$(pdfdir)
198 $(INSTALL) -m 0644 $(DOC_PDF) $(DESTDIR)$(pdfdir) 198 $(INSTALL) -m 0644 $(DOC_PDF) $(DESTDIR)$(pdfdir)
199 199
200uninstall: 200uninstall:
201 rm -f $(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME) 201 rm -f $(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME)
202 rm -f $(CGIT_DATA_PATH)/cgit.css 202 rm -f $(CGIT_DATA_PATH)/cgit.css
203 rm -f $(CGIT_DATA_PATH)/cgit.png 203 rm -f $(CGIT_DATA_PATH)/cgit.png
204 204
205uninstall-doc: uninstall-man uninstall-html uninstall-pdf 205uninstall-doc: uninstall-man uninstall-html uninstall-pdf
206 206
207uninstall-man: 207uninstall-man:
208 @for i in $(DOC_MAN5); do \ 208 @for i in $(DOC_MAN5); do \
209 rm -fv $(DESTDIR)$(mandir)/man5/$$i; \ 209 rm -fv $(DESTDIR)$(mandir)/man5/$$i; \
210 done 210 done
211 211
212uninstall-html: 212uninstall-html:
213 @for i in $(DOC_HTML); do \ 213 @for i in $(DOC_HTML); do \
214 rm -fv $(DESTDIR)$(htmldir)/$$i; \ 214 rm -fv $(DESTDIR)$(htmldir)/$$i; \
215 done 215 done
216 216
217uninstall-pdf: 217uninstall-pdf:
218 @for i in $(DOC_PDF); do \ 218 @for i in $(DOC_PDF); do \
219 rm -fv $(DESTDIR)$(pdfdir)/$$i; \ 219 rm -fv $(DESTDIR)$(pdfdir)/$$i; \
220 done 220 done
221 221
222doc: doc-man doc-html doc-pdf 222doc: doc-man doc-html doc-pdf
223doc-man: doc-man5 223doc-man: doc-man5
224doc-man5: $(DOC_MAN5) 224doc-man5: $(DOC_MAN5)
225doc-html: $(DOC_HTML) 225doc-html: $(DOC_HTML)
226doc-pdf: $(DOC_PDF) 226doc-pdf: $(DOC_PDF)
227 227
228%.5 : %.5.txt 228%.5 : %.5.txt
229 a2x -f manpage $< 229 a2x -f manpage $<
230 230
231$(DOC_HTML): %.html : %.txt 231$(DOC_HTML): %.html : %.txt
232 a2x -f xhtml --stylesheet=cgit-doc.css $< 232 a2x -f xhtml --stylesheet=cgit-doc.css $<
233 233
234$(DOC_PDF): %.pdf : %.txt 234$(DOC_PDF): %.pdf : %.txt
235 a2x -f pdf cgitrc.5.txt 235 a2x -f pdf cgitrc.5.txt
236 236
237clean: clean-doc 237clean: clean-doc
238 rm -f cgit VERSION *.o *.d 238 rm -f cgit VERSION *.o *.d
239 239
240clean-doc: 240clean-doc:
241 rm -f cgitrc.5 cgitrc.5.html cgitrc.5.pdf cgitrc.5.xml cgitrc.5.fo 241 rm -f cgitrc.5 cgitrc.5.html cgitrc.5.pdf cgitrc.5.xml cgitrc.5.fo
242 242
243get-git: 243get-git:
244 curl $(GIT_URL) | tar -xj && rm -rf git && mv git-$(GIT_VER) git 244 curl $(GIT_URL) | tar -xjf - && rm -rf git && mv git-$(GIT_VER) git
diff --git a/cgit.c b/cgit.c
index 916feb4..f4dd6ef 100644
--- a/cgit.c
+++ b/cgit.c
@@ -707,85 +707,86 @@ static void cgit_parse_args(int argc, const char **argv)
707 */ 707 */
708 ctx.cfg.snapshots = 0xFF; 708 ctx.cfg.snapshots = 0xFF;
709 scan++; 709 scan++;
710 scan_tree(argv[i] + 12, repo_config); 710 scan_tree(argv[i] + 12, repo_config);
711 } 711 }
712 } 712 }
713 if (scan) { 713 if (scan) {
714 qsort(cgit_repolist.repos, cgit_repolist.count, 714 qsort(cgit_repolist.repos, cgit_repolist.count,
715 sizeof(struct cgit_repo), cmp_repos); 715 sizeof(struct cgit_repo), cmp_repos);
716 print_repolist(stdout, &cgit_repolist, 0); 716 print_repolist(stdout, &cgit_repolist, 0);
717 exit(0); 717 exit(0);
718 } 718 }
719} 719}
720 720
721static int calc_ttl() 721static int calc_ttl()
722{ 722{
723 if (!ctx.repo) 723 if (!ctx.repo)
724 return ctx.cfg.cache_root_ttl; 724 return ctx.cfg.cache_root_ttl;
725 725
726 if (!ctx.qry.page) 726 if (!ctx.qry.page)
727 return ctx.cfg.cache_repo_ttl; 727 return ctx.cfg.cache_repo_ttl;
728 728
729 if (ctx.qry.has_symref) 729 if (ctx.qry.has_symref)
730 return ctx.cfg.cache_dynamic_ttl; 730 return ctx.cfg.cache_dynamic_ttl;
731 731
732 if (ctx.qry.has_sha1) 732 if (ctx.qry.has_sha1)
733 return ctx.cfg.cache_static_ttl; 733 return ctx.cfg.cache_static_ttl;
734 734
735 return ctx.cfg.cache_repo_ttl; 735 return ctx.cfg.cache_repo_ttl;
736} 736}
737 737
738int main(int argc, const char **argv) 738int main(int argc, const char **argv)
739{ 739{
740 const char *path; 740 const char *path;
741 char *qry; 741 char *qry;
742 int err, ttl; 742 int err, ttl;
743 743
744 prepare_context(&ctx); 744 prepare_context(&ctx);
745 cgit_repolist.length = 0; 745 cgit_repolist.length = 0;
746 cgit_repolist.count = 0; 746 cgit_repolist.count = 0;
747 cgit_repolist.repos = NULL; 747 cgit_repolist.repos = NULL;
748 748
749 cgit_parse_args(argc, argv); 749 cgit_parse_args(argc, argv);
750 parse_configfile(expand_macros(ctx.env.cgit_config), config_cb); 750 parse_configfile(expand_macros(ctx.env.cgit_config), config_cb);
751 ctx.repo = NULL; 751 ctx.repo = NULL;
752 http_parse_querystring(ctx.qry.raw, querystring_cb); 752 http_parse_querystring(ctx.qry.raw, querystring_cb);
753 753
754 /* If virtual-root isn't specified in cgitrc, lets pretend 754 /* If virtual-root isn't specified in cgitrc, lets pretend
755 * that virtual-root equals SCRIPT_NAME. 755 * that virtual-root equals SCRIPT_NAME, minus any possibly
756 * trailing slashes.
756 */ 757 */
757 if (!ctx.cfg.virtual_root) 758 if (!ctx.cfg.virtual_root)
758 ctx.cfg.virtual_root = ctx.cfg.script_name; 759 ctx.cfg.virtual_root = trim_end(ctx.cfg.script_name, '/');
759 760
760 /* If no url parameter is specified on the querystring, lets 761 /* If no url parameter is specified on the querystring, lets
761 * use PATH_INFO as url. This allows cgit to work with virtual 762 * use PATH_INFO as url. This allows cgit to work with virtual
762 * urls without the need for rewriterules in the webserver (as 763 * urls without the need for rewriterules in the webserver (as
763 * long as PATH_INFO is included in the cache lookup key). 764 * long as PATH_INFO is included in the cache lookup key).
764 */ 765 */
765 path = ctx.env.path_info; 766 path = ctx.env.path_info;
766 if (!ctx.qry.url && path) { 767 if (!ctx.qry.url && path) {
767 if (path[0] == '/') 768 if (path[0] == '/')
768 path++; 769 path++;
769 ctx.qry.url = xstrdup(path); 770 ctx.qry.url = xstrdup(path);
770 if (ctx.qry.raw) { 771 if (ctx.qry.raw) {
771 qry = ctx.qry.raw; 772 qry = ctx.qry.raw;
772 ctx.qry.raw = xstrdup(fmt("%s?%s", path, qry)); 773 ctx.qry.raw = xstrdup(fmt("%s?%s", path, qry));
773 free(qry); 774 free(qry);
774 } else 775 } else
775 ctx.qry.raw = xstrdup(ctx.qry.url); 776 ctx.qry.raw = xstrdup(ctx.qry.url);
776 cgit_parse_url(ctx.qry.url); 777 cgit_parse_url(ctx.qry.url);
777 } 778 }
778 779
779 ttl = calc_ttl(); 780 ttl = calc_ttl();
780 ctx.page.expires += ttl*60; 781 ctx.page.expires += ttl*60;
781 if (ctx.env.request_method && !strcmp(ctx.env.request_method, "HEAD")) 782 if (ctx.env.request_method && !strcmp(ctx.env.request_method, "HEAD"))
782 ctx.cfg.nocache = 1; 783 ctx.cfg.nocache = 1;
783 if (ctx.cfg.nocache) 784 if (ctx.cfg.nocache)
784 ctx.cfg.cache_size = 0; 785 ctx.cfg.cache_size = 0;
785 err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root, 786 err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root,
786 ctx.qry.raw, ttl, process_request, &ctx); 787 ctx.qry.raw, ttl, process_request, &ctx);
787 if (err) 788 if (err)
788 cgit_print_error(fmt("Error processing page: %s (%d)", 789 cgit_print_error(fmt("Error processing page: %s (%d)",
789 strerror(err), err)); 790 strerror(err), err));
790 return err; 791 return err;
791} 792}
diff --git a/html.c b/html.c
index a1fe87d..a60bc13 100644
--- a/html.c
+++ b/html.c
@@ -232,89 +232,89 @@ void html_link_close(void)
232} 232}
233 233
234void html_fileperm(unsigned short mode) 234void html_fileperm(unsigned short mode)
235{ 235{
236 htmlf("%c%c%c", (mode & 4 ? 'r' : '-'), 236 htmlf("%c%c%c", (mode & 4 ? 'r' : '-'),
237 (mode & 2 ? 'w' : '-'), (mode & 1 ? 'x' : '-')); 237 (mode & 2 ? 'w' : '-'), (mode & 1 ? 'x' : '-'));
238} 238}
239 239
240int html_include(const char *filename) 240int html_include(const char *filename)
241{ 241{
242 FILE *f; 242 FILE *f;
243 char buf[4096]; 243 char buf[4096];
244 size_t len; 244 size_t len;
245 245
246 if (!(f = fopen(filename, "r"))) { 246 if (!(f = fopen(filename, "r"))) {
247 fprintf(stderr, "[cgit] Failed to include file %s: %s (%d).\n", 247 fprintf(stderr, "[cgit] Failed to include file %s: %s (%d).\n",
248 filename, strerror(errno), errno); 248 filename, strerror(errno), errno);
249 return -1; 249 return -1;
250 } 250 }
251 while((len = fread(buf, 1, 4096, f)) > 0) 251 while((len = fread(buf, 1, 4096, f)) > 0)
252 html_raw(buf, len); 252 html_raw(buf, len);
253 fclose(f); 253 fclose(f);
254 return 0; 254 return 0;
255} 255}
256 256
257int hextoint(char c) 257int hextoint(char c)
258{ 258{
259 if (c >= 'a' && c <= 'f') 259 if (c >= 'a' && c <= 'f')
260 return 10 + c - 'a'; 260 return 10 + c - 'a';
261 else if (c >= 'A' && c <= 'F') 261 else if (c >= 'A' && c <= 'F')
262 return 10 + c - 'A'; 262 return 10 + c - 'A';
263 else if (c >= '0' && c <= '9') 263 else if (c >= '0' && c <= '9')
264 return c - '0'; 264 return c - '0';
265 else 265 else
266 return -1; 266 return -1;
267} 267}
268 268
269char *convert_query_hexchar(char *txt) 269char *convert_query_hexchar(char *txt)
270{ 270{
271 int d1, d2, n; 271 int d1, d2, n;
272 n = strlen(txt); 272 n = strlen(txt);
273 if (n < 3) { 273 if (n < 3) {
274 *txt = '\0'; 274 *txt = '\0';
275 return txt-1; 275 return txt-1;
276 } 276 }
277 d1 = hextoint(*(txt+1)); 277 d1 = hextoint(*(txt+1));
278 d2 = hextoint(*(txt+2)); 278 d2 = hextoint(*(txt+2));
279 if (d1<0 || d2<0) { 279 if (d1<0 || d2<0) {
280 memmove(txt, txt+3, n-3); 280 memmove(txt, txt+3, n-2);
281 return txt-1; 281 return txt-1;
282 } else { 282 } else {
283 *txt = d1 * 16 + d2; 283 *txt = d1 * 16 + d2;
284 memmove(txt+1, txt+3, n-2); 284 memmove(txt+1, txt+3, n-2);
285 return txt; 285 return txt;
286 } 286 }
287} 287}
288 288
289int http_parse_querystring(const char *txt_, void (*fn)(const char *name, const char *value)) 289int http_parse_querystring(const char *txt_, void (*fn)(const char *name, const char *value))
290{ 290{
291 char *t, *txt, *value = NULL, c; 291 char *t, *txt, *value = NULL, c;
292 292
293 if (!txt_) 293 if (!txt_)
294 return 0; 294 return 0;
295 295
296 t = txt = strdup(txt_); 296 t = txt = strdup(txt_);
297 if (t == NULL) { 297 if (t == NULL) {
298 printf("Out of memory\n"); 298 printf("Out of memory\n");
299 exit(1); 299 exit(1);
300 } 300 }
301 while((c=*t) != '\0') { 301 while((c=*t) != '\0') {
302 if (c=='=') { 302 if (c=='=') {
303 *t = '\0'; 303 *t = '\0';
304 value = t+1; 304 value = t+1;
305 } else if (c=='+') { 305 } else if (c=='+') {
306 *t = ' '; 306 *t = ' ';
307 } else if (c=='%') { 307 } else if (c=='%') {
308 t = convert_query_hexchar(t); 308 t = convert_query_hexchar(t);
309 } else if (c=='&') { 309 } else if (c=='&') {
310 *t = '\0'; 310 *t = '\0';
311 (*fn)(txt, value); 311 (*fn)(txt, value);
312 txt = t+1; 312 txt = t+1;
313 value = NULL; 313 value = NULL;
314 } 314 }
315 t++; 315 t++;
316 } 316 }
317 if (t!=txt) 317 if (t!=txt)
318 (*fn)(txt, value); 318 (*fn)(txt, value);
319 return 0; 319 return 0;
320} 320}
diff --git a/ui-shared.c b/ui-shared.c
index 7efae7a..5aa9119 100644
--- a/ui-shared.c
+++ b/ui-shared.c
@@ -529,97 +529,97 @@ void cgit_print_age(time_t t, time_t max_relative, const char *format)
529 529
530 if (secs > max_relative && max_relative >= 0) { 530 if (secs > max_relative && max_relative >= 0) {
531 cgit_print_date(t, format, ctx.cfg.local_time); 531 cgit_print_date(t, format, ctx.cfg.local_time);
532 return; 532 return;
533 } 533 }
534 534
535 if (secs < TM_HOUR * 2) { 535 if (secs < TM_HOUR * 2) {
536 htmlf("<span class='age-mins'>%.0f min.</span>", 536 htmlf("<span class='age-mins'>%.0f min.</span>",
537 secs * 1.0 / TM_MIN); 537 secs * 1.0 / TM_MIN);
538 return; 538 return;
539 } 539 }
540 if (secs < TM_DAY * 2) { 540 if (secs < TM_DAY * 2) {
541 htmlf("<span class='age-hours'>%.0f hours</span>", 541 htmlf("<span class='age-hours'>%.0f hours</span>",
542 secs * 1.0 / TM_HOUR); 542 secs * 1.0 / TM_HOUR);
543 return; 543 return;
544 } 544 }
545 if (secs < TM_WEEK * 2) { 545 if (secs < TM_WEEK * 2) {
546 htmlf("<span class='age-days'>%.0f days</span>", 546 htmlf("<span class='age-days'>%.0f days</span>",
547 secs * 1.0 / TM_DAY); 547 secs * 1.0 / TM_DAY);
548 return; 548 return;
549 } 549 }
550 if (secs < TM_MONTH * 2) { 550 if (secs < TM_MONTH * 2) {
551 htmlf("<span class='age-weeks'>%.0f weeks</span>", 551 htmlf("<span class='age-weeks'>%.0f weeks</span>",
552 secs * 1.0 / TM_WEEK); 552 secs * 1.0 / TM_WEEK);
553 return; 553 return;
554 } 554 }
555 if (secs < TM_YEAR * 2) { 555 if (secs < TM_YEAR * 2) {
556 htmlf("<span class='age-months'>%.0f months</span>", 556 htmlf("<span class='age-months'>%.0f months</span>",
557 secs * 1.0 / TM_MONTH); 557 secs * 1.0 / TM_MONTH);
558 return; 558 return;
559 } 559 }
560 htmlf("<span class='age-years'>%.0f years</span>", 560 htmlf("<span class='age-years'>%.0f years</span>",
561 secs * 1.0 / TM_YEAR); 561 secs * 1.0 / TM_YEAR);
562} 562}
563 563
564void cgit_print_http_headers(struct cgit_context *ctx) 564void cgit_print_http_headers(struct cgit_context *ctx)
565{ 565{
566 if (ctx->env.no_http && !strcmp(ctx->env.no_http, "1")) 566 if (ctx->env.no_http && !strcmp(ctx->env.no_http, "1"))
567 return; 567 return;
568 568
569 if (ctx->page.status) 569 if (ctx->page.status)
570 htmlf("Status: %d %s\n", ctx->page.status, ctx->page.statusmsg); 570 htmlf("Status: %d %s\n", ctx->page.status, ctx->page.statusmsg);
571 if (ctx->page.mimetype && ctx->page.charset) 571 if (ctx->page.mimetype && ctx->page.charset)
572 htmlf("Content-Type: %s; charset=%s\n", ctx->page.mimetype, 572 htmlf("Content-Type: %s; charset=%s\n", ctx->page.mimetype,
573 ctx->page.charset); 573 ctx->page.charset);
574 else if (ctx->page.mimetype) 574 else if (ctx->page.mimetype)
575 htmlf("Content-Type: %s\n", ctx->page.mimetype); 575 htmlf("Content-Type: %s\n", ctx->page.mimetype);
576 if (ctx->page.size) 576 if (ctx->page.size)
577 htmlf("Content-Length: %ld\n", ctx->page.size); 577 htmlf("Content-Length: %zd\n", ctx->page.size);
578 if (ctx->page.filename) 578 if (ctx->page.filename)
579 htmlf("Content-Disposition: inline; filename=\"%s\"\n", 579 htmlf("Content-Disposition: inline; filename=\"%s\"\n",
580 ctx->page.filename); 580 ctx->page.filename);
581 htmlf("Last-Modified: %s\n", http_date(ctx->page.modified)); 581 htmlf("Last-Modified: %s\n", http_date(ctx->page.modified));
582 htmlf("Expires: %s\n", http_date(ctx->page.expires)); 582 htmlf("Expires: %s\n", http_date(ctx->page.expires));
583 if (ctx->page.etag) 583 if (ctx->page.etag)
584 htmlf("ETag: \"%s\"\n", ctx->page.etag); 584 htmlf("ETag: \"%s\"\n", ctx->page.etag);
585 html("\n"); 585 html("\n");
586 if (ctx->env.request_method && !strcmp(ctx->env.request_method, "HEAD")) 586 if (ctx->env.request_method && !strcmp(ctx->env.request_method, "HEAD"))
587 exit(0); 587 exit(0);
588} 588}
589 589
590void cgit_print_docstart(struct cgit_context *ctx) 590void cgit_print_docstart(struct cgit_context *ctx)
591{ 591{
592 if (ctx->cfg.embedded) { 592 if (ctx->cfg.embedded) {
593 if (ctx->cfg.header) 593 if (ctx->cfg.header)
594 html_include(ctx->cfg.header); 594 html_include(ctx->cfg.header);
595 return; 595 return;
596 } 596 }
597 597
598 char *host = cgit_hosturl(); 598 char *host = cgit_hosturl();
599 html(cgit_doctype); 599 html(cgit_doctype);
600 html("<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n"); 600 html("<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n");
601 html("<head>\n"); 601 html("<head>\n");
602 html("<title>"); 602 html("<title>");
603 html_txt(ctx->page.title); 603 html_txt(ctx->page.title);
604 html("</title>\n"); 604 html("</title>\n");
605 htmlf("<meta name='generator' content='cgit %s'/>\n", cgit_version); 605 htmlf("<meta name='generator' content='cgit %s'/>\n", cgit_version);
606 if (ctx->cfg.robots && *ctx->cfg.robots) 606 if (ctx->cfg.robots && *ctx->cfg.robots)
607 htmlf("<meta name='robots' content='%s'/>\n", ctx->cfg.robots); 607 htmlf("<meta name='robots' content='%s'/>\n", ctx->cfg.robots);
608 html("<link rel='stylesheet' type='text/css' href='"); 608 html("<link rel='stylesheet' type='text/css' href='");
609 html_attr(ctx->cfg.css); 609 html_attr(ctx->cfg.css);
610 html("'/>\n"); 610 html("'/>\n");
611 if (ctx->cfg.favicon) { 611 if (ctx->cfg.favicon) {
612 html("<link rel='shortcut icon' href='"); 612 html("<link rel='shortcut icon' href='");
613 html_attr(ctx->cfg.favicon); 613 html_attr(ctx->cfg.favicon);
614 html("'/>\n"); 614 html("'/>\n");
615 } 615 }
616 if (host && ctx->repo) { 616 if (host && ctx->repo) {
617 html("<link rel='alternate' title='Atom feed' href='"); 617 html("<link rel='alternate' title='Atom feed' href='");
618 html(cgit_httpscheme()); 618 html(cgit_httpscheme());
619 html_attr(cgit_hosturl()); 619 html_attr(cgit_hosturl());
620 html_attr(cgit_fileurl(ctx->repo->url, "atom", ctx->qry.vpath, 620 html_attr(cgit_fileurl(ctx->repo->url, "atom", ctx->qry.vpath,
621 fmt("h=%s", ctx->qry.head))); 621 fmt("h=%s", ctx->qry.head)));
622 html("' type='application/atom+xml'/>\n"); 622 html("' type='application/atom+xml'/>\n");
623 } 623 }
624 if (ctx->cfg.head_include) 624 if (ctx->cfg.head_include)
625 html_include(ctx->cfg.head_include); 625 html_include(ctx->cfg.head_include);