tresp.c - quark - quark web server | |
git clone git://git.suckless.org/quark | |
Log | |
Files | |
Refs | |
LICENSE | |
--- | |
tresp.c (2539B) | |
--- | |
1 /* See LICENSE file for copyright and license details. */ | |
2 #include <dirent.h> | |
3 #include <stdio.h> | |
4 #include <stdlib.h> | |
5 #include <string.h> | |
6 #include <sys/stat.h> | |
7 #include <time.h> | |
8 #include <unistd.h> | |
9 | |
10 #include "http.h" | |
11 #include "resp.h" | |
12 #include "util.h" | |
13 | |
14 static int | |
15 compareent(const struct dirent **d1, const struct dirent **d2) | |
16 { | |
17 int v; | |
18 | |
19 v = ((*d2)->d_type == DT_DIR ? 1 : -1) - | |
20 ((*d1)->d_type == DT_DIR ? 1 : -1); | |
21 if (v) { | |
22 return v; | |
23 } | |
24 | |
25 return strcmp((*d1)->d_name, (*d2)->d_name); | |
26 } | |
27 | |
28 static char * | |
29 suffix(int t) | |
30 { | |
31 switch (t) { | |
32 case DT_FIFO: return "|"; | |
33 case DT_DIR: return "/"; | |
34 case DT_LNK: return "@"; | |
35 case DT_SOCK: return "="; | |
36 } | |
37 | |
38 return ""; | |
39 } | |
40 | |
41 enum status | |
42 resp_dir(int fd, const struct response *res) | |
43 { | |
44 enum status ret; | |
45 struct dirent **e; | |
46 size_t i; | |
47 int dirlen; | |
48 char esc[PATH_MAX /* > NAME_MAX */ * 6]; /* strlen("&...;") <= 6… | |
49 | |
50 /* read directory */ | |
51 if ((dirlen = scandir(res->path, &e, NULL, compareent)) < 0) { | |
52 return S_FORBIDDEN; | |
53 } | |
54 | |
55 /* listing */ | |
56 for (i = 0; i < (size_t)dirlen; i++) { | |
57 /* skip hidden files, "." and ".." */ | |
58 if (e[i]->d_name[0] == '.') { | |
59 continue; | |
60 } | |
61 | |
62 /* entry line */ | |
63 html_escape(e[i]->d_name, esc, sizeof(esc)); | |
64 if (dprintf(fd, "<br />\n\t\t<a href=\"%s%s\">%s%s</a>", | |
65 esc, | |
66 (e[i]->d_type == DT_DIR) ? "/" : "", | |
67 esc, | |
68 suffix(e[i]->d_type)) < 0) { | |
69 ret = S_REQUEST_TIMEOUT; | |
70 goto cleanup; | |
71 } | |
72 } | |
73 | |
74 /* listing footer */ | |
75 if (dprintf(fd, "\n\t</body>\n</html>\n") < 0) { | |
76 ret = S_REQUEST_TIMEOUT; | |
77 goto cleanup; | |
78 } | |
79 | |
80 cleanup: | |
81 while (dirlen--) { | |
82 free(e[dirlen]); | |
83 } | |
84 free(e); | |
85 | |
86 return ret; | |
87 } | |
88 | |
89 enum status | |
90 resp_file(int fd, const struct response *res) | |
91 { | |
92 FILE *fp; | |
93 enum status ret = 0; | |
94 ssize_t bread, bwritten; | |
95 size_t remaining; | |
96 static char buf[BUFSIZ], *p; | |
97 | |
98 /* open file */ | |
99 if (!(fp = fopen(res->path, "r"))) { | |
100 ret = S_FORBIDDEN; | |
101 goto cleanup; | |
102 } | |
103 | |
104 /* seek to lower bound */ | |
105 if (fseek(fp, res->file.lower, SEEK_SET)) { | |
106 ret = S_INTERNAL_SERVER_ERROR; | |
107 goto cleanup; | |
108 } | |
109 | |
110 /* write data until upper bound is hit */ | |
111 remaining = res->file.upper - res->file.lower + 1; | |
112 | |
113 while ((bread = fread(buf, 1, MIN(sizeof(buf), | |
114 remaining), fp))) { | |
115 if (bread < 0) { | |
116 ret = S_INTERNAL_SERVER_ERROR; | |
117 goto cleanup; | |
118 } | |
119 remaining -= bread; | |
120 p = buf; | |
121 while (bread > 0) { | |
122 bwritten = write(fd, p, bread); | |
123 if (bwritten <= 0) { | |
124 ret = S_REQUEST_TIMEOUT; | |
125 goto cleanup; | |
126 } | |
127 bread -= bwritten; | |
128 p += bwritten; | |
129 } | |
130 } | |
131 cleanup: | |
132 if (fp) { | |
133 fclose(fp); | |
134 } | |
135 | |
136 return ret; | |
137 } |