comparison src/c/urweb.c @ 1979:81bc76aa4acd

Merge in upstream changes.
author Patrick Hurst <phurst@mit.edu>
date Sat, 18 Jan 2014 18:26:24 -0500
parents 155bd0bc4d28 ac1be85e91ad
children e90f218f2d48
comparison
equal deleted inserted replaced
1978:c5143edaf3c7 1979:81bc76aa4acd
429 size_t sz_inputs, n_subinputs, used_subinputs; 429 size_t sz_inputs, n_subinputs, used_subinputs;
430 430
431 unsigned long long source_count; 431 unsigned long long source_count;
432 432
433 void *db; 433 void *db;
434 int transaction_started;
434 435
435 jmp_buf jmp_buf; 436 jmp_buf jmp_buf;
436 437
437 regions *regions; 438 regions *regions;
438 439
439 cleanup *cleanup, *cleanup_front, *cleanup_back; 440 cleanup *cleanup, *cleanup_front, *cleanup_back;
440 441
441 const char *script_header; 442 const char *script_header;
442 443
443 int needs_push, needs_sig; 444 int needs_push, needs_sig, could_write_db;
444 445
445 size_t n_deltas, used_deltas; 446 size_t n_deltas, used_deltas;
446 delta *deltas; 447 delta *deltas;
447 448
448 client *client; 449 client *client;
471 int amInitializing; 472 int amInitializing;
472 473
473 char error_message[ERROR_BUF_LEN]; 474 char error_message[ERROR_BUF_LEN];
474 475
475 int usedSig, needsResig; 476 int usedSig, needsResig;
477
478 char *output_buffer;
479 size_t output_buffer_size;
476 }; 480 };
477 481
478 size_t uw_headers_max = SIZE_MAX; 482 size_t uw_headers_max = SIZE_MAX;
479 size_t uw_page_max = SIZE_MAX; 483 size_t uw_page_max = SIZE_MAX;
480 size_t uw_heap_max = SIZE_MAX; 484 size_t uw_heap_max = SIZE_MAX;
505 ctx->cur_container = NULL; 509 ctx->cur_container = NULL;
506 ctx->subinputs = malloc(0); 510 ctx->subinputs = malloc(0);
507 ctx->sz_inputs = ctx->n_subinputs = ctx->used_subinputs = 0; 511 ctx->sz_inputs = ctx->n_subinputs = ctx->used_subinputs = 0;
508 512
509 ctx->db = NULL; 513 ctx->db = NULL;
514 ctx->transaction_started = 0;
510 515
511 ctx->regions = NULL; 516 ctx->regions = NULL;
512 517
513 ctx->cleanup_front = ctx->cleanup_back = ctx->cleanup = malloc(0); 518 ctx->cleanup_front = ctx->cleanup_back = ctx->cleanup = malloc(0);
514 519
515 ctx->script_header = ""; 520 ctx->script_header = "";
516 ctx->needs_push = 0; 521 ctx->needs_push = 0;
517 ctx->needs_sig = 0; 522 ctx->needs_sig = 0;
523 ctx->could_write_db = 1;
518 524
519 ctx->source_count = 0; 525 ctx->source_count = 0;
520 526
521 ctx->n_deltas = ctx->used_deltas = 0; 527 ctx->n_deltas = ctx->used_deltas = 0;
522 ctx->deltas = malloc(0); 528 ctx->deltas = malloc(0);
548 554
549 ctx->amInitializing = 0; 555 ctx->amInitializing = 0;
550 556
551 ctx->usedSig = 0; 557 ctx->usedSig = 0;
552 ctx->needsResig = 0; 558 ctx->needsResig = 0;
559
560 ctx->output_buffer = malloc(1);
561 ctx->output_buffer_size = 1;
553 562
554 return ctx; 563 return ctx;
555 } 564 }
556 565
557 size_t uw_inputs_max = SIZE_MAX; 566 size_t uw_inputs_max = SIZE_MAX;
606 615
607 for (i = 0; i < ctx->n_globals; ++i) 616 for (i = 0; i < ctx->n_globals; ++i)
608 if (ctx->globals[i].free) 617 if (ctx->globals[i].free)
609 ctx->globals[i].free(ctx->globals[i].data); 618 ctx->globals[i].free(ctx->globals[i].data);
610 free(ctx->globals); 619 free(ctx->globals);
620
621 free(ctx->output_buffer);
611 622
612 free(ctx); 623 free(ctx);
613 } 624 }
614 625
615 void uw_reset_keep_error_message(uw_context ctx) { 626 void uw_reset_keep_error_message(uw_context ctx) {
642 uw_reset_keep_request(ctx); 653 uw_reset_keep_request(ctx);
643 if (ctx->app) 654 if (ctx->app)
644 memset(ctx->inputs, 0, ctx->app->inputs_len * sizeof(input)); 655 memset(ctx->inputs, 0, ctx->app->inputs_len * sizeof(input));
645 memset(ctx->subinputs, 0, ctx->n_subinputs * sizeof(input)); 656 memset(ctx->subinputs, 0, ctx->n_subinputs * sizeof(input));
646 ctx->used_subinputs = ctx->hasPostBody = ctx->isPost = 0; 657 ctx->used_subinputs = ctx->hasPostBody = ctx->isPost = 0;
658 ctx->transaction_started = 0;
647 } 659 }
648 660
649 failure_kind uw_begin_init(uw_context ctx) { 661 failure_kind uw_begin_init(uw_context ctx) {
650 int r = setjmp(ctx->jmp_buf); 662 int r = setjmp(ctx->jmp_buf);
651 663
728 } 740 }
729 741
730 char *uw_Basis_htmlifyString(uw_context, const char *); 742 char *uw_Basis_htmlifyString(uw_context, const char *);
731 743
732 void uw_login(uw_context ctx) { 744 void uw_login(uw_context ctx) {
733 if (ctx->needs_push) { 745 char *id_s, *pass_s;
734 char *id_s, *pass_s; 746
735 747 if ((id_s = uw_Basis_requestHeader(ctx, "UrWeb-Client"))
736 if ((id_s = uw_Basis_requestHeader(ctx, "UrWeb-Client")) 748 && (pass_s = uw_Basis_requestHeader(ctx, "UrWeb-Pass"))) {
737 && (pass_s = uw_Basis_requestHeader(ctx, "UrWeb-Pass"))) { 749 unsigned id = atoi(id_s);
738 unsigned id = atoi(id_s); 750 int pass = atoi(pass_s);
739 int pass = atoi(pass_s); 751 client *c = find_client(id);
740 client *c = find_client(id); 752
741 753 if (c == NULL)
742 if (c == NULL) 754 uw_error(ctx, FATAL, "Unknown client ID in HTTP headers (%s, %s)", uw_Basis_htmlifyString(ctx, id_s), uw_Basis_htmlifyString(ctx, pass_s));
743 uw_error(ctx, FATAL, "Unknown client ID in HTTP headers (%s, %s)", uw_Basis_htmlifyString(ctx, id_s), uw_Basis_htmlifyString(ctx, pass_s)); 755 else {
744 else {
745 use_client(c);
746 ctx->client = c;
747
748 if (c->mode != USED)
749 uw_error(ctx, FATAL, "Stale client ID (%u) in subscription request", id);
750 if (c->pass != pass)
751 uw_error(ctx, FATAL, "Wrong client password (%u, %d) in subscription request", id, pass);
752 }
753 } else {
754 client *c = new_client();
755
756 if (c == NULL)
757 uw_error(ctx, FATAL, "Limit exceeded on number of message-passing clients");
758
759 use_client(c); 756 use_client(c);
760 uw_copy_client_data(c->data, ctx->client_data);
761 ctx->client = c; 757 ctx->client = c;
762 } 758
759 if (c->mode != USED)
760 uw_error(ctx, FATAL, "Stale client ID (%u) in subscription request", id);
761 if (c->pass != pass)
762 uw_error(ctx, FATAL, "Wrong client password (%u, %d) in subscription request", id, pass);
763 }
764 } else if (ctx->needs_push) {
765 client *c = new_client();
766
767 if (c == NULL)
768 uw_error(ctx, FATAL, "Limit exceeded on number of message-passing clients");
769
770 use_client(c);
771 uw_copy_client_data(c->data, ctx->client_data);
772 ctx->client = c;
763 } 773 }
764 } 774 }
765 775
766 failure_kind uw_begin(uw_context ctx, char *path) { 776 failure_kind uw_begin(uw_context ctx, char *path) {
767 int r = setjmp(ctx->jmp_buf); 777 int r = setjmp(ctx->jmp_buf);
768 778
769 if (r == 0) { 779 if (r == 0)
770 if (ctx->app->db_begin(ctx)) 780 ctx->app->handle(ctx, path);
781
782 return r;
783 }
784
785 void uw_ensure_transaction(uw_context ctx) {
786 if (!ctx->transaction_started) {
787 if (ctx->app->db_begin(ctx, ctx->could_write_db))
771 uw_error(ctx, BOUNDED_RETRY, "Error running SQL BEGIN"); 788 uw_error(ctx, BOUNDED_RETRY, "Error running SQL BEGIN");
772 789 ctx->transaction_started = 1;
773 ctx->app->handle(ctx, path); 790 }
774 }
775
776 return r;
777 } 791 }
778 792
779 uw_Basis_client uw_Basis_self(uw_context ctx) { 793 uw_Basis_client uw_Basis_self(uw_context ctx) {
780 if (ctx->client == NULL) 794 if (ctx->client == NULL)
781 uw_error(ctx, FATAL, "Call to Basis.self() from page that has only server-side code"); 795 uw_error(ctx, FATAL, "Call to Basis.self() from page that has only server-side code");
1182 1196
1183 void uw_set_needs_sig(uw_context ctx, int n) { 1197 void uw_set_needs_sig(uw_context ctx, int n) {
1184 ctx->needs_sig = n; 1198 ctx->needs_sig = n;
1185 } 1199 }
1186 1200
1201 void uw_set_could_write_db(uw_context ctx, int n) {
1202 ctx->could_write_db = n;
1203 }
1204
1187 1205
1188 static void uw_buffer_check_ctx(uw_context ctx, const char *kind, uw_buffer *b, size_t extra, const char *desc) { 1206 static void uw_buffer_check_ctx(uw_context ctx, const char *kind, uw_buffer *b, size_t extra, const char *desc) {
1189 if (b->back - b->front < extra) { 1207 if (b->back - b->front < extra) {
1190 size_t desired = b->front - b->start + extra, next; 1208 size_t desired = b->front - b->start + extra, next;
1191 char *new_heap; 1209 char *new_heap;
1285 int uw_pagelen(uw_context ctx) { 1303 int uw_pagelen(uw_context ctx) {
1286 return ctx->page.front - ctx->page.start; 1304 return ctx->page.front - ctx->page.start;
1287 } 1305 }
1288 1306
1289 int uw_send(uw_context ctx, int sock) { 1307 int uw_send(uw_context ctx, int sock) {
1290 int n = uw_really_send(sock, ctx->outHeaders.start, ctx->outHeaders.front - ctx->outHeaders.start); 1308 size_t target_length = (ctx->outHeaders.front - ctx->outHeaders.start) + 2 + (ctx->page.front - ctx->page.start);
1291 1309
1292 if (n < 0) 1310 if (ctx->output_buffer_size < target_length) {
1293 return n; 1311 do {
1294 1312 ctx->output_buffer_size *= 2;
1295 n = uw_really_send(sock, "\r\n", 2); 1313 } while (ctx->output_buffer_size < target_length);
1296 1314 ctx->output_buffer = realloc(ctx->output_buffer, ctx->output_buffer_size);
1297 if (n < 0) 1315 }
1298 return n; 1316
1299 1317 memcpy(ctx->output_buffer, ctx->outHeaders.start, ctx->outHeaders.front - ctx->outHeaders.start);
1300 return uw_really_send(sock, ctx->page.start, ctx->page.front - ctx->page.start); 1318 memcpy(ctx->output_buffer + (ctx->outHeaders.front - ctx->outHeaders.start), "\r\n", 2);
1319 memcpy(ctx->output_buffer + (ctx->outHeaders.front - ctx->outHeaders.start) + 2, ctx->page.start, ctx->page.front - ctx->page.start);
1320
1321 return uw_really_send(sock, ctx->output_buffer, target_length);
1301 } 1322 }
1302 1323
1303 int uw_print(uw_context ctx, int fd) { 1324 int uw_print(uw_context ctx, int fd) {
1304 int n = uw_really_write(fd, ctx->outHeaders.start, ctx->outHeaders.front - ctx->outHeaders.start); 1325 int n = uw_really_write(fd, ctx->outHeaders.start, ctx->outHeaders.front - ctx->outHeaders.start);
1305 1326
1338 uw_check_headers(ctx, len + 1); 1359 uw_check_headers(ctx, len + 1);
1339 strcpy(ctx->outHeaders.front, s); 1360 strcpy(ctx->outHeaders.front, s);
1340 ctx->outHeaders.front += len; 1361 ctx->outHeaders.front += len;
1341 } 1362 }
1342 1363
1364 int uw_has_contentLength(uw_context ctx) {
1365 return strstr(ctx->outHeaders.start, "Content-length: ") != NULL;
1366 }
1367
1343 void uw_clear_headers(uw_context ctx) { 1368 void uw_clear_headers(uw_context ctx) {
1344 uw_buffer_reset(&ctx->outHeaders); 1369 uw_buffer_reset(&ctx->outHeaders);
1370 }
1371
1372 void uw_Basis_clear_page(uw_context ctx) {
1373 uw_buffer_reset(&ctx->page);
1345 } 1374 }
1346 1375
1347 static void uw_check_script(uw_context ctx, size_t extra) { 1376 static void uw_check_script(uw_context ctx, size_t extra) {
1348 ctx_uw_buffer_check(ctx, "script", &ctx->script, extra); 1377 ctx_uw_buffer_check(ctx, "script", &ctx->script, extra);
1349 } 1378 }
3203 3232
3204 for (i = ctx->used_transactionals-1; i >= 0; --i) 3233 for (i = ctx->used_transactionals-1; i >= 0; --i)
3205 if (ctx->transactionals[i].free) 3234 if (ctx->transactionals[i].free)
3206 ctx->transactionals[i].free(ctx->transactionals[i].data, will_retry); 3235 ctx->transactionals[i].free(ctx->transactionals[i].data, will_retry);
3207 3236
3208 return ctx->app ? ctx->app->db_rollback(ctx) : 0; 3237 if (ctx->app && ctx->transaction_started) {
3209 } 3238 ctx->transaction_started = 0;
3210 3239 return ctx->app->db_rollback(ctx);
3211 static const char begin_xhtml[] = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">"; 3240 } else
3241 return 0;
3242 }
3243
3244 const char uw_begin_xhtml[] = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">";
3245 const char uw_begin_html5[] = "<!DOCTYPE html><html>";
3212 3246
3213 extern int uw_hash_blocksize; 3247 extern int uw_hash_blocksize;
3214 3248
3215 static const char sig_intro[] = "<input type=\"hidden\" name=\"Sig\" value=\""; 3249 static const char sig_intro[] = "<input type=\"hidden\" name=\"Sig\" value=\"";
3216 3250
3231 return NULL; 3265 return NULL;
3232 3266
3233 return s; 3267 return s;
3234 } 3268 }
3235 3269
3236 void uw_commit(uw_context ctx) { 3270 int uw_commit(uw_context ctx) {
3237 int i; 3271 int i;
3238 char *sig; 3272 char *sig;
3239 3273
3240 if (uw_has_error(ctx)) { 3274 if (uw_has_error(ctx)) {
3241 uw_rollback(ctx, 0); 3275 uw_rollback(ctx, 0);
3242 return; 3276 return 0;
3243 } 3277 }
3244 3278
3245 for (i = ctx->used_transactionals-1; i >= 0; --i) 3279 for (i = ctx->used_transactionals-1; i >= 0; --i)
3246 if (ctx->transactionals[i].rollback != NULL) 3280 if (ctx->transactionals[i].rollback != NULL)
3247 if (ctx->transactionals[i].commit) { 3281 if (ctx->transactionals[i].commit) {
3248 ctx->transactionals[i].commit(ctx->transactionals[i].data); 3282 ctx->transactionals[i].commit(ctx->transactionals[i].data);
3249 if (uw_has_error(ctx)) { 3283 if (uw_has_error(ctx)) {
3250 uw_rollback(ctx, 0); 3284 uw_rollback(ctx, 0);
3251 return; 3285 return 0;
3252 } 3286 }
3253 } 3287 }
3254 3288
3255 for (i = ctx->used_transactionals-1; i >= 0; --i) 3289 for (i = ctx->used_transactionals-1; i >= 0; --i)
3256 if (ctx->transactionals[i].rollback == NULL) 3290 if (ctx->transactionals[i].rollback == NULL)
3257 if (ctx->transactionals[i].commit) { 3291 if (ctx->transactionals[i].commit) {
3258 ctx->transactionals[i].commit(ctx->transactionals[i].data); 3292 ctx->transactionals[i].commit(ctx->transactionals[i].data);
3259 if (uw_has_error(ctx)) { 3293 if (uw_has_error(ctx)) {
3260 uw_rollback(ctx, 0); 3294 uw_rollback(ctx, 0);
3261 return; 3295 return 0;
3262 } 3296 }
3263 } 3297 }
3264 3298
3265 if (ctx->app->db_commit(ctx)) { 3299 if (ctx->transaction_started) {
3266 uw_set_error_message(ctx, "Error running SQL COMMIT"); 3300 int code = ctx->app->db_commit(ctx);
3267 return; 3301
3302 if (code) {
3303 if (code == -1)
3304 return 1;
3305
3306 for (i = ctx->used_transactionals-1; i >= 0; --i)
3307 if (ctx->transactionals[i].free)
3308 ctx->transactionals[i].free(ctx->transactionals[i].data, 0);
3309
3310 uw_set_error_message(ctx, "Error running SQL COMMIT");
3311 return 0;
3312 }
3268 } 3313 }
3269 3314
3270 for (i = 0; i < ctx->used_deltas; ++i) { 3315 for (i = 0; i < ctx->used_deltas; ++i) {
3271 delta *d = &ctx->deltas[i]; 3316 delta *d = &ctx->deltas[i];
3272 client *c = find_client(d->client); 3317 client *c = find_client(d->client);
3285 ctx->transactionals[i].free(ctx->transactionals[i].data, 0); 3330 ctx->transactionals[i].free(ctx->transactionals[i].data, 0);
3286 3331
3287 uw_check(ctx, 1); 3332 uw_check(ctx, 1);
3288 *ctx->page.front = 0; 3333 *ctx->page.front = 0;
3289 3334
3290 if (!ctx->returning_indirectly && !strncmp(ctx->page.start, begin_xhtml, sizeof begin_xhtml - 1)) { 3335 if (!ctx->returning_indirectly
3336 && (ctx->app->is_html5
3337 ? !strncmp(ctx->page.start, uw_begin_html5, sizeof uw_begin_html5 - 1)
3338 : !strncmp(ctx->page.start, uw_begin_xhtml, sizeof uw_begin_xhtml - 1))) {
3291 char *s; 3339 char *s;
3292 3340
3293 // Splice script data into appropriate part of page, also adding <head> if needed. 3341 // Splice script data into appropriate part of page, also adding <head> if needed.
3294 s = ctx->page.start + sizeof begin_xhtml - 1; 3342 s = ctx->page.start + (ctx->app->is_html5 ? sizeof uw_begin_html5 - 1 : sizeof uw_begin_xhtml - 1);
3295 s = strchr(s, '<'); 3343 s = strchr(s, '<');
3296 if (s == NULL) { 3344 if (s == NULL) {
3297 // Weird. Document has no tags! 3345 // Weird. Document has no tags!
3298 3346
3299 uw_write(ctx, "<head></head><body></body>"); 3347 uw_write(ctx, "<head></head><body></body>");
3368 memcpy(sig, realsig, 2*uw_hash_blocksize); 3416 memcpy(sig, realsig, 2*uw_hash_blocksize);
3369 sig = find_sig(sig); 3417 sig = find_sig(sig);
3370 } while (sig); 3418 } while (sig);
3371 } 3419 }
3372 } 3420 }
3421
3422 return 0;
3373 } 3423 }
3374 3424
3375 3425
3376 size_t uw_transactionals_max = SIZE_MAX; 3426 size_t uw_transactionals_max = SIZE_MAX;
3377 3427
3426 failure_kind fk = UNLIMITED_RETRY; 3476 failure_kind fk = UNLIMITED_RETRY;
3427 if (prev) 3477 if (prev)
3428 prev->next = next; 3478 prev->next = next;
3429 else 3479 else
3430 clients_used = next; 3480 clients_used = next;
3431 uw_reset(ctx);
3432 while (fk == UNLIMITED_RETRY) { 3481 while (fk == UNLIMITED_RETRY) {
3482 uw_reset(ctx);
3433 fk = uw_expunge(ctx, c->id, c->data); 3483 fk = uw_expunge(ctx, c->id, c->data);
3434 if (fk == UNLIMITED_RETRY) 3484 if (fk == UNLIMITED_RETRY)
3435 printf("Unlimited retry during expunge: %s\n", uw_error_message(ctx)); 3485 printf("Unlimited retry during expunge: %s\n", uw_error_message(ctx));
3436 } 3486 }
3437 if (fk == SUCCESS) 3487 if (fk == SUCCESS)
3449 3499
3450 failure_kind uw_initialize(uw_context ctx) { 3500 failure_kind uw_initialize(uw_context ctx) {
3451 int r = setjmp(ctx->jmp_buf); 3501 int r = setjmp(ctx->jmp_buf);
3452 3502
3453 if (r == 0) { 3503 if (r == 0) {
3454 if (ctx->app->db_begin(ctx)) 3504 uw_ensure_transaction(ctx);
3455 uw_error(ctx, FATAL, "Error running SQL BEGIN");
3456 ctx->app->initializer(ctx); 3505 ctx->app->initializer(ctx);
3457 if (ctx->app->db_commit(ctx)) 3506 if (ctx->app->db_commit(ctx))
3458 uw_error(ctx, FATAL, "Error running SQL COMMIT"); 3507 uw_error(ctx, FATAL, "Error running SQL COMMIT");
3459 } 3508 }
3460 3509
3709 uw_buffer_reset(&ctx->page); 3758 uw_buffer_reset(&ctx->page);
3710 3759
3711 uw_write_header(ctx, on_success); 3760 uw_write_header(ctx, on_success);
3712 uw_write_header(ctx, "Content-Type: "); 3761 uw_write_header(ctx, "Content-Type: ");
3713 uw_write_header(ctx, mimeType); 3762 uw_write_header(ctx, mimeType);
3714 uw_write_header(ctx, "\r\nContent-Length: "); 3763 uw_write_header(ctx, "\r\nContent-length: ");
3715 ctx_uw_buffer_check(ctx, "headers", &ctx->outHeaders, INTS_MAX); 3764 ctx_uw_buffer_check(ctx, "headers", &ctx->outHeaders, INTS_MAX);
3716 sprintf(ctx->outHeaders.front, "%lu%n", (unsigned long)b.size, &len); 3765 sprintf(ctx->outHeaders.front, "%lu%n", (unsigned long)b.size, &len);
3717 ctx->outHeaders.front += len; 3766 ctx->outHeaders.front += len;
3718 uw_write_header(ctx, "\r\n"); 3767 uw_write_header(ctx, "\r\n");
3719 if (oldh) uw_write_header(ctx, oldh); 3768 if (oldh) uw_write_header(ctx, oldh);
3720 3769
3721 ctx_uw_buffer_append(ctx, "page", &ctx->page, b.data, b.size); 3770 ctx_uw_buffer_append(ctx, "page", &ctx->page, b.data, b.size);
3771
3772 for (cl = ctx->cleanup; cl < ctx->cleanup_front; ++cl)
3773 cl->func(cl->arg);
3774
3775 ctx->cleanup_front = ctx->cleanup;
3776
3777 longjmp(ctx->jmp_buf, RETURN_INDIRECTLY);
3778 }
3779
3780 __attribute__((noreturn)) void uw_return_blob_from_page(uw_context ctx, uw_Basis_string mimeType) {
3781 cleanup *cl;
3782 int len;
3783 char *oldh;
3784
3785 if (!ctx->allowed_to_return_indirectly)
3786 uw_error(ctx, FATAL, "Tried to return a blob from an RPC");
3787
3788 ctx->returning_indirectly = 1;
3789 oldh = old_headers(ctx);
3790 uw_buffer_reset(&ctx->outHeaders);
3791
3792 uw_write_header(ctx, on_success);
3793 uw_write_header(ctx, "Content-Type: ");
3794 uw_write_header(ctx, mimeType);
3795 uw_write_header(ctx, "\r\nContent-length: ");
3796 ctx_uw_buffer_check(ctx, "headers", &ctx->outHeaders, INTS_MAX);
3797 sprintf(ctx->outHeaders.front, "%lu%n", (unsigned long)uw_buffer_used(&ctx->page), &len);
3798 ctx->outHeaders.front += len;
3799 uw_write_header(ctx, "\r\n");
3800 if (oldh) uw_write_header(ctx, oldh);
3722 3801
3723 for (cl = ctx->cleanup; cl < ctx->cleanup_front; ++cl) 3802 for (cl = ctx->cleanup; cl < ctx->cleanup_front; ++cl)
3724 cl->func(cl->arg); 3803 cl->func(cl->arg);
3725 3804
3726 ctx->cleanup_front = ctx->cleanup; 3805 ctx->cleanup_front = ctx->cleanup;
4029 else 4108 else
4030 fprintf(stderr, "%s\n", s); 4109 fprintf(stderr, "%s\n", s);
4031 return uw_unit_v; 4110 return uw_unit_v;
4032 } 4111 }
4033 4112
4113 static pthread_mutex_t rand_mutex = PTHREAD_MUTEX_INITIALIZER;
4114
4034 uw_Basis_int uw_Basis_rand(uw_context ctx) { 4115 uw_Basis_int uw_Basis_rand(uw_context ctx) {
4035 uw_Basis_int ret; 4116 uw_Basis_int ret;
4117 pthread_mutex_lock(&rand_mutex);
4036 int r = RAND_bytes((unsigned char *)&ret, sizeof ret); 4118 int r = RAND_bytes((unsigned char *)&ret, sizeof ret);
4119 pthread_mutex_unlock(&rand_mutex);
4037 4120
4038 if (r) 4121 if (r)
4039 return abs(ret); 4122 return abs(ret);
4040 else 4123 else
4041 uw_error(ctx, FATAL, "Random number generation failed"); 4124 uw_error(ctx, FATAL, "Random number generation failed");
4083 4166
4084 failure_kind uw_runCallback(uw_context ctx, void (*callback)(uw_context)) { 4167 failure_kind uw_runCallback(uw_context ctx, void (*callback)(uw_context)) {
4085 int r = setjmp(ctx->jmp_buf); 4168 int r = setjmp(ctx->jmp_buf);
4086 4169
4087 if (r == 0) { 4170 if (r == 0) {
4088 if (ctx->app->db_begin(ctx)) 4171 uw_ensure_transaction(ctx);
4089 uw_error(ctx, BOUNDED_RETRY, "Error running SQL BEGIN");
4090 4172
4091 callback(ctx); 4173 callback(ctx);
4092 } 4174 }
4093 4175
4094 return r; 4176 return r;
4131 failure_kind uw_begin_onError(uw_context ctx, char *msg) { 4213 failure_kind uw_begin_onError(uw_context ctx, char *msg) {
4132 int r = setjmp(ctx->jmp_buf); 4214 int r = setjmp(ctx->jmp_buf);
4133 4215
4134 if (ctx->app->on_error) { 4216 if (ctx->app->on_error) {
4135 if (r == 0) { 4217 if (r == 0) {
4136 if (ctx->app->db_begin(ctx)) 4218 uw_ensure_transaction(ctx);
4137 uw_error(ctx, BOUNDED_RETRY, "Error running SQL BEGIN");
4138 4219
4139 uw_buffer_reset(&ctx->outHeaders); 4220 uw_buffer_reset(&ctx->outHeaders);
4140 if (on_success[0]) 4221 if (on_success[0])
4141 uw_write_header(ctx, "HTTP/1.1 "); 4222 uw_write_header(ctx, "HTTP/1.1 ");
4142 else 4223 else
4143 uw_write_header(ctx, "Status: "); 4224 uw_write_header(ctx, "Status: ");
4144 uw_write_header(ctx, "500 Internal Server Error\r\n"); 4225 uw_write_header(ctx, "500 Internal Server Error\r\n");
4145 uw_write_header(ctx, "Content-type: text/html\r\n"); 4226 uw_write_header(ctx, "Content-type: text/html\r\n");
4146 uw_write(ctx, begin_xhtml); 4227 uw_write(ctx, ctx->app->is_html5 ? uw_begin_html5 : uw_begin_xhtml);
4147 ctx->app->on_error(ctx, msg); 4228 ctx->app->on_error(ctx, msg);
4148 uw_write(ctx, "</html>"); 4229 uw_write(ctx, "</html>");
4149 } 4230 }
4150 4231
4151 return r; 4232 return r;