Mercurial > urweb
comparison src/c/urweb.c @ 1094:db52c32dbe42
All three current protocols work with move to using uw_app
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Sun, 27 Dec 2009 10:37:24 -0500 |
parents | f1647f16097d |
children | 72670131dace |
comparison
equal
deleted
inserted
replaced
1093:8d3aa6c7cee0 | 1094:db52c32dbe42 |
---|---|
1 #define _XOPEN_SOURCE 500 | 1 #define _XOPEN_SOURCE 600 |
2 | 2 |
3 #include <stdlib.h> | 3 #include <stdlib.h> |
4 #include <stdio.h> | 4 #include <stdio.h> |
5 #include <string.h> | 5 #include <string.h> |
6 #include <strings.h> | 6 #include <strings.h> |
7 #include <ctype.h> | 7 #include <ctype.h> |
8 #include <setjmp.h> | 8 #include <setjmp.h> |
9 #include <stdarg.h> | 9 #include <stdarg.h> |
10 #include <assert.h> | 10 #include <assert.h> |
11 #include <ctype.h> | 11 #include <ctype.h> |
12 #include <sys/types.h> | |
13 #include <sys/socket.h> | |
12 | 14 |
13 #include <pthread.h> | 15 #include <pthread.h> |
14 | 16 |
15 #include "types.h" | 17 #include "types.h" |
16 | 18 |
285 } | 287 } |
286 | 288 |
287 | 289 |
288 // Global entry points | 290 // Global entry points |
289 | 291 |
290 extern void uw_client_init(); | |
291 | |
292 void uw_global_init() { | 292 void uw_global_init() { |
293 srand(time(NULL) ^ getpid()); | 293 srand(time(NULL) ^ getpid()); |
294 | 294 |
295 clients = malloc(0); | 295 clients = malloc(0); |
296 | 296 } |
297 uw_client_init(); | 297 |
298 void uw_app_init(uw_app *app) { | |
299 app->client_init(); | |
298 } | 300 } |
299 | 301 |
300 | 302 |
301 // Single-request state | 303 // Single-request state |
302 | 304 |
347 void *data; | 349 void *data; |
348 void (*free)(void*); | 350 void (*free)(void*); |
349 } global; | 351 } global; |
350 | 352 |
351 struct uw_context { | 353 struct uw_context { |
354 uw_app *app; | |
355 | |
352 char *(*get_header)(void *, const char *); | 356 char *(*get_header)(void *, const char *); |
353 void *get_header_data; | 357 void *get_header_data; |
354 | 358 |
355 buf outHeaders, page, heap, script; | 359 buf outHeaders, page, heap, script; |
356 int returning_indirectly; | 360 int returning_indirectly; |
357 input *inputs, *subinputs, *cur_container; | 361 input *inputs, *subinputs, *cur_container; |
358 size_t n_subinputs, used_subinputs; | 362 size_t sz_inputs, n_subinputs, used_subinputs; |
359 | 363 |
360 int source_count; | 364 int source_count; |
361 | 365 |
362 void *db; | 366 void *db; |
363 | 367 |
365 | 369 |
366 regions *regions; | 370 regions *regions; |
367 | 371 |
368 cleanup *cleanup, *cleanup_front, *cleanup_back; | 372 cleanup *cleanup, *cleanup_front, *cleanup_back; |
369 | 373 |
370 const char *script_header, *url_prefix; | 374 const char *script_header; |
371 | 375 |
372 int needs_push, needs_sig; | 376 int needs_push, needs_sig; |
373 | 377 |
374 size_t n_deltas, used_deltas; | 378 size_t n_deltas, used_deltas; |
375 delta *deltas; | 379 delta *deltas; |
376 | 380 |
377 int timeout; | |
378 | |
379 client *client; | 381 client *client; |
380 | 382 |
381 transactional *transactionals; | 383 transactional *transactionals; |
382 size_t n_transactionals, used_transactionals; | 384 size_t n_transactionals, used_transactionals; |
383 | 385 |
387 char *current_url; | 389 char *current_url; |
388 | 390 |
389 char error_message[ERROR_BUF_LEN]; | 391 char error_message[ERROR_BUF_LEN]; |
390 }; | 392 }; |
391 | 393 |
392 extern int uw_inputs_len, uw_timeout; | |
393 | |
394 uw_context uw_init() { | 394 uw_context uw_init() { |
395 uw_context ctx = malloc(sizeof(struct uw_context)); | 395 uw_context ctx = malloc(sizeof(struct uw_context)); |
396 | |
397 ctx->app = NULL; | |
396 | 398 |
397 ctx->get_header = NULL; | 399 ctx->get_header = NULL; |
398 ctx->get_header_data = NULL; | 400 ctx->get_header_data = NULL; |
399 | 401 |
400 buf_init(&ctx->outHeaders, 0); | 402 buf_init(&ctx->outHeaders, 0); |
402 ctx->returning_indirectly = 0; | 404 ctx->returning_indirectly = 0; |
403 buf_init(&ctx->heap, 0); | 405 buf_init(&ctx->heap, 0); |
404 buf_init(&ctx->script, 1); | 406 buf_init(&ctx->script, 1); |
405 ctx->script.start[0] = 0; | 407 ctx->script.start[0] = 0; |
406 | 408 |
407 ctx->inputs = calloc(uw_inputs_len, sizeof(input)); | 409 ctx->inputs = malloc(0); |
408 ctx->cur_container = NULL; | 410 ctx->cur_container = NULL; |
409 ctx->subinputs = malloc(0); | 411 ctx->subinputs = malloc(0); |
410 ctx->n_subinputs = ctx->used_subinputs = 0; | 412 ctx->sz_inputs = ctx->n_subinputs = ctx->used_subinputs = 0; |
411 | 413 |
412 ctx->db = NULL; | 414 ctx->db = NULL; |
413 | 415 |
414 ctx->regions = NULL; | 416 ctx->regions = NULL; |
415 | 417 |
416 ctx->cleanup_front = ctx->cleanup_back = ctx->cleanup = malloc(0); | 418 ctx->cleanup_front = ctx->cleanup_back = ctx->cleanup = malloc(0); |
417 | 419 |
418 ctx->script_header = ""; | 420 ctx->script_header = ""; |
419 ctx->url_prefix = "/"; | |
420 ctx->needs_push = 0; | 421 ctx->needs_push = 0; |
421 ctx->needs_sig = 0; | 422 ctx->needs_sig = 0; |
422 | 423 |
423 ctx->error_message[0] = 0; | 424 ctx->error_message[0] = 0; |
424 | 425 |
425 ctx->source_count = 0; | 426 ctx->source_count = 0; |
426 | 427 |
427 ctx->n_deltas = ctx->used_deltas = 0; | 428 ctx->n_deltas = ctx->used_deltas = 0; |
428 ctx->deltas = malloc(0); | 429 ctx->deltas = malloc(0); |
429 | 430 |
430 ctx->timeout = uw_timeout; | |
431 | |
432 ctx->client = NULL; | 431 ctx->client = NULL; |
433 | 432 |
434 ctx->error_message[0] = 0; | 433 ctx->error_message[0] = 0; |
435 | 434 |
436 ctx->transactionals = malloc(0); | 435 ctx->transactionals = malloc(0); |
440 ctx->n_globals = 0; | 439 ctx->n_globals = 0; |
441 | 440 |
442 ctx->current_url = ""; | 441 ctx->current_url = ""; |
443 | 442 |
444 return ctx; | 443 return ctx; |
444 } | |
445 | |
446 void uw_set_app(uw_context ctx, uw_app *app) { | |
447 ctx->app = app; | |
448 | |
449 if (app->inputs_len > ctx->sz_inputs) { | |
450 ctx->sz_inputs = app->inputs_len; | |
451 ctx->inputs = realloc(ctx->inputs, ctx->sz_inputs * sizeof(input)); | |
452 memset(ctx->inputs, 0, ctx->sz_inputs * sizeof(input)); | |
453 } | |
445 } | 454 } |
446 | 455 |
447 void uw_set_db(uw_context ctx, void *db) { | 456 void uw_set_db(uw_context ctx, void *db) { |
448 ctx->db = db; | 457 ctx->db = db; |
449 } | 458 } |
497 ctx->error_message[0] = 0; | 506 ctx->error_message[0] = 0; |
498 } | 507 } |
499 | 508 |
500 void uw_reset(uw_context ctx) { | 509 void uw_reset(uw_context ctx) { |
501 uw_reset_keep_request(ctx); | 510 uw_reset_keep_request(ctx); |
502 memset(ctx->inputs, 0, uw_inputs_len * sizeof(input)); | 511 memset(ctx->inputs, 0, ctx->app->inputs_len * sizeof(input)); |
503 memset(ctx->subinputs, 0, ctx->n_subinputs * sizeof(input)); | 512 memset(ctx->subinputs, 0, ctx->n_subinputs * sizeof(input)); |
504 ctx->used_subinputs = 0; | 513 ctx->used_subinputs = 0; |
505 } | 514 } |
506 | 515 |
507 void uw_db_init(uw_context); | |
508 void uw_handle(uw_context, char *); | |
509 | |
510 failure_kind uw_begin_init(uw_context ctx) { | 516 failure_kind uw_begin_init(uw_context ctx) { |
511 int r = setjmp(ctx->jmp_buf); | 517 int r = setjmp(ctx->jmp_buf); |
512 | 518 |
513 if (r == 0) | 519 if (r == 0) |
514 uw_db_init(ctx); | 520 ctx->app->db_init(ctx); |
515 | 521 |
516 return r; | 522 return r; |
517 } | 523 } |
518 | 524 |
519 void uw_set_headers(uw_context ctx, char *(*get_header)(void *, const char *), void *get_header_data) { | 525 void uw_set_headers(uw_context ctx, char *(*get_header)(void *, const char *), void *get_header_data) { |
520 ctx->get_header = get_header; | 526 ctx->get_header = get_header; |
521 ctx->get_header_data = get_header_data; | 527 ctx->get_header_data = get_header_data; |
522 } | 528 } |
523 | |
524 int uw_db_begin(uw_context); | |
525 | 529 |
526 static void uw_set_error(uw_context ctx, const char *fmt, ...) { | 530 static void uw_set_error(uw_context ctx, const char *fmt, ...) { |
527 va_list ap; | 531 va_list ap; |
528 va_start(ap, fmt); | 532 va_start(ap, fmt); |
529 | 533 |
598 | 602 |
599 failure_kind uw_begin(uw_context ctx, char *path) { | 603 failure_kind uw_begin(uw_context ctx, char *path) { |
600 int r = setjmp(ctx->jmp_buf); | 604 int r = setjmp(ctx->jmp_buf); |
601 | 605 |
602 if (r == 0) { | 606 if (r == 0) { |
603 if (uw_db_begin(ctx)) | 607 if (ctx->app->db_begin(ctx)) |
604 uw_error(ctx, BOUNDED_RETRY, "Error running SQL BEGIN"); | 608 uw_error(ctx, BOUNDED_RETRY, "Error running SQL BEGIN"); |
605 | 609 |
606 uw_handle(ctx, path); | 610 ctx->app->handle(ctx, path); |
607 } | 611 } |
608 | 612 |
609 return r; | 613 return r; |
610 } | 614 } |
611 | 615 |
625 } | 629 } |
626 | 630 |
627 char *uw_error_message(uw_context ctx) { | 631 char *uw_error_message(uw_context ctx) { |
628 return ctx->error_message; | 632 return ctx->error_message; |
629 } | 633 } |
630 | |
631 extern int uw_input_num(const char*); | |
632 | 634 |
633 static input *INP(uw_context ctx) { | 635 static input *INP(uw_context ctx) { |
634 if (ctx->cur_container == NULL) | 636 if (ctx->cur_container == NULL) |
635 return ctx->inputs; | 637 return ctx->inputs; |
636 else if (ctx->cur_container->kind == SUBFORM) | 638 else if (ctx->cur_container->kind == SUBFORM) |
672 size_t offset = new_subinputs - ctx->subinputs; | 674 size_t offset = new_subinputs - ctx->subinputs; |
673 | 675 |
674 if (ctx->subinputs != new_subinputs) { | 676 if (ctx->subinputs != new_subinputs) { |
675 for (i = 0; i < ctx->used_subinputs; ++i) | 677 for (i = 0; i < ctx->used_subinputs; ++i) |
676 adjust_input(&new_subinputs[i], ctx->subinputs, new_subinputs, ctx->used_subinputs); | 678 adjust_input(&new_subinputs[i], ctx->subinputs, new_subinputs, ctx->used_subinputs); |
677 for (i = 0; i < uw_inputs_len; ++i) | 679 for (i = 0; i < ctx->app->inputs_len; ++i) |
678 adjust_input(&ctx->inputs[i], ctx->subinputs, new_subinputs, ctx->used_subinputs); | 680 adjust_input(&ctx->inputs[i], ctx->subinputs, new_subinputs, ctx->used_subinputs); |
679 | 681 |
680 adjust_pointer(&ctx->cur_container, ctx->subinputs, new_subinputs, ctx->used_subinputs); | 682 adjust_pointer(&ctx->cur_container, ctx->subinputs, new_subinputs, ctx->used_subinputs); |
681 | 683 |
682 ctx->n_subinputs = ctx->used_subinputs + len; | 684 ctx->n_subinputs = ctx->used_subinputs + len; |
694 | 696 |
695 int uw_set_input(uw_context ctx, const char *name, char *value) { | 697 int uw_set_input(uw_context ctx, const char *name, char *value) { |
696 //printf("Input name %s\n", name); | 698 //printf("Input name %s\n", name); |
697 | 699 |
698 if (!strcasecmp(name, ".b")) { | 700 if (!strcasecmp(name, ".b")) { |
699 int n = uw_input_num(value); | 701 int n = ctx->app->input_num(value); |
700 input *inps; | 702 input *inps; |
701 | 703 |
702 if (n < 0) { | 704 if (n < 0) { |
703 uw_set_error(ctx, "Bad subform name %s", value); | 705 uw_set_error(ctx, "Bad subform name %s", value); |
704 return -1; | 706 return -1; |
705 } | 707 } |
706 | 708 |
707 if (n >= uw_inputs_len) { | 709 if (n >= ctx->app->inputs_len) { |
708 uw_set_error(ctx, "For subform name %s, index %d is out of range", value, n); | 710 uw_set_error(ctx, "For subform name %s, index %d is out of range", value, n); |
709 return -1; | 711 return -1; |
710 } | 712 } |
711 | 713 |
712 inps = check_input_space(ctx, uw_inputs_len); | 714 inps = check_input_space(ctx, ctx->app->inputs_len); |
713 | 715 |
714 INP(ctx)[n].kind = SUBFORM; | 716 INP(ctx)[n].kind = SUBFORM; |
715 INP(ctx)[n].data.subform.parent = ctx->cur_container; | 717 INP(ctx)[n].data.subform.parent = ctx->cur_container; |
716 INP(ctx)[n].data.subform.fields = inps; | 718 INP(ctx)[n].data.subform.fields = inps; |
717 ctx->cur_container = &INP(ctx)[n]; | 719 ctx->cur_container = &INP(ctx)[n]; |
739 default: | 741 default: |
740 uw_set_error(ctx, "uw_set_input: Wrong kind"); | 742 uw_set_error(ctx, "uw_set_input: Wrong kind"); |
741 return -1; | 743 return -1; |
742 } | 744 } |
743 } else if (!strcasecmp(name, ".s")) { | 745 } else if (!strcasecmp(name, ".s")) { |
744 int n = uw_input_num(value); | 746 int n = ctx->app->input_num(value); |
745 | 747 |
746 if (n < 0) { | 748 if (n < 0) { |
747 uw_set_error(ctx, "Bad subforms name %s", value); | 749 uw_set_error(ctx, "Bad subforms name %s", value); |
748 return -1; | 750 return -1; |
749 } | 751 } |
750 | 752 |
751 if (n >= uw_inputs_len) { | 753 if (n >= ctx->app->inputs_len) { |
752 uw_set_error(ctx, "For subforms name %s, index %d is out of range", value, n); | 754 uw_set_error(ctx, "For subforms name %s, index %d is out of range", value, n); |
753 return -1; | 755 return -1; |
754 } | 756 } |
755 | 757 |
756 INP(ctx)[n].kind = SUBFORMS; | 758 INP(ctx)[n].kind = SUBFORMS; |
768 if (ctx->cur_container->kind != SUBFORMS) { | 770 if (ctx->cur_container->kind != SUBFORMS) { |
769 uw_set_error(ctx, "Bad kind for entry parent"); | 771 uw_set_error(ctx, "Bad kind for entry parent"); |
770 return -1; | 772 return -1; |
771 } | 773 } |
772 | 774 |
773 inps = check_input_space(ctx, uw_inputs_len + 1); | 775 inps = check_input_space(ctx, ctx->app->inputs_len + 1); |
774 | 776 |
775 inps->kind = ENTRY; | 777 inps->kind = ENTRY; |
776 inps->data.entry.parent = ctx->cur_container; | 778 inps->data.entry.parent = ctx->cur_container; |
777 inps->data.entry.next = ctx->cur_container->data.subforms.entries; | 779 inps->data.entry.next = ctx->cur_container->data.subforms.entries; |
778 ctx->cur_container->data.subforms.entries = inps; | 780 ctx->cur_container->data.subforms.entries = inps; |
779 | 781 |
780 inps->data.entry.fields = inps+1; | 782 inps->data.entry.fields = inps+1; |
781 ctx->cur_container = inps; | 783 ctx->cur_container = inps; |
782 } else { | 784 } else { |
783 int n = uw_input_num(name); | 785 int n = ctx->app->input_num(name); |
784 | 786 |
785 if (n < 0) { | 787 if (n < 0) { |
786 if (!strcmp(name, "null")) | 788 if (!strcmp(name, "null")) |
787 return 0; | 789 return 0; |
788 uw_set_error(ctx, "Bad input name %s", name); | 790 uw_set_error(ctx, "Bad input name %s", name); |
789 return -1; | 791 return -1; |
790 } | 792 } |
791 | 793 |
792 if (n >= uw_inputs_len) { | 794 if (n >= ctx->app->inputs_len) { |
793 uw_set_error(ctx, "For input name %s, index %d is out of range", name, n); | 795 uw_set_error(ctx, "For input name %s, index %d is out of range", name, n); |
794 return -1; | 796 return -1; |
795 } | 797 } |
796 | 798 |
797 INP(ctx)[n].kind = NORMAL; | 799 INP(ctx)[n].kind = NORMAL; |
802 } | 804 } |
803 | 805 |
804 char *uw_get_input(uw_context ctx, int n) { | 806 char *uw_get_input(uw_context ctx, int n) { |
805 if (n < 0) | 807 if (n < 0) |
806 uw_error(ctx, FATAL, "Negative input index %d", n); | 808 uw_error(ctx, FATAL, "Negative input index %d", n); |
807 if (n >= uw_inputs_len) | 809 if (n >= ctx->app->inputs_len) |
808 uw_error(ctx, FATAL, "Out-of-bounds input index %d", n); | 810 uw_error(ctx, FATAL, "Out-of-bounds input index %d", n); |
809 | 811 |
810 switch (INP(ctx)[n].kind) { | 812 switch (INP(ctx)[n].kind) { |
811 case UNSET: | 813 case UNSET: |
812 return NULL; | 814 return NULL; |
826 } | 828 } |
827 | 829 |
828 char *uw_get_optional_input(uw_context ctx, int n) { | 830 char *uw_get_optional_input(uw_context ctx, int n) { |
829 if (n < 0) | 831 if (n < 0) |
830 uw_error(ctx, FATAL, "Negative input index %d", n); | 832 uw_error(ctx, FATAL, "Negative input index %d", n); |
831 if (n >= uw_inputs_len) | 833 if (n >= ctx->app->inputs_len) |
832 uw_error(ctx, FATAL, "Out-of-bounds input index %d", n); | 834 uw_error(ctx, FATAL, "Out-of-bounds input index %d", n); |
833 | 835 |
834 switch (INP(ctx)[n].kind) { | 836 switch (INP(ctx)[n].kind) { |
835 case UNSET: | 837 case UNSET: |
836 return ""; | 838 return ""; |
848 uw_error(ctx, FATAL, "Impossible input kind"); | 850 uw_error(ctx, FATAL, "Impossible input kind"); |
849 } | 851 } |
850 } | 852 } |
851 | 853 |
852 int uw_set_file_input(uw_context ctx, const char *name, uw_Basis_file f) { | 854 int uw_set_file_input(uw_context ctx, const char *name, uw_Basis_file f) { |
853 int n = uw_input_num(name); | 855 int n = ctx->app->input_num(name); |
854 | 856 |
855 if (n < 0) { | 857 if (n < 0) { |
856 uw_set_error(ctx, "Bad file input name %s", name); | 858 uw_set_error(ctx, "Bad file input name %s", name); |
857 return -1; | 859 return -1; |
858 } | 860 } |
859 | 861 |
860 if (n >= uw_inputs_len) { | 862 if (n >= ctx->app->inputs_len) { |
861 uw_set_error(ctx, "For file input name %s, index %d is out of range", name, n); | 863 uw_set_error(ctx, "For file input name %s, index %d is out of range", name, n); |
862 return -1; | 864 return -1; |
863 } | 865 } |
864 | 866 |
865 ctx->inputs[n].kind = FIL; | 867 ctx->inputs[n].kind = FIL; |
867 | 869 |
868 return 0; | 870 return 0; |
869 } | 871 } |
870 | 872 |
871 void *uw_malloc(uw_context ctx, size_t len); | 873 void *uw_malloc(uw_context ctx, size_t len); |
872 | |
873 | 874 |
874 static void parents(input *inp) { | 875 static void parents(input *inp) { |
875 printf("Stack: %p\n", inp); | 876 printf("Stack: %p\n", inp); |
876 while (inp) { | 877 while (inp) { |
877 switch (inp->kind) { | 878 switch (inp->kind) { |
900 } | 901 } |
901 | 902 |
902 uw_Basis_file uw_get_file_input(uw_context ctx, int n) { | 903 uw_Basis_file uw_get_file_input(uw_context ctx, int n) { |
903 if (n < 0) | 904 if (n < 0) |
904 uw_error(ctx, FATAL, "Negative file input index %d", n); | 905 uw_error(ctx, FATAL, "Negative file input index %d", n); |
905 if (n >= uw_inputs_len) | 906 if (n >= ctx->app->inputs_len) |
906 uw_error(ctx, FATAL, "Out-of-bounds file input index %d", n); | 907 uw_error(ctx, FATAL, "Out-of-bounds file input index %d", n); |
907 | 908 |
908 switch (INP(ctx)[n].kind) { | 909 switch (INP(ctx)[n].kind) { |
909 case UNSET: | 910 case UNSET: |
910 { | 911 { |
928 } | 929 } |
929 | 930 |
930 void uw_enter_subform(uw_context ctx, int n) { | 931 void uw_enter_subform(uw_context ctx, int n) { |
931 if (n < 0) | 932 if (n < 0) |
932 uw_error(ctx, FATAL, "Negative subform index %d", n); | 933 uw_error(ctx, FATAL, "Negative subform index %d", n); |
933 if (n >= uw_inputs_len) | 934 if (n >= ctx->app->inputs_len) |
934 uw_error(ctx, FATAL, "Out-of-bounds subform index %d", n); | 935 uw_error(ctx, FATAL, "Out-of-bounds subform index %d", n); |
935 | 936 |
936 switch (INP(ctx)[n].kind) { | 937 switch (INP(ctx)[n].kind) { |
937 case UNSET: | 938 case UNSET: |
938 uw_error(ctx, FATAL, "Missing subform"); | 939 uw_error(ctx, FATAL, "Missing subform"); |
967 int uw_enter_subforms(uw_context ctx, int n) { | 968 int uw_enter_subforms(uw_context ctx, int n) { |
968 input *inps; | 969 input *inps; |
969 | 970 |
970 if (n < 0) | 971 if (n < 0) |
971 uw_error(ctx, FATAL, "Negative subforms index %d", n); | 972 uw_error(ctx, FATAL, "Negative subforms index %d", n); |
972 if (n >= uw_inputs_len) | 973 if (n >= ctx->app->inputs_len) |
973 uw_error(ctx, FATAL, "Out-of-bounds subforms index %d", n); | 974 uw_error(ctx, FATAL, "Out-of-bounds subforms index %d", n); |
974 | 975 |
975 switch (INP(ctx)[n].kind) { | 976 switch (INP(ctx)[n].kind) { |
976 case UNSET: | 977 case UNSET: |
977 uw_error(ctx, FATAL, "Missing subforms"); | 978 uw_error(ctx, FATAL, "Missing subforms"); |
1026 | 1027 |
1027 void uw_set_script_header(uw_context ctx, const char *s) { | 1028 void uw_set_script_header(uw_context ctx, const char *s) { |
1028 ctx->script_header = s; | 1029 ctx->script_header = s; |
1029 } | 1030 } |
1030 | 1031 |
1031 void uw_set_url_prefix(uw_context ctx, const char *s) { | 1032 const char *uw_get_url_prefix(uw_context ctx) { |
1032 ctx->url_prefix = s; | 1033 return ctx->app->url_prefix; |
1033 } | 1034 } |
1034 | 1035 |
1035 void uw_set_needs_push(uw_context ctx, int n) { | 1036 void uw_set_needs_push(uw_context ctx, int n) { |
1036 ctx->needs_push = n; | 1037 ctx->needs_push = n; |
1037 } | 1038 } |
1202 sprintf(r, " onunload='unload();%s'", s); | 1203 sprintf(r, " onunload='unload();%s'", s); |
1203 return r; | 1204 return r; |
1204 } | 1205 } |
1205 } | 1206 } |
1206 | 1207 |
1207 extern uw_Basis_string uw_cookie_sig(uw_context); | |
1208 | |
1209 const char *uw_Basis_get_settings(uw_context ctx, uw_unit u) { | 1208 const char *uw_Basis_get_settings(uw_context ctx, uw_unit u) { |
1210 if (ctx->client == NULL) { | 1209 if (ctx->client == NULL) { |
1211 if (ctx->needs_sig) { | 1210 if (ctx->needs_sig) { |
1212 char *sig = uw_cookie_sig(ctx); | 1211 char *sig = ctx->app->cookie_sig(ctx); |
1213 char *r = uw_malloc(ctx, strlen(sig) + 8); | 1212 char *r = uw_malloc(ctx, strlen(sig) + 8); |
1214 sprintf(r, "sig=\"%s\";", sig); | 1213 sprintf(r, "sig=\"%s\";", sig); |
1215 return r; | 1214 return r; |
1216 } | 1215 } |
1217 else | 1216 else |
1218 return ""; | 1217 return ""; |
1219 } else { | 1218 } else { |
1220 char *sig = ctx->needs_sig ? uw_cookie_sig(ctx) : ""; | 1219 char *sig = ctx->needs_sig ? ctx->app->cookie_sig(ctx) : ""; |
1221 char *r = uw_malloc(ctx, 59 + 3 * INTS_MAX + strlen(ctx->url_prefix) | 1220 char *r = uw_malloc(ctx, 59 + 3 * INTS_MAX + strlen(ctx->app->url_prefix) |
1222 + (ctx->needs_sig ? strlen(sig) + 7 : 0)); | 1221 + (ctx->needs_sig ? strlen(sig) + 7 : 0)); |
1223 sprintf(r, "client_id=%u;client_pass=%d;url_prefix=\"%s\";timeout=%d;%s%s%slistener();", | 1222 sprintf(r, "client_id=%u;client_pass=%d;url_prefix=\"%s\";timeout=%d;%s%s%slistener();", |
1224 ctx->client->id, | 1223 ctx->client->id, |
1225 ctx->client->pass, | 1224 ctx->client->pass, |
1226 ctx->url_prefix, | 1225 ctx->app->url_prefix, |
1227 ctx->timeout, | 1226 ctx->app->timeout, |
1228 ctx->needs_sig ? "sig=\"" : "", | 1227 ctx->needs_sig ? "sig=\"" : "", |
1229 sig, | 1228 sig, |
1230 ctx->needs_sig ? "\";" : ""); | 1229 ctx->needs_sig ? "\";" : ""); |
1231 return r; | 1230 return r; |
1232 } | 1231 } |
2764 buf_append(&d->msgs, "\n", 1); | 2763 buf_append(&d->msgs, "\n", 1); |
2765 | 2764 |
2766 return uw_unit_v; | 2765 return uw_unit_v; |
2767 } | 2766 } |
2768 | 2767 |
2769 int uw_db_commit(uw_context); | |
2770 int uw_db_rollback(uw_context); | |
2771 | |
2772 void uw_commit(uw_context ctx) { | 2768 void uw_commit(uw_context ctx) { |
2773 unsigned i; | 2769 unsigned i; |
2774 | 2770 |
2775 for (i = 0; i < ctx->used_transactionals; ++i) | 2771 for (i = 0; i < ctx->used_transactionals; ++i) |
2776 if (ctx->transactionals[i].rollback != NULL) | 2772 if (ctx->transactionals[i].rollback != NULL) |
2780 for (i = 0; i < ctx->used_transactionals; ++i) | 2776 for (i = 0; i < ctx->used_transactionals; ++i) |
2781 if (ctx->transactionals[i].rollback == NULL) | 2777 if (ctx->transactionals[i].rollback == NULL) |
2782 if (ctx->transactionals[i].commit) | 2778 if (ctx->transactionals[i].commit) |
2783 ctx->transactionals[i].commit(ctx->transactionals[i].data); | 2779 ctx->transactionals[i].commit(ctx->transactionals[i].data); |
2784 | 2780 |
2785 if (uw_db_commit(ctx)) | 2781 if (ctx->app->db_commit(ctx)) |
2786 uw_error(ctx, FATAL, "Error running SQL COMMIT"); | 2782 uw_error(ctx, FATAL, "Error running SQL COMMIT"); |
2787 | 2783 |
2788 for (i = 0; i < ctx->used_deltas; ++i) { | 2784 for (i = 0; i < ctx->used_deltas; ++i) { |
2789 delta *d = &ctx->deltas[i]; | 2785 delta *d = &ctx->deltas[i]; |
2790 client *c = find_client(d->client); | 2786 client *c = find_client(d->client); |
2853 | 2849 |
2854 for (i = 0; i < ctx->used_transactionals; ++i) | 2850 for (i = 0; i < ctx->used_transactionals; ++i) |
2855 if (ctx->transactionals[i].free) | 2851 if (ctx->transactionals[i].free) |
2856 ctx->transactionals[i].free(ctx->transactionals[i].data); | 2852 ctx->transactionals[i].free(ctx->transactionals[i].data); |
2857 | 2853 |
2858 return uw_db_rollback(ctx); | 2854 return ctx->app->db_rollback(ctx); |
2859 } | 2855 } |
2860 | 2856 |
2861 void uw_register_transactional(uw_context ctx, void *data, uw_callback commit, uw_callback rollback, | 2857 void uw_register_transactional(uw_context ctx, void *data, uw_callback commit, uw_callback rollback, |
2862 uw_callback free) { | 2858 uw_callback free) { |
2863 if (ctx->used_transactionals >= ctx->n_transactionals) { | 2859 if (ctx->used_transactionals >= ctx->n_transactionals) { |
2872 } | 2868 } |
2873 | 2869 |
2874 | 2870 |
2875 // "Garbage collection" | 2871 // "Garbage collection" |
2876 | 2872 |
2877 void uw_expunger(uw_context ctx, uw_Basis_client cli); | |
2878 | |
2879 static failure_kind uw_expunge(uw_context ctx, uw_Basis_client cli) { | 2873 static failure_kind uw_expunge(uw_context ctx, uw_Basis_client cli) { |
2880 int r = setjmp(ctx->jmp_buf); | 2874 int r = setjmp(ctx->jmp_buf); |
2881 | 2875 |
2882 if (r == 0) { | 2876 if (r == 0) { |
2883 if (uw_db_begin(ctx)) | 2877 if (ctx->app->db_begin(ctx)) |
2884 uw_error(ctx, FATAL, "Error running SQL BEGIN"); | 2878 uw_error(ctx, FATAL, "Error running SQL BEGIN"); |
2885 uw_expunger(ctx, cli); | 2879 ctx->app->expunger(ctx, cli); |
2886 if (uw_db_commit(ctx)) | 2880 if (ctx->app->db_commit(ctx)) |
2887 uw_error(ctx, FATAL, "Error running SQL COMMIT"); | 2881 uw_error(ctx, FATAL, "Error running SQL COMMIT"); |
2888 } | 2882 } |
2889 | 2883 |
2890 return r; | 2884 return r; |
2891 } | 2885 } |
2892 | 2886 |
2893 void uw_prune_clients(uw_context ctx) { | 2887 void uw_prune_clients(uw_context ctx) { |
2894 client *c, *next, *prev = NULL; | 2888 client *c, *next, *prev = NULL; |
2895 time_t cutoff; | 2889 time_t cutoff; |
2896 | 2890 |
2897 cutoff = time(NULL) - uw_timeout; | 2891 cutoff = time(NULL) - ctx->app->timeout; |
2898 | 2892 |
2899 pthread_mutex_lock(&clients_mutex); | 2893 pthread_mutex_lock(&clients_mutex); |
2900 | 2894 |
2901 for (c = clients_used; c; c = next) { | 2895 for (c = clients_used; c; c = next) { |
2902 next = c->next; | 2896 next = c->next; |
2909 clients_used = next; | 2903 clients_used = next; |
2910 uw_reset(ctx); | 2904 uw_reset(ctx); |
2911 while (fk == UNLIMITED_RETRY) { | 2905 while (fk == UNLIMITED_RETRY) { |
2912 fk = uw_expunge(ctx, c->id); | 2906 fk = uw_expunge(ctx, c->id); |
2913 if (fk == UNLIMITED_RETRY) { | 2907 if (fk == UNLIMITED_RETRY) { |
2914 uw_db_rollback(ctx); | 2908 ctx->app->db_rollback(ctx); |
2915 printf("Unlimited retry during expunge: %s\n", uw_error_message(ctx)); | 2909 printf("Unlimited retry during expunge: %s\n", uw_error_message(ctx)); |
2916 } | 2910 } |
2917 } | 2911 } |
2918 if (fk == SUCCESS) | 2912 if (fk == SUCCESS) |
2919 free_client(c); | 2913 free_client(c); |
2920 else { | 2914 else { |
2921 uw_db_rollback(ctx); | 2915 ctx->app->db_rollback(ctx); |
2922 fprintf(stderr, "Expunge blocked by error: %s\n", uw_error_message(ctx)); | 2916 fprintf(stderr, "Expunge blocked by error: %s\n", uw_error_message(ctx)); |
2923 } | 2917 } |
2924 } | 2918 } |
2925 else | 2919 else |
2926 prev = c; | 2920 prev = c; |
2928 } | 2922 } |
2929 | 2923 |
2930 pthread_mutex_unlock(&clients_mutex); | 2924 pthread_mutex_unlock(&clients_mutex); |
2931 } | 2925 } |
2932 | 2926 |
2933 void uw_initializer(uw_context ctx); | |
2934 | |
2935 failure_kind uw_initialize(uw_context ctx) { | 2927 failure_kind uw_initialize(uw_context ctx) { |
2936 int r = setjmp(ctx->jmp_buf); | 2928 int r = setjmp(ctx->jmp_buf); |
2937 | 2929 |
2938 if (r == 0) { | 2930 if (r == 0) { |
2939 if (uw_db_begin(ctx)) | 2931 if (ctx->app->db_begin(ctx)) |
2940 uw_error(ctx, FATAL, "Error running SQL BEGIN"); | 2932 uw_error(ctx, FATAL, "Error running SQL BEGIN"); |
2941 uw_initializer(ctx); | 2933 ctx->app->initializer(ctx); |
2942 if (uw_db_commit(ctx)) | 2934 if (ctx->app->db_commit(ctx)) |
2943 uw_error(ctx, FATAL, "Error running SQL COMMIT"); | 2935 uw_error(ctx, FATAL, "Error running SQL COMMIT"); |
2944 } | 2936 } |
2945 | 2937 |
2946 return r; | 2938 return r; |
2947 } | 2939 } |
2948 | |
2949 extern int uw_check_url(const char *); | |
2950 extern int uw_check_mime(const char *); | |
2951 | 2940 |
2952 static int url_bad(uw_Basis_string s) { | 2941 static int url_bad(uw_Basis_string s) { |
2953 for (; *s; ++s) | 2942 for (; *s; ++s) |
2954 if (!isgraph(*s)) | 2943 if (!isgraph(*s)) |
2955 return 1; | 2944 return 1; |
2958 } | 2947 } |
2959 | 2948 |
2960 uw_Basis_string uw_Basis_bless(uw_context ctx, uw_Basis_string s) { | 2949 uw_Basis_string uw_Basis_bless(uw_context ctx, uw_Basis_string s) { |
2961 if (url_bad(s)) | 2950 if (url_bad(s)) |
2962 uw_error(ctx, FATAL, "Invalid URL %s", uw_Basis_htmlifyString(ctx, s)); | 2951 uw_error(ctx, FATAL, "Invalid URL %s", uw_Basis_htmlifyString(ctx, s)); |
2963 if (uw_check_url(s)) | 2952 if (ctx->app->check_url(s)) |
2964 return s; | 2953 return s; |
2965 else | 2954 else |
2966 uw_error(ctx, FATAL, "Disallowed URL %s", uw_Basis_htmlifyString(ctx, s)); | 2955 uw_error(ctx, FATAL, "Disallowed URL %s", uw_Basis_htmlifyString(ctx, s)); |
2967 } | 2956 } |
2968 | 2957 |
2969 uw_Basis_string uw_Basis_checkUrl(uw_context ctx, uw_Basis_string s) { | 2958 uw_Basis_string uw_Basis_checkUrl(uw_context ctx, uw_Basis_string s) { |
2970 if (url_bad(s)) | 2959 if (url_bad(s)) |
2971 return NULL; | 2960 return NULL; |
2972 if (uw_check_url(s)) | 2961 if (ctx->app->check_url(s)) |
2973 return s; | 2962 return s; |
2974 else | 2963 else |
2975 return NULL; | 2964 return NULL; |
2976 } | 2965 } |
2977 | 2966 |
2985 | 2974 |
2986 uw_Basis_string uw_Basis_blessMime(uw_context ctx, uw_Basis_string s) { | 2975 uw_Basis_string uw_Basis_blessMime(uw_context ctx, uw_Basis_string s) { |
2987 if (!mime_format(s)) | 2976 if (!mime_format(s)) |
2988 uw_error(ctx, FATAL, "MIME type \"%s\" contains invalid character", uw_Basis_htmlifyString(ctx, s)); | 2977 uw_error(ctx, FATAL, "MIME type \"%s\" contains invalid character", uw_Basis_htmlifyString(ctx, s)); |
2989 | 2978 |
2990 if (uw_check_mime(s)) | 2979 if (ctx->app->check_mime(s)) |
2991 return s; | 2980 return s; |
2992 else | 2981 else |
2993 uw_error(ctx, FATAL, "Disallowed MIME type %s", uw_Basis_htmlifyString(ctx, s)); | 2982 uw_error(ctx, FATAL, "Disallowed MIME type %s", uw_Basis_htmlifyString(ctx, s)); |
2994 } | 2983 } |
2995 | 2984 |
2996 uw_Basis_string uw_Basis_checkMime(uw_context ctx, uw_Basis_string s) { | 2985 uw_Basis_string uw_Basis_checkMime(uw_context ctx, uw_Basis_string s) { |
2997 if (!mime_format(s)) | 2986 if (!mime_format(s)) |
2998 return NULL; | 2987 return NULL; |
2999 | 2988 |
3000 if (uw_check_mime(s)) | 2989 if (ctx->app->check_mime(s)) |
3001 return s; | 2990 return s; |
3002 else | 2991 else |
3003 return NULL; | 2992 return NULL; |
3004 } | 2993 } |
3005 | 2994 |
3018 | 3007 |
3019 return r; | 3008 return r; |
3020 } | 3009 } |
3021 | 3010 |
3022 uw_Basis_string uw_Basis_sigString(uw_context ctx, uw_unit u) { | 3011 uw_Basis_string uw_Basis_sigString(uw_context ctx, uw_unit u) { |
3023 return uw_cookie_sig(ctx); | 3012 return ctx->app->cookie_sig(ctx); |
3024 } | 3013 } |
3025 | 3014 |
3026 uw_Basis_string uw_Basis_fileName(uw_context ctx, uw_Basis_file f) { | 3015 uw_Basis_string uw_Basis_fileName(uw_context ctx, uw_Basis_file f) { |
3027 return f.name; | 3016 return f.name; |
3028 } | 3017 } |