diff options
author | Adam Chlipala <adam@chlipala.net> | 2012-04-27 09:43:09 -0400 |
---|---|---|
committer | Adam Chlipala <adam@chlipala.net> | 2012-04-27 09:43:09 -0400 |
commit | c4daee27278ae99dd4d2cd0507f7ffc555d266f4 (patch) | |
tree | 62a8fa9896b4310f97d319d0a64313afb032404e /src | |
parent | 6320e0f89da5fd1afc85e36bde7351d514b02e99 (diff) |
Ensure proper ordering of <script> execution, to bring identifiers into scope in time
Diffstat (limited to 'src')
-rw-r--r-- | src/c/urweb.c | 77 | ||||
-rw-r--r-- | src/monoize.sml | 26 |
2 files changed, 55 insertions, 48 deletions
diff --git a/src/c/urweb.c b/src/c/urweb.c index 2d26d0b2..ab14144d 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -1312,10 +1312,6 @@ void uw_write_script(uw_context ctx, uw_Basis_string s) { ctx->script.front += len; } -const char *uw_Basis_get_script(uw_context ctx, uw_unit u) { - return "<sc>"; -} - const char *uw_get_real_script(uw_context ctx) { if (strstr(ctx->outHeaders.start, "Set-Cookie: ")) { uw_write_script(ctx, "sig=\""); @@ -3157,6 +3153,8 @@ int uw_rollback(uw_context ctx, int will_retry) { return ctx->app ? ctx->app->db_rollback(ctx) : 0; } +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\">"; + void uw_commit(uw_context ctx) { int i; @@ -3210,36 +3208,53 @@ void uw_commit(uw_context ctx) { uw_check(ctx, 1); *ctx->page.front = 0; - // Splice script data into appropriate part of page - if (ctx->returning_indirectly || ctx->script_header[0] == 0) { - char *start = strstr(ctx->page.start, "<sc>"); - if (start) { - memmove(start, start + 4, uw_buffer_used(&ctx->page) - (start - ctx->page.start) - 4); - ctx->page.front -= 4; - } - } else if (uw_buffer_used(&ctx->script) == 0) { - size_t len = strlen(ctx->script_header); - char *start = strstr(ctx->page.start, "<sc>"); - if (start) { - ctx_uw_buffer_check(ctx, "page", &ctx->page, uw_buffer_used(&ctx->page) - 4 + len); - start = strstr(ctx->page.start, "<sc>"); - memmove(start + len, start + 4, uw_buffer_used(&ctx->page) - (start - ctx->page.start) - 3); - ctx->page.front += len - 4; - memcpy(start, ctx->script_header, len); - } - } else { - size_t lenH = strlen(ctx->script_header), len = uw_buffer_used(&ctx->script); - size_t lenP = lenH + 40 + len; - char *start = strstr(ctx->page.start, "<sc>"); - if (start) { - ctx_uw_buffer_check(ctx, "page", &ctx->page, uw_buffer_used(&ctx->page) - 4 + lenP); - start = strstr(ctx->page.start, "<sc>"); - memmove(start + lenP, start + 4, uw_buffer_used(&ctx->page) - (start - ctx->page.start) - 3); - ctx->page.front += lenP - 4; + if (!ctx->returning_indirectly && !strncmp(ctx->page.start, begin_xhtml, sizeof begin_xhtml - 1)) { + char *s; + + // Splice script data into appropriate part of page, also adding <head> if needed. + s = ctx->page.start + sizeof begin_xhtml - 1; + s = strchr(s, '<'); + if (s == NULL) { + // Weird. Document has no tags! + + uw_write(ctx, "<head></head><body></body>"); + uw_check(ctx, 1); + *ctx->page.front = 0; + } else if (!strncmp(s, "<head>", 6)) { + // <head> is present. Let's add the <script> tags immediately after it. + + size_t lenH = strlen(ctx->script_header), len = uw_buffer_used(&ctx->script); + size_t lenP = lenH + 40 + len; + char *start = s + 6, *oldPage = ctx->page.start; + + ctx_uw_buffer_check(ctx, "page", &ctx->page, uw_buffer_used(&ctx->page) + lenP); + start += ctx->page.start - oldPage; + memmove(start + lenP, start, uw_buffer_used(&ctx->page) - (start - ctx->page.start) + 1); + ctx->page.front += lenP; memcpy(start, ctx->script_header, lenH); memcpy(start + lenH, "<script type=\"text/javascript\">", 31); memcpy(start + lenH + 31, ctx->script.start, len); memcpy(start + lenH + 31 + len, "</script>", 9); + } else { + // No <head>. At this point, add it, with <script> tags inside. + + size_t lenH = strlen(ctx->script_header), len = uw_buffer_used(&ctx->script); + size_t lenP = lenH + 53 + len; + char *start = s, *oldPage = ctx->page.start; + + printf("start = %ld\n", start - ctx->page.start); + + ctx_uw_buffer_check(ctx, "page", &ctx->page, uw_buffer_used(&ctx->page) + lenP); + start += ctx->page.start - oldPage; + printf("page1 = %s\n", ctx->page.start); + memmove(start + lenP, start, uw_buffer_used(&ctx->page) - (start - ctx->page.start) + 1); + printf("page2 = %s\n", ctx->page.start); + ctx->page.front += lenP; + memcpy(start, "<head>", 6); + memcpy(start + 6, ctx->script_header, lenH); + memcpy(start + 6 + lenH, "<script type=\"text/javascript\">", 31); + memcpy(start + 6 + lenH + 31, ctx->script.start, len); + memcpy(start + 6 + lenH + 31 + len, "</script></head>", 16); } } } @@ -3919,8 +3934,6 @@ uw_Basis_time *uw_Basis_readUtc(uw_context ctx, uw_Basis_string s) { return NULL; } -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\">"; - failure_kind uw_begin_onError(uw_context ctx, char *msg) { int r = setjmp(ctx->jmp_buf); diff --git a/src/monoize.sml b/src/monoize.sml index 50bc2060..99d93ff9 100644 --- a/src/monoize.sml +++ b/src/monoize.sml @@ -1,4 +1,4 @@ -(* Copyright (c) 2008-2011, Adam Chlipala +(* Copyright (c) 2008-2012, Adam Chlipala * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -3179,7 +3179,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) = | _ => (Print.prefaces "Targs" (map (fn t => ("T", CorePrint.p_con env t)) targs); raise Fail "No name passed to input tag") - fun normal (tag, extra, extraInner) = + fun normal (tag, extra) = let val (tagStart, fm) = tagStart tag val tagStart = case extra of @@ -3189,10 +3189,6 @@ fun monoExp (env, st, fm) (all as (e, loc)) = fun normal () = let val (xml, fm) = monoExp (env, st, fm) xml - - val xml = case extraInner of - NONE => xml - | SOME ei => (L'.EStrcat (ei, xml), loc) in ((L'.EStrcat ((L'.EStrcat (tagStart, (L'.EPrim (Prim.String ">"), loc)), loc), (L'.EStrcat (xml, @@ -3316,8 +3312,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) = loc), (L'.EFfiApp ("Basis", "maybe_onunload", [(onunload, s)]), - loc)), loc), - SOME (L'.EFfiApp ("Basis", "get_script", [((L'.ERecord [], loc), (L'.TRecord [], loc))]), loc)) + loc)), loc)) end | "dyn" => @@ -3346,9 +3341,9 @@ fun monoExp (env, st, fm) (all as (e, loc)) = | _ => raise Fail "Monoize: Bad dyn attributes" end - | "submit" => normal ("input type=\"submit\"", NONE, NONE) - | "image" => normal ("input type=\"image\"", NONE, NONE) - | "button" => normal ("input type=\"submit\"", NONE, NONE) + | "submit" => normal ("input type=\"submit\"", NONE) + | "image" => normal ("input type=\"image\"", NONE) + | "button" => normal ("input type=\"submit\"", NONE) | "hidden" => input "hidden" | "textbox" => @@ -3404,8 +3399,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) = NONE => raise Fail "No name for radioGroup" | SOME name => normal ("input", - SOME (L'.EPrim (Prim.String (" type=\"radio\" name=\"" ^ name ^ "\"")), loc), - NONE)) + SOME (L'.EPrim (Prim.String (" type=\"radio\" name=\"" ^ name ^ "\"")), loc))) | "select" => (case targs of @@ -3502,7 +3496,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) = fm) end) - | "coption" => normal ("option", NONE, NONE) + | "coption" => normal ("option", NONE) | "ctextarea" => (case List.find (fn ("Source", _, _) => true | _ => false) attrs of @@ -3527,8 +3521,8 @@ fun monoExp (env, st, fm) (all as (e, loc)) = fm) end) - | "tabl" => normal ("table", NONE, NONE) - | _ => normal (tag, NONE, NONE) + | "tabl" => normal ("table", NONE) + | _ => normal (tag, NONE) in case #1 dynClass of L'.ENone _ => baseAll |