Introduction
Introduction Statistics Contact Development Disclaimer Help
data.c - quark - quark web server
git clone git://git.suckless.org/quark
Log
Files
Refs
LICENSE
---
data.c (4933B)
---
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 "data.h"
11 #include "http.h"
12 #include "util.h"
13
14 enum status (* const data_fct[])(const struct response *,
15 struct buffer *, size_t *) = {
16 [RESTYPE_DIRLISTING] = data_prepare_dirlisting_buf,
17 [RESTYPE_ERROR] = data_prepare_error_buf,
18 [RESTYPE_FILE] = data_prepare_file_buf,
19 };
20
21 static int
22 compareent(const struct dirent **d1, const struct dirent **d2)
23 {
24 int v;
25
26 v = ((*d2)->d_type == DT_DIR ? 1 : -1) -
27 ((*d1)->d_type == DT_DIR ? 1 : -1);
28 if (v) {
29 return v;
30 }
31
32 return strcmp((*d1)->d_name, (*d2)->d_name);
33 }
34
35 static char *
36 suffix(int t)
37 {
38 switch (t) {
39 case DT_FIFO: return "|";
40 case DT_DIR: return "/";
41 case DT_LNK: return "@";
42 case DT_SOCK: return "=";
43 }
44
45 return "";
46 }
47
48 static void
49 html_escape(const char *src, char *dst, size_t dst_siz)
50 {
51 const struct {
52 char c;
53 char *s;
54 } escape[] = {
55 { '&', "&amp;" },
56 { '<', "&lt;" },
57 { '>', "&gt;" },
58 { '"', "&quot;" },
59 { '\'', "&#x27;" },
60 };
61 size_t i, j, k, esclen;
62
63 for (i = 0, j = 0; src[i] != '\0'; i++) {
64 for (k = 0; k < LEN(escape); k++) {
65 if (src[i] == escape[k].c) {
66 break;
67 }
68 }
69 if (k == LEN(escape)) {
70 /* no escape char at src[i] */
71 if (j == dst_siz - 1) {
72 /* silent truncation */
73 break;
74 } else {
75 dst[j++] = src[i];
76 }
77 } else {
78 /* escape char at src[i] */
79 esclen = strlen(escape[k].s);
80
81 if (j >= dst_siz - esclen) {
82 /* silent truncation */
83 break;
84 } else {
85 memcpy(&dst[j], escape[k].s, esclen);
86 j += esclen;
87 }
88 }
89 }
90 dst[j] = '\0';
91 }
92
93 enum status
94 data_prepare_dirlisting_buf(const struct response *res,
95 struct buffer *buf, size_t *progress)
96 {
97 enum status s = 0;
98 struct dirent **e;
99 size_t i;
100 int dirlen;
101 char esc[PATH_MAX /* > NAME_MAX */ * 6]; /* strlen("&...;") <= 6…
102
103 /* reset buffer */
104 memset(buf, 0, sizeof(*buf));
105
106 /* read directory */
107 if ((dirlen = scandir(res->internal_path, &e, NULL, compareent))…
108 return S_FORBIDDEN;
109 }
110
111 if (*progress == 0) {
112 /* write listing header (sizeof(esc) >= PATH_MAX) */
113 html_escape(res->path, esc, MIN(PATH_MAX, sizeof(esc)));
114 if (buffer_appendf(buf,
115 "<!DOCTYPE html>\n<html>\n\t<head>"
116 "<title>Index of %s</title></head>\n"
117 "\t<body>\n\t\t<a href=\"..\">..</a>",
118 esc) < 0) {
119 s = S_REQUEST_TIMEOUT;
120 goto cleanup;
121 }
122 }
123
124 /* listing entries */
125 for (i = *progress; i < (size_t)dirlen; i++) {
126 /* skip hidden files, "." and ".." */
127 if (e[i]->d_name[0] == '.') {
128 continue;
129 }
130
131 /* entry line */
132 html_escape(e[i]->d_name, esc, sizeof(esc));
133 if (buffer_appendf(buf,
134 "<br />\n\t\t<a href=\"%s%s\">%s%s</a…
135 esc,
136 (e[i]->d_type == DT_DIR) ? "/" : "",
137 esc,
138 suffix(e[i]->d_type))) {
139 /* buffer full */
140 break;
141 }
142 }
143 *progress = i;
144
145 if (*progress == (size_t)dirlen) {
146 /* listing footer */
147 if (buffer_appendf(buf, "\n\t</body>\n</html>\n") < 0) {
148 s = S_REQUEST_TIMEOUT;
149 goto cleanup;
150 }
151 (*progress)++;
152 }
153
154 cleanup:
155 while (dirlen--) {
156 free(e[dirlen]);
157 }
158 free(e);
159
160 return s;
161 }
162
163 enum status
164 data_prepare_error_buf(const struct response *res, struct buffer *buf,
165 size_t *progress)
166 {
167 /* reset buffer */
168 memset(buf, 0, sizeof(*buf));
169
170 if (*progress == 0) {
171 /* write error body */
172 if (buffer_appendf(buf,
173 "<!DOCTYPE html>\n<html>\n\t<head>\n"
174 "\t\t<title>%d %s</title>\n\t</head>\…
175 "\t<body>\n\t\t<h1>%d %s</h1>\n"
176 "\t</body>\n</html>\n",
177 res->status, status_str[res->status],
178 res->status, status_str[res->status])…
179 return S_INTERNAL_SERVER_ERROR;
180 }
181 (*progress)++;
182 }
183
184 return 0;
185 }
186
187 enum status
188 data_prepare_file_buf(const struct response *res, struct buffer *buf,
189 size_t *progress)
190 {
191 FILE *fp;
192 enum status s = 0;
193 ssize_t r;
194 size_t remaining;
195
196 /* reset buffer */
197 memset(buf, 0, sizeof(*buf));
198
199 /* open file */
200 if (!(fp = fopen(res->internal_path, "r"))) {
201 s = S_FORBIDDEN;
202 goto cleanup;
203 }
204
205 /* seek to lower bound + progress */
206 if (fseek(fp, res->file.lower + *progress, SEEK_SET)) {
207 s = S_INTERNAL_SERVER_ERROR;
208 goto cleanup;
209 }
210
211 /* read data into buf */
212 remaining = res->file.upper - res->file.lower + 1 - *progress;
213 while ((r = fread(buf->data + buf->len, 1,
214 MIN(sizeof(buf->data) - buf->len,
215 remaining), fp))) {
216 if (r < 0) {
217 s = S_INTERNAL_SERVER_ERROR;
218 goto cleanup;
219 }
220 buf->len += r;
221 *progress += r;
222 remaining -= r;
223 }
224
225 cleanup:
226 if (fp) {
227 fclose(fp);
228 }
229
230 return s;
231 }
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.