0599e899f73d914ad904b21601c1b4b6054fa43b
[citadel.git] / webcit-ng / server / static.c
1 // Output static content
2 //
3 // Copyright (c) 1996-2022 by the citadel.org team
4 //
5 // This program is open source software.  Use, duplication, or
6 // disclosure is subject to the GNU General Public License v3.
7
8 #include "webcit.h"
9
10
11 // Called from perform_request() to handle static content.
12 void output_static(struct http_transaction *h) {
13         char filename[PATH_MAX];
14         struct stat statbuf;
15
16         syslog(LOG_DEBUG, "static: %s", h->url);
17
18         if (!strncasecmp(h->url, "/ctdl/s/", 8)) {
19                 snprintf(filename, sizeof filename, "static/%s", &h->url[8]);
20         }
21         else if (!strncasecmp(h->url, "/.well-known/", 13)) {
22                 snprintf(filename, sizeof filename, "static/.well-known/%s", &h->url[13]);
23         }
24         else if (!strcasecmp(h->url, "/favicon.ico")) {
25                 snprintf(filename, sizeof filename, "static/images/favicon.ico");
26         }
27         else {
28                 do_404(h);
29                 return;
30         }
31
32         if (strstr(filename, "../")) {          // 100% guaranteed attacker.
33                 do_404(h);                      // Die in a car fire.
34                 return;
35         }
36
37         FILE *fp = fopen(filename, "r");        // Try to open the requested file.
38         if (fp == NULL) {
39                 syslog(LOG_DEBUG, "%s: %s", filename, strerror(errno));
40                 do_404(h);
41                 return;
42         }
43
44         fstat(fileno(fp), &statbuf);
45         h->response_body_length = statbuf.st_size;
46         h->response_body = malloc(h->response_body_length);
47         if (h->response_body != NULL) {
48                 fread(h->response_body, h->response_body_length, 1, fp);
49         }
50         else {
51                 h->response_body_length = 0;
52         }
53         fclose(fp);                             // Content is now in memory.
54
55         h->response_code = 200;
56         h->response_string = strdup("OK");
57         add_response_header(h, strdup("Content-type"), strdup(GuessMimeByFilename(filename, strlen(filename))));
58
59         char *datestring = http_datestring(statbuf.st_mtime);
60         if (datestring) {
61                 add_response_header(h, strdup("Last-Modified"), datestring);
62         }
63 }