aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Adam Chlipala <adamc@hcoop.net>2010-01-26 14:59:19 -0500
committerGravatar Adam Chlipala <adamc@hcoop.net>2010-01-26 14:59:19 -0500
commit703661dcfcf96e23acedf7c2a6d36cda3fb68bc6 (patch)
treeee5f39838aeadd38e02c34783400c48d5f2899e9
parentfba3039a03ae55a080b530665cfa0a9271f55d98 (diff)
Handling errors during commit
-rw-r--r--Makefile.in4
-rw-r--r--include/urweb.h3
-rw-r--r--lib/ur/string.ur11
-rw-r--r--lib/ur/string.urs1
-rw-r--r--src/c/request.c15
-rw-r--r--src/c/urweb.c74
6 files changed, 80 insertions, 28 deletions
diff --git a/Makefile.in b/Makefile.in
index 99e1a3ac..d3a089c4 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -92,6 +92,10 @@ install:
libtool --silent --mode=install install -c lib/c/liburweb_http.la $(LIB)/../liburweb_http.la
libtool --silent --mode=install install -c lib/c/liburweb_cgi.la $(LIB)/../liburweb_cgi.la
libtool --silent --mode=install install -c lib/c/liburweb_fastcgi.la $(LIB)/../liburweb_fastcgi.la
+ libtool --silent --finish $(LIB)/../liburweb.la
+ libtool --silent --finish $(LIB)/../liburweb_http.la
+ libtool --silent --finish $(LIB)/../liburweb_cgi.la
+ libtool --silent --finish $(LIB)/../liburweb_fastcgi.la
package:
hg archive -t tgz -X tests /tmp/urweb.tgz
diff --git a/include/urweb.h b/include/urweb.h
index b62adce1..3a2d2baf 100644
--- a/include/urweb.h
+++ b/include/urweb.h
@@ -42,7 +42,8 @@ int uw_rollback(uw_context);
__attribute__((noreturn)) void uw_error(uw_context, failure_kind, const char *fmt, ...);
char *uw_error_message(uw_context);
-void uw_set_error_message(uw_context, const char *);
+void uw_set_error_message(uw_context, const char *fmt, ...);
+int uw_has_error(uw_context);
void uw_push_cleanup(uw_context, void (*func)(void *), void *arg);
void uw_pop_cleanup(uw_context);
diff --git a/lib/ur/string.ur b/lib/ur/string.ur
index 4025cf68..07d7e6b8 100644
--- a/lib/ur/string.ur
+++ b/lib/ur/string.ur
@@ -38,6 +38,17 @@ fun all f s =
al 0
end
+fun mp f s =
+ let
+ fun mp' i acc =
+ if i < 0 then
+ acc
+ else
+ mp' (i - 1) (str (f (sub s i)) ^ acc)
+ in
+ mp' (length s - 1) ""
+ end
+
fun newlines [ctx] [[Body] ~ ctx] s : xml ([Body] ++ ctx) [] [] =
case split s #"\n" of
None => cdata s
diff --git a/lib/ur/string.urs b/lib/ur/string.urs
index 5590b50c..557e73c0 100644
--- a/lib/ur/string.urs
+++ b/lib/ur/string.urs
@@ -20,5 +20,6 @@ val split : t -> char -> option (string * string)
val msplit : {Haystack : t, Needle : t} -> option (string * char * string)
val all : (char -> bool) -> string -> bool
+val mp : (char -> char) -> string -> string
val newlines : ctx ::: {Unit} -> [[Body] ~ ctx] => string -> xml ([Body] ++ ctx) [] []
diff --git a/src/c/request.c b/src/c/request.c
index 1a2c0a93..247ae92c 100644
--- a/src/c/request.c
+++ b/src/c/request.c
@@ -339,7 +339,20 @@ request_result uw_request(uw_request_context rc, uw_context ctx,
fk = uw_begin(ctx, rc->path_copy);
if (fk == SUCCESS || fk == RETURN_INDIRECTLY) {
uw_commit(ctx);
- return SERVED;
+ if (uw_has_error(ctx)) {
+ log_error(logger_data, "Fatal error: %s\n", uw_error_message(ctx));
+
+ uw_reset_keep_error_message(ctx);
+ on_failure(ctx);
+ uw_write_header(ctx, "Content-type: text/html\r\n");
+ uw_write(ctx, "<html><head><title>Fatal Error</title></head><body>");
+ uw_write(ctx, "Fatal error: ");
+ uw_write(ctx, uw_error_message(ctx));
+ uw_write(ctx, "\n</body></html>");
+
+ return FAILED;
+ } else
+ return SERVED;
} else if (fk == BOUNDED_RETRY) {
if (retries_left) {
log_debug(logger_data, "Error triggers bounded retry: %s\n", uw_error_message(ctx));
diff --git a/src/c/urweb.c b/src/c/urweb.c
index 8ccecdaa..28b73715 100644
--- a/src/c/urweb.c
+++ b/src/c/urweb.c
@@ -613,6 +613,10 @@ static void uw_set_error(uw_context ctx, const char *fmt, ...) {
vsnprintf(ctx->error_message, ERROR_BUF_LEN, fmt, ap);
}
+int uw_has_error(uw_context ctx) {
+ return ctx->error_message[0] != 0;
+}
+
__attribute__((noreturn)) void uw_error(uw_context ctx, failure_kind fk, const char *fmt, ...) {
cleanup *cl;
@@ -2888,21 +2892,61 @@ uw_unit uw_Basis_send(uw_context ctx, uw_Basis_channel chn, uw_Basis_string msg)
return uw_unit_v;
}
+int uw_rollback(uw_context ctx) {
+ int i;
+ cleanup *cl;
+
+ if (ctx->client)
+ release_client(ctx->client);
+
+ for (cl = ctx->cleanup; cl < ctx->cleanup_front; ++cl)
+ cl->func(cl->arg);
+
+ ctx->cleanup_front = ctx->cleanup;
+
+ for (i = ctx->used_transactionals-1; i >= 0; --i)
+ if (ctx->transactionals[i].rollback != NULL)
+ ctx->transactionals[i].rollback(ctx->transactionals[i].data);
+
+ for (i = ctx->used_transactionals-1; i >= 0; --i)
+ if (ctx->transactionals[i].free)
+ ctx->transactionals[i].free(ctx->transactionals[i].data);
+
+ return ctx->app->db_rollback(ctx);
+}
+
void uw_commit(uw_context ctx) {
int i;
+ if (uw_has_error(ctx)) {
+ uw_rollback(ctx);
+ return;
+ }
+
for (i = ctx->used_transactionals-1; i >= 0; --i)
if (ctx->transactionals[i].rollback != NULL)
- if (ctx->transactionals[i].commit)
+ if (ctx->transactionals[i].commit) {
ctx->transactionals[i].commit(ctx->transactionals[i].data);
+ if (uw_has_error(ctx)) {
+ uw_rollback(ctx);
+ return;
+ }
+ }
for (i = ctx->used_transactionals-1; i >= 0; --i)
if (ctx->transactionals[i].rollback == NULL)
- if (ctx->transactionals[i].commit)
+ if (ctx->transactionals[i].commit) {
ctx->transactionals[i].commit(ctx->transactionals[i].data);
+ if (uw_has_error(ctx)) {
+ uw_rollback(ctx);
+ return;
+ }
+ }
- if (ctx->app->db_commit(ctx))
- uw_error(ctx, FATAL, "Error running SQL COMMIT");
+ if (ctx->app->db_commit(ctx)) {
+ uw_set_error_message(ctx, "Error running SQL COMMIT");
+ return;
+ }
for (i = 0; i < ctx->used_deltas; ++i) {
delta *d = &ctx->deltas[i];
@@ -2954,28 +2998,6 @@ void uw_commit(uw_context ctx) {
}
}
-int uw_rollback(uw_context ctx) {
- int i;
- cleanup *cl;
-
- if (ctx->client)
- release_client(ctx->client);
-
- for (cl = ctx->cleanup; cl < ctx->cleanup_front; ++cl)
- cl->func(cl->arg);
-
- ctx->cleanup_front = ctx->cleanup;
-
- for (i = ctx->used_transactionals-1; i >= 0; --i)
- if (ctx->transactionals[i].rollback != NULL)
- ctx->transactionals[i].rollback(ctx->transactionals[i].data);
-
- for (i = ctx->used_transactionals-1; i >= 0; --i)
- if (ctx->transactionals[i].free)
- ctx->transactionals[i].free(ctx->transactionals[i].data);
-
- return ctx->app->db_rollback(ctx);
-}
size_t uw_transactionals_max = SIZE_MAX;