Mercurial > paster
comparison http.c @ 12:93f0440d452e
pasterd: add siimple theme
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 06 Feb 2020 10:29:02 +0100 |
parents | 75cfe3795de3 |
children | 29033b4fe558 |
comparison
equal
deleted
inserted
replaced
11:b9b046818b0c | 12:93f0440d452e |
---|---|
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 */ | 17 */ |
18 | 18 |
19 #include <sys/types.h> | 19 #include <sys/types.h> |
20 #include <sys/stat.h> | |
20 #include <assert.h> | 21 #include <assert.h> |
22 #include <ctype.h> | |
21 #include <limits.h> | 23 #include <limits.h> |
22 #include <stdarg.h> | 24 #include <stdarg.h> |
23 #include <stdint.h> | 25 #include <stdint.h> |
24 #include <stdio.h> | 26 #include <stdio.h> |
25 #include <stdlib.h> | 27 #include <stdlib.h> |
26 #include <string.h> | 28 #include <string.h> |
27 #include <unistd.h> | 29 #include <unistd.h> |
28 | 30 |
29 #include <kcgi.h> | 31 #include <kcgi.h> |
32 #include <kcgihtml.h> | |
30 | 33 |
31 #include "config.h" | 34 #include "config.h" |
32 #include "database.h" | 35 #include "database.h" |
33 #include "http.h" | 36 #include "http.h" |
34 #include "log.h" | 37 #include "log.h" |
38 static void page_index(struct kreq *); | 41 static void page_index(struct kreq *); |
39 static void page_new(struct kreq *); | 42 static void page_new(struct kreq *); |
40 static void page_fork(struct kreq *); | 43 static void page_fork(struct kreq *); |
41 static void page_paste(struct kreq *); | 44 static void page_paste(struct kreq *); |
42 static void page_download(struct kreq *); | 45 static void page_download(struct kreq *); |
46 static void page_static(struct kreq *); | |
43 | 47 |
44 enum page { | 48 enum page { |
45 PAGE_INDEX, | 49 PAGE_INDEX, |
46 PAGE_NEW, | 50 PAGE_NEW, |
47 PAGE_FORK, | 51 PAGE_FORK, |
48 PAGE_PASTE, | 52 PAGE_PASTE, |
49 PAGE_DOWNLOAD, | 53 PAGE_DOWNLOAD, |
54 PAGE_STATIC, | |
50 PAGE_LAST /* Not used. */ | 55 PAGE_LAST /* Not used. */ |
51 }; | 56 }; |
52 | 57 |
53 static const char *pages[] = { | 58 static const char *pages[] = { |
54 [PAGE_INDEX] = "", | 59 [PAGE_INDEX] = "", |
55 [PAGE_NEW] = "new", | 60 [PAGE_NEW] = "new", |
56 [PAGE_FORK] = "fork", | 61 [PAGE_FORK] = "fork", |
57 [PAGE_PASTE] = "paste", | 62 [PAGE_PASTE] = "paste", |
58 [PAGE_DOWNLOAD] = "download", | 63 [PAGE_DOWNLOAD] = "download", |
64 [PAGE_STATIC] = "static" | |
59 }; | 65 }; |
60 | 66 |
61 static void (*handlers[])(struct kreq *req) = { | 67 static void (*handlers[])(struct kreq *req) = { |
62 [PAGE_INDEX] = page_index, | 68 [PAGE_INDEX] = page_index, |
63 [PAGE_NEW] = page_new, | 69 [PAGE_NEW] = page_new, |
64 [PAGE_FORK] = page_fork, | 70 [PAGE_FORK] = page_fork, |
65 [PAGE_PASTE] = page_paste, | 71 [PAGE_PASTE] = page_paste, |
66 [PAGE_DOWNLOAD] = page_download | 72 [PAGE_DOWNLOAD] = page_download, |
73 [PAGE_STATIC] = page_static | |
67 }; | 74 }; |
68 | 75 |
69 struct tmpl_index { | 76 struct tmpl_index { |
70 struct kreq *req; | 77 struct kreq *req; |
71 struct paste pastes[10]; | 78 struct paste pastes[10]; |
344 /* Other in days. */ | 351 /* Other in days. */ |
345 return bprintf("%lld day(s)", left / 86400); | 352 return bprintf("%lld day(s)", left / 86400); |
346 } | 353 } |
347 | 354 |
348 static void | 355 static void |
356 replace(char **dst, const char *s) | |
357 { | |
358 assert(dst); | |
359 assert(s); | |
360 | |
361 /* Trim leading spaces. */ | |
362 while (*s && isspace(*s)) | |
363 s++; | |
364 | |
365 if (*s) { | |
366 free(*dst); | |
367 *dst = estrdup(s); | |
368 } | |
369 } | |
370 | |
371 static void | |
349 render_languages(struct kreq *req, const struct paste *paste) | 372 render_languages(struct kreq *req, const struct paste *paste) |
350 { | 373 { |
351 for (const char **l = languages; *l != NULL; ++l) { | 374 for (const char **l = languages; *l != NULL; ++l) { |
352 const char *line; | 375 const char *line; |
353 | 376 |
380 static int | 403 static int |
381 tmpl_paste(size_t index, void *arg) | 404 tmpl_paste(size_t index, void *arg) |
382 { | 405 { |
383 struct tmpl_paste *data = arg; | 406 struct tmpl_paste *data = arg; |
384 struct paste *paste = &data->paste; | 407 struct paste *paste = &data->paste; |
408 struct khtmlreq htmlreq; | |
409 | |
410 khtml_open(&htmlreq, data->req, KHTML_PRETTY); | |
385 | 411 |
386 switch (index) { | 412 switch (index) { |
387 case 0: | 413 case 0: |
388 khttp_puts(data->req, paste->uuid); | 414 khtml_puts(&htmlreq, paste->uuid); |
389 break; | 415 break; |
390 case 1: | 416 case 1: |
391 khttp_puts(data->req, paste->title); | 417 khtml_puts(&htmlreq, paste->title); |
392 break; | 418 break; |
393 case 2: | 419 case 2: |
394 khttp_puts(data->req, paste->author); | 420 khtml_puts(&htmlreq, paste->author); |
395 break; | 421 break; |
396 case 3: | 422 case 3: |
397 khttp_puts(data->req, paste->language); | 423 khtml_puts(&htmlreq, paste->language); |
398 break; | 424 break; |
399 case 4: | 425 case 4: |
400 khttp_puts(data->req, paste->code); | 426 khtml_puts(&htmlreq, paste->code); |
401 break; | 427 break; |
402 case 5: | 428 case 5: |
403 khttp_puts(data->req, bstrftime("%c", localtime(&paste->timestamp))); | 429 khtml_puts(&htmlreq, bstrftime("%c", localtime(&paste->timestamp))); |
404 break; | 430 break; |
405 case 6: | 431 case 6: |
406 khttp_puts(data->req, bprintf("%s", paste->visible ? "Yes" : "No")); | 432 khtml_puts(&htmlreq, bprintf("%s", paste->visible ? "Yes" : "No")); |
407 break; | 433 break; |
408 case 7: | 434 case 7: |
409 khttp_puts(data->req, ttl(paste->timestamp, paste->duration)); | 435 khtml_puts(&htmlreq, ttl(paste->timestamp, paste->duration)); |
410 break; | 436 break; |
411 default: | 437 default: |
412 break; | 438 break; |
413 } | 439 } |
440 | |
441 khtml_close(&htmlreq); | |
414 | 442 |
415 return true; | 443 return true; |
416 } | 444 } |
417 | 445 |
418 static int | 446 static int |
419 tmpl_index_pastes(size_t index, void *arg) | 447 tmpl_index_pastes(size_t index, void *arg) |
420 { | 448 { |
421 struct tmpl_index *data = arg; | 449 struct tmpl_index *data = arg; |
422 struct paste *paste = &data->pastes[data->current]; | 450 struct paste *paste = &data->pastes[data->current]; |
451 struct khtmlreq htmlreq; | |
452 | |
453 khtml_open(&htmlreq, data->req, KHTML_PRETTY); | |
423 | 454 |
424 switch (index) { | 455 switch (index) { |
425 case 0: | 456 case 0: |
426 khttp_puts(data->req, paste->uuid); | 457 khtml_puts(&htmlreq, paste->uuid); |
427 break; | 458 break; |
428 case 1: | 459 case 1: |
429 khttp_puts(data->req, paste->title); | 460 khtml_puts(&htmlreq, paste->title); |
430 break; | 461 break; |
431 case 2: | 462 case 2: |
432 khttp_puts(data->req, paste->author); | 463 khtml_puts(&htmlreq, paste->author); |
433 break; | 464 break; |
434 case 3: | 465 case 3: |
435 khttp_puts(data->req, paste->language); | 466 khtml_puts(&htmlreq, paste->language); |
436 break; | 467 break; |
437 case 4: | 468 case 4: |
438 khttp_puts(data->req, ttl(paste->timestamp, paste->duration)); | 469 khtml_puts(&htmlreq, ttl(paste->timestamp, paste->duration)); |
439 break; | 470 break; |
440 case 5: | 471 case 5: |
441 khttp_puts(data->req, bstrftime("%c", localtime(&paste->timestamp))); | 472 khtml_puts(&htmlreq, bstrftime("%c", localtime(&paste->timestamp))); |
442 break; | 473 break; |
443 default: | 474 default: |
444 break; | 475 break; |
445 } | 476 } |
477 | |
478 khtml_close(&htmlreq); | |
446 | 479 |
447 return true; | 480 return true; |
448 } | 481 } |
449 | 482 |
450 static int | 483 static int |
451 tmpl_index(size_t index, void *arg) | 484 tmpl_index(size_t index, void *arg) |
452 { | 485 { |
453 /* No check, only one index. */ | 486 /* No check, only one index. */ |
487 (void)index; | |
488 | |
454 struct tmpl_index *data = arg; | 489 struct tmpl_index *data = arg; |
455 const struct ktemplate kt = { | 490 const struct ktemplate kt = { |
456 .key = tmpl_index_pastes_keywords, | 491 .key = tmpl_index_pastes_keywords, |
457 .keysz = 6, | 492 .keysz = 6, |
458 .arg = data, | 493 .arg = data, |
470 static int | 505 static int |
471 tmpl_new(size_t index, void *arg) | 506 tmpl_new(size_t index, void *arg) |
472 { | 507 { |
473 struct tmpl_paste *data = arg; | 508 struct tmpl_paste *data = arg; |
474 struct paste *paste = &data->paste; | 509 struct paste *paste = &data->paste; |
510 struct khtmlreq htmlreq; | |
511 | |
512 khtml_open(&htmlreq, data->req, KHTML_PRETTY); | |
475 | 513 |
476 switch (index) { | 514 switch (index) { |
477 case 0: | 515 case 0: |
478 if (paste->title) | 516 if (paste->title) |
479 khttp_puts(data->req, paste->title); | 517 khtml_puts(&htmlreq, paste->title); |
480 break; | 518 break; |
481 case 1: | 519 case 1: |
482 if (paste->author) | 520 if (paste->author) |
483 khttp_puts(data->req, paste->author); | 521 khtml_puts(&htmlreq, paste->author); |
484 break; | 522 break; |
485 case 2: | 523 case 2: |
486 if (paste->code) | 524 if (paste->code) |
487 khttp_puts(data->req, paste->code); | 525 khtml_puts(&htmlreq, paste->code); |
488 break; | 526 break; |
489 case 3: | 527 case 3: |
490 /* Add checked attribute to combobox. */ | 528 /* Add checked attribute to combobox. */ |
491 if (!paste->visible) | 529 if (!paste->visible) |
492 khttp_puts(data->req, "checked"); | 530 khttp_puts(data->req, "checked"); |
498 render_durations(data->req, paste); | 536 render_durations(data->req, paste); |
499 break; | 537 break; |
500 default: | 538 default: |
501 break; | 539 break; |
502 }; | 540 }; |
541 | |
542 khtml_close(&htmlreq); | |
503 | 543 |
504 return true; | 544 return true; |
505 } | 545 } |
506 | 546 |
507 static void | 547 static void |
584 | 624 |
585 static void | 625 static void |
586 page_new_post(struct kreq *req) | 626 page_new_post(struct kreq *req) |
587 { | 627 { |
588 struct paste paste = { | 628 struct paste paste = { |
589 .visible = true | 629 .author = estrdup("Anonymous"), |
630 .title = estrdup("Untitled"), | |
631 .language = estrdup("nohighlight"), | |
632 .visible = true | |
590 }; | 633 }; |
591 | 634 |
592 for (size_t i = 0; i < req->fieldsz; ++i) { | 635 for (size_t i = 0; i < req->fieldsz; ++i) { |
593 const char *key = req->fields[i].key; | 636 const char *key = req->fields[i].key; |
594 const char *val = req->fields[i].val; | 637 const char *val = req->fields[i].val; |
595 | 638 |
596 if (strcmp(key, "title") == 0) | 639 if (strcmp(key, "title") == 0) |
597 paste.title = estrdup(val); | 640 replace(&paste.title, val); |
598 else if (strcmp(key, "author") == 0) | 641 else if (strcmp(key, "author") == 0) |
599 paste.author = estrdup(val); | 642 replace(&paste.author, val); |
600 else if (strcmp(key, "language") == 0) | 643 else if (strcmp(key, "language") == 0) |
601 paste.language = estrdup(val); | 644 replace(&paste.language, val); |
602 else if (strcmp(key, "duration") == 0) | 645 else if (strcmp(key, "duration") == 0) |
603 paste.duration = duration(val); | 646 paste.duration = duration(val); |
604 else if (strcmp(key, "code") == 0) | 647 else if (strcmp(key, "code") == 0) |
605 paste.code = estrdup(val); | 648 paste.code = estrdup(val); |
606 else if (strcmp(key, "private") == 0) | 649 else if (strcmp(key, "private") == 0) |
607 paste.visible = strcmp(val, "on") != 0; | 650 paste.visible = strcmp(val, "on") != 0; |
608 } | 651 } |
609 | 652 |
610 if (!paste.title || !paste.author || !paste.language || !paste.code) | 653 if (!database_insert(&paste)) |
611 page(req, NULL, KHTTP_400, "400.html"); | 654 page(req, NULL, KHTTP_500, "500.html"); |
612 else { | 655 else { |
613 if (!database_insert(&paste)) | 656 /* Redirect to paste details. */ |
614 page(req, NULL, KHTTP_500, "500.html"); | 657 khttp_head(req, kresps[KRESP_STATUS], "%s", khttps[KHTTP_302]); |
615 else { | 658 khttp_head(req, kresps[KRESP_LOCATION], "/paste/%s", paste.uuid); |
616 /* Redirect to paste details. */ | 659 khttp_body(req); |
617 khttp_head(req, kresps[KRESP_STATUS], "%s", khttps[KHTTP_302]); | 660 khttp_free(req); |
618 khttp_head(req, kresps[KRESP_LOCATION], "/paste/%s", paste.uuid); | |
619 khttp_body(req); | |
620 khttp_free(req); | |
621 } | |
622 } | 661 } |
623 | 662 |
624 paste_finish(&paste); | 663 paste_finish(&paste); |
625 } | 664 } |
626 | 665 |
744 break; | 783 break; |
745 } | 784 } |
746 } | 785 } |
747 | 786 |
748 static void | 787 static void |
788 page_static_get(struct kreq *req) | |
789 { | |
790 struct stat st; | |
791 char path[PATH_MAX]; | |
792 | |
793 snprintf(path, sizeof (path), "%s%s", config.themedir, req->fullpath); | |
794 | |
795 if (stat(path, &st) < 0) | |
796 page(req, NULL, KHTTP_404, "404.html"); | |
797 else { | |
798 khttp_head(req, kresps[KRESP_STATUS], "%s", khttps[KHTTP_200]); | |
799 khttp_head(req, kresps[KRESP_CONTENT_TYPE], "%s", kmimetypes[req->mime]); | |
800 khttp_head(req, kresps[KRESP_CONTENT_TYPE], | |
801 "%llu", (unsigned long long)(st.st_size)); | |
802 khttp_body(req); | |
803 khttp_template(req, NULL, path); | |
804 khttp_free(req); | |
805 } | |
806 } | |
807 | |
808 static void | |
809 page_static(struct kreq *req) | |
810 { | |
811 switch (req->method) { | |
812 case KMETHOD_GET: | |
813 page_static_get(req); | |
814 break; | |
815 default: | |
816 page(req, NULL, KHTTP_400, "400.html"); | |
817 break; | |
818 } | |
819 } | |
820 | |
821 static void | |
749 process(struct kreq *req) | 822 process(struct kreq *req) |
750 { | 823 { |
751 assert(req); | 824 assert(req); |
752 | 825 |
753 handlers[req->page](req); | 826 if (req->page == PAGE_LAST) |
827 page(req, NULL, KHTTP_404, "404.html"); | |
828 else | |
829 handlers[req->page](req); | |
754 } | 830 } |
755 | 831 |
756 void | 832 void |
757 http_fcgi_run(void) | 833 http_fcgi_run(void) |
758 { | 834 { |