Mercurial > paster
comparison http.c @ 1:836a698946f8
pasterd: add basic routes
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 04 Feb 2020 16:44:43 +0100 |
parents | |
children | 65607ae124b1 |
comparison
equal
deleted
inserted
replaced
0:15a06aa20298 | 1:836a698946f8 |
---|---|
1 /* | |
2 * http.c -- HTTP parsing and rendering | |
3 * | |
4 * Copyright (c) 2020 David Demelier <markand@malikania.fr> | |
5 * | |
6 * Permission to use, copy, modify, and/or distribute this software for any | |
7 * purpose with or without fee is hereby granted, provided that the above | |
8 * copyright notice and this permission notice appear in all copies. | |
9 * | |
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
17 */ | |
18 | |
19 #include <sys/types.h> | |
20 #include <assert.h> | |
21 #include <limits.h> | |
22 #include <stdarg.h> | |
23 #include <stdint.h> | |
24 #include <stdio.h> | |
25 #include <stdlib.h> | |
26 #include <unistd.h> | |
27 | |
28 #include <kcgi.h> | |
29 | |
30 #include "config.h" | |
31 #include "database.h" | |
32 #include "http.h" | |
33 #include "log.h" | |
34 #include "paste.h" | |
35 #include "util.h" | |
36 | |
37 static void page_index(struct kreq *); | |
38 static void page_new(struct kreq *); | |
39 static void page_fork(struct kreq *); | |
40 static void page_paste(struct kreq *); | |
41 static void page_about(struct kreq *); | |
42 static void page_download(struct kreq *); | |
43 | |
44 enum page { | |
45 PAGE_INDEX, | |
46 PAGE_NEW, | |
47 PAGE_FORK, | |
48 PAGE_PASTE, | |
49 PAGE_ABOUT, | |
50 PAGE_DOWNLOAD, | |
51 PAGE_LAST /* Not used. */ | |
52 }; | |
53 | |
54 static const char *pages[] = { | |
55 [PAGE_INDEX] = "", | |
56 [PAGE_NEW] = "new", | |
57 [PAGE_FORK] = "fork", | |
58 [PAGE_PASTE] = "paste", | |
59 [PAGE_ABOUT] = "about", | |
60 [PAGE_DOWNLOAD] = "download", | |
61 }; | |
62 | |
63 static void (*handlers[])(struct kreq *req) = { | |
64 [PAGE_INDEX] = page_index, | |
65 [PAGE_NEW] = page_new, | |
66 [PAGE_FORK] = page_fork, | |
67 [PAGE_PASTE] = page_paste, | |
68 [PAGE_ABOUT] = page_about, | |
69 [PAGE_DOWNLOAD] = page_download | |
70 }; | |
71 | |
72 struct tmpl_index { | |
73 struct kreq *req; | |
74 struct paste pastes[10]; | |
75 size_t count; | |
76 size_t current; | |
77 }; | |
78 | |
79 struct tmpl_paste { | |
80 struct kreq *req; | |
81 struct paste paste; | |
82 }; | |
83 | |
84 static const char * | |
85 template(const char *filename) | |
86 { | |
87 /* Build path to the template file. */ | |
88 static char path[PATH_MAX]; | |
89 | |
90 snprintf(path, sizeof (path), "%s/%s", config.themedir, filename); | |
91 | |
92 return path; | |
93 } | |
94 | |
95 static int | |
96 tmpl_paste(size_t index, void *arg) | |
97 { | |
98 struct tmpl_paste *data = arg; | |
99 struct paste *paste = &data->paste; | |
100 | |
101 switch (index) { | |
102 case 0: | |
103 khttp_puts(data->req, paste->uuid); | |
104 break; | |
105 case 1: | |
106 khttp_puts(data->req, paste->title); | |
107 break; | |
108 case 2: | |
109 khttp_puts(data->req, paste->author); | |
110 break; | |
111 case 3: | |
112 khttp_puts(data->req, paste->language); | |
113 break; | |
114 case 4: | |
115 khttp_puts(data->req, paste->code); | |
116 break; | |
117 case 5: | |
118 /* TODO: timestamp here. */ | |
119 khttp_puts(data->req, "TODO"); | |
120 break; | |
121 case 6: | |
122 khttp_puts(data->req, bprintf("%s", paste->visible ? "Yes" : "No")); | |
123 break; | |
124 case 7: | |
125 /* TODO: convert time left. */ | |
126 khttp_puts(data->req, "TODO"); | |
127 break; | |
128 default: | |
129 break; | |
130 } | |
131 | |
132 return true; | |
133 } | |
134 | |
135 static int | |
136 tmpl_index_pastes(size_t index, void *arg) | |
137 { | |
138 struct tmpl_index *data = arg; | |
139 struct paste *paste = &data->pastes[data->current]; | |
140 | |
141 switch (index) { | |
142 case 0: | |
143 khttp_puts(data->req, paste->uuid); | |
144 break; | |
145 case 1: | |
146 khttp_puts(data->req, paste->title); | |
147 break; | |
148 case 2: | |
149 khttp_puts(data->req, paste->author); | |
150 break; | |
151 case 3: | |
152 khttp_puts(data->req, paste->language); | |
153 break; | |
154 case 4: | |
155 khttp_puts(data->req, bprintf("%d", paste->duration)); | |
156 break; | |
157 default: | |
158 break; | |
159 } | |
160 | |
161 return true; | |
162 } | |
163 | |
164 static int | |
165 tmpl_index(size_t index, void *arg) | |
166 { | |
167 /* No check, only one index. */ | |
168 struct tmpl_index *data = arg; | |
169 const char *keywords[] = { | |
170 "uuid", | |
171 "name", | |
172 "author", | |
173 "language", | |
174 "expiration" | |
175 }; | |
176 struct ktemplate kt = { | |
177 .key = keywords, | |
178 .keysz = 5, | |
179 .arg = data, | |
180 .cb = tmpl_index_pastes | |
181 }; | |
182 | |
183 for (size_t i = 0; i < data->count; ++i) { | |
184 khttp_template(data->req, &kt, template("index-paste.html")); | |
185 data->current++; | |
186 } | |
187 | |
188 return true; | |
189 } | |
190 | |
191 static void | |
192 header(struct kreq *req) | |
193 { | |
194 khttp_template(req, NULL, template("header.html")); | |
195 } | |
196 | |
197 static void | |
198 footer(struct kreq *req) | |
199 { | |
200 khttp_template(req, NULL, template("footer.html")); | |
201 } | |
202 | |
203 static void | |
204 page_index(struct kreq *req) | |
205 { | |
206 struct tmpl_index data = { | |
207 .req = req, | |
208 .count = 10 | |
209 }; | |
210 | |
211 khttp_head(req, kresps[KRESP_CONTENT_TYPE], "%s", kmimetypes[KMIME_TEXT_HTML]); | |
212 | |
213 if (!database_recents(data.pastes, &data.count)) { | |
214 khttp_head(req, kresps[KRESP_STATUS], "%s", khttps[KHTTP_500]); | |
215 khttp_body(req); | |
216 khttp_template(req, NULL, template("500.html")); | |
217 } else { | |
218 const char *keywords[] = { "pastes" }; | |
219 struct ktemplate kt = { | |
220 .key = keywords, | |
221 .keysz = 1, | |
222 .arg = &data, | |
223 .cb = tmpl_index | |
224 }; | |
225 | |
226 khttp_head(req, kresps[KRESP_STATUS], "%s", khttps[KHTTP_200]); | |
227 khttp_body(req); | |
228 header(req); | |
229 khttp_template(req, &kt, template("index.html")); | |
230 footer(req); | |
231 } | |
232 | |
233 khttp_free(req); | |
234 } | |
235 | |
236 static void | |
237 page_new(struct kreq *req) | |
238 { | |
239 (void)req; | |
240 } | |
241 | |
242 static void | |
243 page_fork(struct kreq *req) | |
244 { | |
245 (void)req; | |
246 } | |
247 | |
248 static void | |
249 page_paste(struct kreq *req) | |
250 { | |
251 struct tmpl_paste data = { | |
252 .req = req | |
253 }; | |
254 | |
255 khttp_head(req, kresps[KRESP_CONTENT_TYPE], "%s", kmimetypes[KMIME_TEXT_HTML]); | |
256 | |
257 if (!database_get(&data.paste, req->path)) { | |
258 khttp_head(req, kresps[KRESP_STATUS], "%s", khttps[KHTTP_404]); | |
259 khttp_body(req); | |
260 khttp_template(req, NULL, template("404.html")); | |
261 } else { | |
262 const char *keywords[] = { | |
263 "uuid", | |
264 "title", | |
265 "author", | |
266 "language", | |
267 "code", | |
268 "timestamp", | |
269 "visible", | |
270 "duration" | |
271 }; | |
272 const struct ktemplate kt = { | |
273 .key = keywords, | |
274 .keysz = 8, | |
275 .cb = tmpl_paste, | |
276 .arg = &data | |
277 }; | |
278 | |
279 khttp_head(req, kresps[KRESP_STATUS], "%s", khttps[KHTTP_200]); | |
280 khttp_body(req); | |
281 header(req); | |
282 khttp_template(req, &kt, template("paste.html")); | |
283 footer(req); | |
284 khttp_free(req); | |
285 } | |
286 } | |
287 | |
288 static void | |
289 page_about(struct kreq *req) | |
290 { | |
291 (void)req; | |
292 } | |
293 | |
294 static void | |
295 page_download(struct kreq *req) | |
296 { | |
297 (void)req; | |
298 } | |
299 | |
300 static void | |
301 process(struct kreq *req) | |
302 { | |
303 assert(req); | |
304 | |
305 handlers[req->page](req); | |
306 } | |
307 | |
308 void | |
309 http_fcgi_run(void) | |
310 { | |
311 struct kreq req; | |
312 struct kfcgi *fcgi; | |
313 | |
314 if (khttp_fcgi_init(&fcgi, NULL, 0, pages, PAGE_LAST, 0) != KCGI_OK) | |
315 return; | |
316 | |
317 while (khttp_fcgi_parse(fcgi, &req) == KCGI_OK) | |
318 process(&req); | |
319 | |
320 khttp_fcgi_free(fcgi); | |
321 } | |
322 | |
323 void | |
324 http_cgi_run(void) | |
325 { | |
326 struct kreq req; | |
327 | |
328 if (khttp_parse(&req, NULL, 0, pages, PAGE_LAST, 0) == KCGI_OK) | |
329 process(&req); | |
330 } |