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;