# HG changeset patch # User Adam Chlipala # Date 1259072665 18000 # Node ID a8a8258613976763b32d80154f3f0bbda1e1e81f # Parent 0d767c8d29235bdc370eb9dfb6c68438935dae5c Explicitly abort in-flight RPCs onunload diff -r 0d767c8d2923 -r a8a825861397 include/urweb.h --- a/include/urweb.h Sun Nov 22 17:57:15 2009 -0500 +++ b/include/urweb.h Tue Nov 24 09:24:25 2009 -0500 @@ -69,6 +69,7 @@ const char *uw_Basis_get_script(uw_context, uw_unit); uw_Basis_string uw_Basis_maybe_onload(uw_context, uw_Basis_string); +uw_Basis_string uw_Basis_maybe_onunload(uw_context, uw_Basis_string); void uw_set_needs_push(uw_context, int); void uw_set_needs_sig(uw_context, int); diff -r 0d767c8d2923 -r a8a825861397 lib/js/urweb.js --- a/lib/js/urweb.js Sun Nov 22 17:57:15 2009 -0500 +++ b/lib/js/urweb.js Tue Nov 24 09:24:25 2009 -0500 @@ -627,7 +627,20 @@ var sig = null; +var unloading = false, inFlight = null; + +function unload() { + unloading = true; + + for (; inFlight; inFlight = inFlight.next) { + inFlight.data.abort(); + } +} + function requestUri(xhr, uri, needsSig) { + if (unloading) + return; + xhr.open("POST", uri, true); if (client_id != null) { @@ -642,9 +655,15 @@ xhr.setRequestHeader("UrWeb-Sig", sig); } + inFlight = cons(xhr, inFlight); xhr.send(null); } +function xhrFinished(xhr) { + xhr.abort(); + inFlight = remove(xhr, inFlight); +} + function rc(prefix, uri, parse, k, needsSig) { uri = cat(prefix, uri); uri = flattenLocal(uri); @@ -668,6 +687,8 @@ } else { conn(); } + + xhrFinished(xhr); } }; @@ -772,7 +793,7 @@ } } - xhr.abort(); + xhrFinished(xhr); connect(); } @@ -786,7 +807,7 @@ }; onTimeout = function() { - xhr.abort(); + xhrFinished(xhr); connect(); }; diff -r 0d767c8d2923 -r a8a825861397 src/c/urweb.c --- a/src/c/urweb.c Sun Nov 22 17:57:15 2009 -0500 +++ b/src/c/urweb.c Tue Nov 24 09:24:25 2009 -0500 @@ -1173,6 +1173,16 @@ } } +uw_Basis_string uw_Basis_maybe_onunload(uw_context ctx, uw_Basis_string s) { + if (ctx->script_header[0] == 0) + return ""; + else { + char *r = uw_malloc(ctx, 22 + strlen(s)); + sprintf(r, " onunload='unload();%s'", s); + return r; + } +} + extern uw_Basis_string uw_cookie_sig(uw_context); const char *uw_Basis_get_settings(uw_context ctx, uw_unit u) { diff -r 0d767c8d2923 -r a8a825861397 src/monoize.sml --- a/src/monoize.sml Sun Nov 22 17:57:15 2009 -0500 +++ b/src/monoize.sml Tue Nov 24 09:24:25 2009 -0500 @@ -2483,13 +2483,14 @@ else attrs - fun findOnload (attrs, acc) = + fun findOnload (attrs, onload, onunload, acc) = case attrs of - [] => (NONE, acc) - | ("Onload", e, _) :: rest => (SOME e, List.revAppend (acc, rest)) - | x :: rest => findOnload (rest, x :: acc) + [] => (onload, onunload, acc) + | ("Onload", e, _) :: rest => findOnload (rest, SOME e, onunload, acc) + | ("Onunload", e, _) :: rest => findOnload (rest, onload, SOME e, acc) + | x :: rest => findOnload (rest, onload, onunload, x :: acc) - val (onload, attrs) = findOnload (attrs, []) + val (onload, onunload, attrs) = findOnload (attrs, NONE, NONE, []) val (class, fm) = monoExp (env, st, fm) class @@ -2669,26 +2670,33 @@ :: str ";" :: assgns) end + + fun execify e = + case e of + NONE => (L'.EPrim (Prim.String ""), loc) + | SOME e => + let + val e = (L'.EApp (e, (L'.ERecord [], loc)), loc) + in + (L'.EStrcat ((L'.EPrim (Prim.String "exec("), loc), + (L'.EStrcat ((L'.EJavaScript (L'.Attribute, e), loc), + (L'.EPrim (Prim.String ")"), loc)), loc)), loc) + end in case tag of "body" => let - val onload = case onload of - NONE => (L'.EPrim (Prim.String ""), loc) - | SOME e => - let - val e = (L'.EApp (e, (L'.ERecord [], loc)), loc) - in - (L'.EStrcat ((L'.EPrim (Prim.String "exec("), loc), - (L'.EStrcat ((L'.EJavaScript (L'.Attribute, e), loc), - (L'.EPrim (Prim.String ")"), loc)), loc)), loc) - end + val onload = execify onload + val onunload = execify onunload in normal ("body", - SOME (L'.EFfiApp ("Basis", "maybe_onload", - [(L'.EStrcat ((L'.EFfiApp ("Basis", "get_settings", - [(L'.ERecord [], loc)]), loc), - onload), loc)]), - loc), + SOME (L'.EStrcat ((L'.EFfiApp ("Basis", "maybe_onload", + [(L'.EStrcat ((L'.EFfiApp ("Basis", "get_settings", + [(L'.ERecord [], loc)]), loc), + onload), loc)]), + loc), + (L'.EFfiApp ("Basis", "maybe_onunload", + [onunload]), + loc)), loc), SOME (L'.EFfiApp ("Basis", "get_script", [(L'.ERecord [], loc)]), loc)) end