Mercurial > urweb
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; |