tresp.c - quark - quark web server
(HTM) git clone git://git.suckless.org/quark
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) 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 }