Mercurial > urweb
comparison src/c/urweb.c @ 1113:40d48a2b78a7
Memory limits
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Sun, 03 Jan 2010 15:32:11 -0500 |
parents | 7fc4e0087e50 |
children | 01b6c7144a44 |
comparison
equal
deleted
inserted
replaced
1112:7a31e0cf25e9 | 1113:40d48a2b78a7 |
---|---|
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 <stdint.h> | |
12 #include <sys/types.h> | 13 #include <sys/types.h> |
13 #include <sys/socket.h> | 14 #include <sys/socket.h> |
14 | 15 |
15 #include <pthread.h> | 16 #include <pthread.h> |
16 | 17 |
51 | 52 |
52 | 53 |
53 // Buffers | 54 // Buffers |
54 | 55 |
55 typedef struct { | 56 typedef struct { |
57 size_t max; | |
56 char *start, *front, *back; | 58 char *start, *front, *back; |
57 } buf; | 59 } buf; |
58 | 60 |
59 static void buf_init(buf *b, size_t s) { | 61 static void buf_init(size_t max, buf *b, size_t s) { |
62 b->max = max; | |
60 b->front = b->start = malloc(s); | 63 b->front = b->start = malloc(s); |
61 b->back = b->front + s; | 64 b->back = b->front + s; |
62 } | 65 } |
63 | 66 |
64 static void buf_free(buf *b) { | 67 static void buf_free(buf *b) { |
67 | 70 |
68 static void buf_reset(buf *b) { | 71 static void buf_reset(buf *b) { |
69 b->front = b->start; | 72 b->front = b->start; |
70 } | 73 } |
71 | 74 |
72 static void buf_check(buf *b, size_t extra) { | 75 static int buf_check(buf *b, size_t extra) { |
73 if (b->back - b->front < extra) { | 76 if (b->back - b->front < extra) { |
74 size_t desired = b->front - b->start + extra, next; | 77 size_t desired = b->front - b->start + extra, next; |
75 char *new_heap; | 78 char *new_heap; |
76 | 79 |
77 next = b->back - b->start; | 80 next = b->back - b->start; |
78 if (next == 0) | 81 if (next == 0) |
79 next = 1; | 82 next = 1; |
80 for (; next < desired; next *= 2); | 83 for (; next < desired; next *= 2); |
81 | 84 |
85 if (next > b->max) | |
86 if (desired <= b->max) | |
87 next = desired; | |
88 else | |
89 return 1; | |
90 | |
82 new_heap = realloc(b->start, next); | 91 new_heap = realloc(b->start, next); |
83 b->front = new_heap + (b->front - b->start); | 92 b->front = new_heap + (b->front - b->start); |
84 b->back = new_heap + next; | 93 b->back = new_heap + next; |
85 b->start = new_heap; | 94 b->start = new_heap; |
86 } | 95 } |
96 | |
97 return 0; | |
98 } | |
99 | |
100 __attribute__((noreturn)) void uw_error(uw_context, failure_kind, const char *, ...); | |
101 | |
102 static void ctx_buf_check(uw_context ctx, const char *kind, buf *b, size_t extra) { | |
103 if (buf_check(b, extra)) | |
104 uw_error(ctx, FATAL, "Memory limit exceeded (%s)", kind); | |
87 } | 105 } |
88 | 106 |
89 static size_t buf_used(buf *b) { | 107 static size_t buf_used(buf *b) { |
90 return b->front - b->start; | 108 return b->front - b->start; |
91 } | 109 } |
92 | 110 |
93 static size_t buf_avail(buf *b) { | 111 static size_t buf_avail(buf *b) { |
94 return b->back - b->start; | 112 return b->back - b->start; |
95 } | 113 } |
96 | 114 |
97 static void buf_append(buf *b, const char *s, size_t len) { | 115 static int buf_append(buf *b, const char *s, size_t len) { |
98 buf_check(b, len+1); | 116 if (buf_check(b, len+1)) |
117 return 1; | |
118 | |
119 memcpy(b->front, s, len); | |
120 b->front += len; | |
121 *b->front = 0; | |
122 | |
123 return 0; | |
124 } | |
125 | |
126 static void ctx_buf_append(uw_context ctx, const char *kind, buf *b, const char *s, size_t len) { | |
127 ctx_buf_check(ctx, kind, b, len+1); | |
128 | |
99 memcpy(b->front, s, len); | 129 memcpy(b->front, s, len); |
100 b->front += len; | 130 b->front += len; |
101 *b->front = 0; | 131 *b->front = 0; |
102 } | 132 } |
103 | 133 |
127 static client **clients, *clients_free, *clients_used; | 157 static client **clients, *clients_free, *clients_used; |
128 static unsigned n_clients; | 158 static unsigned n_clients; |
129 | 159 |
130 static pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER; | 160 static pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER; |
131 | 161 |
162 size_t uw_messages_max = SIZE_MAX; | |
163 size_t uw_clients_max = SIZE_MAX; | |
164 | |
132 static client *new_client() { | 165 static client *new_client() { |
133 client *c; | 166 client *c; |
134 | 167 |
135 pthread_mutex_lock(&clients_mutex); | 168 pthread_mutex_lock(&clients_mutex); |
136 | 169 |
137 if (clients_free) { | 170 if (clients_free) { |
138 c = clients_free; | 171 c = clients_free; |
139 clients_free = clients_free->next; | 172 clients_free = clients_free->next; |
140 } | 173 } |
174 else if (n_clients >= uw_clients_max) | |
175 return NULL; | |
141 else { | 176 else { |
142 ++n_clients; | 177 ++n_clients; |
143 clients = realloc(clients, sizeof(client) * n_clients); | 178 clients = realloc(clients, sizeof(client) * n_clients); |
144 c = malloc(sizeof(client)); | 179 c = malloc(sizeof(client)); |
145 c->id = n_clients-1; | 180 c->id = n_clients-1; |
146 pthread_mutex_init(&c->lock, NULL); | 181 pthread_mutex_init(&c->lock, NULL); |
147 pthread_mutex_init(&c->pull_lock, NULL); | 182 pthread_mutex_init(&c->pull_lock, NULL); |
148 buf_init(&c->msgs, 0); | 183 buf_init(uw_messages_max, &c->msgs, 0); |
149 clients[n_clients-1] = c; | 184 clients[n_clients-1] = c; |
150 } | 185 } |
151 | 186 |
152 pthread_mutex_lock(&c->lock); | 187 pthread_mutex_lock(&c->lock); |
153 c->mode = USED; | 188 c->mode = USED; |
278 c->send(c->sock, on_success, strlen(on_success)); | 313 c->send(c->sock, on_success, strlen(on_success)); |
279 c->send(c->sock, begin_msgs, sizeof(begin_msgs) - 1); | 314 c->send(c->sock, begin_msgs, sizeof(begin_msgs) - 1); |
280 c->send(c->sock, msg->start, buf_used(msg)); | 315 c->send(c->sock, msg->start, buf_used(msg)); |
281 c->close(c->sock); | 316 c->close(c->sock); |
282 c->sock = -1; | 317 c->sock = -1; |
283 } else | 318 } else if (buf_append(&c->msgs, msg->start, buf_used(msg))) |
284 buf_append(&c->msgs, msg->start, buf_used(msg)); | 319 fprintf(stderr, "Client message buffer size exceeded"); |
285 | 320 |
286 pthread_mutex_unlock(&c->lock); | 321 pthread_mutex_unlock(&c->lock); |
287 } | 322 } |
288 | 323 |
289 | 324 |
393 char *current_url; | 428 char *current_url; |
394 | 429 |
395 char error_message[ERROR_BUF_LEN]; | 430 char error_message[ERROR_BUF_LEN]; |
396 }; | 431 }; |
397 | 432 |
433 size_t uw_headers_max = SIZE_MAX; | |
434 size_t uw_page_max = SIZE_MAX; | |
435 size_t uw_heap_max = SIZE_MAX; | |
436 size_t uw_script_max = SIZE_MAX; | |
437 | |
398 uw_context uw_init() { | 438 uw_context uw_init() { |
399 uw_context ctx = malloc(sizeof(struct uw_context)); | 439 uw_context ctx = malloc(sizeof(struct uw_context)); |
400 | 440 |
401 ctx->app = NULL; | 441 ctx->app = NULL; |
402 | 442 |
403 ctx->get_header = NULL; | 443 ctx->get_header = NULL; |
404 ctx->get_header_data = NULL; | 444 ctx->get_header_data = NULL; |
405 | 445 |
406 buf_init(&ctx->outHeaders, 0); | 446 buf_init(uw_headers_max, &ctx->outHeaders, 0); |
407 buf_init(&ctx->page, 0); | 447 buf_init(uw_page_max, &ctx->page, 0); |
408 ctx->returning_indirectly = 0; | 448 ctx->returning_indirectly = 0; |
409 buf_init(&ctx->heap, 0); | 449 buf_init(uw_heap_max, &ctx->heap, 0); |
410 buf_init(&ctx->script, 1); | 450 buf_init(uw_script_max, &ctx->script, 1); |
411 ctx->script.start[0] = 0; | 451 ctx->script.start[0] = 0; |
412 | 452 |
413 ctx->inputs = malloc(0); | 453 ctx->inputs = malloc(0); |
414 ctx->cur_container = NULL; | 454 ctx->cur_container = NULL; |
415 ctx->subinputs = malloc(0); | 455 ctx->subinputs = malloc(0); |
445 ctx->current_url = ""; | 485 ctx->current_url = ""; |
446 | 486 |
447 return ctx; | 487 return ctx; |
448 } | 488 } |
449 | 489 |
450 void uw_set_app(uw_context ctx, uw_app *app) { | 490 size_t uw_inputs_max = SIZE_MAX; |
491 | |
492 int uw_set_app(uw_context ctx, uw_app *app) { | |
451 ctx->app = app; | 493 ctx->app = app; |
452 | 494 |
453 if (app && app->inputs_len > ctx->sz_inputs) { | 495 if (app && app->inputs_len > ctx->sz_inputs) { |
496 if (app->inputs_len > uw_inputs_max) | |
497 return 1; | |
498 | |
454 ctx->sz_inputs = app->inputs_len; | 499 ctx->sz_inputs = app->inputs_len; |
455 ctx->inputs = realloc(ctx->inputs, ctx->sz_inputs * sizeof(input)); | 500 ctx->inputs = realloc(ctx->inputs, ctx->sz_inputs * sizeof(input)); |
456 memset(ctx->inputs, 0, ctx->sz_inputs * sizeof(input)); | 501 memset(ctx->inputs, 0, ctx->sz_inputs * sizeof(input)); |
457 } | 502 } |
458 } | 503 } |
553 ctx->cleanup_front = ctx->cleanup; | 598 ctx->cleanup_front = ctx->cleanup; |
554 | 599 |
555 longjmp(ctx->jmp_buf, fk); | 600 longjmp(ctx->jmp_buf, fk); |
556 } | 601 } |
557 | 602 |
603 size_t uw_cleanup_max = SIZE_MAX; | |
604 | |
558 void uw_push_cleanup(uw_context ctx, void (*func)(void *), void *arg) { | 605 void uw_push_cleanup(uw_context ctx, void (*func)(void *), void *arg) { |
559 if (ctx->cleanup_front >= ctx->cleanup_back) { | 606 if (ctx->cleanup_front >= ctx->cleanup_back) { |
560 int len = ctx->cleanup_back - ctx->cleanup, newLen; | 607 int len = ctx->cleanup_back - ctx->cleanup, newLen; |
561 if (len == 0) | 608 if (len == 0) |
562 newLen = 1; | 609 newLen = 1; |
563 else | 610 else |
564 newLen = len * 2; | 611 newLen = len * 2; |
612 | |
613 if (newLen > uw_cleanup_max) | |
614 if (len+1 <= uw_cleanup_max) | |
615 newLen = uw_cleanup_max; | |
616 else | |
617 uw_error(ctx, FATAL, "Exceeded limit on number of cleanup handlers"); | |
618 | |
565 ctx->cleanup = realloc(ctx->cleanup, newLen * sizeof(cleanup)); | 619 ctx->cleanup = realloc(ctx->cleanup, newLen * sizeof(cleanup)); |
566 ctx->cleanup_front = ctx->cleanup + len; | 620 ctx->cleanup_front = ctx->cleanup + len; |
567 ctx->cleanup_back = ctx->cleanup + newLen; | 621 ctx->cleanup_back = ctx->cleanup + newLen; |
568 } | 622 } |
569 | 623 |
597 if (c->pass != pass) | 651 if (c->pass != pass) |
598 uw_error(ctx, FATAL, "Wrong client password (%u, %d) in subscription request", id, pass); | 652 uw_error(ctx, FATAL, "Wrong client password (%u, %d) in subscription request", id, pass); |
599 } | 653 } |
600 } else { | 654 } else { |
601 client *c = new_client(); | 655 client *c = new_client(); |
656 | |
657 if (c == NULL) | |
658 uw_error(ctx, FATAL, "Limit exceeded on number of message-passing clients"); | |
659 | |
602 use_client(c); | 660 use_client(c); |
603 ctx->client = c; | 661 ctx->client = c; |
604 } | 662 } |
605 } | 663 } |
606 } | 664 } |
668 adjust_pointer(&x->data.entry.next, old_start, new_start, len); | 726 adjust_pointer(&x->data.entry.next, old_start, new_start, len); |
669 adjust_pointer(&x->data.entry.parent, old_start, new_start, len); | 727 adjust_pointer(&x->data.entry.parent, old_start, new_start, len); |
670 } | 728 } |
671 } | 729 } |
672 | 730 |
731 size_t uw_subinputs_max = SIZE_MAX; | |
732 | |
673 static input *check_input_space(uw_context ctx, size_t len) { | 733 static input *check_input_space(uw_context ctx, size_t len) { |
674 size_t i; | 734 size_t i; |
675 input *r; | 735 input *r; |
676 | 736 |
677 if (ctx->used_subinputs + len >= ctx->n_subinputs) { | 737 if (ctx->used_subinputs + len >= ctx->n_subinputs) { |
738 if (ctx->used_subinputs + len > uw_subinputs_max) | |
739 uw_error(ctx, FATAL, "Exceeded limit on number of subinputs"); | |
740 | |
678 input *new_subinputs = realloc(ctx->subinputs, sizeof(input) * (ctx->used_subinputs + len)); | 741 input *new_subinputs = realloc(ctx->subinputs, sizeof(input) * (ctx->used_subinputs + len)); |
679 size_t offset = new_subinputs - ctx->subinputs; | 742 size_t offset = new_subinputs - ctx->subinputs; |
680 | 743 |
681 if (ctx->subinputs != new_subinputs) { | 744 if (ctx->subinputs != new_subinputs) { |
682 for (i = 0; i < ctx->used_subinputs; ++i) | 745 for (i = 0; i < ctx->used_subinputs; ++i) |
1045 void uw_set_needs_sig(uw_context ctx, int n) { | 1108 void uw_set_needs_sig(uw_context ctx, int n) { |
1046 ctx->needs_sig = n; | 1109 ctx->needs_sig = n; |
1047 } | 1110 } |
1048 | 1111 |
1049 | 1112 |
1050 static void buf_check_ctx(uw_context ctx, buf *b, size_t extra, const char *desc) { | 1113 static void buf_check_ctx(uw_context ctx, const char *kind, buf *b, size_t extra, const char *desc) { |
1051 if (b->back - b->front < extra) { | 1114 if (b->back - b->front < extra) { |
1052 size_t desired = b->front - b->start + extra, next; | 1115 size_t desired = b->front - b->start + extra, next; |
1053 char *new_heap; | 1116 char *new_heap; |
1054 | 1117 |
1055 next = b->back - b->start; | 1118 next = b->back - b->start; |
1056 if (next == 0) | 1119 if (next == 0) |
1057 next = 1; | 1120 next = 1; |
1058 for (; next < desired; next *= 2); | 1121 for (; next < desired; next *= 2); |
1059 | 1122 |
1123 if (next > b->max) | |
1124 if (desired <= b->max) | |
1125 next = desired; | |
1126 else | |
1127 uw_error(ctx, FATAL, "Memory limit exceeded (%s)", kind); | |
1128 | |
1060 new_heap = realloc(b->start, next); | 1129 new_heap = realloc(b->start, next); |
1061 b->front = new_heap + (b->front - b->start); | 1130 b->front = new_heap + (b->front - b->start); |
1062 b->back = new_heap + next; | 1131 b->back = new_heap + next; |
1063 | 1132 |
1064 if (new_heap != b->start) { | 1133 if (new_heap != b->start) { |
1069 b->start = new_heap; | 1138 b->start = new_heap; |
1070 } | 1139 } |
1071 } | 1140 } |
1072 | 1141 |
1073 void uw_check_heap(uw_context ctx, size_t extra) { | 1142 void uw_check_heap(uw_context ctx, size_t extra) { |
1074 buf_check_ctx(ctx, &ctx->heap, extra, "heap chunk"); | 1143 buf_check_ctx(ctx, "heap", &ctx->heap, extra, "heap chunk"); |
1075 } | 1144 } |
1076 | 1145 |
1077 char *uw_heap_front(uw_context ctx) { | 1146 char *uw_heap_front(uw_context ctx) { |
1078 return ctx->heap.front; | 1147 return ctx->heap.front; |
1079 } | 1148 } |
1161 | 1230 |
1162 return output(data, ctx->page.start, ctx->page.front - ctx->page.start); | 1231 return output(data, ctx->page.start, ctx->page.front - ctx->page.start); |
1163 } | 1232 } |
1164 | 1233 |
1165 static void uw_check_headers(uw_context ctx, size_t extra) { | 1234 static void uw_check_headers(uw_context ctx, size_t extra) { |
1166 buf_check(&ctx->outHeaders, extra); | 1235 ctx_buf_check(ctx, "headers", &ctx->outHeaders, extra); |
1167 } | 1236 } |
1168 | 1237 |
1169 void uw_write_header(uw_context ctx, uw_Basis_string s) { | 1238 void uw_write_header(uw_context ctx, uw_Basis_string s) { |
1170 int len = strlen(s); | 1239 int len = strlen(s); |
1171 | 1240 |
1177 void uw_clear_headers(uw_context ctx) { | 1246 void uw_clear_headers(uw_context ctx) { |
1178 buf_reset(&ctx->outHeaders); | 1247 buf_reset(&ctx->outHeaders); |
1179 } | 1248 } |
1180 | 1249 |
1181 static void uw_check_script(uw_context ctx, size_t extra) { | 1250 static void uw_check_script(uw_context ctx, size_t extra) { |
1182 buf_check(&ctx->script, extra); | 1251 ctx_buf_check(ctx, "script", &ctx->script, extra); |
1183 } | 1252 } |
1184 | 1253 |
1185 void uw_write_script(uw_context ctx, uw_Basis_string s) { | 1254 void uw_write_script(uw_context ctx, uw_Basis_string s) { |
1186 int len = strlen(s); | 1255 int len = strlen(s); |
1187 | 1256 |
1393 | 1462 |
1394 return uw_unit_v; | 1463 return uw_unit_v; |
1395 } | 1464 } |
1396 | 1465 |
1397 static void uw_check(uw_context ctx, size_t extra) { | 1466 static void uw_check(uw_context ctx, size_t extra) { |
1398 buf_check(&ctx->page, extra); | 1467 ctx_buf_check(ctx, "page", &ctx->page, extra); |
1399 } | 1468 } |
1400 | 1469 |
1401 static void uw_writec_unsafe(uw_context ctx, char c) { | 1470 static void uw_writec_unsafe(uw_context ctx, char c) { |
1402 *(ctx->page.front)++ = c; | 1471 *(ctx->page.front)++ = c; |
1403 } | 1472 } |
2734 uw_write_header(ctx, "; " THE_PAST "\r\n"); | 2803 uw_write_header(ctx, "; " THE_PAST "\r\n"); |
2735 | 2804 |
2736 return uw_unit_v; | 2805 return uw_unit_v; |
2737 } | 2806 } |
2738 | 2807 |
2808 size_t uw_deltas_max = SIZE_MAX; | |
2809 | |
2739 static delta *allocate_delta(uw_context ctx, unsigned client) { | 2810 static delta *allocate_delta(uw_context ctx, unsigned client) { |
2740 unsigned i; | 2811 unsigned i; |
2741 delta *d; | 2812 delta *d; |
2742 | 2813 |
2743 for (i = 0; i < ctx->used_deltas; ++i) | 2814 for (i = 0; i < ctx->used_deltas; ++i) |
2744 if (ctx->deltas[i].client == client) | 2815 if (ctx->deltas[i].client == client) |
2745 return &ctx->deltas[i]; | 2816 return &ctx->deltas[i]; |
2746 | 2817 |
2747 if (ctx->used_deltas >= ctx->n_deltas) { | 2818 if (ctx->used_deltas >= ctx->n_deltas) { |
2819 if (ctx->n_deltas + 1 > uw_deltas_max) | |
2820 uw_error(ctx, FATAL, "Exceeded limit on number of deltas"); | |
2821 | |
2748 ctx->deltas = realloc(ctx->deltas, sizeof(delta) * ++ctx->n_deltas); | 2822 ctx->deltas = realloc(ctx->deltas, sizeof(delta) * ++ctx->n_deltas); |
2749 buf_init(&ctx->deltas[ctx->n_deltas-1].msgs, 0); | 2823 buf_init(uw_messages_max, &ctx->deltas[ctx->n_deltas-1].msgs, 0); |
2750 } | 2824 } |
2751 | 2825 |
2752 d = &ctx->deltas[ctx->used_deltas++]; | 2826 d = &ctx->deltas[ctx->used_deltas++]; |
2753 d->client = client; | 2827 d->client = client; |
2754 buf_reset(&d->msgs); | 2828 buf_reset(&d->msgs); |
2770 | 2844 |
2771 len = strlen(msg); | 2845 len = strlen(msg); |
2772 | 2846 |
2773 sprintf(pre, "%u\n%n", chn.chn, &preLen); | 2847 sprintf(pre, "%u\n%n", chn.chn, &preLen); |
2774 | 2848 |
2775 buf_append(&d->msgs, pre, preLen); | 2849 ctx_buf_append(ctx, "messages", &d->msgs, pre, preLen); |
2776 buf_append(&d->msgs, msg, len); | 2850 ctx_buf_append(ctx, "messages", &d->msgs, msg, len); |
2777 buf_append(&d->msgs, "\n", 1); | 2851 ctx_buf_append(ctx, "messages", &d->msgs, "\n", 1); |
2778 | 2852 |
2779 return uw_unit_v; | 2853 return uw_unit_v; |
2780 } | 2854 } |
2781 | 2855 |
2782 void uw_commit(uw_context ctx) { | 2856 void uw_commit(uw_context ctx) { |
2820 } | 2894 } |
2821 } else if (buf_used(&ctx->script) == 0) { | 2895 } else if (buf_used(&ctx->script) == 0) { |
2822 size_t len = strlen(ctx->script_header); | 2896 size_t len = strlen(ctx->script_header); |
2823 char *start = strstr(ctx->page.start, "<sc>"); | 2897 char *start = strstr(ctx->page.start, "<sc>"); |
2824 if (start) { | 2898 if (start) { |
2825 buf_check(&ctx->page, buf_used(&ctx->page) - 4 + len); | 2899 ctx_buf_check(ctx, "page", &ctx->page, buf_used(&ctx->page) - 4 + len); |
2826 start = strstr(ctx->page.start, "<sc>"); | 2900 start = strstr(ctx->page.start, "<sc>"); |
2827 memmove(start + len, start + 4, buf_used(&ctx->page) - (start - ctx->page.start) - 3); | 2901 memmove(start + len, start + 4, buf_used(&ctx->page) - (start - ctx->page.start) - 3); |
2828 ctx->page.front += len - 4; | 2902 ctx->page.front += len - 4; |
2829 memcpy(start, ctx->script_header, len); | 2903 memcpy(start, ctx->script_header, len); |
2830 } | 2904 } |
2831 } else { | 2905 } else { |
2832 size_t lenH = strlen(ctx->script_header), len = buf_used(&ctx->script); | 2906 size_t lenH = strlen(ctx->script_header), len = buf_used(&ctx->script); |
2833 size_t lenP = lenH + 40 + len; | 2907 size_t lenP = lenH + 40 + len; |
2834 char *start = strstr(ctx->page.start, "<sc>"); | 2908 char *start = strstr(ctx->page.start, "<sc>"); |
2835 if (start) { | 2909 if (start) { |
2836 buf_check(&ctx->page, buf_used(&ctx->page) - 4 + lenP); | 2910 ctx_buf_check(ctx, "page", &ctx->page, buf_used(&ctx->page) - 4 + lenP); |
2837 start = strstr(ctx->page.start, "<sc>"); | 2911 start = strstr(ctx->page.start, "<sc>"); |
2838 memmove(start + lenP, start + 4, buf_used(&ctx->page) - (start - ctx->page.start) - 3); | 2912 memmove(start + lenP, start + 4, buf_used(&ctx->page) - (start - ctx->page.start) - 3); |
2839 ctx->page.front += lenP - 4; | 2913 ctx->page.front += lenP - 4; |
2840 memcpy(start, ctx->script_header, lenH); | 2914 memcpy(start, ctx->script_header, lenH); |
2841 memcpy(start + lenH, "<script type=\"text/javascript\">", 31); | 2915 memcpy(start + lenH, "<script type=\"text/javascript\">", 31); |
2866 ctx->transactionals[i].free(ctx->transactionals[i].data); | 2940 ctx->transactionals[i].free(ctx->transactionals[i].data); |
2867 | 2941 |
2868 return ctx->app->db_rollback(ctx); | 2942 return ctx->app->db_rollback(ctx); |
2869 } | 2943 } |
2870 | 2944 |
2945 size_t uw_transactionals_max = SIZE_MAX; | |
2946 | |
2871 void uw_register_transactional(uw_context ctx, void *data, uw_callback commit, uw_callback rollback, | 2947 void uw_register_transactional(uw_context ctx, void *data, uw_callback commit, uw_callback rollback, |
2872 uw_callback free) { | 2948 uw_callback free) { |
2873 if (ctx->used_transactionals >= ctx->n_transactionals) { | 2949 if (ctx->used_transactionals >= ctx->n_transactionals) { |
2950 if (ctx->used_transactionals+1 > uw_transactionals_max) | |
2951 uw_error(ctx, FATAL, "Exceeded limit on number of transactionals"); | |
2874 ctx->transactionals = realloc(ctx->transactionals, sizeof(transactional) * (ctx->used_transactionals+1)); | 2952 ctx->transactionals = realloc(ctx->transactionals, sizeof(transactional) * (ctx->used_transactionals+1)); |
2875 ++ctx->n_transactionals; | 2953 ++ctx->n_transactionals; |
2876 } | 2954 } |
2877 | 2955 |
2878 ctx->transactionals[ctx->used_transactionals].data = data; | 2956 ctx->transactionals[ctx->used_transactionals].data = data; |
3052 | 3130 |
3053 uw_write_header(ctx, on_success); | 3131 uw_write_header(ctx, on_success); |
3054 uw_write_header(ctx, "Content-Type: "); | 3132 uw_write_header(ctx, "Content-Type: "); |
3055 uw_write_header(ctx, mimeType); | 3133 uw_write_header(ctx, mimeType); |
3056 uw_write_header(ctx, "\r\nContent-Length: "); | 3134 uw_write_header(ctx, "\r\nContent-Length: "); |
3057 buf_check(&ctx->outHeaders, INTS_MAX); | 3135 ctx_buf_check(ctx, "headers", &ctx->outHeaders, INTS_MAX); |
3058 sprintf(ctx->outHeaders.front, "%d%n", b.size, &len); | 3136 sprintf(ctx->outHeaders.front, "%d%n", b.size, &len); |
3059 ctx->outHeaders.front += len; | 3137 ctx->outHeaders.front += len; |
3060 uw_write_header(ctx, "\r\n"); | 3138 uw_write_header(ctx, "\r\n"); |
3061 | 3139 |
3062 buf_append(&ctx->page, b.data, b.size); | 3140 ctx_buf_append(ctx, "page", &ctx->page, b.data, b.size); |
3063 | 3141 |
3064 for (cl = ctx->cleanup; cl < ctx->cleanup_front; ++cl) | 3142 for (cl = ctx->cleanup; cl < ctx->cleanup_front; ++cl) |
3065 cl->func(cl->arg); | 3143 cl->func(cl->arg); |
3066 | 3144 |
3067 ctx->cleanup_front = ctx->cleanup; | 3145 ctx->cleanup_front = ctx->cleanup; |
3074 int len; | 3152 int len; |
3075 char *s; | 3153 char *s; |
3076 | 3154 |
3077 ctx->returning_indirectly = 1; | 3155 ctx->returning_indirectly = 1; |
3078 buf_reset(&ctx->page); | 3156 buf_reset(&ctx->page); |
3079 buf_check(&ctx->page, buf_used(&ctx->outHeaders)+1); | 3157 ctx_buf_check(ctx, "page", &ctx->page, buf_used(&ctx->outHeaders)+1); |
3080 memcpy(ctx->page.start, ctx->outHeaders.start, buf_used(&ctx->outHeaders)); | 3158 memcpy(ctx->page.start, ctx->outHeaders.start, buf_used(&ctx->outHeaders)); |
3081 ctx->page.start[buf_used(&ctx->outHeaders)] = 0; | 3159 ctx->page.start[buf_used(&ctx->outHeaders)] = 0; |
3082 buf_reset(&ctx->outHeaders); | 3160 buf_reset(&ctx->outHeaders); |
3083 | 3161 |
3084 uw_write_header(ctx, on_redirect); | 3162 uw_write_header(ctx, on_redirect); |
3176 return ctx->globals[i].data; | 3254 return ctx->globals[i].data; |
3177 | 3255 |
3178 return NULL; | 3256 return NULL; |
3179 } | 3257 } |
3180 | 3258 |
3259 size_t uw_globals_max = SIZE_MAX; | |
3260 | |
3181 void uw_set_global(uw_context ctx, char *name, void *data, void (*free)(void*)) { | 3261 void uw_set_global(uw_context ctx, char *name, void *data, void (*free)(void*)) { |
3182 int i; | 3262 int i; |
3183 | 3263 |
3184 for (i = 0; i < ctx->n_globals; ++i) | 3264 for (i = 0; i < ctx->n_globals; ++i) |
3185 if (!strcmp(name, ctx->globals[i].name)) { | 3265 if (!strcmp(name, ctx->globals[i].name)) { |
3188 ctx->globals[i].data = data; | 3268 ctx->globals[i].data = data; |
3189 ctx->globals[i].free = free; | 3269 ctx->globals[i].free = free; |
3190 return; | 3270 return; |
3191 } | 3271 } |
3192 | 3272 |
3273 if (ctx->n_globals+1 > uw_globals_max) | |
3274 uw_error(ctx, FATAL, "Exceeded limit on number of globals"); | |
3275 | |
3193 ++ctx->n_globals; | 3276 ++ctx->n_globals; |
3194 ctx->globals = realloc(ctx->globals, ctx->n_globals * sizeof(global)); | 3277 ctx->globals = realloc(ctx->globals, ctx->n_globals * sizeof(global)); |
3195 ctx->globals[ctx->n_globals-1].name = name; | 3278 ctx->globals[ctx->n_globals-1].name = name; |
3196 ctx->globals[ctx->n_globals-1].data = data; | 3279 ctx->globals[ctx->n_globals-1].data = data; |
3197 ctx->globals[ctx->n_globals-1].free = free; | 3280 ctx->globals[ctx->n_globals-1].free = free; |