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 {