Mercurial > paster
comparison http.c @ 2:65607ae124b1
pasterd: implement /new
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 04 Feb 2020 20:47:00 +0100 |
parents | 836a698946f8 |
children | 80d67d8dbfb2 |
comparison
equal
deleted
inserted
replaced
1:836a698946f8 | 2:65607ae124b1 |
---|---|
21 #include <limits.h> | 21 #include <limits.h> |
22 #include <stdarg.h> | 22 #include <stdarg.h> |
23 #include <stdint.h> | 23 #include <stdint.h> |
24 #include <stdio.h> | 24 #include <stdio.h> |
25 #include <stdlib.h> | 25 #include <stdlib.h> |
26 #include <string.h> | |
26 #include <unistd.h> | 27 #include <unistd.h> |
27 | 28 |
28 #include <kcgi.h> | 29 #include <kcgi.h> |
29 | 30 |
30 #include "config.h" | 31 #include "config.h" |
79 struct tmpl_paste { | 80 struct tmpl_paste { |
80 struct kreq *req; | 81 struct kreq *req; |
81 struct paste paste; | 82 struct paste paste; |
82 }; | 83 }; |
83 | 84 |
85 static const char *tmpl_index_keywords[] = { | |
86 "uuid", | |
87 "name", | |
88 "author", | |
89 "language", | |
90 "expiration" | |
91 }; | |
92 | |
93 static const char *tmpl_paste_keywords[] = { | |
94 "uuid", | |
95 "title", | |
96 "author", | |
97 "language", | |
98 "code", | |
99 "timestamp", | |
100 "visible", | |
101 "duration" | |
102 }; | |
103 | |
104 static const char *tmpl_new_keywords[] = { | |
105 "title", /* /fork only */ | |
106 "author", /* /fork only */ | |
107 "code", /* /fork only */ | |
108 "languages" | |
109 }; | |
110 | |
111 static const char *languages[] = { | |
112 "1c", | |
113 "abnf", | |
114 "accesslog", | |
115 "actionscript", | |
116 "ada", | |
117 "apache", | |
118 "applescript", | |
119 "arduino", | |
120 "armasm", | |
121 "asciidoc", | |
122 "aspectj", | |
123 "autohotkey", | |
124 "autoit", | |
125 "avrasm", | |
126 "awk", | |
127 "axapta", | |
128 "bash", | |
129 "basic", | |
130 "bnf", | |
131 "brainfuck", | |
132 "cal", | |
133 "capnproto", | |
134 "ceylon", | |
135 "clean", | |
136 "clojure", | |
137 "clojure-repl", | |
138 "cmake", | |
139 "coffeescript", | |
140 "coq", | |
141 "cos", | |
142 "cpp", | |
143 "crmsh", | |
144 "crystal", | |
145 "cs", | |
146 "csp", | |
147 "css", | |
148 "dart", | |
149 "delphi", | |
150 "diff", | |
151 "django", | |
152 "d", | |
153 "dns", | |
154 "dockerfile", | |
155 "dos", | |
156 "dsconfig", | |
157 "dts", | |
158 "dust", | |
159 "ebnf", | |
160 "elixir", | |
161 "elm", | |
162 "erb", | |
163 "erlang", | |
164 "erlang-repl", | |
165 "excel", | |
166 "fix", | |
167 "flix", | |
168 "fortran", | |
169 "fsharp", | |
170 "gams", | |
171 "gauss", | |
172 "gcode", | |
173 "gherkin", | |
174 "glsl", | |
175 "go", | |
176 "golo", | |
177 "gradle", | |
178 "groovy", | |
179 "haml", | |
180 "handlebars", | |
181 "haskell", | |
182 "haxe", | |
183 "hsp", | |
184 "htmlbars", | |
185 "http", | |
186 "hy", | |
187 "inform7", | |
188 "ini", | |
189 "irpf90", | |
190 "java", | |
191 "javascript", | |
192 "jboss-cli", | |
193 "json", | |
194 "julia", | |
195 "julia-repl", | |
196 "kotlin", | |
197 "lasso", | |
198 "ldif", | |
199 "leaf", | |
200 "less", | |
201 "lisp", | |
202 "livecodeserver", | |
203 "livescript", | |
204 "llvm", | |
205 "lsl", | |
206 "lua", | |
207 "makefile", | |
208 "markdown", | |
209 "mathematica", | |
210 "matlab", | |
211 "maxima", | |
212 "mel", | |
213 "mercury", | |
214 "mipsasm", | |
215 "mizar", | |
216 "mojolicious", | |
217 "monkey", | |
218 "moonscript", | |
219 "n1ql", | |
220 "nginx", | |
221 "nimrod", | |
222 "nix", | |
223 "nohighlight", | |
224 "nsis", | |
225 "objectivec", | |
226 "ocaml", | |
227 "openscad", | |
228 "oxygene", | |
229 "parser3", | |
230 "perl", | |
231 "pf", | |
232 "php", | |
233 "pony", | |
234 "powershell", | |
235 "processing", | |
236 "profile", | |
237 "prolog", | |
238 "protobuf", | |
239 "puppet", | |
240 "purebasic", | |
241 "python", | |
242 "q", | |
243 "qml", | |
244 "rib", | |
245 "r", | |
246 "roboconf", | |
247 "routeros", | |
248 "rsl", | |
249 "ruby", | |
250 "ruleslanguage", | |
251 "rust", | |
252 "scala", | |
253 "scheme", | |
254 "scilab", | |
255 "scss", | |
256 "shell", | |
257 "smali", | |
258 "smalltalk", | |
259 "sml", | |
260 "sqf", | |
261 "sql", | |
262 "stan", | |
263 "stata", | |
264 "step21", | |
265 "stylus", | |
266 "subunit", | |
267 "swift", | |
268 "taggerscript", | |
269 "tap", | |
270 "tcl", | |
271 "tex", | |
272 "thrift", | |
273 "tp", | |
274 "twig", | |
275 "typescript", | |
276 "vala", | |
277 "vbnet", | |
278 "vbscript-html", | |
279 "vbscript", | |
280 "verilog", | |
281 "vhdl", | |
282 "vim", | |
283 "x86asm", | |
284 "xl", | |
285 "xml", | |
286 "xquery", | |
287 "yaml", | |
288 "zephir", | |
289 NULL | |
290 }; | |
291 | |
84 static const char * | 292 static const char * |
85 template(const char *filename) | 293 template(const char *filename) |
86 { | 294 { |
87 /* Build path to the template file. */ | 295 /* Build path to the template file. */ |
88 static char path[PATH_MAX]; | 296 static char path[PATH_MAX]; |
89 | 297 |
90 snprintf(path, sizeof (path), "%s/%s", config.themedir, filename); | 298 snprintf(path, sizeof (path), "%s/%s", config.themedir, filename); |
91 | 299 |
92 return path; | 300 return path; |
301 } | |
302 | |
303 static void | |
304 header(struct kreq *req) | |
305 { | |
306 khttp_template(req, NULL, template("header.html")); | |
307 } | |
308 | |
309 static void | |
310 footer(struct kreq *req) | |
311 { | |
312 khttp_template(req, NULL, template("footer.html")); | |
313 } | |
314 | |
315 static long long int | |
316 duration(const char *val) | |
317 { | |
318 if (strcmp(val, "hour") == 0) | |
319 return PASTE_HOUR; | |
320 if (strcmp(val, "day") == 0) | |
321 return PASTE_DAY; | |
322 if (strcmp(val, "week") == 0) | |
323 return PASTE_WEEK; | |
324 if (strcmp(val, "month") == 0) | |
325 return PASTE_MONTH; | |
326 | |
327 /* Default to month. */ | |
328 return PASTE_MONTH; | |
93 } | 329 } |
94 | 330 |
95 static int | 331 static int |
96 tmpl_paste(size_t index, void *arg) | 332 tmpl_paste(size_t index, void *arg) |
97 { | 333 { |
164 static int | 400 static int |
165 tmpl_index(size_t index, void *arg) | 401 tmpl_index(size_t index, void *arg) |
166 { | 402 { |
167 /* No check, only one index. */ | 403 /* No check, only one index. */ |
168 struct tmpl_index *data = arg; | 404 struct tmpl_index *data = arg; |
169 const char *keywords[] = { | 405 const struct ktemplate kt = { |
170 "uuid", | 406 .key = tmpl_index_keywords, |
171 "name", | |
172 "author", | |
173 "language", | |
174 "expiration" | |
175 }; | |
176 struct ktemplate kt = { | |
177 .key = keywords, | |
178 .keysz = 5, | 407 .keysz = 5, |
179 .arg = data, | 408 .arg = data, |
180 .cb = tmpl_index_pastes | 409 .cb = tmpl_index_pastes |
181 }; | 410 }; |
182 | 411 |
186 } | 415 } |
187 | 416 |
188 return true; | 417 return true; |
189 } | 418 } |
190 | 419 |
191 static void | 420 static int |
192 header(struct kreq *req) | 421 tmpl_new(size_t index, void *arg) |
193 { | 422 { |
194 khttp_template(req, NULL, template("header.html")); | 423 struct tmpl_paste *data = arg; |
195 } | 424 struct paste *paste = &data->paste; |
196 | 425 |
197 static void | 426 switch (index) { |
198 footer(struct kreq *req) | 427 case 0: |
199 { | 428 if (paste->title) |
200 khttp_template(req, NULL, template("footer.html")); | 429 khttp_puts(data->req, paste->title); |
430 break; | |
431 case 1: | |
432 if (paste->author) | |
433 khttp_puts(data->req, paste->author); | |
434 break; | |
435 case 2: | |
436 if (paste->code) | |
437 khttp_puts(data->req, paste->code); | |
438 break; | |
439 case 3: | |
440 /* TODO: fragment? */ | |
441 for (const char **l = languages; *l != NULL; ++l) | |
442 khttp_puts(data->req, | |
443 bprintf("<option value=\"%s\">%s</option>", *l, *l)); | |
444 break; | |
445 default: | |
446 break; | |
447 }; | |
448 | |
449 return true; | |
201 } | 450 } |
202 | 451 |
203 static void | 452 static void |
204 page_index(struct kreq *req) | 453 page_index(struct kreq *req) |
205 { | 454 { |
228 header(req); | 477 header(req); |
229 khttp_template(req, &kt, template("index.html")); | 478 khttp_template(req, &kt, template("index.html")); |
230 footer(req); | 479 footer(req); |
231 } | 480 } |
232 | 481 |
482 for (size_t i = 0; i < data.count; ++i) | |
483 paste_finish(&data.pastes[i]); | |
484 | |
233 khttp_free(req); | 485 khttp_free(req); |
234 } | 486 } |
235 | 487 |
236 static void | 488 static void |
489 page_new_get(struct kreq *req) | |
490 { | |
491 struct tmpl_paste data = { | |
492 .req = req | |
493 }; | |
494 const struct ktemplate kt = { | |
495 .key = tmpl_new_keywords, | |
496 .keysz = 4, | |
497 .cb = tmpl_new, | |
498 .arg = &data | |
499 }; | |
500 | |
501 khttp_head(req, kresps[KRESP_CONTENT_TYPE], "%s", kmimetypes[KMIME_TEXT_HTML]); | |
502 khttp_head(req, kresps[KRESP_STATUS], "%s", khttps[KHTTP_200]); | |
503 khttp_body(req); | |
504 header(req); | |
505 khttp_template(req, &kt, template("new.html")); | |
506 footer(req); | |
507 khttp_free(req); | |
508 } | |
509 | |
510 static void | |
511 page_new_post(struct kreq *req) | |
512 { | |
513 struct paste paste = { | |
514 .visible = true | |
515 }; | |
516 | |
517 for (size_t i = 0; i < req->fieldsz; ++i) { | |
518 const char *key = req->fields[i].key; | |
519 const char *val = req->fields[i].val; | |
520 | |
521 if (strcmp(key, "title") == 0) | |
522 paste.title = estrdup(val); | |
523 else if (strcmp(key, "author") == 0) | |
524 paste.author = estrdup(val); | |
525 else if (strcmp(key, "language") == 0) | |
526 paste.language = estrdup(val); | |
527 else if (strcmp(key, "duration") == 0) | |
528 paste.duration = duration(val); | |
529 else if (strcmp(key, "code") == 0) | |
530 paste.code = estrdup(val); | |
531 else if (strcmp(key, "private") == 0) | |
532 paste.visible = strcmp(val, "on") != 0; | |
533 } | |
534 | |
535 khttp_head(req, kresps[KRESP_CONTENT_TYPE], "%s", kmimetypes[KMIME_TEXT_HTML]); | |
536 | |
537 if (!paste.title || !paste.author || !paste.language || !paste.code) { | |
538 khttp_head(req, kresps[KRESP_STATUS], "%s", khttps[KHTTP_400]); | |
539 khttp_body(req); | |
540 header(req); | |
541 khttp_template(req, NULL, template("400.html")); | |
542 footer(req); | |
543 } else { | |
544 if (!database_insert(&paste)) { | |
545 khttp_head(req, kresps[KRESP_STATUS], "%s", khttps[KHTTP_500]); | |
546 khttp_body(req); | |
547 header(req); | |
548 khttp_template(req, NULL, template("500.html")); | |
549 footer(req); | |
550 } else { | |
551 khttp_head(req, kresps[KRESP_STATUS], "%s", khttps[KHTTP_302]); | |
552 khttp_head(req, kresps[KRESP_LOCATION], "/paste/%s", paste.uuid); | |
553 } | |
554 } | |
555 | |
556 khttp_free(req); | |
557 paste_finish(&paste); | |
558 } | |
559 | |
560 static void | |
237 page_new(struct kreq *req) | 561 page_new(struct kreq *req) |
238 { | 562 { |
239 (void)req; | 563 switch (req->method) { |
564 case KMETHOD_GET: | |
565 page_new_get(req); | |
566 break; | |
567 case KMETHOD_POST: | |
568 page_new_post(req); | |
569 break; | |
570 default: | |
571 break; | |
572 } | |
240 } | 573 } |
241 | 574 |
242 static void | 575 static void |
243 page_fork(struct kreq *req) | 576 page_fork(struct kreq *req) |
244 { | 577 { |
257 if (!database_get(&data.paste, req->path)) { | 590 if (!database_get(&data.paste, req->path)) { |
258 khttp_head(req, kresps[KRESP_STATUS], "%s", khttps[KHTTP_404]); | 591 khttp_head(req, kresps[KRESP_STATUS], "%s", khttps[KHTTP_404]); |
259 khttp_body(req); | 592 khttp_body(req); |
260 khttp_template(req, NULL, template("404.html")); | 593 khttp_template(req, NULL, template("404.html")); |
261 } else { | 594 } 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 = { | 595 const struct ktemplate kt = { |
273 .key = keywords, | 596 .key = tmpl_paste_keywords, |
274 .keysz = 8, | 597 .keysz = 8, |
275 .cb = tmpl_paste, | 598 .cb = tmpl_paste, |
276 .arg = &data | 599 .arg = &data |
277 }; | 600 }; |
278 | 601 |
279 khttp_head(req, kresps[KRESP_STATUS], "%s", khttps[KHTTP_200]); | 602 khttp_head(req, kresps[KRESP_STATUS], "%s", khttps[KHTTP_200]); |
280 khttp_body(req); | 603 khttp_body(req); |
281 header(req); | 604 header(req); |
282 khttp_template(req, &kt, template("paste.html")); | 605 khttp_template(req, &kt, template("paste.html")); |
283 footer(req); | 606 footer(req); |
284 khttp_free(req); | 607 } |
285 } | 608 |
609 khttp_free(req); | |
610 paste_finish(&data.paste); | |
286 } | 611 } |
287 | 612 |
288 static void | 613 static void |
289 page_about(struct kreq *req) | 614 page_about(struct kreq *req) |
290 { | 615 { |